Sunday, November 22, 2009

Releasing ICMPv4/IP fuzzer prototype

This is a short message to release an IP/ICMPv4 fuzzer, destinated for UTesting, and else.
I'd like to thanks Philippe Biondi for making such a library as scapy

In this example we go deep as layer 3 fuzzing, thanks scapy, we fuzz IP and ICMP by disassembling the packet in bytes, and modifing it, and then joining it and sending back

You can simply capture a ping echo (for example) you sended and then fuzz it, you will need to replace the checksum bytes by 00 00 always, for more information :

http://www.networksorcery.com/enp/protocol/ip.htm
http://www.networksorcery.com/enp/protocol/icmp.htm

You can easily adapt this fuzzer to any kind of networking fuzzing.

Dont forget it's a prototype, and i ASSUME you know what you're doing, do not ask for help.

As blogger is not python friendly: http://pastebin.com/f5c536013

Have fun with this concept :)

#!/usr/bin/python
import random, sys,logging,os
from random import *
from scapy.all import *
logging.getLogger("scapy").setLevel(1)

##fuzzer core##
def onerand(packet):
pack = packet[:]
byte = str(chr(choice(range(256))))
pack[choice(range(len(packet)))]= byte
print "fuzzing rand byte:%s\n" % (byte.encode("hex"))
return pack

def doublerand(packet):
pack = packet[:]
byte = str(chr(choice(range(256))))
byte2 = str(chr(choice(range(256))))
pack[choice(range(len(packet)))]= byte
pack[choice(range(len(packet)))]= byte2
print "fuzzing rand byte:%s byte2:%s\n" % (byte.encode("hex"),byte2.encode("hex"))
return pack

def longrand(packet):
pack = packet[:]
byte = str(chr(choice(range(256))))
lon = randrange(0,600)
pack[choice(range(len(packet)))]= byte*lon
print "fuzzing rand byte:%s len:%s\n" % (byte.encode("hex"),lon)
return pack

def longerrand(packet):
pack = packet[:]
byte = str(chr(choice(range(256))))
lon = randrange(0,600)
pack[choice(range(len(packet)))]= byte
pack[choice(range(len(packet)))]= byte*lon
print "fuzzing rand byte:%s len:%s\n" % (byte.encode("hex"),lon)
return pack

def longerrandnull(packet):
pack = packet[:]
byte = str(chr(choice(range(256))))
lon = randrange(0,600)
pack[choice(range(len(packet)))]= byte
pack[choice(range(len(packet)))]= byte+"\x00"*lon
print "fuzzing rand byte:%s len:%s\n" % (byte.encode("hex"),lon)
return pack

def opnum(packet):
pack = packet[:]
byte = str(chr(choice(range(0,2))))
pack[choice(range(len(packet)))]= byte
print "fuzzing opnum:%s\n" % (byte.encode("hex"))
return pack

def doubleopnum(packet):
pack = packet[:]
byte = str(chr(choice(range(0,2))))
byte2 = str(chr(choice(range(0,2))))
pack[choice(range(len(packet)))]= byte
pack[choice(range(len(packet)))]= byte2
print "fuzzing opnum:%s et opnum no-2:%s\n" % (byte.encode("hex"),byte2.encode("hex"))
return pack

def remove1(packet):
pack = packet[:]
i = randrange(0, len(pack)-1)
b = pack[:i] + pack[i+1:]
print "remove one char fuzz, removed :%s"%(pack[i].encode("hex"))
return b

def changenull(packet):
pack = packet[:]
null = [i for i in range(len(pack)) if pack[i] == '\x00']
byte = str(chr(choice(range(256))))
pack[choice(null)] = byte
print "replaced one null by a %s"%(byte.encode("hex"))
return pack


def removenull(packet):
pack = packet[:]
null = [i for i in range(len(pack)) if pack[i] == '\x00']
num = choice(null)
del pack[choice(null)]
print "deleted null no-:%s"%(num)
return pack

def randfunc(packet):
func = choice([onerand,doublerand,longrand,longerrand,longerrandnull,removenull,changenull,remove1,doubleopnum,opnum])
print "using %s fuzzing type (HARD)"%(func.__name__)
return func(packet)

def zenfunc(packet):
func = choice([onerand,removenull,changenull,remove1,doubleopnum,opnum])
print "using %s fuzzing type (ZEN)"%(func.__name__)
return func(packet)

##End fuzzer core##

ip = [chr(int(a, 16)) for a in """
4e fe 01 08 00 00 40 00 fa 01 00 00 c0 a8 02 64
c0 a8 02 65 44 24 0d 01 c0 a8 02 64 04 80 30 77
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00""".split()]

icmp = [chr(int(a, 16)) for a in """
08 00 00 00 00 00 00 04 75 54 08 4b 00 00 00 00
04 6b 0d 00 00 00 00 00 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
""".split()]

def longueur(payload):
length = struct.pack(">i", len(''.join(payload)))
a= length[2:4]
pack = payload[:]
pack[2:4]= a
return pack

def OpIP(packet):
pack = packet[:]
num = str(chr(choice(range(1,9))))
num1 = str(chr(choice(range(0,150))))
#pack[0] = num
#pack[9] = num1
print "fuzzing version OPNUM no-:%s and nh OPNUM no-:%s"%(num.encode("hex"),num1.encode("hex"))
return pack

def OpIcmp(packet):
pack = packet[:]
num = str(chr(choice(range(0,42))))
pack[0] = num
print "fuzzing ICMP OPNUM no-:%s"%(num.encode("hex"))
return pack

##checksum calculation and replacement##
##checksum() ripped from scapy, hard to do better...
def checksum(pkt):
pkt=str(pkt)
s=0
if len(pkt) % 2 == 1:
pkt += "\0"
for i in range(len(pkt)/2):
s = s + (struct.unpack("!H",pkt[2*i:2*i+2])[0])
s = (s >> 16) + (s & 0xffff)
s += s >> 16
return ~s & 0xffff
##/checksum() ripped from scapy, hard to do better...

def add_checksum(packet):
a = struct.pack(">i",checksum(''.join(packet)))
b = a[2:4]
pack = packet[:]
pack[2:4]=b
return pack

def add_ip_checksum(packet):
a = struct.pack(">i",checksum(''.join(packet)))
b = a[2:4]
pack = packet[:]
pack[10:12]=b
return pack

##checksum calculation and replacement##

### snort is an example of hookin' a prog in your fuzzin'

pid = os.system("pidof snort")
while os.system("pidof snort") == pid:

a = longueur(zenfunc(ip)+add_checksum(randfunc(icmp)))
b = ''.join(add_ip_checksum(a))
packet = (Ether(dst="ff:ff:ff:ff:ff:ff",type=0x0800)/b)
print "packet IP:%s\n"%(b.encode("hex"))
sendp(packet)

##enjoy !

6 comments:

  1. YOU ARE JUST INSANE
    Sell your fuzzers, do not give them for free !

    ReplyDelete
  2. Hi Laurent, thanks. Keep up the good job.

    I would appreciate if you could share why this error occured.

    I've Python ver2.5.1 installed on my pc

    D:\Fuzz>python
    Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>>

    Thanks in advance

    D:\Fuzz>"fuzzer core.py"
    C:\Python25\lib\site-packages\scapy.py:3656: Warning: 'with' will become a reserved keyword in Pytho
    n 2.6
    C:\Python25\lib\site-packages\scapy.py:3658: Warning: 'with' will become a reserved keyword in Pytho
    n 2.6
    Traceback (most recent call last):
    File "D:\PenTest\Fuzz\fuzzer core.py", line 4, in
    from scapy.all import *
    File "C:\Python25\lib\site-packages\scapy.py", line 462, in
    ifaces.load_from_dnet()
    File "C:\Python25\lib\site-packages\scapy.py", line 425, in load_from_dnet
    self.data[i["name"]] = NetworkInterface(i)
    File "C:\Python25\lib\site-packages\scapy.py", line 347, in __init__
    self.update(dnetdict)
    File "C:\Python25\lib\site-packages\scapy.py", line 361, in update
    self._update_pcapdata()
    File "C:\Python25\lib\site-packages\scapy.py", line 383, in _update_pcapdata
    fixed_ip = _winreg.QueryValueEx(key, "IPAddress")[0][0].encode("utf-8")
    IndexError: list index out of range

    ReplyDelete
  3. Hi,

    It would be better to run this fuzzer on linux than on windows.

    1) Scapy is not 100% working on windows, and wasn't destinated to run on windows, for more info check :
    http://trac.secdev.org/scapy/wiki/WindowsInstallationGuide

    2) windows kernel will drop 3/4 of the packet you want to send.

    ReplyDelete
  4. Wow this is really cool exactly what I was looking for!

    Found this link helped answer a few of my questions.
    http://trac.secdev.org/scapy/wiki/WindowsInstallationGuide

    Thanks

    ReplyDelete
  5. Hi laurent, you work is absolutely awesome. i am interested in your work but want to build a TCP stack fuzzer similar to the tool used by stonesoft (predator).. i am a newbie doing some research in advance evasion techniques.. how do i start?

    ReplyDelete
  6. Thanks for the exceptional information.

    ReplyDelete