【发布时间】:2015-06-28 03:36:48
【问题描述】:
我有一个现有的应用程序,它曾经使用过时的 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>'=>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"=>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'] 接收的。事实上,还有第二个值 not 在 SQL 查询中使用,而是在 switch 语句中使用。因此,完整的请求如下所示:
http://localhost/api/view.php?rsvp=<status>&id=<id>
这可能会有所帮助。
编辑 2:
提及ids 实际上是GUIDs,而不是数值可能很重要。到目前为止,我使用正确的 ID 在 cmets 中运行了所有查询。以下是一些结果:
http://localhost/api/view.php?id=62FD23D8-B6C0-03F1-D45A-C9AC33C91774%27;%20drop%20table%20users;--=>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=>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();
// ...
}
【问题讨论】:
-
啊不。我现在看到了。试试
?id=1'; drop table users;-- -
1) 为了发现漏洞,访问生产系统上的运行代码几乎是必要的。仅仅有一个我们几乎无法执行的代码转储只会迫使我们猜测。 2)mysql本身并不是不安全的,如果应用得当就可以了。但是,如果不查看整个代码库,很难知道您是否正确应用了它。 3) 即使
'; DROP TABLE ..不起作用,仅仅能够添加一个条件并稍微改变查询的含义就足以让攻击者收集到有用的信息。 -
我不认为你会让
; drop anything像@deceze指出的那样工作......只是因为mysql_querydoes not allow multiple queries with;to be executed -
我会说如果您的用户可以简单地破坏它并导致语法错误,那么它就坏了。
-
您可以使查询行为不端(出错)这一事实表明攻击者对系统有一些的影响力。究竟有多少杠杆以及在实践中可以利用多少杠杆是一个不同的话题,但它肯定不是好兆头。付钱给一个渗透测试仪一个小时,你就会知道到底有多少杠杆。
标签: php mysql sql-injection