picoCTF 2024 - Writeup

# まえがき

今年の1月からTryHackMeをやり始め、少しずつ出来ることが増えてきた実感があったので、 **picoCTF2024** に参加してみました。

### 結果

47問中25問解きました。開催期間が2週間あるので、分からない問題も勉強しながら取り組めると良かったのですが、（グラフを見るとわかる通り）最初と最後しか参加できず、、、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/982f1ce3-6613-802e-0d06-608cb555075c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/f924b46a-bc3d-8162-b94f-22d75e1e6ec1.png)


### 感想


TryHackMeなどとは毛色が違ってブルートフォースなどの力技で解ける問題は無く、細かい技術を学ぶことが出来て良かったです。
解けそうで解けない問題が多かったので、他の方のWriteupを参考に復習したいです。

今回のコンテストでは、以下の要素を初めて体験することが出来ました。

- 壊れたバイナリの修正
- Reversing体験（IDA, gdb-peda）
    - ZFフラグを立てて分岐させる
- NoSQLi
- メモリを書き換える

開催前にpicoGymでForensicの過去問を少し練習で解いていたので、Forensicは取り掛かりやすかったです。開催期間中は時間がなく、闇雲にやってしまっていたのですが、今後は慣れるのに時間が必要そうなツール(IDA,gdb,バイナリ編集ツール等)をゆっくり触ってみたいなと思いました。

また、heapやformat stringシリーズは、典型的な問題だと思うので解けるべきなのですが、勉強不足で解くことが出来ませんでした。開催前に似たような問題を解いておくべきでした。
あとはリバースエンジニアリングが全然できなかったので、練習したいです。

# Forensics

## Scan Surprise (50)

QRコードを携帯のカメラで読んだらわかった。

## Verify (50)

大量のハッシュファイルと復号するための実行ファイルが与えられる。
実行ファイルのパスを修正してあげるとうまく実行でき、フラグが取得できる。

```shell
┌──(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のビッグエンディアンに変換するコードを作成します。

```python
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
```

ファイルを開くとフラグが表示されました（あえて全体を表示していません）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/550278b4-3a1c-4143-9a0e-b7a08085d1f9.png)


# 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ということなのかな。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/01ea15aa-93a2-78d3-a4a8-62de0ff1063d.png)


## heap1 (100)

ソースコードを読むと、safe_varの値がpicoになれば良いみたいです。

```c
 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のほかに３つあるようです。

```
└─$ 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)

基本的な２進数の計算に答える問題。
```
+,-,*,|,<<, >>, &
```

などの演算をさせられます。暗算は面倒なので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の場合は反転させて入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/b6e3d58c-753a-8bb7-b174-63cc1668e1ff.png)

```
// 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)

開発者ツールで確認したら見つかりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/c6461195-3015-e0a5-e9a9-50371bab984f.png)


## IntroToBurp(100)×

BurSuiteの練習問題のようなので絶対解けると思ったのですが解けず。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/4ac0a0bd-ef41-35a9-a649-1cad4f1078b5.png)

適当にフォームに入力してBurpで見てみると、以下のようなリスクエストが送信されているようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/5e5c3580-9e38-1ccf-bd51-5564e54596a3.png)

適当にSQLインジェクションを試すがなかなかうまくいかない～


## No Sql Injection(200)

> Hint: SQLインジェクションだけでなく、NoSQLインジェクションも存在します。サーバーが送り返しているものをすべて見てください。

NoSQLインジェクションを調べて適当に入れてみるとログイン出来ました。
ログインフォームで以下をemail, passwordに入れます。

```
{ "$ne": null }
```

ログイン出来ました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576001/dd0d8393-b805-cf38-41ca-7b9d14df854f.png)

ソースコードを確認すると、tokenのデフォルトが `{{flag}}` であるとわかります。
どうしたらこの部分を取得することが出来るでしょうか？

```js
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して、最後に反転させるように逆関数を書いていきます。

```python
  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)

こちらもデコードする関数を書く問題です。
以下のコードを書きました。

```python
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"==========================")
```

実行してみると、コードが出力される。
長い暗号文だなーと思っていたのですが、コードを暗号化したものだったようです。

```python 
$ 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する
```

https://qiita.com/miyagaw61/items/248a486cca671686c58c

https://wisdom.sakura.ne.jp/programming/asm/assembly13.html

https://www.ninjastars-net.com/entry/2019/09/11/190000




# 解けなくて悔しかった問題

- **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の問題で読みたい記事

https://qiita.com/hachan0179/items/ff6053039353dbf53d8f