# picoCTF-General_Skills writeup
picoCTF All General Skills Challenge Writeup
[TOC]
## picoCTF 2025
### FANTASY CTF
> EASY
題目給了一個 `netcat` 連線資訊 連進去之後一直按 `Enter` 會出現第一個選單
```
Options:
A) *Register multiple accounts*
B) *Share an account with a friend*
C) *Register a single, private account*
[a/b/c] >
```
隨便選一個就好 繼續按 `Enter` 會遇到第二個選單
```
Options:
A) *Play the game*
B) *Search the Ether for the flag*
[a/b] >
```
這次選 `a` 繼續按 `Enter` 按完就有 flag 了
---
### Rust fixme 1
> EASY
這個是考 rust 的 code review
```rust
use xor_cryptor::XORCryptor;
fn main() {
// Key for decryption
let key = String::from("CSUCKS") // How do we end statements in Rust?
// Encrypted flag values
let hex_values = ["41", "30", "20", "63", "4a", "45", "54", "76", "01", "1c", "7e", "59", "63", "e1", "61", "25", "7f", "5a", "60", "50", "11", "38", "1f", "3a", "60", "e9", "62", "20", "0c", "e6", "50", "d3", "35"];
// Convert the hexadecimal strings to bytes and collect them into a vector
let encrypted_buffer: Vec<u8> = hex_values.iter()
.map(|&hex| u8::from_str_radix(hex, 16).unwrap())
.collect();
// Create decrpytion object
let res = XORCryptor::new(&key);
if res.is_err() {
ret; // How do we return in rust?
}
let xrc = res.unwrap();
// Decrypt flag and print it out
let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer);
println!(
":?", // How do we print out a variable in the println function?
String::from_utf8_lossy(&decrypted_buffer)
);
}
```
按照這些步驟修正錯誤的語法
1. `let key = String::from("CSUCKS")` 結尾加入 `;`
2. `ret;` 改成 `return;`
3. `println!(":?", String::from_utf8_lossy(&decrypted_buffer));` 把 `":?"` 改成 `"{}"`
修正錯誤的語法後 在專案根目錄下執行 `cargo run` 就會輸出 flag 了
---
### Rust fixme 2
> EASY
一樣的 code review
```rust
use xor_cryptor::XORCryptor;
fn decrypt(encrypted_buffer:Vec<u8>, borrowed_string: &String){ // How do we pass values to a function that we want to change?
// Key for decryption
let key = String::from("CSUCKS");
// Editing our borrowed value
borrowed_string.push_str("PARTY FOUL! Here is your flag: ");
// Create decrpytion object
let res = XORCryptor::new(&key);
if res.is_err() {
return; // How do we return in rust?
}
let xrc = res.unwrap();
// Decrypt flag and print it out
let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer);
borrowed_string.push_str(&String::from_utf8_lossy(&decrypted_buffer));
println!("{}", borrowed_string);
}
fn main() {
// Encrypted flag values
let hex_values = ["41", "30", "20", "63", "4a", "45", "54", "76", "01", "1c", "7e", "59", "63", "e1", "61", "25", "0d", "c4", "60", "f2", "12", "a0", "18", "03", "51", "03", "36", "05", "0e", "f9", "42", "5b"];
// Convert the hexadecimal strings to bytes and collect them into a vector
let encrypted_buffer: Vec<u8> = hex_values.iter()
.map(|&hex| u8::from_str_radix(hex, 16).unwrap())
.collect();
let party_foul = String::from("Using memory unsafe languages is a: "); // Is this variable changeable?
decrypt(encrypted_buffer, &party_foul); // Is this the correct way to pass a value to a function so that it can be changed?
}
```
要修復的點
1. `borrowed_string: &String` 改為 `borrowed_string: &mut String`
2. `let party_foul` 改為 `let mut party_foul`
3. `&party_foul` 改為 `&mut party_foul`
更改完後一樣 `cargo run` 就會輸出 flag
---
### Rust fixme 3
> EASY
```rust
use xor_cryptor::XORCryptor;
fn decrypt(encrypted_buffer: Vec<u8>, borrowed_string: &mut String) {
// Key for decryption
let key = String::from("CSUCKS");
// Editing our borrowed value
borrowed_string.push_str("PARTY FOUL! Here is your flag: ");
// Create decryption object
let res = XORCryptor::new(&key);
if res.is_err() {
return;
}
let xrc = res.unwrap();
// Did you know you have to do "unsafe operations in Rust?
// https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html
// Even though we have these memory safe languages, sometimes we need to do things outside of the rules
// This is where unsafe rust comes in, something that is important to know about in order to keep things in perspective
// unsafe {
// Decrypt the flag operations
let decrypted_buffer = xrc.decrypt_vec(encrypted_buffer);
// Creating a pointer
let decrypted_ptr = decrypted_buffer.as_ptr();
let decrypted_len = decrypted_buffer.len();
// Unsafe operation: calling an unsafe function that dereferences a raw pointer
let decrypted_slice = std::slice::from_raw_parts(decrypted_ptr, decrypted_len);
borrowed_string.push_str(&String::from_utf8_lossy(decrypted_slice));
// }
println!("{}", borrowed_string);
}
fn main() {
// Encrypted flag values
let hex_values = ["41", "30", "20", "63", "4a", "45", "54", "76", "12", "90", "7e", "53", "63", "e1", "01", "35", "7e", "59", "60", "f6", "03", "86", "7f", "56", "41", "29", "30", "6f", "08", "c3", "61", "f9", "35"];
// Convert the hexadecimal strings to bytes and collect them into a vector
let encrypted_buffer: Vec<u8> = hex_values.iter()
.map(|&hex| u8::from_str_radix(hex, 16).unwrap())
.collect();
let mut party_foul = String::from("Using memory unsafe languages is a: ");
decrypt(encrypted_buffer, &mut party_foul);
}
```
這次要修正的點只有一個 把這個不安全的操作片段用 `unsafe` 包起來
```rust
let decrypted_slice = std::slice::from_raw_parts(decrypted_ptr, decrypted_len);
```
修改後
```rust
let decrypted_slice = unsafe {
std::slice::from_raw_parts(decrypted_ptr, decrypted_len)
};
```
一樣執行 `cargo run` 就會有 flag
---
### YaraRules0x100
> MEDIUM
把檔案下載下來後用密碼 `picoctf` 解壓縮得到 `suspicious.exe`
先用 `file` 查看後知道有用 `upx` 加殼
```bash
❯ file suspicious.exe
suspicious.exe: PE32 executable (GUI) Intel 80386, for MS Windows, UPX compressed
```
用 `upx` 解殼後用 `strings` 查看特徵字串並撰寫規則
```bash
upx -d suspicious.exe
```
規則寫完後用 `socat` 送出測試
```bash
socat -t60 - TCP:standard-pizzas.picoctf.net:55501 < rule.yar
```
最後經過不斷測試後和 ~~ChatGPT~~ 得到這個成功通過檢測的規則
```yar
rule TestRule {
meta:
description = "基於字串模式和API調用檢測可疑執行檔"
strings:
// UPX壓縮檔案的標記
$upx1 = "UPX0" ascii
$upx2 = "UPX1" ascii
$upx3 = "UPX!" ascii
// 可疑字串:可能與惡意行為相關的字串
$mal_str1 = "NtQueryInformationProcess" ascii wide // 進程查詢,常見於反調試
$mal_str2 = "DebugActiveProcess" ascii wide // 調試進程的API,通常與惡意程式有關
$mal_str3 = "DebugActiveProcessStop" ascii wide // 停止調試進程
$mal_str4 = "CreateProcessA" ascii wide // 用於創建新進程,可能會用來執行惡意程式
$mal_str5 = "TerminateProcess" ascii wide // 用於終止進程,可能用於終止監控或防禦程序
$mal_str6 = "CreateToolhelp32Snapshot" ascii wide // 用於列舉進程,常用於惡意進程掃描
$mal_str7 = "Process32FirstW" ascii wide // 進程掃描API
$mal_str8 = "Process32NextW" ascii wide // 進程掃描API
$mal_str9 = "Sleep" ascii wide // 用來使程序等待一段時間,常見於惡意行為
$mal_str10 = "OutputDebugStringW" ascii wide // 用於輸出調試字串,可能被用來進行調試或偵測
// 十六進制模式:可能的惡意代碼或數據
$hex1 = { 25 64 64 64 6C 21 30 } // "%dddl!0"
$hex2 = { 62 33 60 35 64 35 6C 35 } // "b3`5d5l5"
$hex3 = { 6E 74 51 75 65 72 79 49 6E 66 6F 72 6D 61 74 69 6F 6E 50 72 6F 63 65 73 73 } // "NtQueryInformationProcess"
// 常見的 PE 區段名稱:用來識別檔案結構
$sect1 = ".text" ascii // 程式碼區
$sect2 = ".rdata" ascii // 只讀數據區
$sect3 = ".data" ascii // 數據區
$sect4 = ".rsrc" ascii // 資源區
$sect5 = ".reloc" ascii // 重定位區
$sect6 = ".upx" ascii // UPX 壓縮區
condition:
uint16(0) == 0x5A4D and // MZ 頭標誌,檢查是否為 PE 檔案
filesize < 100MB and // 檔案大小小於 100MB,避免錯誤檢測大檔案
(
// 1. 檢測 UPX 壓縮過的檔案並與可疑字串匹配
(1 of ($upx*) and 1 of ($mal_str*)) or
// 2. 檢測可疑的 API 調用,並結合檢查 PE 檔案的區段名稱
(all of ($mal_str*) and 1 of ($sect*)) or
// 3. 檢測特徵的惡意位元模式
(1 of ($hex*))
)
}
```
---
## picoCTF 2024
### Binary Search
> EASY
按照題目給的連線資訊 `ssh` 進去後就是一般的猜數字遊戲 用 `二分搜` 的概念就可以通關了
---
### Time Machine
> EASY
題目檔案下載下來解壓縮後的資料夾內有一個文字檔
```txt
This is what I was working on, but I'd need to look at my commit history to know why...
```
根據裡面的 `commit history` 我們可以猜測和 `git` 有關 查看 `git log` 就會找到 flag
``` bash
git log
```
---
### Super SSH
> EASY
直接根據題目給的連線資訊和帳號密碼 `ssh` 進機器就會輸出 flag
```bash
ssh -p 54321 ctf-player@titan.picoctf.net
```
---
### endianness
> EASY
根據題目給的挑戰原始碼的關鍵片段 我們可以知道
`little_endian` 指的是字串中的每個字母 `由後往前` 組成的 `hex`
`bin_endian` 指的是字串中的每個字母 `由前往後` 組成的 `hex`
```c
char *find_little_endian(const char *word)
{
size_t word_len = strlen(word);
char *little_endian = (char *)malloc((2 * word_len + 1) * sizeof(char));
for (size_t i = word_len; i-- > 0;)
{
snprintf(&little_endian[(word_len - 1 - i) * 2], 3, "%02X", (unsigned char)word[i]);
}
little_endian[2 * word_len] = '\0';
return little_endian;
}
char *find_big_endian(const char *word)
{
size_t length = strlen(word);
char *big_endian = (char *)malloc((2 * length + 1) * sizeof(char));
for (size_t i = 0; i < length; i++)
{
snprintf(&big_endian[i * 2], 3, "%02X", (unsigned char)word[i]);
}
big_endian[2 * length] = '\0';
return big_endian;
}
```
因為題目沒有限制連線時間 所以 `nc` 進去取得字串後對照 `ascii` 表就可以得出 要輸入的內容
```
Word: aaqua
Enter the Little Endian representation: 6175716161
Enter the Big Endian representation: 6161717561
```
> `a` -> `0x61`, `q` -> `0x71`, `u` -> `0x75`
---
### Commitment Issues
> EASY
根據題目標題可以猜到跟 `git` 的 `commit` 有關
檔案下載下來後用 `git log` 可以看到有一筆過往的 `commit`

用 `git checkout` 查看過往的 `commit` 紀錄
```bash
git checkout ea859bf3b5d94ee74ce5ee1afa3edd7d4d6b35f0
```
這時候再次查看 `message.txt` 就會看到 flag 了
---
### Collaborative Development
> EASY
這題提到了協作 所以我們聯想到跟 `git branch` 分支功能有關 先查看所有的分支
```bash
git branch -a
```
可以發現除了當前的 `main` 還有其他三個分支
```
feature/part-1
feature/part-2
feature/part-3
* main
```
用 `git switch` 切換過去每個分支後查看 `flag.py` 就可以搜集到每一段 flag 了
```bash
git switch feature/part-1
git switch feature/part-2
git switch feature/part-3
```
---
### Blame Game
> EASY
根據題目的敘述可以推測一樣和 `commit` 有關 直接 `git log` 發現非常多筆 分不出來
所以改成針對目錄下唯一的檔案查看 `log` 後就可以在 `Author` 的地方看到 flag
```bash
git log message.py
```
---
### binhexa
> EASY
這題 `nc` 到題目後 會叫我們進行一些 `binary` 運算
我們用 `python` 解題 因為要回傳 `binary` 所以用 `bin()` 包起來 以下提供幾個範例
> 要注意在數字最前面加入 `0b` python 才會當成是 `binary`
```python
num1 = 0b11011011
num2 = 0b10011110
bin(num1 << 1)
bin(num1 >> 1)
bin(num1 & num2)
```
得到的結果會是 `0bxxxxxxxx` 要記得把 `0b` 去掉再回傳給題目
運算到最後一個的時候要改成回傳 `hex` 把運算後的結果(記得要有 `0b` ) 一樣使用 python
```python
hex(result)
```
會得到 `0x???` 會傳這個數值就可以得到 flag
---
### dont-you-love-banners
> MEDIUM
題目給了兩個連線資訊 先 `nc` 到第一台機器後得到一個 password
```bash
❯ nc tethys.picoctf.net 61195
SSH-2.0-OpenSSH_7.6p1 My_Passw@rd_@1234
```
連線到第二台機器並回答問題 回答完就可以正常連線進機器了
```bash
❯ nc tethys.picoctf.net 53159
*************************************
**************WELCOME****************
*************************************
what is the password?
My_Passw@rd_@1234
What is the top cyber security conference in the world?
DEFCON
the first hacker ever was known for phreaking(making free phone calls), who was it?
John Draper
player@challenge:~$
```
接下來我們可以知道 flag 在 `/root` 底下 但我們沒有權限讀取
這邊有兩個解法:
1. symlink 符號連結
在 `/root` 底下雖然 `flag.txt` 讀不到 但我們可以讀到 `script.py`
```python
import os
import pty
incorrect_ans_reply = "Lol, good try, try again and good luck\n"
if __name__ == "__main__":
try:
with open("/home/player/banner", "r") as f:
print(f.read())
except:
print("*********************************************")
print("***************DEFAULT BANNER****************")
print("*Please supply banner in /home/player/banner*")
print("*********************************************")
try:
request = input("what is the password? \n").upper()
while request:
if request == 'MY_PASSW@RD_@1234':
text = input("What is the top cyber security conference in the world?\n").upper()
if text == 'DEFCON' or text == 'DEF CON':
output = input(
"the first hacker ever was known for phreaking(making free phone calls), who was it?\n").upper()
if output == 'JOHN DRAPER' or output == 'JOHN THOMAS DRAPER' or output == 'JOHN' or output== 'DRAPER':
scmd = 'su - player'
pty.spawn(scmd.split(' '))
else:
print(incorrect_ans_reply)
else:
print(incorrect_ans_reply)
else:
print(incorrect_ans_reply)
break
except:
KeyboardInterrupt
```
因為我們知道這個 `script.py` 是以 `root` 身份執行的
所以可以控制檔案內引用的 `/home/player/banner`
我們可以把 `/root/flag.txt` 連結到 `/home/player/banner` 這樣一登入機器時就會顯示 flag
```bash
ln -s --force /root/flag.txt /home/player/banner
```

2. root password crack 爆破 root 密碼
我們可以讀取 `/etc/passwd` 和 `/etc/shadow` 所以把 `root` 的密碼存到本地後
用 `unshadow` 產生 hash 再用 `john` 搭配 `rockyou.txt` 爆破密碼
```
passwd : root:x:0:0:root:/root:/bin/bash
shadow : root:$6$6QFbdp2H$R0BGBJtG0DlGFx9H0AjuQNOhlcssBxApM.CjDEiNzfYkVeJRNy2d98SDURNebD5/l4Hu2yyVk.ePLNEg/56DV0:19791:0:99999:7:::
```
```bash
unshadow passwd shadow > hash
❯ john --wordlist=rockyou.txt hash
Press 'q' or Ctrl-C to abort, almost any other key for status
iloveyou (root)
1g 0:00:00:00 DONE (2025-05-06 13:19) 8.333g/s 1066p/s 1066c/s 1066C/s 123456..diamond
```
得到密碼後就可以用 `su` 切換到 `root` 接著就可以讀取 `/root/flag.txt` 了
```bash
player@challenge:~$ su root
su root
Password: iloveyou
root@challenge:/home/player#
```
---
### SansAlpha
> MEDIUM
這題是一個 shell escape 的 sandbox 連線進去後 發現所有字母都被擋了
嘗試 `*/*` 發現 flag.txt 的位置 但是沒辦法讀取 改成使用 `?` 查看有沒有可用的指令
```shell
SansAlpha$ /???/??????
/bin/base32: extra operand '/bin/base64'
Try '/bin/base32 --help' for more information.
```
找到 `base64` 指令 我們先確定 `flag.txt` 的位置 `/home/ctf-player/blargh/flag.txt`
```shell
SansAlpha$ */*
bash: blargh/flag.txt: Permission denied
SansAlpha$ ../*
bash: ../ctf-player: Is a directory
SansAlpha$ ./*
bash: ./blargh: Is a directory
SansAlpha$ /????/??????????/??????/????????
bash: /home/ctf-player/blargh/flag.txt: Permission denied
```
確定好位置後就可以用 `base64` 加密了 但這時候遇到了一個問題 有另一個指令 `/bin/x86_64`
因為我們是用 `?` 這個萬用匹配字元 所以 `x86_64` 也符合條件 要繞過這個限制就要新增 `[!_]`
這個指令的意思是「任何不是底線的字元」這樣一來 `x86_64` 就不符合條件了
```shell
SansAlpha$ /???/????64 /????/??????????/??????/????????
/bin/base64: extra operand '/bin/x86_64'
Try '/bin/base64 --help' for more information.
```
最終的 payload :
```shell
SansAlpha$ /???/???[!_]64 /????/??????????/??????/????????
cmV0dXJuIDAgcGljb0NURns3aDE1X211MTcxdjNyNTNfMTVfbTRkbjM1NV8zNmE2NzRjMH0=
```
---
## picoCTF 2023
### repetitions
> EASY
一個經過 6 次 `base64` 加密的字串 所以重複解密 6 次就可以了
---
### useless
> MEDIUM
用題目給的資訊 `ssh` 連線進機器後有一個 shell script
```bash
#!/bin/bash
# Basic mathematical operations via command-line arguments
if [ $# != 3 ]
then
echo "Read the code first"
else
if [[ "$1" == "add" ]]
then
sum=$(( $2 + $3 ))
echo "The Sum is: $sum"
elif [[ "$1" == "sub" ]]
then
sub=$(( $2 - $3 ))
echo "The Substract is: $sub"
elif [[ "$1" == "div" ]]
then
div=$(( $2 / $3 ))
echo "The quotient is: $div"
elif [[ "$1" == "mul" ]]
then
mul=$(( $2 * $3 ))
echo "The product is: $mul"
else
echo "Read the manual"
fi
fi
```
在最下面那一行可以看到 `Read the manual` 所以我們用 `man` 查看這個腳本的名稱 `useless`
```bash
man useless
```
---
### Special
> MEDIUM
這次也是一個 shell 的 sandbox escape 這題的解法有非常多種 這裡整理一下我的及網路上找到的各種解法
1. ${0}
因為 ${0} 是只自己的意思 又因為當前執行的是 shell 所以執行 ${0} 就會再開啟一個 shell 新的 shell 就不會有限制了
2. <something><something>cmd
隨便輸入測試一下之後可以知道他似乎只會改前兩個字元 所以我們只要在前面加兩個 padding
就可以執行 command 了
```bash
((ls))
""ls""
``ls``
aa`ls`
a;`ls`
a;$(ls)
```
3. ${parameter=cmd}
這是 shell 的變數預設語法 他的意思是 如果變數 `parameter` 尚未定義 就把 `cmd` 指定給 `parameter` 並回傳 `parameter` 的值 也就是說
```bash
${a=ls}
```
其實等價於
```bash
a=ls
$a
```
4. Command Substitution 命令替換
我們先看一個例子 在這個例子中我們可以看到 我們執行 `ls` 後 輸出的結果被當成指令執行了
這是因為 `Command Substitution 命令替換` 會將一個命令的輸出作為參數傳給另一個命令
所以要注意 payload 中必須要有分隔符號 `;` 和命令替換 ` `` ` `$()`
```bash
Special$ a;`ls`
A;`ls`
sh: 1: A: not found
sh: 1: blargh: not found
```
知道這個技巧後 我們就可以想辦法讓他成功執行 `bash`
隨便找一個需要等待直到有輸入的指令 輸入 `bash` 後按下 `Ctrl + D` 就會成功執行了
> 在下面這個例子中 ``` a;`cat` ``` 就會變成 ``` a;`bash` ```
> 等待直到有輸入的指令我測試了一下除了 `cat` 還有 `tee` 和 `dd` 也都可以成功執行
```bash
Special$ a;`cat`
A;`cat`
sh: 1: A: not found
bash
<Ctrl + D>
ctf-player@challenge:~$
```
進到 shell 後就可以任意翻找檔案了 查看 `/etc/passwd` 可以找到這題的原始碼
```
ctf-player:x:1000:1000::/home/ctf-player:/usr/local/Special.py
```
```python
#!/usr/bin/python3
import os
from spellchecker import SpellChecker
spell = SpellChecker()
while True:
cmd = input("Special$ ")
rval = 0
if cmd == 'exit':
break
elif 'sh' in cmd:
print('Why go back to an inferior shell?')
continue
elif cmd[0] == '/':
print('Absolutely not paths like that, please!')
continue
# Spellcheck
spellcheck_cmd = ''
for word in cmd.split():
fixed_word = spell.correction(word)
if fixed_word is None:
fixed_word = word
spellcheck_cmd += fixed_word + ' '
# Capitalize
fixed_cmd = list(spellcheck_cmd)
words = spellcheck_cmd.split()
first_word = words[0]
first_letter = first_word[0]
if ord(first_letter) >= 97 and ord(first_letter) <= 122:
fixed_cmd[0] = chr(ord(spellcheck_cmd[0]) - 0x20)
fixed_cmd = ''.join(fixed_cmd)
try:
print(fixed_cmd)
os.system(fixed_cmd)
except:
print("Bad command!")
```
---
### Specialer
> MEDIUM
這題不知道被 ban 了哪些指令 嘗試過後發現 `echo` 沒有被擋
於是使用 `echo *` 當作 `ls` 用 `echo $(< <filepath>)` 當作 `cat`
嘗試一下就可以找到 flag 了
```bash
Specialer$ echo *
abra ala sim
Specialer$ echo $(< ala/kazam.txt)
return 0 picoCTF{<flag>}
```
---
### Permissions
> MEDIUM
這題是一個經典的提權題目 用 `sudo -l` 查看有哪些指令是可以以 `root` 身份執行而不用密碼的
```bash
picoplayer@challenge:~$ sudo -l
[sudo] password for picoplayer:
Matching Defaults entries for picoplayer on challenge:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User picoplayer may run the following commands on challenge:
(ALL) /usr/bin/vi
```
發現可以執行 `vi` 用 `vi` 查看 `/root/.flag.txt`
```bash
sudo /usr/bin/vi /root/.flag.txt
```
---
### chrono
> MEDIUM
根據題目敘述可以知道跟 linux 的排程 tasks 有關
查看 `crontab` 的設定檔就解開了
```bash
cat /etc/crontab
```
---
## Beginner picoMini 2022
### runme.py
> EASY
直接查看檔案或者用 `python` 跑一次都會有 flag
---
### PW Crack 1
> EASY
把密文和解密的 script 放在同一個目錄後 查看 `level1.py` 得到 password
執行 `level.py` 輸入密碼 `1e1a` 就會輸出 flag 了
---
### PW Crack 2
> EASY
跟第一關一樣的做法 但這次的 `level2.py` 裡面給的密碼是 `hex`
```
chr(0x64) + chr(0x65) + chr(0x37) + chr(0x36)
```
> 可以用 python `print(chr(0x64))` 來得到 ascii
解密後得到 `de76` 一樣執行並輸入密碼就可以得到 flag
---
### HashingJobApp
> EASY
連線進去題目後會給你一串文字要你回傳 `md5` 因為給的連線時間還蠻長的 所以不用寫腳本
把字串丟到 [CyberChef 的 md5 功能](https://gchq.github.io/CyberChef/#recipe=MD5()) 就會得到回傳的 `md5` 值
連續回答幾關後就回得到 flag

---
### Glitch Cat
> EASY
這題連線進去給了一串文字 用 python 的 `print` 把這些字串轉成 ascii 就會有完整的 flag
```python
print('picoCTF{gl17ch_m3_n07_' + chr(0x62) + chr(0x64) + chr(0x61) + chr(0x36) + chr(0x38) + chr(0x66) + chr(0x37) + chr(0x35) + '}')
```
---
### fixme1.py
> EASY
這題給了一個 python script 要我們把它復原 最下面這一行左邊多了空格 把空格刪掉再執行就好了

---
### fixme2.py
> EASY
這次我們可以看到在 `if` 的地方 `=` 只用了一個 改成 `==` 就可以通過了

---
### convertme.py
> EASY
這題要我們把數字從 `Decimal` 十進位轉成 `binary` 二進位
用 [CyberChef](https://gchq.github.io/CyberChef/#recipe=From_Decimal('Space',false)To_Binary('None',4)) 選取 `From Decimal` 和 `To Binary` 設定 `Byte Length` 為 `4`
回傳得到的 `binary` 就會輸出 flag 了
---
### Codebook
> EASY
把兩個檔案放在同個目錄後 用 `python` 執行 `code.py` 就會得到 flag
---
### Serpentine
> MEDIUM
這題給了一個 python script 執行後有三個選項 選擇 `print_flag` 會提示查看 source code
查看後發現沒有使用 `print_flag()` 修改程式碼加入 `print_flag()` 再次執行並選擇 b 就好了

---
### PW Crack 3
> MEDIUM
這次一樣要找密碼 但這次密碼有被加密過 `level3.py` 中有給明文的陣列(其中一個會是正確的)
裡面也有給加密的函式 直接仿造加密過程爆破出正確的明文密碼
```python
import hashlib
correct_pw_hash = open('level3.hash.bin', 'rb').read()
def hash_pw(pw_str):
pw_bytes = bytearray()
pw_bytes.extend(pw_str.encode())
m = hashlib.md5()
m.update(pw_bytes)
return m.digest()
pos_pw_list = ["6997", "3ac8", "f0ac", "4b17", "ec27", "4e66", "865e"]
for i in pos_pw_list:
user_pw_hash = hash_pw(i)
if user_pw_hash == correct_pw_hash:
print(i)
break
```
執行後就會得到正確的密碼了 用這個密碼執行 `level3.py` 就會得到 flag
---
### PW Crack 4
> MEDIUM
這題跟上一題做法一樣 更改 `pos_pw_list` 和 `correct_pw_hash` 就可以了
---
### PW Crack 5
> MEDIUM
這次的 `pos_pw_list` 變成了字典檔 所以我們要更改讀取方式 改成一行一行讀取
又因為字典檔內的字串不是 `str` 我們在加密前要先轉成 `str`
```python!
import hashlib
correct_pw_hash = open('level5.hash.bin', 'rb').read()
def hash_pw(pw_str):
pw_bytes = bytearray()
pw_bytes.extend(pw_str.encode())
m = hashlib.md5()
m.update(pw_bytes)
return m.digest()
with open('dictionary.txt', 'r') as pos_pw_list :
for i in pos_pw_list:
user_pw_hash = hash_pw(str(i.strip()))
if user_pw_hash == correct_pw_hash :
print(i)
break
```
---
## picoCTF 2021
### Magikarp Ground Mission
> EASY
連線進去後跟著步驟就可以拼出完整的 flag
1. `cat 1of3.flag.txt`
2. `cd /` `cat 2of3.flag.txt`
3. `cd ~` `cat 3of3.flag.txt`
---
### Tab, Tab, Attack
> EASY
解壓縮後 輸入 `cd` 之後一直按 `tab` 直到按不了之後會看到一個執行檔 執行後就有 flag 了
---
### Wave a flag
> EASY
先 `chmod +x` 給執行權限後 根據提示執行 `./warm -h` 就有 flag
---
### Python Wrangling
> EASY
把檔案都下載下來後 執行 `python3 ende.py -d flag.txt.en` 密碼使用 `pw.txt` 裡面的密碼
---
### Static ain't always noise
> EASY
檔案下載下來後用 `chmod +x` 給 `ltdis.sh` 執行權限 接下來執行 `./ltdis.sh static` 最後查看 `static.ltdis.strings.txt` 就可以找到 flag
---
### Nice netcat...
> EASY
連線進去會輸出一堆數字 把這些數字複製起來貼到 [CyberChef 的 From Decimal](https://gchq.github.io/CyberChef/#recipe=From_Decimal('Line%20feed',false))
選擇 `Line feed` 後就會有完整的 flag
---
### Obedient Cat
> EASY
就 `cat flag`。
---
## picoCTF 2019
### 2Warm
> EASY
題目要我們 convert the number 42 (base 10) to binary (base 2)
用 [CyberChef](https://gchq.github.io/CyberChef/#recipe=From_Decimal('Space',false)To_Binary('Space',4)) 轉換後把答案包在 `picoCTF{}` 提交就可以了
---
### First Grep
> EASY
給了一堆文字的檔案 用 `grep` 找出 flag
```bash!
grep picoCTF file
```
---
### Bases
> EASY
題目給了一個 `base64` 字串 `bDNhcm5fdGgzX3IwcDM1` 用 `base64` 解密後 包在 `picoCTF{}` 提交
---
### Warmed Up
> EASY
這題問了 `What is 0x3D (base 16) in decimal (base 10)?` 一樣用 [CyberChef](https://gchq.github.io/CyberChef/#recipe=From_Hex('Auto')To_Decimal('Space',false)) 後包在 `picoCTF` 就好了
---
### strings it
> EASY
根據標題用 `strings` 查看檔案 並用 `grep` 過濾出 flag
```bash!
strings strings | grep pico
```
---
### what's a net cat?
> EASY
連線進去就好了 `nc jupiter.challenges.picoctf.org 64287`
---
### Lets Warm Up
> EASY
題目說這個字在 `hex` 下是 `0x70` 轉換成 `Dec` 後得到 `112` 又問在 `ascii` 下會是什麼
對照 `ascii` 表就可以知道了 最後包在 `picoCTF` 提交就好了
```
❯ ascii
Usage: ascii [-adxohv] [-t] [char-alias...]
-t = one-line output -a = vertical format
-d = decimal table -o = octal table -x = hex table -b binary table
-h = this help screen -v = version information
Prints all aliases of an ASCII character. Args may be chars, C \-escapes,
English names, ^-escapes, ASCII mnemonics, or numerics in decimal/octal/hex.
Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex Dec Hex
0 00 NUL 16 10 DLE 32 20 48 30 0 64 40 @ 80 50 P 96 60 ` 112 70 p
1 01 SOH 17 11 DC1 33 21 ! 49 31 1 65 41 A 81 51 Q 97 61 a 113 71 q
2 02 STX 18 12 DC2 34 22 " 50 32 2 66 42 B 82 52 R 98 62 b 114 72 r
3 03 ETX 19 13 DC3 35 23 # 51 33 3 67 43 C 83 53 S 99 63 c 115 73 s
4 04 EOT 20 14 DC4 36 24 $ 52 34 4 68 44 D 84 54 T 100 64 d 116 74 t
5 05 ENQ 21 15 NAK 37 25 % 53 35 5 69 45 E 85 55 U 101 65 e 117 75 u
6 06 ACK 22 16 SYN 38 26 & 54 36 6 70 46 F 86 56 V 102 66 f 118 76 v
7 07 BEL 23 17 ETB 39 27 ' 55 37 7 71 47 G 87 57 W 103 67 g 119 77 w
8 08 BS 24 18 CAN 40 28 ( 56 38 8 72 48 H 88 58 X 104 68 h 120 78 x
9 09 HT 25 19 EM 41 29 ) 57 39 9 73 49 I 89 59 Y 105 69 i 121 79 y
10 0A LF 26 1A SUB 42 2A * 58 3A : 74 4A J 90 5A Z 106 6A j 122 7A z
11 0B VT 27 1B ESC 43 2B + 59 3B ; 75 4B K 91 5B [ 107 6B k 123 7B {
12 0C FF 28 1C FS 44 2C , 60 3C < 76 4C L 92 5C \ 108 6C l 124 7C |
13 0D CR 29 1D GS 45 2D - 61 3D = 77 4D M 93 5D ] 109 6D m 125 7D }
14 0E SO 30 1E RS 46 2E . 62 3E > 78 4E N 94 5E ^ 110 6E n 126 7E ~
15 0F SI 31 1F US 47 2F / 63 3F ? 79 4F O 95 5F _ 111 6F o 127 7F DEL
```
---
### mus1c
> MEDIUM
把題目給的歌詞丟到 [rockstar](https://web.archive.org/web/20190522020843/https://codewithrockstar.com/online) 得到一串數字 用 [CyberCbef](https://gchq.github.io/CyberChef/#recipe=From_Decimal('Line%20feed',false)) 解碼後 把得到的字串用 `picoCTF` 包起來就好
---
### 1_wanna_b3_a_r0ck5tar
> MEDIUM
這次沒辦法直接 decode 使用 [rockstart-py](https://github.com/yyyyyyyan/rockstar-py) 把這個語言轉成 `python`
```bash
pip intall rockstar-py
rockstar-py -i lyrics.txt -o lyrics.py
```
轉換後得到 python 後我們就可以知道要輸入 `10` 和 `170`
```python
Rocknroll = True
Silence = False
a_guitar = 10
Tommy = 44
Music = 170
the_music = input()
if the_music == a_guitar:
print("Keep on rocking!")
the_rhythm = input()
if the_rhythm - Music == False:
Tommy = 66
print(Tommy!)
Music = 79
Jamming = 78
print(Music!)
print(Jamming!)
Tommy = 74
print(Tommy!)
They are dazzled audiences
print(it!)
Rock = 86
print(it!)
Tommy = 73
print(it!)
break
print("Bring on the rock!")
Else print("That ain't it, Chief")
break
```
再次丟到 [rockstar](https://web.archive.org/web/20190522020843/https://codewithrockstar.com/online) 理論上會輸出 但因為他現在好像壞掉了 ~~所以直接抄答案~~
```
Keep on rocking!
66
79
78
74
79
86
73
Program completed in 118 ms
```
一樣 decode 後得到的放入 `picoCTF` 就可以了
---
### flag_shop
> MEDIUM
這題是考 `integer overflow 整數溢位` 查看原始碼可以看到這個片段
```c
int number_flags = 0;
fflush(stdin);
scanf("%d", &number_flags);
if(number_flags > 0){
int total_cost = 0;
total_cost = 900*number_flags;
printf("\nThe final cost is: %d\n", total_cost);
if(total_cost <= account_balance){
account_balance = account_balance - total_cost;
printf("\nYour current balance after transaction: %d\n\n", account_balance);
}
else{
printf("Not enough funds to complete purchase\n");
}
```
從這裡我們可以猜想 如果控制 `total_cost` 變成負數 這樣就會變成
`account_balance = account_balance - (-total_cost)` 實際會是 `+`
`int[32]` (32-bit) 的範圍是 `-2147483648 ~ 2147483647` 所以我們讓他大於 `2147483647`
> 低 32 位 0 ~ 2147483647
> 高 32 位 2147483647 ~ 4294967295 (這裡因為超過最大值所以會變成負數) 所以實際是
> -2147483647 ~ 0
嘗試 `9999999999` (10個9) 卻發現沒有成功 這是因為取模後沒有超過最大值
```c
900 * 9999999999 = 8999999999100
// 取低 32 位
8999999999100 % 2^32 = 2043513980
// 結果會是正的 所以不會造成 integer overflow
2043513980 < 2147483647
```
嘗試 `999999999` (9個9) 有成功 這是因為取模後有超過最大值
`total_cost` 就會變成 `-1943133060`
```c
900 * 999999999 = 899,999,999,100
// 取低 32 位
899999999100 % 2^32 = 2351834236
// 2351834236 對應的有符號整數是 2^32 - 2351834236 = 1943133060
// 再加上符號位(取負數) -1943133060
// 結果會是負的 所以會造成 integer overflow
2351834236 > 2147483647
```
成功拿到一堆錢後就可以去買 flag 了
---
### plumbing
> MEDIUM
連進去後會直接輸出一大坨東西 所以我們先把全部的輸出另存起來
```bash!
nc jupiter.challenges.picoctf.org 4427 > flag.txt
```
得到全部的輸出後 用 `grep` 尋找 flag
```bash
grep picoCTF flag.txt
```
---
### Based
> MEDIUM
連線進去後過三關
1. [From Binary](https://gchq.github.io/CyberChef/#recipe=From_Binary('Space',8))
2. [From Octal](https://gchq.github.io/CyberChef/#recipe=From_Octal('Space'))
3. [From Hex](https://gchq.github.io/CyberChef/#recipe=From_Hex('None'))
> 最後會發現其實都是||oven||
---
## picoGym Exclusive
### Big Zip
> EASY
下載下來後會是一個很亂的資料夾 裡面有一大堆檔案和資料夾 用 `grep` 搜尋 flag
```bash!
grep -r "picoCTF{" .
```
---
### First Find
> EASY
根據題目用 `find` 找到 `uber-secret.txt` 裡面就有 flag
```bash!
find . -name "uber-secret.txt"
```
~~但其實用上一題的 grep 就可以解了~~
---
### ASCII Numbers
> MEDIUM
把題目的字串丟到 [CyberChef 的 From Hex](https://gchq.github.io/CyberChef/#recipe=From_Hex('Auto')) 就可以了