XSS game
level 1
화면에 JS alert 창을 띄우는 문제이다. 검색창에 script 태그를 넣은 alert문을 넣어주면 해결.
level2
<a href = "javascript:alert('Hello, world!')"> alert </a>
다음 코드를 삽입하여 alert를 눌렀을 때 경고창이 뜨도록 하였다.
반면에 script태그를 바로 삽입하였을 때는 글이 사라지고 alert창이 생기지 않았는데, 이 사이트에서는 script태그를 이용한 공격을 필터링 하고 있을 가능성이 있다. (정확한 이유를 다음 코드에서 찾아보자!)
<!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" />
<!-- This is our database of messages -->
<script src="/static/post-store.js"></script>
<script>
var defaultMessage = "Welcome!<br><br>This is your <i>personal</i>"
+ " stream. You can post anything you want here, especially "
+ "<span style='color: #f00ba7'>madness</span>.";
var DB = new PostDB(defaultMessage);
function displayPosts() {
var containerEl = document.getElementById("post-container");
containerEl.innerHTML = "";
var posts = DB.getPosts();
for (var i=0; i<posts.length; i++) {
var html = '<table class="message"> <tr> <td valign=top> '
+ '<img src="/static/level2_icon.png"> </td> <td valign=top '
+ ' class="message-container"> <div class="shim"></div>';
html += '<b>You</b>';
html += '<span class="date">' + new Date(posts[i].date) + '</span>';
html += "<blockquote>" + posts[i].message + "</blockquote";
html += "</td></tr></table>"
containerEl.innerHTML += html;
}
}
window.onload = function() {
document.getElementById('clear-form').onsubmit = function() {
DB.clear(function() { displayPosts() });
return false;
}
document.getElementById('post-form').onsubmit = function() {
var message = document.getElementById('post-content').value;
DB.save(message, function() { displayPosts() } );
document.getElementById('post-content').value = "";
return false;
}
displayPosts();
}
</script>
</head>
<body id="level2">
<div id="header">
<img src="/static/logos/level2.png" />
<div>Chatter from across the Web.</div>
<form action="?" id="clear-form">
<input class="clear" type="submit" value="Clear all posts">
</form>
</div>
<div id="post-container"></div>
<table class="message">
<tr>
<td valign="top">
<img src="/static/level2_icon.png">
</td>
<td class="message-container">
<div class="shim"></div>
<form action="?" id="post-form">
<textarea id="post-content" name="content" rows="2"
cols="50"></textarea>
<input class="share" type="submit" value="Share status!">
<input type="hidden" name="action" value="sign">
</form>
</td>
</tr>
</table>
</body>
</html>
<!-- index.html -->
class MainPage(webapp.RequestHandler):
def render_template(self, filename, context={}):
path = os.path.join(os.path.dirname(__file__), filename)
self.response.out.write(template.render(path, context))
def get(self):
self.render_template('index.html')
application = webapp.WSGIApplication([ ('.*', MainPage) ], debug=False)
#level.py
/*
* Objects to implement a client-side post database.
*/
function Post(message) {
this.message = message;
this.date = (new Date()).getTime();
}
function PostDB(defaultMessage) {
// Initial message to display to users
this._defaultMessage = defaultMessage || "";
this.setup = function() {
var defaultPost = new Post(defaultMessage);
window.localStorage["postDB"] = JSON.stringify({
"posts" : [defaultPost]
});
}
this.save = function(message, callback) {
var newPost = new Post(message);
var allPosts = this.getPosts();
allPosts.push(newPost);
window.localStorage["postDB"] = JSON.stringify({
"posts" : allPosts
});
callback();
return false;
}
this.clear = function(callback) {
this.setup();
callback();
return false;
}
this.getPosts = function() {
return JSON.parse(window.localStorage["postDB"]).posts;
}
if(!window.localStorage["postDB"]) {
this.setup();
}
}
//post-score.js
level 3
이미지가 포함된 웹 페이지에서 alert 창을 띄우는 방법을 생각해보니, img 태그에 onerror 문구를 넣는 것이 생각났다.
<img src = "#" onerror = "alert('XSS 공격!');">
https://xss-game.appspot.com/level3
Oops! Based on your browser cookies it seems like you haven't passed the previous level of the game. Please go back to the previous level and complete the challenge.
xss-game.appspot.com
이런 식으로 html 변수에 img를 클릭하였을 때 alert(1)이 실행되도록 만들었으나 왜인지 뜻대로 alert가 실행되지 않았다.
window.location은 읽기 전용인 location 오브젝트를 얻어올 수 있다.
ex) alert(location); //alerts "http://blog.naver.com/mingyum119"
4번 힌트를 보고 페이지가 로드되기 전에 script 문의 변경사항을 적용시키는 방법을 생각해보았다.
https://wickedmagic.tistory.com/420
<!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" />
<!-- Load jQuery -->
<script
src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<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>
</head>
<body id="level3">
<div id="header">
<img id="logo" src="/static/logos/level3.png">
<span>Take a tour of our cloud data center.</a>
</div>
<div class="tab" id="tab1" onclick="chooseTab('1')">Image 1</div>
<div class="tab" id="tab2" onclick="chooseTab('2')">Image 2</div>
<div class="tab" id="tab3" onclick="chooseTab('3')">Image 3</div>
<div id="tabContent"> </div>
</body>
</html>
다음 index.html 코드를 보고 window.location을 중심으로 살펴보았다.
* substr(1) : 문자열을 1 인덱스까지 자른다.
* self.location.hash : URL의 # 부분 뒤에 적은 입력값을 의미한다.
* unescape 함수 : 16진수의 아스키코드 값을 라틴 문자로 바꿔준다.
이 코드를 보면 image의 num값이 url의 #뒤의 해시값으로 들어가는 것을 볼 수 있다. 그럼 url에 onerror을 붙이려면 어떻게 해야할까?
일단 script 태그 안에서 Js 구문을 넣으면 코드가 무시된다.
num변수에 우리가 원하는 값을 넣으면 되는 것인데, 입력한 num 값이 해시값이 되므로 #뒤에 onerror 태그 구문을 넣도록 한다.
self.location.hash값에 다음과 같이 입력하면
이 해시값이 num 변수에 들어가게 되고, html 변수에 저장된다.
$('#tabContent').html(html);
이 부분에서 .html 메서드를 통해 html의 내용을 가져와 탭에 구현한다.
최종적으로 만들어지는 html 변수 값은 <img src = '/static/level3/cloud1.jpg' onerror = "alert('Hello,world!'); "/>가 되고, onerror에 의해서 alert가 실행되어 XSS 공격이 먹히게 된다.
(이번 문제에서 시간이 오래 소요된 이유는 코드 해석을 정확히 하지 않아서라고 생각한다. 꼼꼼히 코드를 읽고 목적을 달성하도록 노력해야겠다. )
level 4
//index.html
<!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="level4">
<img src="/static/logos/level4.png" />
<br>
<form action="" method="GET">
<input id="timer" name="timer" value="3">
<input id="button" type="submit" value="Create timer"> </form>
</form>
</body>
</html>
페이지의 모든 부분의 내용을 정확히 'escape'해야한다고 나와있다.
//timer.html
<!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>
힌트이다.
* window.confirm() : 확인 및 취소를 선택할 수 있는 모달 대화 상자를 표시한다.
* window.history.back() : 이전 화면으로 돌아간다 .
* img onload : 이미지가 표시되는 동안 startTimer 함수를 작동시킨다
* parseint(문자열, n) : 문자열을 n진법 정수로 바꾼다.
* setTimeout(function() { //code here}, delay); : 함수를 의도적으로 지연한 뒤 실행하고 싶은 경우 사용 (지연한 시간 뒤에 함수 안의 코드 내용을 실행시킨다) + 지연시간 1000은 1초를 의미한다.
https://www.w3schools.com/w3js/w3js_display.asp
W3.JS Display HTML Data
W3.JS Display HTML Data ❮ Previous Next ❯ Display data in HTML: w3.displayObject( selector ) Easy to Use Just add brackets {{ }} to any HTML element to reserve space for your data: Example < div id ="id01" > {{firstName}} {{lastName}} < /div > Finally call w3.displayObject to display the data in yo...
www.w3schools.com
{{ time }} 부분이 무슨 의미인지 궁금하여 검색하였다. timer은 변수 이름이고 (get 방식으로 전달되며, 입력창에 적은 타이머 숫자 값을 받는다), seconds 인자로 들어가게 된다.
그 다음은 디코딩에 관한 부분이다. get방식으로 받은 timer은 디코딩되어 저장된다.
get방식으로 불러오니까 timer 뒤에 스크립트 구문을 넣어주면 될 것같다. onload구문을 보면 3을 넣었을 때 '3'의 형태로 인자가 전달되니까,
onload = startTimer('3'); alert('Hello,world!');"/> 를 입력해주기 위해서 timer에 3'); alert('Hello,world!을 넣으면 될 것같다.
넣어주니 ; 까지만 입력값을 받는 것을 알 수 있었다.
<img src="/static/loading.gif" onload="startTimer('3'); alert('Hello,world!);" />
해결!
'Other > Web Hacking' 카테고리의 다른 글
IGRUS 웹해킹 5주차 과제 webhacking-kr old.23 Write-up (0) | 2021.01.28 |
---|---|
IGRUS 웹해킹 5주차 과제 #xss #드림핵 (0) | 2021.01.28 |
IGRUS 웹해킹 4주차 과제 #PHP #워게임 (0) | 2021.01.28 |
IGRUS 웹해킹 3주차 과제 #워게임 (0) | 2021.01.28 |
IGRUS 웹해킹 2주차 과제 #워게임 (0) | 2021.01.27 |