CTF/웹해킹

[CrewCTF] Cuaas - 웹해킹 / SSRF / HTTP Smuggling

SecurityMan 2022. 4. 20. 13:45

 

재밌게 풀었던 웹해킹 문제.

 

Cleaning urls as a Service 라고 하는 새로운 서비스를 개발했는데,

 

이걸 공격할 수 있냐고 물음을 던진다.

 

반응형

 

문제페이지 주소가 주어지고,

 

웹 소스파일도 같이 주어진다.

 

 

문제페이지에 접속하면 이런 화면이 나온다.

 

Clean url as a Service라고 가운데 크게 적혀있고,

 

URL을 입력하는 칸이 중간에 보인다.

 

시험삼아 www.example.com  이라고 입력해보았다.

 

그랬더니 아래쪽에 host 이름만 잘라서 example.com 이라고 출력을 해준다.

 

복잡한 URL에서 host 이름만 골라 출력해주는 서비스인듯 하다.

 

 

이번엔 www.example.tld@naver.com  이라고 입력해봤다.

 

그랬더니 출력값이 naver.com 이라고 나왔다.

 

원래 host 이름은 example.tld 가 맞지만, @로 인해서 naver.com 이 host로 인식이 되는것이다.

 

이게 왜 이렇게 되냐면, 이메일 주소를 생각하면 쉽다.

 

이메일 주소를 보면 myname@gmail.com 처럼 앞에는 계정명이 오고 뒤에는 host 이름이 오게된다.

 

위 경우에서 example.tld 가 계정명처럼 인식이되고,

 

@ 뒤에있는 naver.com 이 host 이름으로 인식되어서 저렇게 출력된 것이다.

 

이걸 활용하여 SSRF(Server Side Request Forgery) 공격을 수행할 수 있다.

 

<?php
if($_SERVER['REQUEST_METHOD'] == "POST" and isset($_POST['url']))
    {
        clean_and_send($_POST['url']);
    }

	function clean_and_send($url){
			$uncleanedURL = $url; // should be not used anymore
			$values = parse_url($url);
			$host = explode('/',$values['host']);
			$query = $host[0];
			$data = array('host'=>$query);
			$cleanerurl = "http://127.0.0.1/cleaner.php";
   			$stream = file_get_contents($cleanerurl, true, stream_context_create(['http' => [
			'method' => 'POST',
			'header' => "X-Original-URL: $uncleanedURL",
			'content' => http_build_query($data)
			]
			]));
    			echo $stream;
			}
?>

 

문제에서 주어진 index.php 의 코드를 살펴보자.

 

사용자의 입력을 POST 메소드로 받아 url 변수에 담는다.

 

입력받은 url에서 host 부분만 잘라서 data 변수에 담아주고,

 

http://127.0.0.1/cleaner.php 요청메세지를 보낸다.

 

그리고나서 돌아온 응답을 echo $stream 으로 보여주게 된다.

 

<?php

if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){

die("<img src='https://imgur.com/x7BCUsr.png'>");

}

echo "<br>There your cleaned url: ".$_POST['host'];
echo "<br>Thank you For Using our Service!";

function tryandeval($value){
                echo "<br>How many you visited us ";
                eval($value);
}

foreach (getallheaders() as $name => $value) {
	if ($name == "X-Visited-Before"){
		tryandeval($value);
}}
?>

 

위 부분은 cleaner.php 의 소스코드이다.

 

맨 처음에 ip 주소로 접근제한이 걸려있는걸 볼 수 있다.

 

127.0.0.1이 아닌 외부에서의 접근은 불가능하도록 해놓았다.

 

다음으로 메인페이지에서 봤던 host 이름을 출력해주는 부분이 보이고(echo)

 

맨 아래쪽에는 패킷의 헤더를 검사해서 헤더 중 "X-Visiied-Before" 라는 헤더가 있다면

 

value를 tryandeval 함수로 전달해준다.

 

trayandeval 함수에서는 전달받은 value를 eval 해주는 기능을 가지고 있다.

 

 

Burp Suite 라는 프록시 도구를 이용해서 요청/응답 패킷을 캡쳐해봤다.

(도구설치법 : https://hackingstudypad.tistory.com/72)

 

아까 문제페이지와 소스코드에서 본것처럼

 

url 변수로 http://example.com 을 전달하면 왼쪽 처럼 host 이름인 example.com 이 출력되는걸 볼 수 있다.

 

 

이것저것 테스트해보다가 신기한걸 발견했는데

 

url 변수에 http://example.com 을 넣어주고, 그뒤에 @를 적은다음

 

위에 있는 POST 요청 패킷을 @ 뒤에 그대로 복사/붙혀넣기 해봤다.

 

그랬더니 왼쪽에 원래 출력되야하는 There your cleaned url 이라는 메세지가 뜨지 않고,

 

저렇게 알 수 없는 문자들이 출력되는것이 보였다.

 

이렇게 요청 패킷을 조작하여 공격하는 방식을 HTTP Smuggling 이라고 부른다.

 

이제 공격 벡터를 알아냈으니 본격적으로 exploit을 시도해본다.

 

 

이번엔 GET 메소드를 사용해서 127.0.0.1 에서만 접근이 가능했던

 

/cleaner.php 로 접근을 시도했다.

 

접근을 하면서 아까 소스코드에서 봤던 X-Visited-Before 헤더를 추가해줬고,

 

헤더의 내용으로 echo 'hello world'; 라고 넣어줬다.

 

그랬더니 왼쪽 응답 패킷에서 원래 출력되던 There your cleaned url 과 더불어

 

tryandeval 함수가 실행되어야만 출력되던 How many you visited us 와 함께 

 

입력했던 hello world도 출력이 된 것을 확인했다.

 

 

이번엔 시스템 명령어 실행을 시도해봤다.

 

X-Visited-Before: 헤더에 system('id'); 라고 값을 넣어주고 패킷을 보내봤는데

 

How many you visited us 는 잘 출력되는것에 반해 

 

그 뒤에는 아무것도 출력이 되지 않았다.

 

disable_functions = proc_open, popen, disk_free_space, diskfreespace, set_time_limit, leak, tmpfile, 
exec, system, passthru, show_source, system, phpinfo, pcntl_alarm, pcntl_fork, pcntl_waitpid, 
pcntl_wait, pcntl_wifexited, pcntl_wifstopped, pcntl_wifsignaled, pcntl_wexitstatus, pcntl_wtermsig, 
pcntl_wstopsig, pcntl_signal, pcntl_signal_dispatch, pcntl_get_last_error, pcntl_strerror, pcntl_sigprocmask, 
pcntl_sigwaitinfo, pcntl_sigtimedwait, pcntl_exec, pcntl_getpriority, pcntl_setpriority

 

같이 주어졌던 php.ini 파일을 열어보니 

 

disable_functions 에 수많은 제약조건을 걸어놓았다.

 

시스템 명령어를 실행시킬 수 있는 exec, system, passthru 같은 명령어들이 모조리 막혀있었다.

 

 

하지만 방법이 없는건 아니다.

 

echo `id` 라고 입력해줬더니

 

id 명령어가 실행되어서 그 결과가 응답 패킷에 포함되어 돌아오는것이 확인되었다.

(작은따옴표가( ' ) 아닌 물결 기호 아래있는 문자( ` ))

 

 

서버 안에 있는 플래그를 찾기 위해

 

echo `ls /' 로 루트 디렉토리 아래있는 파일/폴더 목록을 출력시켜봤더니

 

중간에 maybethisistheflag 라는 폴더가 하나 눈에 띄었다.

 

 

echo `cat /maybethisistheflag` 라고 입력하면

 

플래그를 확인할 수 있다.

반응형