펜테스트짐


훈련을 통해 당신의 실력을 향상시켜보세요.



Stored XSS (저장된 XSS)

모두 28명의 회원님이 완료했어요.


 실습 환경

  실습을 하시려면 로그인이 필요합니다.

이번 훈련에서는 저장된 XSS(Stored XSS)에 대해 알아본 후 실습을 통해 취약점을 식별하고 테스트하는 방법에 대해 학습합니다.





저장된 XSS란?


저장된 XSS(Stored XSS)는 사용자의 입력값이 웹 애플리케이션의 데이터베이스나 파일 등의 저장소에 저장되어 있다가 이 저장된 입력값이 응답에 안전하지 않은 방식으로 포함될 때 발생합니다. 악성 스크립트 주입을 위한 "저장" 요청(공격자가 수행)과 실질적인 피해를 유발하는 행위의 "조회" 요청(피해자가 수행), 2개의 요청이 요구되므로 다른 말로 Second Order XSS 라고 하기도 합니다. 저장된 XSS의 예로는 취약한 게시판을 생각하시면 이해하기 쉽습니다. 어떤 웹 애플리케이션에 구현되어 있는 게시판은 게시글을 등록할 때 사용자의 입력값에 대해 유효성 검증이나 위생 처리를 하지 않으며 등록된 게시글을 조회할 때도 게시글에 포함된 유해한 문자에 대해 위생 처리를 하지 않는다고 생각해봅시다.

먼저 공격자는 아래 그림과 같이 write_board.php라는 게시글 등록 화면에서 악성 스크립트가 포함된 글을 등록합니다.


게시글 등록 화면 (write_board.php)


이제 공격자는 다른 사용자가 해당 게시글을 조회하길 기다립니다. 마침내 한 사용자가 해당 게시글을 조회(view_board.php)하게 되면 사용자의 브라우저에서 게시글에 포함된 악성 스크립트가 실행되게 됩니다. 


악성 게시글을 조회할 때 스크립트가 실행된 화면 (view_board.php)


저장된 XSS는 말씀드렸다시피 악성 스크립트가 웹 애플리케이션의 데이터베이스나 파일시스템 내에 저장되어 있으므로 해당 게시글을 조회하는 다수의 사용자에게 지속적으로 영향을 줄 수 있습니다. 그래서 Persistent XSS(영구 XSS)라고도 부르죠. 만일 취약한 웹 페이지가 사용자의 인증을 요구하는 페이지라면 쿠키로 전송되는 세션 토큰을 탈취할 수 있으므로 반사된 XSS 보다 심각한 취약점으로 간주됩니다. 또한 반사된 XSS는 다른 사용자가 악성 URL을 클릭하도록 유도하기 위해 메일이나 SNS, 메신저 등을 통해 URL을 유포하는 등 공격자의 추가적인 노력이 필요한 반면 저장된 XSS는 사용자의 자발적인 접근을 통해 저장되어 있던 악성 스크립트가 실행되므로 공격자는 그저 기다리기만 하면 됩니다. 만일 관리자 계정으로 로그인된 사용자가 악성 스크립트가 포함된 게시글을 클릭한다면 웹 애플리케이션을 통째로 공격자에게 갖다 바치는 것과 다를 게 없는 셈입니다. 


저장된 XSS 테스트 방법


저장된 XSS가 자주 발견되는 웹 애플리케이션의 기능은 게시판이나 회원 프로필 조회 화면입니다. 이러한 기능들은 주로 POST 메소드와 HTML 폼 태그(<form>...</form>)를 이용해 게시판에 새 글을 작성하거나 수정할 수 있고, 프로필 정보를 수정할 수 있습니다. POST 요청을 통해 웹 애플리케이션으로 전달된 사용자 입력값은 웹 서버의 데이터베이스나 파일시스템에 저장된 후 다른 요청의 응답에서 해당 입력값이 표시됩니다. 즉, 일반적으로 테스터는 페이로드를 서버로 전달하는 요청과 저장된 페이로드가 응답에 그대로 표시되는 두 개 이상의 요청을 파악해야 할 필요가 있습니다.


Step 1. 사용자 입력이 웹 서버에 저장되는 요청 식별

사용자 입력이 가능한 진입점(Endpoint) 중 사용자 입력값이 웹 서버의 데이터베이스나 파일시스템에 저장되는 요청을 찾습니다. 우선 매개변수를 가진 POST 요청을 살펴보는 것이 좋습니다. 웹 개발자들은 사용자에게 데이터를 입력받아서 저장, 수정, 삭제하는 기능을 구현할 때 주로 POST 메소드를 사용하기 때문입니다. 


Step 2. 테스트 문자열 보내기 

Step 1에서 찾은 요청을 이용하여 웹 애플리케이션에서 사용되지 않을 법한 무해하고 고유한 테스트 문자열을 매개변수의 값으로 지정하여 다시 요청합니다. 예를 들면 아래와 같습니다. 

xsstestpayload


Step 3. 테스트 문자열이 응답 내에 표시되는 모든 진입점(Endpoint) 식별

저장되었던 테스트 문자열이 표시되는 응답을 찾기 위해 웹 애플리케이션의 컨텐츠나 기능을 다시 살펴 봅니다. 테스트 문자열을 저장하기 위해 사용된 매개변수의 성격이나 용도를 생각해보고 웹 애플리케이션에서 이와 관련이 있을 것으로 판단되는 웹 페이지나 기능들을 중심으로 다시 점검해봅니다. 예를 들면, 회원 프로필 수정과 같은 기능에서 등록된 사용자명은 웹 애플리케이션 상단에 현재 로그인된 사용자명을 표시하거나 회원 프로필 조회 또는 게시판 등의 글 목록 등에도 표시될 수 있으며 소개 메세지 같은 경우에는 회원 프로필 조회 등의 웹 페이지에서 다시 웹 페이지에 표시될 수 있습니다. 


Step 4. 테스트 문자열이 표시된 위치의 응답 소스코드 분석

테스트 문자열이 응답에 표시되는 진입점(Endpoint)를 찾았다면 응답 내에서 입력값이 포함된 위치가 원시 HTML 영역에 있는지, HTML 태그 내부의 속성값으로 포함되는지, 자바스크립트 내부에 포함되는지 등을 파악하기 위해 소스코드를 분석합니다. 이 위치에 따라 사용될 페이로드의 유형이 달라집니다.


Step 5. 입력값으로 스크립트를 전달

테스트 문자열이 응답에 다시 표시되는 위치에 대한 분석이 끝났다면 1번 단계에서 식별한 요청에 테스트 문자열 대신 적절한 XSS 테스트 스크립트를 지정(XSS 기초 훈련을 참고)하여 웹 애플리케이션으로 다시 요청해봅니다.  

  더 읽어보세요.


Step 6. 스크립트 실행 여부 확인

이제 Step 3에서 식별되었던 테스트 문자열이 응답으로 표시되었던 진입점(Endpoint)들을 방문해보고 입력값으로 전달했던 스크립트가 정상적으로 실행되는지 확인합니다. 스크립트가 실행된다면 저장된 XSS에 취약한 것 입니다. 스크립트에 포함된 꺽쇠괄호(< 또는 >)나 쌍따옴표("), 홑따옴표(') 등의 일부 문자가 삭제되거나 인코딩 또는 이스케이프 처리되어 스크립트가 실행되지 않는다면 방화벽이 동작 중이거나 자체적으로 구현된 필터링이 구현되어 있을 가능성이 높습니다.  


Step 7. 방어 필터로 인한 실패 시 방화벽 식별 또는 필터의 패턴 분석

방화벽이나 입력값/출력값 필터링에 의해 실패하는 경우 필터링 패턴을 조사하고 분석하여 우회를 시도해야 합니다.


실습 문제 풀이


혹시 위의 가상 실습 환경을 생성하여 실습을 먼저 해보셨나요? 아직 해보지 않으셨다면 아래 내용을 읽어보시기에 앞서 직접 실습해보시는 것을 권장합니다. 아래에 설명된 방법 외에 다른 다양한 방법으로 스크립트 실행이 가능할 수도 있습니다. 먼저 실습을 해보신 후 자신의 풀이 방법을 아래에 설명된 풀이 방법과 비교해보세요. 


Exercise 1

이 문제에서는 저장된 XSS에 취약한 공지사항 게시판이 제공됩니다. 사용자는 게시판에 새로운 글을 등록할 수 있으며, 등록된 글은 데이터베이스 등의 서버의 백엔드 데이터 저장소에 저장되었다가 사용자가 공지사항 게시판을 방문할 때 화면에 다시 출력됩니다. 



참고 문헌