zl程序教程

您现在的位置是:首页 >  其他

当前栏目

代码审计之逻辑上传漏洞挖掘

漏洞逻辑上传代码 挖掘 审计
2023-06-13 09:15:49 时间

话说一个人的快乐,两个人分享就成为两份快乐,这个我看未必吧,倘若分享与被分享的两者之间是情敌关系,而分享者快乐的原因恰好是… 哈哈,不说了,都懂的;

BUT, 倘若一个技巧被分享出来,那么受益的人我坚信肯定远远不只两个,所以我们更应该学会的是 分享!

Today,简单说说漏洞挖掘中由逻辑缺陷造成的文件上传漏洞。

Tips:传统的MIME验证、客户端js验证、黑名单验证、解析漏洞等这些都比较简单,不在我们讨论的范围内。

0x01 程序员对某些常用函数的错误认识

这些函数有:empty()、isset()、strpos()、rename()等,如下面的代码(摘自用友ICC软件):

#!php

if($operateId == 1){

 $date = date("Ymd");

 $dest = $CONFIG- basePath."data/files/".$date."/";

 $COMMON- createDir($dest);

 //if (!is_dir($dest)) mkdir($dest, 0777);

 $nameExt = strtolower($COMMON- getFileExtName($_FILES[Filedata][name]));

 $allowedType = array(jpg, gif, bmp, png, jpeg);

 if(!in_array($nameExt, $allowedType)){

 $msg = 0;

 if(empty($msg)){

 $filename = getmicrotime()...$nameExt;

 $file_url = urlencode($CONFIG- baseUrl.data/files/.$date."/".$filename);

 $filename = $dest.$filename;

 if(empty($_FILES[Filedata][error])){

 move_uploaded_file($_FILES[Filedata][tmp_name],$filename);

 if (file_exists($filename)){

 //$msg = 1;

 $msg = $file_url;

 @chmod($filename, 0444);

 }else{

 $msg = 0;

 $outMsg = "fileUrl=".$msg;

 $_SESSION["eoutmsg"] = $outMsg;

 exit;

我们来看上面的这段代码,要想文件成功的上传, if(empty($msg)) 必须为True才能进入if的分支,接下来我们来看empty函数何时返回True,看看PHP Manual怎么说,如图

代码审计之逻辑上传漏洞挖掘

很明显, 、0、 0 、NULL、FALSE、array()、var $var; 以及没有任何属性的对象都将被认为是空的,如果var为空,则返回True。 非常好,接下来我们往回看,有这样的几行代码

#!php

$allowedType = array(jpg, gif, bmp, png, jpeg);

if(!in_array($nameExt, $allowedType)){

 $msg = 0;

看见没有,即使我们上传类似shell.php的文件,虽然程序的安全检查把$msg赋值为0,经empty($msg)后,仍然返回True,于是我们利用这个逻辑缺陷即可成功的上传shell.php。

具体详见漏洞案例:

WooYun: 用友ICC网站客服系统远程代码执行漏洞

0x02 程序员对某些常用函数的错误使用

这些函数有iconv()、copy()等,如下面的这段代码(摘自SiteStar)

#!php

public function img_create(){

 $file_info = ParamHolder::get(img_name, array(), PS_FILES);

 if($file_info[error] 0){

 Notice::set(mod_marquee/msg, __(Invalid post file data!));

 Content::redirect(Html::uriquery(mod_tool, upload_img));

 if(!preg_match(//.(.PIC_ALLOW_EXT.)$/i, $file_info["name"])){

 Notice::set(mod_marquee/msg, __(File type error!));

 Content::redirect(Html::uriquery(mod_marquee, upload_img));

 if(file_exists(ROOT./upload/image/.$file_info["name"])){

 $file_info["name"] = Toolkit::randomStr(8).strrchr($file_info["name"],".");

 if(!$this- _savelinkimg($file_info)){

 Notice::set(mod_marquee/msg, __(Link image upload failed!));

 Content::redirect(Html::uriquery(mod_marquee, upload_img));

 //...

private function _savelinkimg($struct_file){

 $struct_file[name] = iconv("UTF-8", "gb2312", $struct_file[name]);

 move_uploaded_file($struct_file[tmp_name], ROOT./upload/image/.$struct_file[name]);

 return ParamParser::fire_virus(ROOT./upload/image/.$struct_file[name]);

我们再来看看这段代码, img_create()函数的逻辑非常严密,安全检查做的很到位。然而问题出在了_savelinkimg()函数,即在保存文件的前面程序员错误的使用了iconv()函数,并且文件名经过了此函数,为什么是错用了呢?因为啊 iconv函数在转码过程中,可能存在字符串截断的问题:

在iconv转码的过程中,utf- gb2312(其他部分编码之间转换同样存在这个问题)会导致字符串被截断,如:$filename= shell.php(hex).jpg (hex为0x80-0x99),经过iconv转码后会变成$filename= shell.php

所以,经过iconv 后$struct_file[ name ])为shell.php,于是我们利用这个逻辑缺陷可以成功的上传shell.php(前提是上传的文件名为shell.php{%80-%99}.jpg)。

具体详见漏洞案例:

WooYun: 建站之星模糊测试实战之任意文件上传漏洞

0x03 历史经典漏洞再次爆发

条件竞争漏洞,这类历史经典漏洞在逐渐淡出人们视线的时候,再次爆发..

接着看下面这段代码(摘自某VPN系统)

#!php

if($_POST[realfile]){

 copy($_POST[realfile],$_POST[path]);

$file = mb_convert_encoding($_POST[file],"GBK","UTF-8");

header("Pragma:");

header("Cache-Control:");

header("Content-type:application/octet-stream");

header("Content-Length:".filesize($_POST[path]));

header("Content-Disposition:attachment;filename=/"$file/"");

readfile($_POST[path]);

if($_POST[realfile]){

 unlink($_POST["path"]);

上述代码的逻辑表面上看起来是这样的(对于攻击者来说):

利用copy函数,将realfile生成shell.php-→删除掉shell.php

这样初看起来没办法利用,但是仔细一想, 这段代码其实是存在逻辑问题的,所以我们可以利用这个逻辑缺陷达到GetShell的目的。

具体利用方法:

copy成temp.php 不断访问temp.php- temp.php生成shell.php- 删除temp.php

具体详见漏洞案例:

WooYun: 国内外多家vpn设备厂商批量漏洞(续集一)

WooYun: PHPCMS前台设计缺陷导致任意代码执行

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/55751.html

phpshell程序员