Python3 Quickly Pull TCP Service Banner
Hello readers! I recently wanted to pull the banner that was being supplied when connecting to a TCP service. In this case, I was poking a ZyWall device. To do this, we can simply use python's socket lib and decode messages.
Let's dive into the code, shall we?
#!/usr/bin/env python3
import sys
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = sys.argv[1].rstrip()
port = sys.argv[2].rstrip()
port = int(port)
try:
s.connect((host,port))
except Exception as e:
print("[+]Error: {0}".format(e))
try:
bdata = s.recv(128).decode('utf-8').strip()
print(bdata)
except Exception as e:
print("[+]Error: {0}".format(e))
s.close()
If you don't know entirely what's going on here with sockets, that's fine; we'll go over it.
As we will be connecting to a TCP service to send/receive messages, we are going to import the socket
library.
Next step, we want to build a socket object. We know that we will be issuing our request over TCP. Thus, we will be using socket.AF_INET, socket.SOCK_STREAM)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
AF_INET
declares Address Family, Internet Protocol v4. As TCP does not use datagrams—like UDP does—it uses a continuous stream of bytes. This requires us to use SOCK_STREAM
. If we were continuing on with creating a UDP socket, we would specify socket.SOCK_DGRAM
.
We need to send a host/port pair over to our socket to connect to. This is where we send the .connect()
method.
s.connect((host,port))
As some services will send a banner or data to clients just after a connection is established, we can simply listen/receive data from the server. To do this, we call:
bdata = s.recv(128).decode('utf-8').strip()
Per python socket manual, to receive data, we call socket.recv(bufsize[, flags])
. As we're really only interested in retrieving banner data, we'll specify a relatively small buffer of 128 bytes. Of course, you may need to change this depending on what you are doing. 128 bytes is quite a lot of data, however, YMMV.
As our TCP client will, in many cases, receive a literal byte string, we'll decode the bytes to utf-8 and also strip()
out carriage returns and new lines, else, we'll receive something like b'220 FTP Server (ZyWALL USG 20) [::ffff:192.168.66.11]\r\n'
.
This allows us to retrieve a nicer looking banner:
synfinner@synbook ~/P/p/Packd> ./packd.py 192.168.66.11 21
220 FTP Server (ZyWALL USG 20) [::ffff:192.168.66.11]