Jump to content

Secure communication in C#


sud0nick

Recommended Posts

I've created a payload in C# that appears as a legitimate application but grants an attacker admin remote shell access on a windows system. My primary focus now it to encrypt the network traffic as best as I can for obvious reasons. I haven't done this before so I would like some guidance on how it should be done. I've done some research and come across two methods, AES using RSA to encrypt the key and SSL. I'm worried that the SSL method could easily be attacked with SSL-Strip since there is no HSTS-like implementation to prevent it. I know how to start with AES in C# as the System.Security.Cryptography namespace makes that fairly simple. However, I have no idea how to use RSA to encrypt the AES key and send it over the network. A lot of my research lead me to using AES-HMAC but some of the recent posts I've seen hint toward that only being used for encryption of local information rather than network information. Can someone shed some light on these methods, which is the most secure, and how to use it?

Link to comment
Share on other sites

This may or may not help. I remember there being some Visual BASIC 2010 tutorials that made use of system.security. But really I've only gotten as far as hashing and I've never coded a crypto application. There might be something promising on YouTube. I find some pretty decent tutorials and lectures there once in a while.

Cryptographic Services

https://msdn.microsoft.com/en-us/library/92f9ye3s%28v=vs.110%29.aspx

AES

https://msdn.microsoft.com/en-us/library/system.security.cryptography.aesmanaged%28v=vs.110%29.aspx

Link to comment
Share on other sites

I'd use TLS, much easier to implement, it also blends in with normal network traffic.

SSLStrip works by intercepting HTTP communications and downgrading links to HTTPS to HTTP, as your app will be initiating the connections then there is nothing to downgrade, you are your own HSTS as you hardcode the HTTPS. You just need to make sure you do proper certificate validation.

Link to comment
Share on other sites

In C# you create a socket between A and B, use it to create a NetworkStream and in turn use that to create an SSLStream. You tell the SSLStream to AuthenticateAsServer or AuthenticateAsClient and there are delegates that you should provide which will verify the opposing side as actually being who they are or aren't, and how you'd like to deal with that.

In one particularly scummy example I've created some code to do just this which basically has the server generate a self-signed cert (there's code on StackOverflow for this and it involves an unmanaged DLL - can't be done easily from within C#), the client connects to it and gets the cert and even though the hostname is wrong/missing and the cert is unknown to the client, it connects anyway and the communication from then on will be TLS 1.2 encrypted. The only downside is that the client has zero guarantees it's talking to the correct remote server so MITM is still very possible. The upside is that to enable 'secure communications' like this you don't have to configure anything or buy and store certs and keys (and handle the associated passwords) or what have you.

Link to comment
Share on other sites

Thanks for all of the suggestions. I think I'm going to try and implement a TLS solution as I found more posts online today to support that choice over any other. @Cooper, thanks for breaking that down for me. I've been using lower level sockets instead of those higher level classes. I'm now working on replacing my socket code with the TcpClient, TcpListener, and NetworkStream classes. From there I think I can follow some of the steps from this article to implement TLS. Once I get everything working I will post my solutions here. The goal is to make this work with a Python server (the one I recently implemented with Portal Auth) so I can have secure communications between the Pineapple and my payloads.

Link to comment
Share on other sites

So, I'm not too familiar with TLS other than knowing its purpose is to keep stuff secure. Would I be correct in saying that the certificates used with TLS are only for authentication and could be replaced with a password? My problem is I don't want to include a certificate in the payload (unless if there is some way to bundle it with the .exe) and I think I should only need to verify the attacker from the target so I'm the only one allowed to connect to the target. Since I know who the target is already I shouldn't have to check their certificate. So, if I were to go the route of using a password instead of certificates would the data still be encrypted? Are there any downsides to this option with its specific purpose?

Link to comment
Share on other sites

TLS can be used for authentication and encryption. By default, the server prooves their identity to the client by presenting the certificate, assuming the client does a proper check of the certificate it can then be sure that the server is who it says it is. The data from that cert is then used to generate a key to encrypt traffic.

If you want the client to authenticate themselves to the server as well you need a client side certificate which the client presents during the initial set up. Again, the server should do proper certificate checking to ensure it is valid.

I don't know about c# but in most languages I've used you can bake the certificates into the application so on the client side you'd include the client certificate and you could also include a copy of the server's public CA cert (if you are using self-signed certs). That way the client has all it needs to authenticate and to veryify the server.

You ask about using a password, that would all depend on what you do with it, if the client just checks the password is the one it expects then it only does authentication, if you then use it as a key to encrypt traffic then it does encryption as well. That isn't a good way to do things as setting it up correctly isn't easy.

Link to comment
Share on other sites

TLS is just a fancy name that says "Do PKI with one of $CIPHERS[], one of $HASHES[] and one of $KEY_EXCHANGE_ALGORITHM[]" and each successive version changes the arrays by adding new ones that are deemed sufficiently secure and removing those that aren't anymore. It's a bit of a sliding scale which in this case is a good thing.

You need the certificate to verify it's the actual remote server you're talking to. The way to do it with a password is mostly manually and I'd employ the same method WPA2 does. Each side sends the other a nonce (=big-ass random) and each side hashes the nonce with the password hash and sends that back. You verify that the value you got back is valid, which proves the other side knows the password hash. One side can now encrypt a session key with the password hash, send that across to the other side who decrypts that and you now have a session key on both sides that should've been safe from prying eyes. Use that to encrypt any data sent across the line between the both of you.

You'll probably end up wrapping your socket/tcpclient (and I would suggest you wrap a NetworkStream over a Socket much like SSLStream does) such that the initial setup and subsequent encrypting/decrypting is transparent to the code that wants to do the actual communicating.

Link to comment
Share on other sites

You'll probably end up wrapping your socket/tcpclient (and I would suggest you wrap a NetworkStream over a Socket much like SSLStream does) such that the initial setup and subsequent encrypting/decrypting is transparent to the code that wants to do the actual communicating.

This is what I'm doing in C#. On the Python side I'm using wrap_socket() but still trying to work out some issues. I'm trying to force TLS 1.2 and ran into some trouble testing last night with a Win7 VM as the target. Apparently Win7 by default doesn't support TLS 1.2 but Win8 does. I may just have to create a separate payload for Win7 systems to use TLS 1.0.

If you want the client to authenticate themselves to the server as well you need a client side certificate which the client presents during the initial set up. Again, the server should do proper certificate checking to ensure it is valid.

The weird thing about my setup is the client and server swap after initial communication. The target calls back to the Pineapple with system information then sets up a listener on itself. I'm thinking it's not so important to provide a certificate from the client for this part. It could even ignore the cert because it just connects back to a listener on the Pineapple to tell it which port it's going to listen on. As long as the server provides a cert the connection should still be encrypted, right?

I don't know about c# but in most languages I've used you can bake the certificates into the application so on the client side you'd include the client certificate and you could also include a copy of the server's public CA cert (if you are using self-signed certs). That way the client has all it needs to authenticate and to veryify the server.

This would be awesome. I hope I can do this in C#.

Edit: I found this question on Stack Overflow that may help in embedding the certificate as a resource in the executable.

You ask about using a password, that would all depend on what you do with it, if the client just checks the password is the one it expects then it only does authentication, if you then use it as a key to encrypt traffic then it does encryption as well. That isn't a good way to do things as setting it up correctly isn't easy.

I think I will add a password for additional security. Is it even possible for someone to capture a certificate over the network then use it to connect to my target? I'm trying to provide as much security as possible to ensure I'm the only one connecting to my target and all communication is encrypted. Is it overboard to add a password?

Edited by sud0nick
Link to comment
Share on other sites

Alright I've got it working! Please let me know if there are any holes in the way I've implemented TLS.

I used OpenSSL to create two sets of certificates, one for the client and one for the server. I was able to embed the .pfx into the payload executable so when it starts it is loaded from within itself and opened with its password. It then begins listening for clients.

My python script has a copy of the payload cert plus its own private and public keys. I use the following method in my script to connect to the target and grab the cert.

tlsck = wrap_socket(sck, ssl_version=PROTOCOL_TLSv1_2, keyfile="attacker.pem", certfile="attacker.cer", cert_reqs=CERT_REQUIRED, ca_certs="payload.cer")
try:
    tlsck.connect((rhost,rport))

    # Fetch the target's certificate to verify their identity
    cert = tlsck.getpeercert()
    if not cert['serialNumber'] == "payload_cert_serial_number":
        print "[!] Serial number of payload certificate does not match"
        print "[!] Exiting..."
        sys.exit()

except error as sockerr:
    print sockerr
    sys.exit()

This should execute Python's built in certificate verification method then check the serial number of the peer certificate which I have hard-coded here. From my understanding the serial number should never change and therefore if someone were to recreate a certificate with the exact same information the connection would still fail.

On the payload side I've modified the certificate validation method that was implemented in a link I posted previously.

var sslStream = new SslStream(client.GetStream(), false, atkCertValidation);
sslStream.AuthenticateAsServer(payloadcert, true, SslProtocols.Tls12, false);

...

private static bool atkCertValidation(Object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
    if (BitConverter.ToString(cert.GetSerialNumber()) != "hex_format_serial_number" || cert.GetCertHashString() != "thumbprint") { return false; }
    if (sslPolicyErrors == SslPolicyErrors.None) { return true; }
    if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { return true; }
    return false;
}

The initial version of this method did not include the serial number and thumbprint checks. Going off of my last note if someone were to regenerate my attacker certificates they still would not be able to connect to the target.

At this point the connection is established. I've reviewed it in Wireshark and only saw the initial certificate pass was unencrypted (as expected) and after that everything was random garbage. Next I plan to implement a password upon connection. This way a certificate is required to connect but an additional password is required to execute commands.

Link to comment
Share on other sites

Not got time to go over the code but I'd say the password is redundant. If someone manages to acquire the client side cert required to connect then they are going to be able to get the password as well.

Link to comment
Share on other sites

The C# side looks decent enough. My cert validation code was simply "return true" so... yeah. :smile:

This side at least will reject connecting to anything that isn't TLS 1.2. I'm insufficiently familiar with Python to say anything about that but if it connects it must talk at least TLS 1.2 to the C# side so at the very least it's compatible with TLS 1.2.

Link to comment
Share on other sites

Not got time to go over the code but I'd say the password is redundant. If someone manages to acquire the client side cert required to connect then they are going to be able to get the password as well.

I think the only way they would be able to get the password at that point is by sniffing it out on the network. I think you're right, though, it does seem redundant.

The C# side looks decent enough. My cert validation code was simply "return true" so... yeah. :smile:

This side at least will reject connecting to anything that isn't TLS 1.2. I'm insufficiently familiar with Python to say anything about that but if it connects it must talk at least TLS 1.2 to the C# side so at the very least it's compatible with TLS 1.2.

lol. It's working just fine. I've run tests to ensure connections would be rejected under proper circumstances so I feel comfortable with it.

Thanks for the help everyone.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...