The Penetration Testing Mindset

Many penetration testers want to send an exploit to pop a box and call it a day, but a single exploit is rarely enough to achieve the goals of a penetration test. Most penetration testing goals require exploiting multiple weaknesses throughout a system. As an example, a tester may need to compromise an internal user’s machine and then pivot through it to get to an internal database. Testers with the one-and-done mindset will find themselves often frustrated and failing to accomplish the goals of the penetration test. Instead, a good tester will continually assess the goals of the test, their current information or access level, the information or access level they still need, and the ways in which they can obtain what is needed from their current vantage point. An example of the continual assessment mindset is given below.

Gail needs to access the sensitive data stored in a Microsoft SQL server. To access the server she wants to get the username and password for a domain administrator account, an SQL admin account, or the sa account. Gail currently has network access to the server and other devices on the network. She attempts to brute force the sa account, which fails. Next, she scans the SQL server and other network devices for exploitable vulnerabilities. The SQL server does not have any exploitable vulnerabilities but another server on the network does. After compromising the other server, she now has access to the hashed password of the local administrator account. She then accesses the SQL server using the local administrator password but still cannot access the data in the SQL server. Fortunately, a SQL admin account was used to run a Windows service. Gail is able to use her administrative access to impersonate the SQL admin’s security token and is then able to access the data in the SQL server.

By continually assessing her situation, Gail was able to accomplish her goal even though she did not achieve the goal in a direct manner.

I was a Junior

In the beginning

I went to college to study Computer Science. Unfortunately, the college I attended only offered a Math major with a Computer Science concentration, so that’s what I did. I learned programming from an excellent man named Dan Fetters. He taught me two very important programming lessons: first, never trust user input and second, always document your code. I left college and started working as a developer, which lasted about a year. I took a teaching job, High School Math, for another year. That did not go well but it prepared me for teaching at New Horizons, where I learned a lot of new skills and became and MCSE. The MCSE lead to a Sysadmin job, which included some information security. That lasted almost three years and then I moved on to work for an systems integrator who asked me to get my CISSP. This company was a sinking ship so I got out as soon as I could thanks to a man named Bill Karwisch, who decided to take a chance on a junior infosec guy with a newly minted CISSP.

I am the Junior

Bill Karwisch had the most profound impact on my infosec career. He took a chance on me when I didn’t think I was worth taking a chance on. He taught me how to write reports, I’m pretty sure my first few reports had more revisions than actual text but Bill was patient and I eventually learned. I’ve moved on to work with two pentesting companies since then and I’ve never received bad remarks about my report writing skills. Bill is also the reason I learned Ruby; we had a system that would automate a lot of our report writing and it was written in Ruby. It was at this time that I started my Twitter account and met people like Carlos Perez and started contributing to Metasploit with his help and encouragement. Working with Bill I was primarily doing auditing not pentesting and I wanted to be a pentester. The company paid for me to get my OSCP which allowed me to get my next job as a real penetration tester.

Still the Junior

I moved on to work with Sword & Shield, a penetration testing firm in Knoxville, it was there that I met Adrian (@sawaba), Adam (@tatanus), and Matt (@realconehead). These three men took me under their wings and taught me so many new skills, I can’t count the number of times I would go to one of them and say, “I’m on a box with this level of access, what can I do from here?” They would get up from their desks, take time out of their busy schedule and walk me through some new technique or give me ideas of attacks to try. With their support I became a better tester and I was able to then teach other folks.

Finally the Senior

I moved on from Sword & Shield and worked a stint at Tenable doing API development but I had to get back into penetration testing. Even with my 2.5 year lapse, AppSec Consulting took a chance on me an hired me as a Senior Penetration Tester. It wasn’t a complete lapse as I was doing contract pentests while I worked for Tenable, but still I was a chance none the less. Now that I am a Senior, I try to help out whoever I can however I can. I get questions by email and Twitter about how to use tools I’ve written, talks I’ve given, or my free Intro to Penetration Testing book. I am also encouraging AppSec to hire Junior penetration testers and train them up. I know they see the value in it and I hope we start hiring some soon. In the mean time, if you are a Junior penetration tester and want help moving up, email me. I’ll help you in any way I can, resume review, career advice, conference talk reviews, whatever. If you are a Senior penetration tester, I would encourage you to do the same for any Juniors you know.

Finding and Exploiting MongoDB

MongoDB is a NoSQL database used to handle backend data for many web applications. Often, MongoDB is used to store configuration information, session information, and user profile information. By default the MongoDB does not require authentication for client access. This is not a problem if MongoDB is only listening on localhost but often it is not.

Finding MongoDB Servers

By default MongoDB listens on port 27017, which is not in the Nmap top 1000 port list or the /etc/services list used by Nessus. You will need to scan specifically for this service if you want to find it.

Although MongoDB does not have authentication enabled by default it can be enabled. Nessus, Metasploit , and Nmap have methods to identify MongoDB servers that are not using authentication.

Manual Interaction with MongoDB

The easiest way to interact with MongoDB is to use the Mongo CLI client, mongo. On Kali2 you can install the client by installing the mongodb-clients package with apt-get. After installing mongodb-clients you can connect to the MongoDB server using:

mongo [hostname]:[port]/[database_name]. 

The local database holds information about the server while the admin database holds any credentials stored on the server.

Once connected you can use the following commands to gather data from the server:

  • show databases – Shows all of the databases on the server.
  • use – Uses the specified database name
  • show collections – Shows a list of collections (similar to tables) in the database.
  • db.findOne() – Displays the first entry in the collection. All collection entries are JSON objects.
  • db.find() – Displays a list of entries in the collection.
  • it – Iterates through the list returned by find().

More information about using the mongo shell can be found here:

Scripted Interaction with MongoDB

One of the nice things about the mongo shell is we can write JavaScript files and have them executed on the server. So if there is a particular set of information you would like to find you can write a script to gather that data for you.

To run a script specify the script file on the as part of the mongo command to connect to the server:

mongo [hostname]:[port]/[database_name] [script_name]

Example Script to Gather Mongo Server Info

Download the access.js script run it against the “local” database on the MongoDB server. We need to specify the “local” database because that is where the startup_log collection is stored.

If you have a list of IP addresses that you want to gather information about, you can use a simple bash one-liner along with the access.js script to gather the data.

for i in $(ip_list); do echo $i; mongo $i/local access.js; done;

Example Script to Gather Mongo Credentials

In some cases the MongoDB server may be configured to allow users to access it both with credentials and anonymously. In this case it may be possible to access the server anonymously and gather the plaintext or hashed credentials from the admin database. The creds.js script will gather MONGODB-CR and SCRAM-SHA-1 hashes from the “admin” database on the MongoDB server if they exist.

As of April, 2016, oclHashcat could not crack either form of password hash. You can use the MongoDB password cracking scripts, which are available here and here to crack these passwords.

Fixing the Problem

MongoDB can be configured to require authentication for all user accounts and as of Mongo3.0 it supports a strong hashing algorithm, SCRAM-SHA-1. I highly recommend enabling authentication for all users and using the SCRAM-SHA-1 hashing algorithm with strong passphrases.

Cracking MongoDB Passwords

On a recent penetration test I came across a number of MongoDB servers that allowed unauthenticated access. Using this access, I was able to download the MongoDB user accounts and their associated password hashes. MongoDB uses two password hashing schemes. The first is called MONGODB-CR, which is a simple MD5 hash of the string username:mongo:password. This password hashing algorithm is no longer used and has been replaced by a much stronger password hashing algorithm based on SCRAM-SHA-1. When MongoDB introduced the SCRAM-SHA-1 algorithm they didn’t update the older user accounts to use the new hashing algorithm so you will still find servers that use the older MONGODB-CR format.

I wrote two scripts to crack these passwords. The first,, is a Python script for cracking MONGODB-CR passwords that is multithreaded and can process a large number of passwords quickly because MD5 password hashes are easily calculated. This script uses Python3 and the standard libraries. To use this script run ./ hashfile wordfile, where hashfile is file containing a list of colon (:) separated usernames and password hashes (one per line) and wordfile is a list of password candidates.

The second script, mongoscram.go, is written in Go, which worked much faster than Python for calculating the SCRAM-SHA-1 passwords. Since the SCRAM algorithm uses PBKDF2 with 10,000 iterations, cracking these passwords is compute intensive and takes a lot of time. The mongoscram.go script can test over 300 passwords per second for one user. To use the script you will need to install the latest version of the Go language and you will need to install the PBKDF2 library using go get You will also need to define the environment variable GOPATH (On Linux or Mac add export GOPATH=$HOME/go to your .bash_profile file.).

When running the mongoscram.go script you will need to provide the username, password_file, salt, and stored_key. The username, salt, and stored_key can be obtained from the MongoDB server. The password_file is the list of passwords you want to test.

As always, if you have any trouble running the scripts or getting them to work please let me know and I will be happy to help.

DNS Footprinting at Scale

Recently I wrote an article on doing domain footprinting. Shortly after that article a friend on Twitter mentioned that he was doing zone transfer research against the Alexa top 1 million web sites so I decided to try my hand at it as well. My work on that project eventually resulted in code, raw data, and some analysis, which can be found here:

Part of the analysis from the zone transfer research resulted in a huge list of subdomain names. I took the top 10,000 subdomains and used a modified version of the script to foot print the Alexa top 1000 domains.

The modified script,, that I used and the resulting dataset in tar.gz format are both available. The script only works on one domain at a time so I used the GNU parallel program to run 8 copies of the script in parallel. I can get through the top 1000 domains within a day. Most domains take anywhere from 2 -10 minutes depending on how fast their DNS servers respond.

To run the script in parallel use the following command:

parallel -a domain.list -j 8 ./dnsbrute {1} subdomain.list

Make sure you have Python3 installed and that the dnspython3, netaddr, and ipwhois libraries are installed.