mirror of
https://github.com/GhostPack/Rubeus
synced 2026-06-08 11:10:41 +00:00
618 lines
26 KiB
C#
Executable File
618 lines
26 KiB
C#
Executable File
using System;
|
|
using System.ComponentModel;
|
|
using System.DirectoryServices;
|
|
using System.DirectoryServices.Protocols;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text.RegularExpressions;
|
|
using System.Collections.Generic;
|
|
using SearchScope = System.DirectoryServices.Protocols.SearchScope;
|
|
using System.IO;
|
|
using System.Net;
|
|
using Asn1;
|
|
|
|
namespace Rubeus
|
|
{
|
|
public class Networking
|
|
{
|
|
public static string GetDCName(string domainName = "")
|
|
{
|
|
// retrieves the current domain controller name
|
|
|
|
// adapted from https://www.pinvoke.net/default.aspx/netapi32.dsgetdcname
|
|
Interop.DOMAIN_CONTROLLER_INFO domainInfo;
|
|
const int ERROR_SUCCESS = 0;
|
|
IntPtr pDCI = IntPtr.Zero;
|
|
|
|
int val = Interop.DsGetDcName("", domainName, 0, "",
|
|
Interop.DSGETDCNAME_FLAGS.DS_DIRECTORY_SERVICE_REQUIRED |
|
|
Interop.DSGETDCNAME_FLAGS.DS_RETURN_DNS_NAME |
|
|
Interop.DSGETDCNAME_FLAGS.DS_IP_REQUIRED, out pDCI);
|
|
|
|
if (ERROR_SUCCESS == val) {
|
|
domainInfo = (Interop.DOMAIN_CONTROLLER_INFO)Marshal.PtrToStructure(pDCI, typeof(Interop.DOMAIN_CONTROLLER_INFO));
|
|
string dcName = domainInfo.DomainControllerName;
|
|
Interop.NetApiBufferFree(pDCI);
|
|
return dcName.Trim('\\');
|
|
}
|
|
else {
|
|
try {
|
|
string pdc = System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain().PdcRoleOwner.Name;
|
|
return pdc;
|
|
}
|
|
catch {
|
|
string errorMessage = new Win32Exception((int)val).Message;
|
|
Console.WriteLine("\r\n [X] Error {0} retrieving domain controller : {1}", val, errorMessage);
|
|
Interop.NetApiBufferFree(pDCI);
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string GetDCIP(string DCName, bool display = true, string domainName = "")
|
|
{
|
|
if (String.IsNullOrEmpty(DCName))
|
|
{
|
|
DCName = GetDCName(domainName);
|
|
}
|
|
Match match = Regex.Match(DCName, @"([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(\d{1,3}\.){3}\d{1,3}");
|
|
if (match.Success)
|
|
{
|
|
if (display)
|
|
{
|
|
Console.WriteLine("[*] Using domain controller: {0}", DCName);
|
|
}
|
|
return DCName;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
// If we call GetHostAddresses with an empty string, it will return IP addresses for localhost instead of DC
|
|
if (String.IsNullOrEmpty(DCName))
|
|
{
|
|
Console.WriteLine("[X] Error: No domain controller could be located");
|
|
return null;
|
|
}
|
|
System.Net.IPAddress[] dcIPs = System.Net.Dns.GetHostAddresses(DCName);
|
|
|
|
foreach (System.Net.IPAddress dcIP in dcIPs)
|
|
{
|
|
if (dcIP.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork || dcIP.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
|
|
{
|
|
if (display)
|
|
{
|
|
Console.WriteLine("[*] Using domain controller: {0} ({1})", DCName, dcIP);
|
|
}
|
|
return String.Format("{0}", dcIP);
|
|
}
|
|
}
|
|
Console.WriteLine("[X] Error resolving hostname '{0}' to an IP address: no IPv4 or IPv6 address found", DCName);
|
|
return null;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine("[X] Error resolving hostname '{0}' to an IP address: {1}", DCName, e.Message);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string GetDCNameFromIP(string IP)
|
|
{
|
|
Match match = Regex.Match(IP, @"([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(\d{1,3}\.){3}\d{1,3}");
|
|
if (match.Success)
|
|
{
|
|
try
|
|
{
|
|
System.Net.IPHostEntry DC = System.Net.Dns.GetHostEntry(IP);
|
|
return DC.HostName;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine("[X] Error resolving IP address '{0}' to a name: {1}", IP, e.Message);
|
|
return null;
|
|
}
|
|
}
|
|
return IP;
|
|
}
|
|
|
|
public static byte[] SendBytes(string server, int port, byte[] data)
|
|
{
|
|
var ipEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse(server), port);
|
|
try
|
|
{
|
|
using (System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient(ipEndPoint.AddressFamily)) {
|
|
|
|
// connect to the server over The specified port
|
|
client.Client.Ttl = 128;
|
|
client.Connect(ipEndPoint);
|
|
BinaryReader socketReader = new BinaryReader(client.GetStream());
|
|
BinaryWriter socketWriter = new BinaryWriter(client.GetStream());
|
|
|
|
socketWriter.Write(System.Net.IPAddress.HostToNetworkOrder(data.Length));
|
|
socketWriter.Write(data);
|
|
|
|
int recordMark = System.Net.IPAddress.NetworkToHostOrder(socketReader.ReadInt32());
|
|
int recordSize = recordMark & 0x7fffffff;
|
|
|
|
if((recordMark & 0x80000000) > 0) {
|
|
Console.WriteLine("[X] Unexpected reserved bit set on response record mark from Domain Controller {0}:{1}, aborting", server, port);
|
|
return null;
|
|
}
|
|
|
|
byte[] responseRecord = socketReader.ReadBytes(recordSize);
|
|
|
|
if(responseRecord.Length != recordSize) {
|
|
Console.WriteLine("[X] Incomplete record received from Domain Controller {0}:{1}, aborting", server, port);
|
|
return null;
|
|
}
|
|
|
|
return responseRecord;
|
|
}
|
|
}
|
|
catch (System.Net.Sockets.SocketException e)
|
|
{
|
|
if (e.SocketErrorCode == System.Net.Sockets.SocketError.TimedOut) {
|
|
Console.WriteLine("[X] Error connecting to {0}:{1} : {2}", server, port, e.Message);
|
|
} else {
|
|
Console.WriteLine("[X] Failed to get response from Domain Controller {0}:{1} : {2}", server, port, e.Message);
|
|
}
|
|
|
|
}catch(FormatException fe) {
|
|
Console.WriteLine("[X] Error parsing IP address {0} : {1}", server, fe.Message);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static DirectoryEntry GetLdapSearchRoot(System.Net.NetworkCredential cred, string OUName, string domainController, string domain)
|
|
{
|
|
DirectoryEntry directoryObject = null;
|
|
string ldapPrefix = "";
|
|
string ldapOu = "";
|
|
|
|
//If we have a DC then use that instead of the domain name so that this works if user doesn't have
|
|
//name resolution working but specified the IP of a DC
|
|
if (!String.IsNullOrEmpty(domainController))
|
|
{
|
|
ldapPrefix = domainController;
|
|
}
|
|
else if (!String.IsNullOrEmpty(domain)) //If we don't have a DC then use the domain name (if we have one)
|
|
{
|
|
ldapPrefix = domain;
|
|
}
|
|
else if (cred != null) //If we don't have a DC or a domain name but have credentials, get domain name from them
|
|
{
|
|
ldapPrefix = cred.Domain;
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(OUName))
|
|
{
|
|
ldapOu = OUName.Replace("ldap", "LDAP").Replace("LDAP://", "");
|
|
}
|
|
else if (!String.IsNullOrEmpty(domain))
|
|
{
|
|
ldapOu = String.Format("DC={0}", domain.Replace(".", ",DC="));
|
|
}
|
|
|
|
//If no DC, domain, credentials, or OU were specified
|
|
if (String.IsNullOrEmpty(ldapPrefix) && String.IsNullOrEmpty(ldapOu))
|
|
{
|
|
directoryObject = new DirectoryEntry();
|
|
|
|
}
|
|
else //If we have a prefix (DC or domain), an OU path, or both
|
|
{
|
|
string bindPath = "";
|
|
if (!String.IsNullOrEmpty(ldapPrefix))
|
|
{
|
|
bindPath = String.Format("LDAP://{0}", ldapPrefix);
|
|
}
|
|
if (!String.IsNullOrEmpty(ldapOu))
|
|
{
|
|
if (!String.IsNullOrEmpty(bindPath))
|
|
{
|
|
bindPath = String.Format("{0}/{1}", bindPath, ldapOu);
|
|
}
|
|
else
|
|
{
|
|
bindPath = String.Format("LDAP://{0}", ldapOu);
|
|
}
|
|
}
|
|
|
|
directoryObject = new DirectoryEntry(bindPath);
|
|
}
|
|
|
|
if (cred != null)
|
|
{
|
|
// if we're using alternate credentials for the connection
|
|
string userDomain = String.Format("{0}\\{1}", cred.Domain, cred.UserName);
|
|
directoryObject.Username = userDomain;
|
|
directoryObject.Password = cred.Password;
|
|
|
|
// Removed credential validation check because it just caused problems and doesn't gain us anything (if invalid
|
|
// credentials are specified, the LDAP search will fail with "Logon failure: bad username or password" anyway)
|
|
|
|
//string contextTarget = "";
|
|
//if (!string.IsNullOrEmpty(domainController))
|
|
//{
|
|
// contextTarget = domainController;
|
|
//}
|
|
//else
|
|
//{
|
|
// contextTarget = cred.Domain;
|
|
//}
|
|
|
|
//using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, contextTarget))
|
|
//{
|
|
// if (!pc.ValidateCredentials(cred.UserName, cred.Password))
|
|
// {
|
|
// throw new Exception(String.Format("\r\n[X] Credentials supplied for '{0}' are invalid!", userDomain));
|
|
// }
|
|
// else
|
|
// {
|
|
// Console.WriteLine("[*] Using alternate creds : {0}", userDomain);
|
|
// }
|
|
//}
|
|
}
|
|
|
|
if(directoryObject != null)
|
|
{
|
|
directoryObject.AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.Sealing | AuthenticationTypes.Signing;
|
|
}
|
|
|
|
return directoryObject;
|
|
}
|
|
|
|
public static List<IDictionary<string, Object>> GetLdapQuery(System.Net.NetworkCredential cred, string OUName, string domainController, string domain, string filter, bool ldaps = false)
|
|
{
|
|
var ActiveDirectoryObjects = new List<IDictionary<string, Object>>();
|
|
if (String.IsNullOrEmpty(domainController))
|
|
{
|
|
domainController = Networking.GetDCName(domain); //if domain is null, this will try to find a DC in current user's domain
|
|
}
|
|
if (String.IsNullOrEmpty(domainController))
|
|
{
|
|
Console.WriteLine("[X] Unable to retrieve the domain information, try again with '/domain'.");
|
|
return null;
|
|
}
|
|
|
|
if (ldaps)
|
|
{
|
|
LdapConnection ldapConnection = null;
|
|
SearchResponse response = null;
|
|
List<SearchResultEntry> result = new List<SearchResultEntry>();
|
|
// perhaps make this dynamic?
|
|
int maxResultsToRequest = 1000;
|
|
|
|
try
|
|
{
|
|
var serverId = new LdapDirectoryIdentifier(domainController, 636);
|
|
ldapConnection = new LdapConnection(serverId, cred);
|
|
ldapConnection.SessionOptions.SecureSocketLayer = true;
|
|
ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };
|
|
ldapConnection.Bind();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (ex.InnerException != null)
|
|
{
|
|
Console.WriteLine("[X] Error binding to LDAP server: {0}", ex.InnerException.Message);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("[X] Error binding to LDAP server: {0}", ex.Message);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
if (String.IsNullOrEmpty(OUName))
|
|
{
|
|
OUName = String.Format("DC={0}", domain.Replace(".", ",DC="));
|
|
}
|
|
|
|
try
|
|
{
|
|
Console.WriteLine("[*] Searching path '{0}' for '{1}'", OUName, filter);
|
|
PageResultRequestControl pageRequestControl = new PageResultRequestControl(maxResultsToRequest);
|
|
PageResultResponseControl pageResponseControl;
|
|
SearchRequest request = new SearchRequest(OUName, filter, SearchScope.Subtree, null);
|
|
request.Controls.Add(pageRequestControl);
|
|
while (true)
|
|
{
|
|
response = (SearchResponse)ldapConnection.SendRequest(request);
|
|
foreach (SearchResultEntry entry in response.Entries)
|
|
{
|
|
result.Add(entry);
|
|
}
|
|
pageResponseControl = (PageResultResponseControl)response.Controls[0];
|
|
if (pageResponseControl.Cookie.Length == 0)
|
|
break;
|
|
pageRequestControl.Cookie = pageResponseControl.Cookie;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("[X] Error executing LDAP query: {0}", ex.Message);
|
|
}
|
|
|
|
if (response.ResultCode == ResultCode.Success)
|
|
{
|
|
ActiveDirectoryObjects = Helpers.GetADObjects(result);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DirectoryEntry directoryObject = null;
|
|
DirectorySearcher searcher = null;
|
|
try
|
|
{
|
|
directoryObject = Networking.GetLdapSearchRoot(cred, OUName, domainController, domain);
|
|
searcher = new DirectorySearcher(directoryObject);
|
|
// enable LDAP paged search to get all results, by pages of 1000 items
|
|
searcher.PageSize = 1000;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (ex.InnerException != null)
|
|
{
|
|
Console.WriteLine("[X] Error creating the domain searcher: {0}", ex.InnerException.Message);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("[X] Error creating the domain searcher: {0}", ex.Message);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// check to ensure that the bind worked correctly
|
|
try
|
|
{
|
|
string dirPath = directoryObject.Path;
|
|
if (String.IsNullOrEmpty(dirPath))
|
|
{
|
|
Console.WriteLine("[*] Searching the current domain for '{0}'", filter);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("[*] Searching path '{0}' for '{1}'", dirPath, filter);
|
|
}
|
|
}
|
|
catch (DirectoryServicesCOMException ex)
|
|
{
|
|
if (!String.IsNullOrEmpty(OUName))
|
|
{
|
|
Console.WriteLine("\r\n[X] Error validating the domain searcher for bind path \"{0}\" : {1}", OUName, ex.Message);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("\r\n[X] Error validating the domain searcher: {0}", ex.Message);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
searcher.Filter = filter;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("[X] Error settings the domain searcher filter: {0}", ex.InnerException.Message);
|
|
return null;
|
|
}
|
|
|
|
SearchResultCollection results = null;
|
|
|
|
try
|
|
{
|
|
results = searcher.FindAll();
|
|
|
|
if (results.Count == 0)
|
|
{
|
|
Console.WriteLine("[X] No results returned by LDAP!");
|
|
return null;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (ex.InnerException != null)
|
|
{
|
|
Console.WriteLine("[X] Error executing the domain searcher: {0}", ex.InnerException.Message);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("[X] Error executing the domain searcher: {0}", ex.Message);
|
|
}
|
|
return null;
|
|
}
|
|
ActiveDirectoryObjects = Helpers.GetADObjects(results);
|
|
}
|
|
|
|
return ActiveDirectoryObjects;
|
|
}
|
|
|
|
// implementation adapted from https://github.com/tevora-threat/SharpView
|
|
public static Dictionary<string, Dictionary<string, Object>> GetGptTmplContent(string path, string user = null, string password = null)
|
|
{
|
|
Dictionary<string, Dictionary<string, Object>> IniObject = new Dictionary<string, Dictionary<string, Object>>();
|
|
string sysvolPath = String.Format("\\\\{0}\\SYSVOL", (new System.Uri(path).Host));
|
|
|
|
int result = AddRemoteConnection(null, sysvolPath, user, password);
|
|
if (result != (int)Interop.SystemErrorCodes.ERROR_SUCCESS)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (System.IO.File.Exists(path))
|
|
{
|
|
var content = File.ReadAllLines(path);
|
|
var CommentCount = 0;
|
|
var Section = "";
|
|
foreach (var line in content)
|
|
{
|
|
if (Regex.IsMatch(line, @"^\[(.+)\]"))
|
|
{
|
|
Section = Regex.Split(line, @"^\[(.+)\]")[1].Trim();
|
|
Section = Regex.Replace(Section, @"\s+", "");
|
|
IniObject[Section] = new Dictionary<string, object>();
|
|
CommentCount = 0;
|
|
}
|
|
else if (Regex.IsMatch(line, @"^(;.*)$"))
|
|
{
|
|
var Value = Regex.Split(line, @"^(;.*)$")[1].Trim();
|
|
CommentCount = CommentCount + 1;
|
|
var Name = @"Comment" + CommentCount;
|
|
IniObject[Section][Name] = Value;
|
|
}
|
|
else if (Regex.IsMatch(line, @"(.+?)\s*=(.*)"))
|
|
{
|
|
var matches = Regex.Split(line, @"=");
|
|
var Name = Regex.Replace(matches[0].Trim(), @"\s+", "");
|
|
var Value = Regex.Replace(matches[1].Trim(), @"\s+", "");
|
|
// var Values = Value.Split(',').Select(x => x.Trim());
|
|
|
|
// if ($Values -isnot [System.Array]) { $Values = @($Values) }
|
|
|
|
IniObject[Section][Name] = Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
result = RemoveRemoteConnection(null, sysvolPath);
|
|
|
|
return IniObject;
|
|
}
|
|
|
|
public static int AddRemoteConnection(string host = null, string path = null, string user = null, string password = null)
|
|
{
|
|
var NetResourceInstance = Activator.CreateInstance(typeof(Interop.NetResource)) as Interop.NetResource;
|
|
List<string> paths = new List<string>();
|
|
int returnResult = 0;
|
|
|
|
if (host != null)
|
|
{
|
|
string targetComputerName = host.Trim('\\');
|
|
paths.Add(String.Format("\\\\{0}\\IPC$", targetComputerName));
|
|
}
|
|
else
|
|
{
|
|
paths.Add(path);
|
|
}
|
|
|
|
foreach (string targetPath in paths)
|
|
{
|
|
NetResourceInstance.RemoteName = targetPath;
|
|
NetResourceInstance.ResourceType = Interop.ResourceType.Disk;
|
|
|
|
NetResourceInstance.RemoteName = targetPath;
|
|
|
|
Console.WriteLine("[*] Attempting to mount: {0}", targetPath);
|
|
|
|
|
|
int result = Interop.WNetAddConnection2(NetResourceInstance, password, user, 4);
|
|
|
|
if (result == (int)Interop.SystemErrorCodes.ERROR_SUCCESS)
|
|
{
|
|
Console.WriteLine("[*] {0} successfully mounted", targetPath);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("[X] Error mounting {0} error code {1} ({2})", targetPath, (Interop.SystemErrorCodes)result, result);
|
|
returnResult = result;
|
|
}
|
|
}
|
|
return returnResult;
|
|
}
|
|
|
|
public static int RemoveRemoteConnection(string host = null, string path = null)
|
|
{
|
|
|
|
List<string> paths = new List<string>();
|
|
int returnResult = 0;
|
|
|
|
if (host != null)
|
|
{
|
|
string targetComputerName = host.Trim('\\');
|
|
paths.Add(String.Format("\\\\{0}\\IPC$", targetComputerName));
|
|
}
|
|
else
|
|
{
|
|
paths.Add(path);
|
|
}
|
|
|
|
foreach (string targetPath in paths)
|
|
{
|
|
Console.WriteLine("[*] Attempting to unmount: {0}", targetPath);
|
|
int result = Interop.WNetCancelConnection2(targetPath, 0, true);
|
|
|
|
if (result == 0)
|
|
{
|
|
Console.WriteLine("[*] {0} successfully unmounted", targetPath);
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("[X] Error unmounting {0}", targetPath);
|
|
returnResult = result;
|
|
}
|
|
}
|
|
return returnResult;
|
|
}
|
|
|
|
public static byte[] MakeProxyRequest(string proxyUrl, KDC_PROXY_MESSAGE message)
|
|
{
|
|
byte[] responseBytes = null;
|
|
|
|
byte[] messageBytes = message.Encode().Encode();
|
|
BinaryWriter bw = new BinaryWriter(new MemoryStream());
|
|
bw.Write(messageBytes);
|
|
byte[] data = ((MemoryStream)bw.BaseStream).ToArray();
|
|
|
|
// because we don't care if the server certificate can't be verified
|
|
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
|
|
|
|
try
|
|
{
|
|
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(proxyUrl);
|
|
request.Method = "POST";
|
|
request.ContentLength = data.Length;
|
|
request.ContentType = "application/kerberos";
|
|
request.UserAgent = "Rubeus/1.0";
|
|
|
|
BinaryWriter socketWriter = new BinaryWriter(request.GetRequestStream());
|
|
socketWriter.Write(data);
|
|
|
|
var response = (HttpWebResponse)request.GetResponse();
|
|
|
|
BinaryReader socketReader = new BinaryReader(response.GetResponseStream());
|
|
responseBytes = socketReader.ReadBytes((int)response.ContentLength);
|
|
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine("\r\n[!] Unhandled Rubeus exception:\r\n");
|
|
Console.WriteLine(e);
|
|
}
|
|
|
|
KDC_PROXY_MESSAGE responseMessage = new KDC_PROXY_MESSAGE(AsnElt.Decode(responseBytes));
|
|
|
|
BinaryReader br = new BinaryReader(new MemoryStream(responseMessage.kerb_message));
|
|
int recordMark = IPAddress.NetworkToHostOrder(br.ReadInt32());
|
|
int recordSize = recordMark & 0x7fffffff;
|
|
|
|
if ((recordMark & 0x80000000) > 0)
|
|
{
|
|
Console.WriteLine("[X] Unexpected reserved bit set on response record mark from KDC Proxy: {0}, aborting", proxyUrl);
|
|
return null;
|
|
}
|
|
|
|
return br.ReadBytes(recordSize);
|
|
}
|
|
|
|
public static bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|