安全圈 | 专注于最新网络信息安全讯息新闻

首页

攻擊scrapyd爬蟲

作者 strmiska 时间 2020-02-27
all

類似我一貫的做法,這次Real World CTF我出了一道實戰性的題目,目標仍然是getshell。

我們以滲透測試的步驟來審視這道題目。

0x01資訊蒐集

與我以往的題目不同的是,這次雖然我自己寫了一部分程式碼,但是這部分程式碼的目的是串聯起幾個服務,整個流程與程式碼漏洞無關,所以沒有給出原始程式碼。

目標是一個簡單的web,描述是“Use crawlbox to get all links from a page”,輸入一個URL,稍等片刻可以獲取這個頁面裏所有的連結,後端應該是一個爬蟲:

我們抓取一下這個“爬蟲”的請求:

可見其User-Agent是Scrapy/ChromeHeadless(+https://scrapy.org)。從其中獲取到了兩個資訊:

Scrapy/ChromeHeadless (+https://scrapy.org)

scrapy是python下的一款非常流行的爬蟲框架,猜測用戶輸入的URL被交給scrapy執行,而scrapy中使用了Chrome對URL進行訪問並獲取結果。

關注到這一點,我們可以瀏覽一下scrapy這個工具的首頁:

其中提到部署爬蟲可以部署到scrapyd,在檔案中也提到了這一點:https://docs.scrapy.org/en/latest/topics/deploy.html。

思考,作為一個Web服務,如果要調用scrapy爬蟲爬取資訊,無非有兩種方法:

那麼,如何分辨目標使用了哪種方法調用scrapy呢?

方法也很容易想到:我們可以嘗試探測本地或內網中是否有開啟scrapyd服務的埠。打開scrapyd的檔案(https://scrapyd.readthedocs.io/en/latest/overview.html#webui),可知scrapyd默認開放在6800埠。

最簡單的方法,我們直接用目標提供的爬蟲功能進行探測(需要用xip.io簡單繞過一下SSRF的檢測):

xip.io

顯然,本地6800埠是開啟的,可以確定後端是scrapyd。

如果你完全沒注意到User-Agent中的scrapy,題幹中的“I wrote a secure crawler on top of a browser,which you can use to crawl all the links on a website”也提到了瀏覽器,你也可以完全將這裡理解為一個XSS盲打漏洞。

於是,我們可以利用XSS中的一些技巧,如:獲取內網地址、對內網服務進行掃描、獲取User-Agent、Cookie、LocalStorage等資訊,進而也能獲取到User-Agent中的scrapy,或者發現6800埠這樣的敏感服務。

如果你閱讀檔案或者掃描到了6023埠,這也是曾經一個可以攻擊scrapy的埠。scrapy在啟動掃描期間會開放6023埠作為Telnet Console,通過這個埠可以直接執行任意Python程式碼。在1.5.2後,scrapy官方修復了這個問題,詳見https://docs.scrapy.org/en/latest/news.html#scrapy-1-5-2-2019-01-22。

0x02如何攻擊scrapyd

一頓資訊蒐集後,目標整個工作流程就清晰了:用戶輸入的URL被交給部署在scrapyd上的爬蟲進行爬取,爬蟲調用了Chrome渲染頁面,並將結果中的連結返回給用戶。

那麼,這裡重點就是scrapyd了。我們需要閱讀scrapyd的檔案,方便理解這個項目的工作流程。通過檔案可知,scrapy是一個爬蟲框架,而scrapyd是一個雲服務,用戶可以將自己用scrapy框架開發的爬蟲上傳到雲端,然後通過Web API調用這個爬蟲爬取資訊。

scrapyd主要提供以下一些API:

簡單來說,scrapyd雲服務下可以有多個項目,每個項目下可以有多個程式碼版本,每個程式碼版本就是一個完整的scrapy項目,一個scrapy項目下可以有多個spider,最終執行的任務的載體是一個spider。

那麼,也就是說,攻擊者可以創建一個項目,並部署他自己的scrapy程式碼版本,將惡意程式碼部署到雲端,進而對scrapyd雲端進行攻擊。

根據這個思路,我們先在本地進行測試。

安裝並啟動scrapyd:

啟動後訪問http://127.0.0.1:6800即可看到主頁:

http://127.0.0.1:6800

此時雲端沒有項目:

然後,我們本地再安裝scrapy框架,並創建一個scrapy項目:

生成了項目後,我們在evil/__init__.py中加入惡意程式碼:

evil/__init__.py

然後,我們用scrapyd-client這個工具,將項目打包成egg包。當然也可以自己用setuptools手工打包。

此時,惡意的egg包已經生成,然後我們將其部署到雲端:

成功部署:

此時,touch success已成功執行:

touch success

0x03利用CSRF漏洞攻擊瀏覽器爬蟲

針對6800埠的攻擊在本地可以複現了,但是目標網站的6800是開啟在內網的,我們無法直接訪問。

可以借助目標前端的那個SSRF嗎?不行,因為這只是一個GET型的URL請求,無法發送POST包部署程式碼。

不過,因為這個URL是被瀏覽器執行的,而scrapyd的所有API介面實際上都是可以進行CSRF攻擊的,所以我們可以利用頁面中的JavaScript發送POST數据包給6800埠,進而調用那些非GET型的API。

構造一個向http://127.0.0.1:6800/addversion.json發送POST上傳請求的頁面:

http://127.0.0.1:6800/addversion.json

值得注意的是,因為我們要上傳一個二進位檔案,所以我將evil.egg進行的base64編碼:cat evil.egg | base64,然後將其轉換成JavaScript中的Blob對象,添加到FormData中。

cat evil.egg | base64

將這個頁面提交給爬蟲進行爬取,成功完成整個利用過程。

0x04總結

首先吐槽一下scrapy這個框架,真是盛名之下其實難副,雖然說到爬蟲必然會說到這個框架,但實際上不管是從其生態、檔案、程式碼等角度看待這個項目,都是無法和Python下另一個偉大的項目Django相提並論的。實際使用下來感覺其架構不合理,檔案也模糊不清,周邊生態如scrapyd、scrapyd-client更是陳舊不堪,問題很多,處於弃療狀態。

總的來說scrapy作為一個生態框架是不及格的,但聊勝於無吧,相比於手工編寫爬蟲來說還是給開發者提供了很多幫助。

另外,在MVVM架構日益流行的當下,爬蟲也變得更加靈活,特別是借助Chrome Headless或splash的爬蟲能够動態執行JavaScript這個特性,能讓爬蟲爬到的資訊更加完善,但也讓攻擊者有更多攻擊途徑。

通常來說scrapy和splash是一對標配,雖然我這次用的是Chrome,事實上沒啥太大差別。對於此類動態爬蟲,攻擊者可以對瀏覽器或js引擎本身進行攻擊,或者如我這樣利用JavaScript攻擊內網裏一些基礎服務。

另外,經常會有人在運行爬蟲的時候會設定--no-sandbox、--disable-web-security等危險選項,這也給攻擊者提供了很多便利,我建議利用普通用戶許可權啟動瀏覽器爬蟲,以避免使用這些不安全的選項。

--no-sandbox --disable-web-security

作為一個“駭客”,在開動自己掃描器的同時,也要注意這些問題了哦,不要踏進別人的蜜罐還被人反日了。