Home Blog

“Huis & Aanbod”, I don’t even know where to start…

8th December 2012 (2 notes)

Note: I saved the following post originally as draft, because I wanted them to give a chance to fix the vulnerabilities before making them public. So I sent them an email. The next day I received a call from an unknown number, which to my surprise, was from them. The guy on the other side of the line told me that he tried to email me back, but that my server was down and the email didn’t go through. Which was true. I was having problems with my server that day. He also told me that he tried to contact me through the contact form on my website, and that that didn’t work either. I did sense slight amusement in his tone of voice, as if he was thinking, “you may know how to hack our website, but you can’t even code a freaking contact form in PHP”.

I explained him in detail all the problems with their site, although I’m not entirely sure he understood everything I said. He also seemed surprised that I found these vulnerabilities, and wondered how I did it.

At the end, he thanked me, and promised to take care of everything. As of writing this, roughly 4 weeks after the phone call, only about 40% of the issues are fixed. I don’t think more is coming anytime soon.

Now to the actual post:

Every now and then, I write scripts to automate processes, like the uploading of our entire database full of products. These are generally being uploaded to web portals, where we’re looking for exposure.

This involves writing cURL based scripts that have to do things like logging in, inserting descriptions and prices, and uploading images to a remote server. In order to do that, I have to get a pretty good understanding of how the sites work internally.

Today I wrote such a script for huisenaanbod.nl, which is a Dutch real estate portal. After creating an account there, I received an email from them which asked me to confirm my email address. But that was not all it contained, they also thought it would be a good idea to send me my password, in plain text! I know, a lot of sites do this, and while it’s not a good thing to do, that alone is not worth a blog post. But this is only the beginning. I got slightly more offended when I saw that they also had my password in the account activation link. Why would they do that?

How can a big site like this be so poorly coded? I decided to take a closer look at it after this, and now I don’t even know where to start…

The first thing I noticed while writing the script was that every HTTP request contained cookies with my email address, and a short string of random characters as it seemed at first. I didn’t want to think they’d be that stupid, but then I just had to see what happened if I base 64 decoded the little string. Before you ask… yes, it was my password. It’s being sent back and forth on every… single… request.

If you absolutely must send the password through cookies to the server, and I honestly can’t think of a good reason why, then for fuck’s sake, don’t use base fucking 64. Security through obscurity does never work. Usually it just slows things down. Well, unless you’re using base 64… fuck!

That’s pretty bad already, but it gets worse. While I haven’t found an SQL injection vector (yet), to my surprise, and there better not be any, seeing as they’re storing passwords in plain text, I’ve found several other exploitable bugs. It’s actually a combination of three, that work beautifully together. The second one makes the first one way more potentially dangerous. And the third one makes the second one more dangerous, which makes the first one a killer.

The second is related to the property descriptions. They’re not stripping out JavaScript… at all. Or HTML for that matter. The only annoyance is that they’re converting line breaks to <br> tags, which will cause syntax errors. But it’s a non-issue if you write all your code in one line, or even embed an external JavaScript file.

It’s pretty much an invitation to embed some code that grabs other people’s cookies (remember they contain your whole access data in plain text?), and send them over to your own server. All you have to do is to sit tight, grab some popcorn, and wait for the data to fly in.

Want to accelerate the process? No problem! The third exploit allows you to edit other people’s ads. That includes descriptions, prices, and even photos. It’s so simple, it’s embarrassing. You just have to browse through their main site, open a property you like (perhaps one of the featured ones on the home page?), and copy its ID from the URL. Then you go back to your control panel, click “edit” on one of your properties, and swap IDs in the URL. After that, you may change or insert anything you like, then click “save”, and you’re done. It works the same way for photos too. You can even delete anyone else’s ad.

I tried to do the same in the user area, where I can change my personal details, such as my email address and my password. My user ID is being submitted in the URL to the ‘edit’ page, (which, in a perfect world would be completely redundant), and then my data is being fetched based on that ID. But astonishingly, when I put another ID there, it just said I wasn’t logged in. Which is not entirely true, but I’d rather see this erroneous error message than other people’s sensitive data (I’m probably lying here). Why do they verify the ID there, but nowhere else? Who knows. But good for them someone had a slight sense of security here, and thought something bad might be able to happen.

19th August 2012

Anonymous asked: How are you old school?

Pretty fucking awesome! ;D Thanks for asking!

Deltascripts.com *promo* code! (Everything for free!)

6th February 2012

UPDATE: I opened a support ticket and explained them the issue. But I got no response. It’s been so long, the ticket even automatically closed. I guess that’s all I can do… so go crazy on it. Also, don’t expect any support from their end. Even if you paid.

UPDATE 2: I posted the issue on their forums, where it got ignored for a long while. Much later, at some point my account got deleted along with the post I made. Nicely handled, Deltascripts.

Get everything for free with this unique promo code: pastebin.com/j9Qkdsyg 

You can just put this into the “license” field. This gets you everything off their site, even their $349 “PHP Classifieds” script.

I’m posting this to raise awareness. If a company like this can’t even protect what’s most valuable to them, how do you think they can protect what’s most valuable to you and your users?

It has been around since 1998 and was the first PHP Classifieds script introduced in the world.

I wouldn’t be surprised if it hadn’t been updated since 1998 either! Their requirements are funny too:

The following PHP settings:

Magic_Quotes ON

Magic Quotes? Really? This feature has been deprecated in PHP 5.3, and will be completely removed in PHP 5.4. I’m not exactly sure how PHP 5.4 users are going to enable this feature to meet their requirements.

“PHP Classifieds” is a horrible script. I wouldn’t even use the *free* version.

Stay far away from it.

(Let’s see how long they take to fix this)

Note: This is not a real promo code, but it works regardless. Using the scripts you get with this code might get you in trouble. Use at own risk!

BigDump, big goof!

31st May 2011

I just had to import a big database, and I used BigBump for that.

My dirty mind immediately thought, how many people do actually leave the script on the server after importing their databases? Turns out, a lot.

Now that’s pretty careless, but hey, their loss is my gain. Pretty quickly I found my first victim: A phpBB board. I always used to be more of a vBulletin guy, and since I have no experience with that particular software (as to what hashing algorithm, salts, etc, it uses), I figured I’d just download it and install it locally. After doing so, I went to my phpMyAdmin, and exported the users table, which only had two users in it. My new admin account, and some random ‘Anonymous’ account, which makes no sense to me without further investigating, but I don’t care enough at this point.

I just removed said account from the exported .sql file, leaving only my account in it. I changed the user ID to some ID the forum wasn’t likely to have already. Seeing as the forum has 1500 something users, so I just used the ID 2000, considering it probably has some banned users which are not counted. Make sure the user group ID is set to 5, otherwise you won’t be admin.

I grabbed the file, uploaded it via BigDump to the server, and hit ‘Start import’. Since it was a single query only, it went rather fast.

I went back to the forums, and logged in, using the moniker and password I picked during the local installation. Directly after logging in, the forum showed me a link at the bottom to the admin control panel… Success!

It was unbelievably easy, and yet it’s a very dangerous attack!

If I wanted, I could change anyone’s password, and log into their account. I could delete whole accounts, and what not…! I can run any MySQL query I want to, UPDATE, DELETE, DROP, etc…

On a further note, older versions of BigBump (v.0.28b, I believe) use eregi() instead of preg_match() for the file name validation. And since eregi() is not binary safe, you probably could just prepend a null character (\0) to the file name, and upload .php files this way. It’s only theory, though, as I haven’t actually tried it.

And on a last note, you may be able to create .php files with your own code using native SQL.

SELECT '<?php echo \'hi there\'; ?>' INTO OUTFILE '../../public_html/hacked.php'

MySQL isn’t very likely to have permissions to write to that directory, but it’s worth a shot.

Client-side password hashing before log-in.

28th May 2010 (1 note)

UPDATE: This method protects your password (slightly, at least), but it does not protect user accounts on the forum. If someone *sniffed* your password hash, it could just be captured and resent to the server it was gathered from, along with your user name. The forum would not know whether the hash was directly submitted, or if your Javascript code created it before logging in.

I’ve seen vBulletin doing this, and I thought it was very interesting.

What they do is, they hash the user password using JavaScript before logging in. How MD5 hashing works is no secret. And not even reverse engineering the code that generates these hashes will make them “decryptable”. But I don’t want to get into this now. What I’m saying is, that JavaScript can create valid MD5 hashes, just like PHP would do. And we can take advantage of this to make our systems a little more secure.

Here’s an example JavaScript code that creates MD5 hashes:

http://github.com/kvz/phpjs/raw/master/functions/strings/md5.js

(Feel free to use it.)

If the user has JavaScript enabled on his browser, vBulletin converts his password as soon as the form is being submitted, and removes the value from the original password field. So that only the hashed password will be sent to the server.

This is an example request that my browser sends to the server. As you can see, my password is only being sent in form of MD5 hashes. No trace of the real password!

So why are they doing this you might ask?

Security is the obvious answer. If you’re not connected to the server using a secure (SSL) protocol, your request is being sent “as is”, meaning PLAIN TEXT, and can be seen by others, using certain packet analyzing or HTTP sniffing tools.

Since SSL certs are not always an option, and sometimes a little pricey too… And since I’m yet to see a message board actually using a secure log-in system, I find this method rather interesting. I’m by no means trying to say that this method is anywhere as secure as SSL connections, or that it can replace them.

Implementing this method into existing log-in systems might be a little bit difficult or even impossible if you’re using “salts” or anything besides just MD5.

However, In case you’re interested, here’s an example on how to use this method in your own forms.

The md5() function from phpjs relies on their utf8_encode() function as well, so we must include it.

The above code looks pretty much like most log in forms, except that I’ve added a hidden field called “md5password”, which will later hold the hashed password. And I’ve added an “onsubmit” handler to the <form> tag.

The JavaScript code does the same as vBulletin’s does. It prevents the original password from being sent (meaning it removes its value), and instead it includes an MD5 hash of it.

Please note that this only works if the user has JavaScript enabled. So on the server-side, we cannot rely on the password being hashed. We have to check for it.

In this example I’m assuming you’re only using MD5 without salts or any other ingredients on your user’s passwords.

Please also note that this code is for reference only. A simple copy and paste will not work. Furthermore, I cannot provide many more examples as the password hashing can be done in too many ways. But I’ll post one more for vBulletin-a-like systems where a custom salt is being used:

Make sure you’ve previously selected the user’s salt from the database and it’s present in the $userinfo array.

As I said earlier, implementing this method into your existing log-in system might be impossible. It all depends on how you’ve been handling the passwords from the beginning.

Questions?

Dear “CyD Software Labs”…

27th May 2010

CyD Software Labs claim themselves to be “WEB security specialists”.

Sounds great… so I decided to look at the stuff they’re actually doing. After a short while, I stumbled up on this post about Cross Site Scripting (XSS).

While they make a good point about HTML entities, they’re completely forgetting SQL injections. The code they’re suggesting to prevent Cross Site Scripting is completely worthless, considering I can exploit their SQL query. I can still inject any HTML code, as if htmlspecialchars() never existed in their code.

I mean,… seriously? That’s all you have to suggest? This post is probably still from the PHP 4 days, when Magic Quotes were enabled by default, but still… this suggestion is more than ridiculous. Especially for a “WEB security specialist”.

Since they don’t suggest mysql_real_escape_string(), I can insert single quotes into the query, and manipulate it that way. (For more information, I posted about this type of exploit a while ago here.)

They are however suggesting to apply htmlspecialchars() on the input, AND the output, which is pretty stupid, because it’ll result in ugly output to the user. This method does not prevent code injection, but it prevents the code from executing on the client’s side. That means I can save valid HTML in their database, but it won’t be executed by the client because it’s being converted to HTML entities.

But there are other types of attacks I can execute using the exploit. What if I’m not interested in the user’s cookies, or redirects to spam sites, or anything else JavaScript can do? What if I inject a sub-query that selects user passwords and adds them to my posts?

It’s as easy as inserting something like this into the “Name” field of their page:

’, (SELECT `password` FROM `users` WHERE `userid` = 1), 1, 1, 1) #

This can be way more harmful than any XSS attack. Allowing me to insert JavaScript can give me some options to steal user information, and maybe even hijack their sessions by stealing their cookies and what not.

But in all honesty, why bother coding a script that can steal user’s cookies and save them on another server, when I can get their info directly and more accurately?

There are some parts of their code that needs to be analyzed before continuing:

They’re for example using a mysql_query() call without error control. Meaning, there’s no “OR die(mysql_error())”. That’s good for them, and bad for us. Since we’re not getting any useful errors, it can be hard to inject code as we don’t know what we’re really doing. However, there are still thousands of sites using proper error control, and most of them naively show the error to the user too.

Another thing is that we usually don’t see is the actual code behind the user interface, so we don’t necessarily know how many fields we need to insert into the database. In this example, they’re inserting data into 4 columns before the user name and the message, and more data into 3 columns after that:

INSERT INTO minibbtable_posts   VALUES(NULL, 1, 1, 1, '$username', '$message', 1, 1, 1)

The data before the message ($message) is rather unimportant, as we inject code right after it. What we need to know is how many fields there are after it, as they might be required (can’t be empty). Obviously, when injecting code we start with the minimum amount of columns.

We’re first closing the initial single quote by inserting another one. Thus, resulting in a query like:

INSERT INTO minibbtable_posts VALUES(NULL, 1, 1, 1, ''

Now we add a comma, and then the actual SQL code we want to execute. This could be a SELECT sub-query, or a CHAR() call to write characters which would usually be converted by htmlspecialchars().

INSERT INTO minibbtable_posts VALUES(NULL, 1, 1, 1, '', (SELECT [...]))

This query alone would be valid, but the rest of the original query is hard coded into the PHP script and we can’t modify it. So we have to tell MySQL to ignore it, by adding a # to the end.

INSERT INTO minibbtable_posts VALUES(NULL, 1, 1, 1, '', (SELECT [...])) #

Now the actual code will be send to the database like this:

INSERT INTO minibbtable_posts VALUES(NULL, 1, 1, 1, '', (SELECT [...])) #', '$message', 1, 1, 1)

In SQL, the # character stands for a command. Meaning it’s “just” information for the programmer, and therefore ignored by MySQL.

However, in this case, the three 1s are unknown fields that can’t be empty. So we’re getting an error like this:

Column count doesn’t match value count at row 1

This error means we’re inserting less (or more) columns than required. From there we keep adding more, until it works.

INSERT INTO minibbtable_posts VALUES(NULL, 1, 1, 1, '', (SELECT [...]), 1) #

(Note the 1 after the SELECT sub-query. This would still produce the same error as we’re not yet inserting the required amount of fields.)

INSERT INTO minibbtable_posts VALUES(NULL, 1, 1, 1, '', (SELECT [...]), 1, 1) #

(Still no luck… keep trying, and add one more field.)

INSERT INTO minibbtable_posts VALUES(NULL, 1, 1, 1, '', (SELECT [...]), 1, 1, 1) #

Bingo…

Most of the times, hacking involves trying. You can’t always know everything.

I’m aware that they’re also addressing htmlentites() and htmlspecialchars()’s “quote style”, but they’re neither using it in their code, nor do they say how dangerous it is not to use these functions.

Not sure what exactly makes them think they’re WEB security specialists, but this post proves pretty much the opposite. It’s just giving their readers a false sense of security.

Some common PHP security pitfalls…

7th May 2010

… and how to exploit them.

Chapter One: Image uploading.

Allowing users to upload files to your server needs to be done carefully. Very carefully. If a user manages to upload a (PHP) script, they’ll be able to do pretty much anything with your server, including the database (if any).

Let’s assume for a moment that you only want to allow images to be uploaded. So how can you make sure the file is really an image? Some might say “Hey, there’s $_FILES[‘file’][‘type’], which holds the file’s content type.”

I’ve seen many people (INCLUDING w3schools!) relying on this value for verification. But not only comes this value directly from the CLIENT, it can also be easily modified/faked.

I could upload a PHP file with an image/jpeg content type, and it would pass the verification. Everyone’s site using the code from w3schools is vulnerable.

EDIT: w3schools updated their sample code and fixed the issue. But still…

Don’t EVER rely on this value.

The first thing you should do, is validate the file extension. Only files that are parsed by the server (or the user’s browser) are dangerous to us. And by default, the server only parses certain files with certain extensions, such as .php, .asp, .pl, .py, etc… Depending on what you have installed.

Validating the extension is quite easy:

NOTE: Some servers parse .gif files by default. I’m not exactly sure why, but try it out to be on the safe side. Valid and normal looking GIF (as well as other) images can contain PHP code. So you don’t want to have those images parsed.

Secondly, you can use PHP’s image functions to verify if the file is an actual image. They’re not 100% bullet-proof, but it’s a fairly good start.

If you don’t have the EXIF extension installed, use getimagesize().

As I said, this is not 100% bullet-proof, meaning this can be exploited as well. But it’s a very good start.

Another option:

Upload the files to a non-public directory. The user needs to access the file using his browser in order to execute it. And this is impossible if the file is outside the public directory.

If you need to display the images at some point to the user, use a PHP script to read the file’s contents. This way they won’t be parsed and can’t cause trouble.

Another safe, but “not-so-optimal” option is storing the file in a BLOB field in the database. I wouldn’t suggest doing this if you plan on storing a lot of images, though.

And last, I highly suggest you to read this PDF from Scanit. It’s a good and mind opening read. (It also contains a Perl script which allows custom content types).

Chapter Two: HTTP header redirects.

This is one of the things I’ve seen too many times as well. People have protected areas on their pages which require some kind of authentication. If the users fails to be authenticated, they’re redirected to the log-in page. Usually, there’s nothing wrong with that. But a lot of people seem to forget to EXIT their script after redirecting.

The browser follows the redirect header for your COMFORT. It’s just a function and can be disabled easily. And if you do not exit the script, it’ll continue to run, meaning, the user will be able to see the output even after sending the header.

I’ve exploited this here, for example. And even ImperialBB was vulnerable to this a few years ago, before i reported the issue. I was able to see protected administrator forums.

http://www.php.net/exit
http://www.php.net/header

Chapter Three: Cross site scripting (XSS).

Another thing I see on a daily basis:

<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">

I won’t even lie, I was guilty of doing this too in my early PHP days. Until I learned that I could append JavaScript to the URL in the address bar, and it would be injected directly into the page I was on.

example.com/page.php/<script>alert(‘XSS’);</script>

… the above is a valid URL, and PHP_SELF would contain this bit of JavaScript. Needless to say, this alert() is harmless, but I could inject any code, and this could be potentially harmful.

Some sites use .htaccess to block requests that contain <script> tags. But in some cases, this can be bypassed by adding for example type=”text/javascript” to the tag. If you’re already using this attribute, try again without it. It all depends on how weak the regex they’re using is.

Solution? It’s even easier than any line of code… It’s as simple as leaving the action=”” attribute in BLANK! This will force the browser to submit the page to itself. Exactly as PHP_SELF would do.

<form action="" method="post">

Cross site scripting goes a lot further than that, though. But I’m only going to cover this as of now, ‘cause it’s probably the mistake I see the most. You might want to take a look at this post, if you haven’t already.

Chapter Four: Email header injection.

Another common one:

I’ve seen this a lot in contact forms. Assuming $_POST[‘email’] is unfiltered, I would be able to inject CC/BCC headers, and thus, allowing me to send emails to anyone I wanted to using your server. Now if I had some spare Viagra, or a certain “enlargement” service, I could make good use of this.

Make always sure the email is valid, and does not contain new lines or carriage returns. Just because it contains an @, it doesn’t mean it’s a valid email (apparently some people think it does).

PHP has a built-in function that does a pretty good job at verifying email addresses.

To be continued…

It’s time again… exit;

15th April 2010

As most of you probably don’t know, I work in a real estate agency. So every now and then I search for new websites where I can upload our properties to.

Recently I came across bancodecasas.com

When I first saw the site, I already had the feeling that something wasn’t quite right with it.

The site allows you to upload up to 8 images per property. So basically, you have 8 steady slots for images, whether they contain images or not, they’re there. If one of the slots is empty, the site shows a default image, which is just a placeholder. Well that was the idea, but the paths to the default images were wrong, so Firefox was unable to display these images. Not very professional, I thought to myself. There are also buttons to delete the images. If I click the button, I get a PHP error:

Warning: unlink(../images/mgrafico/noimagen.jpg) [function.unlink]: No such file or directory in /home/xxxxxxxxxx/xxxxxxxx/xxxxxxxxxx.xxx/public_html/userspanel/eliminarimg3.php  on line 17

That, is what I call a major logic error in the script. First off, there shouldn’t be a “delete button” if there’s no image. And second, I (as user) shouldn’t be able to delete any images except my own. They also had a separate PHP file for each image. Meaning, “eliminarimg1.php” would delete the first image, “eliminarimg2.php” the second, etc… I found this fairly unprofessional too, from a technical point of view.

This is where it started getting suspicious. If there are silly errors like this, there must be some security related errors as well.

I went to the page where you can modify your uploaded properties. The URL in the address bar held the ID of my property. My first thought was, okay, what if I change the ID to some other ID, which would be the one of a property that I didn’t upload.

I picked a random ID and tried it out, but the site redirected me to the main page instead of showing me the property. I was a little surprised they thought of checking for this at all. But I went a step further…

What if I disabled HTTP redirects? I’m assuming they’re simply using a header(‘Location: xxx’) redirect if the property doesn’t appear to be mine.

I disabled redirects, and voila, I was able to see and edit other properties.

Wait, what happened here?

They verify if the property with ID (given by URL) belongs to the current user (they’re using simple PHP sessions to identify them). If the property doesn’t belong to the user, they send a new Location header which redirects the browser to a new page.

Something like this:

if ($property['userid'] != $_SESSION['userid'])
{
header('Location: xxxxx');
}

The header() function only sends a new location to the browser. But the browser behaves the way I want it to, and I can tell it to stop following those redirects.

Besides, header() does not stop the code execution. The rest of the code continues running after sending the header. Usually the browser redirects fast enough, before anyone would notice, though.

So I think what I’ve done here is getting obvious. I disabled HTTP redirects on my browser, and was able to see the actual page because nothing prevented the code from continuing after sending the redirect.

What they should have done is as simple as an exit() or die() call after the header() call. Yup, it’s that easy.

http://www.php.net/exit

WAIT, I’m not done yet with this site!

They have one of those fancy WYSIWYG editors for the description of the property (TinyMCE, if you must know). Next, I checked if I was able to inject JavaScript code somewhere. I typed some code into the editor, saved, and checked what happened. Looks like my input is being converted to HTML entities, and therefore useless once saved.

But I didn’t give up here. I figured that perhaps TinyMCE is actually the guilty converter. I popped up Firebug, and changed the fancy editor back to a regular <textarea> field. Once again I typed in some code, hit save, and… SUCCESS! I’m now able to inject an unlimited amount of JavaScript code!

I mentioned once before that trusting the user when it comes to input, isn’t a good idea. And this post confirms it.

Don’t. Ever. Trust. The user.

Fun with JavaScript injection.

25th February 2010

UPDATE: Now that I’ve patched the exploit, you might no longer be able to inject your code. So in this post I’ll just assume that you’ve found your way to inject code and are curious as to what you can do now.

Now that we can inject JavaScript into our posts, why not have some fun with it?

How about we make some users give us some reputation? I wrote some functions which make this quite easy.

This is only a part of a class I wrote, and I’m not going to post it all (as of now).

This code attempts to get the current user’s ID whenever possible, so we can filer the users. Meaning we can decide which users we want to “attack”.

The cookie functions I’m using can be found here.

So, now that we can chose the affected users, let’s make them “rep” us. I’m not going to explain the whole code. If you understand it, you’ll see what changes you’re gonna have to make. Otherwise you probably shouldn’t be reading this blog in first place.

This will make users “rep” you, whether they want to or not. Although, they will probably get annoyed, because this will attempt to give reputation every time they open one of the threads you replied to. We could easily set a cookie to only make them rep you once a week or something. But I’ll leave that up to you. I’ve done the most difficult part for you already.

Happy experimenting.

Unwanted promotion.

25th February 2010

UPDATE: I’ve patched this exploit using my newly acquired admin powers. It will no longer work. So don’t waste your time! ;p

There’s another section on this site, where users can upload their music to promote it.

On the front page of the forum, there are the top 5 songs of the month. (The 5 most played songs).

In the user CP, there’s a form where you can upload your MP3, and add a title, album, and track number. And yet again, the user input wasn’t being escaped at all. I figured this out quickly by only entering a single quote into one of the fields, and receiving this error:

Invalid SQL:
UPDATE profile_audio SET title = ''', album = '',tracknumber = '00' WHERE audioid = 'xxx';

Great! Again we have full write/UPDATE access to the whole “profile_audio” table. Now how to make use of this?

Remember I have full admin rights? So I went to the admin CP to see if I was able to find useful information about the audio table. It didn’t take me long to find a list of all uploaded MP3s, including their information. There was one column called “Views per month”, and it took me about 3 guesses to find out that the actual field name in the database was “viewsmonth”.

Now let’s try to update this value using the exploit.

The user input was limited to 30, but yet again on the client-side only. I opened my best friend Firebug and removed this: maxlength=”30”

UPDATE `profile_audio`
SET title='', `viewsmonth` = 5000
WHERE `audioid` = xxx

Yes, it’s that easy. Now my song is on the front page, and first in the list. But that’s not all. This exploit would also allow me to inject JavaScript into the front page, as explained here.

If I had malicious intentions, I could really mess things up now.