SQLChop — это новый механизм обнаружения SQL инжектов, построенный на выявлении определённых маркеров SQL и анализе синтаксиса. Принимаемые данные (URLадрес, body, cookie и т. д.) вначале будут декодированы и приведены к виду, наиболее близкому к виду, соответствующему выполняемой в веб-приложении функции, затем будет произведён анализ для классификации результата. SQLChop основывается на знании компилятора и теории автоматов и работает на временной сложности O(N).
Исходный код доступен здесь: https://github.com/chaitin/sqlchop
Документация:
Есть возможность проверить свои запросы онлайн, поиграться с SQLChop. По этой ссылке введите интересующие вас SQL запросы и посмотрите, будут ли они классифицированы как попытка SQL-инъекции.
Зависимости SQLChop
Альфа релиз SQLChop, предназначенный для тестирования, включает C++ заголовок и разделяемые объекты, библиотеку python, а также несколько примеров использования. Этот выпуск был протестирован на большинстве дистрибутивов Linux.
Если будете использовать с Python'ом, то нужно установить protobuf-python, например, так:
$ sudo pip install protobuf
Если вы используете C++, то вам нужно установить protobuf, protobuf-compiler и protobuf-devel, например так:
$ sudo yum install protobuf protobuf-compiler protobuf-devel
Собираем SQLChop
Загрузите последний выпуск с https://github.com/chaitin/sqlchop/releases
Make
Запустите python2 test.py или LD_LIBRARY_PATH=./ ./sqlchop_test
is_sqli
Получив строку запрос определим, является ли SQL-инъекцией
Параметр: строка
Возвращаемое значение: тип bool, возвращает True для SQLi (инжект), возвращает False для нормальных случаев.
>>> from sqlchop import SQLChop >>> detector = SQLChop() >>> detector.is_sqli('SELECT 1 From users') True >>> detector.is_sqli("' or '1'='1") True >>> detector.is_sqli('select the best student from classes as the student union representative') False >>> detector.is_sqli('''(select(0)from(select(sleep(0)))v)/*'+(select(0)from(select(sleep(12)))v)+'"+(select(0)from(select(sleep(0)))v)+"*/''') True
classify
Получив ввод для веб-приложения, classify API декодирует этот ввод и ищут возможный SQL-инжект внутри. Если SQLi найден, то будет выведен запрос.
- Параметр 1: объект со следующими ключами
- urlpath: полный адрес веб-запроса
- body: строка, тело http запроса POST/PUT
- cookie: строка, содержимое куки веб-запроса
- raw: строка, другое обычное поле, которое нуждается в обычном декодировании.
- Параметр 2: детали, если возвращаемое значение True, то будут возвращены детали по запросу, если False, то будет возвращён только результат, которые выполняется быстрее.
- Return: объект содержит результат и запрос
- result: int, положительная величина, показывающая содержит ли веб-запрос sql-инжект
- payloads: список объектов, содержащих key, score, value и source
- key: строка, зарезервирована
- source: строка, показывает, как рабочий запрос включён в оригинальный веб-запрос и как рабочий запрос раскодирован
- value: раскодированный sqli запрос
- score: источник декодированного запроса sqli
Пример:
>>> from sqlchop import SQLChop >>> detector = SQLChop() >>> detector.classify({'urlpath': '/tag/sr/news.asp?d=LTElMjBhbmQlMjAxPTIlMjB1bmlvbiUyMHNlbGVjdCUyMDEsMiwzLGNocigxMDYpLDUsNiw3LDgsOSwxMCwxMSwxMiUyMGZyb20lMjBhZG1pbg==' }, True) >>> { 'payloads': [{ 'key': '', 'score': 4.070000171661377, 'source': 'urlpath: querystring_decode b64decode url_decode ', 'value': '-1 and 1=2 union select 1,2,3,chr(106),5,6,7,8,9,10,11,12 from admin' }], 'result': 1 } >>> detector.classify({'body': 'opt=saveedit&arrs1[]=83&arrs1[]=69&arrs1[]=76&arrs1[]=69&arrs1[]=67&arrs1[]=84&arrs1[]=32&arrs1[]=42&arrs1[]=32&arrs1[]=70&arrs1[]=114&arrs1[]=111&arrs1[]=109&arrs1[]=32&arrs1[]=84&arrs1[]=97&arrs1[]=98&arrs1[]=108&arrs1[]=101&arrs1[]=32&arrs1[]=87&arrs1[]=72&arrs1[]=69&arrs1[]=82&arrs1[]=69&arrs1[]=32&arrs1[]=78&arrs1[]=97&arrs1[]=109&arrs1[]=101&arrs1[]=61&arrs1[]=39&arrs1[]=83&arrs1[]=81&arrs1[]=76&arrs1[]=32&arrs1[]=105&arrs1[]=110&arrs1[]=106&arrs1[]=101&arrs1[]=99&arrs1[]=116&arrs1[]=39&arrs1[]=32&arrs1[]=97&arrs1[]=110&arrs1[]=100&arrs1[]=32&arrs1[]=80&arrs1[]=97&arrs1[]=115&arrs1[]=115&arrs1[]=119&arrs1[]=111&arrs1[]=114&arrs1[]=100&arrs1[]=61&arrs1[]=39&arrs1[]=39&arrs1[]=32&arrs1[]=97&arrs1[]=110&arrs1[]=100&arrs1[]=32&arrs1[]=67&arrs1[]=111&arrs1[]=114&arrs1[]=112&arrs1[]=61&arrs1[]=39&arrs1[]=39&arrs1[]=32&arrs1[]=111&arrs1[]=114&arrs1[]=32&arrs1[]=49&arrs1[]=61&arrs1[]=40&arrs1[]=83&arrs1[]=69&arrs1[]=76&arrs1[]=69&arrs1[]=67&arrs1[]=84&arrs1[]=32&arrs1[]=64&arrs1[]=64&arrs1[]=86&arrs1[]=69&arrs1[]=82&arrs1[]=83&arrs1[]=73&arrs1[]=79&arrs1[]=78&arrs1[]=41&arrs1[]=45&arrs1[]=45&arrs1[]=32&arrs1[]=39'}, True) >>> { 'payloads': [{ 'key': '', 'score': 3.9800000190734863, 'source': 'body: querystring_decode ', 'value': "SELECT * From Table WHERE Name='SQL inject' and Password='' and Corp='' or 1=(SELECT @@VERSION)-- '" }, { 'key': '', 'score': 2.0899999141693115, 'source': 'body: querystring_decode ', 'value': "'SQL inject' and Password" }, { 'key': '', 'score': 2.180000066757202, 'source': 'body: querystring_decode ', 'value': "(SELECT @@VERSION)-- '" }, { 'key': '', 'score': 0.0, 'source': 'body: querystring_decode ', 'value': 'saveedit' }], 'result': 1 }
Настройка
is_sqli API (в sqlchop.py) выявляют SQLi, дают оценку в качестве некоторой величины, вы можете настроить порог этой величины и вызвать действие в соответствии со сценарием использования.
def is_sqli(self, payload): ret = self.score_sqli(payload) return ret > 2.1 # here you can modify and test this threshold def classify(self, request, detail=False): ...