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:

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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)