Subscribed unsubscribe Subscribe Subscribe

しゃろの日記

CTFのwriteup置き場になる予定(`・ω・´)

Boston Key Party 2015 write up

Boston Key Party 2015に参加してみました。

難しそうだから大して点数稼げないだろうなーと思っていましたが、
案の定10点・25点問題しかできませんでしたとさ(*´ω`*)


BU Central(10)

the flag is party

この問題の存在に気づくのに30分くらいかかった。

FLAG:party

Park Street(10)

What is the OpenFlow table modification message type to add a new flow?

ググる参考

FLAG:OFPFC_ADD

Prudential(25)

I dont think that sha1 is broken. Prove me wrong.

<html>
<head>
    <title>level1</title>
    <link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php
require 'flag.php';

if (isset($_GET['name']) and isset($_GET['password'])) {
    if ($_GET['name'] == $_GET['password'])
        print 'Your password can not be your name.';
    else if (sha1($_GET['name']) === sha1($_GET['password']))
      die('Flag: '.$flag);
    else
        print '<p class="alert">Invalid password.</p>';
}
?>

<section class="login">
    <div class="title">
        <a href="./index.txt">Level 1</a>
    </div>

    <form method="get">
        <input type="text" required name="name" placeholder="Name"/><br/>
        <input type="text" required name="password" placeholder="Password" /><br/>
        <input type="submit"/>
    </form>
</section>
</body>
</html>

sha1関数は引数に配列を渡すとFALSEを返すので、nameとpasswordを配列にするとフラグが取れる。
ただし$_GET['name'] == $_GET['password']に引っかかるとNGなので、nameとpasswordにはそれぞれ違う文字列を入れる。

FLAG:I_think_that_I_just_broke_sha1

Symphony(25)

A less than four characters number, bigger than 999? Maybe the bug is elsewhere.

<html>
<head>
    <title>level2</title>
    <link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php
require 'flag.php';

if (isset($_GET['password'])) {
    if (is_numeric($_GET['password'])){
        if (strlen($_GET['password']) < 4){
            if ($_GET['password'] > 999)
                die('Flag: '.$flag);
            else
                print '<p class="alert">Too little</p>';
        } else
                print '<p class="alert">Too long</p>';
    } else
        print '<p class="alert">Password is not numeric</p>';
}
?>

<section class="login">
        <div class="title">
                <a href="./index.txt">Level 2</a>
        </div>

        <form method="get">
                <input type="text" required name="password" placeholder="Password" /><br/>
                <input type="submit"/>
        </form>
</section>
</body>
</html>

is_numeric関数は指数表記も通すので、1e3とか入れればOK。

FLAG:B4SE10_IS_F0R_LOSERS

Northeastern Univ.(25)

Of course, a timing attack might be the answer, but Im quite sure that you can do better than that.

<html>
<head>
    <title>level3</title>
    <link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php
require 'flag.php';

if (isset($_GET['password'])) {
    if (strcmp($_GET['password'], $flag) == 0)
        die('Flag: '.$flag);
    else
        print '<p class="alert">Invalid password.</p>';
}
?>

<section class="login">
        <div class="title">
                <a href="./index.txt">Level 3</a>
        </div>

        <form method="get">
                <input type="text" required name="password" placeholder="Password" /><br/>
                <input type="submit"/>
        </form>
</section>
</body>
</html>

strcmp関数は引数に文字列以外を渡すと0を返す。
従って、Prudential同様に配列にすればOK。

FLAG:Still_better_than_the_d0uble_equals

Museum of Fine Arts(25)

Because cryptography is hard, we only implemented a hand-made PRNG. What could possibly go wrong?

<html>
<head>
    <title>level4</title>
    <link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php
session_start(); 

require 'flag.php';

if (isset ($_GET['password'])) {
    if ($_GET['password'] == $_SESSION['password'])
        die ('Flag: '.$flag);
    else
        print '<p class="alert">Wrong guess.</p>';
}

// Unpredictable seed
mt_srand((microtime() ^ rand(1, 10000)) % rand(1, 10000) + rand(1, 10000));
?>

<section class="login">
        <div class="title">
                <a href="./index.txt">Level 4</a>
        </div>

        <ul class="list">
        <?php
        for ($i=0; $i<3; $i++)
            print '<li>' . mt_rand (0, 0xffffff) . '</li>';
        $_SESSION['password'] = mt_rand (0, 0xffffff);
        ?>
        </ul>

        <form method="get">
                <input type="text" required name="password" placeholder="Next number" /><br/>
                <input type="submit"/>
        </form>
</section>
</body>
</html>

mt_rand関数で生成された3つの整数から、4つ目の整数を予測して答える問題。
乱数の種さえわかってしまえばOKなので、システム時間から遡って総当たりで調べる。

<?php
$hint = 0;
fscanf(STDIN, "%d", $hint);

$seed = microtime();

while(TRUE){
    mt_srand(($seed ^ rand(1, 10000)) % rand(1, 10000) + rand(1, 10000));
    if(mt_rand(0, 0xffffff) == $hint){
        for($i = 0; $i < 3; $i++){
            echo(mt_rand(0, 0xffffff));echo("\n");
        }
        break;
    }else{
        $seed--;
    }
}
?>

FLAG:It_s33ms_that_PRNG_are_hard_too_after_all

Longwood Medical(25)

Because we dont trust mysqli_real_escape_string, we wrote our own military-grade sanitization method.

<html>
<head>
    <title>level5</title>
    <link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php

require 'flag.php';

if (isset ($_GET['login']) and isset ($_GET['password'])) {
    $name = $_GET['login'];
    $password = $_GET['password'];

    if (ctype_alnum ($name) and ctype_alnum ($password)) {
        $request = 'SELECT login FROM user where login = ' . $name . ' AND password = ' . $password . ';';
        $db = new SQLite3 (sha1($flag).'.db', SQLITE3_OPEN_READONLY); // Ghetto anti-database-download
        $result = $db->querySingle ($request);
        $db->close ();

        if ($result === FALSE)
            echo '<p class="alert">"Invalid login or password</p>';
        else
            die('Flag: ' . $flag);
    } else
        echo '<p class="alert">Invalid chars detected</p>';
}
?>

<section class="login">
        <div class="title">
                <a href="./index.txt">Level 5</a>
        </div>

        <form method="get">
                <input type="text" required name="login" placeholder="Name"/><br/>
                <input type="text" required name="password" placeholder="Password" /><br/>
                <input type="submit"/>
        </form>
</section>
</body>
</html>

querySingleは結果がない場合はNULLを返し、クエリがエラーになったときにFALSEを返す。
nameとpasswordを数値にすればエラーにならないので、nameとpasswordに数字を入れる。

FLAG:Did_you_know_that_in_french_a_chiken_makes_the_sound_quotquotquotquot?

Brigham Circle(25)

Sanitization is hard, lets use regexp!

<html>
<head>
    <title>level6</title>
    <link rel='stylesheet' href='style.css' type='text/css'>
</head>
<body>

<?php
require 'flag.php';

if (isset ($_GET['password'])) {
    if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
        echo '<p class="alert">You password must be alphanumeric</p>';
    else if (strpos ($_GET['password'], '--') !== FALSE)
        die('Flag: ' . $flag);
    else
        echo '<p class="alert">Invalid password</p>';
}
?>

<section class="login">
        <div class="title">
                <a href="./index.txt">Level 6</a>
        </div>

        <form method="get">
                <input type="text" required name="password" placeholder="Password" /><br/>
                <input type="submit"/>
        </form>
</section>
</body>
</html>

ereg関数はNULLバイトセーフではないので、"a\0--"とか送ればOK。

FLAG:OK_Maybe_using_rexpexp_wasnt_a_clever_move