SQL injection search
github.com
github.com
the first result I see currently: https://github.com/matsprehn/122B/blob/1d54d2a72f25a23d63ff7...
also spotted this, which looks pretty harmless: https://github.com/cameroni2003/picgrid/blob/0b3becda1f250ef...
a lot others look similar, plus it depends on context...
I can definitely see the issue if the server saves the unfiltered input and tries to print that out for other uses, but it seems to me that outputting a raw $_GET variable will only go to the requester and therefore could only run unfiltered code on that requesters machine.
EDIT: Answering my own question:
This is a security hole because the unsafe JavaScript is stored in the URL for the page (it is a GET parameter). This bad URL could then be sent as a link in a spam email or similar. Victims clicking on the link would then see a page that comes from the legitimate source, but is running unsafe code compromising that user's session. This sort of attack relies on the attacker distributing the link with the bad code as a URL parameter, and is not a vulnerability that a user could encounter when just visiting that site as I had first assumed.
This (http://web.math.jjay.cuny.edu/fcm791/web2.0_Vulnerabilities....) is a pretty good paper (jump to page 7) if you are interested.
https://codeclimate.com/ is one I've used but it's Ruby only AFAIK.
[1] https://news.ycombinator.com/item?id=4982240 "GitHub Says ‘No Thanks’ to Bots — Even if They’re Nice"
Nothing new here. Google code search a while back was similar. Also search for index.php~, a great way to see the source for an index page with a unix temp file that Apache will forward as plain text. Oops.
$id = mysql_real_escape_string($_GET['id']);
$res = mysql_query("SELECT foo FROM bar WHERE id='$id'");
That may be ugly, but it's bulletproof regarding injection. use PDO;
use PDOException;
/**
* Used for interacting with the database. Usage:
* <pre>
* $db = Database::get();
* $db->call( ... );
* </pre>
*/
class Database extends Obj {
private static $instance;
private $dataStore;
/**
* Sets the connection that this class uses for database transactions.
*/
public function __construct() {
global $dbhost;
global $dbname;
global $dbuser;
global $dbpass;
try {
$this->setDataStore(
new PDO( "pgsql:dbname=$dbname;host=$dbhost", $dbuser, $dbpass ) );
}
catch( PDOException $ex ) {
$this->log( $ex->getMessage() );
}
}
/**
* Returns the singleton database instance.
*/
public function get() {
if( self::$instance === null ) {
self::$instance = new Database();
}
return self::$instance;
}
/**
* Call a database function and return the results. If there are
* multiple columns to return, then the value for $params must contain
* a comma; otherwise, without a comma, the value for $params is used
* as the return column name. For example:
*
*- SELECT $params FROM $proc( ?, ? ); -- with comma
*- SELECT $proc( ?, ? ) AS $params; -- without comma
*- SELECT $proc( ?, ? ); -- empty
*
* @param $proc Name of the function or stored procedure to call.
* @param $params Name of parameters to use as return columns.
*/
public function call( $proc, $params = "" ) {
$args = array();
$count = 0;
$placeholders = "";
// Key is zero-based (e.g., $proc = 0, $params = 1).
foreach( func_get_args() as $key => $parameter ) {
// Skip the $proc and $params arguments to this method.
if( $key < 2 ) continue;
$count++;
$placeholders = empty( $placeholders ) ? "?" : "$placeholders,?";
array_push( $args, $parameter );
}
$sql = "";
if( empty( $params ) ) {
// If there are no parameters, then just make a call.
$sql = "SELECT recipe.$proc( $placeholders )";
}
else if( strpos( $params, "," ) !== false ) {
// If there is a comma, select the column names.
$sql = "SELECT $params FROM recipe.$proc( $placeholders )";
}
else {
// Otherwise, select the result into the given column name.
$sql = "SELECT recipe.$proc( $placeholders ) AS $params";
}
$statement = $this->getDataStore()->prepare( $sql );
//$this->log( "SQL: $sql" );
for( $i = 1; $i <= $count; $i++ ) {
//$this->log( "Bind " . $i . " to " . $args[$i - 1] );
$statement->bindParam( $i, $args[$i - 1] );
}
$statement->execute();
$result = $statement->fetchAll();
$this->decodeArray( $result );
return $result;
}
/**
* Converts an array of numbers into an array suitable for usage with
* PostgreSQL.
*
* @param $array An array of integers.
*/
public function arrayToString( $array ) {
return "{" . implode( ",", $array ) . "}";
}
/**
* Recursive method to decode a UTF8-encoded array.
*
* @param $array - The array to decode.
* @param $key - Name of the function to call.
*/
private function decodeArray( &$array ) {
if( is_array( $array ) ) {
array_map( array( $this, "decodeArray" ), $array );
}
else {
$array = utf8_decode( $array );
}
}
private function getDataStore() {
return $this->dataStore;
}
private function setDataStore( $dataStore ) {
$this->dataStore = $dataStore;
}
}
Example usage: $db = Database::get();
$result = $db->call( "is_existing_cookie", "existing", $cookie_value );
return isset( $result[0] ) ? $result[0]["existing"] > 0 : false;
Another example: private function authenticate() {
$db = Database::get();
$db->call( "authentication_upsert", "",
$this->getCookieToken(),
$this->getBrowserPlatform(),
$this->getBrowserName(),
$this->getBrowserVersion(),
$this->getIp()
);
}
Switching to PDO is better. Critiques welcome on Code Review SE.http://codereview.stackexchange.com/questions/26507/generic-...
I found this interesting, though, regarding specifically SQL injection when mysql_real_escape_string is used: http://stackoverflow.com/questions/5741187/sql-injection-tha...
basically the argument appears to boil down to mixed character sets causing escaping not to act as predicted. I can't speak to the validity of it though.
SELECT * FROM table WHERE id=$_GET['field']
where $_GET['field'] has been passed through mysql_real_escape_string is still vulnerable. Using prepared statements forces php to send data to the DBMS in such a way that it cannot confuse user input from the actual SQL. This is due to the fact that preparing data forces you to give types to the data before you use it in a query. Escaping input (such as with mysql_real_escape_string) makes this confusion still possible.For example the random usage of underscores: strtoupper(...) substr_compare(...) str_split(...) str_word_count(...)
The search goes like this: https://github.com/search?q=mysql_query+%22SET+NAMES%22+mysq...
PHP has some of the insanest defaults due to its C heritage. String functions deal with bytes not characters, so cannot be used safely with utf8 without setting the mbstring.func_overload setting to replace them with unicode-aware versions (except for str_pad, which always deals in bytes). Sort() defaults to binary sorting, and cannot be tricked in any way to sort utf8 in dictionary order if you're running your server on windows (and even on linux it requires an extra parameter on every call). Natsort(), which is supposed to sort like a human would, cannot be made to sort in dictionary order at all. The proper way to sort is by using the Collator class, which is not referenced from the sort() documentation, didn't exist before PHP 5.3, and is in the optional intl extension which is usually disabled by default.
Still better than mysql though, which has a very unique interpretation of unicode collation.
It would be interesting to know if some of these developers are relying on "magic quotes" or something similar... and also to know how large share of the total number of projects these projects represent.
https://github.com/search?p=2&q=MD5+password+extension%3...
https://github.com/search?q=CURLOPT_SSL_VERIFYHOST+NOT+depre...
There's more low-hanging fruit, if you're willing to use more specialized searches. For example, guess what mode of operation the PyCrypto library uses by default for all its block ciphers if you don't explicitly pick a sane one:
You don't even have to be a script kiddie. You just have to be able to click a button.
$result = mysql_query('DELETE FROM saves WHERE id = '.(int)$_GET['delete']);While there's nothing technically wrong with the example given, I might argue that since that won't work in all cases, it might be better to enforce a more rigorous policy of SQL query cleansing, or using bound params. Although this example is so simple I might not.
Then again, the fact that $_GET is even available at the location the query is taking place means this is most likely a type of design that I abhor, that PHP makes easy. Put actions in functions or methods, and then call them.
That doesn't mean PHP doesn't deserve some stick, it does, but most of it's current reported problems spawn from backwards compatibility. Nobody should be using mysql_*, they should be using prepared statements via PDO.
They could solve this by deleteing all the functions you're not supposed to use, but a whole bunch of legacy PHP would stop working. I'm fairly sure this would illicit more hate than the current method of slowly deprecating.
IMHO, neither are good design choices, as one couples the program to HTTP too tightly (and not in a sane way), the other leads to crazy spaghetti PHP as the control flow can be affected by global variables set (or received from the user) far from where they are used.
Casting to int is not a general purpose escaping system, and further, if you miss even one of these your entire application can be trashed.
Using mysql_query at all is a sign there's something severely wrong with your application.
And also, doing the cast inside the sql statement makes it difficult to see. It should be done, if at all, outside the query where it's obvious to anyone looking at the code that this is something that should be paid attention to.
If you're inserting a value in a database, you always, always, always use the proper escaping mechanism. No exceptions.
That's why using a library with a reliable, well-defined, easy to use escaping system is absolutely imperative.
This is an actual, serious problem which I would note in a code review, as opposed to the int thing which cannot, as far as I can can tell, ever lead to an exploit or malfunction which would have been avoided by using a named escape function in this code. If anyone can think of a specific example to prove this wrong, please say so.
That said, I'm sure a slight tweak to the search would find a lot in other languages as well.
https://github.com/search?q=extension%3Aphp+mysql_query+%24_...
"We found these issues, and we can fix them all. Pay us for finding them or pay us some more for fixing them, too." sort of thing.
Why don't you see QA shops popping up like this?
Bigger issue is a market problem. People who need the help the most do not know they need it.
But was that
"We found a hole, here it is." "Thanks! Your good at that" "I know, want to hire us?"
or
"We found a hole. Pay us and we'll tell you."
Because those are very different approaches.
Info about the QA/Security Consulting: http://www.cigital.com/services/
Secure coding plugin - http://www.cigital.com/products/secureassist/
When dealing with legacy code, especially code going back into the 1980s for example, it's not at all unusual for the code to have been stored in several different version control systems over that time. I know of projects that started with SCCS, moved to RCS, then to CVS, then to Perforce, then to Subversion, and most recently to Git.
If those transitions are done quickly, then somebody will often just take all of the code from a checkout of the old VCS, and check it into the new system.
The same can happen when initially using a VCS, after having not used one before, especially when taking a project over from a developer or even a team that was less-talented. Even if the new developer(s) are going to review the code, and fix bugs and other flaws, a version with the initial state of the code is often a useful thing to have.
http://pentestlab.wordpress.com/2012/11/27/automated-source-...
https://www.owasp.org/index.php/Static_Code_Analysis
http://code.google.com/p/yara-project/
http://www.lightbluetouchpaper.org/ (the 3rd post
(these aren't the services, these are what you shd read to decide if some service's operatives are appropriately expensive, and up on current research
When you upgrade to PHP 5.6 and your application grinds to a halt because mysql_query isn't available, you'll be wishing you'd fixed it sooner.
(RHEL/CentOS is currently on PHP 5.3 and will stay there for a long time.)
I'd be interested in a cite on the licensing issues, incidentally; I'm not aware of anything. (There _is_ an issue with the JSON extension at present, though, so it's not impossible.)
Alarmingly (and sadly) most do not.
Without some real-world context for each project, we just can't say whether the code we're looking at represents a real security problem. I'm certain that github hosts just as many one-off, let-me-scratch-some-code-together-that-I'll-never-use-again type projects as it does hard core, production quality ones.
That said it's a neat technique for quickly auditing code. Someone should now write an automated tool for submitting security patches to all of these projects.
It is very easy to verify that a mysqli or PDO call is correct by looking at it. The same cannot be said for mysql_query.