해당 문제는 대회 때 풀지못하고 추후 롸업을 보고 다시 풀어보았다.
소스는 다음과 같다.
<?php
stream_wrapper_unregister('php');
if(isset($_GET['hl'])) highlight_file(__FILE__);
$mkdir = function($dir) {
system('mkdir -- '.escapeshellarg($dir));
};
$randFolder = bin2hex(random_bytes(16));
$mkdir('users/'.$randFolder);
chdir('users/'.$randFolder);
$userFolder = (isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR']);
$userFolder = basename(str_replace(['.','-'],['',''],$userFolder));
$mkdir($userFolder);
chdir($userFolder);
file_put_contents('profile',print_r($_SERVER,true));
chdir('..');
$_GET['page']=str_replace('.','',$_GET['page']);
if(!stripos(file_get_contents($_GET['page']),'<?') && !stripos(file_get_contents($_GET['page']),'php')) {
include($_GET['page']);
}
chdir(__DIR__);
system('rm -rf users/'.$randFolder);
내 IP를 기반으로한 디렉토리 내에 profile이란 파일을 생성한다. 이 때 파일 내용은 $_SERVER 변수에 담긴 값들이 삽입된다.
위의 상황에서 나는 특정 페이지를 include시킬 수 있다.이 때 내가 입력한 페이지에서 .을 제거하고 wrapper와 같은 경우 php wrapper를 사용할 수 없다.
여기서 간단히 생각해볼 수 있는건 헤더값에 php코드넣고 profile 파일을 포함시키면 될 것 같지만 profile 내에 php,<? 문자열이 존재하는지 검증을 해 php코드를 삽입할 수가 없다.
현 상황에서 lfi로는 해볼만한게 없었고, rfi 중 현재상황에서 사용가능한 data wrapper를 사용해봤지만 allow_url_include가 off라 사용이 불가능 했다.
일단 profile 파일을 include 시켜야 할 것 같기 때문에 실제로 일단 include부터 시켜보려하면 include가 되지 않는다. 그 이유는 기본적으로 $_SERVER에 PHP_SELF란 속성이 존재해서 include자체가 될 수가 없다.
말도안되는 상황이지만 해당 서버에 설정을 보면 allow_url_fopen이 On으로 되어있고 이 설정은 일반적으로 디폴트가 On이다. 즉 file관련함수에서 data wrapper사용이 가능하다는 거다. 이 말은 data wrapper로 <?,php 검증은 우회가 가능한데, 추가로 data wrapper 값이 include내에 들어갔을때 allow_url_include가 off라 에러가터져서 필터링 우회한 의미가 없다는 거다.
근데 여기서 우리가 눈여겨봐야할 게 사용자별 디렉토리를 만들 때 무조건 내 IP가 아니라 X_FORWARED_FOR 헤더를 통해 지정된 IP가 존재하면 이걸로 디렉토리를 만든다. 이 값은 내가 컨트롤이 가능하기 떄문에 이 헤더를 통해 디렉토리를 data wrapper형태로 만들어놓으면 data wrapper로 파일내용 검증을 우회한 뒤 이 값이 include에서 wrapper로서가 아닌 디렉토리로서 먼저 인식되어 에러를 안내고 profile 포함이 가능해진다는 거다.
include에서 입력값을 처리하는 순서에 의해 이러한 현상이 발생하는 것 같다. 만약 입력값을 파일경로로서 먼저처리하지않고 wrapper인지 먼저 처리하고 파일경로인지 확인했다면 wrapper로서 인식되어 그대로 에러가 터졌을 것이다.
해당 문제를 풀면서 느낀건 한 로직 한 로직 의심을가지고 바라보며 한 로직이 우회가능할 때 다음 로직에서 이전 값들이 유효한지를 막연히 추측할게 하니라 이 또한 연계해서 또 끝없는 의심으로 실제 검증테스트까지 다 해봐야한다는 거다. 막연히 이건 이래서 안되라고 생각할게 아니라 혹시?라는 생각이 필요할 것 같다.
여기까지 설명하고 났으니 exploit은 간단하다.
'CTF > Writeup' 카테고리의 다른 글
NCSC CTF 2019 Web Wrietup (0) | 2019.02.04 |
---|---|
Codegate CTF 2019 Preliminary Rich Project (0) | 2019.01.27 |
Insomnihack CTF Teaser 2019 l33t-hoster (0) | 2019.01.21 |
ROOT CTF 2017 ROOT Ransomware (0) | 2019.01.02 |
ROOT CTF 2018 CrackMe (0) | 2019.01.01 |