XSS-1 소스코드
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
#!/usr/bin/python3
from flask import Flask, request, render_template
from selenium import webdriver
import urllib
import os
app = Flask(__name__)
app.secret_key = os.urandom(32)
try:
FLAG = open("./flag.txt", "r").read()
except:
FLAG = "[**FLAG**]"
def read_url(url, cookie={"name": "name", "value": "value"}):
cookie.update({"domain": "127.0.0.1"})
try:
options = webdriver.ChromeOptions()
for _ in [
"headless",
"window-size=1920x1080",
"disable-gpu",
"no-sandbox",
"disable-dev-shm-usage",
]:
options.add_argument(_)
driver = webdriver.Chrome("/chromedriver", options=options)
driver.implicitly_wait(3)
driver.set_page_load_timeout(3)
driver.get("http://127.0.0.1:8000/")
driver.add_cookie(cookie)
driver.get(url)
except Exception as e:
driver.quit()
# return str(e)
return False
driver.quit()
return True
def check_xss(param, cookie={"name": "name", "value": "value"}):
url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
return read_url(url, cookie)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
return param
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param")
if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
memo_text = ""
@app.route("/memo")
def memo():
global memo_text
text = request.args.get("memo", "")
memo_text += text + "\n"
return render_template("memo.html", memo=memo_text)
app.run(host="0.0.0.0", port=8000)
|
cs |
XSS-1 풀이
flask로 구현된 웹 사이트를 볼 수 있다.
16번째 줄을 보면 read_url 함수는 driver를 통해서 방문하는 사용자가 구현되어있는 것을 알 수 있다.
42번째 줄도 보면 check_xss라는 함수가 urllib.parse.quote를 통해서 파라미터를 넘겨주는 것을 알 수 있다.
그 후 바로 read_url을 호출한다.
58번째 줄에 /flag가 있는데, 메소드는 GET과 POST고 GET일 때, html 리턴하고 POST일 때, 파라미터를 받아서, check_xss에 flag를 넣고 호출해준다.
앞에 not이 붙었으니 함수가 true를 리턴하면 false가 되고 good이 출력된다. 아니라면 wrong이 출력된다.
flag에 들어가보았다. 입력받은 값을 파라미터로 넘겨주는 걸 알 수 있다.
vuln에 파라미터로 넘겨준 값이 <script> alert(1)</script>인데 그냥 아무런 필터링 없이 script가 실행되는 것을 볼 수 있다. 이를 통해서 Reflected XSS가 가능하다고 추측할 수 있다.
개발자 도구에서 본 모습이다.
처음에 파라미터로 hello를 넘겨주고 <script>를 써도 동작하지 않는다.
그렇다면 flag를 통해서 document.cookie의 내용을 memo의 파라미터로 넘겨주도록 한다면, flag의 값을 얻을 수 있을 것이다.
<script> document.location.href='/memo? memo='+document.cookie </script>를 파라미터로 넘겨주면 아래처럼 뜬다.
flag 값을 알 수 있다.
XSS-2 소스코드
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
#!/usr/bin/python3
from flask import Flask, request, render_template
from selenium import webdriver
import urllib
import os
app = Flask(__name__)
app.secret_key = os.urandom(32)
try:
FLAG = open("./flag.txt", "r").read()
except:
FLAG = "[**FLAG**]"
def read_url(url, cookie={"name": "name", "value": "value"}):
cookie.update({"domain": "127.0.0.1"})
try:
options = webdriver.ChromeOptions()
for _ in [
"headless",
"window-size=1920x1080",
"disable-gpu",
"no-sandbox",
"disable-dev-shm-usage",
]:
options.add_argument(_)
driver = webdriver.Chrome("/chromedriver", options=options)
driver.implicitly_wait(3)
driver.set_page_load_timeout(3)
driver.get("http://127.0.0.1:8000/")
driver.add_cookie(cookie)
driver.get(url)
except Exception as e:
driver.quit()
# return str(e)
return False
driver.quit()
return True
def check_xss(param, cookie={"name": "name", "value": "value"}):
url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
return read_url(url, cookie)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/vuln")
def vuln():
return render_template("vuln.html")
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param")
if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
memo_text = ""
@app.route("/memo")
def memo():
global memo_text
text = request.args.get("memo", "")
memo_text += text + "\n"
return render_template("memo.html", memo=memo_text)
app.run(host="0.0.0.0", port=8000)
|
cs |
XSS-2 풀이
전체적으로 코드는 XSS-1과 비슷하다. 53번째 줄 vuln가 조금 바뀌었다.
vuln에 파라미터를 저렇게 넘겨줘도 아예 작동을 안 한다.
개발자 도구를 통해 본모습이다.
아까와는 다르게 뭐가 조금 추가된 모습이다.
아마 추가된 것들이 스크립트 실행을 막고 있는 것 같다.
memo는 넘겨준 파라미터대로 잘 작동되는 모습을 볼 수 있다.
/flag에서 <img src='' onerror = location.href='/memo? memo='+document.cookie>를 파라미터로 넘겨주었다.
flag를 얻을 수 있다.
xss-game level 1
간단하다. 그냥 script태그 열어주고 alert(1)을 썼다.
xss-game level 2
올려주고 새로고침 하면 풀린다. <script> 태그가 필터링되어있어서 img와 onerror를 사용했다.
xss-game level 3 풀이
코드는 아래 적혀있다. 보면 fragment뒤에 숫자가 바뀌면 그림도 바뀐다.
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
|
<!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>
|
cs |
20번째 줄을 보면 num은 window.location.hash인데 window.location.hash를 찾아봤다.
fragment가 num에 들어간다.
16번째 줄부터 보면 num이 숫자인지 아닌지 판단도 안 하고 그냥 바로 냅다 parseInt를 하는 것을 볼 수 있다.
그래서 asdf를 fragment로 넘겨주면 Nan(not a number)가 리턴되는 것을 볼 수 있다.
17번째 줄을 보면 이상한 문자열 처리가 있다.
<img src='/static/level3/cloud문자열.jpg'> 이런 식으로 결합된다.
문자열을 'onerror=alert(1) '이런 식으로 넣어준다면 <img src='/static/level3/cloud'onerror=alert(1) '. jpg'>이렇게 될 것이다. 그리고 띄어쓰기를 해줘서 '. jpg'가 무시되도록 했다.
XSS challenge stage #1
그냥 이것도 script 태그를 써서 풀었다.
XSS Filtering Bypass - 소스코드
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
#!/usr/bin/python3
from flask import Flask, request, render_template
from selenium import webdriver
import urllib
import os
app = Flask(__name__)
app.secret_key = os.urandom(32)
try:
FLAG = open("./flag.txt", "r").read()
except:
FLAG = "[**FLAG**]"
def read_url(url, cookie={"name": "name", "value": "value"}):
cookie.update({"domain": "127.0.0.1"})
try:
options = webdriver.ChromeOptions()
for _ in [
"headless",
"window-size=1920x1080",
"disable-gpu",
"no-sandbox",
"disable-dev-shm-usage",
]:
options.add_argument(_)
driver = webdriver.Chrome("/chromedriver", options=options)
driver.implicitly_wait(3)
driver.set_page_load_timeout(3)
driver.get("http://127.0.0.1:8000/")
driver.add_cookie(cookie)
driver.get(url)
except Exception as e:
driver.quit()
# return str(e)
return False
driver.quit()
return True
def check_xss(param, cookie={"name": "name", "value": "value"}):
url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
return read_url(url, cookie)
def xss_filter(text):
_filter = ["script", "on", "javascript"]
for f in _filter:
if f in text.lower():
text = text.replace(f, "")
return text
@app.route("/")
def index():
return render_template("index.html")
@app.route("/vuln")
def vuln():
param = request.args.get("param", "")
param = xss_filter(param)
return param
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param")
if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
memo_text = ""
@app.route("/memo")
def memo():
global memo_text
text = request.args.get("memo", "")
memo_text += text + "\n"
return render_template("memo.html", memo=memo_text)
app.run(host="0.0.0.0", port=8000)
|
cs |
XSS Filtering Bypass - 풀이
46번째 줄을 보면 script, on, javascript를 필터링하고 있는 것을 확인 할 수 있다.
그래서 파라미터로 <img src='' oonnerror=locatioonn.href='/memo?memo='+document.cookie>를 넣어주면 on이 ""로 replace되면서 /memo에 쿠키 값을 기록해 줄 수 있다.
플래그를 얻을 수 있다.
Webhacking.kr old - 23번
<script>alert(1)</script>를 입력했다.
no hack이라고 뜨는 것을 확인할 수 있다.
a를 넣었더니
그대로 출력이 되고,
aa를 넣었더니 no hack이라고 뜬다.
%0A를 통해서 공백을 넣어줬더니 제대로 출력이 된다.
연속된 문자가 나오면 필터링이 되는 것을 확인할 수 있다.
NULL byte injection을 이용할 것이다. C에서 NULL byte즉 \0는 문자열의 끝을 나타낸다. 이것을 이용해 공격하는 기법이 NULL byte injection이다.
url 인코딩을 통해서 %00을 입력하면 \0을 삽입할 수 있다.
그래서 %00<%00s%00c%00r%00i%00p%00t%00>%00a%00l%00e%00r%00t%00(%001%00)%00<%00/%00s%00c%00r%00i%00p%00t%00>%00 를 파라미터로 보내주면 풀 수 있다.
'Layer7 동아리 과제' 카테고리의 다른 글
웹 해킹 6차시 과제 (0) | 2022.05.19 |
---|---|
웹 해킹 4차시 과제 (0) | 2022.05.16 |
웹 해킹 2차시 과제 (0) | 2022.05.08 |
C 4차시 과제 (0) | 2022.04.16 |
C 3차시 과제 (0) | 2022.04.12 |