Saturday, May 09, 2026 AM03:21:24 HKT
This commit is contained in:
@@ -0,0 +1 @@
|
||||
lua-TestMore
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2012, 2013 Nick Galbreath
|
||||
# nickg@client9.com
|
||||
# BSD License -- see COPYING.txt for details
|
||||
#
|
||||
|
||||
"""
|
||||
Converts a libinjection JSON data file to a C header (.h) file
|
||||
"""
|
||||
|
||||
def toc(obj):
|
||||
""" main routine """
|
||||
if False:
|
||||
print 'fingerprints = {'
|
||||
for fp in sorted(obj[u'fingerprints']):
|
||||
print "['{0}']='X',".format(fp)
|
||||
print '}'
|
||||
|
||||
words = {}
|
||||
keywords = obj['keywords']
|
||||
|
||||
for k,v in keywords.iteritems():
|
||||
words[str(k)] = str(v)
|
||||
|
||||
for fp in list(obj[u'fingerprints']):
|
||||
fp = '0' + fp.upper()
|
||||
words[str(fp)] = 'F';
|
||||
|
||||
print 'words = {'
|
||||
for k in sorted(words.keys()):
|
||||
#print "['{0}']='{1}',".format(k, words[k])
|
||||
print "['{0}']={1},".format(k, ord(words[k]))
|
||||
print '}'
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
import json
|
||||
sys.exit(toc(json.load(sys.stdin)))
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Generates a Lua table of fingerprints.
|
||||
One can then add, turn off or delete fingerprints from lua.
|
||||
"""
|
||||
|
||||
def make_lua_table(obj):
|
||||
"""
|
||||
Generates table. Fingerprints don't contain any special chars
|
||||
so they don't need to be escaped. The output may be
|
||||
sorted but it is not required.
|
||||
"""
|
||||
fp = obj[u'fingerprints']
|
||||
print("sqlifingerprints = {")
|
||||
for f in fp:
|
||||
print(' ["{0}"]=true,'.format(f))
|
||||
print("}")
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
import json
|
||||
with open('../c/sqlparse_data.json', 'r') as fd:
|
||||
make_lua_table(json.load(fd))
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/* libinjection.i SWIG interface file */
|
||||
%module libinjection
|
||||
%{
|
||||
#include "libinjection.h"
|
||||
#include "libinjection_sqli.h"
|
||||
|
||||
static char libinjection_lua_lookup_word(sfilter* sf, int lookup_type,
|
||||
const char* s, size_t len)
|
||||
{
|
||||
lua_State* L = (lua_State*) sf->userdata;
|
||||
//char* luafunc = (char *)lua_tostring(L, 2);
|
||||
lua_getglobal(L, "lookup_word");
|
||||
SWIG_NewPointerObj(L, (void*)sf, SWIGTYPE_p_libinjection_sqli_state, 0);
|
||||
lua_pushnumber(L, lookup_type);
|
||||
lua_pushlstring(L, s, len);
|
||||
|
||||
if (lua_pcall(L, 3, 1, 0)) {
|
||||
printf("Something bad happened");
|
||||
}
|
||||
|
||||
const char* result = lua_tostring(L, -1);
|
||||
if (result == NULL) {
|
||||
return 0;
|
||||
} else {
|
||||
return result[0];
|
||||
}
|
||||
}
|
||||
%}
|
||||
%include "typemaps.i"
|
||||
|
||||
|
||||
// The C functions all start with 'libinjection_' as a namespace
|
||||
// We don't need this since it's in the libinjection table
|
||||
// i.e. libinjection.libinjection_is_sqli --> libinjection.is_sqli
|
||||
//
|
||||
%rename("%(strip:[libinjection_])s") "";
|
||||
|
||||
%typemap(in) (ptr_lookup_fn fn, void* userdata) {
|
||||
if (lua_isnil(L, 1)) {
|
||||
arg2 = NULL;
|
||||
arg3 = NULL;
|
||||
} else {
|
||||
arg2 = libinjection_lua_lookup_word;
|
||||
arg3 = (void *) L;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
%typemap(out) stoken_t [ANY] {
|
||||
int i;
|
||||
lua_newtable(L);
|
||||
for (i = 0; i < $1_dim0; i++) {
|
||||
lua_pushnumber(L, i+1);
|
||||
SWIG_NewPointerObj(L, (void*)(& $1[i]), SWIGTYPE_p_stoken_t,0);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
SWIG_arg += 1;
|
||||
}
|
||||
|
||||
|
||||
%include "libinjection.h"
|
||||
%include "libinjection_sqli.h"
|
||||
@@ -0,0 +1,107 @@
|
||||
|
||||
require 'libinjection'
|
||||
|
||||
-- dofile('sqlifingerprints.lua')
|
||||
|
||||
-- silly callback that just calls back into C
|
||||
-- identical to libinjection_is_sqli(sql_state, string_input, nil)
|
||||
--
|
||||
function check_pattern_c(sqlstate)
|
||||
return(libinjection.sqli_blacklist(sqlstate) and
|
||||
libinjection.sqli_not_whitelist(sqlstate))
|
||||
end
|
||||
|
||||
-- half lua / half c checker
|
||||
-- use lua based fingerprint lookup and still uses C code
|
||||
-- to eliminate false positives
|
||||
function check_pattern(sqlstate)
|
||||
fp = sqlstate.pat
|
||||
if sqlifingerprints[fp] == true then
|
||||
-- try to eliminate certain false positives
|
||||
return(libinjection.sqli_not_whitelist(sqlstate))
|
||||
else
|
||||
-- not sqli
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
function lookup_word(sqlstate, ltype, word)
|
||||
if ltype == 'X' then
|
||||
return words['0' .. word:upper()]
|
||||
else
|
||||
return words[word:upper()]
|
||||
end
|
||||
end
|
||||
|
||||
dofile('words.lua')
|
||||
|
||||
|
||||
-- THIS USES BUILT IN FINGERPRINTS
|
||||
-- (with last arg of 'nil')
|
||||
sqli = '1 union select * from table'
|
||||
|
||||
|
||||
sql_state = libinjection.sqli_state()
|
||||
libinjection.sqli_init(sql_state, sqli, sqli:len(), 0)
|
||||
|
||||
print(libinjection.is_sqli(sql_state))
|
||||
print(sql_state.pat)
|
||||
print('----')
|
||||
|
||||
|
||||
|
||||
inputs = {
|
||||
"123 LIKE -1234.5678E+2;",
|
||||
"APPLE 1 9.123 'FOO' \"BAR\"",
|
||||
"/* BAR */ UNION ALL SELECT (2,3,4)",
|
||||
"1 || COS(+0X04) --FOOBAR",
|
||||
"dog apple @cat banana bar",
|
||||
"dog apple cat \"banana \'bar",
|
||||
"102 TABLE CLOTH"
|
||||
}
|
||||
|
||||
function benchmark(imax)
|
||||
local x,s
|
||||
local t0 = os.clock()
|
||||
local sql_state = libinjection.sqli_state()
|
||||
for x = 0, imax do
|
||||
s = inputs[(x % 7) + 1]
|
||||
libinjection.sqli_init(sql_state, s, s:len(), 0)
|
||||
libinjection.is_sqli(sql_state)
|
||||
end
|
||||
local t1 = os.clock()
|
||||
print( imax / (t1-t0) )
|
||||
end
|
||||
|
||||
function benchmark_callback(imax)
|
||||
local x,s
|
||||
local t0 = os.clock()
|
||||
local sql_state = libinjection.sqli_state()
|
||||
for x = 0, imax do
|
||||
s = inputs[(x % 7) + 1]
|
||||
libinjection.sqli_init(sql_state, s, s:len(), 0)
|
||||
libinjection.sqli_callback(sql_state, 'lookup_word');
|
||||
libinjection.is_sqli(sql_state)
|
||||
end
|
||||
local t1 = os.clock()
|
||||
print( imax / (t1-t0) )
|
||||
end
|
||||
|
||||
benchmark(1000000)
|
||||
benchmark_callback(1000000)
|
||||
|
||||
-- THIS USES LUA FINGERPRINTS via 'check_pattern' function above
|
||||
|
||||
if 0 then
|
||||
for x = 1,2 do
|
||||
ok = libinjection.is_sqli(sql_state)
|
||||
if ok == 1 then
|
||||
print(sql_state.pat)
|
||||
vec = sql_state.tokenvec
|
||||
for i = 1, sql_state.pat:len() do
|
||||
print(vec[i].type, vec[i].val)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import glob
|
||||
import sys
|
||||
|
||||
def readtestdata(filename):
|
||||
"""
|
||||
Read a test file and split into components
|
||||
"""
|
||||
|
||||
state = None
|
||||
info = {
|
||||
'--TEST--': '',
|
||||
'--INPUT--': '',
|
||||
'--EXPECTED--': ''
|
||||
}
|
||||
|
||||
for line in open(filename, 'r'):
|
||||
line = line.rstrip()
|
||||
if line in ('--TEST--', '--INPUT--', '--EXPECTED--'):
|
||||
state = line
|
||||
elif state:
|
||||
info[state] += line + '\n'
|
||||
|
||||
# remove last newline from input
|
||||
info['--INPUT--'] = info['--INPUT--'][0:-1]
|
||||
|
||||
return (info['--TEST--'], info['--INPUT--'].strip(), info['--EXPECTED--'].strip())
|
||||
|
||||
def luaescape(s):
|
||||
return s.strip().replace("\\", "\\\\").replace("\n", "\\n").replace("'", "\\'")
|
||||
|
||||
def genluatest(fname, data):
|
||||
# TBD: change to python os.path
|
||||
name = fname.split('/')[-1]
|
||||
if name.startswith('test-tokens-'):
|
||||
testname = 'test_tokens'
|
||||
extra = "\\n"
|
||||
elif name.startswith('test-tokens_mysql'):
|
||||
testname = 'test_tokens_mysql'
|
||||
extra = "\\n"
|
||||
elif name.startswith('test-folding-'):
|
||||
testname = 'test_folding'
|
||||
extra = "\\n"
|
||||
elif name.startswith('test-sqli-'):
|
||||
testname = 'test_fingerprints'
|
||||
extra = ''
|
||||
else:
|
||||
#print "IGNORING: " + name
|
||||
return
|
||||
|
||||
name = name.replace('.txt', '')
|
||||
|
||||
print "is({0}('{1}'),\n '{2}{3}',\n '{4}')\n".format(
|
||||
testname,
|
||||
luaescape(data[1]),
|
||||
extra,
|
||||
luaescape(data[2]),
|
||||
name
|
||||
)
|
||||
|
||||
def test2lua(fname):
|
||||
data = readtestdata(fname)
|
||||
genluatest(fname, data)
|
||||
|
||||
def main():
|
||||
print "require 'testdriver'\n"
|
||||
files = glob.glob('../tests/test-*.txt')
|
||||
print "plan({0})\n".format(len(files))
|
||||
for testfile in sorted(files):
|
||||
test2lua(testfile)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,90 @@
|
||||
require 'libinjection'
|
||||
require 'Test.More'
|
||||
require 'Test.Builder.Tester'
|
||||
|
||||
function trim(s)
|
||||
return s:find'^%s*$' and '' or s:match'^%s*(.*%S)'
|
||||
end
|
||||
|
||||
function print_token_string(tok)
|
||||
local out = ''
|
||||
if tok.str_open ~= '\0' then
|
||||
out = out .. tok.str_open
|
||||
end
|
||||
out = out .. tok.val
|
||||
if tok.str_close ~= '\0' then
|
||||
out = out .. tok.str_close
|
||||
end
|
||||
return trim(out)
|
||||
end
|
||||
|
||||
function print_token(tok)
|
||||
local out = ''
|
||||
out = out .. tok.type
|
||||
out = out .. ' '
|
||||
if tok.type == 's' then
|
||||
out = out .. print_token_string(tok)
|
||||
elseif tok.type == 'v' then
|
||||
if tok.count == 1 then
|
||||
out = out .. '@'
|
||||
elseif tok.count == 2 then
|
||||
out = out .. '@@'
|
||||
end
|
||||
out = out .. print_token_string(tok)
|
||||
else
|
||||
out = out .. tok.val
|
||||
end
|
||||
return '\n' .. trim(out)
|
||||
end
|
||||
|
||||
function test_tokens(input)
|
||||
local out = ''
|
||||
local sql_state = libinjection.sqli_state()
|
||||
libinjection.sqli_init(sql_state, input, input:len(),
|
||||
libinjection.FLAG_QUOTE_NONE + libinjection.FLAG_SQL_ANSI)
|
||||
while (libinjection.sqli_tokenize(sql_state) == 1) do
|
||||
out = out .. print_token(sql_state.current)
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
function test_tokens_mysql(input)
|
||||
local out = ''
|
||||
local sql_state = libinjection.sqli_state()
|
||||
libinjection.sqli_init(sql_state, input, input:len(),
|
||||
libinjection.FLAG_QUOTE_NONE + libinjection.FLAG_SQL_MYSQL)
|
||||
while (libinjection.sqli_tokenize(sql_state) == 1) do
|
||||
out = out .. print_token(sql_state.current)
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
function test_folding(input)
|
||||
local out = ''
|
||||
local sql_state = libinjection.sqli_state()
|
||||
libinjection.sqli_init(sql_state, input, input:len(), 0)
|
||||
libinjection.sqli_fingerprint(sql_state,
|
||||
libinjection.FLAG_QUOTE_NONE + libinjection.FLAG_SQL_ANSI)
|
||||
for i = 1, sql_state.fingerprint:len() do
|
||||
-- c array is still 0 based
|
||||
out = out .. print_token(libinjection.sqli_get_token(sql_state, i-1))
|
||||
end
|
||||
-- hack for when there is no output
|
||||
if out == '' then
|
||||
out = '\n'
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
function test_fingerprints(input)
|
||||
local out = ''
|
||||
local sql_state = libinjection.sqli_state()
|
||||
libinjection.sqli_init(sql_state, input, input:len(), 0)
|
||||
local issqli = libinjection.is_sqli(sql_state)
|
||||
if issqli == 1 then
|
||||
out = sql_state.fingerprint
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user