从0开始到Exploit工具编写
2021-01-10 23:48:35 Author: wiki.ioin.in(查看原文) 阅读量:2063 收藏

一.信息收集

(1)已知功能

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

    • 用户登录
    • 忘记密码

(2)指纹信息

    看了下,网站由.net开发,使用的webforms。

    但是这里显示了Web服务器是Nginx,手动探测。得知该系统由Nginx反向代理出来的。且映射路径为/WebSite/。

(3)厂商信息

    在主页下方发现了该系统的客服专线,使用fofa搜索指定内容,查找同类系统

    根据相关信息,搜索出来了8w多个站点,使用量还挺大的

    在某处发现了官方演示站点。

    为: XX软件股份有限公司

    信息收集到此结束。

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

    使用工具提取fofa结果。

    废话少说,直接上御剑(老品牌,值得信赖) 因为目标系统是Nginx反代出来的(应该是配套的安装包)。所以在扫描的时候需要加上映射路径 如/WebSite/web.rar

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

    一顿操作后。

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

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

    果然有

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

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

    环境: Vmware  IIS 8.0  SQLServer 2008

    由于是.NET程序,这里直接切到站点的根目录。

    .NET程序在发布时,会编译后在发布。所以,我们只需要对bin目录下的dll程序集进行审计即可。

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


    该站点使用了预编译。。。。且在根目录下的PrecompiledApp.config 中的updatable值设置成了false (当updatable为false时,.NET将不再更新预编译文件的内容,简单的来说就是上传的aspx文件未经编译,不能正常处理)

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

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

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

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

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

    但是这里仔细一看,顶端居然有一个效验。

    直接GG,绕不动,绕不动。

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

    最终在某处aspx文件中发现了一处文件上传漏洞。

    这里虽然做了效验,但是做的不完全,只是对上传文件的Content-Type做了效验,只要在上传的时候更改一下Content-Type为image/gif 图片格式即可。

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

    为:/import/file/Upload.aspx

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

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

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

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

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

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

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

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

    FilePath对应的是IIS的虚拟路径,URL 

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

    这里是无法绕过的。但是这里注意到了这么一行代码:

    以GET形式接收一个参数为isadmin。如果isadmin 为1 那么bool值flag参数为True。

    且在进行效验时。

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

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

    在搭建好的环境中测试。

    并没有弹出未登录的提示,证明成功绕过。根据文件的逻辑,构造好POC。

    尝试上传文件。

    在虚拟机中检测文件是否成功上传。

    成功上传,尝试打印系统相关信息。

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

<%

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

%>

    果然还是遇到了上文中所写的预编译问题,由于根目录下的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,放在指定目录

    然后运行命令

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

    编译后的文件存储在bx\server\Web下

    这时候shell.aspx已经被编译了

    即使shell.aspx不存在,访问指定路径,也是能正常处理的。

    这里主要看bin目录。生成了两个文件

    .dll 和compiled文件。这就是已经编译好的内容

    将dll文件拖入dnspy

    这里的AppRelativeVirtualPath 就是你shell的地址。这里是根目录下的/shell.aspx。

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

    先直接拖入网站的bin目录中,看看是否可行。

    成功getshell

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)


米斯特安全团队是一群热爱网络安全技术的年轻人组成的线上团队,成员来自于国内各大公司,以及各大高校。

新年招新:二进制安全、安卓安全,CTF欢迎申请加入

简历投至邮箱: [email protected]

抄送[email protected]


文章来源: https://wiki.ioin.in/url/Krp1
如有侵权请联系:admin#unsafe.sh