123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- using System;
- using System.IO;
- using System.IO.Compression;
- using System.Linq;
- using System.Net;
- using System.Net.Security;
- using System.Net.Sockets;
- using System.Runtime.ConstrainedExecution;
- using System.Security.Cryptography.X509Certificates;
- using System.Text;
- using System.Threading;
- using DnsClient;
- //////////////////////////////////
- #region __________ INIT __________
- using Microsoft.Extensions.Logging.Console;
- var builder = WebApplication.CreateBuilder(args);
- //控制台日志格式
- builder.Services.AddLogging(opt =>
- {
- opt.AddSimpleConsole(p =>
- {
- p.TimestampFormat = "[dd HH:mm:ss] ";
- p.SingleLine = true;
- p.ColorBehavior = LoggerColorBehavior.Enabled;
- });
- });
- using var host = builder.Build();
- builder.WebHost.UseUrls("http://*:0");
- await host.StartAsync();
- var isRunning = true;
- var cts = new CancellationTokenSource();
- Console.CancelKeyPress += (_, _) =>
- {
- isRunning = false;
- cts.Cancel(false);
- };
- var logger = host.Services.GetRequiredService<ILogger<Program>>();
- logger.LogInformation("Hello, World!");
- //Main
- try
- {
- await RealMain();
- }
- catch (Exception ex)
- {
- logger.LogError(ex, "Main");
- }
- finally
- {
- logger.LogInformation("Bye!");
- await host.StopAsync();
- Console.WriteLine();
- Console.Write("Press ENTER to exit...");
- Console.ReadLine();
- }
- #endregion __________ INIT __________
- //////////////////////////////////
- async Task RealMain()
- {
- const string url = "http://www.example.org/index.html";
- const string host = "www.example.org";
- const string path = "/index.html";
- const string dnsServerName = "reliable-dns-server-in-hosts";
- var dnsServerIp = Dns.GetHostEntry(dnsServerName).AddressList.FirstOrDefault();
- var lookup = new LookupClient(dnsServerIp);
- var result = await lookup.QueryAsync(host, QueryType.A);
- var record = result.Answers.ARecords().FirstOrDefault();
- var ip = record?.Address;
- var tcpClient = new TcpClient();
- tcpClient.Connect(new IPEndPoint(ip, 443)); // stuck if was ip gfw-ed
- var ssl = new SslStream(tcpClient.GetStream());
- var sslOptions = new SslClientAuthenticationOptions
- {
- TargetHost = string.Empty, // Leave this empty to avoid sending SNI
- RemoteCertificateValidationCallback = (_, certificate, chain, errs) =>
- {
- if (errs == SslPolicyErrors.None) return true;
- if (errs != SslPolicyErrors.RemoteCertificateNameMismatch) return false;
- if (certificate is not X509Certificate2 cert2) return false;
- // 比较证书名称和主机名称
- var certName = cert2.GetNameInfo(X509NameType.DnsName, false);
- if (certName.StartsWith("*."))
- {
- if (!host.EndsWith(certName[2..], StringComparison.OrdinalIgnoreCase)) return false;
- }
- else if (!certName.Equals(host, StringComparison.OrdinalIgnoreCase)) return false;
- // 验证证书的有效期
- if (DateTime.Now < cert2.NotBefore || DateTime.Now > cert2.NotAfter) return false;
- // 构建证书链
- if (chain == null) return false;
- chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; //检测吊销耗时太长,忽略
- chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
- chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 0, 10);
- chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
- var isValidChain = chain.Build(cert2);
- if (isValidChain) return true;
- foreach (X509ChainStatus chainStatus in chain.ChainStatus)
- {
- // 仅处理会影响安全性的错误状态
- if (chainStatus.Status == X509ChainStatusFlags.RevocationStatusUnknown ||
- chainStatus.Status == X509ChainStatusFlags.OfflineRevocation ||
- chainStatus.Status == X509ChainStatusFlags.NoError)
- {
- continue;
- }
- // 其他任何错误状态都认为证书无效
- return false;
- }
- return true;
- }
- };
- await ssl.AuthenticateAsClientAsync(sslOptions, cts.Token);
- ssl.Write(Encoding.ASCII.GetBytes($"GET {path} HTTP/1.1\r\n"));
- ssl.Write(Encoding.ASCII.GetBytes($"Host: {host}\r\n"));
- ssl.Write(Encoding.ASCII.GetBytes($"\r\n"));
- var reader = new StreamReader(ssl);
- var lines = new List<string>(); // <- 200 OK , PoC SUCC!
- do
- {
- var line = reader.ReadLine();
- if (line == "") break;
- lines.Add(line);
- } while (true);
- int bp = 0;
- }
|