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:

Unknown said...

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

vuln said...

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

Laurent Gaffié blog said...

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.

Shane said...

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

fameen said...

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?

John Barness said...

Thanks for the exceptional information.

Post a Comment