Sunday, May 20, 2007

CSRF Dorks

You've all seen Johnny Long's google hacking database

Its an excellent example of a full disclosure platform that helps raise awareness about vulnerabilities in the wild. I just launched the first version of the csrf hacking database here:

http://csrf.0x000000.com/csrfdb.php

I designed, developed and am maintaining it on my own right now so go easy on me ;)

thanks to Ronald van den Heetkamp for the hosting.

EDIT:

http://h4k.in/csrf now forwards to the csrf database as well

Thanks to
Mario Heiderich for the redirect as well as for his suggestions and help.

Wednesday, April 25, 2007

l33t haxxors

I dont usually post on nontechnical subjects, but I'm making an exception:


l33t haxxors - Episode 1
l33t haxxors - Episode 2
l33t haxxors - Episode 3

Excellent comic relief for a tough day. Enjoy :)

Tuesday, April 24, 2007

The Ellusive Negative Quantity Vulnerability

I guess I'm just going to pick up where I left off a few months back. Rather than backtracking over all the stuff thats happened between then and now, I'll just keep on posting as things come up.

So here's one that just sorta came to me as I was pen-testing a browser based php mmorpg with a friend. I expect this type of vulnerability exists in more problematic places: Banking systems, shopping cart systems, etc.

The vulnerability is a sort of logic error. Lets have a look at some psuedo code designed to allow customers to make purchases.


let $Customers_Money = 100
let $Object_Price = 10

let customer input value for $Quantity

let $Total_Price = $Object_Price * Quantity
if $Total_Price > $Customers_Money then tell customer its too much, and exit

else let $Customers_Money = $Customers_Money - $Total_Price


We give the customers $100 to start and we create an object worth 10$.
We ask the customer how many of the object they want to buy.
We calculate the total price for all the objects, and check whether or not the customer can afford it.
If they can we take the total price and subtract it from the customers money.

The subtraction operation is where the problem exists. What happens when we supply a negative quantity? Well lets run through it:

With a quantity of -10, the total price becomes -10 * 10 = -100
We check if the total price is more than I have in my wallet, ...its not, its less.
So we take that total price, and subtract it from the customers money: 1000 - -100 = 1100
WAIT, see that? using a negative quantity, we have actually GAINED money.

There's a simple solve. And its a solution thats repeated over and over again in web/all security. WHITELISTING. Only allow good input. Theres no need for a negative quantity, so don't allow them. I'm surprised I havn't seen more of this poor logic type vulnerability. Anyone else have similar stories?

<3

RE: TAG or How I Got My Start.

Hi! Its been a LONG time since my last update but I'm making a resolution to start posting again. I got an email from Didier the other day prompting me to update my blog with a story on how I got my start in infosec. Well, here goes nothing :)

I guess it really all started waaaaaaaaaaaay back when I was a toddler. I was one of those kids who loved to fiddle with things. That smart kid cliche. Always breaking and fixing things. All of that stuff you'd expect, but I have a very vivid memory of one day that I'm convinced played a large role in my gravitating toward security rather than anywhere else in IT. I must have been 10 or 11 years old. My mom and a few of her friends showed me something sorta neat they could do with a telephone. They would call this number... I remember it clearly: 999 followed by my phone number, then they would hang up the phone and pick it up real quick. They'd get a busy signal and hang up again... seconds later the phone would ring and the caller id would show 123-456-7890. They had another trick too. If they dialed 759-9999 and hung up, all the phones in my house would go dead for about 5 minutes. To this day I don't know where my mom and her friends found those numbers, and she doesn't remember either. From that one moment, though, I was absolutely hooked.

All aspects of telephony became more interesting than most people could imagine. I wanted to learn everything there was to know about it. I learned, for instance, that the 999 number was called a ringback. You dial 999-your exchange/subscriber number (xxx-xxxx), flash the hook and hang up and that signals the switch at the central office to ring you back. Line techs use it for testing. The 759 number was to allow techs to safely work on a pair without getting shocked.

I modified an old radioshack miniature phone to be the stealthiest little toy you'd ever seen. Instead of having a hook switch, I replaced that button with a variable resistor. Using this I could pick up my phone slowly... if someone was on the line, they'd never hear the telltale click. Using a battery, I could pull enough current off the line to make any extension-in-use lights on other phones turn off so that I could talk on the phone with friends when I was supposed to be sleeping. I learned about the brilliant and intricate signalling systems. I learned about electronic signalling, like the circuit completion when you take your phone off hook, and the rise in current that causes your phone to ring... Audio signalling like DTMF, the tones that are played when you dial a number, dialtone, busy, and all about the signals transmitted elsewhere that I couldn't hear, but that were used to control the entire system. I became very... I guess 'in tune' with the phone system. Sometimes I could tell what numbers people were dialing just by listening. If I heard a click, I knew if it was someone in my house picking up the phone, or someone in the house of the person I was talking to. It sounds really nerdy, but I learned to just... listen to the lines.

Anyways, as all this was happening, I also got my first computer. It was a tandy2000. The only harddrive was large enough to fit only the necesarry os stuffs and was writeprotected. Everything had to be done from disks. I taught myself qbasic. I got myself a modem (2400bps) and started frequenting local bbs's. It was a whole new world. I remember wishing I had better hardware, (tandys and 2400bps were already obsolete at this time) but I'm glad I didn't. I pushed that machine. If all I had was a modem and a dot matrix printer, I'd use it. I learned the hayes command set and programmed a terminal application in qbasic capable of connecting to bbs's when I was 12. I wrote programs that could use the dot matrix printer protocol to communicate with the printer and make it spit out cool designs.

This is where things took a bit of a turn. Most of the bbs's in my area at the time were running on wildcat. There was one, though, that looked totally different. I learned later that it was a purely custom design. Most of the security systems built into these bbs's were standard login/password forms and sometimes callback verification during your registration. This custom one did things a little differently. When you sign up it asks for your phone number, just like regular callback verification. But rather than only using it once, it uses it everytime you log on. You call this BBS, it asks for your username and password. The bbs looks in its database of users and finds the phone number you registered with. It spits out a msg

"Calling you back. BYE! "

It then hangs up on you and calls the number it has stored. This means that even if someone steals your username/password... they can't use your account unless they're calling from your line. Now, this seems relatively secure but my geeky obsession with telephones made me think about it a little differently. You know when you pick up your phone to make a call and someone is already there? Well, you know they're there because you dont here a dialtone. I tought to myself, does the computer on the other end know to wait for a dialtone? So I made some quick modifications to my qb terminal software. I called up the bbs and entered a friends login/password.

"Calling you back. BYE! "

I quickly call the number back before it gets a chance. I hear over the modem it picks up the line. I hear it dial my friends number. IT DIDNT WAIT FOR DIALTONE! I have my modem pick up the call as though it was just answering the phone and tada, I broke his system. I quickly pressed C to (C)hat with the sysop and told him what I found. He was surprised to find out how young I was.

I became very interested with hacker culture. I began getting in trouble for messing around with the computers at school. Eventually I got the internet and began to submerge myself in the hacker underground. I was surrounded by people who might have been breaking the law, but I was always more interested in just learning. Thats not to say I never got my hands dirty... I just knew where to draw the line. Scanning out different routers, guessing there passwords and poking around in them, things like that. I wrote for an ezine for a time. Articles on network recon methodology, how to map out rulesets of a firewall, problems with tcp, even an article on xss before I even knew what xss was. It was all very romanticised. Like a movie, almost. Most of my learning took place during this time. A span of about 6 years. eventually, people I knew, people I talked to on IRC or teleconferences began getting in trouble and I quickly realized that wasn't where I wanted to be.

It sort of all came to a head when I got in some real trouble for a hack. Not legal trouble, but probably not far off. I was in highschool and I had this teacher who was a real hard ass. She was teaching us "Computer Programming with Turing". I asked her one day why we were learning to program in a language we'd never be able to apply rather than a real language like c/cpp (I think I even mentioned qbasic lol). She said and I quote "I suggested turing to the board because you cant mess up the system in turing".

I was a bratty, confrontational kid. No denying it. I took it as a challenge. "The system" was a really weird one. The network was a LAN and the security system was based on a slew of mashed together batch files/exe's and profile data. I don't remember it in too much detail, but I remember finding the exe that was called to load your profile after you successfully logged in. Something like loadprofile.exe f:\staff\teachers\smithj for teachers. Me and some friends had already written a little qbasic application that mimicked the login screen, stored the usernames/passwords and logged the user in seemlessly, but for one of my assignments in that programming class I presented something that caught Ms Devos off guard. Using the system() command to call loadprofile.exe I could load up ms devos's profile without even having her credentials. She was walking around checking everyones work, she reaches over and presses f2 to execute my program and it logs her directly into her profile. On my screen is access to student marks, report cards, things I should never see. I was suspended.

I really learned my lesson though, I went off to study computer engineering technology and computer sciences at algonquin college in Ottawa Ontario canada, met some great people, learned all kinds of things. To this day I sometimes see hacker handles that I remember clearly from the scene show up in the news. Mostly botnets. I'm glad to have left that all behind. I've kept some friends from that scene, and I hope that will never change. Media made us want to be hackers and eventually life and common sense made us realize that we can be without ending up in prison. Its really too bad for those that don't figure that out.

I've since worked as an administrator, as a freelance security auditor for smalltime e-tax filers and other small sized business networks, as a pentester for countless internet systems. Living in a small town has really limited my ability to gain field experience... but what I lack there I make up in sheer learning momentum. I never stop reading. I never stop learning. I annoy the heck out of my gf with all the reading I do.

Anyways, thats my history. As always, all comments are appreciated.

Tuesday, October 24, 2006

Defeating Dean Edwards' Javascript Packer

Today a friend passed me some obfuscated javascript and asked if I would help him decode it. I had a quick look at it and saw the following code fragment:

eval(function(p,a,c,k,e,d){ ...

This made me smile. p,a,c,k,e,d... Cute. After a little research, I found this to be a signature function of Dean Edwards javascript packer. I found 2 very quick ways to deobfuscate code packed with this packer, and I have decided to share them with you. By presenting this my intention is NOT to insult Dean's work in any way, when it comes to javascript, and a few other topics, Dean is lightyears ahead of me. I present this to provide the community with a few methodologies they might use to approach these scenarios in the future, should it be necessary.

Here's a link to the packer:

http://dean.edwards.name/packer/

The first method does not attack the obfuscation technique, but a feature of the packer interface. Built RIGHT IN to the interface is a decode button. This has been designed to only allow decoding of your own code. If you look at the interface, you can't paste into the top textarea (because of the readonly attribute) and the decode button is disabled until you've actually packed something. This design is inherently flawed as it depends on the browser.

I wrote a bookmarklet called reEnable that will remove the readonly attribute from textfields and the disabled attribute from other html elements.

reEnable: Bookmark this :)

Using reEnable you can paste obfuscated code into the interface and decode it with a click.

The second method attacks a weakness in the obfuscation technique itself. Here is some code

unpacked:



document.write('Hello World!');



and packed:



eval(function(p,a,c,k,e,d){e=function(c){
return c};if(!''.replace(/^/,String)){while
(c--){d[c]=k[c]||c}k=[(function(e){return
d[e]})];e=(function(){return'\\w+'});c=1}
;while(c--){if(k[c]){p=p.replace(new
RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return
p}('3.0(\'1 2!\');',4,4,'write|Hello|World
|document'.split('|'),0,{}))



(I had to force multiple lines to avoid it breaking my layout lol)

it looks like a lot of randomness, but the weakness is pretty easy to spot if you know what you're looking for.

Notice near the bottom all the code is there, just rearanged with the syntax punctuation removed? if you look even closer the syntax punctuation is there as well, only seperate from the strings. If we looked at this long enough, we might be able to write a utility to unpack it... but there's an even easier way. Notice how everything is wrapped in an eval()? well, we don't want the code to be evaluated, we want to SEE it... If you replace the opening eval( with document.write( ... all the code is dumped to the screen. If some of it is being interpereted as html rather than being displayed consider forcing your document.write to write between <textarea></textarea> tags.

<3

Friday, September 15, 2006

Chasing Wild Geese? ...Keep Chasing.

I'm BACK! Sorry for the hiatus, I was preparing for and starting school. Now that things have gotten into a bit of a groove, I can get back on the HACK. The title for todays post is sort of tongue-in-cheek. I spent a lot of time chasing my tail on this particular project, and what fun would I be if I couldn't have a laugh at my own expense? The main point is that, even though I got stopped up a few times... I didn't give up, and in the end I got positive results.

My friend Dustin passed me the source for a c program he developed. Its purpose is to encrypt files. After looking it over, I told him I could defeat his encryption and he told me to give it a try, here's how the project played out. (keep in mind, I'm not a cryptanalyst... and I might very well be missing something or even dead wrong, therefore I'd LOVE to hear from anyone with advice or constructive criticism.)

The program is shush.c, and this is how it works. You provide the program with two pieces of information, the name of the file to encrypt and an integer in the set 0 - 3435973836. This integer becomes your KEY. Shush then encrypts the file using an XOR encryption scheme. If you don't know what XOR is, or you don't have a very good grasp of XOR read wikipedias entry for truth tables. Right away, you're probably seeing the #1 problem with this encryption scheme. Too small a keyspace, or in other words, there are so few possible keys that this can be easily brute forced.

Lets examine: there are approximately 3.4 billion possible keys (0-3435973836). Compare this to a simple 8 character password using only characters from the set [a-z]. The keyspace here is 26^8 or 208827064576 which is over 208 billion possible keys. How long would it take your password cracker to incrementally crack a password that was known to be 8 characters in the set [a-z]? Not very long, and that password is over 65 times stronger than any key for this program.

Now here's the difference between hacking and ...cracking or whatever other awkward label you use. I could stop here, write a little program to implement the brute forcing and be done with it, or I could keep hacking at it to see if there's an even more efficient way. You know me, of course I'll keep going... And heres where all the trouble started ;)

Lets take a look at how shush uses the key to encrypt the file (the shush.c source is available below this description, use it as a reference). When you give shush your integer, shush passes it to a function called srand(). This function uses the integer as an initial value for generating "random" numbers with the rand() function. This concept is called seeding. To be as basic as I possibly can... The SEED is a number that the random number generator does weird math stuff with. Once its done its weird math stuff, the result is the random number thats been generated, that result ALSO becomes the new seed. Here's some psuedo code to represent this:

seed = 31337

Generate random number:
random_number = seed + 1234 * 4321 / 7
seed = random_number

Now this is VERY arbitrary. The "weird math stuff" is actually quite technical, but far from within the scope of this post. For more information on this stuff research Linear congruential generators.

The point to note here is that this "weird math stuff" is an algorithm, and if you think about it... there is nothing truly "random" about mathematical algorithms. Thats why we call this algorithmic randomness "psuedorandom". And we call this generator a "psuedorandom number generator" (hereafter PRNG).

It might seem like i'm on a tangent, but trust me its relevant.

So, basically You give shush an integer, this integer becomes a SEED. Shush then gets into a loop. This loop reads in one byte, and performs an XOR operation on that byte against the result of a call to the PRNG. This PRNG is actually the function rand(). Keep that psuedo code in mind, everytime rand() is called, the seed changes, and so, the next time its called the result is different. The result of this XOR operation becomes the value for the encrypted byte, and so is written out to the encrypted file.

Here is shush.c


#include <stdio.h>
#include <stdlib.h>

void XOR(char filename[], unsigned key)
{
FILE * in, * out;
srand(key);
unsigned ascii;
char tempfilename[9999];
sprintf(tempfilename,"%s%s",filename,".temp");
if ((in = fopen(filename, "rb")) == NULL) printf("Error: Could not open: %s\n",filename);
else if ((out = fopen(tempfilename, "wb")) == NULL) printf("Error: Could not open: %s\n",tempfilename);
else
{
while((ascii = fgetc(in)) != EOF) fputc(ascii^rand(),out);
fclose(in);
fclose(out);
remove(filename);
rename(tempfilename,filename);
}
}

void main(unsigned argc, char * argv[])
{
printf("XOR File Encryption v1.0\nProgrammed by xxx\nEmail: xxx\n\n");
if (argc==1) printf("Error: No file(s) supplied.\n");
else
{
unsigned key, counter=1;
printf("List:\n");
while (counter<argc)
{
printf("[%u] %s\n",counter,argv[counter]);
counter++;
}
counter=1;
printf("\nKey [0:3435973836]: ");
scanf("%u", &key);
printf("\nOne moment please. Processing...\nTo cancel, press ctrl + c\n\nStatus:\n");
while (counter<argc)
{
printf("[%u] %s...",counter,argv[counter]);
XOR(argv[counter],key);
counter++;
printf("done\n");
}
}
system("pause");
}




If you're following me, this will make sense. Based on the fact that rand() uses a static algorithm, the sequence of numbers it returns will always be the same sequence for a particular seed. With a symmetrical stream cipher like this XOR scheme, this is useful. I'll demonstrate.

Lets look at this sequence of numbers: 1, 2, 3, 4. We'll use them to "XOR encrypt" these 4 values: 5, 5, 5, 5. In a realworld example, these numbers would be numerical representations of the byte's from the file.

as XOR is a bitwise operator, Lets see these in binary form:

00000101 00000101 00000101 00000101 (5, 5, 5, 5: unencrypted)
00000001 00000010 00000011 00000100 (1, 2, 3, 4: KEY)
-------------------------------------------------------------
00000100 00000111 00000110 00000001 (4, 7, 6, 1: encrypted)

This is what happens when you run shush on a file... Now, you send that file to someone and they run shush with the same key, and this happens:

00000100 00000111 00000110 00000001 (4, 7, 6, 1: encrypted)
00000001 00000010 00000011 00000100 (1, 2, 3, 4: KEY)
-----------------------------------------------------------
00000101 00000101 00000101 00000101 (5, 5, 5, 5: decrypted!)

This is the concept of a symetrical encryption scheme. Now lets review what we know. The user supplies an integer. This integer seeds rand(). Rand generates a sequence of numbers against which each byte in the file is XOR'd, the results make up the encrypted file.

Now that we understand shush more thoroughly, we can design an attack. My theory was this:

The user supplies a key that seeds rand(), rand() then returns a predefined algorithmic series of numbers. Since this is algorithmic, given any number in the series, I will be able to predict the next number, or even the previous number in the series. Therefore if ANY of those numbers are known to me, I can reverse the algorithm to get the key. With that key, I can decrypt the file. This is pretty standard, the question is how can I find any of these numbers? Well, really I shouldn't be able to... but a weakness in the implementation gives me a leg up. When a file is encrypted with shush, it keeps its filename. This means that, for a lot of file formats, SOME of the plaintext characters will be known. For instance, every valid JPG will have the same first 4 bytes (have a look if you want to verify). These are file headers. The nature of XOR allows us to use these known values to extract part of the key!

(OKAY WAIT. Here is where we're going to get mixed up with our terminology... when I say "key" I'm talking about the integer the user gave to shush. When I say "part of the key" i'm not talking about part of that number, I'm talking about one value returned by rand()... This might be confusing, but assume the integer supplied by the user to be 'the same thing' as the series of numbers returned by rand(). )

Lets look at how this works. Lets say we're looking at the first four bytes of the encrypted file (same values as the last examples) and in this case we KNOW (based on file format specifications) that these bytes were originally 5, 5, 5, 5 before being encrypted.

00000100 00000111 00000110 00000001 (4, 7, 6, 1: encrypted)
00000101 00000101 00000101 00000101 (5, 5, 5, 5: unencrypted)
-------------------------------------------------------------
00000001 00000010 00000011 00000100 (1, 2, 3, 4: KEY!)

Now that we've extracted some of the numbers returned by rand(), all we need to do is reverse the algorithm in rand() to determine what key was given to srand(), and the encryption is defeated. This is A LOT faster than brute forcing... Everything looks good Right? hmm....

If anyone see's a problem here you get props. I didn't see a problem until I started experimenting. My theory seems pretty solid, but (my c++ prof loves to call me on this) I'm making an assumption. XOR is bitwise. Shush takes 1 byte from the file, and XOR's it against 1 integer returned by rand(). Until now, we've been assuming that both of these peices of data were of the same size. Thats assuming that rand() can only generate 8bit integers, making the maximum value 255 (unsigned). This isn't the case, after experimenting with rand() for a bit, its clear that rand() returns values outside that range. So lets see what happens when we XOR two values with different bit lengths, we'll use the same values as before, but we'll change one number from the key:

00000101 00000101 00000101 000000101 (5, 5, 5, 5 : unencrypted)
00000001 00000010 00000011 110010000 (1, 2, 3, 400: KEY)
-------------------------------------------------------------
00000100 00000111 00000110 110010101 (4, 7, 6, 405: encrypted)

Notice that the fourth value returned by rand() this time is to 400, this makes the bit length 9 instead of 8. Since the key changed in bit length, a 0 was padded to the beginning of the value it is being XOR'd against, and the encrypted value ends up being 9 bits as well. Since we're writing byte values out to a file, only 8 of those bits will actually be used, 1 will be discarded. Lost Forever. This complicates our methodology, watch (remember the encrypted value was 110010101, or 405, but when the most significant bit is discarded, it becomes 10010101, or 149):

10010101 (149: encrypted)
00000101 (5 : Known unencrypted value)
--------------------------------------
10010000 (144: key? ...)

Flawed logic gave us a false positive. the key is 400, not 144... So if rand() returns a value greater than 255, our attack fails. Right? well... To an extent. Think of it on a bit level... The value of the actual key, versus the value or the key we got are actually pretty close when we look at it this way:

110010000
10010000

Basically, we still know the last 8 bits of the key no matter what. So we could build a set of potentials based how many values rand() can return that end in our 8 bits. In order to do this we need to know the largest possible value rand() can give us. This value changes from compiler to compiler (remember this, I'll come back to it.) and its set in cstdlib/stdlib.h as RAND_MAX. In the compiler I use (mingw), it's set to 0x7fff, or 32767 which is 15 bits. So how many potential values exist when the last 8 bits are known? 2^7 == 128 possible values. Thats a pretty small keyspace, compared to the 3.4 billion we were dealing with before...

Incase anyones lost, quick review:

We xor a byte from the encrypted file against what we KNOW was the original byte before it was encrypted. The result becomes the final 8 bits of what that byte was originaly xor'd with by shush. This gives us a set of 128 potential values. Now we can reverse the algorithm in rand(), and determine 128 potential keys one of which was originally supplied to shush by the user.

If anyone see's a problem HERE, again... props. There's something I didn't take into account. We've been assuming that in rand() is a symmetrical algorithm that can be reversed. I think the reason I thought this was because in most descriptions of rand(), they talk about algorithmic randomness, and in pure mathematics algorithms are symmetrical but in programming, not necesarilly. Here is what rand() does (this is the implementation used by mingw, it also changes between compilers, I've also changed how it looks a bit for simplicity, it still functions the same.)

return((seed = seed * 214013L + 2531011L) >> 16);

As you can see, it takes the seed (your key) and multiplies it by 214013, the product of that is added to 2531011. If this was all, it could be trivially reversed. We'd take the result, subtract 2531011 and divide the difference by 214013. But there's more. >> 16 indicates that 16 bits are dropped off the end of the value... And again, lost forever. So this introduces a whole new set of potentials... How many? well... remember the maximum allowed seed (as indicated by shush) is: 3435973836, which is a 32bit value. 16 of those bits are discarded from the seed. This means that for every number from our list of 128 potentials there is 2^16 or 65536 additional potentials. This gives us 8388608 potentials in all. Still beats brute-forcing.

Their's a question to ask yourself at this point though. A modern computer can crunch 3.4 billion numbers in seconds. So does the difference in efficiency and execution time justify the complexity of the code required to accomplish it? Probably not to the average user. If this was a professional developer project, your boss would kick you in the ass for wasting so much time. But it was a lot of fun anyways.

One side note is that shush is depending on rand(). Through my research, I learned that rand() has no standard. Its implemented differently on many different platforms, and in different compilers, and even changes from version to version. This program would be mostly useless if it was released opensource, as if two users compiled it with different compilers, chances are it would fail.

Anyways, hope SOMEONE had fun reading this lol

Monday, August 07, 2006

Authentication bypass.

This is an example of a far too common problem. Developers have a tendency to assume that client applications will always act how they were designed to act. This is fine if you're depending on them for functionality, but NOT if you're depending on them for security.

Recently I was asked to take a peek at a content management system currently in developement. A lot of it seemed relatively stable, except for this one short snippet of code. Whenever a protected page is loaded, one that you have to be logged in to view, a function containing this code is called:

if(!isset($_SESSION['session']["privLvl"])) {
header("Location: login.php");
}

It grabs a variable called 'privLvl' registered to the users session. If the user is not logged in, this variable is unset and the browser is redirected to the login page. So then, what is the problem? The problem exists, because our developer is putting his trust in a function that depends on the browsers response. header("Location: login.php"); will force a browser to redirect to login.php, but only because that is how a browser is programmed to react. watch what happens when I load this page in ie, then in netcat:

first, here is the code for admin.php:

<?

if(!isset($_SESSION['session']["privLvl"])) {
header("Location: login.php");
}

echo "BIG SECRET!";

?>

Here is an image of what loads in IE:





that form is what is stored in login.php, we've been happily redirected, as intended. And now, in netcat:






Whoops. Netcat has no idea what to do with the Location: header, its not a browser. A secure way to implement this would be as follows:


<?

if(!isset($_SESSION['session']["privLvl"])) {
header("Location: login.php");
exit();
}

echo "BIG SECRET!";

?>


Here we force exit of the script after redirect, incase the client doesn't listen.
There are plenty of other vulnerabilities based on this same flawed thinking. Using javascript to sanatize input is a common one. As a developer you should always be concious of what your functions depend on, and whether or not those dependencies are under your control.

Thursday, August 03, 2006

New Bookmarklets

I developed a few new web app pentesting bookmarklets this afternoon. If anyone has any requests, or bookmarklets of their own to share, please leave me a comment.

Here are the new ones:

Password2text: for quickly viewing whats in a password input.
Form Report: Detailed report of all forms on the current page.

Here is a running list of all my security marklets so far:

modcookie: For on-the-fly cookie modification.
methodToggle: for toggling the method of a form, to test method strictness
noMax: removes the maxlength property of text inputs.
hidden2text: displays hidden inputs.

I'll be looking forward to requests, and other security marklets from all of you ;)