SIP OPTIONS with Scapy
"Scapy is a powerful Python-based interactive packet manipulation program and library." which I recently used to identify an issue with some incoming SIP OPTIONS pings to a Cisco Expressway. This article, as an output of working through the issue, provides the python script to perform (a) a TCP handshake, and (b) craft a SIP OPTIONS message and send it towards a device, which in this case is a Cisco Expressway. An in-depth overview of TCP or general packet manipulation is not discussed, however, as an aside, I've found that some of the existing Scapy TCP three-way handshake code used an incorrect TCP SYN number on the subsequent TCP PUSH/ACK packet following the handshake which is accounted for in the code below.
To do this you will need:
- Python (I'm using Python 3.6.2 on Windows 10 at the time of writing) - https://www.python.org/
- Scapy - https://github.com/secdev/scapy/
For reference, a pcap of the TCP exchange can be found here.
The following python script (gist here) will take three parameters,
- -sp - the source TCP port
- -dst - the destination IP
- -src - the source IP
To run the script enter the following, adjusting where required: python craftedSipOptions.py -sp 1573 -dst 192.168.44.59 -src 192.168.44.32
The following screenshots show the packet interaction as captured by Wireshark (note I have filtered out the noise).
Overall conversation.
SIP OPTIONS Request from the client-to-server.
Response from server-to-client.
Expressway-C event log showing the interaction.
from scapy.all import *
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-sp", type=int, help="The source TCP port")
parser.add_argument("-dst", help="The destination IP")
parser.add_argument("-src", help="The source IP")
parser.parse_args()
args = parser.parse_args()
sourcePort = args.sp
destinationIp = args.dst
sourceIp = args.src
ip=IP(src=sourceIp, dst=destinationIp)
# TCP SYN
TCP_SYN=TCP(sport=sourcePort, dport=5060, flags="S", seq=100)
TCP_SYNACK=sr1(ip/TCP_SYN)
# TCP SYN+ACK
myAck = TCP_SYNACK.seq + 1
TCP_ACK=TCP(sport=sourcePort, dport=5060, flags="A", seq=101, ack=myAck)
send(ip/TCP_ACK)
# TCP PSH+ACK with Payload
myPayload=(
'OPTIONS sip:{0}:5060;transport=tcp SIP/2.0\r\n'
'Via: SIP/2.0/TCP 192.168.44.32:5060;branch=1234\r\n'
'From: \"somedevice\"<sip:somedevice@1.1.1.1:5060>;tag=5678\r\n'
'To: <sip:{0}:5060>\r\n'
'Call-ID: 9abcd\r\n'
'CSeq: 1 OPTIONS\r\n'
'Max-Forwards: 0\r\n'
'Content-Length: 0\r\n\r\n').format(destinationIp)
TCP_PUSH=TCP(sport=sourcePort, dport=5060, flags="PA", seq=101, ack=myAck)
send(ip/TCP_PUSH/myPayload)