Authorization Attack Case Studies

Now that you have gotten the basic techniques of attacking web application authorization and session management, let's walk through some real-world examples from the authors' consulting work that illustrate how to stitch the various techniques together to identify and exploit authorization vulnerabilities.

Many of the hair-brained schemes we'll recount next are becoming less and less common as overall security awareness has improved, and the use of COTS authorization/ session management frameworks like ASP.NET and J2EE has become increasingly common. Nevertheless, it's astounding how many sites still out there suffer from such issues.

Note 

Obviously, the names and exact technical details in this chapter have been changed to protect the confidentiality of the relevant parties.

Horizontal Privilege Escalation

Horizontal privilege escalation is exploiting an authorization vulnerability to gain the privileges of a peer user with equal or lesser privileges within the application (contrast this with the more dangerous vertical escalation to higher privilege, which we'll discuss in the next section). Let's walk through the process of identifying such an authorization vulnerability using a fictitious web shopping application as an example.

First, we'll set up our browser so that you can view and manipulate all input and output to the web application, using any one of the HTTP analysis tools discussed in Chapter 1. Then we navigate to the site and immediately set out to identify how the site creates new accounts. This is almost brain-dead easy, since the "set up new account" feature is available right where existing users log in (these applications are usually eager to register new shoppers!), as shown in Figure 5-7.


Figure 5-7: The "set up new account" feature is usually available right at the application login screen.

Like most helpful web shopping applications, this one walks you through the account creation forms that ask for various types of personal information. We make sure to fill in all of this information properly (not!). Near the very end of the process we reach a Finish or Create Account option, but we don't click it just yet. Instead, we go to our HTTP analysis tool and clear any requests so we have a clean slate. Now it's time to go ahead and click the button to finalize the creation of the account, which results in the screen shown in Figure 5-8.


Figure 5-8: Successful account creation

Using our analysis tool, we look carefully at the request that was sent to the server in raw HTTP format. This is the actual POST that creates the account:

 POST /secure/MyAcctBilling.asp HTTP/1.1 Host: secure2.site.com Content-Type: application/x-www-form-urlencoded Content-Length: 414 Cookie: 20214200UserName=foo%40foo%2Ecom; 20214200FirstName=Michael; BIGipServerSecure2.TEAM.WebHosting=1852316332.20480.0000; LastURL= http%3A%2F%2Fwww%2Esite%2Ecom; ASPSESSIONIDQAASCCQS= GKEMINACKANKBNLFJAPKNLEM stealth=1&RegType=1&UserID=&Salutation=Mr&FirstName=Michael&LastName= Holmes&EmailAddress=foo@foo.com&Password1=testpassword&Password2= testpassword&DayPhone1=678&DayPhone2=555&DayPhone3=555&AltPhone1= &AltPhone2=&AltPhone3=&Address1=294+forest+break+lane&Address2=&City= atlanta&State=GA&Country=United+States&PostalCode=30338&CCName=0&CCNum= &CCExpMonth=0&CCExpYear=0000&update_billing_info=on&submit.x= 43&submit.y=13 

And here's the response from the server:

 HTTP/1.x 302 Object moved Set-Cookie: BIGipServerSecure2.TEAM.WebHosting=1852316332.20480.0000; path=/ Set-Cookie: UserID=2366239; path=/ Set-Cookie: ShopperID=193096346; path=/ Set-Cookie: 20214200UserName=foo@foo.com; path=/ Date: Wed, 12 Oct 2005 18:13:23 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET Location: https://secure2.site.com/secure/MyAcctBillingSuccess.asp?r=1 Content-Length: 185 Content-Type: text/html Cache-Control: private 

As we noted earlier in this chapter, cookies usually contain authorization information that is used to identify a session, so we take brief note of the Set-Cookie values in this response. They are summarized in Table 5-7.

Table 5-7: Cookie Information Gleaned from our Fictitious Web Shopping Application

Cookie Name

Value

20214200UserName

foo%40foo%2Ecom

20214200FirstName

Michael

BIGipServerSecure2.TEAM.WebHosting

1852316332.20480.0000

LastURL

http%3A%2F%2Fwww%2Esite%2Ecom

ShopperID

193096346

ASPSESSIONIDQAASCCQS

GKEMINACKANKBNLFJAPKNLEM

UserID

2366239

Notice that ShopperID and UserID look very promising . Their names obviously evoke authorization and their values are numeric, which means they are likely subject to simple manipulation attacks (next serial iteration, etc.).

Now, our task is figuring out how these cookies are actually used, and whether the ShopperID and UserID tokens are actually what we think they are. To do this, we'll need to replay these cookies to the application, preferably some functionality that might result in privilege escalation if abused. As we noted earlier in this chapter, one of the most commonly abused aspects of web authorization is account management interfaces, especially self-help functionality. With this in mind, we make a beeline to the interface within this web application that allows users to view or edit their own account information. Using SPI Dynamics' SPI ToolKit HTTP Editor (available to customers who've purchased their WebInspect product), we analyze the underlying HTTP of this interface while simultaneously walking through the graphical HTML interface of the application, as shown in Figure 5-9.


Figure 5-9: Analyzing the self-help account editing interface for our fictitious web shopping application using SPI Dynamics' SPI ToolKit HTTP Editor

Using this self-help functionality, we'll run a few replay tests with the would-be authorization cookies we found earlier. Here's how the cookies look when they're replayed back from the client to the server in an HTTP header:

 Cookie: 20214200UserName=foo%40foo%2Ecom; 20214200FirstName=Michael; BIGipServerSecure2.TEAM.WebHosting=1852316332.20480.0000; LastURL= http%3A%2F%2Fwww%2Esite%2Ecom; ShopperID=193096346; ASPSESSIONIDQAASCCQS=GKEMINACKANKBNLFJAPKNLEM; UserID=2366239 

To check our guess that ShopperID and UserID carry authorization data, we now start individually removing each cookie and sending the request back. When we remove the UserID cookie, the server still responds with the account registration page shown in Figure 5-9. Therefore, this cookie is not important to our mission right now. We repeat the previous steps for each cookie until we eventually remove a cookie that will respond with an HTTP 302 redirect, which tells us in web server-ese, "Hey, I don't know who you are, you're going back to the login page." In other words, whatever token we removed was necessary for authorization. When we removed the ShopperID cookie, we ended up with the following response:

 HTTP/1.1 302 Object moved Date: Wed, 12 Oct 2005 18:36:06 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET Location: /secure/MyAcctLogin.asp?sid= Content-Length: 149 Content-Type: text/html Set-Cookie: ASPSESSIONIDQAASCCQS=OOEMINACOANKOLIIHMDAMFGF; path=/ Cache-control: private 

This tells us that the ShopperID cookie is most likely the application authorization token.

Note 

We actually found with this site that the BIGipServer cookie also resulted in failed authorization; however, because we know that BIG-IP is a web load-balancing product from F5 Networks Inc., we disregarded it. We did have to subsequently replay the BIGip token, however, since it is necessary to communicate with the web site.

At this point, we can test the vulnerability of the ShopperID cookie by simply altering its value and replaying it to the server. Because we just created the account, let's decrement the number and see if we can access the information for the account that was created right before ours. We take the cookie and change the ShopperID number from 193096346 to 193096345 (note that we replay the exact same BIGip cookie, but it's only incidental to the goal here). Here's what the client cookie header looks like before the change:

 Cookie: BIGipServerSecure2.TEAM.WebHosting=1852316332.20480.0000; ShopperID=  193096346;  

And here's what it looks like after (only one number difference!)

 Cookie: BIGipServerSecure2.TEAM.WebHosting=1852316332.20480.0000; ShopperID=  193096345;  

We send the second, decremented value to the server and check to see whether the same account information is returned. Success! Figure 5-10 shows the account data for an "Emily Sima". We have just identified a horizontal privilege escalation vulnerability. Furthermore, an attacker can now enumerate every account and grab personal data, or even impersonate any user with their full account privileges.


Figure 5-10: Success! The information for another account can now be changed .

Vertical Privilege Escalation

Vertical privilege escalation is the ability to upgrade or gain access to a higher account status or permission level. There are four scenarios that typically result in vertical privilege escalation.

  • User-modifiable Roles   The application identifies roles in a manner that is changeable by the user.

  • Hijacked Accounts   The person's account that was hijacked via horizontal privilege escalation has higher privileges.

  • Exploiting Other Security Flaws   Ability to gain access via other security flaws to an administration area where privileges can be changed.

  • Insecure Admin Functions   Administrative functions that do not have proper authorization.

Let's take a look at an example of each of these in a real-world scenario.

User-modifiable Roles

As we've seen numerous times in this chapter, many web applications store the authorization data like permission level or role level in user-modifiable locations. We just saw an example of a web shopping application that stored the role in a cookie. For a similar example with a vertical escalation flavor, consider a fictitious web application with a privileged administrative interface located at http://www.site.com/siteAdmin/menu.aspx. When we tried to access this page normally, it just redirected back to the administrative login screen. Upon analysis of the HTTP request, we noticed this cookie being passed:

 Cookie: Auth= 897ec5aef2914fd153091011a4f0f1ca8e64f98c33a303eddfbb7ea29d217b34; - 563131=Roles=End User; K=HomePageHits=True;ASP.NET_SessionId= dbii2555qecqfimijxzfaf55 

The "Roles=End User" value is almost a dead giveaway that this application is leaving authorization parameters open to client manipulation. We started changing this value and requesting the page to see if it made any difference. For instance, we tried "Roles= admin", "Roles=root", and "Roles=administrator". After several failed attempts, we took a closer look at the naming convention and tried "Roles=Admin User" and were then presented with access to the administration page. Amazingly, our web application testing experiences are replete with even simpler scenarios, where just appending "admin= true" or "admin=1" to the URL will work.

Let's look at a more challenging example. In the following fictitious web application, we logged into an application as a normal user and the cookie that was being sent looked similar to the following:

 Cookie: ASPSESSIONIDAACAACDA=AJBIGAJCKHPMDFLLMKNFLFME; rC=X= C910805903&Y=1133214680303; role=ee11cbb19052e40b07aac0ca060c23ee 

We noticed the "role=" syntax right away but didn't dwell too long because of the cryptic nature of the value (one of those alphanumeric blobs again!). During subsequent horizontal escalation testing, we created a second account in order to perform differential analysis (as described earlier in this chapter). When we were logged into the second account, the cookie looked like the following:

 Cookie: ASPSESSIONIDAACAACDA=KPCIGAJCGBODNLNMBIPBOAHI; rC=C=0&T= 1133214613838&V=1133214702185; role=ee11cbb19052e40b07aac0ca060c23ee 

Notice anything unusual? The value for the role cookie is the same as it was for the first account we created. This was no random number but a fixed value. In fact, when looking at it more closely it resembles an MD5 hash. By counting the characters in the value, they add up to 32 characters . Per the characteristics described in our earlier discussion of session ID fingerprinting, a 32-byte value is one of the canonical ways to represent an MD5 hash (it is the hexadecimal representation of a standard 128-bit MD5 hash). At this point, we figured the application was using a fixed role value for users and then hashing it using the MD5 algorithm.

Lions and tigers and crypto, oh my! Slowed down only momentarily, we implemented essentially the same privilege escalation attack as before, changing the cookie to "role=admin", only using MD5 to hash the string "admin" rather than using it cleartext. The cookie we sent looked like the following:

 Cookie: ASPSESSIONIDAACAACDA=KPCIGAJCGBODNLNMBIPBOAHI; rC=C=0&T= 1133214613838&V=1133214702185; role=21232f297a57a5a743894a0e4a801fc3 

Again, the "role=" value above is the word admin hashed with MD5. When we requested the main account screen with this cookie, the application sent back a 302 redirect back to the login pageno dice. After several additional manual attempts using strings like "administrator" and "root" (the usual suspects ) hashed using MD5, we decided to go ahead and write a script to automate this process and read from a dictionary file of common user account names. Once again, if the application returned a response that was not a 302 redirect, then we will have found a correct role. It didn't take long; after about five minutes of running this script, we found that "Supervisor" was a valid role and presented us with superuser access to the application.

Using Hijacked Accounts

Horizontal privilege escalation is usually quite easy to take vertical. For example, if the authorization token is implemented using sequential identifiers (as we saw in our previous example of the fictitious web shopping site), then looking for vertical can be as easy as guessing the lowest account ID that is still valid, which is usually a superuser. More concretely, a cookie containing the value "AuthID=32896" probably refers to user 32,896 and "AuthID=1" probably refers to an administrator. Usually, the lower account ID's are the accounts of the developers or administrators of the application and many times those accounts will have higher privileges. We'll discuss a systematic way to identify administrative accounts using sequential guessing like this in the upcoming section about using curl to map permissions.

Using Other Security Flaws

This is just a given. Breaking into the system via another security flaw such as a buffer overflow in a COTS component or SQL injection will usually be enough to be able to change what you need in order to move your account up the ladder. For example, take the omnipresent web statistics page that gives away the location of an administrative interface located at http://www.site.com/cgi-bin/manager.cgi that doesn't require any authentication (we talked about common ways to find web statistics pages in Chapter 2). Are you in disbelief? Don't bein our combined years of experience pen-testing web applications, this example has occurred much too often.

Insecure Admin Functions

In our travels , we've found many web application administrative functions that aren't authenticated or authorized properly. For example, consider an application with a POST call to the script "http://www.site.com/admin/utils/updatepdf.asp". Clearly an administrative script based on the folder that it was stored within. Or so the application developers thought, since the script was supposedly only accessible from the administrative portions of the site, which required authentication. Of course, potential intruders with a propensity to tinker and a little luck at guessing at directory naming conventions easily found the /admin/ utils directory. Some simple tinkering with the updatepdf script indicated that it took an ID number and a filename as parameters to upload a PDF file to the site. When run as even a normal user, the script would replace any PDFs currently offered to users, as you might imagine befitting of a content management role. Denial-of-service was written all over this. More devastating, we ended up being able to use the updatepdf script to upload our own ASP pages, which then allowed us almost full access to the server.

Differential Analysis

We've discussed the concept of differential analysis (as it relates to authorization audits ) a couple of times previously in this chapter. Essentially, it involves crawling the target web site while authenticated (or not) using different accounts, noting where parameters such as cookies and/or other authorization/state-tracking data differ .

One of our recent consulting experiences highlights the use of this technique. We were contracted to perform an authenticated assessment, and were provided two sets of valid credentials by the client: a "standard" application user and an administrative user. We first crawled the site while authenticated as the standard user, logging all pages and forms that were submitted. We then did the same using the administrative credentials. We then sorted both data sets and counted the totals for each type of data submitted. The results are shown in Table 5-8.

Table 5-8: Differential Analysis Results Produced While Browsing a Web Application While Authenticated As a Standard and Administrative User

Data Type

Standard User

Admin User

Form submissions

6

15

Cookies

8

8

Pages

62

98

Based on this data, the first obvious attack was to attempt to access the administrative forms and pages using the standard user account. No easy wins here; the pages that we hit appeared to be well protected.

We then took a closer look at how standard and admin roles were differentiated via session management. As noted in Table 5-8, both the standard and administrative user received the same number of cookies from the application. This means that the session/ role authorization was possibly associated with one of the cookies. By using the process of cookie elimination shown in the Horizontal Privilege Escalation case study described earlier, we were able to identify a single cookie that appeared to perform the authorization function. Table 5-9 shows the values for both the standard and administrative user.

Table 5-9: Cookie Values for Both Standard and Admin User Types

User Type

Cookie Value

Standard

jonafid= 833219244.213a72e5767c1c7a6860e199e2f2bfaa.0092.783823921

Admin

jonafid= 833208193.dd5d520617fb26aeb18b8570324c0fcc.0092.836100218

We next analyzed the differences between the standard and administrative cookies. Spend a couple of minutes looking at the cookies in Table 5-9 and see if what you come up with matches the same things we noticed listed here:

  • The cookie value is separated into segments using periods.

  • The first, third, and fourth segments are the same length and are all numeric.

  • The second segment could be an MD5 hash (it's 32 bytes long; see the section entitled "Analyzing Session Tokens").

  • Each segment is the same length for each user.

  • The first three numbers in the first segment for each user are the same.

Although we may have gleaned the algorithm used to produce the second segment, this cursory analysis hasn't really revealed anything useful, so let's probe further. We'll do this by systematically changing values in the cookie and resubmitting it to the application. We'll begin by changing values in the last segment of the cookie, and then work our way to the front. Table 5-10 shows the results of some of our testing.

Table 5-10: Input Validation Checking Results for the Last Segment of the "jonafid" Cookie

Changed Value

Result

Add a character (9)

Application error: "Not logged in."

Change last character from 1 to 9

No visible changes to login state

Change the penultimate character

Same as previous

Change all characters to 9's

Same as previous

We interpreted the data in Table 5-10 to mean that the last segment had little to do with authorization.

We repeated this process for each segment in the cookie, and when we were done, we were surprised to find out that only the first five characters in the cookie appeared to be relevant to authorization state. Looking back at Table 5-9, the only difference between the standard and admin user accountswithin the first five characters of the cookiewas in the fifth character position: the admin user had a 0 and the standard user had a 1. With a bit more input manipulation, we subsequently discovered that the fifth position contained serially incrementing account numbers, and that by changing these we were able to easily hijack other users' sessions.

Using Curl To Map Permissions

Curl is a fantastic tool for automating tests. For example, suppose you are auditing an application that doles out user ID numbers sequentially (now where have we seen that before?). You have identified the session tokens necessary for a user to view his profile information: uid (a numeric user ID) and sessid (the session ID). The URL request is a GET command that passes these arguments: menu=4 (the number that indicates the view profile menu), userID=uid (the user ID is passed in the cookie and in the URL), profile= uid (the profile to view, assumed to be the user's own), and r=874bace2 (a random number assigned to the session when the user first logs in). So, the complete request would look like this:

 GET /secure/display.php?menu=4&userID=24601&profile=24601&r=874bace2 Cookie: uid=24601; sessid=99834948209 

We have determined that it is possible to change the profile and userID parameters on the URL in order to view someone else's profile (including the ability to change the e-mail address to which password reminders are sent). Now, we know that the user ID numbers are generated sequentially, but we don't know what user IDs belong to the application administrators. In other words, we need to determine which user IDs can view an arbitrary profile. A little bit of manual testing reveals that if we use an incorrect combination of profile and userID values, then the application returns "You are not authorized to view this page," and a successful request returns "Membership profile for"; both return a 200 HTTP code. We'll automate this check with two curl scripts.

The first curl script is used to determine what other user IDs can view our profile. If another user ID can view our profile, then it is assumed to belong to an administrator. The script tests the first 100,000 user ID numbers:

 #!/bin/sh USERID=1 while [ $USERID -le 100000 ] ; do   echo e "$USERID ******\n" >> results.txt   `curl v G \        -H 'Cookie: uid=$USERID; sessid=99834948209' \        -d 'menu=4' \        -d 'userID=$USERID' \        -d 'profile=24601' \        -d 'r=874bace2' \        --url https://www.victim.com/  results.txt`   echo e "*********\n\n" >> results.txt   UserID=`expr $USERID + 1` done exit 

After the script executes, we still need to manually search the results.txt file for successes, but this is as simple as running a grep for "Membership profile for" against the file. In this scenario, user ID numbers 1001, 19293, and 43000 were able to view our profilewe've found three administrators!

Next, we'll use the second script to enumerate all of the active user IDs by sequentially checking profiles. This time we leave the userID value static and increment the profile value. We'll use the user ID of 19293 for the administrator:

 #!/bin/sh PROFILE=1 while [ $PROFILE -le 100000 ] ; do   echo e "$PROFILE ******\n" >> results.txt   `curl v G \        -H 'Cookie: uid=19293; sessid=99834948209' \        -d 'menu=4' \        -d 'userID=19293' \        -d 'profile=$PROFILE' \        -d 'r=874bace2' \        --url https://www.victim.com/  results.txt`   echo e "*********\n\n" >> results.txt   UserID=`expr $PROFILE + 1` done exit 

Once this script has finished running, we will have enumerated the profile information for every active user in the application.

After taking another look at the URL's query string parameters (menu=4&userID= 24601&profile =24601&r=874bace2), a third attack comes to mind. So far we've accessed the application as a low-privilege user. That is, our user ID number, 24601, has access to a limited number of menu options. On the other hand, it is likely that the administrator, user ID number 19293, has more menu options available. We can't log in as the administrator because we don't have that user's password. We can impersonate the administrator, but we've only been presented with portions of the application intended for low-privilege users.

The third attack is simple. We'll modify the curl script and enumerate the menu values for the application. Since we don't know what the results will be, we'll create the script so it accepts a menu number from the command line and prints the server's response to the screen:

 #!/bin/sh # guess menu options with curl: guess.sh curl v G \        -H 'Cookie: uid=19293; sessid=99834948209' \        -d 'menu=' \        -d 'userID=19293' \        -d 'r=874bace2' \        --url https://www.victim.com/ 

Here's how we would execute the script:

 $ ./guess.sh 4 $ ./guess.sh 7 $ ./guess.sh 8 $ ./guess.sh 32 

Table 5-11 shows the result of the manual tests.

Table 5-11: Results of Manual Parameter Injection to the "menu" Query String Parameter

Menu Number

Function

13

Display home page

4

View the user's profile

8

Change the user's password

16

Search for a user

32

Delete a user

We skipped a few numbers for this example, but it looks like each power of two (4, 8, 16, 32) returns a different menu. This makes sense in a way. The application could be using an 8-bit bitmask to pull up a particular menu. For example, the profile menu appears in binary as 00000100 (4) and the delete user appears as 00100000 (32). A bitmask is merely one method of referencing data. There are two points to this example. One, examine all of an application's parameters in order to test the full measure of their functionality. Two, look for trends within the application. A trend could be a naming convention or a numeric progression, as we've shown here.

There's a final attack that we haven't tried yetenumerating sessid values. These curl scripts can be easily modified to enumerate valid sessids as well; we'll leave this as an exercise for the reader.

Before we finish talking about curl, let's examine why this attack worked:

  • Poor Session Handling   The application tracked the sessid cookie value and the r value in the URL; however, the application did not correlate either value with the user ID number. In other words, once we authenticated to the application, all we needed to remain authenticated were the sessid and r values. The uid and userID values were used to check authorization, whether or not the account could access a particular profile. By not coordinating the authorization tokens (uid, userID, sessid, r), we were able to impersonate other users and gain privileged access. If the application had checked that the uid value matched the sessid value from when the session was first established, then the application would have stopped the attack because the impersonation attempt used the wrong sessid for the corresponding uid.

  • No Forced Session Timeout   The application did not expire the session token (sessid) after six hours. This is a tricky point to bring up, because technically the session was active the entire time as it enumerated 100,000 users. However, applications can still enforce hard time limits on a session, such as one hour , and request the user to reauthenticate. This would not have stopped the attack, but it would have been mitigated. This would protect users in shared environments such as university computer labs from someone taking their session, and also protects against session fixation attacks where the attacker attempts to fix the session expiry unrealistically far into the future.



Hacking Exposed Web Applications
HACKING EXPOSED WEB APPLICATIONS, 3rd Edition
ISBN: 0071740643
EAN: 2147483647
Year: 2006
Pages: 127

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net