WEB渗透偏之SQL注入

不管用什么语言编写的web应用,它们都有一个共同点,就是具有交互性并且大多数是数据库驱动的,WEB应用随处可见,因此存在的SQL注入是影响企业运营最具破坏性的漏洞,SQL注入就是通过操作SQL语句进行攻击的从而达到攻击的目的,我们通常在网上能够看到的,某某网站被脱,某某网站被脱裤,那么这些很大可能就是通过SQL注入来实现的,通常渗透者攻击的目的是得到数据库相关的信息,例如账号密码,用户信息等等。



image

二. SQL注入是如何产生的呢?

image

简单的来说,网站新闻内容,会员中心,查询等都会和数据库进行关联,其中在数据之间交互中,传输的就是SQL语句,攻击者通过操作SQL语句来达到SQL注入攻击。



三. SQL注入漏洞能造成哪些危害呢?

常见的操作:

  • 网站数据库信息泄露
  • 网站数据被修改
  • 网站整站程序源码被Download
  • 架设网站的服务器被入侵挂木马等等…

四. SQL注入原理分析

可注入是因为网站程序存在可控传递参数,参数未进行过滤直接带入数据库查询,导致攻击者可通过传递恶意sql语句代码进行执行攻击。


SQL注入的产生条件

  1. 必须有传输传递
  2. 传输值带入数据库查询并执行

我们来看一个基本网站组成的url链接:

网站地址:
http://127.0.0.1/0/Production/PRODUCT_DETAIL.asp?id=1513

网站地址:http://127.0.0.1/0/

文件目录:Production

文件名:PRODUCT_DETAIL.asp

参数名:id

参数值:1513


首先是有网站地址—>文件目录—>文件名—>参数名—>参数值

基于这种链接我们可以尝试在参数1513后面再随便传递一些参数比如dddd,如果报错,是因为在接受1513这个ID值的时候后把dddd也传递过去了,这个情况我们称之为SQL带入查询。

image

显然刚才不是SQL语句,所以报错了,一般情况下如果参数只接收不带入查询的话我们无论输入什么都不会有任何报错的迹象,证明是不存在SQL注入点的,能够带入查询是因为网站没有对参数进行过滤,所以导致带入查询,那么试想一下假设我带入查询是SQL语句,这语句的操作是查看网站用户信息或者密码的这时候是不是很危险呢?

测试题

1.下面那些地址可能存在sql注入?


A.www.cnblog.io/news.asp

B.www.cnblog.io/index.asp?page=11

C.www.cnblog.io/news.asp?id=1&page=2

D.www.cnblog.io/?id=11

2.已知cnblog.io/news.asp?id=1&page=1 中参数id存在注入,下面那个注入测试正确?


A.cnblog.io/news.asp?id=1 and 1=1&page=1
B.cnblog.io/news.asp?id=1&page=1 and 1=1
C.cnblog.io/news.asp?id=1 and 1=1&page=1 and 1=1

cnblog.io/news.asp?id=1&page=1 and 1=1 将注入参数设为page(工具检测不出)


cnblog.io/news.asp?page=1&id=1 将注入参数设为id

前面我们说到,只所以能够带入数据库查询是因为网站没有对参数进行过滤,也就是说编写网站的人在写这个业务逻辑代码有BUG,
我们来看看如下的一串代码案例,这次代码是没有对参数进行过滤的,存在带入数据库查询的操作。

1
2
3
4
5
6
7
PRODUCT_DETAIL.asp代码:

<%
id=request("id") 接受参数名id的值并赋值给变量id (前面id=变量,后面id=参数名)
sql="select * from product where id="&id 组合变量id的sql语句
set rs=conn.execute(sql) 执行sql语句
%>

http://127.0.0.1/0/Production/PRODUCT_DETAIL.asp?id=1513
select * from product where id=1513

我们来看一下PRODUCT_DETAIL.asp里面的id=request(“id”)
其中id是等于变量 request(‘id’)接受参数的值并且赋值给了变量ID,
这时sql语句组合select * from product where id=1513,
1513是接收到的网站参数,那么这个页面存在肯定是返回正常的。

http://127.0.0.1/0/Production/PRODUCT_DETAIL.asp?id=1513’
select * from product where id=1513’ 页面报错,无此id

看上行的链接和SQL语句组合,当在网站链接的id参数后面多家了一个’ 这时SQL语句执行错误报错返回错误页面,证明我们可以任意带入参数查询的,那么大家想假设我在参数后面带入的是sql查询语句是不是能够查到数据库的信息呢,这就是SQL注入对网站危害之处。

判断注入点常用的逻辑语

数学逻辑运算符:

  • 或 且 非(or and xor)
  • 真且真=真
  • 假且真=假
  • 真或真=真
  • 真或假=真

用法是在网站链接参数后面加上逻辑判断法 id=1513 and 1=1
那么加上之后,这是SQL语句是这样组合的 select * from product where id=1513 and 1=1 真且真=真 返回正常

因为这是真逻辑所以返回真,我们 加上and 1 = 11 ,
这是SQL语句是这样组合的 select * from product where id=1513 and 1=11 真且假=假 返回错误,这时我们可以确定注入点的存在,我们重新组SQL语句可以在参数后面进行传达相关的恶意sql语句来达到带入数据库查询的目的

那么判断到有注入点之后,我们怎么猜数据库里面的信息呢?
这里需要了解一个分层结构。

ACCESS数据库

表名

列名

数据

通过以上四部我们可以得到数据,首先是过表名来得到列名,再通过列名最后得到数据的。

总结分为4步

  1. 判断注入
  2. 猜解表名
  3. 猜解列名
  4. 猜解数据

接下来我们搭建个测试环境来进行实战一下注入的操作,
以access数据库为例,首先猜表明,在参数id=1513 后面传入,
猜表明的语句首先是判断有多少个字段,语句是order by 22,如下图

image

当回车的时候页面返回是正常的,那么我们继续判断order by 23

image
这次我填的字段是23 返回了错误页面因此可见表名的字段不等于23,那么可以确定表名的字段是<=22的。

找到表名的字段长度之后我们继续进行猜列名的操作语句如下

UNION SELECT
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 from admin

这段SQL语句的意思是 查询有没有admin这个表,我们一般做渗透猜解的大部分是admin表,因为这通常是一些管理员信息,如账号密码等,我们把上面语句带入查询一下,一般情况下如果存在admin这个表名的话,
网页会随机爆出一些数字,我们得到这些具体数字之后,可以对应着字段去查列名相关信息了,之后能得到数据。

image

得到的数字是3和15,那么我们可以在3和15字段利填写相关列名的信息,如果存在这个列名,那么就会爆出相关的数据,一般列名常见要爆的都是一些密码和账号信息列名如果存在的话就会爆出相关的数据信息,如下图

image

字段15填的是admin爆出了管理员账号,字段3填的是password爆出的是一个md5值,md5值我们可以进行md5解密得到真正的密码如下图所示

image

得到明文“bendss” 我们可以尝试用管理员的账号密码登录一下网站后台。

image

OK 能够成功登录,证明我们猜解出来的账号密码是正确的。

换第二种猜解方式,来尝试一下猜解,刚才的猜解方式叫联合查询法,联合查询法和逐字才猜解法是有一定区别的,

逐字才猜解法,兼容性强,一般的注入工具猜解的都是采用:逐字猜解法如明小子,阿迪,萝卜头,穿山甲等注入工具,因为联合查询法有时候猜解不出来,明明存在注入点都猜解不出来来,兼容性不强。

猜解语法:

  1. 查表:and exists (select * from 表名)
  2. 查列:and exists (select 列名 from 表名)
  3. 查数据:1.确定长度 2.确定asc数据(asc编码)
  4. and (select top 1 len(列名) from admin)=5
  5. and (select top 1 asc(mid(列名,位数,1)) from admin)=97
  6. and (select top 1 asc(mid(列名,位数,1)) from admin)=97

依然是先猜表名,我们使用 and exists (select * from admin) 语句来猜解一下 admin表是否存在,如果存在就返回正常,返回错误就代表不存在早

image

确定admin表存在之后,我们来猜一下列名,使用1. 查列:and exists (select username from admin) 来猜解,
如果返回错误则是代表这个列名不存在。

image

然而这个列名是不存在的,我们换一个试试,换成密码列名 exists (select password from admin)

image

看结果是返回正常页面的,证明有password这个表,接下来我们确定一下这个表的长度,使用 and (select top 1 len(password) from admin)=5

image

第一次我猜解的长度设置为5,返回的结果是错误页面,证明长度并不是等于5,
我们再把长度设置为>=5如果返回正常页面说明,这个列名长度肯定是大于5或者等于5的

image

看上图返回正确页面了,我们都知道一般像这些网站管理员密码通常都采用md5加密,所以一般的md5加密长度为16的,我们再把长度的值选择17位试试,如果返回错误,我们再设置回16,如果返回正确那么证明,这个列名的长度等于16位的md5加密长度。

image

事实证明,长度不也不等于17位,那么再把长度设置为16位看看,如果返回正确页面基本上,可以断定是16位的md5加密值了

image

事实证明,这个密码列名的长度为16位的md5加密值,
好以上的基本猜解步骤已经完成,我们可以着手猜列名的内容,
使用语法 and (select top 1 asc(mid(password,1,1)) from admin)=97

mid()里面的password代表是列名,1是代表猜16位长度的第一位的值内容,后面=97是ascii编码97对应的是a,如下是ascii码的对应表。

image

我们明白了怎么回事之后就开始猜解吧

image

回车:

image

好,回车之后发现返回页面的结果是正确的,证明16位的md5值第一位是97ascii码表的对应值,也就是“a” 接下来我们猜第二位,
这次我把值设置为<=52 发现是正确的,那么说明这个结果可能少于52又或者等于52,所以继续猜,最后我发现这个结果是等于52。

image

所以是ascii码对应的值“4”,以此类推,值到把16位md5值猜解完毕,猜解得到的md5值,就可以进行md5解密了。