首页
学习
活动
专区
工具
TVP
发布

sql注入学习笔记2-基础知识

前记

今天是sql注入学习笔记,基础知识篇,本文主要介绍sql注入当中的一些基础知识,包括一些重要的trick、文件操作、常用的函数(如字符串连接、截取、编码等函数)等,以及在中间会穿插很多细微的、比较少人留意到的一些tips知识点。

0x00 测试环境

先给出测试环境的数据库表

mysql> show variables like '%log_file%'; 查看日志文件存放位置,后续权限够的情况下,我们可能还会通过这个来拿webshell

0x01 一些重要的trick

0x011 查看日志文件存放位置

0x012 查看数据库编码情况

show variables like 'char%'; 查看编码情况

0x013 指定可外连的数据库用户和ip

这里的意思是允许root用户以这个密码,在任意ip上连,实际中肯定不能这样

mysql> grant all privileges on *.* to 'root'@'%' identified by 'admin' with grant option;

mysql> flush privileges;

0x014 关于mysql账号密码

mysql数据库的账号密码在mysql.user这个表中,MYSQL数据库的认证密码有两种方式,MYSQL 4.1版本之前是MYSQL323加密,MYSQL 4.1和之后的版本都是MYSQLSHA1加密,MYSQL数据库中自带Old_Password(str)和Password(str)函数,它们均可以在MYSQL数据库里进行查询,前者是MYSQL323加密,后者是MYSQLSHA1方式加密。

例如

mysql> select user,password from mysql.user ;

例如

localhost root *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B

查询出来的值只取*后面的内容拿去解密即

81F5E21E35407D884A6CD4A731AEBFB6AF209E1B

这个才是密文

要解密mysql中查出来的密码,可以在这个网站上解密

选择对应的mysql解密方法或者选择sha1解密都行

MYSQL 4.1版本之前的就选择mysql323这个解密方法

MYSQL 4.1和之后的版本就选择MySQL4.1/MySQL5+ (40 bytes)或者sha1都行

ps:

mysql> select user,authentication_string from user;

有些版本的数据库原有的密码字段名是这个

0x015 模糊匹配

rlike、regexp、like

其中rlike、regexp的用法都和php中正则的用法一模一样

like中使用%表示匹配任意个数的任意字符

匹配username中包含字母j的行

0x016 注释符

# 最普通的单行注释,实际渗透中最好用之前用url编码下,效果会更好,编码后的值为 %23

-- - 注意中间的空格哦

-- +

`` 在bypass一些比较老的waf可能还会有些用

/**/ 常规内联注释--可代替空格,绕过空格过滤

/*!*/

/*!50000 */ mysql 5通用,带版本内联注释

注意:多行注释符(在mysql下需要能闭合 才有效):/* */或` `(反引号)等

0x017 Mysql内置变量,搜集数据库信息时会用到

version() 当前数据库详细版本号,注意,针对mysql 4和5的注入方式是完全不一样的

database() 当前所在的数据库

user() 当前数据库用户权限

@@datadir 数据文件的存放目录

@@basedir 数据库的安装路径

@@version_compile_os 宿主系统平台是什么

@@hostname 当前机器的机器名,可不是域名哦

null 特殊工具,因为它可以匹配任意数据类型,在遍历字段个数时可能会用到

0x02文件操作(读写)

·文件写入--需要有写的权限,通常只有root有

一定要用绝对路径--限制了必须能使用引号

select * into outfile '绝对路径'

select * into dumpfile '绝对路径'

如果是dll,so,exe,必须二进制写,尝试导出udf时可能会用到

tips:

·可以使用16进制和char()来绕过对字符串关键字的过滤

至于使用char()函数来写入,我们可以使用python来辅助构造payload

将刚刚得到的hex放进python里面执行得到payload

关于绝对路径

linux和windows下都可以使用 /

windows下还可以使用 \\ 注意是两个反斜杠(即反斜杠要转义一下)

写入的文件必须是原来不存在的,若是原来已经存在了的文件,我们无法覆盖它写入,会产生一个错误

这里要注意我们使用char()和使用0x16进制的时候都不要加单引号,否则就当成一个字符串来写入了,而不会unhex处理,例如

文件读取--绝对路径

load_file(绝对路径)

0x03常用函数

字符串连接函数--3个

-----MySQL的concat和group_concat函数在连接字符串的时候,只要其中一个是NULL,那么将返回NULL(注意:group_concat也是这样,验证过了 5.x版本)

concat(str1,str2,str3...)中间只要字符串有一个为null,最后结果也为null,注意 ‘null’ 和 null 不一样(区别同 ‘1’ 和 1)

concat_ws(‘指定分隔符’,str1,str2,str3...)它会自动忽略中间的空值,只有分隔符为空,整体才返回空

group_concat(field_name1, field_name2, field_name3...)

把某个字段下的所有数据全部连接成一个字符串,注意有长度限制,默认1024,(默认使用逗号隔开)(不会受limit的限制)

实例测试如下

截取函数--5个

注意在mysql中的所有字符串截取操作[除了limit],默认都是从1开始的,并非像代码中的数组是从0开始的

substring(要截取的字符串,从什么地方开始截取,截取多长)

substr(要截取的字符串,从什么地方开始截取,截取多长)

mid(要截取的字符串,从什么地方开始截取,截取多长)

left(str,length)从左往右截取length个字符,左截取

right(str,length)从右往左截取length个字符,右截取

根据官方文档的描述substring和substr两者基本没有任何区别,所以一个被过滤了的时候可以使用另一个去替代。

而mid()是mysql 专有的字符串截取,也就是说只有在mysql中有,mssql和oracle以及pgsql中都没有。

Tips:

username第一行内容为mjc,长度为3,若截取第四个字符,则输出的ascii码值为0--对应的是null空字符--这个特点可以用于盲注的判断(这个以后讲)

select ascii(substring((select username from user limit 0,1),4,1));

字符串填充,跟代码中的字符串填充是一个意思,注意,如果被填充的位置原来有数据则会被直接覆盖,我们可利用这种方式来查数据

lpad(str,len,padstr)

rpad(str,len,padstr)

用字符串 padstr对 str进行左填充或者右边填充直至它的长度达到 len个字符长度,然后返回填充后的结果。

tips

如果 str的长度长于 len',那么它将被截除到 len个字符,所以可以用这个来代替字符串截断函数,绕过一些过滤了常规的字符串截断函数的waf

返回出现位置--可尝试配合上面的字符串截取函数在读取文件时用

ps:返回的位置从 1 开始

locate(substr,str)第一个语法返回字符串str第一次出现的子串substr的位置。

locate(substr,str,pos)第二个语法返回第一次出现在字符串str的子串substr的位置,从位置pos开始。 substr不在str中,则返回0。

字符串替换--在读取文件时,我们可能需要用到replace()替换一些特殊字符

replace(搜索字符串范围,替换前的子字符串,替换后的子字符串)

这是临时替换,返回替换后的内容,但并不改变原来的内容。

大小写转换,有时候为了减少我们的手工劳动量,可能就需要用到这种转换函数,尽可能的帮我们缩小范围

lower(字符串) upper(字符串)

返回对应的ascii码的函数--2个

ascii(单个字符)

ord(单个字符)

tips:

如果输入多个字符的话,返回第一个字符的ascii码

把指定的数字转换成对应的ASCII码字符,n久以前 bypasswaf的惯用招数,各类编码绕过waf也是最常见的一种方式

char(num)

进制转换函数--3个

16进制转换,导出udf的时候可能会用到

hex() unhex()

conv(num,from_base,to_base) 经常会用来绕过某些编码过滤

Conv(数字,进制1,进制2)返回 数字 从进制1 转为 进制2 的内容

mysql> select conv(11,10,16);

tips:hex()和unhex()都是从右到左读取字符的,如unhex(223)读取的是 23和2,而不是22和3 (0x23代表的是#)

case用法--相当于sql中的’switch’语句

case..when..then..when..then..else..end

语法:

CASE search_expression

WHEN expression1 THEN result1

WHEN expression2 THEN result2

...

WHEN expressionN THEN resultN

ELSE default_result

搜索CASE表达式,使用条件确定返回值.

语法:

CASE

WHEN condition1 THEN result1

WHEN condistion2 THEN result2

...

WHEN condistionN THEN resultN

ELSE default_result

END

tips

有一个类似php的弱比较的特性

0x04 统计(长度、记录)

统计字符串长度

length(字符串)

统计某个表下总共有多少条记录

count(*)

0x05 时间盲注常用函数+if

·时间盲注最常用的两个函数

benchmark(count,expr) 性能测试函数,意思就是执行expr count次

sleep(second) 定时休眠函数

if判断特性,常配合时间盲注一起使用

if(exp,a,b)--表达式exp为真则返回a,否则返回b

0x06 Information_schema数据库的结构+常规利用

(列schema_name跟其他两个表的table_schema是一样的,但名字不同,注意)

查询数据库名字的时候使用schemata表,查询table_name时使用tables表,查询column_name的时候使用columns表,这是有原因的!(重复性问题!在tips中详细说明)

查询所有的数据库名

查询test数据库中的表名

查询user2表的列名

tips

思考:information_schema.tables表中拥有table_schema字段,那为什么查询数据库名字的时候使用schemata表,而不使用tables表呢?

主要还是一个重复性的问题!看下面例子

例如我们使用tables表查询table_schema和使用schemata表查询schema_name

使用schemata表,结果很正常

使用tables表查,会看到很多重复的,这就是区别!

所以查询数据库名字的时候使用schemata表,查询table_name时使用tables表,查询column_name的时候使用columns表

结尾

据此,本文把sql注入中文件操作、常用的函数(如字符串连接、截取、编码等函数)等方面的基础知识基本介绍完了,后续的深入就是常规注入、报错注入、盲注(基于布尔值、基于时间),再深入一点就是实现脚本化自动注入、绕过各种waf等。

看不过瘾?合天2017年度干货精华请点击《【精华】2017年度合天网安干货集锦》

别忘了投稿哟!!!

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180209G0Y3XD00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券