我有一个现有的应用程序,它曾经使用不推荐的mysql_ *函数来执行数据库查询。我已经将大多数数据库访问(以及所有具有用户输入的内容)更改为PDO,因此我相信我对注入攻击相对安全。但是,我想知道如何对前面的代码执行注入攻击,以便我可以证明在需要时它是多么不安全。
我有以下格式的链接:
http://localhost/api/view.php?id=
然后将未经过验证的内容传递到下面的select
函数中:
$db->select('invitations','Replied, Response, Registered',null,"Id = '".$id."'");
$res = $db->getResult();
然后我会var_dump()
查看结果。
我尝试过类似的事情:
http://localhost/api/view.php?id=<id>'
=&GT; array(1) { [0]=> string(185) "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''<id>''' at line 1" }
http://localhost/api/view.php?id=<id>" or 1=1"
=&gt; array(0) { }
但似乎这些类型的查询都不会成功。理想情况下,我希望能够做一些严厉的事情。我希望有类似'); DROP TABLE users;--
的东西,但我似乎无法做出任何类似的事情。
以下是完整的select
函数:
public function select($table, $rows = '*', $join = null, $where = null, $order = null, $limit = null){
// Create query from the variables passed to the function
$q = 'SELECT '.$rows.' FROM '.$table;
if($join != null){
$q .= ' JOIN '.$join;
}
if($where != null){
if (is_array($where)) {
$filter = $where;
$where = " 0 = 0 ";
$qs = "";
for ($i=0;$i<count($filter);$i++){
switch($filter[$i]['data']['type']){
case 'string' : $qs .= " AND ".$filter[$i]['field']." LIKE '%".$filter[$i]['data']['value']."%'"; Break;
case 'list' :
if (strstr($filter[$i]['data']['value'],',')){
$fi = explode(',',$filter[$i]['data']['value']);
for ($q=0;$q<count($fi);$q++){
$fi[$q] = "'".$fi[$q]."'";
}
$filter[$i]['data']['value'] = implode(',',$fi);
$qs .= " AND ".$filter[$i]['field']." IN (".$filter[$i]['data']['value'].")";
}else{
$qs .= " AND ".$filter[$i]['field']." = '".$filter[$i]['data']['value']."'";
}
Break;
case 'boolean' : $qs .= " AND ".$filter[$i]['field']." = ".($filter[$i]['data']['value']); Break;
case 'numeric' :
switch ($filter[$i]['data']['comparison']) {
case 'eq' : $qs .= " AND ".$filter[$i]['field']." = ".$filter[$i]['data']['value']; Break;
case 'lt' : $qs .= " AND ".$filter[$i]['field']." < ".$filter[$i]['data']['value']; Break;
case 'gt' : $qs .= " AND ".$filter[$i]['field']." > ".$filter[$i]['data']['value']; Break;
}
Break;
case 'date' :
switch ($filter[$i]['data']['comparison']) {
case 'eq' : $qs .= " AND ".$filter[$i]['field']." = '".date('Y-m-d',strtotime($filter[$i]['data']['value']))."'"; Break;
case 'lt' : $qs .= " AND ".$filter[$i]['field']." < '".date('Y-m-d',strtotime($filter[$i]['data']['value']))."'"; Break;
case 'gt' : $qs .= " AND ".$filter[$i]['field']." > '".date('Y-m-d',strtotime($filter[$i]['data']['value']))."'"; Break;
}
Break;
}
}
$where .= $qs;
}
$q .= ' WHERE '.$where;
}
if($order != null){
$q .= ' ORDER BY '.$order;
}
if($limit != null){
$q .= ' LIMIT '.$limit;
}
// Check to see if the table exists
if($this->tableExists($table)){
// The table exists, run the query
$query = @mysql_query($q);
if($query){
// If the query returns >= 1 assign the number of rows to numResults
$this->numResults = mysql_num_rows($query);
// Loop through the query results by the number of rows returned
for($i = 0; $i < $this->numResults; $i++){
$r = mysql_fetch_array($query);
$key = array_keys($r);
for($x = 0; $x < count($key); $x++){
// Sanitizes keys so only alphavalues are allowed
if(!is_int($key[$x])){
if(mysql_num_rows($query) > 1){
$this->result[$i][$key[$x]] = $r[$key[$x]];
}else if(mysql_num_rows($query) < 1){
$this->result = null;
}else{
$this->result[$key[$x]] = $r[$key[$x]];
}
}
}
}
return true; // Query was successful
}else{
array_push($this->result,mysql_error());
return false; // No rows where returned
}
}else{
return false; // Table does not exist
}
}
我如何能够执行SQL注入?
修改:
使用$_GET['id']
通过浏览器接收该值。事实上,第二个值是不在SQL查询中使用,而是一个switch语句。因此,完整请求如下所示:
http://localhost/api/view.php?rsvp=<status>&id=<id>
这可能会有所帮助。
编辑2 :
值得一提的是,有问题的id
实际上是GUID
s,而不是数值。到目前为止,我使用正确的ID在评论中运行了所有查询。以下是一些结果:
http://localhost/api/view.php?id=62FD23D8-B6C0-03F1-D45A-C9AC33C91774%27;%20drop%20table%20users;--
=&gt; array(1) { [0]=> string(166) "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'drop table users;--'' at line 1" }
http://localhost/api/view.php?id=62FD23D8-B6C0-03F1-D45A-C9AC33C91774%27;select%20*%20from%20invitations;%27
=&gt; array(1) { [0]=> string(179) "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select * from invitations;''' at line 1" }
以下这些行是使用$id
的全部代码:
// ...
if(isset($_GET['id'])) {
$id = $_GET['id'];
$db->select('invitations','Replied, Response, Registered',null,"Id = '".$id."'");
$res = $db->getResult();
// ...
}
答案 0 :(得分:3)
仅仅因为某些特定输入导致MySQL语法错误的事实证明用户输入对SQL语法有一些意想不到的影响,这意味着可以进行SQL注入。
但是这种SQL注入的利用是另一个章节。 MySQL,或更准确地说PHP’s MySQL extension,默认情况下不支持使用mysql_query
执行多个语句:
mysql_query()发送唯一查询(不支持多个查询)[...]
因此,删除表格的经典示例将不起作用,您从注入点开始limited to the capabilities of the current statement和allowed syntax elements。
在您的具体示例中,SELECT将您限制为
LOAD_FILE
function INTO …
syntax 对于读取任意数据,UNION
将是最佳选择,因为结果似乎会反映回用户。您必须确保生成的SQL是有效的,这意味着您的UNION
必须有三列(即已回复,响应和从现有SELECT
注册:
' UNION SELECT '1','2','3
结果语句如下:
SELECT Replied, Response, Registered FROM invitations WHERE Id = '' UNION SELECT '1','2','3'
您现在可以用自己的表达式(包括LOAD_FILE
)或子查询替换额外选择的值。