tmxklab

[HackCTF/Pwnable] Offset 본문

War Game/HackCTF

[HackCTF/Pwnable] Offset

tmxk4221 2020. 1. 27. 22:10

1. 문제확인

 

nc ctf.j0n9hyun.xyz 3007

 

1) 접속

  • 문자열 출력과 동시에 프로그램은 아무런 수행없이 종료

 

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

  • main()의 인자 개수(argc)를 v5에 저장
  • gets()를 통해 표준 입력 값을 s변수에 저장한 뒤, select_func()의 파라미터로 전달

 

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

  • 함수 포인터 v3 선언 후 two()로 초기화
  • strncpy()를 통해 31bytes(0x1Fu)만큼 파라미터 src값을 dest로 복사
  • if문에서 dest변수에 저장된 문자열과 "one"이 같으면 함수 포인터 v3에 one()주소로 저장
  • return값으로 v3()함수 포인터 반환

 

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

  • flag.txt파일을 읽기모드로 열어 1byte씩 화면에 표준 출력
  • 실행시켜야할 함수

 

5) IDA(Pseudocode)확인 - one(), two()

  • puts()를 통해 문자열 출력

 

6) $checksec를 통해 elf파일에 걸린 메모리 보호기법 확인

  • RELRO : Relocation Read-Only의 줄임말로 GOT Overwirte와 같은 공격에 대비하여 elf바이너리 또는 프로세스의 데이터 섹션을 보호하는 기술, 즉, 메모리가 변경되는 것을 보호, Full RELRO으로 걸려있으면 .ctors, .dtors, .jcr, .dynamic, .got섹션이 읽기 전용 상태가 됨
  • NX : 리눅스 보호기법중 DEP(Data Execution Prevention)로 데이터 영역에서 코드가 실행되는 것을 막는 기법, 예를 들어 DEP가 적용된 경우 bof공격을 통해 return address를 변조했을 때 실행권한이 없어 쉘코드가 실행되지 않고 프로그램에 대한 예외처리 후 종료됨
  • PIE : Position Independent Executable의 줄임말로 위치 독립 실행파일, 실행할 때마다 매핑되는 주소가 어디든지 상관없이 실행되는 파일로 매핑되는 주소가 매번달라 바이너리의 주소를 랜덤화하여 바이너리의 특정 주소의 값을 수정하는 것과 같은 공격을 방어
  • Stack Canary : 함수 진입 시 스택에 SFP와 return address정보를 저장할 때, 이 정보들이 공격자에 의해 덮어씌어지는 것으로부터 보호하기 위해 스택상의 변수들의 공간과 SFP사이에 특정한 값을 추가하는데 이 값을 canary라고 불림, 예를 들어 bof공격시 return address를 덮기 전에 canary값이 먼저 덮어지므로 canary값의 변조 유무로 bof 탐지 가능
  • 따라서, 현재 RELRO가 적용되어 GOT Overwrite가 불가능하고 PIE가 적용되어 바이너리 주소 값을 수정하는 공격이 불가능하고 NX가 걸려 DEP보호기법이 작동중인 상태

2. 접근방법

  • 결과적으로 main()에서 실행하지 않은 printf_flag()를 실행시켜야 함
  • 메모리 보호기법이 다수 걸려있는 상태에서 먼저 main()에서 입력 값을 받고 처리하는 select_func()분석

 

1) 스택구조(select_func)

  • strncpy()를 통해 파라미터이자 입력 값인 src변수의 내용을 dest변수로 복사
  • 이때, 31bytes까지 복사할 수 있는데 스택구조를 보면 dest와 v3사이에 30bytes 차이 발생
  • 따라서, 31bytes를 꽉 채워서 입력하면 1byte만큼 v3변수를 덮어씌울 수 있음
  • 또한, v3는 two()의 주소를 담은 포인터이며 함수의 return값

 

2) two()와 print_flag()비교

  • two()의 시작주소 : 0x000006AD -> \xAD\x06\x00\x00

  • flag_print()의 시작주소 : 0x000006D8 -> \xD8\x06\x00\x00

 

3) 결론

  • strncpy()를 통해 v3변수에서 1byte만큼 변조 가능
  • 실행시켜야할 flag_print()와 v3변수에 초기화된 two()의 각각 주소는 1byte만 차이남
  • 따라서, 30bytes의 더미 값과 1byte인 \xD8을 사용하여 flag_print()를 실행

  • dummy(30bytes) + \xD8(1byte)입력 시

3. 풀이

1) 공격 코드 작성

from pwn import *   # pwntools모듈
# remote(ip, port), ip는 string형, port는 int형
p = remote("ctf.j0n9hyun.xyz", 3007)

p.recvuntil("Which function would you like to call?")
payload = "A"*30
payload += "\xD8"
p.sendline(paylaod)
# interactive()는 쉘과 직접적으로 명령을 송수신할 수 있는 함수
p.interactive()

 

2) 공격실행

'War Game > HackCTF' 카테고리의 다른 글

[HackCTF/Pwnable] Yes or no  (0) 2020.02.22
[HackCTF/Pwnable] BOF_PIE  (0) 2020.01.28
[HackCTF/Pwnable] Simple_Overflow_ver_2  (0) 2020.01.27
[HackCTF/Pwnable] x64 Simple_size_BOF  (0) 2020.01.27
[HackCTF/Pwnable] x64 Buffer Overflow  (0) 2020.01.27
Comments