I found myself in the office on Saturday night, mainly because the frozen pizza selection is more expansive than mine at home, and I wanted to get a head start on my project for this week. It was a normal Static Application Security Test (SAST), which follows a mostly pre-defined process, with embellishments depending on the languages and frameworks at play.
The first step in that process is to search for hardcoded passwords. I dug out the simple and ugly password regex I’ve created for this and did a search for /pa?ssw?o?r?d?|pwd/gi across the entire codebase. This regex covers all of the standard ways I’ve seen “password” used as a variable name in code. Without fail I got back:
After digging through all the results and parsing out the false positives I ended up with a total of 30 hardcoded passwords. All of them were database connection strings spread across 20 total users, including multiple users with admin access to the database. Our recommendation for this is simple:
Passwords should never be hardcoded in the source code.
The reasoning behind this is that there are multiple attack paths that result in source code/arbitrary file disclosure. Error messages, public Github repos, arbitrary file read, “oopsies” email attachments, and shoulder surfing being just a few.
A typical escalation path that exploits hardcoded passwords could start with an XML External Entity (XXE) Injection. An application that is vulnerable to XXE will allow us to read (almost) any file on the server. Through this an attacker will fingerprint the technology at play and target the important source code files. For example, a web application using the Python Django framework will contain a settings.py file. This file will sometimes contain hardcoded passwords for the DB connection. With some luck/bruteforce an attacker can find the source code directory and read the settings.py file via XXE.
POST /xxe HTTP/1.1
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY settings SYSTEM "file:///django-app/settings.py" >]>
An attacker can now take this information and connect directly to the database, which is public-facing because someone assumed authentication was enough. Once an attacker has this amount of access, any number of paths can be followed to further infiltrate the network. This attack extends to anything that requires a password: admin pages, config pages, mail servers, etc…
We need various forms of secrets (passwords, api keys, etc…) on the box somehow and the goal is to find the method that minimizes the organization’s risk to the greatest degree. Our suggested remediation regularly has the goal of assigning them through environmental variables on the server. Environmental variables are the recommended method due to the low likelihood of an attacker gaining access to them. I’ve only seen them exploited in two common scenarios, overly-verbose debug pages left running in prod, or using OS command execution to list all of the environmental variables*. Both of which are easily combatable in large code repositories. Environmental variables also allow a more scalable solution, as rotating secrets will only require one configuration change.
Like most things in security, except 0days, all the information is out there. A lot of people just aren’t aware of the vulnerability or what the proper way to fix it is. Because of that I won’t rehash how every platform implements environmental variables, but I will identify what I think are the best resources for doing so.
The handling of sensitive data for an app should always be done at the deployment/orchestration level. This ensures that secrets are stored and managed away from the web servers and databases. Here are some of the popular deployment and orchestration frameworks, with their related resources:
This is an interesting method using Docker Secrets. Unfortunately they are stored in files, but are the recommended method inside of the Docker ecosystem.
In the end, secrets don’t belong in the code. Proper distribution will decrease the reach an attacker has through other methods of attack and protect an organization by allowing them to rotate secrets easily and often.
This blog is an attempt at describing a holistic solution to secret handling that will work in every environment. Using environmental variables is still not the most secure method, as plaintext sensitive information is available to every user on the box. To combat this a platform-specific method is usually required, which Windows and Linux both offer.
We’re curious to hear how other organizations handle secrets in their code and what improvements could be made to further advance the topic. Let us know @NetSPI or by leaving a comment below!
PTaaS is NetSPI’s delivery model for penetration testing. It enables customers to simplify the scoping of new engagements, view their testing results in real time, orchestrate faster remediation, perform always-on continuous testing, and more - all through the Resolve™ vulnerability management and orchestration platform.
We help organizations defend against adversaries by being the best at simulating real-world, sophisticated adversaries with the products, services, and training we provide. We know how attackers think and operate, allowing us to help our customers better defend against the threats they face daily.
At NetSPI, we believe that there is simply no replacement for human-led manual deep dive testing. Our Resolve platform delivers automation to ensure our people spend time looking for the critical vulnerabilities that tools miss. We provide automated and manual testing of all aspects of an organization’s entire attack surface, including external and internal network, application, cloud, and physical security.
Our proven methodology ensures that the client experience and our findings aren’t only as good as the latest tester assigned to your project. That consistency gives our customers assurance that if vulnerabilities exist, we will find them.