Saturday, May 09, 2026 AM03:21:24 HKT

This commit is contained in:
2026-05-09 03:21:32 +08:00
commit 41f17b127c
884 changed files with 263824 additions and 0 deletions
@@ -0,0 +1 @@
lua-TestMore
+41
View File
@@ -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)))
@@ -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
View File
@@ -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