SQL语法

0x00 information_schema数据库

该库是mysql数据库中记录所有表的信息,为我们提供了各种状态、权限和配置信息等等。

Mysql中的INFORMATION_SCHEMA数据库包含了一些表和视图,提供了访问数据库元数据的方式。

元数据(数据词典、系统目录)是关于数据的数据,如:数据库名或表名,列的数据类型,访问权限等。

说明:

  • SCHEMATA:数据库中的信息,一般显示出数据库中的各个数据库及其简要信息
  • TABLES:数据库中所有表的信息
  • COLUMNS:表的所有列信息
  • STATISTICS:表的索引信息
  • USER_PRIVILEGES:用户权限信息
  • SCHEMA_PRIVILEGES:数据库权限信息
  • TABLE_PRIVILEGES:表权限信息
  • COLUMN_PRIVILEGES:列权限信息
  • CHARACTER_SETS:关于可用字符集信息
  • COLLATIONS([kə’leɪʃn] 核对,小吃,这里意思是排序规则):可用字符集的排序信息
  • COLLATION_CHARACTER_SET_APPLICABILITY:指明可用与校对的字符集
  • TABLE_CONSTRAINTS:描述存在约束的表
  • KEY_COLUMN_USAGE([ˈjusɪdʒ]使用;用法;惯例):描述具有约束的键列
  • ROUTINES:关于存储子程序的信息,不包含自定义函数
  • VIEWS:视图信息
  • TRIGGERS:触发器信息
1
SELECT * FROM INFORMATION_SCHEMA.ROUTINES;
  • 不同数据库的sql语句不同

0X01 CURD

插入

1
2
insert test.a values (all);
insert test.a (id, name) values (1, 'jack');

删除

1
delete from test.a where id >= 10 and id <= 100;

修改

1
2
3
4
5
6
7
8
alter table test.a 
--添加
add constraint primary key(id);
--删除
drop primary key;


add column <name> <dataType> [restriction]

查询字符串

  • ‘_’为任意单个字符,’%’为任意长度字符,使用LIKE来判断,但是匹配字符串不包含通配符时,可以用‘=’来判断。
1
2
3
SELECT * FROM INFO
WHERE
description NOT LIKE 'a%bb_'
  • 数据库字符集为ASCII时,一个汉字需要两个’_’,当字符集为GBK时,只需要一个。

e.g.

查询以‘DB_’开头,且倒数第三个字符为i的课程的详细情况。

1
2
3
SELECT * FROM COURSE
WHERE
CNAME LIKE 'DB\_%i__';

表的连接

1
2


建立索引

1
2
3
4
5
6
7
8
9
10
CREATE [UNIQUE][CLUSTER] INDEX <indexName>
ON <tableName>(<columnName>[order][,<columnName>[order]]...);

e.g.
create unique index Stusno
on Student(Sno);

e.g.
create unique index SCno
on SC(Sno ASC, Cno DESC);

给表取别名(用于自身连接等)

1
2
3
4
5
6
7
SELECT 
FIRST.Cno, SECOND.Cpno
FROM
drasp_excel.xxx AS FIREST,
drasp_excel.xxx AS SECOND
WHERE
FIRST.Cpno = SECOND.Cno;

聚集函数

1
2
3
4
5
6
COUNT(*)
COUNT([DISTINCT|ALL] <columnName>)
SUM([DISTINCT|ALL] <columnName>)
AVG([DISTINCT|ALL] <columnName>)
MAX([DISTINCT|ALL] <columnName>)
MIN([DISTINCT|ALL] <columnName>)
  • 聚集函数除了COUNT之外,都是跳过空值
  • ==WHERE==子句是==不能==用聚集函数作为条件表达式的
  • ==聚集函数作为条件表达式时,只能用于SELECT子句和GROUP BY中的HAVING子句==

GROUP BY 子句

将查询结构按一或多列的值分组,值相等为一组

1
2
3
SELECT Cno, COUNT(Sno)
FROM SC
GROUP BY Cno;

使用变量

1
2
3
4
5
6
7
8
9
10
11
12
13
--第一种
set @num = 1; --or set @num := 1;
select @num;

--第二种
set @username = 'clevercode'

SELECT
@id := id
from sys_user
where username = @username;

--注意在SELECT的时候只能用:=

变量种类

  • 用户变量

不用提前声明,直接使用’@变量名‘,如上面“使用变量”代码块

特点:变量和数据库连接有关,在连接中声明的变量,在存储过程中创建了用户变量后一直到数据库断开,变量才消失。该变量不能跨连接

select @name:=team from organize

如果返回多条的@name只保存最后一条记录

需求:

在建立视图较为困难的情况下,选择建立一张新表

新表需要某一个表的一个字段所有情况作为字段,同时当别的表进行CUD时做出相应的变动,某个人的某种类型题目分数相加。

  • 说实话这篇博客并不太明白,讲到了动态查询列,问题基本是一样的,但是似乎不是简单的sql变量语句拼接

杂谈1 杂谈2

0x02 授权:授予与收回

  • GRANT

    1
    2
    3
    4
    GRANT<权限>[,<权限>]...
    ON<对象类型><对象名>[,<对象类型><对象名>]...
    TO <用户>[,<用户>]... --这里写PUBLIC就是全体用户
    [WITH GRANT OPTION]; --是否可以传播当前权限

    e.g.

    1
    2
    3
    4
    5
    6
    7
    8
    GRANT SELECT
    ON TABLE billboard.organize
    TO user1;

    GRANT UPDATE(billboard.organize.team), INSERT, DELETE
    ON TABLE billboard.organize
    TO user2
    WITH GRANT OPTION;
  • REVOKE

    1
    2
    3
    REVOKE <权限>[,<权限>]...
    ON <对象类型><对象名>[,<对象类型><对象名>]...
    FROM <用户> [,<用户>]...[CASCADE|RESTRICT];

    e.g.

    1
    2
    3
    4
    5
    6
    7
    8
    REVOKE UPDATE(Sno)
    ON TABLE Student
    FROM user4;

    REVOKE SELECT, INSERT
    ON TABLE SC
    FROM USER5
    CASCADE;
  • 创建数据库模式的权限

    CREATE USER <username> [WITH][DBA|RESOURCE|CONNECT]

    • 只有超级用户才能创建新的数据库用户
    • 有三种权限
    权限 CREATE USER CREATE SCHEMA CREATE TABLE 登陆数据库,执行查询操作和操纵
    DBA :v: :v: :v: :v:
    RESOURCE :x: :x: :v: :v:
    CONNECT :x: :x: :x: :v:但必须有相应权限
  • 角色

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    --创建
    CREATE ROLE <rolename>

    --授权
    GRANT <权限>[,<权限>]...
    ON <对象类型>对象名
    TO <角色>[,<角色>]...

    --将一个角色授予其他角色或者用户
    GRANT <角色1>[,<角色2>]...
    ON <角色3>[,<用户1>]...
    [WITH ADMIN OPTIOIN]; --是否可授予别的角色或对象

    --角色权限的收回
    REVOKE <角色1>[,<角色2>]...
    ON <对象类型><对象名>
    FROM <角色>[,<角色>]...

T_SQL语法

0x00 表的建立

1
2
3
CREATE TABLE <TABLE NAME> (

)

0x01 表的连接

(如果不使用on直接添加在where处,就是全表生成笛卡儿积,再做处理,这样产生了大量的临时表,性能极低,比较好的方法是比较好的方法是==使用ON关键字先处理好相应的数据源==,再使用WHERE)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
---------------------内连接
SELECT student.studentono, sname, final
FROM student INNER JOIN score
ON student.studentno = score.studentno
WHERE score.courseno = student.courseno

---------------------外连接
-----左外连接
SELECT student.studentno, sname,, usually, final
FROM
student LEFT JOIN score
ON student.studentno = score.studentno
WHERE
substring(student.studentno, 1, 2) = '16'

-----右外连接
SELECT student.studentno, sname, usually, final
FROM
student RIGHT JOIN score
WHERE
student.studentno = score.studentno

-----全外连接
SELECT courseno, tname, major, teacher.teacherno
FROM
teacher FULL JOIN teach_class
WHERE
...

-----多表连接
SELECT *
FROM
student JOIN score ON ...
JOIN course ON ...
JOIN teacher ON ...
WHERE
...

-----交叉连接:全表笛卡儿积,没有where的情况,基本不用
SELECT *
FROM
student CROSS JOIN score

-----合并结果集,使用UNION
SELECT * FROM student
UNION [all] --all可选,如果写上的话,将重复的行也加上,否则删除
SELECT * FROM course

0x02 子查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
--子查询作表达式,用在WHERE 或者 IN

--子查询做数据关联,给表取别名,数据库原理上几种比较复杂的操作,记得看看!!

--利用子查询生成派生表(本质就是在 FROM子句 中 使用子查询)
SELECT TT.studentno, TT.courseno,
TT.final*0.8 + TT.usually*0.2 AS 'ultimate'
FROM (
SELECT *
FROM score
WHERE final > 85
) AS tt
WHERE TT.final * 0.8 + TT.usually * 0.2 > 90

--子查询修改表数据(批量CRUD)

0x03 EXIXTS 和 NOT EXISTS

(查询到第一个就结束)

0x04 游标

(指向内存中结果集的指针,对内存中的结果集进行操作)

1
2
3
4
DECLEAR cursor_name
CURSOR[GLOBAL|LOCAL][FORWARD_ONLY|SCROLL][STATIC|DINAMIC][READ_ONLY]
FOR select_statement
[;]

运用

  • 使用FETCH获取记录信息

  • 游标嵌套

  • 查看游标信息

    • CURSOR__STATUS
    • @@CURSOR_ROWS
    • @@FETCH_STATUS

0x05 大对象的导入

  • BULK INSERT
1
2
3
4
5
6
BULK INSERT st_store(表名)
FROM 'D:/X.txt'
WITH(FORMATFILE = '/(format_file_path)')

BULK INSERT st_store
FROM ''

0x06 索引

  1. 利用SQL Server图形工具进行创建

  2. 利用CREATE INDEX 命令创建索引

    1
    2
    3
    4
    5
    6
    7
    8
    CREATEE [UNIQUE|CLUSTERED|NONCLUSTERED]
    INDEX index_name
    ON
    {table_or_view_name}
    (column[ASC|DESC][,.......n])
    [INCLUDE(column_namme[,.......n])]
    [ON{filegroup_name|default}]
    [; ]
  3. 利用ALTER INDEX命令修改索引

    1
    2
    3
    4
    5
    6
    7
    ALTER INDEX {index_name | ALL}
    ON <table_or_view_name>
    {REBUILD
    [[WITH ( <rebuild_index_option>[,...n])]]
    | DISABLE
    | REORGANIZE
    } [;]
  4. 索引碎片检测

  5. 索引重组

0x07 事务

0x08 触发器

0x09 锁

SQL 注入

0x00 mysql CLI基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 显示版本|用户名|数据库路径|操作系统版本
select version() | user() | @@datadir | @@version_compile_os

#
字符串连接函数
concat(str1, str2, ...)
concat_ws(seperator, str1, str2, ...)
group_concat(str1, str2, ...)

#
显示所有数据库
show databases;

#
使用某数据库
use your_database_name

#
显示所有表
show tables

#
显示某表结构
desc your_table_name

0x01 mysql基本查询

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 基于information_schema

-- 查数据库
select schema_name from information_schema.schemata;

-- 查某库数据表
select table_name from information_schema.tables where table_schema = 'XXX';

-- 查某表所有列
select column_name from information_schema.columns where table_name = 'XXX';

-- 获取某列数据
select *** from ***
  • 小贴士:当数据库使用union查询时,如果union前的数据不存在,那么就会只返回union后的数据,这样就可以显示我们想要看到的数据

0x02 基本注入

思路:通过简单地闭合字符串来构造sql语句。

常见闭合情况:单引号、双引号、括号(以及这几种的组合),还有可能直接采用数字(不用闭合)

结合information_schema使用union查询自己想要的数据

注释方式#, –%20, –, –+

0x03 盲注

没有回显的注入

  • bool
1
2
3
left(database(), 2, 1) > 'h'
substr()
regexp
  • 时间
1
if(ascii(left(database(), 1, 1)) > 115, 1, sleep(5))
  • 报错
1
select 1, count(*), concat(0x3a,  0x3a, (select user()), floor(rand(0) * 2)) as a from information_schema.columns group by a

基于报错的盲注主要就是三块:

  1. 普通查询语句中的count(*)
  2. 分组语句group by后连接函数concat内部floor(rand(0) * 2),这里的形式不定,只要满足用其来分组就行
  3. 分组语句group by后连接函数concat,你想要通过报错查询的信息,比如:database()
  • 合并之后就是select count(*) from YOUR_SCHEMA.YOUR_TABLE group by concat(@@version, floor(rand(0)*2);
  • 当然可以在上式基础上更改成更多变式,比如子查询(表被限制)、使用局部变量(rand被限制)

函数集合

0x00 Mysql

截取字符串

  • mid(str, start, length)
  • substr(str, start, length) substring(str, start, length)
  • left(string, length)
    • ord()该函数可以和上述几个组合将单个字符(若为字符串则转换最左边的的字符)转为ascii

正则

regexp(暂用于盲注)

1
2
3
4
5
6
7
8
9
10
11
12
select 1 from information_schema.tables where table_schema = 'your_table_schema' and table_name regexp '^[a-z]' limit 0, 1

-- 用于查询在该数据库内的表第一个字符是否为小写字母
-- 此时的limit是针对table_schema的,这里如果明确指定了table_schema,不用也可以

-- 接下来,调整正则,缩小范围
'^[a-n]'
'^n[a-z]'
...
'^newview$'

-- IMPORTANT: regexp的匹配对象是‘某数据库内部所有的表’,出现表名newuser和newview时,就会在v和u处出现两个甚至多个匹配点,这时候会返回多个,可以写个工具跑一遍

0x01 Mssql

伪正则

1
2
3
4
5
6
7
8
-- top 1 是选择第一个,实际是select 1
select top 1 1 from information_schema.tables where table_schema = 'your_database_name' and table_name like '[a-z]%';

-- 查询第二行表名
select top 1 1 from information_schema.tables where table_schema = 'your_database_name' not in (select top 1 table_name from information_schema.tables) and table_name like '[a-z]%';

-- 查询顺序
'n[a-z]%' -> 'ne[a-z]%' -> 'new[a-z]%' -> 'news[a-z]%' -> true

TIPS

  • 数据查询优化,很重要的一部分
  • bool型盲注

思筛

  • start:基本的注入就是对于网站输入以及回显情况来使用不同的sql函数,前提是有注入点,这里如果要提高就要熟悉sql函数及它的用法,有思路了再去查。
  • 说到根本上还是思维的问题,思维层面上提升了,一切都会有新的高度,系统思维,搜搜这本书。

待分配

  • 约束攻击
1
2
3
4
5
6
7
8
9
10
11
12
在SQL中执行字符串处理时,字符串末尾的空格符将会被删除。换句话说“vampire”等同于“vampire ”,对于绝大多数情况来说都是成立的(诸如WHERE子句中的字符串或INSERT语句中的字符串)例如以下语句的查询结果,与使用用户名“vampire”进行查询时的结果是一样的。

SELECT * FROM users WHERE username='vampire ';
但也存在异常情况,最好的例子就是LIKE子句了。注意,对尾部空白符的这种修剪操作,主要是在“字符串比较”期间进行的。这是因为,SQL会在内部使用空格来填充字符串,以便在比较之前使其它们的长度保持一致。

在所有的INSERT查询中,SQL都会根据varchar(n)来限制字符串的最大长度。也就是说,如果字符串的长度大于“n”个字符的话,那么仅使用字符串的前“n”个字符。比如特定列的长度约束为“5”个字符,那么在插入字符串“vampire”时,实际上只能插入字符串的前5个字符,即“vampi”。

执行条件:
1.mysql处于ANSI模式。如果是TRADITIONAL模式或者STRICT_TRANS_TABLES模式会报错data too long for column
2.服务端没有对用户名长度进行限制。如果服务端限制了用户名长度就自然就不客能导致数据库截断,也就没有利用条件。
3.登陆验证的SQL语句必须是用户名和密码一起验证。如果是验证流程是先根据用户名查找出对应的密码然后再比对密码,当使用vampire为用户名来查询密码的话,数据库此时就会返回两条记录,而一般取第一条即目标用户的记录,那么传输的密码肯定和目标用户密码匹配不上的。
4.验证成功后返回的必须是用户传递进来的用户名,而不是从数据库取出的用户名。因为当我们以用户vampire和密码random_pass登陆时,其实数据库返回的是我们自己的用户信息,而我们的用户名其实是vampire+若干个空格,如果此后的业务逻辑以该用户名为准,那么就不能达到越权的目的了。

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!