Pages

Monday, August 1, 2016

PoweShell: Encrypt TCP Client-Server Traffic with a self-signed X509 Certificate

Following my last PowerShell post: Generate self-signed X509 Certificates, this time I will show you how to use the customized self-signed certificate to encrypt your traffic in a client-server infrastructure. This is really important in order to maintain the confidentiality of your communications. Either if you are conducting a pen-test or an IR engagement, you will want to encrypt your traffic at all times. 

As usual, I will start with some requirements for this program and some definitions in order to make things easier for you guys to understand. Furthermore, I will be providing as many details as I can and a few references for those interested on reading more about this topic. Also, I will provide a quick overview of how I built a TCP Client and Server from my post TCP Client-Server with .NET Classes (not a line-by-line explanation of the scripts). This will make it easier for you to understand how the SSL portion gets integrated with the scripts.



Requirements:


  • At least Windows 7
  • At least PowerShell V2
  • PowerShell ISE
  • Basic understanding of the Public Key Infrastructure (PKI)
  • Basic understanding of TCP Client-Server communications and .NET classes. I recommend to read these first two posts:



SslStream .NET Class


Provides a stream used for client-server communication that uses the Secure Socket Layer (SSL) security protocol to authenticate the server and optionally the client. This stream will be used to send and receive data. This class is part of the System.Net.Security namespace.




Constructor Description
SslStream(Stream, Boolean, RemoteCertificateValidationCallBack)   Initializes a new instance of the SslStream class using the specified Stream, stream closure behavior, and certificate validation delegate.



Method
Description
AuthenticateAsServer(X509Certificate, Boolean, SslProcotols, Boolean) Called by Servers to authenticate the server and optionally the client in a client-server connection using the specified certificates, requirements and security protocols.
AuthenticateAsClient(String) Called by clients to authenticate the server and optionally the client in a client-server connection.



Properties Description
IsSigned  Gets a Boolean value that indicates whether the data sent using the stream is signed.
IsEncryptedGets a Boolean value that indicates whether this SslStream uses data encryption. (Verifies if the data is being encrypted)



SSL Authentication - handshake


  • Client sends a ClientHello message to the server 
  • Server responds with a ServerHello message defining the SSL options
  • Server sends a Certificate message with its own certificate (Public Key)
  • Server finishes its part of the negotiation with a ServerHelloDone message
  • Client sends a ClientKeyExchange message which contains information of the session key encrypted with the server's public key.
  • Client sends ChangeCipherSpec message to the server to let it know that it will start using the new session keys for hashing and encrypting messages.
  • Client sends a ClientFinished message to let the server check the newly activated options
  • Server receives the ChangedCipherSpec message and switches its record layer security state to symmetric encryption using the session keys.
  • Server sends ServerFinished to the client
  • All messages sent from the client to the server and vice-versa will be encrypted using the session key.



TCP Client-Server Overview


ServerClient


  • Start the listener on the specific port.
  • Start accepting connection request.
  • Connection request is accepted and TCP Client .NET Object is created to hangle the remote communication.
  • Network Stream is obtained from the TCP client object and is used to send results and receive data.
  • While loop is created to send and receive commands.
  • If connection is interrupted of terminated, the loop finishes and the server shutdown gracefully.



  • Connect to the server on the specific port where it is listening on.
  • Connection is accepted
  • Network Stream is obtained from the TCP Object client initialized at the beginning to sent the connection request.
  • While loop is created to send commands and receive server responses.
  • If connection is interrupted or terminated, the loop finishes and the client shutdown gracefully. 





TCP Client-Server + SSL Overview


ServerClient


  • Start the listener on the specific port.
  • Start accepting connection request.
  • Connection request is accepted and TCP Client .NET Object is created to hangle the remote communication.
  • Network Stream is obtained from the TCP client object and is used to send results and receive data.
  • SSL Stream object is initialized from the current Network Stream.
  • the X509 Certificate is imported to the server. (From base64 to X509 Format) 
  • Server authenticates as a server defining the X509 Certificate & preferred Certificate requirements
  • While loop is created to send and receive commands.
  • If connection is interrupted of terminated, the loop finishes and the server shutdown gracefully.



  • Connect to the server on the specific port where it is listening on.
  • Connection is accepted
  • Network Stream is obtained from the TCP Object client initialized at the beginning to sent the connection request.
  • SSL Stream object is initialized from the current Network Stream.
  • Client authenticates to the server by calling for the name of the server (Name on the Server's Certificate )
  • While loop is created to send commands and receive server responses.
  • If connection is interrupted or terminated, the loop finishes and the client shutdown gracefully. 








Adding SSL functionalities to the TCP Server

1
2
3
4
5
6
7
8
9
    $SslStream = New-Object System.Net.Security.SslStream($TcpNetworkStream, $false)
       
    $Base64Cert = 'MIIKNQIBAzCCCfEGCSqGSIb3DQEHAaCCCeIEggneMII...'

    $SslFakeCert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2([System.Convert]::FromBase64String($Base64Cert),'')  
    $SslStream.AuthenticateAsServer($SslFakeCert, $false, [System.Security.Authentication.SslProtocols]::tls12, $false)
   
    Write-Verbose "[**] SSLStream Encrypted: $($SslStream.IsEncrypted)"
    Write-Verbose "[**] SSLStream Signed: $($SslStream.IsSigned)"

  • First of all, these lines of code go in between Line#3 & Line #5 of the Second Code Snippet in the Simple TCP Server code section ( PowerShell Post: TCP Client-Server with .NET Classes)
  • Line #1: Initializes a new instance of the SslStream class using the specified network stream and stream closure behavior. Parameters:
    • InnerStream: A Stream Object used by the SslStream for sending and receiving data. In this case it will be the $TCPNetworkStream holding the Network Stream of the $TCPClient Object.
    • LeaveInnerStreamOpen: A Boolean value that indicates the closure behavior of the Stream object used by the SslStream for sending and receiving data. This parameter indicates if the inner stream is left open.
  • Line #3: Defines the variable $Base64Cert which will hold the contents of the X509 Certificate (This is the content of the file that was generated by the Function New-X509 Certificate in my recent PowerShell Post: Generate self-signed X509 Certificates). The content is already base64 encoded.
  • Line #5: Uses the X509Certificate2 Constructor from the X509Certificate2 Class in order to initialize a new instance of the X509Certificate2 Class with the specified X509 Certificate (In this case, it will be the variable $Base64Cert which holds the content of the certificate). As you can see, it first converts the Base64 content to a byte array before using the constructor.
  • Line #6: Uses the method AuthenticateAsServer() from the SslStream Class to authenticate the server. Parameters:
    • Server Certificate: The X509 Certificate used to authenticate the server ($SslFakeCert).
    • ClientCertificateRequired: A Boolean value ($True or $False) that specifies whether the client is asked for a certificate for authentication. Note that this is only a request. If no certificate is provided, the server still accepts the connection request. 
    • EnabledSslProcotols: The SslProtocols value that represents the protocol used for authentication. Make sure you set this one to TLS12 to avoid errors caused by the recent MS16-065 TLS/SSL Protocol Update. 
    • CheckCertificateRevocation: A Boolean value that specifies whether the certificate revocation list is checked during authentication.
  • Line #8: Uses property IsEncrypted from the SslStream Class to indicate whether this SslStream uses data encryption. (Verifies if the data is being encrypted)
  • Line #9: Uses property IsSigned from the SslStream Class to indicate whether the data sent using the stream is signed.
Make sure you replace $TCPNetworkStream with $SslStream after Line #9 on the rest of the code.




Adding SSL functionalities to the TCP  Client

1
2
3
4
5
    $SslStream = New-object System.Net.Security.SslStream ($TcpNetworkStream, $false, { param($Sender, $Cert, $Chain, $Policy) return $true})
    
    $SslStream.AuthenticateAsClient("Wardog",$null,[System.Security.Authentication.SslProtocols]::Tls12, $null)
    Write-Verbose "[**] SSLStream Encrypted: $($SslStream.IsEncrypted)"
    Write-Verbose "[**] SSLStream Signed: $($SslStream.IsSigned)"


  • First of all, these lines of code go right before the while loop in the Simple TCP Client code section ( PowerShell Post: TCP Client-Server with .NET Classes)
  • Line #1: Initializes a new instance of the SslStream class using the specified network stream, stream closure behavior and the certificate validation delegate.
    • InnerStream: A Stream Object used by the SslStream for sending and receiving data. In this case it will be the $TCPNetworkStream holding the Network Stream of the $TCPClient Object.
    • LeaveInnerStreamOpen: A Boolean value that indicates the closure behavior of the Stream object used by the SslStream for sending and receiving data. This parameter indicates if the inner stream is left open.
    • UserCertificateValidationCallBack: A RemoteCertificateValidationCallBack delegate responsible for validating the certificate by the remote party. It bypasses this validation by defining fake parameters (Sender, Cert, Chain and Policy) and returning $True.
  • Line #3: It uses the method AuthenticateAsClient()  from the SslStream Class to authenticate and reach the server. It uses the name on the Server's Certificate to call for it (same as when you browse the Internet. and call for google.com)
    • TargetHost: The name of the server that shares this SslStream.
    • ClientCertificates: The X509CertificateCollection that contains client certificates. In this case just leave it $null to by pass that parameter.
    • EnabledSslProtocols: The SslProtocols value that represents the protocol used for authentication. Make sure you set this one to TLS12 to avoid errors caused by the recent MS16-065 TLS/SSL Protocol Update. 
    • CheckCertificateRevocation: A Boolean value that specifies whether the certificate revocation list is checked during authentication. Since we are using a fake certificate just set it to $false or $null. 
    • The reason why we set all those parameters for the client is to avoid errors/exceptions such as "A Call to SSPI Failed".
  • Line #8: Uses property IsEncrypted from the SslStream Class to indicate whether this SslStream uses data encryption. (Verifies if the data is being encrypted)
  • Line #9: Uses property IsSigned from the SslStream Class to indicate whether the data sent using the stream is signed.
Make sure you replace $TCPNetworkStream with $SslStream after Line #9 on the rest of the code.




Testing Encryption Capabilities 


  • Test was run on two Windows 10 Computers
  • Computers were up to date and had the MS16-065 TLS/SSL Protocol Update installed
  • Make sure you have your WireShark set up to look for TLS on whatever port you are using. Check this config:



Figure 1. Wireshark Config





Figure 2. Successful Test!




Figure 3: Packet capture


I hope this post was helpful for those that did not know how to apply encryption to a TCP Client-Server communication. Remember you can merge the two scripts and set switches to run it either as a client or server. I just wanted to show you how each script works separate to make it easier to understand. I will be adding more capabilities to these scripts so stay tuned.


Feedback is always appreciated !


References


https://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.110).aspx - SslStream Class
https://support.microsoft.com/en-us/kb/3155464 - MS16-065 TLS/SSL Protocol Update

No comments:

Post a Comment