VNC Authentication checking with Python

In this post i describe a small python script which can be used to determine the type of authentication used on a VNC Server. It uses the Scapy packet manipulation program to perform all the network data transmissions and retrievals. The program may not be perfect, but with my limited testing it seemed to work ok. To understand how the program works, i need to explain how a VNC client interacts with a VNC server. The RFB Protocol is used to make the connection to the server. By default this runs on TCP port 5900. I import Scapy into the python program, and save the IP address and port number into the variables IpAddress and port.

from scapy.all import *
IpAddress = '192.168.1.13'
port = 5900

It is important to run the following command before executing the script. This allows for the TCP handshake to complete.

iptables -A OUTPUT -p tcp –tcp-flags RST RST -j DROP

The first stage is to perform a TCP handshake to port 5900. I have set the timeout value of the TCP SYN packet to 2 seconds. This prevents the code running in an endless loop if the VNC server dosn’t respond with a SYNACK.

If the server does respond with a SYNACK, the SYNACK packet is stored in the synack variable.

syn = IP(dst=IpAddress)/TCP(dport=port, flags='S') 
synack = sr1(syn, timeout=2) 

I then finish the TCP handshake with an ACK, and send it to the VNC server.

ack = IP(dst=IpAddress)/TCP(dport=port, flags='A', seq=1, ack=synack.seq + 1)
send(ack)

Now the TCP handshake is complete, the VNC server should respond with a protocol version message. This is a message which tell the client the version number supported by the server. This message needs to be captured. To do this i then run a sniffer on the interface, checking for all data incoming from the VNC servers IP address.

filter = 'host ' + IpAddress
vnc = sniff(filter=filter, count=1,timeout=2, prn=vncCheck)

All data that matches the filter is sent to the vncCheck function for further processing. The first stage of this function is to verify that the packet it received is indeed a protocol version message. An example of a protocol message can be seen below:

pv

All protocol version packets are in the format of ‘RFB xxx.yyy\n’. xxx and yyy are the protocol version numbers. Because of this, the best method of determining if the packet is a protocol version message is by simply checking if the packet payload consists of the string ‘RFB’.

if 'RFB' in packet.load:

When the protocol version message is received. The client then sends a client protocol version. This informs the server the protocol version which the client supports and will be used for the communication. In my case i create a the client protocol version packet with the version payload of ‘RFB 003.003\n’.

clientVersion = IP(dst=IpAddress)/TCP(dport=port, flags='AP', seq=1, ack=packet.seq + 1)/'RFB 003.003\n'

The client protocol version is then sent to the VNC server. The response back from the VNC server is saved into the supportedtypesPacket variable. This response contains the type of authenticaion the server uses in the form of a hexadecimal value. For example, from the following screenshot you can see the security type response 00 00 00 02 highlighted at the bottom.

st

The type of authentication the VNC server uses is defined by the last byte. In this case the value 02. The program then extracts this byte and stores it in the variable authenticationType.

authenticationType = str(ord(supportedtypesPacket.load[2])) + str(ord(supportedtypesPacket.load[3]))
authenticationType = int(authenticationType)

Finally, a simple IF statement is used to compares the value to the matching authentication type.

if authenticationType == 00:
	print IpAddress + ' uses an Invalid Authentication type of ' + str(authenticationType)
elif authenticationType == 01:
	print IpAddress + ' uses No Authentication'
elif authenticationType == 02:
	print IpAddress + ' uses VNC Authentication'
elif authenticationType == 05:
	print IpAddress + ' uses RA2 Authentication'
elif authenticationType == 06:
	print IpAddress + ' uses RA2ne Authentication'
elif authenticationType == 16:
	print IpAddress + ' uses Tight Authentication'
elif authenticationType == 17:
	print IpAddress + ' uses Ultra Authentication'
elif authenticationType == 18:
	print IpAddress + ' uses TLS Authentication'
elif authenticationType == 19:
	print IpAddress + ' uses VeNCrypt Authentication'
elif authenticationType == 20:
	print IpAddress + ' uses GTK-VNC SASL Authentication'
elif authenticationType == 21:
	print IpAddress + ' uses MD5 Hash Authentication'
elif authenticationType == 22:
	print IpAddress + ' uses Colin Dean XVP Authentication'
else:
	print IpAddress + ' uses an Unknown Authentication type of: ' + str(authenticationType)

For completeness, you can find below the complete code with indentation and comments included.

from scapy.all import *

#Must run the following command before executing this script. Allows for the TCP handshake to take place.
#iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP

#IP and Port of the VNC server
IpAddress = '192.168.1.13'
port = 5900

#Function which is executed on each packet.
def vncCheck(packet):
    #Checks that the packet is a server protocol version response. (Should contain 'RFB' if it is.
    if packet.haslayer('Raw'):
        if 'RFB' in packet.load:
            #Creates and sends a clientVersion response. The security type response from the VNC server is saved in the
            #Variable supportedtypesPacket
            clientVersion = IP(dst=IpAddress)/TCP(dport=port, flags='AP', seq=1, ack=packet.seq + 1)/'RFB 003.003\n'
            supportedtypesPacket = sr1(clientVersion)
            #Extract the HEX value from the security type response.
            authenticationType = str(ord(supportedtypesPacket.load[2])) + str(ord(supportedtypesPacket.load[3]))
            authenticationType = int(authenticationType)
            #Match the value with the correct authentication type.
            print IpAddress + ' Uses an Authentication type of : ' + str(authenticationType)
            if authenticationType == 00:
                print IpAddress + ' uses an Invalid Authentication type of ' + str(authenticationType)
            elif authenticationType == 01:
                print IpAddress + ' uses No Authentication'
            elif authenticationType == 02:
                print IpAddress + ' uses VNC Authentication'
            elif authenticationType == 05:
                print IpAddress + ' uses RA2 Authentication'
            elif authenticationType == 06:
                print IpAddress + ' uses RA2ne Authentication'
            elif authenticationType == 16:
                print IpAddress + ' uses Tight Authentication'
            elif authenticationType == 17:
                print IpAddress + ' uses Ultra Authentication'
            elif authenticationType == 18:
                print IpAddress + ' uses TLS Authentication'
            elif authenticationType == 19:
                print IpAddress + ' uses VeNCrypt Authentication'
            elif authenticationType == 20:
                print IpAddress + ' uses GTK-VNC SASL Authentication'
            elif authenticationType == 21:
                print IpAddress + ' uses MD5 Hash Authentication'
            elif authenticationType == 22:
                print IpAddress + ' uses Colin Dean XVP Authentication'
            else:
                print IpAddress + ' uses an Unknown Authentication type of: ' + str(authenticationType)

#Creates and sends a TCP SYN packet to the VNC server. (Step 1 of the TCP handshake)
syn = IP(dst=IpAddress)/TCP(dport=port, flags='S')
synack = sr1(syn, timeout=2)

#Creates and sends an ACK packet is response to the servers SYNACK. (Step 3 of the TCP handshake)
ack = IP(dst=IpAddress)/TCP(dport=port, flags='A', seq=1, ack=synack.seq + 1)
send(ack)

#Sniffs incoming network data after the initial TCP handshake. Sends the packets to the vncCheck function.
filter = 'host ' + IpAddress
vnc = sniff(filter=filter, count=1,timeout=2, prn=vncCheck)

Leave a Reply

Your email address will not be published. Required fields are marked *