Saturday, May 4, 2013

A simple TCP session replay script

Description

This is a simple python script to replay a tcp session with a server. It also has a function to add code for fuzzing the replay session.

Download

simpleSessionReplay_1.py


Code


#! /usr/bin/python
#
# Export the packet data from wireshark in the following text format and this script will replay
# the session to a specified target IP and port.
#
#  No.     Time        Source                Destination           Protocol Info
#      6 0.001176    192.168.186.173       192.168.186.132       LDAP     bindRequest(1) "<ROOT>" simple
#
#  0000  00 0c 29 83 0c d1 00 0c 29 c1 a1 6e 08 00 45 00   ..).....)..n..E.
#  0010  00 42 43 40 40 00 40 06 00 f3 c0 a8 ba ad c0 a8   .BC@@.@.........
#  0020  ba 84 cf c7 01 85 38 93 b5 86 89 70 43 47 80 18   ......8....pCG..
#  0030  00 e5 b9 b9 00 00 01 01 08 0a 0b b3 f6 bb 05 7e   ...............~
#  0040  72 07 30 0c 02 01 01 60 07 02 01 03 04 00 80 00   r.0....`........
#

import socket
import string
import struct
import getopt
import sys

class packet(object):
def __init__(self,srcIP,dstIP,payload,payloadLength):
self.srcIP = srcIP
self.dstIP = dstIP
self.payload = payload
self.payloadLength = payloadLength

def printUsage():
print '\nExport the packet data from wireshark in the following text format and this script will replay'
  print 'the session to a specified target IP and port.'
print ''
print '  No.     Time        Source                Destination           Protocol Info'
print '6 0.001176    192.168.186.173       192.168.186.132       LDAP     bindRequest(1) "<ROOT>" simple'

print '0000  00 0c 29 83 0c d1 00 0c 29 c1 a1 6e 08 00 45 00   ..).....)..n..E.'
print '0010  00 42 43 40 40 00 40 06 00 f3 c0 a8 ba ad c0 a8   .BC@@.@.........'
print '0020  ba 84 cf c7 01 85 38 93 b5 86 89 70 43 47 80 18   ......8....pCG..'
print '0030  00 e5 b9 b9 00 00 01 01 08 0a 0b b3 f6 bb 05 7e   ...............~'
print '0040  72 07 30 0c 02 01 01 60 07 02 01 03 04 00 80 00   r.0....`........'
print ''
print 'An empty line must follow each packets data in the text file.'
print ''
print 'USAGE:'
print '\tsimpleSessionReplay.py -f <file> -d <ip address> -p <port> -s <seed value>'
print ''
print '-s Set this flag to fuzz a message based on a seed value you provide. (Not supported on this version)'

def readPacketsFromFIle(fileName):
nextLineType = 'header'
byteList = []
sourceIP = ''
destIP = ''
packetList = []
print 'Opening packet file ' + fileName
fileHandle = open(fileName,'r')

while 1:
# Read one line from the file
line = fileHandle.readline()
if not line:
#Only keep the layer 5 message so that means we don't need tcp/ip headers
print 'Payload :'
payloadList = byteList[0x42:]
print payloadList
#convert binary data list to binary string
buf = struct.pack('%sB' % len(payloadList),*payloadList)
packetList.append(packet(sourceIP,destIP,buf,len(payloadList)))
# Rest byteList for next packet info we loop through
byteList = []
print 'Finished reading packet info'
break
# The line will be 1 of 3 types of info in order (header, frame description data or a binary frame)
if nextLineType == 'header':
print '\nStarting to read packet info...'
# Verify that this line is the header line
tokens = line.split();
if tokens and tokens[0] != 'No.':
print 'FAILURE: Could not parse line \n\t' + line
exit()
else:
# We can expect the next line to be packet description info
nextLineType = 'description'

elif nextLineType == 'description':
tokens = line.split()
# If not set yet, capture the source and destination IPs
#if sourceIP == '' and destIP == '':
sourceIP = tokens[2]
destIP = tokens[3]
print 'src : ' + sourceIP
print 'dst : ' + destIP
nextLineType = 'emptyLineThenData'

elif nextLineType == 'emptyLineThenData':
# Verify it is an empty line
if line == '':
print 'FAILURE: Expect an empty line before the data'
exit()
nextLineType = 'data'

elif nextLineType == 'data':
# If the line is empty then the next line will be the header info for the next packet
tokens = line.split()
if tokens and tokens[0] != 'No.' :
# Convert the ascii represented binary data to binary data.
# Drop the first and last token. Those tokens are not binary data
for index in range( 1 , len(tokens)-1 ):
byteList.append(int(tokens[index],16))

else:
#Only keep the layer 5 message so that means we don't need tcp/ip headers
print 'Payload :'
payloadList = byteList[0x42:]
print payloadList
#convert binary data list to binary string
buf = struct.pack('%sB' % len(payloadList),*payloadList)
packetList.append(packet(sourceIP,destIP,buf,len(payloadList)))
# Rest byteList for next packet info we loop through
byteList = []
print 'Finished reading packet info'
# The end of the data has been reached. We should have collected the full payload


#print '\nStarting to read packet info...'
# Verify that this line is the header line
tokens = line.split();
if tokens and tokens[0] != 'No.':
print 'FAILURE: Could not parse line \n\t' + line
exit()
else:
# We can expect the next line to be packet description info
nextLineType = 'header'


fileHandle.close()
return packetList

def fuzz(packetList,seedValue):
fuzzFileName = 'fuzzFile.txt'
packetToFuzzIndex = 0

# Determine how many packets need to be sent to get a range
count = 0
src = packetList[0].srcIP
for packet in packetList:
if packet.srcIP == src:
count += 1
print 'packets to send: ' + str(count)

# Pick a packet to fuzz based on seed (0 - (n-1) ).
packetToFuzzIndex = seedValue % count
packetToFuzz = packetList[ packetToFuzzIndex ]

# Write the packet to a file.
print 'Writing bytes to file'
handle = open(fuzzFileName,'wb')
handle.write(packetToFuzz.payload)
handle.close()

# Call fuzzing method here on the file.

# < Place fuzzing code here >
print 'Fuzzing client->server packet ' + str(packetToFuzzIndex) + ' of packets 0 - ' + str(count-1) + '.'
print 'Fuzzing not supported!!!'
# Read in file
handle = open(fuzzFileName,'rb')
fuzzedPacket = handle.read()
handle.close()

# Place fuzzed packet in packet list
packetList[packetToFuzzIndex].payload = fuzzedPacket

# Return packet list
return packetList


fileName = ''
destinationIP = ''
destinationPort = -1
seed = -1

# Read in the command line arguments
try:
opts, args = getopt.getopt(sys.argv[1:],'f:d:p:s:')
except getopt.GetoptError, err:
printUsage()
sys.exit(2)

for o, a in opts:
if o == '-f':
fileName = a
elif o == '-d':
destinationIP = a
elif o == '-p':
destinationPort = int(a)
elif o == '-s':
seed = int(a)
else:
printUsage()
sys.exit(2)

#check that args were set
if fileName == '' or destinationIP == '' or destinationPort == -1:
printUsage()
sys.exit(2)


# Puts packet info from a file into a list of packet objects
packetList = readPacketsFromFIle(fileName)

# Check if packetList is returned
if packetList:
print 'Successfully read packets in from file!'
else:
print 'Failed to read packets from file'

#If the user choose to fuzz a packet, complete the fuzzing job (optional argument)
#Not suppoted in this version
if seed != -1:
print 'FUZZING NOT SUPPORTED!'
# packetList = fuzz(packetList,seed)

# Open a socket
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect((destinationIP,destinationPort))

#Look at the first packet and record src and dest to determine when to send and receive
firstPacket = packetList[0]
client = firstPacket.srcIP
server = firstPacket.dstIP

print '\nReplaying session to ' + destinationIP + ' at port ' + str(destinationPort) + ' ...'
for index in range( len(packetList) ):
if packetList[index].srcIP == client:
msg = packetList[index].payload
msgLength = packetList[index].payloadLength
totalsent = 0
        while totalsent < msgLength:
            sent = sock.send(msg[totalsent:])
print 'Message sent '  + str(sent) + ' bytes'
            if sent == 0:
                raise RuntimeError("socket connection broken")
            totalsent = totalsent + sent
else:
msg = ''
msgLength = packetList[index].payloadLength
        while len(msg) < msgLength:
            chunk = sock.recv(msgLength-len(msg))
print 'Message received: ' + str(msgLength-len(msg)) + ' bytes'
            if chunk == '':
                raise RuntimeError("socket connection broken")
            msg = msg + chunk

print 'Done replaying session,closing connection'
sock.close()


Useful Tcpdump Commands

Here is a list of useful tcpdump commands you can use when capturing, inspecting, and searching live or captured network traffic.

Captures traffic on a host
sudo tcpdump -i <listening (promiscuous) interface> host <target IP to capture all data to and from> -n -s 0 -w <output file name>

Does an ascii dump of traffic captured on a host
tcpdump -Alnqvvvs0

Do a regular expression search on a packet capture (pcap file)
tcpdump -Alnqvvvs0 -r <pcap file>  host "<ip address>" |grep -Ei "<regular expression>"