SQL注入与libinjection分析(3)源码分析之一些重要的结构体说明


SQL注入与libinjection分析系列:
MYSQL命令大全
https://blog.csdn.net/lqy971966/article/details/104922862
SQL注入与libinjection分析(1)SQL注入
https://blog.csdn.net/lqy971966/article/details/105269658
SQL注入与libinjection分析(2)Libinjection
https://blog.csdn.net/lqy971966/article/details/105273753
SQL注入与libinjection分析(3)源码分析之一些重要的结构体说明
https://blog.csdn.net/lqy971966/article/details/106195224
SQL注入与libinjection分析(4)源码分析之整体框架解读
https://blog.csdn.net/lqy971966/article/details/106857168
SQL注入与libinjection分析(5)源码分析之指纹函数fingerprint和查找函数lookup_word剖析
https://blog.csdn.net/lqy971966/article/details/106902216

1. libinjection_sqli_state

libinjection_sqli_state 这个结构体主要输入sql字符串及令牌化后的所有涉及的信息

	struct libinjection_sqli_state {
	const char *s;	/* 输入待检测的sql字符串 如 "1' OR 1=1" */
	size_t slen;	/* 输入待检测的sql字符串的长度 */
	
	/* 输入字符串令牌化(如 s&1)后 去特征库查找的函数指针 在init时候赋值的 这个后面讨论  
	lookup = 
	typedef char (*ptr_lookup_fn)(struct libinjection_sqli_state*, 
					int lookuptype, const char* word, size_t len);
	*/
	ptr_lookup_fn lookup;	
	void* userdata; /* 貌似没啥用 */
	
	/* flags 是每次检查的标志 它的结构体: sqli_flags 
	包括: 没有引号 , 单引号 , 双引号 ,标准sql , mysql */
	int flags;	
	
	/* 字符串在令牌化过程中的指针位置 如 "1' OR 1=1" 
	每次往后移动一位去检测 pos 从0 自加*/	
	size_t pos; 	
	
	/* 记录输入sql字符串对应的每个令牌结构 最大令牌是5个 这个8 为了字节对齐 */
	struct libinjection_sqli_token tokenvec[8]; 
	/* 用于代码中临时指向 tokenvec[i] 每一个令牌结构 用于判断处理 */
	struct libinjection_sqli_token *current; 	
	
	/* 存储输入sql字符串 令牌化后的 令牌 如 数字在令牌化后都变成 1(看 sqli_token_types ) , 
	同上 最大令牌5个+一个结束符 NULL */
	char fingerprint[8];	
	/* debug情况下记录 是否为sqli 的理由 即是在代码哪一行决定的 */
	int reason; 	
	
	/* mysql注释方式为 --加空格 模式  
	MYSQL和标准SQL的区别(注释)在上个博客中已经说明 */
	int stats_comment_ddw; 	
	int stats_comment_ddx;	/* mysql中 --后面没有空格和-一个破折号 的非注释情况处理 */
	int stats_comment_c;	/* c语言模式注释 /x . x/ 未涉及 */
	
	/* 处理# 其中,ANSI模式下#是个操作符, mysql模式下 #是个注释 后面跟注释 */
	int stats_comment_hash;	
	
	int stats_folds; 	/* 用来统计sql输入字符串令牌化后的个数 令牌化一个就+1 */
	
	/* 用于统计一共令牌化了几个字符串 如 "1' OR 1=1" 
	令牌化后就是 s&1 那么 stats_tokens = 3 */
	int stats_tokens; 	
};

2. libinjection_sqli_token

libinjection_sqli_token 记录令牌的信息

struct libinjection_sqli_token {
	size_t pos;	/* 记录sql输入字符串被令牌化的位置 如果转换了 pos+1 */
	size_t len;	/* 记录sql输入字符串被令牌化长度 */
	int  count;	/* 记录@符号开头的数量 */
	
	/* 
		记录每个字符令牌化后的类型 类型在 sqli_token_types 中 
		如 
			TYPE_NUMBER = (int)'1'   /*所有数字会被识别为1 
			TYPE_STRING = (int)'s'   /*单引号和双引号
			……等等
	*/
	char type;	
	
	/* 
		记录字符串开始字符是什么 
			如 CHAR_TICK '`' 
			CHAR_SINGLE  '\''
			或者其他具体字符等
		记录字符串结束字符是什么  
			如 CHAR_NULL  '\0'
			或者其他具体字符等
	*/
	char str_open;	
	char str_close;	
	
	/* 记录输入字符串的每个字符的令牌 一般结尾+结束符\0 */
	char val[32];	
};

3. sqli_flags

sqli_flags 其中的标志位记录 libinjection_sqli_fingerprint 进行令牌/指纹化过程中的参数类型
分四种情况:
1. FLAG_QUOTE_NONE + FLAG_SQL_ANSI 无引号,标准SQL语法
2. FLAG_QUOTE_NONE + FLAG_SQL_MYSQL 无引号,MYSQL语法
3. FLAG_QUOTE_SINGLE + FLAG_SQL_MYSQL 单引号,MYSQL语法
4. FLAG_QUOTE_DOUBLE + FLAG_SQL_MYSQL 单引号,MYSQL语法

enum sqli_flags {
	FLAG_NONE            = 0
	, FLAG_QUOTE_NONE    = 1   /* 1 << 0 */
	, FLAG_QUOTE_SINGLE  = 2   /* 1 << 1 */
	, FLAG_QUOTE_DOUBLE  = 4   /* 1 << 2 */

	, FLAG_SQL_ANSI      = 8   /* 1 << 3 */
	, FLAG_SQL_MYSQL     = 16  /* 1 << 4 */
};

4. lookup_type

  1. LOOKUP_WORD
    /* 查找字符串对应的令牌类型
    返回 sql_keywords 中字符对应的类型 对应的 sqli_token_types 表中的类型 */

  2. LOOKUP_TYPE /* 未涉及 */

  3. LOOKUP_OPERATOR
    /* 查找字符串的操作符对应的令牌类型
    返回 sql_keywords 中字符对应的类型 对应的 sqli_token_types 表中的类型 */

  4. LOOKUP_FINGERPRINT
    /* 输入sql字符串最终的令牌/指纹 进行特征库查找 */

     enum lookup_type {
     	LOOKUP_WORD        = 1
     	, LOOKUP_TYPE        = 2
     	, LOOKUP_OPERATOR    = 3
     	, LOOKUP_FINGERPRINT = 4	
     };
    

5. sqli_token_types

  1. sqli_token_types 是规定的字符串对应的令牌/指纹的转换表

  2. 其中,TYPE_XXX 类型在 sql_keywords (就叫它一个特征库表吧)中给出

  3. 这个 sql_keywords 表一共列出了 9352 种特征情况,并给出每种情况的特征结果,结果就是 sqli_token_types key值

     typedef enum {
     	TYPE_NONE        = 0
     	, TYPE_KEYWORD     = (int)'k' // 关键字 多 如 SELECT ALTER IN FROM
     	, TYPE_UNION       = (int)'U' // 就几个 如 EXCEPT/返回两个结果集的差 UNION/并集 INTERSECT/交集
     	, TYPE_GROUP       = (int)'B' // 分组 GROUP BY/进行分组 ORDER BY/对结果集进行排序 LIMIT/限制查询结果返回的数量
     	, TYPE_EXPRESSION  = (int)'E' // 表达式 如 CASE/判断 SELECT/选择 UPDATE/修改 
     	, TYPE_SQLTYPE     = (int)'t' // sql类型 很多 具体 TYPE_SQLTYPE 参见下面解释
     	, TYPE_FUNCTION    = (int)'f' // sql函数 很多 具体 TYPE_FUNCTION 参见下面解释 
     	, TYPE_BAREWORD    = (int)'n' // 裸词 如 BY DO DATABASE LOCK/LOCK IN FOR OUT WITH
     	, TYPE_NUMBER      = (int)'1' // Number 类型 FLOAT Double True/False也是的
     	, TYPE_VARIABLE    = (int)'v' // sql 变量 如 CURRENT DATE/PATH/TIME 等 及 NULL UNKNOWN
     	, TYPE_STRING      = (int)'s' // 字符串 一般以 ' 和 '' 开头
     	, TYPE_OPERATOR    = (int)'o' // 操作符 如 += >> 及 常用的BETWEEN IS NOT IS NULL等等
     	, TYPE_LOGIC_OPERATOR = (int)'&'  // 逻辑操作符 暂时未涉及
     	, TYPE_COMMENT     = (int)'c' // 注释处理 --空格 # /* */
     	, TYPE_COLLATE     = (int)'A' // 排序 就一个 COLLATE  collate在sql中是用来定义排序规则的
     	, TYPE_LEFTPARENS  = (int)'(' // 左括号
     	, TYPE_RIGHTPARENS = (int)')'  /* not used? */ // 右括号
     	, TYPE_LEFTBRACE   = (int)'{' // 左大括号
     	, TYPE_RIGHTBRACE  = (int)'}' // 右大括号
     	, TYPE_DOT         = (int)'.' // 点好 或者叫做 顿号 
     	, TYPE_COMMA       = (int)',' // 逗号
     	, TYPE_COLON       = (int)':' // 冒号 
     	, TYPE_SEMICOLON   = (int)';' // 分号
     	, TYPE_TSQL        = (int)'T'  /* TSQL start */ // Transact-SQL 是SQL的增强版常见 BEGIN GO GOTO CALL等
     	, TYPE_UNKNOWN     = (int)'?' // 未知符号
     	, TYPE_EVIL        = (int)'X'  /* unparsable, abort  */ // 不能解释的符号
     	, TYPE_FINGERPRINT = (int)'F'  /* not really a token */ // 指纹符号
     	, TYPE_BACKSLASH   = (int)'\\' // 反斜杠 \
     } sqli_token_types;
    

其中,常见数据类型如下所示:

  1. TYPE_SQLTYPE 常见的有:整形,单精度,双精度,可变长度字符,固定长度字符,长型,日期等等。
    Binary ·Varbinary ·Char·Varchar·Nchar·Nvarchar·Datetime ·Text ·Image ·Ntext
    ·Smalldatetime ·Decimal ·Numeric·Float·Real ·Int ·Smallint ·Tinyint
    ·Money ·Smallmoney ·Bit ·Cursor ·Sysname ·Timestamp ·Uniqueidentifier
  2. TYPE_FUNCTION SQL 拥有很多可用于计数和计算的内建函数
    函数的基本类型是:
    Aggregate 合计函数/Aggregate functions AVG/平均值 COUNT/行数 MAX MIN SUM FIRST LAST
    Scalar 函数 UCASE,LCASE/转大小写 LEN/长度 MOD/取余

6. char_parse_map

char_parse_map 列出了 ASCII表每个字符对于的解析函数

例如, ASCII前32个字符都通过 parse_white 函数处理,其不处理+1 往后进行
例如, ASCII 48到57 是数字 0-9 通过 parse_number 函数处理 
其中 129-255 这写字符通过 parse_word 函数处理 
 这里为什么是255 ? 没整明白 不应该只有128吗?

typedef struct libinjection_sqli_state sfilter;
typedef size_t (*pt2Function)(sfilter *sf);
static const pt2Function char_parse_map[] = {
	&parse_white, /* 0 */
	……
	&parse_white, /* 32 */
	&parse_operator2, /* 33 */
	&parse_string, /* 34 */
	&parse_hash, /* 35 */
	&parse_money, /* 36 */
	&parse_operator1, /* 37 */
	&parse_operator2, /* 38 */
	&parse_string, /* 39 */
	&parse_char, /* 40 */
	&parse_char, /* 41 */
	&parse_operator2, /* 42 */
	&parse_operator1, /* 43 */
	&parse_char, /* 44 */
	&parse_dash, /* 45 */
	&parse_number, /* 46 */
	&parse_slash, /* 47 */
	&parse_number, /* 48 */
		……
	&parse_operator2, /* 58 */
	&parse_char, /* 59 */
	&parse_operator2, /* 60 */
	……
	&parse_other, /* 63 */
	&parse_var, /* 64 */
	&parse_word, /* 65 */
	&parse_bstring, /* 66 */
	&parse_word, /* 67 */
	&parse_word, /* 68 */
	&parse_estring, /* 69 */
	&parse_word, /* 70 */
	……
	&parse_word, /* 77 */
	&parse_nqstring, /* 78 */
	&parse_word, /* 79 */
	&parse_word, /* 80 */
	&parse_qstring, /* 81 */
	&parse_word, /* 82 */
	&parse_word, /* 83 */
	&parse_word, /* 84 */
	&parse_ustring, /* 85 */
	&parse_word, /* 86 */
	&parse_word, /* 87 */
	&parse_xstring, /* 88 */
	&parse_word, /* 89 */
	&parse_word, /* 90 */
	&parse_bword, /* 91 */
	&parse_backslash, /* 92 */
	&parse_other, /* 93 */
	&parse_operator1, /* 94 */
	&parse_word, /* 95 */
	&parse_tick, /* 96 */
	&parse_word, /* 97 */
	&parse_bstring, /* 98 */
	&parse_word, /* 99 */
	&parse_word, /* 100 */
	&parse_estring, /* 101 */
	&parse_word, /* 102 */
	……
	&parse_word, /* 109 */
	&parse_nqstring, /* 110 */
	&parse_word, /* 111 */
	&parse_word, /* 112 */
	&parse_qstring, /* 113 */
	&parse_word, /* 114 */
	……
	&parse_ustring, /* 117 */
	&parse_word, /* 118 */
	&parse_word, /* 119 */
	&parse_xstring, /* 120 */
	&parse_word, /* 121 */
	&parse_word, /* 122 */
	&parse_char, /* 123 */
	&parse_operator2, /* 124 */
	&parse_char, /* 125 */
	&parse_operator1, /* 126 */
	&parse_white, /* 127 */
	&parse_word, /* 128 */
		……
	&parse_word, /* 255 */
};

7. sql_keywords

sql_keywords 列出了 9352 种特征对应的指纹/令牌字典表
由于篇幅,下表省略了许多。

static const keyword_t sql_keywords[] = {
	{"!!", 'o'},
	……
	{"0&(1)O", 'F'},
	……
	{"0VUVOS", 'F'},
	{"0X", 'F'},
	{"::", 'o'},
	……
	{"ABORT", 'k'},
	{"ABS", 'f'},
	{"ADDDATE", 'f'},
	{"ADDTIME", 'f'},
	{"AND", '&'},
	{"ANY", 'f'},
	{"EXIT", 'k'},
	……
	{"FOR", 'n'},
	{"TOP", 'k'},
	{"TOTAL", 'f'},
	{"UNION", 'U'},
	……
	{"WHEN", 'k'},
	{"WHERE", 'k'},
	……
	{"_UTF8", 't'},
	{"|/", 'o'},
	{"|=", 'o'},
	{"||", '&'},
	{"~*", 'o'},
};
static const size_t sql_keywords_sz = 9352;

参考

源码托管在在github上:
https://github.com/Audi-1/sqli-labs

https://zhuanlan.zhihu.com/p/44292411
https://zhuanlan.zhihu.com/p/44537204
https://www.anquanke.com/post/id/86097

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值