picoCTF 2018 Writeup
Contents
URL: https://2018game.picoctf.com/
picoCTFのことを知ったのがちょっと前で、すでにイベントは2018年時点で終了してるんですが、続けて勉強ができるようになっていたので他のCTFイベントがない平日とかにちょこちょこやりました。
進み具合はこんな感じ。
もう、これくらいやったら十分かなぁ。気が向いたら、もう少しやるかもです。
いくつかピックアップしてWriteupを書いておきます。
[Forensics]: Desrouleaux (150 points)
Challenge
Our network administrator is having some trouble handling the tickets for all of of our incidents. Can you help him out by answering all the questions? Connect with nc 2018shell.picoctf.com 54782.
Hint: If you need to code, python has some good libraries for it.
Attachment:
- incidents.json
{ "tickets": [ { "ticket_id": 0, "timestamp": "2016/02/08 08:45:56", "file_hash": "33d81fec987b8a8c", "src_ip": "246.69.53.233", "dst_ip": "48.173.183.246" }, { "ticket_id": 1, "timestamp": "2017/03/05 06:01:41", "file_hash": "f2d2c758fe8853b5", "src_ip": "246.69.53.233", "dst_ip": "164.217.208.88" }, { "ticket_id": 2, "timestamp": "2015/02/28 12:24:15", "file_hash": "33d81fec987b8a8c", "src_ip": "251.165.34.242", "dst_ip": "125.130.154.106" }, { "ticket_id": 3, "timestamp": "2015/06/24 12:14:19", "file_hash": "581dc312cc8c16c6", "src_ip": "246.69.53.233", "dst_ip": "48.173.183.246" }, { "ticket_id": 4, "timestamp": "2015/11/15 22:34:03", "file_hash": "8aa16b403ac7de3e", "src_ip": "215.239.98.18", "dst_ip": "231.12.49.241" }, { "ticket_id": 5, "timestamp": "2015/02/06 15:42:17", "file_hash": "8aa16b403ac7de3e", "src_ip": "246.69.53.233", "dst_ip": "168.138.219.19" }, { "ticket_id": 6, "timestamp": "2017/12/29 05:54:41", "file_hash": "8aa16b403ac7de3e", "src_ip": "251.165.34.242", "dst_ip": "168.138.219.19" }, { "ticket_id": 7, "timestamp": "2017/10/10 13:11:20", "file_hash": "6629fde09ed2dab7", "src_ip": "251.165.34.242", "dst_ip": "187.229.175.225" }, { "ticket_id": 8, "timestamp": "2015/01/26 00:01:08", "file_hash": "581dc312cc8c16c6", "src_ip": "231.205.245.44", "dst_ip": "48.173.183.246" }, { "ticket_id": 9, "timestamp": "2017/05/07 09:51:22", "file_hash": "8aa16b403ac7de3e", "src_ip": "251.165.34.242", "dst_ip": "168.138.219.19" } ] }
Solution
ncで繋ぐと、そこで問題が出てきます。
ヒントを無視してLinuxコマンドで全部解こうかと思ったけど、勉強のために最後だけはPythonで解きました。
What is the most common source IP address? If there is more than one IP address that is the most common, you may give any of the most common ones.
$ grep src incidents.json | cut -d: -f2 | sort | uniq -c 1 "215.239.98.18", 1 "231.205.245.44", 4 "246.69.53.233", 4 "251.165.34.242",
答え:251.165.34.242
How many unique destination IP addresses were targeted by the source IP address 246.69.53.233?
$ grep 251.165.34.242 incidents.json -A 2 | grep dst | sort | uniq | wc -l 3
答え:3
What is the number of unique destination ips a file is sent, on average? Needs to be correct to 2 decimal places.
|
|
答え:1.40
[General Skills]: you can’t see me (200 points)
Challenge
‘…reading transmission… Y.O.U. .C.A.N.’.T. .S.E.E. .M.E. …transmission ended…’ Maybe something lies in /problems/you-can-t-see-me_3_1a39ec6c80b3f3a18610074f68acfe69.
Solution
SSHでアクセスした後、emacsのdiredからファイルを開いたらすぐフラグ見つかりました。
逆にemacsが使えなかったらどうするのか気になって、別解も調べてみました。
ファイル名に空白文字が含まれているようなので、trでアンダースコアに置き換えて可視化しました。
captureamerica@pico-2018-shell:/problems/you-can-t-see-me_3_1a39ec6c80b3f3a18610074f68acfe69$ ll total 60 drwxr-xr-x 2 root root 4096 Mar 25 19:57 ./ -rw-rw-r-- 1 hacksports hacksports 57 Mar 25 19:57 . drwxr-x--x 556 root root 53248 Mar 25 19:58 ../ captureamerica@pico-2018-shell:/problems/you-can-t-see-me_3_1a39ec6c80b3f3a18610074f68acfe69$ ls -la | tr " " "_" total_60 drwxr-xr-x___2_root_______root________4096_Mar_25_19:57_. -rw-rw-r--___1_hacksports_hacksports____57_Mar_25_19:57_.__ drwxr-x--x_556_root_______root_______53248_Mar_25_19:58_.. captureamerica@pico-2018-shell:/problems/you-can-t-see-me_3_1a39ec6c80b3f3a18610074f68acfe69$ cat ". " cat: '. ': No such file or directory captureamerica@pico-2018-shell:/problems/you-can-t-see-me_3_1a39ec6c80b3f3a18610074f68acfe69$ cat ". " picoCTF{j0hn_c3na_paparapaaaaaaa_paparapaaaaaa_cf5156ef}
[Cryptography]: Safe RSA (250 points)
Challenge
Now that you know about RSA can you help us decrypt this ciphertext? We don’t have the decryption key but something about those values looks funky..
Hint1: RSA tutorial
Hint2: Hmmm that e value looks kinda small right?
Hint3: These are some really big numbers.. Make sure you’re using functions that don’t lose any precision!
Attachment:
- ciphertext(以下が中身)
--------
N: 374159235470172130988938196520880526947952521620932362050308663243595788308583992120881359365258949723819911758198013202644666489247987314025169670926273213367237020188587742716017314320191350666762541039238241984934473188656610615918474673963331992408750047451253205158436452814354564283003696666945950908549197175404580533132142111356931324330631843602412540295482841975783884766801266552337129105407869020730226041538750535628619717708838029286366761470986056335230171148734027536820544543251801093230809186222940806718221638845816521738601843083746103374974120575519418797642878012234163709518203946599836959811
e: 3
ciphertext (c): 2205316413931134031046440767620541984801091216351222789180535786851451917462804449135087209259828503848304180574549372616172217553002988241140344023060716738565104171296716554122734607654513009667720334889869007276287692856645210293194853
--------
Solution
RsaCtfTool ( https://github.com/Ganapati/RsaCtfTool ) を使ったら解けました。
--------
$ python RsaCtfTool.py -n 374159235470172130988938196520880526947952521620932362050308663243595788308583992120881359365258949723819911758198013202644666489247987314025169670926273213367237020188587742716017314320191350666762541039238241984934473188656610615918474673963331992408750047451253205158436452814354564283003696666945950908549197175404580533132142111356931324330631843602412540295482841975783884766801266552337129105407869020730226041538750535628619717708838029286366761470986056335230171148734027536820544543251801093230809186222940806718221638845816521738601843083746103374974120575519418797642878012234163709518203946599836959811 -e 3 –uncipher 2205316413931134031046440767620541984801091216351222789180535786851451917462804449135087209259828503848304180574549372616172217553002988241140344023060716738565104171296716554122734607654513009667720334889869007276287692856645210293194853
[+] Clear text : b’picoCTF{e_w4y_t00_sm411_34096259}’
--------
Flag: picoCTF{e_w4y_t00_sm411_34096259}
[Reversing]: be-quick-or-be-dead-1 (200 points)
Challenge
You find this when searching for some music, which leads you to be-quick-or-be-dead-1. Can you run it fast enough? You can also find the executable in /problems/be-quick-or-be-dead-1_3_aeb48854203a88fb1da963f41ae06a1c.
Hint: What will the key finally be?
Attachment:
- be-quick-or-be-dead-1 (ELF 64-bit)
Solution
これは、いろんな解き方があると思います。
alert(1)でタイマーを起動していて、flagをprintする前にタイムアウトしちゃうので、gdbでalert(1)をコールしているところで止めて、引数1を0xffとかに書き換えたらオッケー。
[Reversing]: keygen-me-1 (400 points)
Challenge
Can you generate a valid product key for the validation program in /problems/keygen-me-1_2_74297f5e012cf93ee059a2be15d77734
Attachment:
- activate (ELF 32-bit)
Solution
Ghidra使っていきます。
|
|
|
|
処理を完全に把握しなくても、16文字のうちの先頭からの15文字をなんか処理して、最後の1文字となんかしているのがわかれば十分でした。
以下のチェック関数があって、文字の範囲は決まっているので、Brute Forceで行けます。
|
|
ここからが答えです。
以下のようにシェルスクリプトで解きました。適当な15文字と、最後の1文字をBrute Forceしてます。なお、ローカルで実行する際には、flag.txtを自前で適当に作っておきます。
|
|
flag: AAAAAAAAAAAAAAAO
[General Skills]: script me (500 points)
Challenge
Can you understand the language and answer the questions to retrieve the flag? Connect to the service with nc 2018shell.picoctf.com 1542 Maybe try writing a python script?
$ nc 2018shell.picoctf.com 1542 Rules: () + () = ()() => [combine] ((())) + () = ((())()) => [absorb-right] () + ((())) = (()(())) => [absorb-left] (())(()) + () = (())(()()) => [combined-absorb-right] () + (())(()) = (()())(()) => [combined-absorb-left] (())(()) + ((())) = ((())(())(())) => [absorb-combined-right] ((())) + (())(()) = ((())(())(())) => [absorb-combined-left] () + (()) + ((())) = (()()) + ((())) = ((()())(())) => [left-associative] Example: (()) + () = () + (()) = (()())
Solution
なんかカッコが多くて、複雑そうに見えるけど、()を別の文字に置き換えるとわかりやすいと思います。
x + x = xx ((x)) + x = ((x)x) x + ((x)) = (x(x)) (x)(x) + x = (x)(xx) x + (x)(x) = (xx)(x) (x)(x) + ((x)) = ((x)(x)(x)) ((x)) + (x)(x) = ((x)(x)(x)) x + (x) + ((x)) = (xx) + ((x)) = ((xx)(x))
要は、カッコが何重になっているかによって処理が異なっていて、以下の通り。
- 同じ深さの場合は、連結
- 左の方が深かければ、左のカッコの中の最後に連結
- 右の方が深かければ、右のカッコの中の先頭に連結
書いたコード。
|
|
[コード解説]
- コードの中でも、わかりやすくするために()をxで置き換えてます。
+
で分けて、2つずつ処理。1個目をa、2個目をbにしてます。- aとbそれぞれ、余計な文字を削除してます。
- あとは、それぞれカッコの深さを調べて、規則にのっとった処理をするだけ。
以下が、実行結果です。
~/Python2$ ./pico_script_me.py [+] Opening connection to 2018shell.picoctf.com on port 1542: Done Rules: () + () = ()() => [combine] ((())) + () = ((())()) => [absorb-right] () + ((())) = (()(())) => [absorb-left] (())(()) + () = (())(()()) => [combined-absorb-right] () + (())(()) = (()())(()) => [combined-absorb-left] (())(()) + ((())) = ((())(())(())) => [absorb-combined-right] ((())) + (())(()) = ((())(())(())) => [absorb-combined-left] () + (()) + ((())) = (()()) + ((())) = ((()())(())) => [left-associative] Example: (()) + () = () + (()) = (()()) Let's start with a warmup. ((())()) + (()) = ??? > ((())()(())) Correct! Okay, now we're cookin! () + ((())()) + (()()()) = ??? > (()(())()(()()())) Correct! Alright see if you can get this one. (()(())) + (()(())) + (()) + (()()()()()()()()) + (()()()(())()()) = ??? > (()(()))(()(())(())(()()()()()()()()))(()()()(())()()) Correct! This one's a little bigger! ((())()) + ()() + ()() + (()()) + (()(())((()))(((())))((((()))))) + (((()())()())()) + ()() + (()()) + (()(())((()))(((())))((((()))))) + (((()(())((()))(((())))()()))()) = ??? > ((((())()()()()()(()()))()(())((()))(((())))((((()))))(((()())()())())()()(()()))(()(())((()))(((())))((((())))))((()(())((()))(((())))()()))()) Correct! Ha. No more messin around. Final Round. (()(())()()())(()()()(())()()) + ((()(())(()()()()()()()()))()(((()()())()())()())) + (((())()()())()(())((()))(((())))((((()))))) + (((()())()(((()()())()())()()))((((()))))(((())))((()))(())()) + (()()(()))(()()()(())()()) + (((()())()(())(()))((((()))))(((())))((()))(())()) + (()()()())(()()()()()()()()) + (((()(()))((()())()())())((((()))))(((())))((()))(())()) + ((()()(((()()())()())()()))()(())((()))(((())))((((()))))) + ((()(())())((()(())((()))(((())))()()))()(((((()))))(((())))((()))(())())) + ((()())(()()()()()()()())((()())()())()) + ((()()()()()())()()()(())()()) + ((()()()())((((()))))(((())))((()))(())()) + ((()(())()()()())()(((()()())()())()())) + (()()((((()))))(((())))((()))(())()) + ((()())()(())) + (((()()()()()()()()())((()())()())())((()(())((()))(((())))()()))()) + ((()(())()(()))()(((()()())()())()())) + (()(()))((())()()()) + (()()()()()(())((()))(((())))((((())))))(((((()))))(((())))((()))(())()) + (()()()()())(()()()) + (((()())(())()()())((()(())((()))(((())))()()))()) + ((()())((()(())((()))(((())))()()))()) + (((()()())()(()))((()(())((()))(((())))()()))()) + (()()()(((()()())()())()())) + ((()()()((()())()())())()(((()()())()())()())) + (()()(())()()()) + ((()(())()()()())()(((()()())()())()())) + ((()()())((()(())((()))(((())))()()))()(((((()))))(((())))((()))(())())) + ((())()()()()) + ((()()()()(((()()())()())()()))((()(())((()))(((())))()()))()) + (()()()()()()) + (((()())()(()))((())())((()(())((()))(((())))()()))()) + (((()()()())()()()(())()())((()(())((()))(((())))()()))()) + (()()())(()()()) + (()(())()()()(())) + (((()()()(())()())((()())()())())((((()))))(((())))((()))(())()) + (()()()()()())(()()()()()()()()) + (()()(())()()())(()()()(())()()) + (()(())()(())) + ((()()())(()()())()()()(())()()) + ((()())((()(())((()))(((())))()()))()(()(())((()))(((())))((((())))))) + ((()(())()(()()()))((()())()())()) + ((()(())()()()())()(((()()())()())()())) + ((()()())()(())(())) + ((()(((()()())()())()()))()(())((()))(((())))((((()))))) + ((()())(()()()()()()()())()(((()()())()())()())) + (((()())()(()))(()()()(())()())((()(())((()))(((())))()()))()) + (((()()())()(((()()())()())()()))()(())((()))(((())))((((()))))) + (()()(()))((())())(()()()(())()()) = ??? > ((((()(())()()())(()()()(())()())(()(())(()()()()()()()()))()(((()()())()())()()))((())()()())()(())((()))(((())))((((())))))(((()())()(((()()())()())()()))((((()))))(((())))((()))(())()(()()(()))(()()()(())()()))(((()())()(())(()))((((()))))(((())))((()))(())()(()()()())(()()()()()()()()))(((()(()))((()())()())())((((()))))(((())))((()))(())())((()()(((()()())()())()()))()(())((()))(((())))((((())))))(()(())())((()(())((()))(((())))()()))()(((((()))))(((())))((()))(())())((()())(()()()()()()()())((()())()())())((()()()()()())()()()(())()())((()()()())((((()))))(((())))((()))(())())((()(())()()()())()(((()()())()())()()))(()()((((()))))(((())))((()))(())())((()())()(())))(((()()()()()()()()())((()())()())())((()(())((()))(((())))()()))()((()(())()(()))()(((()()())()())()()))(()(()))((())()()())(()()()()()(())((()))(((())))((((())))))(((((()))))(((())))((()))(())())(()()()()())(()()()))(((()())(())()()())((()(())((()))(((())))()()))())((()())((()(())((()))(((())))()()))())(((()()())()(()))((()(())((()))(((())))()()))()(()()()(((()()())()())()()))((()()()((()())()())())()(((()()())()())()()))(()()(())()()())((()(())()()()())()(((()()())()())()())))((()()())((()(())((()))(((())))()()))()(((((()))))(((())))((()))(())())((())()()()()))((()()()()(((()()())()())()()))((()(())((()))(((())))()()))()(()()()()()()))(((()())()(()))((())())((()(())((()))(((())))()()))())(((()()()())()()()(())()())((()(())((()))(((())))()()))()(()()())(()()())(()(())()()()(()))(((()()()(())()())((()())()())())((((()))))(((())))((()))(())())(()()()()()())(()()()()()()()())(()()(())()()())(()()()(())()())(()(())()(()))((()()())(()()())()()()(())()()))((()())((()(())((()))(((())))()()))()(()(())((()))(((())))((((())))))((()(())()(()()()))((()())()())())((()(())()()()())()(((()()())()())()()))((()()())()(())(()))((()(((()()())()())()()))()(())((()))(((())))((((())))))((()())(()()()()()()()())()(((()()())()())()())))(((()())()(()))(()()()(())()())((()(())((()))(((())))()()))()(((()()())()(((()()())()())()()))()(())((()))(((())))((((())))))(()()(()))((())())(()()()(())()())) Correct! Congratulations, here's your flag: picoCTF{5cr1pt1nG_l1k3_4_pRo_0466cdd7} [*] Closed connection to 2018shell.picoctf.com port 1542
最後はめっちゃ長いのが来た!
flag picoCTF{5cr1pt1nG_l1k3_4_pRo_0466cdd7}
[Forensics]: LoadSomeBits (550 points)
Challenge
Can you find the flag encoded inside this image?
Hint1: Look through the Least Significant Bits for the image
Hint2: If you interpret a binary sequence (seq) as ascii and then try interpreting the same binary sequence from an offset of 1 (seq[1:]) as ascii do you get something similar or completely different?
Attachment:
- pico2018-special-logo.bmp
Solution
BMPファイルだったので、「青い空を見上げればいつもそこに白い猫」が使えなかったし、ちょっと意味不明な部分もあったので、他の方のWriteupを少し参照しました。
「青い空を見上げればいつもそこに白い猫」で解いているWriteupもあったので、目からウロコでした。
他のWriteupを見たところ、C言語で解いているWriteupは無かったので、Cで書いてみました。 ```C #include
int sub( int offset ) { FILE *fp; int c; int i; char ch;
if ( ( fp = fopen( "pico2018-special-logo.bmp", "rb" ) ) == NULL ) {
perror( "Can't fopen" );
return -1;
}
for ( i = 0 ; i < offset ; i++ ) {
fgetc( fp );
}
i = 7;
ch = 0;
while ( ( c = fgetc( fp ) ) != EOF ) {
c = c & 0x01;
ch = ch | ( c << i);
i--;
if ( i < 0 ) {
if ( ( ch >= 0x20 ) && (ch <= 0x7e ) ) {
printf( "%c", ch );
}
i = 7;
ch = 0;
}
}
puts("");
fclose( fp );
return 0;
}
int main( void ) { int i; for ( i = 0 ; i < 8 ; i++ ) { sub( i ); } }
|
|
全部載せると多いので、2つくらい載せます。Ghidraのデコンパイルの特徴なのか、returnのところで判定文が出てきます。コードの読み方は、その下に記載しています。
|
|
==> (param_1[0] + param_1[1]) mod 0x24 = 0xE
```C uint key_constraint_02(int param_1)
{ char cVar1; char cVar2; uint uVar3;
cVar1 = ord((int)*(char )(param_1 + 2)); cVar2 = ord((int)(char *)(param_1 + 3)); uVar3 = mod((int)cVar2 + (int)cVar1,0x24); return uVar3 & 0xffffff00 | (uint)(uVar3 == 0x18); }
|
|
最初、これを完全に見逃していて、相当悩みました。
gdbで追っかけて行ったときに、ord()を読んだ後に、レジスタの値が予想外に変わる所まで見てたんですが、別途定義されているという発想が全くなかったです。。。凹○ コテッ
以下は、そのord()も加味した解法です。(pico_ord()の部分を後付しました。)
文字の範囲も限られているので、Brute Forceでやりました。
|
|
captureamerica@pico-2018-shell:/problems/keygen-me-2_1_762036cde49fef79146a706d0eda80a3$ ./activate 0E6IW8BX07K00Q9D Product Activated Successfully: picoCTF{c0n5tr41nt_50lv1nG_15_W4y_f45t3r_3846045707}
Flag: picoCTF{c0n5tr41nt_50lv1nG_15_W4y_f45t3r_3846045707}
[Reversing]: be-quick-or-be-dead-3 (350 points)
Challenge
As the song draws closer to the end, another executable be-quick-or-be-dead-3 suddenly pops up. This one requires even faster machines. Can you run it fast enough too?
Hint: How do you speed up a very repetitive computation?
Attachment:
- be-quick-or-be-dead-3 (ELF 64-bit)
Solution
まず、Ghidraにかけます。
以下の箇所が再帰関数になっており、時間がかかるところです。
|
|
ヒントにしたがって、“再帰関数 高速化” でググってみると、「メモ化」というのがありました。
“一度処理した結果を保存しておく方法を「メモ化」といい、保存する量が多くなってくるとメモリの使用量は増えますが、処理が圧倒的に高速になります。” とのことです。
Rubyでできるようなので、普段Rubyは使わないのですが、ウェブで見つけたサンプルをならって以下を書きました。
|
|
最初に実行した際に、以下のエラーが出ました。
$ ruby be-quick-or-be-dead-3_solve.rb be-quick-or-be-dead-3_solve.rb:7:in `calc': stack level too deep (SystemStackError)
これは、RUBY_THREAD_VM_STACK_SIZEという環境変数で回避できるそうなので、テキトーに100MBでやってみました。
$ export RUBY_THREAD_VM_STACK_SIZE=100000000 $ ruby be-quick-or-be-dead-3_solve.rb 0x2f8cdc3f
gdbでcalc()をコールする直前でbreakして、戻り値をセットして、jumpでcalc()をスキップします。
|
|
Flag: picoCTF{dynamic_pr0gramming_ftw_22ac7d81}
Author CaptureAmerica @ CTF フラxxグゲット
LastMod 2019-09-05