17/04/2014

PHP Source Code Chunks of Insanity (Delete Post Pages) Part 4

Intro 

This post is going to talk about source code reviewing PHP and demonstrate how a relatively small chunk of code can cause you lots of problems.

The Code

In this article we are going to analyze the code displayed below. The code displayed below might seem innocent for some , but obviously is not. We are going to assume that is used by some web site to delete posts from the logged in users securely.
 <?php  
 require_once 'common.php';   
 validatemySession();   
 mydatabaseConnect();  
  $username = $_SESSION['username'];// Insecure source  
 $username = stripslashes($username);// Improper filtering  
 $username = mysql_real_escape_string($username);//Flawed function  
 // Delete the post that matches the postId ensuring that it was created by this user  
  $queryDelete = "DELETE FROM posts WHERE PostId = " . (int) $_GET['postId']. " AND Username = '$username'";  
  if (mysql_query($queryDelete))// Bad validation coding {  
       header('Location: myPosts.php'); }  
  else {  
      echo "An error has occurred.";   
      }  
 ?>  

If you look carefully the code you will se that the code is vulnerable to the following issue: SQL Injection!!
    
Think this is not accurate , think better.

The SQL Injection

An adversary in order to exploit this vulnerability would not have to script custom tools, would only have to have good knowledge of SQL injections methodologies and exposure to PHP coding.

Vulnerable Code:

1st Code Chunk 
 $username = $_SESSION['username'];// Insecure source  
 $username = stripslashes($username);// Improper filtering 
 $username = mysql_real_escape_string($username);//Flawed function  
2nd Code Chunk: 
 $queryDelete = "DELETE FROM posts WHERE PostId = " . (int) $_GET['postId']. " AND Username = '$username'";  
3rd Code Chunk:    
 if (mysql_query($queryDelete))  

The mysql_real_escape_string function is based in the black list mentality. What it does is that escapes special characters in the un-­‐escaped string, taking into account the current character set of the connection so that it is safe to place it in a mysql_query. More specifically mysql_real_escape_string calls MySQL's library function mysql_real_escape_string, which prepends backslashes to the following characters:

1. \x00 
2. \n
3. \r
4. \
5. '
6. “

7. \x1a.

Due to this odd behavior characters such as the % and SQL keywords are not being affected, so queries that have the form of e.g. SELECT BENCHMARK(50,MD5(CHAR(118))) would be executed normally. A realistic scenario would be to use a query such as the one below:

Step1: SQL Payload that would cause the post to delete without the postId be known. 
 LIKE %’s’  

Note1: At this point we assume that the attacker knows the format of the username e.g. its user plus a two-­‐digit number. 

Step2: SQL Payload mutated in order to bypass the filters.
 LIKE CHAR(37, 8217, 115, 8217)  

Note2: Further expanding on the attack if the Web App does not have a standard format for the usernames then the adversary can brute-­‐force the username first latter e.g. try out all English letters e.g. LIKE %’a’, LIKE %’b’, LIKE %’c’ ... etc. and eventually execute the query with a valid first username letter. Translating that to an obfuscated SQL Payload would be LIKE CHAR(39, 97, 37, 39), LIKE CHAR(39, 98, 37, 39) etc.

Note3: The mysql_real_escape_string function is deprecated as of PHP 5.5.0, and will be removed in the future. Instead, the MySQLi or PDO_MySQL extension should be used. Alternatives to this function include: mysqli_real_escape_string and PDO::quote. The mysql_query() function sends a unique query (multiple queries are not supported) to the currently active database on the server that's associated with the specified link_identifier. In this specific code example the query returns true if a record is found (any record). This obscure behavior introduces the vulnerability combined of course with the above code. The function used in the mysql_query statement should return a record set only if the correct record set is returned and not just any match.

Note4: This extension is deprecated as of PHP 5.5.0.

Remedial Code:

Provide Server Side filters filter for remediating the vulnerability. Make use of strongly typed parameterized queries (using the bind_param).
 // Using prepared Statements.  
 if ($stmt = $mysqli-­‐>prepare("DELETE FROM posts WHERE PostId = ? AND Username = ? LIMIT 1"))  
 {  
 $stmt-­‐>bind_param('s', $ username); // Bind "$ username" to parameter. 
 $stmt-­‐>execute(); // Execute the prepared statement.  
 ...  
 }  

15/04/2014

PHP Source Code Chunks of Insanity (Post Pages) Part 3

Intro 

This post is going to talk about source code reviewing PHP and demonstrate how a relatively small chunk of code can cause you lots of problems.

The Code

In this article we are going to analyze the code displayed below. The code displayed below might seem innocent for some , but obviously is not. We are going to assume that is used by some web site to post the user comments securely.
<?php require_once 'common.php'; validateMySession(); ?> <html> <head> <title>User Posts</title> </head> <body> <h1>Showing current posts</h1> <form action='awsomePosts.php'>
<p>MySearch: <input type='text'  value='<?php if (isset($_GET['search'])) echo htmlentities($_GET['search'])?>'></p> <p><input type='submit' value='MySearch'></p>
</form> <?php showAwsomePosts();?> </body>
</html>
If you look carefully the code you will se that the code is vulnerable to the following issue: Stored XSS!!
    
Think this is not accurate , think better.

The Stored XSS

An adversary would need to have very good knowledge of encoding/XSS attacks to exploit this vulnerability. This vulnerability is based on a well known UTF-­‐7 encoding attack that is considered to be old. Other filter bypassing techniques can be used to bypass htmlentities such as JavaScript events.

Vulnerable Code: 
1:  <p>MySearch: <input type='text' value='<?php if (isset($_GET['search'])) echo htmlentities($_GET['search'])?>'></p>// Vulnerable to XSS UTF-­‐7 attack  
The page that the potential XSS resides on doesn't provide a page charset header (e.g. header('Content-­‐ Type: text/html; charset=UTF-­‐8'); or <HEAD><META HTTP-­‐EQUIV="CONTENT-­‐TYPE" CONTENT="text/html; charset=UTF-­‐8">), any browser that is set to UTF-­‐7 encoding can be exploited with the following XSS input (she don't need the charset statement if the user's browser is set to auto-­‐ detect and there is no overriding content-­‐types on the page in Internet Explorer and Netscape rendering engine mode). This does not work in any modern browser without changing the encoding type.

Example1 UTF-­‐7 Encoding

Input Payload :

1:  <script>alert(1)</script>  

Output (UTF-­‐7): 
1:  +ADw-­‐script+AD4-­‐alert('XSS')+ADw-­‐/script+AD4APA-­‐/vulnerable+AD4-­‐  

Example2 JavaScript Events

Injecting also JavaScript events to the htmlentities function of php will also by pass the filter.

The code before injection:     
1<p>MySearch: <input type='text' value='<?php if (isset($_GET['search'])) echo htmlentities($_GET['search'])?>'></p>  

The code after injection:
<p>MySearch: <input type='text' value='onerror='alert(String.fromCharCode(88, 83, 83))'></p>  


Note: This example needs further testing to see if it is applicable.

Remedial Code:

Provide Server Side filters for the vulnerability. Make use of regular expressions and html encode the variables whether displayed back to the user or not.

1st Layer of defense 
1:  //XSS filter the value because this value might be printed later on back in the user. if preg_match ("/[a-­‐zA-­‐Z]+/", "", $search){  
2:  showPosts();  
3:  }  
Note: Using regular expressions to replace parts of the input and proceed with further processing the input is not recommended, once a malicious input is identified should be rejected (e.g. using preg_match instead of preg_replace).

2nd Layer of defense 
1:  header('Content-­‐Type: text/html; charset=UTF-­‐8');  
2:  // This function will convert both double and single quotes. mb_convert_encoding($search, 'UTF-­‐8');  


Countermeasures Summarized
  1. Specify charset clearly (HTTP header is recommended)
  2. Don't place the text attacker can control before <meta>
  3. Specify recognizable charset name by browser.
  4. Apply regular expressions based on the white list mentality.
Note: mb_convert_encoding converts the character encoding of the input string to the desired encoding. 

References:

1. https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#UTF-­‐7_encoding 
2. http://php.net/manual/en/function.mb-­‐convert-­‐encoding.php
3. http://shiflett.org/blog/2005/dec/google-­‐xss-­‐example
4. http://www.motobit.com/util/charset-­‐codepage-­‐conversion.asp
5. http://openmya.hacker.jp/hasegawa/security/utf7cs.html 
6. http://wiremask.eu/?p=tutorials&id=10 


PHP Source Code Chunks of Insanity (Logout Pages) Part 2

Intro 

This post is going to talk about source code reviewing PHP and demonstrate how a relatively small chunk of code can cause you lots of problems.

The Code

In this article we are going to analyze the code displayed below. The code displayed below might seem innocent for some , but obviously is not. We are going to assume that is used by some web site to de-validate the user credentials and allow the users to logout securely.

1:  <?php  
2:  require_once 'common.php';  
3:  if (isset($_SESSION['username']))//Insecure source  
4:  {  
5:  session_unset();// In properly destroyed session.  
6:  }  
7:  header('Location: index.php'); ?>  


I you look carefully the code you will se that the code is vulnerable to the following issues:
  1. NULL De-­Authentication Bypass    
  2. No Proper Session Termination    
Think this is not accurate , think better.

NULL De-­Authentication Bypass 

Exploitation:

An adversary may on purpose exploit this vulnerability possibly without the need of developing any costume tools (but needs a good understanding of PHP design flaws). More specifically an adversary can manipulate the cookie parameter and de-­‐validate the logout process by injecting a NULL value in the begging of the username (after the authentication). This would result into maintaining the user Web resources available for the specific session-­‐id even after the logout is performed. 

Vulnerable Code:    
if (isset($_SESSION['username']))// Malicious de-­validation cancel  
Assuming that the target username is user12 potential malicious payloads that could exploit the vulnerability displayed above would be user[space]12 , %4e%55%4c%4c,user12, user12[space], %20user12, [space] [space]user12 [space],user12 , user12, user12,, user12NULL NULLuser12 etc. This is applicable due to the fact that if multiple parameters are supplied then the isset will return TRUE only if all of the parameters are set. Evaluation goes from left to right and stops as soon as an unset variable is encountered. The attack should occur after the user successfully authenticates her self.

Note1: At this point it should be noted that when on, register_globals (which is on by default in PHP < 5.3.0), will allow an adversary to populate the cookie username variable from various user input such request variables from HTML hidden form fields, Web Application URL’s etc. which translates into working as a vulnerability amplifier! Also this might lead into allowing POST to GET interchanges, promoting CSRF like attacks (e.g. the web app does not distinguish POST from GET).

Note2: This feature has been DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 5.4.0. 

Remedial Code:
1:  //the filter makes sure the username has no spaces. if (strpos($username, " ") !== false){  
2:  // De-­‐validate the session  
3:  }  

2nd Code Chunk:
1:  trim("^$", $username)//Not recommended to process malicious payloads, only identify.  

Note: The NULL value translates into an empty string when validations come. 

No Proper Session Termination

An adversary may on purpose exploit this vulnerability without the need of developing any costume tools. This attack might be used to perform vertical/horizontal user escalation (e.g. the cookie session-­‐ id is assigned to a new user, and the new user automatically gains access to previous user Web resources, assuming that the Web Apps makes access control decisions by using only the session-­‐id. Another attack scenario would be that the session is leaked though a blog post and the adversary makes use of the non de-­‐validated leaked session to gain access to the Web Application user resources etc.).

Vulnerable Code: 
1:  session_unset(); // Improper handling of the session.  
Note1: The function shown above does not properly de-­‐validate the session. The session_unset function just clears the $_SESSION variable. It’s equivalent to doing $_SESSION = array(); So this does only affect the local $_SESSION variable instance, but not the session data in the session storage, everything else remains unchanged (including the session identifier). In this occasion the session_unset is used to destroy/reset the session instead of the session_destroy function in the logout page. The session_destroy() function destroys all of the data associated with the current session.

Note2: The variable session_unset is considered to be deprecated code that does not use $_SESSION.

Remedial Code: 
1:  function destroySession() {  
2:  $params = session_get_cookie_params(); setcookie(session_name(), '', time() -­‐ 42000,  
3:  $params["path"], $params["domain"],  
4:  ... );  
5:  session_destroy(); }  




References:

1. http://php.net/manual/en/security.globals.php
2. https://www.owasp.org/index.php/Unvalidated_Input
3. http://php.net/manual/en/function.isset.php
4. http://php.net/manual/en/function.trim.php