Vulnerabilities in PHP Web Applications

High-Risk Vulnerabilities in PHP Web Applications

Munish Walia

Munish Walia

Sr. Technical Manager

Published May 16 2019

In this blog, we will walk about some of the vulnerabilities found in PHP applications that are generally ignored by the developers. The severity of such vulnerabilities is quite high and may compromise the entire server. Let’s address some of such vulnerabilities.

SQL Injection

An SQL Injection (SQLi) attack exploits the injection of SQL commands into SQL queries of a web application. A successful SQLi attack lets malicious user access and manipulate a web application’s back-end database.

SQL Injection

In the above image, the malicious user can access the back-end database of the web application with SQL injection. This would allow him to do privilege escalations at the application level. When a SQL server is running under the context of system admin (DBO,SA), a malicious user would be able to own the entire server.

Refer to the below PHP code snippet:

#Insert statement

<html>
<form id="login" method="post" >
<table id="login">
<tr> <td><input type="text" id="company" /></td> </tr>
<tr><td><input type="text" id="address" /></td></tr>
<tr><td><input type="button" id="submit" value="submit" /></td></tr>
</table>
</form>
</html>
<?php
if (isset($_POST['submit']))
{
    $company        = $_POST['company'];
    $address        = $_POST[address];
    $insert = "Insert into emp(company, address)values(‘$company’,’$address’)";
mysql_query($insert);
}
?>

  • When a user submits the form, company and address value is saved in local variables - $company and $address fetching their values from $_POST variables.
  • Address and company are then saved in MySQL database, emp table using INSERT statement.
  • Mysql_query fires the INSERT statement.

The above code is vulnerable for persistent cross-site scripting. The script will be executed when details of the company and address are viewed by the user or admin. This would lead to privilege escalation at the application level, gaining admin level permissions.

PHP CODE

#Select statement

<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') 
{
    if (isset($_POST["username"]))
    {
        $user_name = $_POST["username"];
    }
    if (isset($_POST["password"]))
    {
        $pass = $_POST["password"];
    }   
$sql = "SELECT username FROM admin WHERE username = '$user_name' AND password = '$pass'";
$count=$conn->prepare($sql);
$count->execute();
$no=$count->rowCount();
if ($no > 0) {
        $yourURL="http://localhost/admin/welcome.php";
        echo ("<script>location.href='$yourURL'</script>");
    }
else
    {
        print("<h1>Access Denied...!!!</h1>");
    }
}
?>
<html>
<div align="center">
<h1>Login</h1>
<body>
 <form action='logincheck.php' method='post'>
<table>
<tr><td>Username:<input type="text" name="username" /></td></tr><br />
            <tr><td>Password:<input type="password" name="password" /></td></tr><br />
            <tr><td><input type='submit' value='Login' /></td></tr><br />
</table>
  </form>
  </div>
 </body>
</html>

The above code is vulnerable for SQL Injection since none of the POST variables – username and password – are filtered or sanitized. Code is blindly accepting whatever the username and password contain. This is a dangerous situation as it can compromise the application and later the entire server.

PHP Login Screen

PHP Admini Panel

Cross-site Scripting (XSS)

Cross script scripting (XSS): Sole purpose of a malicious user is to inject HTML (HTML injection) or run JavaScript in the website. JavaScript code is injected into the web page source code to execute JavaScript within the website context of the browser.

<?php
echo ‘<h2>Welcome ‘ . $_Get[‘username’] . ‘</h2>’ ;
?>

The code above is intended to print a welcome message for the logged-in user. Username is retrieved using GET variable. GET method stores values of query string parameters in the form of pairs passed through HTTP GET method.

Now, the server will return the following code to the browser:

<h2>Welcome user1</h2>

But malicious user can add additional details in the above code to exploit XSS vulnerability. Such vulnerability occurred because the user input is passed to a local variable since it is not sanitized. These types of attacks are possible when user input is used in the web application output that allows an attacker to take control of the content which is rendered to the users, eventually attacking the users.

Cross-site scripting can be used to achieve the following:

  • Cookies stealing
  • Taking control of the browser
  • Keylogging

Reflected XSS

Persistent XSS

Three types of XSS are identified so far – Reflected, Persistent, and DOM-based XSS.

  • Reflected XSS: This is the most common XSS vulnerability. It occurs when the untrusted user data is sent to the web application and it is instantly echoed back as untrusted content. The browser receives the code from a web server and renders it.
    This vulnerability deals with server-side code. Take a look at the following code snippet:

    <?php
    $name = $_GET[‘username’];
    ?>
    Welcome <?=$name?>;
    

    In this case, the malicious payload is added somehow in the HTTP request and, later on, it gets inserted into the webpage and executed by the browsers. Malicious user tricks the actual user of the web application to click the specially crafted link. By doing so, malicious payload runs into the browser within the context of the user.

  • Persistent XSS: In this case, rather than reflecting the malicious user's input in the response, it stores within the web application in database. Once it occurs, it is echoed back to all web application users. These types of flaws occur in server-side code.
  • DOM-based XSS: The above two types exist only in server-side code and user input must be sent to the server to process. But DOM-based XSS only exists in client-side code, typically in JavaScript. Let us have a look at the below code snippets vulnerable to XSS. This is similar to reflected XSS but it never interacts with the server-side.

    <h2 id=”welcome”></h2>
    <script>
    
    var msg = “Welcome”;
    
    </script>
    document.getElementByID(‘welcome’).innerHTML = w
    

The above code snippet is clearly vulnerable to DOM side cross site scripting. In this case, client-side code is able to access browser DOM elements. It majorly impacts history, cookies, and local storage.

Impact of XSS vulnerabilities:

  • Impersonate the user to perform certain actions on behalf of the user which leads the malicious user to gain higher privileges in the web application- typically a CSRF attack.
  • A malicious user is able to read data, which only authenticated user can access.
  • Inject malware into the website which can benefit the malicious user in gaining remote access of the website visitor’s computers.

Handling XSS Vulnerabilities

Enabling certain protection headers can prevent XSS to a certain level

X-XSS-Protection Header:

  • This header is designed to enable cross-site-scripting filter built into modern browsers. When a cross-site scripting attack is detected, the browser sanitizes the page itself to stop the attack.

    When it is set to x-xss-protection:1 – enables the XSS filter

    When mode=block is set along with it, then the browser will stop rendering the page when XSS attack is detected.

    Using developer tools in Chrome in headers tab, notice the x-xss-protection value (as shown in below screenshot). This protection header is not enabled by blogger.com web server. Its value is set to 0. But this does not mean it is vulnerable to XSS. There are multiple ways to handle XSS.

    Reflectex-xss-protection header

How to enable this protection header in web servers?

  • Apache
    Modify httpd.conf file placed at “/etc/httpd/conf/httpd.conf”. This is the main configuration file for Apache web server. Add the following line in this file:
    Header set X-XSS-Protection "1; mode=block"

  • Nginx
    Nginx webserver configuration file is located at- /etc/nginx/nginx.conf
    Add the following line in this file:
    add_header X-XSS-Protection "1; mode=block";

  • IIS
    Add the following lines in web.config

    <httpProtocol>
        <customHeaders>
          <add name="X-XSS-Protection" value="1; mode=block" />
        </customHeaders>
      </httpProtocol>
    

    Some more headers can also be added in the web server configuration file.

X-Frame-Options Header:

This will prevent clickjacking vulnerability and instruct the web page to not embed web page in frame/iframe. Some of the configuration values for this header are:

  • SAMEORIGIN - iframe content is only allowed from the same website/same domain.
  • DENY - Prevent any external domain to embed any content in iframe.
  • ALLOW-FROM URI - webpage can only be displayed from specific origin – http://myweb.com only. Even subdomain is ignored here.
  • ALLOW ALL – Embedding contents in iframe on your website is allowed, which can be dangerous.

    All parameters mentioned above can be added to web server configurations files

Content Security Policy Header:

By default, all scripts on the web page are allowed to send and fetch data from any other site. But this behavior is dangerous and is prone to security risks.

Content Security Policy header allows the developer to define from where the content can be loaded and from which domain data can be posted to your web application. Let’s say, CSP header is set as default-src:self, then the content can be loaded only from http://myweb.com/*.

Encoding User Output:

Let us assume that the user is searching for a specific product on an eCommerce website. Web application should never trust user input and must encode the user input before it is displayed as an output on the web page. Before adding any data in HTML element or an attribute, developer must ensure that it is HTML encoded. This will encode special characters like “<” to <

Add encoding, user input escaping, and filtering techniques before assigning user input directly to an HTML element.

Overall, usage of iframe must be avoided on your web application which can be used by a malicious user to embed hidden content from other websites. This affects every visitor of your web application by malware or other vulnerabilities like CSRF (Client-side request forgery). It tricks a user to execute unwanted actions on web application in which they are authenticated. Purpose of such attacks is to change the data in database.

Local File Inclusion

Basically, a PHP file can be included in another PHP file using include () function. Contents of the files are included into the calling PHP file along with any functions or variables declared in that PHP file. For example, a file named config.php contains MySQL connection details and a conn variable used to connect and fetch the data from MySQL server when firing SQL statements. The developer will include this file in index.php to fetch the data from MySQL server.

  1. $page = $_REQUEST[“page”];
  2. @include(‘$page.php’);
  3. get_file_contents(‘include/$page.php’);

First scenario:

Let us assume there is a GET variable “productname” passed to local variable:

<?php
$productpage = $_REQUEST['productpage'];

If(isset($productpage))
{
    include(“$productpage”.php);
}
URL becomes - http://www.vuln.web.com/page=<productpage> ?>

Now because $productpage variable is not sanitized, the malicious user can now read any file contents from the web server. This code is also vulnerable for a remote file inclusion as well.

Second scenario:

@include('include/$productpage.php');

The above code is vulnerable but also leads to remote code execution.

If the malicious user is able to access /proc/self/environ variable through LFI, then remote code execution is possible by poisoning using user-agent value. Environ file has variables for web server and one of the variables is the user-agent.

It can execute anything between in PHP file.

Third scenario:

file_get_contents(include/language/$language.lang.php)

The code mentioned above is still vulnerable to file inclusion, but it will read the content of the file. It does not allow remote code execution.

By now, it is identified that including any un-sanitized GET/POST parameter value directly in the include function is dangerous and can lead to high-risk vulnerabilities.

Mitigation

SQL Injection, XSS, and LFI are input validation vulnerabilities and can be prevented by enforcing input volition on any user-controlled parameter. The idea is to never trust user input and take necessary measures in the code to ensure that only intended data is passed to local variables.

  1. Implementation of Mod_Security (Modsec): It is an open-source Windows Application Firewall (WAF) developed by Trustwave Spiderlabs. It adds an extra layer of security to protect web applications and is available for Linux, Windows, Solaris, FreeBSD, Mac OS X. It integrates well with Apache HTTP server, IIS server, and Nginx server.

    Mod_Security is configured as a proxy server between user, web server, and based on certain user-defined rules set. It monitors and filters any incoming and outgoing data from the web server which does not satisfy the defined rules in it. It blocks any special characters passed to GET or POST variables to rule out cross-site scripting SQL injection and other web common attacks. It analyses headers, cookies, server variables, POST payload, etc.

  2. Implementation of mysql_real_escape_string PHP function. This function will escape all special characters in an un-escaped string. Usage:

    $query = ("SELECT * FROM admin WHERE user='%s' AND password='%s'",mysql
    _real_escape_string($user),mysql_real_escape_string($password));
    

  3. Another way is to create a function to filter out the special characters that pass to GET/POST variables.

    function parseSpecialCharacters($chars)
    {
    return str_replace(array("'",""","'",'"'),array("'","""'",""",htmlspecialcharacters($chars));
    }
    $query = ("SELECT * FROM admin WHERE user='%s' AND password='%s'", 
    parseSpecialCharacters($user), parseSpecialCharacters($password));
    

    Htmlspecialcharacters function converts special characters to HTML entities :

    • > becomes >
    • < becomes <
    • & becomes amp;

  4. Validation of input boxes – User should only be allowed to enter intended information in the input box. For example – First name text box should only be alphanumeric characters. Text box should only accept numeric values to accept mobile number. Consider the example below:

    If(!preg_match(!’^[a-z\s-]$i’, $name)) {
    die(‘Please enter a valid name’)
    }
    

    Above is a whitelist-based validation in PHP. Only letters, spaces, and dashes are allowed.

  5. Typecasting – Always typecast the POST and GET variables:

    $user_name = (string) $_POST["username"];

  6. Always sanitize the value of HTTP headers, URL, and cookies.

Thus, any parameter that is passed to the application must be sanitized before its value is passed to a local variable. User input should be considered unsafe and it must be checked against the whitelist (allowed character set) instead of blacklist.

Ensure that Web Application Firewall is configured correctly, which monitors user input and filters out malicious payload using a behavioral and security heuristics.