AverageSecurityGuy

Security, Programming, Pentesting

About

Mastodon

Linked In

Projects

Cheat Sheets

Book

Facebook Private Phone Number Enumeration

I started playing around with the Facebook bug bounty a few weeks ago and submitted a few issues that I considered bugs but wasn’t sure if Facebook would. I wanted to get an idea about what they considered a security/privacy issue and what they did not. Based on Facebook’s bug bounty details, vulnerabilities that reveal public information are not eligible for the bug bounty program. Public information includes your profile picture, username, ID, name, current cover photo, gender, and anything you’ve shared publicly.

While playing around with the account recovery feature of Facebook I noted that you could enter either an email address or a phone number and it would return a list of users that are related to the information provided. This allows you to choose your account and continue the account recovery process. I decided to try a little experiment with my account created specifically for bug hunting. This account had no data associated with me except my email address. I entered my email address in the account recovery form and immediately found my account. This email address is my primary contact information so I can’t make it non-public.

Next, I decided to add my mobile phone number and I set it to Only Me, which implies the phone number is not public. Based on my email interchange with Facebook, they disagree. Anyway, I returned back to the account recovery page and entered what I thought was my private phone number. Facebook immediately brought up my account using the phone number. I then deleted the phone number from my account and tried again. Facebook still associated my private phone number with my account.

At this point I realized that anyone who added a phone number to Facebook expecting it to be private (Only Me) would have that private number associated with their account. If you could enumerate a large number of accounts using the phone number then you could associate users with phone numbers they haven’t made public. I submitted a report to Facebook to inform them that I could enumerate private information and they said,

I’m sorry, but we will not reward this submission. Information about recovering an account (ex: discovering another user’s recovery question or viewing some of their friends to recover an account) isn’t a security vulnerability on its own, as Facebook doesn’t guarantee the privacy of this information and it’s not considered sensitive.

Also, there are protections for account recovery information. For example, before showing security questions or friends to unlock an account, we check if the request seems legitimate. Legitimacy is determined by a number of factors like IP and information about the computer being used to log in. There are also protections which would stop any larger-scale abuse of this feature.

I think they missed the point. I don’t care that I can view friends, recovery questions, etc. I care that a “private” phone number I gave to Facebook is publicly associated with my account. I then asked,

If I can show that your protections against large scale abuse of enumeration are not effective would that make a difference?

Their response was,

Thank you for the proof-of-concept code! One of the reasons we don’t consider this as qualifying under our bug bounty program is that we have rate limiting in place which would kick in once you submitted enough requests. The code may work for a small amount of phone numbers, but you wouldn’t be able to enumerate a large batch.

As mentioned by Samuel, we also only show certain recovery options based on numerous factors including whether you’ve logged in on a specific machine before, or on the same network.

Facebook has the final say in all bug bounty submissions and even though I was frustrated, I dropped it and asked for permission to disclose. Since Facebook does not consider this a security or privacy issue they granted permission.

If you’d like to test this out yourself, add a phone number to your account and set the permissions to Only Me. You should then be able to logout and attempt an account recovery using the phone number you provided. If you’d like to try this at a larger scale you can use the proof of concept code on GitHub.

Here’s some sample output from the script:

$ python fb_phone_enum.py
4233103102
==========
Heather AndLuis Rojas - https://www.facebook.com/profile/pic.php?cuid=AYiKBhR95ZslM8LR_MDEz0dA0z-yb5-aO_OrZ7A7scnGqJM3ORm7elou0oNC4XReyxanVoqWq-LcluyZyWl-yXlmNOhOCWMMLdy_oK37lgEobbMG7vdNITFgsG9dCDDVG1VyaTFsOq_pJkgnW_02vU9B_VTyBwMyUh27H0YL2Jxirw

4233103103
==========
4233103103 - None

4233103105
==========
Kenneth Walker - https://www.facebook.com/profile/pic.php?cuid=AYi1Wew0LNbw2QuBdUZeDlmMpG7_vDEoffe9TMdJK8MPuTW_HVNMSLyfaBSw7K0brjBrWu9N_trDMpZL7q4ZAbe4MopDGLObTeJyV7ECtcBvPsDx_2MuqEEk9nfFEkPAeo5fAnzVz18FC08szzQB2fK-K52p4KCT4-OVcXnYntyWvA

4233103106
==========
Suzanne Churlik - https://www.facebook.com/profile/pic.php?cuid=AYjIDFk4u58z-4PCVaaiWR4mt4t8kDLyObehJn_1F2Sy6Gp-fyZc9YLIboh2Pj3_96UYYO849564mrmWflIVblFX7F5J_v3YqJYRKcYRgMQF88OCdIFZTo6wO7iMDNphy4mi48k9isb5Dtt9FEsF2sIifXCz2pkbKJtkL8xIBJyGWQ

Happy Hunting.

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: https://docs.mongodb.org/getting-started/shell.

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.

https://docs.mongodb.org/manual/tutorial/enable-authentication/ https://docs.mongodb.org/manual/release-notes/3.0-scram/

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, mongodb_cr_crack.py, 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 ./mongodb_cr_crack.py 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 http://golang.org/x/crypto/pbkdf2. 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.