[b00t2root '19] Writeup (EasyPHP)

9090 단어 CTFPHP

소개



b00t2root'19 의 Writeup입니다.

EasyPHP





문제 내용



작성된 URL로 이동하면 해당 페이지의 소스 코드가 표시됩니다.



플래그 표시까지 3단계로 되어 있습니다. 차례로 살펴 보겠습니다.

첫 단계


$str1 = $_GET['1']; 

if(isset($_GET['1'])){ 
    if($str1 == md5($str1)){ 
        echo $flag1; 
    } 
    else{ 
        die(); 
    } 
} 
else{ 
    die();    
} 

입력한 문자열과 해당 문자열의 MD5 해시 값이 일치하면 플래그 중 첫 번째가 표시됩니다.
그러나 그러한 문자열을 찾는 것은 어려운 일입니다.

그래서 코드를 잘 살펴보면 비교하고 있는 부분의 이콜이 3개가 아니라 2개가 되어 있습니다.
이콜 2개의 비교 연산자는 「완만한 비교」라고 불려, PHP측이 적절히 캐스트를 실시하고 나서 비교를 실시합니다.
예를 들어, '3'=='3.0' 는 True 입니다. ( '3'==='3.0' 는 문자열 그대로 비교하기 때문에 False입니다)
즉, 이 성질을 이용하면 문자열과 MD5 해시값이 엄밀하게 일치하지 않아도 돌파할 수 있을 것 같습니다.

그렇다면 어떤 MD5 해시 값을 찾아야합니까?
PHP에서 숫자를 표현하는 몇 가지 방법이 있으며, 그 중 하나는 부동 소수점 숫자 지수 표기법입니다.
이것은 1.2e3 (=1.2*10^3) 와 같은 표현 방법입니다.
이 지수 표기법에서 0e + (数値)는 모두 0입니다.
즉, MD5 해시 값이 0e + (数値) 가 되는 0e + (数値) 의 형태의 캐릭터 라인을 찾습니다.
여기 기사 에서 0e215962017 가 해당하는 것 같습니다.

URL에 ?1=0e215962017를 추가하면 b00t2root{wh4t3v3r_가 표시됩니다.

두 번째 단계


$str2 = $_GET['2']; 
$str3 = $_GET['3']; 

if(isset($_GET['2']) && isset($_GET['3'])){ 
    if($str2 !== $str3){ 
        if(hash('md5', $salt . $str2) == hash('md5', $salt . $str3)){ 
            echo $flag2; 
        } 
        else{ 
            die(); 
        } 
    } 
    else{ 
        die(); 
    } 
} 
else{ 
    die();    
} 

입력한 두 문자열의 시작 부분에 문자열 $salt 를 결합한 후 해시 값이 계산되고 일치하는 경우 플래그의 두 번째가 표시됩니다.
그러나 입력하는 두 문자열은 달라야 합니다.

처음은 해시 신장 공격인가? 라고 생각했습니다만, 해시값이 표시되지 않기 때문에 이것이 아닐 것 같습니다.

여기서 $str2,$str3 가 문자열 이외가 될 가능성을 생각해 봅시다.
예를 들어 배열이었다면 $salt . $str 는 어떻게 될까요?
시도하면 'test' . array('a','b')'testArray'입니다.
즉, $str2,$str3 가 다른 배열이 되면, 플래그가 표시됩니다.

그렇다면 어떻게 배열이 될까요?
PHP에서는 파라미터 송신시에 param[] 로 하면(자) $_GET['param'] 로 배열로서 받습니다.2[]='a' , 3[]='b' 하면 $str2 = array(1) { [0]=> string(1) "a"} , $str3 = array(1) { [0]=> string(1) "b"} 가 되어 다른 배열이 됩니다.

URL에 &2[]=a&3[]=b를 추가하면 b00t2root{wh4t3v3r_17_74k3s가 표시됩니다.

세 번째 단계


class Secrets { 
    var $temp; 
    var $flag; 
} 

if (isset($_GET['4'])) { 
    $str4 = $_GET['4']; 

    if(get_magic_quotes_gpc()){ 
        $str4=stripslashes($str4); 
    } 

    $res = unserialize($str4); 

    if ($res) { 
    $res->flag=$flag3; 
        if ($res->flag === $res->temp) 
            echo $res->flag; 
        else 
            die(); 
    } 
    else die(); 
} 
unserialize 에서 Secrets 클래스의 객체를 만든 후에 $flag 속성에 플래그가 할당되고, 그것이 $temp 속성과 같으면 플래그가 표시됩니다.
엄격한 비교이므로 첫 단계처럼 할 수 없습니다. 그렇다면 어떻게 해야 하나요?

가장 먼저 생각하는 것은 하나의 속성이 다른 속성을 참조하게하는 것입니다.
이번에는 $flag$temp 를 참조하자.
하지만 그런 일을 할 수 있는가?
unserialize 에 대해 조사하면, 참조형이 있는 것 같습니다. ( 참고 )
예를 들어, a:2:{s:3:"1st";i:100;s:3:"2nd";R:2;}$2nd$1st 를 참조합니다.
여러가지 시도했는데, a:2:{s:3:"1st";R:3:100;s:3:"2nd";i:100;} 와 같이 뒤의 프로퍼티의 참조는 할 수 없는 것 같습니다.
이상을 근거로 하면 $flag$temp 를 참조하는 직렬화 데이터는 O:7:"Secrets":2:{s:4:"temp";N;s:4:"flag";R:2;} 가 됩니다.

URL에 4=O:7:%22Secrets%22:2:{s:4:%22temp%22;N;s:4:%22flag%22;R:2;}를 추가하면 b00t2root{wh4t3v3r_17_74k3s_cuz_1_l0v3_th3_4dren4l1n3_1n_my_v31ns_932b315}가 표시되어 플래그를 획득 할 수 있습니다.

좋은 웹페이지 즐겨찾기