Python decrypt TLS traffic - python

I'm trying to decode SIP TLS v1.0 traffic which uses a known port (TCP 5061).
I do have access to my private key to extract the information (TCP raw data)
I have created my code to access TCP traffic and I can read that info right now.
packet = socket.recv(sipLocatorConfig.NETWORK_TCP_MAX_SIZE)
My goal is to be able to read encrypted traffic (which I can already) and decrypt it with my private key so I can analyze it after that.
How to convert TLS to TCP/raw data? I was able to start SSL Server, but how to parse raw data using SSL library.
import socket
from OpenSSL import SSL
context = SSL.Context(SSL.SSLv23_METHOD)
context.use_privatekey_file('key')
context.use_certificate_file('cert')
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s = SSL.Connection(context, s)
s.bind(('', 12345))
s.listen(5)
(connection, address) = s.accept()
while True:
print repr(connection.recv(65535))

Writing a python script to decrypt the raw capture is a huge task. I suggest you give wireshark a try, it is a graphical network analyzer that can already decrypt SSL / TLS when you have the key.
Keep in Mind: Perfect forward secrecy can prevent decryption in both wireshark and scripts. See Decrypting HTTPS traffic in Wireshark not working

Related

Received data from python SSL server is incorrect

I am trying to modify a socket server I wrote with the python socket library to use encryption using python's SSL library.
I am no able to successfully open a connection to the server, wrap it with an SSL context and send data to the server, but data sent back to the client is not what it should be.
My suspicion is that the server responses are not being decrypted on the client side, but I don't know why. I'm pretty new to SSL/TLS, and networking in general so... what am I missing?
The client is also written in python (for now, to facilitate testing)
Code:
Relevant Server stuff:
def sslServerLoop():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(5)
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain('cert.pem')
while True:
conn, addr = s.accept()
sslConn = context.wrap_socket(conn, server_side=True)
data = sslConn.recv(1024)
sslConn.sendall(response)
sslConn.close()
Relevant Client stuff:
context = ssl.create_default_context(cafile='cert.pem')
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s = context.wrap_socket(s, server_hostname=server_addr)
s.connect((address, port))
s.sendall(msg)
s.shutdown(socket.SHUT_WR)
response = s.recv(1024)
Sending from client to server works fine, but data sent back to the client is wrong. For example if I set response = bytes([1]) on the server side, I receive b'\x17\x03\x03\x00\x19\xac\xb6\x7f#\xc0\xd3\xce%\x13G\x01\xbd\x88y\xf0\xda..\x02\xf9\xe4o\xdd\x1a\xdb' on the client side. Most of that changes every time I try to run it, but the first 5 bytes are always the same (which is partly why I suspect it isn't being decrypted).
cert.pem is a self signed certificate generated using openssl as described in the python 3 SSL module documentation
It is not legal to shutdown a socket that is being used for SSL. It is a protocol violation. You must close via the SSL/TLS API you are using.

Why can't I connect to this websocket?

Having great difficulty getting a response, even a reassuring error response, after attempts to connect to Coinfloor's websocket API. Docs here: https://github.com/coinfloor/API/blob/master/WEBSOCKET-README.md
'Commands, replies, and notifications traverse the WebSocket in text
frames with JSON-formatted payloads.'
Here is my attempt:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server = 'api.coinfloor.co.uk'
port = 443
server_ip = socket.gethostbyname('api.coinfloor.co.uk')
payload = '{"method": "WatchTicker","base": int("0xF800", 16),"counter":int("0xFA20",16),"watch":True}'
s.connect((server_ip, port))
s.sendall(payload.encode('utf-8'))
result = s.recv(4096)
print(result)
It just returns this:
b''
i.e. an empty byte string.
Because sockets and WebSocket are completely different things. AF_INET/SOCK_STREAM socket is a facility that uses TCP to communicate to the remote peer. On the other hand, WebSocket is a binary protocol that
Works on the top of TCP or TLS.
Has to perform HTTP handshake before data exchange.
Since WebSocket is a rather complex protocol (see the standard), your best course of action is to find a WebSocket library and use it instead of trying to implement the protocol starting from TCP.

Unable to process mysql login using raw packet on tcp socket established through python? Probably due to salt?

I am trying simulate mysql connection process through python program.
In python script, I am opening a tcp socket to mysql server and writing pre-captured on socket.
On login packet I get an error "#28000Access denied for user 'root'#'10.x.x.xxx' (using password: YES)"
import socket
import sys
import time
Host = '10.x.x.xxx'
Port = '3306'
t_con = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clust_vip = (Host, int(Port))
try:
t_con.connect(clust_vip)
print ('Socket connection established')
print "TCP connection established:", t_con.recv(4096)
byte1 = open("req_r1").read()
t_con.send(byte1)
print "Response for packet1:", t_con.recv(4096)
bytes2 = open("req_r2").read()
t_con.send(byte2)
print "Response for packet2:", t_con.recv(4096)
finally:
t_con.close()
"req_r1" and "req_r2" file used above contains raw packets (mysql protocol raw packets and not entire frame/tcp layer)
I am replaying the capture through socket
I have skipped the TCP connection packet (as I am establishing the socket connection through python)
I am trying to write raw packet (mysql protocol packet) and not entire frame on the socket.
Can anyone guide me how I can overcome this issue. I think error is due to salt used to establish the mysql connection.
I have tried Passwordless connection as well however it didn't worked.
Update: What I understand is on establishing tcp socket connection, db server replies with salt and I need to reuse this salt to generate encrypted password and use it in next connect packet.
If anyone has idea if I am on right track and how i can extract/reuse it it would be great help.
You can't log in by replaying a previous session. As has been pointed out in comments, that would be terribly insecure. It's a challenge/response mechanism, and your response varies with the challenge received.
See https://dev.mysql.com/doc/internals/en/client-server-protocol.html for a breakdown of the protocol.

how to do tls renegotiation by python ssl socket

I need to simulate a tls renegotiation behaviour (I understand this as a new handshake) by python. Is that possible?
I tried below codes, the first do_handshake works but the second one do nothing.
import socket, ssl, pprint, re, time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_sock = ssl.wrap_socket(s,ca_certs="cacert.pem",do_handshake_on_connect=False)
ssl_sock.connect(('172.18.7.162', 443))
time.sleep(3)
ssl_sock.do_handshake()
print repr(ssl_sock.getpeername())
print ssl_sock.cipher()
print pprint.pformat(ssl_sock.getpeercert())
send_content="aaaa"
ssl_sock.write(send_content)
time.sleep(2)
print "do_handshake_again"
ssl_sock.do_handshake()
print "do_handshake_again done"
ssl_sock.write(send_content)
Thanks for helping!
To answer my own question:
Finally I implement this behaviour by using python openssl lib.
from OpenSSL import SSL
import sys, os, select, socket
........
# Initialize context
ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.set_options(SSL.OP_NO_SSLv2)
#ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb) # Demand a certificate
ctx.use_privatekey_file (os.path.join(dir, 'server.pkey'))
ctx.use_certificate_file(os.path.join(dir, 'server.cert'))
ctx.load_verify_locations(os.path.join(dir, 'CA.cert'))
# Set up server
server = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
server.bind(('', int(sys.argv[1])))
server.listen(3)
server.setblocking(0)
........
for cli in w:
try:
ret = cli.send(writers[cli])
cli.renegotiate()
cli.do_handshake()
ret = cli.send(writers[cli])
......
The important thing is the last 4 lines:
1, sending something with the socket
2-3, trigger renegotiate and do handshake
4, sending something again
Because it's non-blocking socket, I can see this code send out two packets: the first packet will only send application data(content type 23), the second packet will have two payloads: one is ssl handshake(type 22) and another one is application data(type 23).
By the way, this is trying to simulate re-negotiate packet has application data in same packet. If for pure tls re-negotiate, we can use openssl to send "R" to trigger a pure tls renegotiation behaviour.

Python sends malformed UDP Packets

I am having trouble receiving UDP packets on an Android device, so I want to find out if I am sending them properly. Using Wireshark, everytime I try to send a UDP packet to a remote address, the following error message occurs:
232646 311.898009000 172.56.16.78 192.168.0.3 UDP 64 Source port: 31947 Destination port: 5001 [ETHERNET FRAME CHECK SEQUENCE INCORRECT]
Frame check sequence: 0xf5b6d06d [incorrect, should be 0xb0c869e3]
Does anyone know how to fix this? Would this be the cause of why I could not receive UDP packets on my Android device?
Server Code:
import http.server
import socket
import threading
import socketserver
class ThreadedUDPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request[0].strip().decode("utf-8")
print("{} Recieved: ".format(self.client_address) + data)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
response = data.upper()
sock.sendto(bytes(response, "utf-8"), self.client_address)
print("{} Sent: {}".format(self.client_address,response))
if __name__ == "__main__":
udpserver = ThreadedUDPServer((HOST,PORT+1), ThreadedUDPRequestHandler)
udp_thread = threading.Thread(target=udpserver.serve_forever)
udp_thread.daemon = True
udp_thread.start()
print("UDP serving at port", PORT+1)
while True:
pass
udpserver.shutdown()
It seems like you're sending packets using regular userspace sockets. In that case, there's very little chance that the packets are being sent malformed since the FCS is generated physically by the network interface card.
What you're probably seeing is an FCS error due to completely different reasons, which can be safely disregarded.
I'd look for other reasons for why the other device doesn't receive the packet, like firewalls or NAT. Start by using netcat or a similar tool for sending and receiving the UDP packets between the two machines.

Categories

Resources