Faster than rushing B.
cd deploy && docker compose up --build -d
We need to escape CSP restrictions and get the flag from /flag. CSP is set only if the cookie session is present.
if (ctx.GetCookie("session") != null) {
ctx.SetHeader(
"Cross-Origin-Resource-Policy", "same-origin"
);
ctx.SetHeader(
"Content-Security-Policy", (
"sandbox allow-scripts allow-same-origin; " +
"base-uri 'none'; " +
"default-src 'none'; " +
"form-action 'none'; " +
"frame-ancestors 'none'; " +
"script-src 'unsafe-inline'; "
)
);
}So here is another way: just remove the session cookie. But we can't remove it directly using document.cookie because session is HttpOnly.
The indended solution exploits the bug in System.Net cookie parsing:
System/net/System/Net/cookie.cs#L1033:
internal CookieToken FindNext(bool ignoreComma, bool ignoreEquals) {
m_tokenLength = 0;
m_start = m_index;
while ((m_index < m_length) && Char.IsWhiteSpace(m_tokenStream[m_index])) {
++m_index;
++m_start;
}
CookieToken token = CookieToken.End;
int increment = 1;
if (!Eof) {
if (m_tokenStream[m_index] == '"') {
Quoted = true;
++m_index;
bool quoteOn = false;
while (m_index < m_length) {
char currChar = m_tokenStream[m_index];
if (!quoteOn && currChar == '"')
break;
if (quoteOn)
quoteOn = false;
else if (currChar == '\\')
quoteOn = true;
++m_index;
}So if the cookie starts with " the parser interprets it as a double-quoted cookie. This way of parsing contradicts RFC, so we can exploit it.
Suppose the Cookie header looks like this: a="beb; session=admin; b=ra". There are actually 3 different cookies:
{
'a': '"beb',
'session': 'admin',
'b': 'ra"'
}
But the server would parse this as
{
'a': 'a="beb; session=admin; b=ra"'
}`
So the session cookie is inserted inside the a cookie. In order to place our cookie before session we need to set Path=/xss because chrome sorts cookies by path values.
Example solver: solution/solver.py