*01 extract变量覆盖
PHP extract() 函数从数组中把变量导⼊到当前的符号表中。对于数组中的每个元素,键名⽤于变量名,键值⽤于变量值。
http://127.0.0.1/extract_vul.php?student=&LLY=1
经过 extract() 函数后,会⾃动解析所有参数,并按照对应 key=value 的⽅式进⾏赋值,因此,当我们输⼊代码中预定义好的变量名时,变量的值会被覆盖。
在上例中,将LLY参数进⾏重新赋值,由于找不到对应⽂件,所以 $content 变量为空,student变量不给他赋值,那么这时就可以满⾜其中的 if ($student == $content) 条件。
*02 绕过过滤的空⽩字符
可以引⼊\f(也就是%0c)在数字前⾯,来绕过最后那个is_palindrome_number函数,⽽对于前⾯的数字判断,因为intval会忽略这个字符,所以不会影响。
1. 要求 $req['number']==strval(intval($req['number']))
2. 要求intval($req['number']) == intval(strrev($req['number']))
3. is_palindrome_number()返回False,这个条件只要在⼀个回⽂数⽐如191前⾯加⼀个字符即可实现
*03 多重加密
$login = unserialize(gzuncompress(base64_decode($requset['token'])));
可以看到,需要拿到token,之后进⾏ base64解码->字符串解压缩->反序列化,最终拿到变量 user 的值进⾏判断,如果等于 magedu 则成功拿到 flag,那么我们的思路就是将上⾯的编码过程进⾏逆转 base64加密->字符串压缩->序列化。
因此可以得到如下payload:
*04 SQL注⼊_WITH ROLLUP绕过
查看代码发现,注⼊成功要满⾜2个条件:
1. mysql_num_rows($query) == 1 ,也就是查询返回的结果⾏数为1
2. $key[‘pwd’] == $_POST[‘pwd’] 即查询返回的结果与POST发送的pwd值相同
其中filter 对特殊字符进⾏了过滤,但是没有过滤 or ,因此可以使⽤or将表的内容都查询出来
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
限制查询结果为 1 ⾏,则可以使⽤ limit,offset 关键字
因此Payload可以写为如下语句:
admin' GROUP BY password WITH ROLLUP LIMIT 1 OFFSET 1-- -
使⽤ WITH ROLLUP,此函数是对聚合函数进⾏求和, with rollup是对 group by 后的第⼀个字段,进⾏分组求和。
*05 ereg正则%00截断
1.GET⽅式提交password,然后⽤ereg()正则限制了password的形式,只能是⼀个或者多个数字、⼤⼩写字⺟
2.strlen()限制了⻓度⼩于8并且⼤⼩必须⼤于9999999
3.继续strpos()对password进⾏匹配,必须含有 *-* ,最终才输出flag
因为ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使⽤%00截断正则匹配。
对于另⼀个问题可以使⽤科学计数法表示,计算器或电脑表达10的的幂是⼀般是e,也就是
1.99714e13=19971400000000,所以构造 1e8 即 100000000 > 9999999,在加上 *-* 。于是乎构
造 password=1e8%00*-* ,成功得到答案
这里注意:ereg 函数使⽤需要PHP版本在5.3及以下
*07 sha()函数⽐较绕过
http://127.0.0.1/07.php?name[]=1&password[]=2
=== 会⽐较类型,⽐如 bool sha1() 函数和 md5() 函数存在着漏洞, sha1() 函数默认的传⼊参数类型是字符串型,传⼊数组的情况下出现错误,使 sha1() 函数返回错误,也就是返回 false ,这时 === 运算符就判断为true,需要构造 username 和 password 既不相等,⼜同样是数组类型
*08 SESSION验证绕过
看关键的⼀⾏ if ($_GET['password'] == $_SESSION['password'])
需要session中的password值和⽤户传的⼀样,就可以成功拿到flag
所以我们只需要删掉session值,或者修改session值为⼀个不存在的session,这样服务器获取不到session,则password为空,我们传⼀个空的password的进去即可拿到flag。
我们利⽤的原理如下:
在PHP配置中的默认情况下,Session是⽤Session ID来确定当前对话所对应的服务器Session,sessionID可在cookie中找到,当我们删除cookie中的sessionID后,$_SESSION[‘password’]就会返回空,我们同样传⼊空的password就能绕过了。
*9 urldecode⼆次编码绕过
由于浏览器的⼀次urldecode,再由服务器端函数的⼀次decode,造成⼆次编码,⽽绕过过滤。 如 %2527 ,两次urldecode会最后变成 '我们将 flag 中第⼀个字符 L 进⾏url⼆次编码, URL 编码为: %4c ,⼆次编码为 %25%34%63 ,绕过http://172.22.0.5/10.php?id=%254cLY
*10jsonp劫持
JSONP原理
JavaScript是⼀种在Web开发中经常使⽤的前端动态脚本技术。在JavaScript中,有⼀个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略)。这⼀策略对于JavaScript代码能够访问的⻚⾯内容做了很重要的限制,即JavaScript只能访问与包含它的⽂档在同⼀域下的内容。
利⽤在⻚⾯中创建 <script> 节点的⽅法向不同域提交HTTP请求的⽅法称为JSONP,这项技术可以解决跨域提交Ajax请求的问题。
JSONP的最基本的原理是:动态添加⼀个 <script> 标签,⽽script标签的src属性是没有跨域的限制的。
简单的例⼦:
其中 jsonCallback 是客户端注册的,获取跨域服务器上的json数据后,回调的函数。
简述原理与过程:⾸先在客户端注册⼀个callback, 然后把callback的名字传给服务器。此时,服务器先⽣成 json数据。 然后以 javascript 语法的⽅式,⽣成⼀个function , function 名字就是传递上来的参数 jsonp。最后将json 数据直接以⼊参的⽅式,放置到 function 中,这样就⽣成了⼀段 js 语法的⽂档,返回给客户端。
客户端浏览器,解析script标签,并执⾏返回的 javascript ⽂档,此时数据作为参数,传⼊到了客户端预先定义好的 callback 函数⾥。(动态执⾏回调函数)
可以使⽤PHP模拟后端服务器,返回json内容