网站建设与维护作业,品牌建设最高境界是培育客户成为,百年建筑网,莱阳房产交易网这里写目录标题 涉及的数据库知识unionorder bydatabase()information_schemalimit--空格注释replaceinto outfilelikeGROUP BYHAVINGGROUP BY、HAVING、WHERE之间的关系regexp 原理信息收集操作系统数据库判断注入点注入点类型POST注入数字型注入字符型注入搜索型注入Insert/u… 这里写目录标题 涉及的数据库知识unionorder bydatabase()information_schemalimit--空格注释replaceinto outfilelikeGROUP BYHAVINGGROUP BY、HAVING、WHERE之间的关系regexp 原理信息收集操作系统数据库判断注入点注入点类型POST注入数字型注入字符型注入搜索型注入Insert/update/delete注入HEADER注入Order By注入 闭合方式闭合转义符号报错得到闭合方式使用表达式来判断是否带括号及引号类型适用无报错时间盲注遍历闭合方式 注释 注入手段联合查询判断字段数判断数据显示位 报错注入XPATH报错注入extractvalue(arg1,arg2)updatexml(arg1,arg2,arg3) 布尔盲注注入流程常用函数payload示例 时间盲注使用场景判断注入点 宽字节注入原理漏洞发现示例 二次注入原理示例 堆叠注入原理示例 特殊场景md5()函数弱类型比较 涉及的数据库知识
union
联合查询将两条SQL语句的结果一起输出
语法select语句1 union select语句2
使用条件前后两个语句的查询结果的字段数相同
order by
结果排序该函数原本用于将查询结果排序
语法select * from table_name order by column_name
通过order by遍历字段序号可以得到原有查询语句输出结果有几个字段
database()
输出当前数据库的库名
information_schema
information_schema为系统自带的数据库
里面有一个tables表该表存放着数据库和数据表的关联其中table_schema为存储数据库名的字段table_name为存储表名的字段
select table_name from information_schema.tables where table_schemadatabase()会输出当前数据库中的所有表名
还有一个columns表该表存放着数据表和字段的关联使用该表查询某表中有哪些字段时需要同时指定是哪个数据的哪个表
select column_name from information_schema.columns where table_nameadminand table_schemadatabase()会输出指定数据表中的所有字段名
limit
用于分页
语法select * from table_name limit n,m;
n表示从第n行开始m表示取m条数据
--空格注释
遇到引号如 select * from user where id$id
可以先将前面的引号闭合再将后面的引号用 -- qwe注释掉
例如如下的payload
2 union select 1,table_name,3 from information_schema.tables where table_schemadatabase() -- qwe此处的qwe只是为了演示出–后面的空格并无实际意义
replace
用于替换字符串
语法REPLACE (String,from_str,to_str)
将String中所有出现的from_str替换为to_str
into outfile
SELECT INTO 语句从一个表中选取数据然后把数据插入另一个表中常用于创建表的备份复件或者用于对记录进行存档。
在 SELECT 查询语句中使用 INTO OUTFILE 参数可以将查询结果保存到文本文件中。
语法SELECT ... INTO OUTFILE file_name
如果题目条件允许可以执行show variables like %secure_file_priv%来查看允许导出结果的目录MySQL服务只允许在这个目录中执行文件的导入和导出操作。
like
LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式
现在我们希望从上面的 “Persons” 表中选取居住在以 “N” 开始的城市里的人
我们可以使用下面的 SELECT 语句
SELECT * FROM Persons
WHERE City LIKE N%提示% 可用于定义通配符模式中缺少的字母
常见通配符% 表示可有零个或多个任意字符; _ 表示需要一个任意字符
GROUP BY
GROUP BY 语句用于结合聚合函数如 COUNT()、MAX() 等根据一个或多个列对结果集进行分组。
GROUP BY 可以配合聚合函数一起使用通过使用聚合函数在分组之后可以对组内结果进行计数COUNT、求和SUM求平均数AVG操作等。
GROUP BY会先按照指定字段的值是否相同来将数据分组
更加详细的介绍可以看下面这篇
GROUP BY与COUNT用法详解_group by count_鲲鹏之上的博客-CSDN博客
HAVING
HAVING 子句可以筛选通过 GROUP BY 分组且聚合后的各组数据。
聚合函数avg、sum、max、min、count不能作为条件放在where之后但可以放在having之后
GROUP BY、HAVING、WHERE之间的关系
在语句的位置上where在group by前 having在group by 之后
在执行顺序上以下面这个SQL语句为例
select city ,count(*) as num from staff where age 19 group by city having num 3;执行where子句查找符合年龄大于19的员工数据group by子句对员工数据根据城市分组。对group by子句形成的城市组运行聚集函数计算每一组的员工数量值最后用having子句选出员工数量大于等于3的城市组。
所以执行顺序为WHERE➡GROUP BY➡聚合函数➡HAVING
regexp
REGEXP的基本语法如下
column_name REGEXP pattern这里column_name 是要搜索的列pattern 是正则表达式模式。
regexp表达式可以放在where后面作为查询的限制条件也可以搭配if或者case作为条件语句
原理
SQL注入就是在数据交互中前端数据传到后台时没有做严格的判断导致传进来的数据被拼接到sql语句中被当作sql语句的一部分进行执行从而导致数据泄露丢失甚至服务器瘫痪。如果代码中没有过滤或者过滤不严谨是会出现漏洞的。
SQL注入攻击的本质是把用户输入的数据当做代码执行
SQL注入的条件是可控变量和可带入数据库查询
信息收集
操作系统
数据库
判断注入点 and 11 页面不变 and 12 页面出现区别 则该地址可能存在注入漏洞 这种方法太过常见可能会被一些站点的防火墙拦截。 此时可以稍微做一些变形比如%26%26 -1 like -1 id 杂乱字符串 若页面出现区别则该地址可能存在注入漏洞 通过运算符检测漏洞 id 2-1id运算结果与原来一致 如果页面也一致则该地址可能存在注入漏洞
如果测试注入点时页面返回404则大概率没有注入点
注入点类型
POST注入
POST和GET注入的区别就是注入点位置发生了变化在浏览器中已经无法直接进行查看与修改。
POST注入高危点网页中的登录框、查询框等各种和数据库有交互的框
手动POST注入一般使用burpsuite工具进行抓包
使用sqlmap自动进行POST注入有两种方法
可以使用--forms对页面的表单进行测试
也可以先用burpsuite抓包并将数据包保存然后使用-r 数据包目录对数据包中的POST注入点进行分析
数字型注入
数字型注入是指在一个期望数字的输入位置注入SQL代码。因为数字型数据通常不需要引号包围所以注入相对简单。例如一个基于数字的 SQL 注入可能在一个像这样的查询中实现
SELECT * FROM users WHERE id [input]如果正常输入为 1那么查询变为 SELECT * FROM users WHERE id 1。如果输入为 1 OR 11则查询变为 SELECT * FROM users WHERE id 1 OR 11这将返回所有用户的数据因为 11 总是真。
字符型注入
字符型注入发生在处理字符串数据的查询中。攻击者必须闭合开放的字符串使用引号然后注入额外的 SQL 代码。例如
SELECT * FROM users WHERE username [input]正常输入可能是 alice查询为 SELECT * FROM users WHERE username alice。如果输入是 ; DROP TABLE users; --那么查询就变成了 SELECT * FROM users WHERE username ; DROP TABLE users; --这会尝试删除整个 users 表。
搜索型注入
搜索型注入通常出现在搜索功能中特别是当查询设计成模糊匹配用户输入时。例如
SELECT * FROM products WHERE name LIKE %[input]%这种情况我们仍然可以只闭合前面的引号
Insert/update/delete注入
当页面中存在修改账号信息、注册账号、删除账号等操作时事实上就是存在插入、修改数据库数据的操作
insert型注入相关的sql语句形式 INSERT INTO table_name VALUES (值1, 值2,....)或者INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
update型注入相关的sql语句形式 UPDATE 表名称 SET 列名称 新值 WHERE 列名称 某值
delete型注入相关的sql语句形式DELETE FROM 表名称 WHERE 列名称 值
这些类型的注入点由于没有select语句所以适合使用
HEADER注入
HEADER注入通过修改请求报文中的请求头部head来进行注入。
PHP中通常使用**$_SERVER**数组来收集请求头信息
手动HEAD注入可以使用burpsuite工具进行抓包
Order By注入
当我们的注入点在SQL语句的Order By关键字之后时常规的联合注入无法实现因为通常回显的内容是前半段语句
那么我们可以考虑使用报错注入和盲注
针对Order By关键字可以使用rand()函数来构造布尔盲注的条件
由于rand(0)和rand(1)返回的内容不同我们可以将判断语句放在rand中这样布尔值不同回显的结果也不同
当然也可以使用时间盲注不过由于查询的条数比较多所以延时时间最好设短一些
闭合方式
闭合
在注入漏洞中构造payload语句的精髓之一在于闭合
不同的场景下我们需要通过猜测源码中的SQL语句、试验不同的方法来构造闭合
转义符号报错得到闭合方式
如果程序开启了sql语句的报错信息可以尝试利用转义符号报错得到闭合方式
当原语句的闭合字符遇到转义字符时会被转义那么没有闭合符的语句就不完整了导致报错通过报错信息我们就可以推断出闭合符。
payload示例如下
?id1\
使用表达式来判断是否带括号及引号类型适用无报错
测试?id2%26%26 11和?id2%26%26 “11这两个payload 如果都回显id2的用户则说明不带括号。此时单双引号需要使用?id1和?id1来进一步判断 哪一个payload如果回显id1的用户说明原SQL语句带括号且使用的是该payload中的引号类型 如果都没有回显说明可能是数字型注入
这种判断方法比较适合在程序关闭了报错信息的情况下使用
时间盲注遍历闭合方式
由于时间盲注的场景中页面没有任何回显我们只能通过延时时间来判断正确的闭合方式
?id1 and sleep(5) --
?id1 and sleep(5) --
?id1) and sleep(5) --
?id1)) and sleep(5) --
?id1) and sleep(5) --注释
常规情况下一般是通过在payload的最后加上注释符将后半段语句整个注释掉
SQL语句中的注释符还是挺多的 --空格 该注释符在GET注入时也常被写作--因为放在url中会被认为是空格符 # #在URL 中会被认为是锚点所以 如果想要在GET注入中使用该注释符需要对其需要进行url编码。#的url 编码为%23 ;%00 分号可以结束当前sql语句而%00会让程序认为这是字符串的末尾
注入手段
联合查询
联合查询主要是运用SQL的union语法
将需要执行的语句与原语句使用union拼接在一起
判断字段数
从order by 1开始一直到order by n观察是否有查询结果用来判断当前数据表有多少字段
判断字段数可以使用二分法先判断1和一个大数n若n无显示则判断n/2
判断数据显示位
若 注入语句-1 union select 1,2,3而页面只输出2
说明第二个字段为当前页面的输出点显示位数据库只输出该字段上的内容
这里使用-1使之前的语句查询无结果即空查询则显示的时候就会显示union之后的第二条语句。
报错注入
报错注入 Error-based injuction就是利用数据库的某些机制人为地制造错误条件使得查询结果能够出现在错误信息中。
当代码中使用die(mysql_error())来返回错误信息时我们可以使用报错注入
XPATH报错注入
通过输入非法路径来导致XPATH syntax error
extractvalue(arg1,arg2)
接受两个参数arg1:XML文档arg2:XPATH语句 条件mysql5.1及以上版本 标准payloadand extractvalue(1,concat(0x7e,(select user()),0x7e)) 返回结果XPATH syntax error.’~rootlocalhost~’
updatexml(arg1,arg2,arg3)
arg1为xml文档对象的名称arg2为xpath格式的字符串arg3为string格式替换查找到的符合条件的数据 条件mysql5.1.5及以上版本 标准payloadand updatexml(1,concat(0x7e,(select user()),0x7e),1) 返回结果XPATH syntax error:’~rootlocalhost~’
布尔盲注
**布尔盲注Boolean-based Blind SQL Injection**属于SQL注入的一种形式。其主要原理是通过向数据库发送特制的SQL查询语句根据应用程序的不同响应通常是真或假来推断数据库中的信息。布尔盲注不直接显示数据库中的数据而是通过观察应用程序对注入恶意SQL语句的响应来推测数据。
注入流程
布尔盲注强调一个盲字所以每次我们只能从返回的布尔值获取有关数据库的某一项信息
例如通过length()函数来判断字符串的长度通过substr()或substring()逐个试出字符串中的每个字符
当然我们想要获取数据库中的某个数据肯定是要从库、表、字段逐步来获取信息
下面是常见的注入流程
求当前数据库长度求当前数据库表的ASCII求当前数据库中表的个数求当前数据库中其中一个表名的长度求当前数据库中其中一个表名的ASCII求列名的数量求列名的长度求列名的ASCII求字段的数量求字段内容的长度求字段内容对应的ASCII
常用函数
ascii() 函数返回字符ascii码值 参数 : str单字符length() 函数返回字符串的长度 参数 : str 字符串left() 函数返回从左至右截取固定长度的字符串 参数str,length str : 字符串 length截取长度substr()/substring() 函数 返回从pos位置开始到length长度的子字符串 参数strposlength str: 字符串 pos开始位置
payload示例
以数据库这一层为例我们需要得到数据库名称的长度然后求数据库名称中有哪些字符
首先获取长度我们可以使用二分法先选一个较大的数将其与lengrh的值进行比较
?id 1 and (length(database())8) --
?id 1 and (length(database())8) --如果长度小于8则再与4进行比较
获取数据库名时以left()函数为例
-- 从左至右截取一个字符
?id 1 and (left(database(),1)s) --
-- 从左只有截取两个字符
?id 1 and (left(database(),2)se) --时间盲注
时间盲注是指基于时间的盲注也叫延时注入根据页面的响应时间来判断是否存在注入。
使用场景
时间盲注使用的优先级并不高通常是在联合注入、报错注入、布尔盲注都无法使用时才会考虑使用
页面没有回显位置联合注入无法使用页面不显示数据库的报错信息报错注入无法使用无论成功还是失败页面只响应一种结果布尔盲注无法使用
判断注入点
依次尝试以下类型的测试payload延时5秒以上则说明判断成立即存在注入
?id1 and if(1,sleep(5),3) -- a
?id1 and if(1,sleep(5),3) -- aif(1,sleep(5),3) 是一个条件表达式其中 1 总是真因为1在逻辑上代表真因此执行 sleep(5)这使得数据库暂停5秒。
IF语句基本语法如下
IF(condition, true_value, false_value)condition: 这是需要评估的条件表达式。true_value: 如果条件为真时返回的值。false_value: 如果条件为假时返回的值。
宽字节注入
原理
计算机底层由二进制存储数据不同的编码映射着不同的二进制数据我们以8位二进制为单字节也称标准字节。宽字节指比标准字节有更多的字节 常见的单字节编码ASCII 常见的宽字节编码GB2312,GBK,GB18030,BIG5等
以GBK为例它以2个字节进行编码
服务端对用户输入的敏感数据主要是单双引号等特殊字符进行了转义如利用mysql_real_escape_string()或addslashes()等函数
它会将用户输入的/?id1转换为/?id1\·这样的目的是为了防止sql注入构造闭合.
此时我们可以使用宽字节注入来摧毁转义当然前提是PHP发送请求到MySql时使用了语句SET NAMES gbk 或是set character_set_client gbk 进行了一次编码
当转义使用的\为ASCII编码而客户端传入的参数被当成GBK等宽字节编码则可以通过在\之前插入一个十六进制字节ASCII码要大于128才到汉字的范围来让mysql以为插入的字节和\是一个中文字符从而吃掉\摧毁转义。
漏洞发现 preg_quote函数 preg_quote() 将字符串中所有正则表达式的特殊字符前添加反斜杠\。这些特殊字符包括. \ * ? [ ^ ] $ ( ) { } ! | : - 语法 string preg_quote ( string $str )参数 $str要进行转义的字符串。 例如 function check_addslashes($string)
{$string preg_replace(/. preg_quote(\\) ./, \\\\\\, $string); //escape any backslash$string preg_replace(/\/i, \\\, $string); //escape single quote with a backslash$string preg_replace(/\/, \\\, $string); //escape double quote with a backslashreturn $string;
} 这段代码分别转义了反斜杠\、单引号和双引号 addslashes 函数 addslashes()是PHP中的一个内置函数用于在某些特殊字符前添加反斜杠 特殊字符包括单引号 双引号 反斜杠 \ 和 NULL 字符 mysql_real_escape_string函数 mysql_real_escape_string的作用和用法和addslashes基本一致
示例
比如使用%df会被PHP当中的addslashes函数转义为“%df\ 。 \ 即url里面的%5c , 对应的url编码是%27那么也就是说%df\ 会被转义%df%5c%27 倘若网站的字符集是GBKmysql使用的编码也是GBK的话就会认为%df%5c%27是一个宽字节。 %df%5c会结合(因为宽字节是占两个字节)也就是縗。后面就有一个 ’这样就能成功构造注入语句。
二次注入
原理
在第一次进行数据库插入数据的时候后端仅仅只是使用了 addslashes 或者是借助get_magic_quotes_gpc 对其中的特殊字符进行了转义但在存入数据库时还是原来的数据数据中一般带有单引号和号然后下次使用在拼凑SQL中所以就形成了二次注入。
示例
插入1‘#转义成1\’#不能注入但是保存在数据库时变成了原来的1’#利用1’#进行注入,这里利用时要求取出数据时不转义
堆叠注入
原理
在堆叠注入中攻击者通常会使用分号(;)将多条SQL命令分隔开来。这种方法的成功执行依赖于后端数据库管理系统的支持因为并非所有的数据库系统都支持一次执行多个查询。
同时也并非什么情况下都能使用堆叠注入例如PHP中的mysql_query函数不支持执行多个语句而mysqli_multi_query函数则允许在一个调用中执行多个SQL语句
由于页面的回显通常只会展示第一个语句的结果所以后面那些语句适合执行一些非查询的SQL语句操作
示例
下面列举了一些堆叠注入中可能用到的SQL操作 修改数据库中的数据项账户密码 ?id1;update users set password12345 where usernameDumb ;-- 增加一条数据 ?id1;insert into users values(3,R1ck,123456); 加载文件 ?id1;select load_file(/etc/passwd);--
特殊场景
md5()函数
题目中可能会计算密码的md5值来比对
$password md5($_POST[password],true);
我们需要了解一下md5()函数中设置true参数有什么用
string md5( string $str[, bool $raw_output false] )
raw_output如果可选的 raw_output 被设置为 TRUE那么 MD5 报文摘要将以16字节长度的原始二进制格式返回。
那么当我们输入的password参数内容在计算md5哈希值后会将哈希值根据转为原始二进制数据的字符串
此时我们可以通过精心构造输入例如ffifdyop
它在经过md5函数后会得到or6]!r,b 那么就可以作为万能密码来使用
例题ctfshow平台的web187
弱类型比较
PHP 是一种弱类型语言它在比较数字和字符串时会进行类型转换
当数字与字符串比较时PHP 通常会尝试将字符串转换成数字。如果字符串的开头部分包含数字那么这些数字将被用来进行比较。如果字符串开头不是数字它通常会被转换为 0。例如比较 123 123 将返回 true而 abc 0 也会返回 true。使用 和 PHP 中 用于值的比较它会进行类型转换。 用于严格比较即值和类型都必须相同因此 123 123 将返回 false。
在SQL中类型转换规则依赖于使用的数据库系统但大多数数据库管理系统如 MySQL也表现出一定的弱类型特征
数字和字符串比较少时字符串会转换为数字如0admin那么如果输入的username是0则会匹配所有开头不是数字或者为0的字符串和数字0
例题ctfshow平台的web188