c = “”.join(“70 2b 7b ef 93 27 53 d3”.split()) c = c.decode('hex’) p = “To be, o” key=“” for i in range(len(p)): print “Dec: %c -> %c” % (c[i], p[i]) for k in range(1,256): d = ord(c[i]) ^ k if d==ord(p[i]): print “Key: ” +str(k), key+=“%02x” % k print key=“”.join(key.split(“0x”))
plain = bytearray(“asdfghjk123456”) key = bytearray(/*Missed*/) assert len(key) == 8 t1 = bytearray() for i in plain: t1.append(A[i]) t2 = bytearray() for i in range(len(t1)): t2.append(LShift(t1[i], B[i % 8])) for times in range(16): for i in range(len(t2)): t2[i] = C[t2[i]] for i in range(len(t2)): t2[i] = LShift(t2[i], i ^ D[i % 8]) for i in range(len(t2)): t2[i] ^= key[i % 8] out = “” for i in t2: out += encode(i) print out
def decrypt(e, i, k): d=e for times in range(16): d ^= k d = RShift(d, i ^ D[i % 8]) d = C.index(d) d = RShift(d, B[i % 8]) return A.index(d)
復号のためのkeyはXORをしているだけなので、総当り(256通り)を行って推定。与えられた plain と out を利用して鍵を探す。
def find_key(e, i, p): print “decrypt[%2d]: %c: ” % (i, p), for k in range(1,256): d = decrypt(e, i, k) if d == p: print “key: %02x,” % k, print return p, k
out = “OO|OO||OO|||||OO|OO||O||O|O||O|||O|OOOOOOO|O|O|O|||||OO|||O|||OO||O|OOOOOO|O|OO|OO||||OO|||OOOO|||||O||||O|OO|O|O|O||OO|O||O|OO|O||O|||O||O|OO|OOOOOO||OOO|O|O|O|||O|OO|O|O||O||O||OOOOO|||OO|O|” dec_out = decode(out) print “decode: ”, print_binarray(dec_out) dec=“” for i in range(len(dec_out)): if i == len(plain): break if not i%8: print p, k = find_key(dec_out[i], i, plain[i]) print dec
鍵長は、与えられたソースの22行目から 8バイト固定ということがわかっていて、さらに、単純にループを回しているだけなので、0と8、1と9、… と同じ鍵が使用される。plainの文字数が足りないけど、適当に”78”を追加したら上手い具合に plain から out へ暗号化できた。
def print_binarray(bin): for i in bin: print hex(i), print
# flag >> flag = “OO||O||O|O|||OOOO||||||O|O|||OOO||O|OOOO||O|O|OO|||||OOOO||||O||OO|OO||O||O|O|O|||||OOOOOO|O|O||OOOOOOO||O|||OOOO||OO|OO|||O|OO|O|||O|O|OO|OOOO|OOO|OOO|OOOO||O|OO||||OO||||OOO|O|O||OO||||O||OOO|||O|OO|OO||OO||OOOO|O|” dec_out = decode(flag) print “flag: ” print_binarray(dec_out) key = bytearray(“\x5e\x26\x23\x71\x44\x39\x33\x5f”) p=“” for i in range(len(dec_out)): p += chr(decrypt(dec_out[i], i, key[i%8])) print p
buf=“”.join(buf.split()) ans=“” for b in range(0,len(buf),2): ans+=chr(int(buf[b:b+2],16)) print ans
出力結果。まさかの縦読み
In the end, it’s all about flags. Whether you win or lose doesn’t matter. {Ofc, winning is cooler Did you find other flags? Noboby finds other flags! Superman is my hero. _HERO!!!_ Help me my friend, I’m lost in my own mind. Always, always, for ever alone. Crying until I’m dying. Kings never die. So do I. }!
Flag: IW{DNS_HACKS}
追記:
チームメンバーから xxd でいけることを教えてもらった
ubuntu@task $ grep -ia “Host: ” flag.pcapng | sed “s/Host: //” | sed “s/.2015.ctf.internetwache.org//” | xxd -ps -r In the end, it’s all about flags. Whether you win or lose doesn’t matter. {Ofc, winning is cooler Did you find other flags? Noboby finds other flags! Superman is my hero. _HERO!!!_ Help me my friend, I’m lost in my own mind. Always, always, for ever alone. Crying until I’m dying. Kings never die. So do I. }!
MISC90 :
BarParty
問題文
Can you read the barcodes?
数が少なかったので、Incscapeでトリミングしてつなぎあわせた。
IW{Bar_B4r_C0d3s}
Rev50 : SPIM
問題文
My friend keeps telling me, that real hackers speak assembly fluently. Are you a real hacker? Decode this string: “IVyN5U3X)ZUMYCs”
buf=“IVyN5U3X)ZUMYCs” ans=“” for i in range(len(buf)): ans+=chr(ord(buf[i])^i) print ans
Flag: IW{M1P5_!S_FUN}
Rev60 : File Checker
問題文
My friend sent me this file. He told that if I manage to reverse it, I’ll have access to all his devices. My misfortune that I don’t know anything about reversing :/
与えられたファイルは x86_64 の実行ファイル
filechecker: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=564c7e61a18251b57f8c2c3dc205ed3a5b35cca6, stripped
seed = 0x1337; ans =[] for i in range(len(buf)): ans.append( chr(seed - buf[i]) ) print “”.join(ans)
Flag:
IW{FILE_CHeCKa}
Crypto 90 : Bank
問題文
Everyone knows that banks are insecure. This one super secure and only allows only 20 transactions per session. I always wanted a million on my account.
サーバに接続すると下記のメッセージが送られてくる。
WELCOME TO THE BANK BACKEND!
Possible commands: help - Prints this message create <a> - Creates a new transaction with amount <a> complete <tid> <hash> - Completes a transaction to the current account. <tid> is the transaction ID to use and <hash> the verification hash.
def get_key(ct): cnt=0 key=[] for i in range(0,len(tmp),2): C=int(ct[i:i+2], 16) for j in range(255): if (ord(org[cnt])^j) == C: key.append(j) break cnt+=1 return key
s = socket(AF_INET, SOCK_STREAM) s.connect((“188.166.133.53”, 10061))
cnt=0 data = rcv_data(s) print data while True: s.send(crt+“\n”) data = rcv_data(s) print data idx = data.index(“code:”) code = data[idx+6:idx+40] print code key = get_key(code) e = enc(mal, key) s.send(“complete ”+str(cnt)+“ ”+e+“\n”) data = rcv_data(s) print data cnt+=1 if “IW{” in data: break
s.close()
Flag: IW{SHUT_UP_AND_T4K3_MY_M000NEYY}
Code50 : A numbers game
問題文
People either love or hate math. Do you love it? Prove it! You just need to solve a bunch of equations without a mistake.
しかし、これだと、最後の文字が M か . か O か o か n か D ということしかわからず、適当に処理を追ってみたところ、例えば、1O とか dD とかのパスワードでも return 1; することになります。 試しにそれらのパスワードを入力してみると笑顔が表示されましたが、出題サーバにsubmitしてみると incorrect (不正解) になりました。
ちょっと途方に暮れて IRC で「 I found many passwords. What shoud I do? 」とぼやいてみたら、「 just analyze and follow the code from the first, only the first case 」という返事が返ってきました。 つまり、コードを順番に追って最初に見つかったのが正しいパスワードということのようです。 コードを最初から手で追うのはとても時間がかかりそうで、もしどこかで間違って最初からやり直すことになると心がくじけそうに思えたので、stateの値と判定文字の組み合わせ処理をテキストエディタで切り出してテーブルにして、テーブルを追うPythonスクリプトを書いてみることにしました。
0 x r 8 d q j 7 6 z m c p f h b a 5 1 t w l 3 k v u e y 2 n s 9 4 o i g -・・- ・・-・ -・・ -・・ ・・-・ -・・- ・・・- --・ ・・-・ --・ ・・・- -・・- -・・- ・・・- --・ -・・ ・・・- -・・ -・・ --・ -・・- -・・- --・ -・・-
$ python grandprix.py
(中略)
|-----|
| |
| |
| |
| |
| |
| |
| |
| |
|=u===|
|-----|
You won this game. Push a key to play again
User won game
The key is: all our prix belong to you