3

I'm asking here just because I've searched a lot and until now I wasn't able to find a clue about how to accomplish this task. The task at hand is to build a python script that is able to:

  • Sniff tcp packets;
  • Decode de payload that in my case is encrypted with JWT - The JWT in turn is a json in base64;
  • Repack with the decrypted data;
  • Reinject the packet on the same interface if possible, but can be a virtual interface too;
  • It has to happen on the fly.

All traffic that arrives to the server come into an interface that hasn't any IP associated, so the sniffing has to happen in layer 2 and reinjected in layer 2, but case is possible could be captured in layer 2 and reinjected right into layer 3, but in this case I'm not sure how to do it. By layer 2 I mean got to be bound to an interface, not with hostname and port.

I've based my script on this http://www.offensivepython.com/2014/08/tcp-packet-injection-with-python.html for the injection and works fine in the lab (Kali, Centos 6.8) passing the tuple host, port to socket.bind() and for sniffing I wrote the following:

#!/usr/bin/python


import socket
import ctypes
import fcntl
from struct import *
from time import sleep
class ifreq(ctypes.Structure):
    _fields_ = [("ifr_ifrn", ctypes.c_char * 16),("ifr_flags", ctypes.c_short)]


IFACE="eth0"
ETH_P_IP=0x0800
IFF_PROMISC = 0x100
SIOCGIFFLAGS = 0x8913
SIOCSIFFLAGS = 0x8914

skt = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_IP))

ifr = ifreq()
ifr.ifr_ifrn = IFACE
fcntl.ioctl(skt.fileno(), SIOCGIFFLAGS, ifr)
ifr.ifr_flags |= IFF_PROMISC
fcntl.ioctl(skt.fileno(), SIOCSIFFLAGS, ifr)


print "[+] Sniffing packets"
while True:
    pct = skt.recvfrom(65535)
    pct = pct[0]
    ipheader = pct[:20]
    iph = unpack('!BBHHHBBH4s4s', ipheader)
    version_ih1 = iph[0]
    version = version_ih1 >> 4
    ih1 = version_ih1 & 0xF
    iph_length = ih1 * 4
    ttl = iph[5]
    protocol = iph[6]
    src_addr = socket.inet_ntoa(iph[8])
    dst_addr = socket.inet_ntoa(iph[9])

    print 'Version: %s \nIP Header Length: %s\nTTL: %s\nProtocol: %s\nSource Addr: %s\nDest Addr: %s'%(version, iph_length, ttl, protocol, src_addr, dst_addr)

    tcp_header = pct[iph_length:iph_length+20]
    tcph = unpack('!HHLLBBHHH', tcp_header)
    src_port = tcph[0]
    dst_port = tcph[1]
    sequence = tcph[2]
    ack = tcph[3]
    doff_reserved = tcph[4]
    tcph_length = doff_reserved >> 4
    if src_port == 0 | dst_port == 0:
        continue

    print 'SRC Port: %s \nDST_Port: %s\nSEQ: %s\nACK: %s\nDoff Reserved: %s\nTCP Header Length: %s'%(src_port, dst_port, sequence, ack, doff_reserved, tcph_length)

    h_size = iph_length + tcph_length * 4
    data_size = len(pct) - h_size
    data = pct[h_size:]
    print 'Data: %s\n' %data
    sleep(2)

I've tested this solution and works fine for injection in my labs (Kali, CentOS 6.8), I can run a tcpdump and see the packets coming to the specified interface but in production (RHEL 6.8) does now show anything in tcpdump.

I've been searching this in the socket linux docs, python socket docs in some books like Core Python, Foundation of Network Programming, The Linux Programming Interface and has from none to little information on how to properly use AF_PACKET. My questions are:

  • Is it possible decode the traffic at layer 2 level;
  • In case yes and following the reasoning of the scripts aforementioned what am I doing wrong?
  • Is there some differences between the sockets implementation across the different Linux distro (RHEL, Centos, Debian);
  • How to proper use the socket interface using the arguments (socket.AF_PACKET, socket.SOCK_RAW,[OPTIONAL]);
  • the OPTIONAL argument in the item above is the protocol, in some examples I've seen socket.htons(ETH_P_IP), ETH_P_IP, socket.ntohs(ETH_P_IP), and the constant sometimes is ETH_P_ALL, what are the differences?
  • Could someone leave an example here?

This question is because I'm working with a Threat Detection tool that processes all data and generate alerts, incidents and reports, but with the data encoded with JWT is not possible to see what is actually happening in the requests, therefore is not possible to see the actual data and properly use the tool.

Thanks in advance.

Community
  • 1
  • 1
Jefer Song
  • 51
  • 1
  • 7
  • 2
    While possible, this is not something you will get working anytime soon. Each TCP peer knows how many bytes it has sent, and the other side will send ACKs according to the bytes received. If you rewrite packets as "man in the middle", you will have to massage TCP header fields in both directions in order for the two sides to successfully communicate. And to be robust, you would need to handle IP fragmentation, TCP dups/re-ordering and window mgmt. Bottom line: this is way more complicated than you're thinking; you're better off figuring out how to modify or plug into the Threat Detection tool. – Gil Hamilton Dec 01 '16 at 17:10
  • 1
    While your problem is more difficult than mine, I did get a python3 implementation working going from a custom raw 80211 broadcast protocol into a virtual tun interface. Pretty good performance too! Used raw socket for reading, scapy for transmitting back over wifi, and pytun for the tun. I didn't have to MITM TCP though. – Allison Nov 18 '17 at 08:19

0 Answers0