A Binary Fuzzer in JavaScript http://dinaburg.org/binfuzz Artem

advertisement
A Binary Fuzzer in JavaScript
http://dinaburg.org/binfuzz
Artem Dinaburg
artem@dinaburg.org
Blackhat Arsenal 2013
Binfuzz.js
ž  A Binary
ž  Written
Data Fuzzer
in JavaScript
Binary Data
ž  A sequence
of bytes not intended to be
interpreted as text
ž  Can be easily defined as a C structure
struct PDU { uint32_t magic; uint8_t type; uint16_t size; char data[1]; }; Fuzzer
ž  Randomized
Input Testing
ž  Impossible to test every program input
ž  Assumption: testing a random subset of
every possible input will find bugs
JavaScript
ž  Dynamically
typed object-based clientside scripting language
ž  Power the client side web
ž  Atwood's Law: any application that can
be written in JavaScript, will eventually
be written in JavaScript.
Binfuzz.js
ž  Randomized
Input Testing
… with some brains
ž  In JavaScript
… because it can be
ž  Makes icons
… I needed a good demo!
Binfuzz.js: Challenges
ž  Too
many combinations!
4294967296 combinations
—  8 Bytes => 1.84467440737096 * 1019
—  4 Bytes =>
combinations
ž  A typical
icon is ~4096 bytes.
ž  We have to be smarter
“more brains please” © flickr user abbamouse
Binfuzz.js: Challenges
ž  Use
semantic knowledge of data to
reduce combinations.
enum { PDU_DATA = 0, PDU_CONTROL = 1 } PDUTYPE; struct PDU { uint32_t magic; uint32_t type; uint32_t length; }; PDU is 12
bytes, but
generates only
two valid
combinations
Binfuzz.js: Challenges
ž  Not
all fuzz changes useful!
—  Checksums
—  Magic Numbers
—  Enumerations
ž  Use
semantic knowledge to create
‘correct-enough’ files.
Binfuzz.js: Features
ž  Fuzz
by defining semantic relationships
struct PDU { uint32_t magic; uint8_t type; uint16_t size; char data[1]; }; var PDU = new Container({'name’: 'PDU’});
PDU.addChild( new UInt32({
'root': PDU, 'name': 'magic’ }));
PDU.addChild( new UInt8({
'root': PDU, 'name': 'type’ }));
PDU.addChild( new IntSize({
'root': PDU, 'name': 'size',
'bytesize': 2, 'target': 'PDU.data’ }));
PDU.addChild(new Blob({
'root': PDU, 'name': 'data',
'generator': makeRandomString }));
Binfuzz.js: Features
ž  Nested
Structures
struct inner { uint16_t foo; char bar[12] }; struct outer { uint32_t magic; struct inner in; }; var outer = new Container( {'name': 'outer'}); var inner = new Container( {'root': outer, 'name': 'in'}); inner.addChild( new UInt16( {'root': outer, 'name': 'foo'} )); inner.addChild( new Blob( {'root': outer, 'name': 'bar', 'length': 12})); outer.addChild( new UInt32 ( {'root': outer, 'name': 'magic', 'constant': 0xDEADBEEF} )); outer.addChild( inner ); Binfuzz.js: Features
ž  Length
Counted Fields
struct big_blob { uint32_t bsize; char b[1]; }; // bsize is the // total size of // big_blob var big_blob = new Container( {'name':'bigblob'}); big_blob.addChild( new IntSize({ 'root': big_blob, 'name': 'bsize', 'bytesize': 4, 'target': big_blob})); big_blob.addChild( new Blob({ 'root': big_blob, 'name': 'b', 'generator': makeRandomString, 'length': function (seed, parent, root) {return getRandomNumber(Math.pow(2,32))}})); Binfuzz.js: Features
ž  Counted Arrays
struct counted { uint16_t num_foo; uint16_t foo[1]; }; // num_foo counts // how many // elements of // ‘foo’ will // actually exist var counted = new Container({'name': 'counted'}); counted.addChild( new UInt16( {'root': counted, 'name': 'num_foo'})); var foo_array = new ArrayContainer( {'root': counted, 'name': 'foo', 'count': 'counted.num_foos'}); foo_array.addChild(new UInt16({ 'root': counted, 'name': 'dummy'})); counted.addChild(foo_array); Binfuzz.js: Features
ž  Combinatorics
—  Determine number of tests a-priori
—  Select tests at random
var cbtest = doDemo4(0); Log('Demo4: Combinatorics'); Log('Demo4 Combos: ' + cbtest.Combos()); Log("Demo4 Size of Combo 0" + ": " + cbtest.Size()); cbtest = doDemo4(6); Log("Demo4 Size of Combo 6" + ": " + cbtest.Size()); Demo4: Combinatorics Demo4 Combos: 64 Demo4 Size of Combo 0: 2 Demo4 Size of Combo 8: 131072 Binfuzz.js: Features
ž  File
Offsets
—  Calculates offsets for this specific fuzz case
... Add counted array ... offsets.addChild(new IntOffset({ 'root': offsets, 'name': 'f_offset', 'bytesize': 4, 'target': 'offsets.f_offset'}); // self referencing! Demo5: File Offsets Demo5 Offset for Combo 1: 4 Demo5 Offset for Combo 4: 65536 Binfuzz.js: Features
ž  Custom
Population Functions
—  Can reference other dynamic elements
new Blob( {'root': ICON, 'name': 'icXOR', 'generator': makeRandomString, 'length': function (seed, parent, root) { var bih = parent.getChild('tagBITMAPINFOHEADER'); var width = bih.getChild('biWidth').NativeValue(); var height = bih.getChild('biHeight').NativeValue()/2; var bpp = bih.getChild('biBitCount').NativeValue(); var planes = bih.getChild('biPlanes').NativeValue(); var stride = (( width * planes * bpp + 31) & ~31) / 8; var thislen = stride * height; return thislen; }})); Binfuzz.js: Features
ž  Open
Source
ž  MIT Licensed
ž  http://github.com/artemdinaburg/binfuzz
The Demo
ž  http://dinaburg.org/binfuzz
ž  Fuzz
Windows Icons
—  Surprisingly complex!
—  Arrays
—  Nested Structures
—  Length Counters
—  Fields calculated from multiple
dependencies
—  File offsets
Future Work
ž  Common
Format Libraries
ž  Permutation of Blobs with generic
fuzzers
ž  Memory Usage
Get The Code
ž  http://dinaburg.org/binfuzz
ž  http://github.com/artemdinaburg/binfuzz
Download