Program.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. using System;
  2. using System.IO;
  3. using System.IO.Compression;
  4. using System.Linq;
  5. using System.Net;
  6. using System.Net.Security;
  7. using System.Net.Sockets;
  8. using System.Runtime.ConstrainedExecution;
  9. using System.Security.Cryptography.X509Certificates;
  10. using System.Text;
  11. using System.Threading;
  12. using DnsClient;
  13. //////////////////////////////////
  14. #region __________ INIT __________
  15. using Microsoft.Extensions.Logging.Console;
  16. var builder = WebApplication.CreateBuilder(args);
  17. //控制台日志格式
  18. builder.Services.AddLogging(opt =>
  19. {
  20. opt.AddSimpleConsole(p =>
  21. {
  22. p.TimestampFormat = "[dd HH:mm:ss] ";
  23. p.SingleLine = true;
  24. p.ColorBehavior = LoggerColorBehavior.Enabled;
  25. });
  26. });
  27. using var host = builder.Build();
  28. builder.WebHost.UseUrls("http://*:0");
  29. await host.StartAsync();
  30. var isRunning = true;
  31. var cts = new CancellationTokenSource();
  32. Console.CancelKeyPress += (_, _) =>
  33. {
  34. isRunning = false;
  35. cts.Cancel(false);
  36. };
  37. var logger = host.Services.GetRequiredService<ILogger<Program>>();
  38. logger.LogInformation("Hello, World!");
  39. //Main
  40. try
  41. {
  42. await RealMain();
  43. }
  44. catch (Exception ex)
  45. {
  46. logger.LogError(ex, "Main");
  47. }
  48. finally
  49. {
  50. logger.LogInformation("Bye!");
  51. await host.StopAsync();
  52. Console.WriteLine();
  53. Console.Write("Press ENTER to exit...");
  54. Console.ReadLine();
  55. }
  56. #endregion __________ INIT __________
  57. //////////////////////////////////
  58. async Task RealMain()
  59. {
  60. const string url = "http://www.example.org/index.html";
  61. const string host = "www.example.org";
  62. const string path = "/index.html";
  63. const string dnsServerName = "reliable-dns-server-in-hosts";
  64. var dnsServerIp = Dns.GetHostEntry(dnsServerName).AddressList.FirstOrDefault();
  65. var lookup = new LookupClient(dnsServerIp);
  66. var result = await lookup.QueryAsync(host, QueryType.A);
  67. var record = result.Answers.ARecords().FirstOrDefault();
  68. var ip = record?.Address;
  69. var tcpClient = new TcpClient();
  70. tcpClient.Connect(new IPEndPoint(ip, 443)); // stuck if was ip gfw-ed
  71. var ssl = new SslStream(tcpClient.GetStream());
  72. var sslOptions = new SslClientAuthenticationOptions
  73. {
  74. TargetHost = string.Empty, // Leave this empty to avoid sending SNI
  75. RemoteCertificateValidationCallback = (_, certificate, chain, errs) =>
  76. {
  77. if (errs == SslPolicyErrors.None) return true;
  78. if (errs != SslPolicyErrors.RemoteCertificateNameMismatch) return false;
  79. if (certificate is not X509Certificate2 cert2) return false;
  80. // 比较证书名称和主机名称
  81. var certName = cert2.GetNameInfo(X509NameType.DnsName, false);
  82. if (certName.StartsWith("*."))
  83. {
  84. if (!host.EndsWith(certName[2..], StringComparison.OrdinalIgnoreCase)) return false;
  85. }
  86. else if (!certName.Equals(host, StringComparison.OrdinalIgnoreCase)) return false;
  87. // 验证证书的有效期
  88. if (DateTime.Now < cert2.NotBefore || DateTime.Now > cert2.NotAfter) return false;
  89. // 构建证书链
  90. if (chain == null) return false;
  91. chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; //检测吊销耗时太长,忽略
  92. chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
  93. chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 0, 10);
  94. chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
  95. var isValidChain = chain.Build(cert2);
  96. if (isValidChain) return true;
  97. foreach (X509ChainStatus chainStatus in chain.ChainStatus)
  98. {
  99. // 仅处理会影响安全性的错误状态
  100. if (chainStatus.Status == X509ChainStatusFlags.RevocationStatusUnknown ||
  101. chainStatus.Status == X509ChainStatusFlags.OfflineRevocation ||
  102. chainStatus.Status == X509ChainStatusFlags.NoError)
  103. {
  104. continue;
  105. }
  106. // 其他任何错误状态都认为证书无效
  107. return false;
  108. }
  109. return true;
  110. }
  111. };
  112. await ssl.AuthenticateAsClientAsync(sslOptions, cts.Token);
  113. ssl.Write(Encoding.ASCII.GetBytes($"GET {path} HTTP/1.1\r\n"));
  114. ssl.Write(Encoding.ASCII.GetBytes($"Host: {host}\r\n"));
  115. ssl.Write(Encoding.ASCII.GetBytes($"\r\n"));
  116. var reader = new StreamReader(ssl);
  117. var lines = new List<string>(); // <- 200 OK , PoC SUCC!
  118. do
  119. {
  120. var line = reader.ReadLine();
  121. if (line == "") break;
  122. lines.Add(line);
  123. } while (true);
  124. int bp = 0;
  125. }