在渗透的侦查踩点阶段,进行全面的信息收集对后面实施渗透的尝试尤为重要。
通过子域名爆破、搜索引擎查询等方式收集目标资产信息之外,对于开放443端口HTTPS服务的网站,我们可通过HTTPS证书来收集子域名和兄弟域名。
例如通过浏览器证书功能查看详细信息在 一栏,可以发现不少该使用证书授权的域名:
DNS Name=developers.weixin.qq.com
DNS Name=ad.weixin.qq.com
DNS Name=game.weixin.qq.com
DNS Name=as.weixin.qq.com
DNS Name=hk.open.weixin.qq.com
DNS Name=open.weixin.qq.com
DNS Name=api.weixin.qq.com
DNS Name=sz.api.weixin.qq.com
DNS Name=long.open.weixin.qq.com
DNS Name=mp.weixinbridge.com
DNS Name=servicewechat.com
DNS Name=hk.mp.weixin.qq.com
DNS Name=sz.mp.weixin.qq.com
DNS Name=hk.api.weixin.qq.com
DNS Name=sh.api.weixin.qq.com
DNS Name=sz.open.weixin.qq.com
DNS Name=a.weixin.qq.com
DNS Name=mp.weixin.qq.com
下面的分享就是编写一款自动获取证书中兄弟域名的C#小工具
首先通过Socket连接服务器HTTPS服务下载证书
TcpClient client = new TcpClient() client.Connect(“mp.weixin.qq.com”, 443); //使用SslStream类存储流 SslStream ssl = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); try { ssl.AuthenticateAsClient(host); } //catch (AuthenticationException e) catch (Exception e) { Debug.WriteLine(e.Message); ssl.Close(); client.Close(); return cert; } //拿到证书,关闭 cert = new X509Certificate2(ssl.RemoteCertificate); ssl.Close(); client.Close();
通过调试断点,可以看到cert的各属性,里面没有DNSName相关的
通过搜索我们发现X509Certificate2. GetNameInfo方法可以获取到证书的DNSName,调用方法如下
cert.GetNameInfo(X509NameType.DnsName, false)
运行程序,得到DnsName
Console.WriteLine(“{0}”, cert.GetNameInfo(X509NameType.DnsName, false));
然而我们发现使用微软自带的类操作证书只能读到诸多“使用者可选名称”中的一个值(最后一个),需要换个思路。
进一步发掘,在X509Certificate2. Extensions对象中存储有证书的扩展信息,
遍历出来观察一下
foreach (X509Extension ext in cert.Extensions)
{
Console.WriteLine(“Oid {0} {1} {2}”, ext.Oid.FriendlyName, ext.Oid.Value, Encoding.Default.GetString(ext.RawData));
}
在证书扩展Oid.FriendlyName 为“使用者可选名称”的RawData中,存储着DNS Name值的列表,从这里可以获取到证书关联的所有兄弟域名的数据。
但是这个列表数据中间使用了不可见字符分隔,通过将RawData转码(ASCII解码),中间的分隔符为82开头,后面的两位表示域名的长度
如developers.weixin.qq.com 长度为24,转为16进制就是18
下面来处理这个问题,方法如下
if (ex.Oid.FriendlyName == “使用者可选名称”|| ex.Oid.FriendlyName == “Subject Alternative Name”) //为了兼容系统中英文 { Console.WriteLine(“{0}”, ext.Oid.FriendlyName + ” – ” + ex.Oid.Value + ” | ” + Encoding.Default.GetString(ext.RawData)); string dnsnames = “”; //由于RawData是Byte数组,这里逐个转为Hex 16进制数据 for (int i = 0; i < ext.RawData.Length; i++) { dnsnames += ext.RawData[i].ToString(“X2”); } Console.WriteLine(dnsnames); //首先通过正则切割,这里正则表达式为”82dw”因为域名长度有限Hex的首位不会是字母,而用”82ww”则会误报 string[] dnsname = Regex.Split(dnsnames, @”82dw”, RegexOptions.None); //逐个还原域名 foreach (string dns in dnsname) { if (dns.Length > 6) { //16进制转换为字符串 var arr = Regex.Matches(dns, @”ww”).Cast<Match> ().Select(m=>m.Value); foreach (var m in arr) { char c = (char)Int32.Parse(m, System.Globalization.NumberStyles.HexNumber);Console.Write(c); } Console.WriteLine(“”); } } }
得到完整的域名列表
这样就没问题了,一个简单的功能实现分享给大家,希望和大家共同进步。
附源码+程序:https://pan.baidu.com/s/1nwa2VyD,可供下载