轉:Python安全 - 從SSRF到命令執行慘案

來源:互聯網
上載者:User

標籤:寫檔案   使用   研究   自己   meta   注入   long   nec   ip限制   

轉:https://www.leavesongs.com/PENETRATION/getshell-via-ssrf-and-redis.html

Python安全 - 從SSRF到命令執行慘案PHITHON 前兩天遇到的一個問題,起源是在某個資料包裡看到 url=這個關鍵字,當時第一想到會不會有SSRF漏洞。

以前烏雲上有很多從SSRF打到內網並執行命令的案例,比如有通過SSRF+S2-016漏洞漫遊內網的案例,十分經典。不過當時拿到這個目標,我只是想確認一下他是不是SSRF漏洞,沒想到後面找到了很多有趣的東西。不多(有的是後面補得),大家湊合看吧。

0x01 判斷SSRF漏洞

目標example.com,根據其中csrf_token的樣式,我猜測其為flask開發(當然也可能是一個我不太熟悉的架構使用了和flaskwtf相似的代碼):

開著代理瀏覽了一遍整個網站的功能,功能點不多,比較小眾的一個分享型網站。偶然間在資料包裡看到url=,看了一下發現是一個本地化外部圖片這麼一個功能。這種功能很容易出現兩種漏洞:

  1. SSRF漏洞
  2. XSS漏洞

SSRF漏洞就不用多說了,在拉取外部資源的時候沒有檢查URL,導致可以向內網發送請求;XSS漏洞容易被忽略,拉取到目標後儲存的時候沒有過濾特殊字元,就可能導致XSS漏洞。

簡單fuzz一下,依次訪問http://127.0.0.1:80/http://127.0.0.1:80/404404404not_foundhttp://127.0.0.1:12321/

依次返回了error和兩個500,這三個結果分別代表什嗎?

因為平時做Python開發比較多,這種500的情況也見的比較多,通常是因為代碼沒有捕捉異常導致返回500。感覺第二個可能是HTTP請求404導致拋出異常,而第三個可能是TCP串連被拒絕(12321連接埠未開放)導致拋出異常。

雖然我還沒理清目標的代碼邏輯,但我能肯定這其中存在SSRF漏洞。

0x02 雞肋redis服務?

經過簡單的測試,我發現目標網站下載外部資源後,會檢查資源類型是否是圖片,不是圖片則返回error。這樣就很尷尬了,這是一個沒有回顯的SSRF漏洞。

這時候我突然想到,既然是判斷圖片,會不會是用imagemagick組件來判斷的?然後我將imagetragick的POC儲存到外網的某個poc.gif裡,然後讓其訪問:

直接把內容返回了,沒出現error,也沒500,但命令也沒執行成功。

當時沒想清楚目標究竟是怎麼判斷圖片的,後來拿到shell以後看了源碼才知道:目標是判斷返回包的content-type,如果不是圖片就直接返回error,我想的太複雜了。

imagemagick這條路死了,我就沒再研究這塊邏輯。因為我不知道目標內網IP段,所以準備先探測一下127.0.0.1的連接埠,我列了一些常用連接埠,用Burp跑了一下:

看到6379是200的時候,我著實激動了一下,眾所周知,在滲透中遇到redis是一件很愉快的事情。

不過我很快發現,GET請求我沒法控制Redis的命令。

科普一下,Redis的協議是簡單的文字資料流,比如我可以向6379連接埠發送如下TCP流:

SET x 1SET y 2

每行代表一個命令,上述資料包執行了兩條set命令。但現在尷尬的是,普通GET請求的資料包如下:

GET / HTTP/1.1Host: example.comAccept: */*Accept-Language: enUser-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)Connection: close

我控制不了任意一行的起始部分,也就沒法自訂redis命令了,非常雞肋……

0x03 CVE-2016-5699 化腐朽為神奇

真的雞肋嗎?

去年,Python的urllib庫曾出過一個頭注入的漏洞,CVE-2016-5699( http://blog.neargle.com/SecNewsBak/drops/Python%20urllib%20HTTP%E5%A4%B4%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E.html )

因為在CTF裡有過類似的思路,所以我基本第一時間就想到了。我在外網伺服器用nc開了個連接埠,在目標web頁面傳入http://[vps-ip]%0d%0aX-injected:%20header:12345/foo,發現果然注入成功了:

有點小激動,因為之前只是聽說過這個漏洞,沒有真實案例的依託,這次真遇到了。如果我們能注入HTTP頭,也就能控制發送往Redis的資料包的某一行,這樣就能執行任意Redis命令了。

有點怕影響目標站,我先在本地搭了個類似的環境。

攻擊Redis有幾個思路,核心就在於寫檔案。在本地測試,發現了幾個巨坑:

  1. CONFIG SET dir /tmp,傳遞斜線/的時候必須進行二次編碼(%252f),否則urllib2會拋出URLError: <urlopen error no host given>的異常。
  2. url過長會導致拋出UnicodeError: label empty or too long的異常,所以我需要依次傳入CONFIG SETSAVE等幾個命令。

最後,我依次發送http://127.0.0.1%0d%0aCONFIG%20SET%20dir%20%252ftmp%0d%0a:6379/foohttp://127.0.0.1%0d%0aCONFIG%20SET%20dbfilename%20evil%0d%0a:6379/foohttp://127.0.0.1%0d%0aSET%20foo%20bar%0d%0aSAVE%0d%0a:6379/foo,最後成功在本地寫入/tmp/evil檔案。

不過目標環境就有點蛋疼了,一是完全沒有回顯,我無法知道我是否寫入成功;二是失敗原因我無法預測,有可能是redis有密碼,或redis是普通許可權,或config set命令被禁用等等。

感覺又是一個比較蛋疼和雞肋的情境。

0x04 Python還原序列化逆襲

果然線上上環境嘗試寫入cron檔案,都沒成功反彈回shell。

在這個地方卡了很久,思路一直在考慮“是否真的成功寫入檔案”這個問題,如果“成功寫入了檔案”,為什麼沒有反彈到shell;如果沒有成功寫入檔案,是不是沒有許可權,是否可以寫入python的webshell?總結起來有幾個思路:

  1. 寫入ssh key進行getshell。但掃連接埠發現似乎並沒有開放22,推測是更換了ssh連接埠並進行的IP限制,或者直接沒有運行sshd。
  2. 寫入cron嘗試反彈shell,但沒成功。也許是redis沒許可權,也許是因為目標是ubuntu或debian,這兩個系統對於cron檔案格式限制會比較嚴,很難用redis反彈shell。
  3. 寫入python的webshell,但可能也會遇到檔案格式要求過嚴導致python運行失敗,而且通常寫入python指令碼需要重啟伺服器才能奏效
  4. 寫入jinja2模板檔案,並通過模板引擎支援的文法執行命令。

總結起來,第4個方法最靠譜,因為模板檔案對格式要求不嚴,只要我需要執行的語句放在類似{{ }}的標籤中即可。但經過測試,還是有幾個問題:一是web路徑(關鍵是存放模板檔案的路徑)和模板名稱都需要猜,這個太難;二是redis如果是從源進行安裝,一般是redis使用者運行,一般無法寫入web目錄。

吃個夜宵再回來想想,我覺得首先得解決“是否真的成功寫入檔案”這個問題。後面fuzz了一下,測試了一堆目錄,發現成功在/var/www/html/static下寫入了檔案,並通過http://example.com/static/xxxfile直接可以訪問!

下載剛寫入的檔案,其實這個檔案即為redis的匯出檔案。我將之匯入到自己本地的redis環境中,又是一個驚喜:

看到這個樣式的資料,我就知道這一定是還原序列化資料,而且是Python2.7的還原序列化資料。

這裡科普一下,Python2.7和3.5預設使用的序列化格式有所區別,一般帶有括弧和換行的序列化資料是2.7使用的,而包含\x00的一般是3.5使用的。

後續利用就和 https://www.leavesongs.com/PENETRATION/zhangyue-python-web-code-execute.html 這篇文章一個套路。目標站使用redis儲存session資料,且session資料使用序列化儲存,我們可以通過還原序列化來執行任意命令。

使用python2.7構造一個執行反彈shell指令碼的序列化資料,並通過SSRF漏洞設定成session:hacker的值,然後訪問目標網站的時候設定Cookie session=hacker

不過有一點需要注意,就是SSRF時URL太長的話會拋出錯誤(之前本地測試的時候說過),所以需要曲線救國,使用redis的append命令,將資料一段一段寫入,類似於這樣:

另外還有個坑,寫入的時候,特殊字元(如換行)需要轉義:http://127.0.0.1%0d%0aAPPEND%20session:hacker%20"(S‘id‘\np1\ntp2\nRp3\n."%0d%0aSAVE%0d%0a:6379/,而且只有值被引號包裹時轉義符才能轉義,否則轉義符又會被轉義……這個把我坑了好久,差點就以為功虧一簣了。

最後感覺,挖漏洞思路還是得跳,之前一直在考慮怎麼通過redis寫檔案來進行getshell,卻沒想到通過讀取redis的備份檔案,找到了突破口。

成功反彈shell:

總結

這一次案例,出現漏洞的根本原因有幾個:

  1. Web層面出現SSRF漏洞
  2. Python版本過低,存在CVE-2016-5699頭注入漏洞
  3. Redis版本過低,新版Redis寫入的檔案許可權一般是660,可以極大程度上避免寫檔案造成的漏洞

拿到shell以後我看了下源碼,其邏輯是這樣:擷取使用者傳入的url參數,直接發送HTTP請求並拿到返回對象,判斷返回對象的Content-Type是否包含image,如果包含則離線資料並顯示出來,否則返回error。

這就導致HTTP請求一旦出現錯誤,伺服器就會拋出500,而返回error是手工判斷的結果,所以狀態代碼還是200。

另外還有個感想,我怕把目標環境搞壞了,整個過程中多次用到了本地環境進行測試,而所有本地環境都是用docker啟動的 ,非常方便。

之後我應該會類比一下這個目標,做一個vulhub環境給大家,有時間再說吧……

轉:Python安全 - 從SSRF到命令執行慘案

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.