SQL Injection through HTTP Headers
resources.infosecinstitute.com
resources.infosecinstitute.com
Cache-Control: no-cache
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 18170
Content-Type: text/html; charset=UTF-8
Date: Wed, 04 Apr 2012 04:50:39 GMT
Pragma: no-cache
Server: '; DROP TABLE servertypes; --
Vary: Accept-Encoding INSERT INTO servertypes SET server = 'Apache'"select user.* from users where TO_BASE64(email + ':'+ password) = '" + headers["Authorization"] + "' limit 1";
(Can't quite remember -- that base 64 bit might have been pre-calculated in a column. It has been a few years.)
One would hope that in addition to fixing the SQL injection they fixed the use of HTTP basic auth over a non-encrypted connection but, well, some stories are probably better left untold.
That was the only authentication for subsequent requests. And the ids were sequential.
After I demonstrated to them that I could get the CEOs personal details, as well as trivially brute force all other personal details in the system with a bash script calling curl, not to mention run up massive bills (the system allowed setting up phone conferences with up to 30 participants and let you use the web interface to call out to participants worldwide), they thanked me and told me they'd fix it.
Next day they'd released an updated version which they said encrypted the customer id.
Two problems:
No nonce or anything, so if you sniffed it once, you could still trivially use it to "log in" and continue as before.
Secondly, their "encryption" turned out to be base64.
I sent them a new script that showed them how to get the customer id's still. They were amazed that I'd "cracked their encryption".
$stmt = $dbh->prepare("SELECT user,password FROM admins WHERE user=? AND password=? AND ip_adr=?");
$stmt->execute($_POST['user'], md5($_POST['password']), ip_adr())
The above approach does not require that you think about what data you are accepting, and if done through-out your code, others who may not be so pre-disposed to think about escaping will not make mistakes if they copy you.Sure. When you started with that query, that IP address likely was just REMOTE_ADDR (guaranteed to not contain "bad" characters), but then the app was put behind a reverse proxy and support for x-forwarded-for was added, suddenly changing the IP address to something user-modifyable.
It costs practically nothing to use your ORM or prepared statements in order to escape all values you put into a query. So just do it and don't try to guess whether you can trust a value or not, because, after all, the source of these values can change, sometimes even without you knowing.
It's not a standard header, it's just a header... a string.
IP addresses may easily be IPv6.
You can easily have comma delimited lists of them.
You don't know how long the input will be.
And unless you are sure that your network is cleaning the incoming requests and setting those headers, you shouldn't even begin to think that they are to be trusted for anything.
<snark> By the way, just to let everyone know also. You should also sanitize form submissions. </snark>
Security! It's a total non-issue! Why would anyone want to break my app?
Most people seem to feel this way until their apps are dumped, rooted, hacked, or they just end up thinking security is cool and say "Man, I didn't realize how much of a mess I had before."
Basic scans need to be part of the CI workflow of startups these days. The same QA tier you use for Selenium and what not you should just throw Nessus/SQLMap at and have injections/vulnerabilities of the web stack fail builds as well.
It's all too common to hear people not caring until its too late. At least with all the skiddies running around nowadays it's harder for anybody rational to ignore.
Use HTMLPurifier to avoid xss.
You still need to be careful if building queries dynamically, such as dynamic WHERE or ORDER by clauses.
your db should never contain xss material. some jackass will forget to escape it on display.
x-forwarded-for: unknown
Whatever they were trying to achieve with this (I'm guessing some sort of reverse IP/geolocation lookup) the effect was that none of the people behind our corporate filter could view their site at all.After 15 years of web development, there is no reason why people still would make this mistake.