By Troy Kent
Threat Researcher

Here’s a post for those of you that are newer to the game, or maybe haven’t had the opportunity to see this kind of traffic before (BTW if that’s the case it is probably good for your organization). What am I talking about? Credentials in plain text, specifically the kind that you’ll find in Basic Auth. You might be thinking: “But Troy (you know my name because it’s listed at the top of the page^), it’s 2017, we may not have flying cars, but surely people know to encrypt their credentials so they’re not in plain text.”

I feel you, but in my experience, this is not at all the case. I’ve seen plenty of examples of credentials in plain text flying across the network and I’m sure I’m not the only one. You may have seen this kind of traffic in the form of login pages that don’t redirect the user to HTTPS, which is certainly still an issue, but I wanted to take some time to focus on a type of creds-in-plain-text-ish traffic that often flies under the radar: HTTP Basic Auth.

You may think that Basic Auth is dated and therefore no longer used in production networks. It may be dated, but it’s certainly still in use. Over a week-long period, in a single environment with Awake, we saw roughly 400k sessions with an HTTP Authorization header. These sessions originated from 443 different machines and were destined for 100 unique hosts (both internal and external to the network). Of those, 8.1k sessions were HTTP Basic Auth from 60 different devices to 12 hosts. More than 64k session were SPNEGO-based Kerberos and NTLM HTTP Authentication. 349k (an overwhelming majority) of the sessions are using Bearer Tokens, which is more secure than Basic Auth because it includes tokens that expire; however, it even states in the abstract of the RFC that other security controls are necessary:

“To prevent misuse, bearer tokens need to be protected from disclosure in storage and in transport.”

Across Awake deployments, we see an average of nearly half a million instances of Basic Auth, 200k Bearer Tokens, and a total of over 2 million Authorization headers – per day. So, while it is true that only 9 out of 10 dentists agree on what toothpaste you should use, all observed networks were sending credentials in Base64 over HTTP.

It’s called “Basic” for a reason

If you’re not familiar with Basic Auth, you’re in luck. There’s an RFC that’s worth the read! Ok seriously it may be a little too verbose, so I will leave it as a homework assignment. For now, let me fast forward to the part of the RFC relevant to our discussion:

http basic auth rfc

You may recognize the string after “Basic” as Base64 encoding (there’s yet another RFC if you’re interested in the nuts and bolts).

Side note: I often see people using online base64 decoders, but I’ll show you how I do it on OSX and Linux. It’s faster, doesn’t need an internet connection, and you don’t have to worry if the site is secretly keeping your decoded base64 in logs somewhere. First, copy the base64 encoded string to your clipboard (use the one above for practice). Then run one of the following commands in the terminal:

OSX:

decoding base64

Linux:

decoding base64

Either way, the output in this case should be: “Aladdin:open sesame”. Obviously, this will work with any base64 encoded string in your clipboard, and you can redirect to a file if it is a binary / larger file (like a base64 encoded email attachment). Looking back at the RFC, ‘Aladdin’ is the user-id and ‘open sesame’ is the password. “Authorization” is an HTTP header just like User-Agent, Host, etc.

Here’s a real(ish) world example:

GET / HTTP/1.1

Host: 0.0.0.0

Connection: keep-alive

Authorization: Basic YWRtaW46WW91IEdvdCBNeSBBZG1pbiBQYXNzd29yZCA6KA==

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Accept-Encoding: gzip, deflate

Accept-Language: en-US,en;q=0.8

Has it sunk in yet? Using Basic Auth over HTTP isn’t going to send your username and password in plain text, but the data is encoded with a simple, widely used, and widely understood encoding scheme that doesn’t use any kind of key or secret to encode/decode the data. So really, what’s the difference? I imagine that if anyone has infiltrated your network and has access to logs or network traffic that has Basic Auth headers, then they would at least recognize the base64 and be able to decode it (if not, then they need to go back to skiddie skool).

Another scenario that is potentially more likely is an insider threat. Imagine that you are using some product in your SOC that uses Basic Auth for authentication, and the username and password used to login are the same as your LDAP credentials for everything else in the organization. You may have a badass password that can’t be reasonably brute forced or guessed. You may have the best password reset policy in the biz. You may use a more secure form of authentication for all your other tools. However, it doesn’t matter once you login to the tool that uses Basic Auth over HTTP one time. Once you do that, your username and password are flying across the network in base64 – naked for all to see. Now think about how you and everyone else in the SOC (and probably some other departments) have access to your SIEM. What’s preventing them from logging into the SIEM, searching for logs containing Basic Auth traffic, and then using your creds to wreak havoc / steal things / send your boss an inappropriate email in your name / prank you by changing your desktop background to a ransomware screenshot? Nothing, that’s what. You’re relying on good intentions as a security policy.

Demo Time!

I like to give little demos for the things that I talk about (even for something as simple as Basic Auth). I think it really helps drive the point home when you can see if for yourself. In this demo, I’ll show you how to set up the ELK stack with Basic Auth, and then one simple way to make it more secure.

It is worth saying that I’m not picking on the ELK stack – it does not force you to use Basic Auth and it does offer plenty of reasonable alternatives. It’s just a simple example of a tool that may be in your environment that is easy to configure with Basic Auth and depending on what version you’re using and what method you use to install it, it may default to Basic Auth. I wonder how many folks just leave the default.

For this example, I’m going to use Digitalocean to spin up a VPS with the ELK stack already installed. If you’re following along at home, simply click along:

ELK stack setup

ELK stack setup

ELK stack setup

ELK stack setup

ELK stack setup

ELK stack setup

ELK stack setup

ELK stack setup

ELK stack setup

You can choose the cheapest size available for ELK (it’s $10 a month, but don’t worry, it’s only $0.015/hour and this won’t take longer than 15 minutes). The location doesn’t really matter, but I suppose it makes sense to get something closer to your physical location. Make sure you add an SSH key so you can log in and don’t have to support password logins out-of-the-box. Go ahead and create your droplet.

Once the droplet creation is complete, SSH to it. You should see a message like the following:

ELK stack message of the day

The white box will be replaced with your server’s IP address, and the password will be whatever randomly generated password they give you. Notice that you’re going to be accessing Kibana over HTTP.

Exit your VPS. Fire up Wireshark (or however you prefer to monitor your network traffic) and visit Kibana on your VPS (copy/paste the URL that was echoed in the message of the day above into your browser). You will be asked to enter your credentials (also in the message of the day).

http basic auth

Login and then click around the interface a bit. It won’t have any logs in it, but that’s ok because we’re just interested in seeing the Basic Auth behavior.

In Wireshark you should see an initial GET for the root web page:

GET / HTTP/1.1

Host: 0.0.0.0

Connection: keep-alive

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Accept-Encoding: gzip, deflate

Accept-Language: en-US,en;q=0.8

Followed by a 401 Unauthorized response:

HTTP/1.1 401 Unauthorized

Server: nginx/1.4.6 (Ubuntu)

Date: Thu, 10 Aug 2017 20:43:11 GMT

Content-Type: text/html

Content-Length: 605

Connection: keep-alive

WWW-Authenticate: Basic realm=”Restricted Access”

Followed by the first authenticated request:

GET / HTTP/1.1

Host: 0.0.0.0

Connection: keep-alive

Authorization: Basic YWRtaW46MXA3VWxHZUkyMQ== ← Copy this to your clipboard

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Accept-Encoding: gzip, deflate

Accept-Language: en-US,en;q=0.8

And here’s our creds:

decoding basic auth base64

Each of the subsequent requests (the ones from you clicking around in the UI) will also have the Authorization header:

Authorization: Basic YWRtaW46MXA3VWxHZUkyMQ==

There’s also the possibility that if you’re using the ELK stack to store / query HTTP metadata on your network and you’re parsing out the Authorization header, that you would not only see the Basic Auth in your requests, but also in the HTTP response data if your query results include a previous authenticated request for your Kibana instance! #BasicAuthception.

What? Basic Auth is Evolving!

Now that I’ve pointed out that Basic Auth is a sneaky, but just-as-destructive cousin of plain text credentials, what can be done to thwart this nasty beast? Well, honestly, there’s plenty of options out there, including not using Basic Auth.

However, if you want to keep Basic Auth around, you could just use it over SSL instead of plain text HTTP. It’s still potentially true that the username/password is being stored in web server logs somewhere depending on how you have your logging setup, but at least you won’t be constantly sending your credentials in plain text over the network. How difficult is it to setup Basic Auth over SSL? Why don’t I just show you.

What you need:

  1. Your VPS server from earlier
  2. A domain registered to you and an A record pointing said domain to your VPS
  3. 5-10 minutes

SSH into your VPS and run the following commands:

Certbot will ask you if you want to make HTTPS optional or required. Pick the second option to ensure that only HTTPS is allowed. Now exit your VPS, fire up Wireshark and visit your domain.

Boom! Secure connection 🙂

SSL turned on

And what does it look like in the network traffic? TLS traffic of course, no more plain text-ish usernames and passwords. If you’re having trouble narrowing down the traffic in Wireshark, you can use the following filter (replacing 0.0.0.0 with your server’s IP address):

Of course, there’s more to be done if you want to further secure your credentials, for example, fixing your weak Diffie-Hellman parameters and configuring the firewall on your VPS, but I will leave that to the reader to look into. Also, as I mentioned before, it may be prudent to avoid Basic Auth altogether.

This was simply an example of one option that would make Basic Auth more secure that doesn’t take that much time or effort to pull off; an option, when as an analyst you happen upon Basic Auth in the network you’re monitoring.

Gotcha! (Shameless Plug)

Speaking of monitoring networks, how does one find HTTP traffic using Basic Auth? Well, that depends on what tool(s) you’re using. There are few different ways to search for it using Awake, depending on what you’re specifically looking for.

The following will search for any HTTP traffic that has an Authorization header and has “Basic” in an HTTP header, which is what you would expect from RFC 7617 compliant traffic.

Security analytics to search for any HTTP traffic that has an Authorization header and has “Basic” in an HTTP header

It is also simple to search for particularly interesting Basic Auth traffic. For example, to search for any Basic Auth traffic that is trying to authenticate using an admin account, you could use the following query:

security analytics to find any Basic Auth traffic that is trying to authenticate using an admin account

You guessed it! The Base64 encoded string from the query above decodes to “admin:”. Ironically, the traffic shown above in the UI was using a long, randomly generated password.

You can also search for Basic Auth traffic that is not using any credentials at all. This may seem like a stretch, but the screenshot below is from an appliance in a production network.

security analytics to find traffic not using any credentials

It’s even possible to search for specific passwords. For example, if you wanted to see if anyone is using Basic Auth with the passwords ‘password’ or ‘admin’ you could use the following search:

security analytics to find Basic Auth with the passwords ‘password’ or ‘admin’

Any of these queries can also be turned into a Watchlist so you can see when new web apps are being deployed in or accessed by the network you’re responsible for.

security analytics watchlist to find basic auth

Basic Auth isn’t something exciting like a 0-day, or the next Shellshock, Freak, Poodle or Struts exploit; not everything that’s a real security flaw has to be sexy or have a cool name. Basic Auth is simply that thing that might be flying around your network, quietly giving away your secrets to the first person who looks for them. I challenge you to go looking for it in a network you are responsible for, I bet you’ll be surprised what you’ll find.

Security
Security Analysis
Security Operations Center
Security Research