首先是说说之前爆的那个注入,相比大家都很头疼就算有注入如果不是root我也解密不了所以我就想着能不能挖一个任意文件下载之类的漏洞然后拿到phpcms的key这样就可以利用注入伪造信息进入后台了。
漏洞文件:/phpcms/modules/content/down.php
文下执行了file_down,我们跟入看看
function file_down($filepath, $filename = '') { if(!$filename) $filename = basename($filepath); if(is_ie()) $filename = rawurlencode($filename); $filetype = fileext($filename); $filesize = sprintf("%u", filesize($filepath)); if(ob_get_length() !== false) @ob_end_clean(); header('Pragma: public'); header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT'); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Cache-Control: pre-check=0, post-check=0, max-age=0'); header('Content-Transfer-Encoding: binary'); header('Content-Encoding: none'); header('Content-type: '.$filetype); header('Content-Disposition: attachment; filename="'.$filename.'"'); header('Content-length: '.$filesize); readfile($filepath); exit; }
没有什么过多的操作直接下载但我们主要看file_down之前的操作
这里是get提交a_k然后提供phpcms的key进行解密最后赋值判断a_k是否TRUE(也就是能够解密则有值,不能解密这个功能就在if这里结束了)所以我们先过了这个判断。然后我们可以想到之前的那个注入最后导致注入的位置也就是down这个位置,我们看看down这里
同样提交了a_k也同样支持了decode,也就是我们最后利用的注入语句是可以用于decode的,那么我们现在就需要生成encode的语句然后请求这里让download函数decode
if(preg_match('/(php|phtml|php3|php4|jsp|dll|asp|cer|asa|shtml|shtm|aspx|asax|cgi|fcgi|pl)(.|$)/i',$f) || strpos($f, ":\")!==FALSE || strpos($f,'..')!==FALSE) showmessage(L('url_error')); $fileurl = trim($f); if(!$downid || empty($fileurl) || !preg_match("/[0-9]{10}/", $starttime) || !preg_match("/[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/", $ip) || $ip != ip()) showmessage(L('illegal_parameters')); $endtime = SYS_TIME - $starttime; if($endtime > 3600) showmessage(L('url_invalid')); if($m) $fileurl = trim($s).trim($fileurl);
但是我们继续看下面还有后缀以及路径的判断,也就是不允许有php的后缀和不允许有..跳目录和c:\这样的形式。之前在考虑的时候脑子有点大把两个系统特性联想到一起了
if(strpos($fileurl, ':/') && (strpos($fileurl, pc_base::load_config('system','upload_url')) === false)) { header("Location: $fileurl"); } else { if($d == 0) { header("Location: ".$fileurl); } else { $fileurl = str_replace(array(pc_base::load_config('system','upload_url'),'/'), array(pc_base::load_config('system','upload_path'),DIRECTORY_SEPARATOR), $fileurl); $filename = basename($fileurl); //´¦ÀíÖÐÎÄÎļþ if(preg_match("/^([]*?)([-][-])([]*?)/", $fileurl)) { $filename = str_replace(array("%5C", "%2F", "%3A"), array("\", "/", ":"), urlencode($fileurl)); $filename = urldecode(basename($filename)); } $ext = fileext($filename); $filename = date('Ymd_his').random(3).'.'.$ext; $fileurl = str_replace(array('<','>'), '',$fileurl); file_down($fileurl, $filename); } }
还对c:/也进行了判断,如果存在c:/则跳转,虽然下面没有exit并不影响操作但是我们的下载功能是else中所以没法利用,还是得从根本上解决问题。
和P牛讨论了一会觉得协议应该行得通(协议我不是很常用所以等P牛测试说结果)但又耐不住手痒就自己几番测试发现
C:www/1.txt这样的路径window是可以的。最后和P牛聊发现他以前看过这种特性。
最后说明一下,最新版无限制,低版本win限制。
【via@91ri team -小续】