好奇心の足跡

飽きっぽくすぐ他のことをしてしまうので、忘れないため・形にして頭に残すための備忘録。

Shakti CTF 2020 writeup [Web]

2020年12月3の21:30 - 12月4日21:30 で行われていた、Shakti CTF 2020の [Web] 分野のwriteupです。

※ まとめはこちら tech.kusuwada.com

AuthEN

Ada is important to the world, she is important for a reason

Link: http://104.198.67.251/authen

リンクを踏むと、こんなログイン画面

f:id:kusuwada:20201206223312p:plain

ソースを見てみると、怪しいところが。

if(username == “admin” && password == String.fromCharCode(115, 104, 97, 107, 116, 105, 99, 116, 102, 123, 98, 51, 121, 48, 110, 100, 95, 112, 117, 114, 51, 95, 99, 52, 108, 99, 117, 108, 97, 116, 105, 48, 110, 115, 125)) 

もうすでにflagになってそう。

arr = [115, 104, 97, 107, 116, 105, 99, 116, 102, 123, 98, 51, 121, 48, 110, 100, 95, 112, 117, 114, 51, 95, 99, 52, 108, 99, 117, 108, 97, 116, 105, 48, 110, 115, 125]

for a in arr:
    print(chr(a), end='')    

実行結果

$ python solve.py 
shaktictf{b3y0nd_pur3_c4lculati0ns}

Ador

Ada was born on 10 December 1815 not 12, identification change makes a difference

Link: http://104.198.67.251/Ador

urlを訪れるとこんなページ

f:id:kusuwada:20201206214608p:plain

Welcome user, secrets only for admin

これが気になる。

cookieとhtmlソースを確認。ソースに

use name for user

的なコメントが書いてあるのも気になる。

色々いじったりUAを変えてみたりしたけどわからなかったので、上の文言からなんとなくurlのparameterクエリに?name=adminを入れたらflagが出た。

f:id:kusuwada:20201206214904p:plain

Biscuits

Ada Lovelace used to love eating french biscuits during her work

Link: http://34.72.245.53/Web/Biscuits/

これはタイトルからcookie関連かな?と想像。

f:id:kusuwada:20201206214952p:plain

cookie見たらそのまんまフラグが書いてあった。

f:id:kusuwada:20201206215030p:plain

THE_FLAG_IS: shaktictf%7Bc00k13s_m4k3_phr3n0l0gy%26m3sm3r15m_3asy%7D

url decodeして

shaktictf{c00k13s_m4k3_phr3n0l0gy&m3sm3r15m_3asy}

Machine

Babbage was impressed by Lovelace's intellect and analytic skills that he called her a humanoid

Link: http://34.72.245.53/Web/Machine/

topページはこんな感じ。

f:id:kusuwada:20201206215208p:plain

Humanoid robot of maths

これは robots.txt 問の予感。

http://34.72.245.53/Web/Machine/robots.txt にアクセスしてみると

User-agent: *
Allow: /var/www/html/
Disallow: /mkiujnbhytgbvfr.html

ほうほう。このdisallowのページにアクセスできれば良さそう。
何も考えずに

http://34.72.245.53/Web/Machine/mkiujnbhytgbvfr.html

にアクセスするとFlagがありました。

flag: shaktictf{7h3_3nch4n7r355_0f_Nu3b3r}

Doors

Ada Loves to travel to places, London-Paris-Spain and discover more

Link: http://35.225.9.113/Doors/

topはこんな感じ

f:id:kusuwada:20201206215305p:plain

ここから飛べるサイトは特にflagのヒントなし。
flag.txt, flag.php, file0.php, file4.php などをpathトラバーサルしたりしてみたがヒットせず。

index.phpのソースコードに

<!-- ?page -->

というコメントがあたので、?page=hogehogeみたいな感じでクエリを投げられそうなことがわかる。
?page=file1.phpとすると、file1の内容が表示される。
?page=index.phpとすると、fileの表示に使われている関数が表示された。

f:id:kusuwada:20201206215354p:plain

この関数には PHP: file_get_contents - Manual のとおり何でも突っ込めるので、上記試したようなファイルを推測して色々試してみたが特にめぼしい成果はなし。

どういう問題が出されるんだろうな?とfile_get_contents ctf的な感じでぐぐってみるとnoisyさんのDEFCONのwriteupを発見。

DefCamp CTF Qualification 2017 writeup - Qiita

/etc/passwdにflagがあった、とある!
easy問題にしては推測部分が多いから違うかもな?と思いつつ ?page=/etc/passwdを入れると、flagがいました!

f:id:kusuwada:20201206223514p:plain

PharAway

Explaining the Analytical Engine's function was a difficult task, bypass the basic php to see what she tried to explain

Link: http://34.72.245.53/Web/PHPhar/

index.phpが配布されます。

<?php
include('flag.php');
$a=$_GET['flag0'];
if(strlen($a)>3){                                                 
}
if($a>900000000){
  echo "<h1>".$flag[0]."</h1>";
}
#------------------------------------------------------------------------------------------------------------------
$_p = 1337;
$_l = 13;
$l = strlen($_GET['secret']);
$_i = intval($_GET['secret']);
if($l !== $_l || $_i !== $_p)                                 
{
    die("bye");
}
echo "<h1>".$flag[1]."</h1>";

#-----------------------------------------------------------------------------------------------------------------------
if (isset($_GET['a']) and isset($_GET['b'])) {
    if ($_GET['a'] === $_GET['b'])
        print 'Your password can not be your dog\'s name.';                                  
    else if (sha1($_GET['a']) === sha1($_GET['b']))
      echo  "<h1>".$flag[2]."</h1>";
    else
        print '<p class="alert">Invalid password.</p>';
}
#-----------------------------------------------------------------------------------------------------------------------------
if (!isset($_GET["md4"]))
{
    
    die();
}

if ($_GET["md4"] == hash("md4", $_GET["md4"]))
{
    echo "<h1>".$flag[3]."</h1>";
}
else
{
    echo "bad";
}

#-----------------------------------------------------------------------------------------------------------------------------

if (isset($_GET['abc'])){
    if (!strcasecmp ($_GET['abc'], $flag[4])){
        echo $flag[4];}}

?>

flag0クエリが用意されていて、これが900000000より大きいと一つ目のflagが表示されるっぽい。

f:id:kusuwada:20201206223031p:plain

でた。format部分だ。

次は?secret。文字列の長さが13で、intvalの値が1337になっていると通るみたい。なんとか進数で表したら良さそう。...と思ったけど、頭に0つけるだけでいいや。

f:id:kusuwada:20201206223111p:plain

次はab
sha1が衝突する別の値を入れれば良さそう。

Googleが2017年に発表した SHAttered を使って攻撃しようと思ったんだけど、もう手動実行の限界だ。スクリプトに移行しよう。

で、スクリプトで組んで、urlクエリにshattered-1のPDF載せて送りつけてやろうと思ったんだけど、HTTP status response 414(too long)。ですよねー。。。

csictf 2020 Writeup - CTF フラxxグゲット

こちらのサイトに sha1 衝突の話が出ていて、値も短かったので良し!と思ったんだけど invalid password のまま。なんで?

var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));

$ echo -n 'aaroZmOk' | shasum -a 1
0e66507019969427134894567494305185566735  -
$ echo -n 'aaK1STfY' | shasum -a 1
0e76658526655756207688271159624026011393  -

確かに違うな。

ここで競技終了。ここから復習。

競技環境は閉じてしまっている & localで再現するコードの配布もされていないので、writeupを見て復習。

Team-Shaktiによるwriteup

これによると、sha1の衝突の件はarrayを突っ込むことで回避できたらしい。

&a[0]=asd&b[1]=dsf

asd,dsfは適当で良さそう。

次のmd4パラメータは、入力値とhashが一致したらOK。
このチェックの回避方法は、まさに

Magic Hashes | WhiteHat Security

で説明されているやつで、PHPの"0e"から始まって通じが続く文字列 (e.g. 0e134545364535464) の==演算子による比較が、0として評価されてしまうため、中身によらず常に真と判定されてしまうことを利用する。
これを利用したMagic Hash的な問題は前に解いたことがあったが(どれか見つけられなかった)、今回はHash前の値(左辺の$_GET["md4"])が0と評価されれば良いので、Hash化後に0e{dddd}になる値を探さなくてよく、単に0e{dddd}をそのままmd4に突っ込めば良い。

&md4=0e12345

最後のチェックはstrcasecmpを使っているので、またarrayを突っ込めば良い。

&abc[]=xxx

これでflagが全部回収でき、くっつけたらOKのはず。残念ながら実際にペイロードを送って検証はできないが、次に出てきたときに役に立ちそう。

感想

XSSやSQL injection問題とかあると嬉しかったなー。
競技中に解けなかった PharAway が面白そうなので、是非復讐したい。sha1の一致のところで詰まってしまった。 -> 復習した。arrayで回避とは思ったより初歩的な解法であった…。