門開了之後,O1 才知道自己搞錯了一件事。
他一直以為門是終點。你把門叩開,你就進去了,事情就結束了。
但進到屋裡,跟擁有這間屋子,是兩件完全不同的事。
他站在那間屋子裡。
能走的地方不多。廚房可以進,柴房可以進,後院的一塊地可以進。但通往樓上的那道樓梯,門是鎖的;書房的抽屜拉不開;牆上掛著的鑰匙串,他伸手去拿,手穿過去了——那串鑰匙不是給他這種身分的人看見的。
他在屋裡走了一圈,走回原地。
他是進來了。但他在這間屋子裡是個什麼都不是的人。
這種感覺他很熟。
他開始翻。
第一個翻的是門房那本值勤簿。
屋主有時候會授權底下的人代做一些事,那些授權會一條一條寫在簿子上:「此人可代為關窗」「此人可代為取柴」「此人可代為清掃前庭」。
O1 一條一條看下去。大部分都很無聊,無聊到他差點翻過去。
然後他在第三頁看到一行:
「此人可代為謄寫卷冊。」
他盯著那一行看了很久。
謄寫卷冊。這有什麼用?他又不想抄書。
他把那一行讀了三遍,正要翻過去的時候,忽然停住了。
問題不在「謄寫」。問題在「代為」。
那行字的意思是:當他坐下來謄寫的時候,他是以屋主的名義在做這件事。不是他在抄,是屋主在抄,只是手是他的。
然後他想起謄寫工具的一個特性。
那種老式的謄寫台,設計的時候考慮過抄寫員的方便——抄到一半需要人添墨、需要人取紙、需要人跑腿的時候,抄寫員可以直接從台前喚一聲,就會有人來代辦。
那是為了方便設計的。誰會覺得「喚一個人來跑腿」有什麼危險?
但如果坐在台前的那個人,此刻的名義是屋主——
那被喚來的那個人,是被屋主喚來的。
他試了六次。
前幾次的失敗都很蠢。他喚了,沒有反應;他喚錯了名字,來的人只是個看門的,什麼都做不了;他把話說得太複雜,對方聽不懂,站在那裡等他重講。
他對那張謄寫台本來就不熟。那是一種老工匠用的台子,操作有自己的一套規矩,而他連最基本的幾個手勢都是現學的。
第六次他把喚法改短,短到只剩最必要的一個詞。
有人從側邊走出來,站在他面前,等他吩咐。
O1 抬頭看了一下那個人。
那個人的腰帶上,掛著屋主的印。
他沒有立刻吩咐。
他坐在謄寫台前面,看著那個人,看了大概三十秒。
他的手在抖。
不是興奮的那種抖。是那種身體先知道了、腦子還沒承認的抖。
因為這一次,沒有人提示他。沒有看台,沒有評語,沒有誰在旁邊點他一句。從翻值勤簿開始,到讀懂「代為」兩個字,到想起謄寫台可以喚人,到第四次才把喚法縮短——每一步都是他自己想的。
一個被判定「程度還不到」的人,在凌晨兩點多,一個人,證明了他到得了。
他上了樓,拿到該拿的東西,然後下來,關掉摹室。
那時候大概三點。
他坐在桌前,第一個冒出來的念頭是:想跟人講。
他真的拿起了筆。筆尖懸在紙上的時候,他才開始想這封信要寫給誰。
雷恩?他們有一陣子沒聯絡了,而且雷恩不會知道「代為謄寫」四個字為什麼重要。
菲菲?菲菲會聽,但她會問他學到什麼,而他現在只想講他做到了。
公會?
——他把筆放下。
那張紙最後什麼都沒寫。
他把冊子翻開,翻到今天那一頁,在「代為謄寫卷冊」那一行下面,把整個過程從頭寫了一次。
寫了兩頁半。
他寫得很詳細,詳細到有點過頭——連他前五次喚錯、坐在台前重想的那一段都寫了。他一邊寫一邊知道自己為什麼要寫這麼細。
因為這是唯一會讀到這件事的地方。
冊子不會恭喜他。但冊子會留著。
他闔上冊子的時候,順手翻到了導典第一頁。那三行字還在。
他想了一下,沒有加第四行。
有些事情不用寫成規矩。
拿到 shell 只是一半。這一篇談另一半。
先給總的心法:
Linux 提權,大多數時候是在找一件「被授予了超出它應得的權限」的東西。
不是找漏洞,是找誤授權。一個指令、一個檔案、一個排程——它被賦予了以 root 身分運作的能力,而它本身沒有做好把關。
id; whoami
hostname; uname -a # 核心版本,先記著
cat /etc/os-release
sudo -l # 最高投報率的一行
ls -la /home/*; ls -la ~
ps aux --forest # 誰在跑什麼
ss -tulpn # 只綁 127.0.0.1 的內部服務
sudo -l:先跑這一行,永遠先跑這一行我第一次成功的提權就是這裡來的,而且後來回頭看,它的命中率一直是最高的。
sudo -l 會直接告訴你:這個帳號被允許以 root 身分執行哪些東西。
新手常犯的錯是看到清單上一個無害的東西就跳過。比如:
(root) NOPASSWD: /usr/bin/vi
一個文字編輯器,能幹嘛?
問題不在「vi」,問題在「以 root 身分執行 vi」。
vi/vim 為了方便,本來就有從編輯器裡執行外部指令的功能。當初用的是:shell--這個方式,就從編輯器開一個 shell 出來。
那個功能設計的時候完全合理——誰會覺得「編輯途中跑個指令」有危險?
但如果這個 vi 是以 root 身分跑起來的,它喚出來的那個 shell 也是 root。
這個邏輯適用於一大票指令:find、awk、less、more、nmap(舊版)、python、perl、tar、git……任何能夠執行外部程式、或能夠讀寫任意檔案的工具,在 sudo/SUID 之下都是一把鑰匙。
這裡一定要收藏 GTFOBins。 那是一本「哪些常見指令可以被拿來當鑰匙」的對照表,查到工具名字就有現成的利用方式。
(附帶一提:實際操作常常不會一次成功。我對 vim 本來就不熟,那次試了六次才進去——不是方向錯,是手不熟。卡住的時候先懷疑語法,不要先懷疑方向。)
find / -perm -4000 -type f 2>/dev/null
find / -perm -2000 -type f 2>/dev/null
SUID 的意思是:不管誰執行這個檔案,它都會以檔案擁有者的身分運作。
找到之後不要急著試——先確認它是不是標準的。passwd、sudo、mount 本來就有 SUID。真正有價值的是那些不該有的:一個 find、一個 vim、一個 python、或某個第三方程式。
然後一樣查 GTFOBins。sudo 和 SUID 兩條路,查的是同一本表。
這一類最不花俏,但命中率很高,我習慣排在第三順位:
cat ~/.bash_history
grep -rIn "password\|passwd\|secret\|api_key" /var/www /opt /home 2>/dev/null
ls -la /var/backups
find / -name "*.conf" -o -name "*.env" -o -name "config.php" 2>/dev/null
人會重複使用密碼。 一個 Web 應用的資料庫密碼,很可能就是某個系統帳號的密碼。
cat /etc/crontab; ls -la /etc/cron.*
cat /var/spool/cron/crontabs/* 2>/dev/null
重點不在有沒有排程,在排程執行的東西你能不能碰:
tar 而不是 /bin/tar)→ PATH 劫持:把你自己的同名執行檔放在它會先找到的目錄tar *)→ 檔名注入PATH 劫持的比喻是:屋主吩咐「去拿槌子」,但沒說哪一把,僕人會拿最先找到的那一把。你只要把自己的槌子放在他會先找到的地方。
ss -tulpn 看到只綁 127.0.0.1 的服務時,那通常是整台機器最軟的地方——因為開發者假設「只有本機能連,所以不用防」。
這也是 Day 14 借道的入口。
getcap -r / 2>/dev/null
Capabilities 是把 root 的能力切成小塊分配。cap_setuid、cap_dac_read_search 出現在不該出現的地方,就是機會。
老實說我自己排得比較後面,因為命中率不如前面幾項。但它值得留在清單上——很多人只找 SUID 就收工,這一條常常沒有人看,所以一旦有,就是沒人動過的路。
LinPEAS 之類的腳本很好用,但輸出很長,新手最常見的錯誤是「跑完,捲過去,沒看到紅色就算了」。
./linpeas.sh | tee linpeas.txt)sudo 權限、SUID、排程、憑證相關工具負責蒐集,判斷還是你的事。 它列出四十個「可能」,你要有能力看出哪三個值得試。
uname -a 的結果先記著,但核心提權放在最後手段:
1. sudo -l
2. SUID → GTFOBins
3. 翻設定檔與歷史紀錄找憑證
4. 排程(可寫腳本 / 相對路徑 / 萬用字元)
5. 內部服務
6. capabilities
7. 自動化工具補漏
8. (最後)核心
九成的機器會停在前四項。
從側門進來的人,還不算進來。