libinjection 语义分析通用绕过分析
字数 919 2025-08-20 18:17:47
Libinjection 语义分析通用绕过分析
1. 概述
Libinjection 是一个用于检测 SQL 注入攻击的开源库,它通过语义分析而非简单的模式匹配来识别恶意输入。本文详细分析了一种绕过 libinjection 检测的方法,并深入探讨了其工作原理。
2. 测试环境搭建
2.1 示例代码
#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include "libinjection.h"
#include "libinjection_sqli.h"
int main(int argc, const char* argv[]) {
struct libinjection_sqli_state state;
int issqli;
const char* input = argv[1];
size_t slen = strlen(input);
libinjection_sqli_init(&state, input, slen, FLAG_NONE);
issqli = libinjection_is_sqli(&state);
if (issqli) {
fprintf(stderr, "sqli detected with fingerprint of '%s'\n", state.fingerprint);
}
return issqli;
}
2.2 编译与测试
# 编译
gcc -o bin example1.c libinjection_sqli.c
# 测试1 - 被检测到的SQL注入
./bin "1' and 1=1"
# 输出: sqli with fingerprint of 's&1'
# 测试2 - 未被检测到的SQL注入
./bin "ad1n'-- %a%0aunion select 1,database(),user() -- "
# 输出: not sqli
3. Libinjection 工作原理
3.1 运行流程
Libinjection 内部分为六种解析模式:
- 无符号 标准SQL 模式
- 无符号 MySQL 模式
- 单引号 标准SQL 模式
- 单引号 MySQL 模式
- 双引号 MySQL 模式
- 双引号 标准模式
3.2 核心函数分析
libinjection_sqli_tokenize 是转换内部字符的主要入口函数:
int libinjection_sqli_tokenize(struct libinjection_sqli_state* sf) {
pt2Function fnptr;
size_t* pos = &sf->pos;
stoken_t* current = sf->current;
const char* s = sf->s;
const size_t slen = sf->slen;
if (slen == 0) {
return FALSE;
}
// 初始化
st_clear(current);
sf->current = current;
if (*pos == 0 && (sf->flags & (FLAG_QUOTE_SINGLE | FLAG_QUOTE_DOUBLE))) {
*pos = parse_string_core(s, slen, 0, current, flag2delim(sf->flags), 0);
printf("单引号双引号进入");
sf->stats_tokens += 1;
return TRUE;
}
while (*pos < slen) {
const unsigned char ch = (unsigned char)(s[*pos]);
fnptr = char_parse_map[ch];
*pos = (*fnptr)(sf);
if (current->type != CHAR_NULL) {
sf->stats_tokens += 1;
return TRUE;
}
}
return FALSE;
}
4. 绕过原理分析
4.1 示例payload解析
"ad1n'-- %a%0aunion select 1,database(),user() -- " 的解析过程:
ad1n'首先进入无符号的标准SQL模式- 发现单引号后转到单引号的标准SQL模式
- 获取
ad1n'后 break - 遇到
--进入parse_dash函数
4.2 parse_dash 函数分析
static size_t parse_dash(struct libinjection_sqli_state* sf) {
const char* cs = sf->s;
const size_t slen = sf->slen;
size_t pos = sf->pos;
if (pos + 2 < slen && cs[pos + 1] == '-' && char_is_white(cs[pos + 2])) {
return parse_eol_comment(sf);
}
else if (pos + 2 == slen && cs[pos + 1] == '-') {
return parse_eol_comment(sf);
}
else if (pos + 1 < slen && cs[pos + 1] == '-' && (sf->flags & FLAG_SQL_ANSI)) {
sf->stats_comment_ddx += 1;
return parse_eol_comment(sf);
}
else {
st_assign_char(sf->current, TYPE_OPERATOR, pos, 1, '-');
return pos + 1;
}
}
4.3 parse_eol_comment 函数分析
static size_t parse_eol_comment(struct libinjection_sqli_state* sf) {
const char* cs = sf->s;
const size_t slen = sf->slen;
size_t pos = sf->pos;
const char* endpos = (const char*)memchr((const void*)(cs + pos), '\n', slen - pos);
if (endpos == NULL) {
st_assign(sf->current, TYPE_COMMENT, pos, slen - pos, cs + pos);
return slen;
}
else {
st_assign(sf->current, TYPE_COMMENT, pos, (size_t)(endpos - cs) - pos, cs + pos);
return (size_t)((endpos - cs) + 1);
}
}
4.4 st_assign 函数分析
static void st_assign(stoken_t* st, const char stype, size_t pos, size_t len, const char* value) {
const size_t MSIZE = LIBINJECTION_SQLI_TOKEN_SIZE;
size_t last = len < MSIZE ? len : (MSIZE - 1);
st->type = (char)stype;
st->pos = pos;
st->len = last;
memcpy(st->val, value, last);
st->val[last] = CHAR_NULL;
}
5. 绕过关键点
admin'被转换为S类型--注释后的内容被简单地标记为TYPE_COMMENT(C)- 最终得到的匹配规则为
SC,这种组合不在 libinjection 的检测规则库中 - 注释处理过于简单,没有深入分析注释后的SQL语句
6. 防御建议
- 改进注释处理逻辑,对注释后的内容进行更严格的分析
- 更新指纹库,添加
SC这种组合的检测规则 - 结合其他检测方法,如语法分析,提高检测准确性
- 对URL编码的内容进行解码后再分析
7. 总结
这种绕过方法利用了 libinjection 对注释处理的不足,通过构造特定的注释格式来隐藏恶意SQL语句。理解这种绕过技术有助于改进SQL注入检测机制,提高Web应用的安全性。