먼저 난이도는 Low로 설정한다.
그리고 왼쪽 메뉴에서 XSS (Stored)를 선택한다.
그럼 다음과 같은 화면이 나타난다.
Stored XSS는 웹 페이지의 게시판 같은 곳을 주로 공략한다.
게시판을 통해 악성 스크립트를 서버에 저장하고 사용자가 이 곳을 방문하면 실행되도록 한다.
1. Low 레벨에서의 Stored XSS 공격
게시판에 다음과 같이 입력하자.
Name은 아무거나 입력하면 된다. 필자는 stored XSS로 입력했다.
Message에는 악성 스크립트를 넣으면 된다.
아래 세 개 중 하나를 선택해 넣어보자.
스크립트에 대한 설명은 이전에 남긴 Reflected XSS 게시물을 참고하자.
<script>alert(document.cookie) |
<img src=x onerror=alert(document.cookie)> |
<svg/onload=alert(document.cookie)> |
정상적으로 입력했다면 다음과 같이 쿠키값이 나온다.
2. Medium 레벨에서의 Stored XSS 공격
Medium 레벨에서는 Low와 같은 방식으로는 공격이 실패해 버린다.
소스를 보면서 이유를 탐색해 보자.
메세지 입력 부분에 다음과 같은 함수가 있다.
$message = htmlspecialchars( $message );
앞서 Reflected XSS 포스팅을 보신 분은 알겠지만
htmlspecialchars 함수는 특수문자를 HTML 엔티티로 변화시킨다.
따라서 특수문자를 사용해야 하는 악성 스크립트를 일반 텍스트로 인식해버리는 것이다.
하지만 아직 헛점이 있다.
Name 입력 부분에 존재하는 악성 스크립트 차단 소스를 보자.
$name = str_replace( '<script>', '', $name );
이 경우 <script>라고 정직하게 입력하는 악성 스크립트는 공백으로 치환되어 차단해 버리지만
다른 스크립트는 차단할 수 없다.
악성 스크립트를 Message가 아닌 Name에 입력해 보자.
<SCRIPT>alert(document.cookie)</script> |
<s<script>cript>alert(document.cookie)</script> |
<img src=x onerror=alert(document.cookie)> |
<svg/onload=alert(document.cookie)> |
그런데 한 가지 문제가 있다.
Name에는 입력할 수 있는 글자 수가 제한이 되어 있는 것이다.
이럴 때는 다음과 같은 방법을 써 보자.
크롬에서 Name의 입력창에서 오른쪽 버튼을 클릭하면 다음과 같은 메뉴가 나온다.
여기서 '검사'를 클릭하자.
그럼 다음과 같은 창이 뜬다.
해당 홈페이지의 소스를 볼 수 있다.
Name 입력창에 마우스를 가져다 대면 다음과 같은 모습을 볼 수 있다.
소스 중 빨간 창이 Name과 관련된 부분이다.
우리가 수정해야 할 곳은 이 곳이다.
<input name="txtName" type="text" size="30" maxlength="10">
여기서 maxlength의 값을 100으로 바꾼다.
이제 Name에 글자 수 제한 없이 입력할 수 있다.
위에 있는 공격 방법을 하나씩 넣어 보자.
공격이 성공하는 것을 볼 수 있다.
3. High 레벨에서의 Stored XSS 공격
공격을 하기 전에 High 레벨의 소스를 먼저 보자.
다른 부분은 비슷한데 이 부분이 변했다.
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
이제 Name에 대문자로 <SCRIPT>를 입력하거나 이중으로 script를 입력하는 방법은 통하지 않는다.
하지만 여전히 이미지와 관련된 공격 방식은 통한다.
<img src=x onerror=alert(document.cookie)> |
<svg/onload=alert(document.cookie)> |
Medium 단계와 마찬가지로 Name에 악성 스크립트를 입력해 보자.
아래와 같이 성공하는 것을 볼 수 있다.
4. Impossible 레벨에서의 Stored XSS 공격
Impossible 레벨의 소스를 보자.
$message = stripslashes( $message ); $message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error(" [MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $message = htmlspecialchars( $message ); $name = stripslashes( $name ); $name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); $name = htmlspecialchars( $name ); |
High레벨과는 다르게 Impossible 레벨에서는
Name 입력창에도 htmlspecialchars 함수를 사용해 방어하고 있다는 것을 볼 수 있다.
이 단계에서는 Stored XSS 공격이 통하지 않는다.
'모의 해킹' 카테고리의 다른 글
[웹 해킹] 6. 반사형 XSS(Reflected XSS) 공격과 방어 (0) | 2024.07.07 |
---|---|
[웹 해킹] 5. 크로스 사이트 스크립팅(XSS) 개요 (0) | 2024.07.05 |
[웹 해킹] 4. SQL Injection 방어_Prepared Statements (0) | 2024.07.02 |
[웹 해킹] 3. SQL Injection 공격 (0) | 2024.06.28 |
[웹 해킹] 2. DVWA 보안 난이도 조정하기 (0) | 2024.06.26 |