Web Security | Web Hacking | Bug Bounty POC | Web Penetration Testing Tools

Thursday, October 13, 2016

Prevent CSV Injection

CSV Injection is an attack technique first discovered by Context Information Security in 2014. Usually, an attacker can exploit this functionality by inserting arbitrary characters into forms that are exportable(be this via analytics, contacts or other functionality). Consequently enabling said attacker to formulate an attack payload that is executed when said CSV file is downloaded.
The attack scenario for this is purely targeting the user(s) who download the CSV file, naturally this attack is usually disregarded as a non-issue however websites should still be aware of information that they are exporting can be potentially harmful to users.
Mitigation
The recommended steps to remediate this issue described above would be to ensure that forms that can be exported contain only alpha-numeric characters and cannot be modified to add arbitrary characters.
It should also be considered that all user input be not trusted and as a result any output should be encoded. The output from this functionality should be assumed as text and not formulae thus steps could be taken to easily designate it as such by placing quotes around the text or applying escape features as described and demonstrated below.
The issue with the CSV injection vectors discussed above isn't actually to do with the@ character, or =+-. The problem lies with the pipe (|) character, which Excel and other applications interpret to execute {arbitrary} commands and launch windows binaries from these payload vectors. From reading about attacks and researching into possible mitigation techniques, I've found that the best workaround is to escape the pipe character in this attack scenario is to prepend a \ before the pipe.This is due to excel and other programs looking for an executable namedcmd.exe or powershell.exe however when adding a \ into the path will prevent the exe from launching hence escaping and fixing this particular issue.
Additionally I have also written a python script to escape CSV files which can be seen below, it's a quick and dirty proof of concept however can be adapted easily:
def escape(payload):
     if payload[0] in ('@','+','-', '=', '|'):
             payload = payload.replace("|", "\|")
             payload = "'" + payload + "'"
     return payload

# An example of payload string
payload = "@cmd|' /C calc'!A0"
print "The Unescaped version is: " +  payload
print "When passed though escape function the value is: " + escape(payload)
From the code above it can be seen that if a payload string contains any of the blacklisted characters the attack is escaped, this is demonstrated in the output from the script:
root@zsec:# python escape_csv.py
The Unescaped version is: "@cmd|' /C calc'!A0"
When passed though escape function the value is: '@cmd\|' /C calc'!A0'
Notice from the output it can be seen that the escaped version has a set of ' around the user string and the pipe character has also been escaped. It should be noted that the issues described above are only one type of CSV injection attack, this mitigation does not cover information theft attacks that can be carried out using same technique but different payloads.
UpdateAdditionally I have re-wrote the mitigation in PHP, again it is quick and dirty, it is likely that there are better ways to code this but here be monsters:
  public static function escape_csv( $payload ) {
    $triggers = array( '=', '+', '-', '@', '|' );

    if ( in_array( mb_substr( $payload, 0, 1 ), $triggers, true ) ) {
        $payload = "'" . $payload . "'";
    }

    return $payload;
}
I hope that this post has given some of you a greater insight into how CSV injection works and how to better mitigate the issue.
Prevent CSV Injection when suing user generated data
def escape_csv(payload):
if payload[0] in ('@','+','-', '=', '|'):
payload = "'" + payload
payload = payload.replace("|", "\|")
return payload
# Example
payload = "@cmd|' /C calc'!A0"
print "The Unescaped version is: " + user_generated_string
print "When passed though escape function the value is: " + escape_csv(user_generated_string)

Save it on csv.py
,

No comments:

Post a Comment