本帖最后由 Grav1ty 于 2022-4-30 00:42 编辑
西湖论剑-信呼oa审计复盘
0x01 前言西湖论剑的题目,比赛时没做出来,赛后又花了点时间还是没做出来.最后看了wp,又去复现了下审计过程,学习到很多知识点. 相关工具: - 信呼oa v2.3.1题目源码
- seay源代码审计系统
- phpstudypro
- php7.3.4
- wind10
- vscode
- xdebug
复制代码
0x02 任意php文件包含代码分析使用代码审计工具在include/View.php的第88行定位到敏感函数include_once,
回溯文件包含中的变量$mpathname,
在本文件的第71和72行发现了变量定义和赋值的操作. 先对第71行的代码进行分析: 由图 2 可以清楚的看到变量$mpathname由其他两个变量$tplpaths和$tplname决定.回溯这两个变量,分别在本文件的第67行和第70行发现最近赋值操作: - $tplpaths = ''.$temppath.''.$d.''.$m.'/';
- $tplname .= '.'.$xhrock->tpldom.'';
复制代码
回溯$temppath,在66行找到最近赋值操作
- $temppath = ''.ROOT_PATH.'/'.$p.'/';
复制代码
回溯$p,在本文件的第4行:
到这里大概可以感觉到$tplpaths的路径是写死了的,所以就暂时放弃变量$tplpaths去回溯$tplname. 回溯$xhrock,在本文件的第37行发现$xhrock的定义:
- $xhrock = new $clsname();
复制代码
回溯$clsname,在本文件第36行发现定义
- $clsname = ''.$m.'ClassAction';
复制代码
回溯$m,在第8行发现最近一次赋值操作:
- $m = $rock->get('m', $m);
复制代码
跟进get()这个函数,最后发现其核心调用在include/class/rockClass.php的第105行,
可以看到这个函数的中的$val可控.继续跟进jmuncode(),到本文件的第127行
其函数逻辑大致为对传入的$s进行合法行检测以及特殊值的一些特殊处理.配合xdebug测试发现只要$_GET['m']的值不是一些sql关键字,$m的值等于$_GET['m'].也就是说,这里的变量$m可以被用户使用$_GET['m']传参进行控制.也就是$xhrock是能够进行控制的.
由于$xhrock->tpldom这种形式是在获取一个成员属性,全局搜索以下tpldom,在include/Action.php文件中的第43行发现定义.
可以看到最后tplname表示文件的后缀名为html,没法利用,看来此路不通. 继续对第72行的代码进行分析: 可以看到第72行代码的形式$mpathname = $xhrock->displayfile;同样为获取某个类的成员属性,再次全局搜索displayfile,总共得到14个搜索结果.
每个文件点进去看了一下,在webmain/index/indexAction.php下发现惊喜!
可以看到这个文件中的$displayfile是以.php为后缀的变量,而变量$displayfile最后可以决定我们文件包含$mpathname的取值,也就是说这里可能存在一个.php的文件包含. 继续回溯$surl,发现其最近赋值在本文件的第250行 $surl = $this->jm->base64decode($this->get('surl'));
跟进get(),最后同样来到include/class/rockClass.php的第105行,和$m赋值时调用的函数一样,也就意味着这里传入base64decode()函数的内容可控. 再来分析分析外面的base64decode()函数,其函数体位于include/chajian/jmChajian.php的第93行
通过阅读可以发现其逻辑主要是对传入的形参$str判断是否为空以及进行敏感字符替换,再返回其base64解码的内容. 这里就存在一个很明显的逻辑错误:很明显base64加密后的字符是不存在! . :,所以对恶意内容进行base64编码后传入最后是可以被还原的.也就是说这里的$surl是可以被控制的. 回到include/View.php的第72行,看看是否存在一个利用点使之能得到 /webmain/index/indexAction.php下的indexClassAction->displayfile.这里需要跟踪的变量是$xhrock,而前面以及分析过了$xhrock的构造流程也得出结论$xhrock部分可控. 这里$xhrock可控还存在一个前提是存在文件$actfile,跟踪$actfile,其定义在此文件下的第30行: $actfile = $rock->strformat('?0/?1Action.php',$actpath, $m);
跟进strformat()方法,来到include/class/rockClass.php下的第551行:
发现函数体里调用了stringformat()方法,继续跟进,到文件的第542行
通过阅读strformat()以及stingformat()的代码可以了解到strformat函数的逻辑为找到$m操作对应的php文件.而可控变量$displayfile位于/webmain/index/indexAction.php中,这里可以构造$m的值为index.在回过来看看变量$xhrock就已经等于new indexClassAction了.一切都是这么流畅! 在第42行,发现一个调用成员方法: $actbstr = $xhrock->$actname();
跟踪$actname,发现其定义在38行: $actname = ''.$a.'Action';
跟踪$a, $a = $rock->get('a', $a);
可以看到$a赋值所使用的方法同变量$m相同,也就意味着$a也可控,那我们可以直接给控制$a为getshtml.从而实现调用webmain/index/indexAction.php中indexClassAction的getshtmlAction()函数,在配合$surl可控,就可以实现任意.php文件读取. 漏洞利用现存在文件phpinfo.php,内容为: <?php phpinfo();
与include/View.php之间的目录关系为 view.php/../../phpinfo.php先登录进信呼协同办公系统后台,再构造url参数,访问 ?m=index&a=getshtml&surl=Li4vLi4vcGhwaW5mbw==其中,Li4vLi4vcGhwaW5mbw==为../../phpifobase64编码后的结果.
可以看到成功包含已知相对路径下的phpinfo.php文件 0x03总结本次代码审计的流程主要使用敏感函数参数回溯的方法,通过代码审计工具定位到敏感函数include_once,回溯敏感函数中关于参数$mpathname的定义以及赋值的操作.再发现其中涉及到函数以及变量再进行回溯,直到发现漏洞点.这种方法的优点可以通过敏感函数或者敏感关键字快速挖掘到想要的漏洞,但由于没有通读代码,对程序的整体框架了解得不够深入,可能会忽略掉部分逻辑漏洞 其次,再使用敏感函数参数回溯法的时候,可能在回溯过程中遇到的变量越来越多,我们不可能短时间内对每个变量和每个函数都进行回溯和跟踪,要学会判断在什么暂停回溯当前变量而去回溯其他变量.有时候代码审计的战线可能会拉的很长,我们得时刻专注和记忆过程中遇到的变量,只有清楚每个变量的变化过程才能更好的挖掘漏洞. 以上就是我本次审计过程中的主要思路以及操作流程,可能过程中存在一些欠佳甚至错误的操作.代码审计入门,希望师傅们多多指出不足.
|