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.
Related
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.
I'm trying to establish a secure socket connection in Python, and i'm having a hard time with the SSL bit of it. I've found some code examples of how to establish a connection with SSL, but they all involve key files. The server i'm trying to connect with doesn't need to receive any keys or certificates. My question is how do I essentially wrap a python socket connection with SSL. I know for a fact that the cipher i'm suppose to use is ADH-AES256-SHA, and the protocol is TLSv1. This is what i've been trying:
import socket
import ssl
# SET VARIABLES
packet, reply = "<packet>SOME_DATA</packet>", ""
HOST, PORT = 'XX.XX.XX.XX', 4434
# CREATE SOCKET
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(10)
# WRAP SOCKET ???
ssl.wrap_socket(sock, ssl_version="TLSv1", ciphers="ADH-AES256-SHA")
# CONNECT AND PRINT REPLY
sock.connect((HOST, PORT))
sock.send(packet)
print sock.recv(1280)
# CLOSE SOCKET CONNECTION
sock.close()
When I run this code, I don't get any errors, but I get a blank response. When trying to debug this code in the command line, by typing in python in the terminal and pasting in code line by line, I get what i'm assuming is a status code when running sock.send(packet). The integer response I get is 26. If anyone knows what this means, or can help in anyway it would be greatly appreciated.
Ok, I figured out what was wrong. It was kind of foolish of me. I had two problems with my code. My first mistake was when specifying the ssl_version I put in TLSv1 when it should have been ssl.PROTOCOL_TLSv1. The second mistake was that I wasn't referencing the wrapped socket, instead I was calling the original socket that I have created. The below code seemed to work for me.
import socket
import ssl
# SET VARIABLES
packet, reply = "<packet>SOME_DATA</packet>", ""
HOST, PORT = 'XX.XX.XX.XX', 4434
# CREATE SOCKET
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(10)
# WRAP SOCKET
wrappedSocket = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1, ciphers="ADH-AES256-SHA")
# CONNECT AND PRINT REPLY
wrappedSocket.connect((HOST, PORT))
wrappedSocket.send(packet)
print wrappedSocket.recv(1280)
# CLOSE SOCKET CONNECTION
wrappedSocket.close()
Hope this can help somebody!
You shouldn't be setting PROTOCOL_TLSv1 (or TLSv1). This restricts the connection to TLS v1.0 only. Instead you want PROTOCOL_TLS (or the deprecated PROTOCOL_SSLv23) that supports all versions supported by the library.
You're using an anonymous cipher, because for some reason you think you don't need a certificate or key. This means that there is no authentication of the server and that you're vulnerable to a man in the middle attack. Unless you really know what you're doing, I suggest you don't use anonymous ciphers (like ADH-AES256-SHA).
I was looking for a good working ssl socket that starts the connection with a https package. This helped me a lot but is a little outdated, so here is the code for python3:
import socket
import ssl
package = "GET /ws/LiveWebcastUpdate/22000557 HTTP/1.1\r\nHost:
www.website_name.com\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64;
rv:80.0) Gecko/20100101 Firefox/80.0\r\nAccept: */*\r\nAccept-Language: nl,en-
US;q=0.7,en;q=0.3\r\nSec-WebSocket-Version: 13\r\nOrigin:
https://www.website_name.com\r\nSec-WebSocket-Key:
NU/EsJMICjSociJ751l0Xw==\r\nConnection: keep-alive, Upgrade\r\nPragma: no-
cache\r\nCache-Control: no-cache\r\nUpgrade: websocket\r\n\r\n"
hostname = 'www.website_name.com'
port = 443
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
print(ssock.version())
ssock.send(package.encode())
while True:
data = ssock.recv(2048)
if ( len(data) < 1 ) :
break
print(data)
This is as simple as possible, for more information visit
https://docs.python.org/3/library/ssl.html
There is a lot of fun to be had solving these problems but for me, I found that the underlying infrastructure for python ssl is openssl. Try validating your certificates with openssl and do this before you try to get python to use that same stack.
I needed to import a root certificate into openssl before I could validate the leaf certificate.
This was helpful.
http://gagravarr.org/writing/openssl-certs/others.shtml#ca-openssl
Another interesting thing was that two different build of the same version of python on different hosts had different methods. One had ssl.get_default_verify_paths() and the other didn't had any at all. The lesson here is that python ssl is built on openssl. Different underlying libraries give you a different python.
Python SSL is built on openssl so solve certificate issues in openssl first.
I was trying to create a python socket server that could send and receive data, so I created a socket on the server using the code here:
import socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(('', 1208))
serversocket.listen(5)
(client,(ip,port)) = serversocket.accept()
Then I tried to create a sample connection from my machine by going to command prompt and typing
telnet www.filesendr.com 1208
However, the console simply replies with "Could not open connection to the host, on port 1208...Connection failed." I went back over my code but couldn't identify the problem. Any help would be greatly appreciated.
I think part of the problem is that after you accept the connection you don't do anything else. Once the accept happens, you get to the end of the script, python exits and closes all open file handles (including the socket you just opened). If you want to be able to talk to yourself through telnet, try something like this:
import socket
import select
import sys
port = 1208
listener = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
listener.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
listener.bind(('',port))
listener.listen(128)
newSock, addr = listener.accept()
while True:
r,w,e = select.select([newSock,sys.stdin],[],[])
if newSock in r:
data = newSock.recv(4096)
sys.stdout.write(data)
if sys.stdin in r:
newSock.send(sys.stdin.readline())
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
I'm trying to make a transparent proxy in python using the socket module. but for some reason it hangs on connect()ing the socket. here is the code i'm using:
from __future__ import division
import socket
import struct
#import mcpackets
import sys
import time
#CUSTOM SETTINGS
HOST="192.168.178.28"
PORT=25565
#END CUSTOM SETTINGS
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(('',25565))
serversocket.listen(1)
print "waiting for client, press multiplayer and use 'localhost' as server"
clientsocket,address=serversocket.accept()
print "client connected from %s:%d"%address
serversocket.close()
print "connecting to '%s:%d'"%(HOST,PORT)
serversocket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "socket created."
serversocket.connect((HOST,PORT))#------------------------------ freezes here
print "socket connected."
serversocket.settimeout(0)
clientsocket.settimeout(0)
print "timeouts set."
print "now proxying."
#tdata=[]
try:
while(True):
dat=None
try:
dat=clientsocket.recv(4096)
except socket.timeout:
pass
if(dat!=None):
try:
serversocket.send(dat)
except socket.timeout:
pass
#vice versa
dat=None
try:
dat=serversocket.recv(4096)
except socket.timeout:
pass
if(dat!=None):
try:
clientsocket.send(dat)
except socket.timeout:
pass
except:
clientsocket.close()
#with open("data.log","w") as fid:
# fid.write(''.join(tdata))
raise
the problem doesn't lie in the network as connecting to the server directly works fine. any ideas on what's going wrong?
This is a part of TCP sockets implementation where the operating system refuses to allow a new socket connection after a socket with the same name has been disconnected recently.
In order to force this request, set the REUSEADDR socket option on your socket, before connecting it (for both of your server socket creations):
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
This way after you close your first server socket, when you want to connect the new server socket (with the same host, port), OS would not refuse.
I'm having difficulty reproducing this as it doesn't appear to hang on Mac OS X or Windows 7 with Python 2.7. So without being able to reproduce I'm guessing there's a problem with reusing serversocket so soon after closing it on your OS. Closing a socket puts that socket into the TIME_WAIT state so it's not closed immediately. How long it takes to really close the socket is dependent on the OS and may be what's causing your problem.
Although people seem to recommend that you don't use it, you might look into using the SO_LINGER option to force the socket to close immediately.
For example:
l_onoff, l_linger = 1, 1 # send RST (hard reset the socket) after 1 second
serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
struct.pack('ii', l_onoff, l_linger))
# this should now complete after l_linger timeout
serversocket.close()