1. Testing Random Numbers
1.1. Problem
You have found some indentifiers, session IDs, or other aspects of
your application that you need to ensure are random. To do this, you’ll
have to use software that can perform various statistical
analyses.
1.2. Solution
You want to use the National Institute of Standards and Technology
(NIST) Statistical test suite available from http://csrc.nist.gov/groups/ST/toolkit/rng/index.html.
This software helps you evaluate the output of a random number generator
to see if it complies with the randomness requirements in the Federal
Information Processing Standards (FIPS) 140-1 document. Although the FIPS standards are
intended to regulate U.S. government agencies, many non-government
agencies adopt them, since they are clear, comprehensive, and endorsed
by well-respected leaders in industry. To fully understand the
mathematics behind how the tests work, you would read and understand the
NIST documentation and operating instructions, since the NIST
mathematicians created the tests. Fortunately, the Burp suite contains
the FIPS tests in an easier-to-use format than the original source code.
We’ll use that for our analysis.
The first step to analyzing the randomness of identifiers is to
collect a lot of them. Burp has the ability to collect lots of
identifiers from web pages (whether in the URL, the body of the page, or
the cookie), as shown in Figure 1.
Many times the identifier you want to analyze will not be so
accessible. Consider that you want to analyze the randomness of a
document ID or a numeric user ID. You won’t want to create 10,000 users
just to get 10,000 user IDs. And if your system doesn’t already have
10,000 documents in it, you won’t have 10,000 document IDs to analyze.
This is a time when you’ll need to collaborate with the application
developers. Get them to write a small demonstration program that invokes
all the same APIs and methods, in the same order and with the same
parameters. Save the output to a file, with one identifier per
line.
When you have your manually gathered data, go to Burp and go to
the Sequencer pane. Choose Manual Load and press the Load button. Locate
the file with the random data on your hard disk, then click the Analyze
Now button.
1.3. Discussion
Very often, because of how mathematicians define and understand
randomness, you will get a lot of handwaving and wishy-washy answers
from experts about whether something is sufficiently random. You want a
big green check mark saying “totally secure.” Burp is helpful in this
regard because it will tell you when the data it analyzes are “poor,”
“reasonable,” and “excellent.” Figure 2 shows
one of the FIPS tests of the variable that was sampled in Figure 9-1. It overall passes the FIPS 140-1 secure
randomness requirements, with one bit failing.
We have to
understand what our attackers might possibly do and what attacks are
feasible before we make claims about how impossible or improbable it is
to attack our random numbers.
2. Abusing Repeatability
2.1. Problem
In many circumstances, allowing a malicious user to try the same attack
repeatedly gives him a great advantage. He can attempt a variety of
different combinations of input, eventually finding the one that breaks
your application. Remember that the strength of identifiers and
passwords depends on only allowing a limited number of guesses. Learn to
recognize repeatable actions that should have limits via this
recipe.
2.2. Solution
For any given feature, any action, any functionality that you’ve
just performed, ask yourself—how can I do this again? If you can do it
again, how many times can you do it? Lastly, what’s the impact if you do
it that many times?
That is a very simple method of determining potential abuse of
repeatability. Of course, with a complex web application, it would be
tremendously time-consuming to attempt to repeat every action and every
system state.
Instead, create a state
transition diagram or perhaps control flow diagram of your application.
These diagrams portray how users move through your application—what they
can do, when, and where. You’ll want to investigate the areas where the
diagram contains loops or cycles. If a user can take several actions to
eventually get back to the starting point, you have a repeatable
action.
Knowing the expected result of this repeatable action allows you
to predict the effects of repeated action. If the repeated effect could
degrade system performance, destroy data, or just annoy other users, you
have a security issue.
Thus, existing test cases often make the best sources for testing
repeatability, as you already have the state transitions, input, and expected result written. If
you think a particular test case has the potential to do damage when
repeated, go ahead and repeat it. Better yet, automate it to repeat for
you.
2.3. Discussion
PayPal gives you money for signing up with a bank account.
Admittedly, it is always less than 15 cents—the deposited amount is used
to verify that you successfully received the money and that it really is
your account. PayPal uses several methods to ensure that you can’t sign
up for too many bank accounts. Imagine the consequences if one could
write a script to open and cancel PayPal accounts several times a
second, collecting 10–15 cents each time. Sound far-fetched? It
happened. You can read about it at http://www.cgisecurity.com/2008/05/12.
Even if your application doesn’t handle money, much of
authentication depends on not being able to guess at a password. The ability to guess repeatedly removes the
strength of the password’s secrecy. At the same time, users expect to be
able to try several passwords; it’s impossible to remember them all the
time.
This makes guessing passwords the classic repeatable action. Most
users’ passwords are not very strong. Even if you enforce password
strength, such as requiring numbers or special characters, there will
still be weak passwords that just barely cover these requirements. For
instance, given additional requirements, the top password of all time
(“password” itself) gets reborn as “p@ssw0rd.”
Guessing a single user’s password can be quite difficult, given
that each request to the server will have some normal lag. This
restricts the sheer volume of password attempts possible in a finite
length of time. However, if any account is a potential target,
probabilistically an attacker is much better off trying the ten most
common passwords against a thousand users than trying the top thousand
passwords against ten specific users. For example, if 1% of all your
users have the password “password1,” then an attacker need only attempt
that password on a few hundred accounts to be confident of
success.
The standard defense against this sort of attack is to lock
accounts after a certain number password attempts. Most implementations
of this fail to adequately protect users; either it opens up new
possibilities of attack or
does not prevent password attempts against many different users.
When it comes down to it, almost any action that is repeatable and
could affect other people should have a limit. You do not want one user
to be able to submit a hundred thousand comments on your blog or sign up
for every possible username. One should not be able to send five
thousand help requests to the help desk via an online form. Yet actions
with no major implications might not deserve limits; if a user wishes to
change their own account password every day, there is little
impact.