[WARGAME] 드림핵 워게임 - phpMyRedis

jckim22·2022년 11월 11일
0

[WEBHACKING] STUDY (WARGAME)

목록 보기
65/114

아래는 서버 코드이다.

index.php

<?php
    include_once "./core.php";
?>
<html>
    <head></head>
    <link rel="stylesheet" href="/static/bulma.min.css" />
    <body>
        <div class="container card">
            <div class="card-content">
                <div class="columns">
                    <div class="column is-10">
                        <h1 class="title">phpMyRedis</h1>
                    </div>
                    <div>
                        <div class="column is-2"><a href="/config.php" class="card-footer-item">Config</a></div>
                    </div>
                </div>
                <form method="post">
                    <div class="field">
                        <label class="label">Command</label>
                        <div class="control">
                            <textarea class="textarea" name="cmd"><?=isset($_POST['cmd'])?$_POST['cmd']:'return 1;'?></textarea>
                        </div>
                        <label class="checkbox">
                            <input type="checkbox" name="save">Save
                        </label>
                    </div>
                    <div class="control">
                        <input class="button is-success" type="submit" value="submit">
                    </div>
                </form>
                <?php 
                    if(isset($_POST['cmd'])){
                        $redis = new Redis();
                        $redis->connect($REDIS_HOST);
                        $ret = json_encode($redis->eval($_POST['cmd']));
                        echo '<h1 class="subtitle">Result</h1>';
                        echo "<pre>$ret</pre>";
                        if (!array_key_exists('history_cnt', $_SESSION)) {
                            $_SESSION['history_cnt'] = 0;
                        }
                        $_SESSION['history_'.$_SESSION['history_cnt']] = $_POST['cmd'];
                        $_SESSION['history_cnt'] += 1;

                        if(isset($_POST['save'])){
                            $path = './data/'. md5(session_id());
                            $data = '> ' . $_POST['cmd'] . PHP_EOL . str_repeat('-',50) . PHP_EOL . $ret;
                            file_put_contents($path, $data);
                            echo "saved at : <a target='_blank' href='$path'>$path</a>";
                        }
                    }
                ?>
            </div>
        </div>
        <br/>
        <div class="container card">
            <div class="card-content">
                <div class="columns">
                    <div class="column is-10">
                        <h1 class="title">Command History</h1>
                    </div>
                    <div class="column is-2"><a href="/reset.php" class="card-footer-item">Reset</a></div>
                </div>
                <div class="content">
                    <ul>
                    <?php
                        for($i=0; $i<$_SESSION['history_cnt']; $i++){
                            echo "<li>".$_SESSION['history_'.$i]."</li>";
                        }
                    ?>
                    </ul>
                </div>
            </div>
        </div>
    </body>
</html>

reset.php

<?php
    include_once "./core.php";
    session_destroy();
    header('Location: /');
?>

core.php

<?php 

$REDIS_HOST = 'localhost';
$REDIS_PORT = 6379;

ini_set('session.save_handler', 'redis');
ini_set('session.save_path', "tcp://$REDIS_HOST:$REDIS_PORT");
session_start();

config.php

<?php
    include_once "./core.php";
?>
<html>
    <head></head>
    <link rel="stylesheet" href="/static/bulma.min.css" />
    <body>
        <div class="container card">
            <div class="card-content">
                <div class="columns">
                    <div class="column is-10">
                        <h1 class="title">phpMyRedis</h1>
                    </div>
                    <div>
                        <div class="column is-2"><a href="/" class="card-footer-item">Command</a></div>
                    </div>
                </div>
                <form method="post">
                    <label class="label">Config</label>
                    <div class="field">
                        <div class="control">
                            <div class="select">
                                <select name="option">
                                    <option>GET</option>
                                    <option>SET</option>
                                </select>
                            </div>
                        </div>
                    </div>
                    <div class="field">
                        <label class="label">Key</label>
                        <div class="control">
                            <input class="input" type="text" name="key">
                        </div>
                    </div>
                    <div class="field">
                        <label class="label">Value</label>
                        <div class="control">
                            <input class="input" type="text" name="value">
                        </div>
                    </div>
                    <div class="control">
                        <input class="button is-success" type="submit" value="submit">
                    </div>
                </form>
                <?php 
                    if(isset($_POST['option'])){
                        $redis = new Redis();
                        $redis->connect($REDIS_HOST);
                        if($_POST['option'] == 'GET'){
                            $ret = json_encode($redis->config($_POST['option'], $_POST['key']));
                        }elseif($_POST['option'] == 'SET'){
                            $ret = $redis->config($_POST['option'], $_POST['key'], $_POST['value']);
                        }else{
                            die('error !');
                        }                        
                        echo '<h1 class="subtitle">Result</h1>';
                        echo "<pre>$ret</pre>";
                    }
                ?>
            </div>
        </div>
    </body>
</html>

키가 되는 곳은 index.php의 바로 아래 부분이다.

if(isset($_POST['cmd'])){
                        $redis = new Redis();
                        $redis->connect($REDIS_HOST);
                        $ret = json_encode($redis->eval($_POST['cmd']));

cmd를 받아 메모리에 저장한다.
lua script를 사용할 수 있다.
앞서 배웠던 redis.call 같은 것들을 말이다.

redis에서 굉장히 장점이 되는 것이 빠른 속도인데 그 비결은 바로 메모리에 저장함에 있다.

하지만 휘발성이 높은 메모리이기에 save라는 config로 몇초에 몇번 파일이 변경되었을 때 저장을 하는지라는 config가 있다.
일단 save를 이용할 것이고 dir로 디렉토리 주소도 중요하다.

그리고 마지막으로 redis의 메모리의 내용이 파일로 저장되는 곳인 dbfilename이라는 파일을 php파일로 조작하여 메모리에 웹쉘 삽입 후 자연스럽게 php파일로 웹쉘이 저장되게 할 것이다.

자 아래를 보자
아래는 config.php 이다.
GET요청으로 확인할 수 있고 SET으로 config를 수정할 수 있다.

아래와 같이 dir을 GET해보니 var/www/html경로에 존재하는 것을 볼 수 있다.
html경로에 있으니 건들지 않아도 되겠다.

자 그럼 아래처럼 메모리의 내용이 저장되는 파일인 dbfilename을 hack.php로 설정해주자
그럼 이제부터 메모리의 내용은 저 php파일에 저장이 될 것이다.

아래에서는 save를 10 1로 설정해주자.
10초에 한번 변경되면 save한다는 뜻이다.

그럼 이제 메모리에 웹 쉘을 올려보자.
아래와 같은 웹쉘을 올리게 되면 메모리에 php파일이 업로드 되고 자동으로 서버 파일에 php파일 안으로 이 내용들이 저장될 것이다.

그럼 우린 자연스럽게 html경로에 있는 우리가 설정해놓은 php파일로 들어가게 되면 자동적으로 쉘이 실행되어 그 내용들을 볼 수 있게 될 것이다.

그럼 우리는 아래와 같이 cmd에 /flag를 입력해서 flag파일에 있는 flag를 확인하여 flag를 얻을 수 있다.

이 문제는 멍 때리고 보면 정말 어려울 수 있는 문제인 것 같다.
왜냐하면 redis는 점유율이 낮고 생소하기 때문이다.
하지만 redis의 메모리를 사용하고 주기적으로 서버내 파일에 저장하는 설정이 있다는 특징을 비롯한 여러 특징과 기본적인 명령어,config만 알면 쉽게 풀 수 있는 문제이다.

profile
개발/보안

0개의 댓글