discuz! x3.4 漏洞分析

从任意文件删除漏洞到苛刻的getshell,后台SQL注入

Posted by SEVENTEEN on June 22, 2021

前言

   红名谷线下半决赛遇到的一个PHP论坛,据说这个论坛有几个很精彩的漏洞,这次来玩一玩。

   因为找不到什么文章以及漏洞适用环境不符,所以基本上的思路是利用任意文件删除来删除install.lock,然后再重装论坛配置密码,到后台使用命令执行漏洞。

配置环境

   首先到GitHub下载源码,我用的是(https://github.com/mektap/Discuz-3.4-Uyghurche)。

任意文件删除漏洞

   先在首页注册一个账号,然后到设置页面源码里面找到formhash保存起来,一会还要用到。

   对保存这个按钮事件触发的请求包抓包,把数据包中的出生地改成要删除文件的相对路径。

   可以看到页面出生地的地方回显成刚刚修改的相对路径。

   构造一个payload来上传文件,这里的formhash记得改成一开始从前端获取到的那个。

   这里贴一下payload的源码。

<body>
    <form action="http://[网站域名]/home.php?mod=spacecp&profilesubmit=1&formhash=[刚刚得到的formhash]" method="post" enctype="multipart/form-data">
        <input type="file" name="birthprovince" />
        <input type="submit" value="upload" />
    </form>
</body>

   接着,在本地表单上传一张喜欢的照片。(不喜欢的其实也行)

   可以看到data目录下的install.lock已经被删除啦!

   来看一下在源码里面到底发生了什么。首先来到source/include/spacecp/spacecp_profile.php,这里有个submitcheck('profilesubit')需要绕过。

   进来submitcheck()函数之后会进入getgpc()函数,这里需要通过get对profilesubmit传参,var才能获取到其它的get参数。 这就解释了为什么上传文件那个payload中的url带有profilesubmit参数。

令profilesubmit=1

   接着,回调submitcheck()函数,可以看到要满足if的条件才能返回一个TRUE。 可以看到这里对formhash进行了校验,所以在刚刚上传文件那个payload中的url带上从前端获取的formhash。

令formhash为前端获取的formhash。

   这个地方的unlink是补丁前的利用点,补丁添加了formtype的判断, 导致这个unlink不可以利用。不过,下面还有一个unlink可以利用。

   上传文件后会进入这个if语句中,先是if判断是否上传失败,成功的话往if里面走。

   接着,这里对更新前的个人资料做unlink处理,这就解释了为什么要在个人设置中找到一个可控的出生地(birthprovine), 并且把它赋值为要删除文件的相对路径。所以,这里删除的就是我们一开始在burpsuite中构造的出生地(birthprovince)。

   然后在这里开始对数据库内容进行update处理,构造update的sql语句。

   执行update的sql语句,将个人资料出生地变为照片的相对路径。

重装getshell漏洞

   访问/install/index.php,进入重装页面,将数据表前缀改为x');phpinfo();('。不过这里不知道数据库的账号密码,实战中可以尝试下root或者123456这类弱密码。 实在不行的话,牺牲一下自己的vps,远程连接自己的数据库(毕竟拿shell血赚不亏)。

   不过这里有一个前提条件需要注意,目标网站需要没登录过后台。因为登录后台后会把install/index.php删除导致不能重装, 所以拿到站,最好先访问/install/index.php,看看能不能通过重装getshell再决定要不要打payload。

   访问config/config_ucenter.php就可以执行插入的payload了。

   审计一下源码,可以看到进入了203行的elseif分支。

   接着,进入install_uc_server()函数。

   调用save_uc_config()函数保存配置。

   可以看到这里没有任何的过滤就直接写入php配置文件,所以只要闭合')即可代码注入。

后台SQL注入

   注入点在后台的UCenter应用id处。

   构造报错注入payload,页面成功回显。

   来到后台设置的代码段。

   可以看到这里对输入的id进行了addslashes()转义处理。

   这里读取配置文件,对配置缓存进行了更新。 而问题在于此处读取时没有再次转义,转义符号在读取的时候已被解析,造成了二次注入。

   note_exists()函数通过result_first()函数将配置内容select出来。

   从result_first()函数执行的sql语句,也可以看到转义符号已经被解析,构造了SQL注入的payload。

There Is Nothing Below

   

Turn at the next intersection.