Skip to content

Commit e551e7c

Browse files
Copilotfzipi
andcommitted
Update module to work with upstream libinjection and improve Python 3 compatibility
Co-authored-by: fzipi <3012076+fzipi@users.noreply.github.com>
1 parent b9f0029 commit e551e7c

7 files changed

Lines changed: 155 additions & 44 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,7 @@ libinjection/libinjection_xss.*
136136
libinjection/libinjection_html5.*
137137
libinjection/libinjection_sqli*
138138
libinjection/libinjection_wrap*
139+
libinjection/libinjection_error.h
140+
141+
# Generated files
142+
words.py

Makefile

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ all: build
44
#
55

66
build: upstream libinjection/libinjection_wrap.c
7-
rm -f libinjection.py libinjection.pyc
8-
python setup.py --verbose build --force
7+
rm -f libinjection/libinjection.py
8+
python3 setup.py --verbose build_ext --inplace
99

1010
install: build
11-
sudo python setup.py --verbose install
11+
sudo python3 setup.py --verbose install
1212

1313
test-unit: build words.py
14-
python setup.py build_ext --inplace
15-
PYTHON_PATH='.' nosetests -v --with-xunit test_driver.py
14+
cd /tmp && python3 -m pytest $(CURDIR)/test_driver.py -v
1615

1716
.PHONY: test
1817
test: test-unit
@@ -24,16 +23,16 @@ speed:
2423
upstream:
2524
[ -d $@ ] || git clone --depth=1 https://github.com/libinjection/libinjection.git upstream
2625

27-
libinjection/libinjection.h libinjection/libinjection_sqli.h: upstream
26+
libinjection/libinjection.h libinjection/libinjection_sqli.h libinjection/libinjection_error.h: upstream
2827
cp -f upstream/src/libinjection*.h upstream/src/libinjection*.c libinjection/
2928

3029
words.py: Makefile json2python.py upstream
31-
./json2python.py < upstream/src/sqlparse_data.json > words.py
30+
python3 json2python.py < upstream/src/sqlparse_data.json > words.py
3231

3332

34-
libinjection/libinjection_wrap.c: libinjection/libinjection.i libinjection/libinjection.h libinjection/libinjection_sqli.h
33+
libinjection/libinjection_wrap.c: libinjection/libinjection.i libinjection/libinjection.h libinjection/libinjection_sqli.h libinjection/libinjection_error.h
3534
swig -version
36-
swig -py3 -python -builtin -Wall -Wextra libinjection/libinjection.i
35+
swig -python -builtin -Wall -Wextra libinjection/libinjection.i
3736

3837

3938
.PHONY: copy
@@ -50,5 +49,6 @@ clean:
5049
@rm -f nosetests.xml
5150
@rm -f words.py
5251
@rm -f libinjection/*~ libinjection/*.pyc
53-
@rm -f libinjection/libinjection.h libinjection/libinjection_sqli.h libinjection/libinjection_sqli.c libinjection/libinjection_sqli_data.h
52+
@rm -f libinjection/libinjection.h libinjection/libinjection_error.h libinjection/libinjection_sqli.h libinjection/libinjection_sqli.c libinjection/libinjection_sqli_data.h
53+
@rm -f libinjection/libinjection_html5.h libinjection/libinjection_html5.c libinjection/libinjection_xss.h libinjection/libinjection_xss.c
5454
@rm -f libinjection/libinjection_wrap.c libinjection/libinjection.py

README.md

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,93 @@
11
# python3-libinjection
22
libInjection Python3 bindings
3+
4+
## Overview
5+
6+
Python3 bindings for [libinjection](https://github.com/libinjection/libinjection) - a SQL/SQLI tokenizer, parser and analyzer.
7+
8+
## Requirements
9+
10+
- Python 3.x
11+
- SWIG 4.x
12+
- GCC or compatible C compiler
13+
14+
## Building
15+
16+
### 1. Clone the repository and get upstream libinjection
17+
18+
```bash
19+
git clone https://github.com/libinjection/python3-libinjection.git
20+
cd python3-libinjection
21+
make upstream
22+
```
23+
24+
### 2. Copy upstream C source files
25+
26+
```bash
27+
make libinjection/libinjection.h libinjection/libinjection_sqli.h libinjection/libinjection_error.h
28+
```
29+
30+
### 3. Generate the SWIG wrapper
31+
32+
```bash
33+
swig -python -builtin -Wall -Wextra libinjection/libinjection.i
34+
```
35+
36+
### 4. Build the Python extension
37+
38+
```bash
39+
python3 setup.py build_ext --inplace
40+
```
41+
42+
Or using the Makefile:
43+
44+
```bash
45+
make build
46+
```
47+
48+
### 5. Generate the word lookup table (needed for tests)
49+
50+
```bash
51+
python3 json2python.py < upstream/src/sqlparse_data.json > words.py
52+
```
53+
54+
## Usage
55+
56+
### SQLi Detection
57+
58+
```python
59+
import libinjection
60+
61+
# Simple API - detect SQLi in a string
62+
result, fingerprint = libinjection.sqli("1 UNION SELECT * FROM users")
63+
if result:
64+
print(f"SQLi detected! Fingerprint: {fingerprint}")
65+
66+
# Advanced API with state object
67+
state = libinjection.sqli_state()
68+
libinjection.sqli_init(state, "1 UNION SELECT * FROM users",
69+
libinjection.FLAG_QUOTE_NONE | libinjection.FLAG_SQL_ANSI)
70+
libinjection.sqli_callback(state, None)
71+
if libinjection.is_sqli(state):
72+
print(f"SQLi detected! Fingerprint: {state.fingerprint}")
73+
```
74+
75+
### XSS Detection
76+
77+
```python
78+
import libinjection
79+
80+
# Detect XSS in a string
81+
result = libinjection.xss("<script>alert(1)</script>")
82+
if result:
83+
print("XSS detected!")
84+
```
85+
86+
## Testing
87+
88+
Run the test suite using pytest:
89+
90+
```bash
91+
cd /tmp # run from outside the repo directory to avoid pytest.py conflict
92+
python3 -m pytest /path/to/python3-libinjection/test_driver.py -v
93+
```

libinjection/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from libinjection import *
1+
from .libinjection import *

libinjection/libinjection.i

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
%{
44
#include "libinjection.h"
55
#include "libinjection_sqli.h"
6+
#include "libinjection_xss.h"
7+
#include "libinjection_error.h"
68
#include <stddef.h>
79

810
/* This is the callback function that runs a python function
@@ -13,7 +15,6 @@ static char libinjection_python_check_fingerprint(sfilter* sf, int lookuptype, c
1315
PyObject *fp;
1416
PyObject *arglist;
1517
PyObject *result;
16-
const char* strtype;
1718
char ch;
1819

1920
// get sfilter->pattern
@@ -25,14 +26,21 @@ static char libinjection_python_check_fingerprint(sfilter* sf, int lookuptype, c
2526
result = PyObject_CallObject((PyObject*) sf->userdata, arglist);
2627
Py_DECREF(arglist);
2728
if (result == NULL) {
28-
printf("GOT NULL\n");
2929
// python call has an exception
3030
// pass it back
3131
ch = '\0';
3232
} else {
33-
// convert value of python call to a char
34-
strtype = PyString_AsString(result);
35-
ch = strtype[0];
33+
// convert value of python call to a char (Python 3 compatible)
34+
if (PyUnicode_Check(result)) {
35+
Py_ssize_t size;
36+
const char* str = PyUnicode_AsUTF8AndSize(result, &size);
37+
ch = (str != NULL && size > 0) ? str[0] : '\0';
38+
} else if (PyBytes_Check(result)) {
39+
const char* str = PyBytes_AsString(result);
40+
ch = (str != NULL) ? str[0] : '\0';
41+
} else {
42+
ch = '\0';
43+
}
3644
Py_DECREF(result);
3745
}
3846
return ch;
@@ -67,6 +75,18 @@ for (i = 0; i < $1_dim0; i++) {
6775

6876
// automatically append string length into arg array
6977
%apply (char *STRING, size_t LENGTH) { (const char *s, size_t slen) };
78+
%apply (char *STRING, size_t LENGTH) { (const char *s, size_t len) };
79+
80+
// Make the fingerprint output parameter in libinjection_sqli() work as an output
81+
// The fingerprint buffer size matches libinjection's internal LIBINJECTION_SQLI_MAX_TOKENS (5) + null byte
82+
#define LIBINJECTION_FINGERPRINT_SIZE 8
83+
%typemap(in, numinputs=0) char fingerprint[] (char temp[LIBINJECTION_FINGERPRINT_SIZE]) {
84+
memset(temp, 0, sizeof(temp));
85+
$1 = temp;
86+
}
87+
%typemap(argout) char fingerprint[] {
88+
$result = SWIG_Python_AppendOutput($result, PyUnicode_FromString($1));
89+
}
7090

7191
%typemap(in) (ptr_lookup_fn fn, void* userdata) {
7292
if ($input == Py_None) {
@@ -77,5 +97,7 @@ for (i = 0; i < $1_dim0; i++) {
7797
$2 = $input;
7898
}
7999
}
100+
%include "libinjection_error.h"
80101
%include "libinjection.h"
81102
%include "libinjection_sqli.h"
103+
%include "libinjection_xss.h"

libinjection/libinjection_error.h

Lines changed: 0 additions & 26 deletions
This file was deleted.

setup.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,40 @@
55
nickg@client9.com
66
BSD License -- see COPYING.txt for details
77
"""
8+
import os
9+
810
try:
911
from setuptools import setup, Extension
1012
except ImportError:
1113
from distutils.core import setup, Extension
1214

15+
16+
def get_libinjection_version():
17+
"""Read the libinjection version from the upstream source file, if available."""
18+
version_file = os.path.join(os.path.dirname(__file__),
19+
'upstream', 'src', 'libinjection_sqli.c')
20+
if os.path.exists(version_file):
21+
with open(version_file) as f:
22+
for line in f:
23+
if '#define LIBINJECTION_VERSION' in line and '__clang_analyzer__' not in line:
24+
# Extract version string from: #define LIBINJECTION_VERSION "x.y.z"
25+
parts = line.strip().split('"')
26+
if len(parts) >= 2:
27+
return parts[1]
28+
return 'undefined'
29+
30+
31+
LIBINJECTION_VERSION = get_libinjection_version()
32+
1333
MODULE = Extension(
14-
'_libinjection', [
34+
'libinjection._libinjection', [
1535
'libinjection/libinjection_wrap.c',
1636
'libinjection/libinjection_sqli.c',
1737
'libinjection/libinjection_html5.c',
1838
'libinjection/libinjection_xss.c'
1939
],
2040
swig_opts=['-Wextra', '-builtin'],
21-
define_macros = [],
41+
define_macros = [('LIBINJECTION_VERSION', '"{}"'.format(LIBINJECTION_VERSION))],
2242
include_dirs = [],
2343
libraries = [],
2444
library_dirs = [],

0 commit comments

Comments
 (0)