[침투 테스팅] HackTheBox - Forge : Server-Side Request Forgery to FTP, PDB 권한 상승

2022. 2. 2. 03:17Penetration Testing/Medium

etc/hosts

먼저 DNS 설정을 해주자. 웹 서버에 접속하면 forge.htb 라는 도메인으로 리다이렉트되기 때문에 해당 도메인을 침투 테스팅 서버의 주소로 연결해줘야 웹 분석이 가능하다.

 

 

 

 

 

 

 

forge.htb

Nmap 스캔으로는 딱히 특별한 정보를 얻을 수 없었다. 바로 웹 접속을 해보니 다음과 같이 갤러리 페이지가 나온다. 우측 상단에 Upload an Image 라는 버튼이 있는 것으로 보아 이미지 업로드 기능이 있는 것 같고 이를 이용해서 내부 침투가 가능할 수도 있을 것 같다.

 

Upload an Image 버튼을 클릭하여 업로드 페이지로 들어가면 이미지 파일 업로드 이외에도 URL을 통한 업로드도 지원한다. 일단은 파일 업로드 기능을 통한 웹셸 업로드가 가능한지를 테스트 해보아야 하지만 해당 문제는 파일 업로드 공격이 아닌 SSRF 문제로 분류되어 있었기에 해봤자 안될 것 같아서 넘어가고 URL을 통한 업로드 기능을 이용해보았다.

 

 

 

 

 

Wireshark

먼저 netcat으로 포트를 열고 URL 업로드 기능에 내 ip를 입력하여 어떤 요청이 오는지를 확인해보았지만 대상 서버가 Python을 통해 요청을 한다는 것 외에는 특별한 정보를 얻을 수는 없었다.

 

 

 

 

 

Burp Suite

딱히 더 정보를 얻을 수 있을 것 같지는 않으니 SSRF 공격을 시도해보자. 일단 루프백 IP를 넣어보면 대상 서버가 URL 블랙리스트를 통해 SSRF를 어느정도 방어하고 있다는 것을 알 수 있다. 여러가지 값을 넣어본 결과 forge.htb 라는 도메인 역시 블랙리스트에 포함되어 있지만 여기에 대문자를 섞어서 넣으면 이를 우회할 수 있는 것을 확인하였다. 다만 실제 서비스되는 서버에서는 도메인이 그 서버의 공인 IP와 연결되어 있어서 로컬에서 도메인 주소를 통해 자신에게 요청을 보낼 수는 없을 것 같다....

 

SSRF 취약점을 찾았으니 이를 악용할 수 있는 서비스를 찾아야 한다. 디렉토리 버스팅을 해본 결과 딱히 수상한 부분을 찾지 못하여 vhost을 찾아보았다. 그런데 해당 시스템이 모든 vhost에 대해서 302 응답을 해서 제대로 된 결과를 확인할 수 없었다. 그래서 gobuster의 옵션을 살펴 보았는데 디렉토리 버스팅 기능에는 특정 응답 코드만 표시하는 기능이 있지만 vhost 버스팅에는 그런 옵션이 없었다....

obuster vhost -u http://forge.htb -w /home/kali/Desktop/exploit/SecLists-master/Discovery/DNS/subdomains-top1million-110000.txt -t 100 -z | grep '200'

그래서 일단 그랩으로 200 코드만 잡아보았더니 다행히 admin.forge.htb 라는 결과가 나왔다. 해당 URL에 접속하려면 위에서 처럼 hosts 파일에 admin.forge.htb를 추가해줘야 하니 주의하자.

 

 

 

 

 

admin.forge.htb

보아하니 로컬호스트만 접속이 가능한 것 같다. 위에서 찾은 SSRF 취약점을 이용해 이를 우회하고 응답 값을 받아내보자. 대문자를 이용해 블랙리스트를 우회하고 admin.forge.htb에 요청을 보내면 서버가 응답 값이 저장된 URL을 반환하는데 이곳에 접속해보면 당연히 이미지를 표시할 수 없다는 에러가 뜬다.

 

 

 

 

 

BurpSuite

이것저것 해보니 아마 accept: 값에 이미지를 받겠다고 되어있어서 그런것 같아서 accept 어쩌고 하는 부분을 전부 날리고 요청을 보내니 다음과 같이 admin.forge.htb의 소스를 얻을 수 있었다.

 

해당 소스에서 admin.forge.htb에 /announcements와 /upload 라는 페이지가 있다는 것을 알 수 있다. 먼저  /announcements 페이지에는 다음과 같이 적혀있다.

    <ul>
        <li>An internal ftp server has been setup with credentials as user:heightofsecurity123!</li>
        <li>The /upload endpoint now supports ftp, ftps, http and https protocols for uploading from url.</li>
        <li>The /upload endpoint has been configured for easy scripting of uploads, and for uploading an image, one can simply pass a url with ?u=&lt;url&gt;.</li>
    </ul>

대충 Nmap 스캔을 했을때 나온 필터링된 FTP 서버의 heightofsecurity123!이라는 계정이 있고 upload 기능으로 FTP서버에 접속할 수 있다는 내용인 것 같다. 세번째 줄에 내용은 이해하지 못하겠어서 찾아보니까 ?u= 로 get 메소드를 통해 URL 보낼 수 있다는 의미였다...

 

위에 내용을 정리하면 SSRF 공격을 통해 admin.forge.htb/upload?u=ftp서버URL 다음과 같은 URL에 요청을 보내 FTP 서버에 접근할 수 있다는 것을 알 수 있다.

일반적으로 URL로 FTP에 접근하는 방법은 다음과 같다.

ftp://ID:password@IP:PORT/FILE_PATH
ftp://user:ID@IP:PORT/FILE_PATH
ftp://IP:PORT/FILE_PATH

FTP 계정의 ID는 알지만 Password는 아직 모르기 때문에 밑에 두 방법을 시도해보자

http://Admin.ForGe.Htb/upload?u=ftp://user:heightofsecurity123!@fOrgE.hTB/../

다음과 같이 입력하고 반환된 URL을 위에서 처럼 accept 부분을 날리고 읽으면 파일 목록이 뜨게된다. 참고로 fOrgE.hTB 대신 127.0.0.1을 16진수로 바꾼 0x7f000001을 써도 블랙리스트를 우회할 수 있다고 한다.

 

 

 

 

 

 

http://Admin.ForGe.Htb/upload?u=ftp://user:heightofsecurity123!@fOrgE.hTB/../user.txt

어쨋든 위 파일 목록에서 user.txt 파일이 있는 것이 확인 가능하기 때문에 FTP로 user Flag를 읽어낼 수 있다.

 

user_flag를 얻었으면 권한 상승(Privilege Escalation)을 통해 root 권한을 얻어 root_flag를 획득해야 한다. 현재는 SSRF 취약점을 통해 파일 열람이 가능하다뿐이지 아직 제대로 시스템에 침투하지 않은 상태이다. Nmap 스캔 결과를 보면 openssh가 열려있다는 것을 알 수 있으니 SSRF 공격으로 ssh 계정을 탈취해보자. 일단 ssh 폴더를 찾으려고 이리저리 뒤져보았지만 없었다. 이외에도 리눅스 디폴트 폴더등이 안보이는 걸 보면 숨김 설정이 되었나보다.

http://Admin.ForGe.Htb/upload?u=ftp://user:heightofsecurity123!@fOrgE.hTB/../.ssh/

 

숨김 설정이 되었더라도 폴더 접근 자체는 가능하다. ssh 폴더 같은 경우 기본적으로 .ssh 라는 폴더명을 사용하기 때문에 다음과 같은 URL로 SSRF 요청을 날려주면 ssh 관련 키 값들이 포함된 파일 목록을 얻을 수 있다. 여기서 FTP URL로 요청을 보내려고 할때 꼭 폴더 명 뒤에는 / 를 붙여줘야된다. 안그러면 에러가 뜬다.

 

어쨋든 .ssh 폴더에 id_rsa라는 RSA 개인키 파일을 얻을 수 있다. 이 부분이 살짝 의문인게 실제로 개인키는 서버측에 저장되지 않는 것으로 알고 있는데... 그냥 안전하지 않은 개인키 관리에 관련한 문제 자체의 의도적인 부분으로 보고 넘어갔다.

curl [주소] >> [파일이름]

BurpSuite의 결과를 복붙하던가 아니면 다음과 같은 명령어로 개인키 파일을 가져올 수 있다.

sudo ssh -i [개인키 파일명] user@10.10.11.111 -p 22

이후 다음 명령어로 openssh 서버로 접속할 수 있다. 유저명은 /../.ssh/ 폴더의 id_rsa.pub (공개키) 파일에서 확인할 수 있었다.

 

 

 

 

 

 

 

openssh

ssh 접속을 시도하면 다음과 같이 성공적으로 시스템 침투가 가능하다. 일단 우분투 버전이 꽤 높아서 Linux_exploit_suggester등으로 날먹 권한 상승을 할 수 있을 것 같지는 않으므로 루트 권한으로 실행되고 있는 프로세스의 취약점을 이용해보자.

ps -aux | grep root

다음과 같은 명령어로 루트 프로세스를 출력할 수 있다.

 

 

 

 

 

차근차근 살펴보면 수상한게 몇가지 보이긴한다. 찾아보면 snapd라는데 권한 상승 취약점이 있다고는 하는데, sudo -l  명령어를 치면 /opt/remote-manage.py를 패스워드 없이 실행할 수 있다고 힌트를 주니 이쪽을 살펴보자.

user@forge:/opt$ cat remote-manage.py
#!/usr/bin/env python3
import socket
import random
import subprocess
import pdb

port = random.randint(1025, 65535)

try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('127.0.0.1', port))
    sock.listen(1)
    print(f'Listening on localhost:{port}')
    (clientsock, addr) = sock.accept()
    clientsock.send(b'Enter the secret passsword: ')
    if clientsock.recv(1024).strip().decode() != 'secretadminpassword':
        clientsock.send(b'Wrong password!\n')
    else:
        clientsock.send(b'Welcome admin!\n')
        while True:
            clientsock.send(b'\nWhat do you wanna do: \n')
            clientsock.send(b'[1] View processes\n')
            clientsock.send(b'[2] View free memory\n')
            clientsock.send(b'[3] View listening sockets\n')
            clientsock.send(b'[4] Quit\n')
            option = int(clientsock.recv(1024).strip())
            if option == 1:
                clientsock.send(subprocess.getoutput('ps aux').encode())
            elif option == 2:
                clientsock.send(subprocess.getoutput('df').encode())
            elif option == 3:
                clientsock.send(subprocess.getoutput('ss -lnt').encode())
            elif option == 4:
                clientsock.send(b'Bye\n')
                break
except Exception as e:
    print(e)
    pdb.post_mortem(e.__traceback__)
finally:
    quit()
user@forge:/opt$

일단 열어보면 다음과 같은 코드가 나온다. 일단 '/usr/bin/python3 /opt/remote-manage.py' 명령어로 실행해주자. 위에 소스를 보면 알 수 있듯이 바로 포트를 출력해주니 따로 스캔할 필요없이 nc로 접속해보면 된다. 방화벽이 포트를 허용해주지 않아서 로컬로만 접속할 수 있는 것 같으니 터미널을 하나 더 켜서 ssh 연결을 해준 다음 nc localhost [포트] 명령어로 접속해주자.

 

이제 위 소스에서 취약점을 찾고 이를 악용하여 root 권한을 획득하면 된다. 이제까지 메모리 커럽션 관련 취약점만 공부해본터라 이런 파이썬 소스에서 취약점을 찾아내는 방법을 당연히 몰라서(....) 검색해보니 생각보다 매우 간단하였다. 취약한 부분은 바로 option에서 비정상 입력 값에 대한 예외처리를 해줄때 파이썬 디버거를 실행해준다는 것인데 파이썬 디버거에서는 파이썬 코드를 실행할 수 있다(...)

 

 

 

 

PDB 취약점

nc로 접속한 터미널에서 아무 문자열이나 입력하여 예외처리가 발생하게 해주면 이렇게 파이썬 소스를 실행한 터미널에서 파이썬 디버거가 실행되는데 여기서 그냥 os 모듈을 import하고 system 함수를 실행해버리면 루트 권한의 쉘을 얻을 수 있게된다....