├── AUTHORS ├── CHANGELOG ├── COPYING.ENUM4LINUX ├── COPYING.GPL ├── README.md ├── enum4linux.pl └── share-list.txt /AUTHORS: -------------------------------------------------------------------------------- 1 | AnotherShen <9160174+AnotherShen@users.noreply.github.com> 2 | BrashEndeavours 3 | DidierA 4 | Eric Fish 5 | Joshua Pereyda 6 | kawsay 7 | Mark Lowe 8 | Nicholas Knight 9 | none 10 | NoxNoctis 11 | parchaks <60071271+parchaks@users.noreply.github.com> 12 | Rob 13 | Tim Brown 14 | Tim Brown 15 | Tim Brown 16 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 2021-06-28 Enum4Linux v0.9.1 2 | 3 | * Cleaned up CHANGELOG. 4 | * Thanks to DidierA. 5 | * Added check for writable shares. 6 | * Hid writable shares sheck being -A flag to ensure no change to default behaviour. 7 | * Fixed check for writable shares to cope with Samba being chatty. 8 | 9 | 2021-04-10 Enum4Linux v0.9.0 10 | 11 | * Thanks to jtpereyda, logicsec, mrefish, Kawsay, NoxNoctis, 12 | BrashEndeavours, real-datagram, rastating. 13 | * Added protocol mismatch detection. 14 | * Cleaned up error messages. 15 | * Attempts to guess domain based on 0.in-addr.arpa records 16 | from default DNS server. 17 | * Bug fix: Adjusted regexes to escape hyphens. 18 | * Bug fix: Added error handling for smbclient yielding no OS 19 | info. 20 | * Updated with color coding and fixed globals to remove 21 | errors. 22 | * Bug fix: Fixed -a help typo. 23 | * Bug fix: Misparsing when sharename IPC exists. 24 | * Bug fix: Updated enum4linux.pl to better handle single 25 | quote character in username and password. 26 | * Bug fix: Updated issues with IPC not parsing correctly. 27 | * Added handling of NT_STATUS_INVALID_PARAMETER when finding users. 28 | * Added README.md. 29 | 30 | 2012-11-30 Enum4linux v0.8.9 31 | 32 | * -d option decodes some of the acb_info field including 33 | if account is disabled, password expired, acct locked. 34 | 35 | 2011-06-16 Enum4linux v0.8.8 36 | 37 | * Bug fix: -w option should now work better. Allows 38 | domain crenedials to be used: 39 | -w domain -u user -p pass ... 40 | 41 | 2011-02-21 Enum4linux v0.8.7 42 | 43 | * Bug fix: Now handles apostrophe in group names and 44 | other places. Thanks to Emeric Epaillard and Nicolas 45 | Kerschenbaum for reporting this. 46 | 47 | 2011-02-17 Enum4linux v0.8.6 48 | 49 | * Added -l option to get long domain name via LDAP. 50 | * Bug fix: Redefining variable warning. 51 | 52 | 2011-02-12 Enum4linux v0.8.5 53 | 54 | * -P attempts to get partial password policy info using 55 | rpclient's "getdompwinfo" - polenum.py is still much 56 | better, though. 57 | 58 | 2008-10-23 Enum4linux v0.8.4 59 | 60 | * Bug fix: No longer rejects hostnames containing hyphen. 61 | * Group members output is more parsable. 62 | * Output looks slightly more pretty. 63 | * Help message is more concise. 64 | * -a option is assumed if not other options are used. 65 | * "-K n" option added to keep RID cycling until n 66 | consecutive RIDs don't have usernames. 67 | 68 | 2008-09-16 Enum4linux v0.8.3 69 | 70 | * Now tries to get all SIDs for target before RID cycling. 71 | This should result in local, domain and builtin accounts 72 | being enumerated - even parent domains sometimes. 73 | * Runs polenum.py (if installed) to get password policy. 74 | 75 | 2008-03-28 Enum4linux v0.8.2 76 | 77 | * Changed HTTP link to point at new labs website. 78 | 79 | 2007-12-05 Enum4Linux v0.8.1 80 | 81 | * nmblookup/nbtstat output now contains human-readable 82 | descriptions. 83 | * Clearer messages about why RID cycling has failed 84 | (either can't get SID or RID cycling not allowed). 85 | 86 | 2007-12-05 Enum4Linux v0.8.0 87 | 88 | * Added -a option to try all simple enumeration. You don't 89 | need to remember long complicated command line options now. 90 | * Gets domain groups and domain group memberships now. 91 | enum.exe fails to do this sometimes, so this feature is 92 | actually incompatible with the original. :-) 93 | * Made RID cycling more robust: by default it now tries a list 94 | of common usernames (administrator, guest, root, ...) to get 95 | initial SID. 96 | * The "-k username" take a list of usernames to use when 97 | attempting to get the SID. Previously only supported one. 98 | * -d option implemented. Displays detailed information about 99 | users (primary group, last logon, password change info, etc.) 100 | and groups (description, number of members). 101 | * Attempts to get Domain SID to determine if the host is 102 | in a domain or in a workgroup. Experimental. 103 | * Added -i option to get info about printers. 104 | * During RID cycling, the type of account discovered is 105 | now displayed (Local User, Domain Group, etc.). 106 | -------------------------------------------------------------------------------- /COPYING.ENUM4LINUX: -------------------------------------------------------------------------------- 1 | This tool may be used for legal purposes only. Users take full responsibility 2 | for any actions performed using this tool. The author accepts no liability for 3 | damage caused by this tool. If these terms are not acceptable to you, then do 4 | not use this tool. 5 | 6 | In all other respects the GPL version 2 applies. 7 | -------------------------------------------------------------------------------- /COPYING.GPL: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # enum4linux 2 | A Linux alternative to enum.exe for enumerating data from Windows and Samba hosts. 3 | 4 | Enum4linux is a tool for enumerating information from Windows and Samba systems. It attempts to offer similar functionality to enum.exe formerly available from www.bindview.com. 5 | 6 | It is written in Perl and is basically a wrapper around the Samba tools smbclient, rpclient, net and nmblookup. 7 | 8 | The tool usage can be found below followed by examples, previous versions of the tool can be found at the bottom of the page. 9 | 10 | Also see: https://labs.portcullis.co.uk/tools/enum4linux/ 11 | -------------------------------------------------------------------------------- /enum4linux.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # enum4linux - Windows enumeration tool for Linux 3 | # Copyright (C) 2011 Mark Lowe 4 | # 5 | # This tool may be used for legal purposes only. Users take full responsibility 6 | # for any actions performed using this tool. The author accepts no liability 7 | # for damage caused by this tool. If these terms are not acceptable to you, then 8 | # you are not permitted to use this tool. 9 | # 10 | # In all other respects the GPL version 2 applies: 11 | # 12 | # This program is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License along 23 | # with this program; if not, write to the Free Software Foundation, Inc., 24 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 25 | # 26 | # You are encouraged to send comments, improvements or suggestions to 27 | # me at mrl@portcullis-security.com 28 | # 29 | # TODO 30 | # 31 | # * replace system($string) with system($prog, @args). 32 | # 33 | # * Search RID space intellegently. Samba starts accounts at 0, but 34 | # Windows starts at 500. We don't want to search 0-500 on all 35 | # hosts. Maybe check 0-10 and abort if nothing is found. Some SIDs 36 | # on samba servers start RIDs much higher (3000+). How do we make 37 | # sure we get all these. 38 | # 39 | # * Mutliple SIDs can be found on some hosts (samba). 40 | # 41 | # * Output Group Memberships in a more parsable format. 42 | # 43 | use strict; 44 | use warnings; 45 | use Getopt::Std; 46 | use File::Basename; 47 | use Data::Dumper; 48 | use Scalar::Util qw(tainted); 49 | use Term::ANSIColor; 50 | 51 | my $VERSION="0.9.1"; 52 | my $verbose = 0; 53 | my $debug = 0; 54 | my $aggressive = 0; 55 | my $global_fail_limit = 1000; # no command line option yet 56 | my $global_search_until_fail = 0; # no command line option yet 57 | my $heighest_rid = 999999; 58 | my $global_workgroup = ''; 59 | my $global_username = ''; 60 | my $global_password = ''; 61 | my $global_dictionary = 0; 62 | my $global_filename = ''; 63 | my $global_share_file = ''; 64 | my $global_detailed = 0; 65 | my $global_passpol = 0; 66 | my $global_rid_range = "500-550,1000-1050"; 67 | my $global_known_username_string = "administrator,guest,krbtgt,domain admins,root,bin,none"; 68 | my @dependent_programs = qw(nmblookup net rpcclient smbclient); 69 | my @optional_dependent_programs = qw(polenum ldapsearch); 70 | my %odp_present = (); 71 | my $null_session_test = 0; 72 | my %opts; 73 | 74 | ############################################################################### 75 | # The following mappings for nmblookup (nbtstat) status codes to human readable 76 | # format is taken from nbtscan 1.5.1 "statusq.c". This file in turn 77 | # was derived from the Samba package which contains the following 78 | # license: 79 | # Unix SMB/Netbios implementation 80 | # Version 1.9 81 | # Main SMB server routine 82 | # Copyright (C) Andrew Tridgell 1992-199 83 | # 84 | # This program is free software; you can redistribute it and/or modif 85 | # it under the terms of the GNU General Public License as published b 86 | # the Free Software Foundation; either version 2 of the License, o 87 | # (at your option) any later version 88 | # 89 | # This program is distributed in the hope that it will be useful 90 | # but WITHOUT ANY WARRANTY; without even the implied warranty o 91 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See th 92 | # GNU General Public License for more details 93 | # 94 | # You should have received a copy of the GNU General Public Licens 95 | # along with this program; if not, write to the Free Softwar 96 | # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA 97 | 98 | my @nbt_info = ( 99 | ["__MSBROWSE__", "01", 0, "Master Browser"], 100 | ["INet~Services", "1C", 0, "IIS"], 101 | ["IS~", "00", 1, "IIS"], 102 | ["", "00", 1, "Workstation Service"], 103 | ["", "01", 1, "Messenger Service"], 104 | ["", "03", 1, "Messenger Service"], 105 | ["", "06", 1, "RAS Server Service"], 106 | ["", "1F", 1, "NetDDE Service"], 107 | ["", "20", 1, "File Server Service"], 108 | ["", "21", 1, "RAS Client Service"], 109 | ["", "22", 1, "Microsoft Exchange Interchange(MSMail Connector)"], 110 | ["", "23", 1, "Microsoft Exchange Store"], 111 | ["", "24", 1, "Microsoft Exchange Directory"], 112 | ["", "30", 1, "Modem Sharing Server Service"], 113 | ["", "31", 1, "Modem Sharing Client Service"], 114 | ["", "43", 1, "SMS Clients Remote Control"], 115 | ["", "44", 1, "SMS Administrators Remote Control Tool"], 116 | ["", "45", 1, "SMS Clients Remote Chat"], 117 | ["", "46", 1, "SMS Clients Remote Transfer"], 118 | ["", "4C", 1, "DEC Pathworks TCPIP service on Windows NT"], 119 | ["", "52", 1, "DEC Pathworks TCPIP service on Windows NT"], 120 | ["", "87", 1, "Microsoft Exchange MTA"], 121 | ["", "6A", 1, "Microsoft Exchange IMC"], 122 | ["", "BE", 1, "Network Monitor Agent"], 123 | ["", "BF", 1, "Network Monitor Application"], 124 | ["", "03", 1, "Messenger Service"], 125 | ["", "00", 0, "Domain/Workgroup Name"], 126 | ["", "1B", 1, "Domain Master Browser"], 127 | ["", "1C", 0, "Domain Controllers"], 128 | ["", "1D", 1, "Master Browser"], 129 | ["", "1E", 0, "Browser Service Elections"], 130 | ["", "2B", 1, "Lotus Notes Server Service"], 131 | ["IRISMULTICAST", "2F", 0, "Lotus Notes"], 132 | ["IRISNAMESERVER", "33", 0, "Lotus Notes"], 133 | ['Forte_$ND800ZA', "20", 1, "DCA IrmaLan Gateway Server Service"] 134 | ); 135 | ####################### end of nbtscan-derrived code ############################ 136 | 137 | my $usage =<&1`; 276 | if (!defined $which_output) { 277 | print "Please install \"which\" for this script to work correctly\n"; 278 | exit 1; 279 | } 280 | my $which_output = `which $prog 2>/dev/null`; 281 | chomp $which_output; 282 | if (($which_output !~ /^\/.*\/$prog$/) && (! -f "/usr/bin/" . $prog) && (! -f "/usr/sbin/" . $prog) && (! -f "/usr/local/bin/" . $prog) && (! -f "/usr/local/bin/" . $prog)) { 283 | print "ERROR: $prog is not in your path. Check that samba package is installed\n"; 284 | $dependency_error = 1; 285 | } else { 286 | print_verbose("Dependent program \"$prog\" found in $which_output\n") if $verbose; 287 | } 288 | } 289 | foreach my $prog (@optional_dependent_programs) { 290 | my $which_output = `which $prog 2>&1`; 291 | chomp $which_output; 292 | if ($which_output !~ /^\/.*\/$prog$/) { 293 | print "WARNING: $prog is not in your path. Check that package is installed and your PATH is sane.\n"; 294 | $odp_present{$prog} = 0; 295 | } else { 296 | print_verbose("Dependent program \"$prog\" found in $which_output\n") if $verbose; 297 | $odp_present{$prog} = 1; 298 | } 299 | } 300 | if ($dependency_error) { 301 | print "For Gentoo, you need to install the \"samba\" package\n"; 302 | print "For Debian, you need to install the \"smbclient\" package\n"; 303 | exit 1; 304 | } 305 | 306 | # Untaint workgroup if supplied on command line 307 | if (defined($global_workgroup)) { 308 | if ($global_workgroup =~ /^([a-zA-Z0-9\.\-_]*)$/) { 309 | $global_workgroup = $1; 310 | } else { 311 | print "ERROR: Workgroup \"$global_workgroup\" contains some illegal characters\n"; 312 | exit 1; 313 | } 314 | } 315 | 316 | # We're going to use hard quotes around all variables used in "system" calls. 317 | # We don't want bad data to be able to break out of these quotes. 318 | foreach my $known_username (@global_known_usernames) { 319 | $known_username =~ s/'/'\''/g; ($known_username) = $known_username =~ /(.*)/; 320 | } 321 | $global_username =~ s/'/'\\''/g; ($global_username) = $global_username =~ /(.*)/; 322 | $global_password =~ s/'/'\\''/g; ($global_password) = $global_password =~ /(.*)/; 323 | 324 | # Output message about options used 325 | print "Starting enum4linux v$VERSION ( http://labs.portcullis.co.uk/application/enum4linux/ ) on " . scalar(localtime) . "\n"; 326 | print_heading("Target Information"); 327 | print "Target ........... $global_target\n"; 328 | print "RID Range ........ $global_rid_range\n"; 329 | print "Username ......... '$global_username'\n"; 330 | print "Password ......... '$global_password'\n"; 331 | print "Known Usernames .. " . join(", ", @global_known_usernames) . "\n"; 332 | print "\n"; 333 | 334 | # Basic enumeration, check session 335 | get_workgroup(); 336 | get_nbtstat() if $opts{'n'}; 337 | make_session(); 338 | get_ldapinfo() if $opts{'l'}; 339 | get_domain_sid(); 340 | get_os_info() if $opts{'o'}; 341 | 342 | # enum-compatible functions 343 | enum_users() if $opts{'U'}; 344 | enum_machines() if $opts{'M'}; 345 | enum_names() if $opts{'N'}; 346 | enum_shares() if $opts{'S'}; 347 | enum_password_policy() if $opts{'P'}; 348 | enum_groups() if $opts{'G'}; 349 | enum_dom_groups() if $opts{'G'}; 350 | enum_lsa_policy() if $opts{'L'}; 351 | 352 | # extra stuff that runs slowly 353 | enum_users_rids() if $opts{'r'}; 354 | enum_shares_unauth() if $opts{'s'}; 355 | get_printer_info() if $opts{'i'}; 356 | 357 | print "enum4linux complete on " . scalar(localtime) . "\n\n"; 358 | 359 | sub get_nbtstat { 360 | print_heading("Nbtstat Information for $global_target"); 361 | my $output = `nmblookup -A '$global_target' 2>&1`; 362 | $output = nbt_to_human($output); 363 | print "$output\n"; 364 | } 365 | 366 | sub get_domain_sid { 367 | print_heading("Getting domain SID for $global_target"); 368 | my $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' $global_target -c 'lsaquery' 2>&1"; 369 | print_verbose("Attempting to get domain SID with command: $command\n") if $verbose; 370 | my $domain_sid_text = `$command`; 371 | chomp $domain_sid_text; 372 | print $domain_sid_text; 373 | print "\n"; 374 | if ($domain_sid_text =~ /Domain Sid: S-0-0/) { 375 | print_plus("Host is part of a workgroup (not a domain)\n"); 376 | } elsif ($domain_sid_text =~ /Domain Sid: S-\d+-\d+-\d+-\d+-\d+-\d+/) { 377 | print_plus("Host is part of a domain (not a workgroup)\n"); 378 | } else { 379 | print_plus("Can't determine if host is part of domain or part of a workgroup\n"); 380 | } 381 | } 382 | 383 | # Get workgroup from nbstat info - we need this for lots of rpcclient calls 384 | sub get_workgroup { 385 | print_heading("Enumerating Workgroup/Domain on $global_target"); 386 | print_verbose("Attempting to get domain name with command: nmblookup -A '$global_target'\n") if $verbose; 387 | 388 | # Workgroup might already be known - e.g. from command line or from get_os_info() 389 | unless ($global_workgroup) { 390 | print "target is tainted\n" if tainted($global_target); # DEBUG 391 | $global_workgroup = `nmblookup -A '$global_target'`; # Global var. Erg! 392 | ($global_workgroup) = $global_workgroup =~ /\s+(\S+)\s+<00> - /s; 393 | unless (defined($global_workgroup)) { 394 | # dc.example.org. hostmaster.example.org. 1 900 600 86400 3600 395 | $global_workgroup = `dig +short 0.in-addr.arpa`; 396 | ($global_workgroup) = $global_workgroup =~ /.*\. hostmaster\.(.*?)\. .*/s; 397 | if (defined($global_workgroup)) { 398 | print "[+] Domain guessed: $global_workgroup\n"; 399 | } else { 400 | $global_workgroup = "WORKGROUP"; 401 | print_error("Can\'t find workgroup/domain\n"); 402 | print "\n"; 403 | return; 404 | } 405 | } 406 | unless (defined($global_workgroup) and $global_workgroup =~ /^[A-Za-z0-9_\.\-]+$/) { 407 | print_error("Workgroup \"$global_workgroup\"contains some illegal characters\n"); 408 | exit 1; 409 | } 410 | } 411 | print_plus("Got domain/workgroup name: $global_workgroup\n"); 412 | } 413 | 414 | # Get long domain name via LDAP 415 | # We don't do this by default because LDAP ports might not be present, or firewalled. 416 | sub get_ldapinfo { 417 | print_heading("Getting information via LDAP for $global_target"); 418 | my $command = "ldapsearch -x -h '$global_target' -p 389 -s base namingContexts 2>&1"; 419 | print_verbose("Attempting to long domain name: $command\n") if $verbose; 420 | unless ($odp_present{"ldapsearch"}) { 421 | print_error("Dependent program \"ldapsearch\" not present. Skipping this check. Install ldapsearch to fix.\n\n"); 422 | return 0; 423 | } 424 | 425 | my $output = `$command`; 426 | 427 | if ($output =~ /ldap_sasl_bind/) { 428 | print_error("Connection error\n"); 429 | return 0; 430 | } 431 | my $parent = 0; 432 | foreach my $line (split "\n", $output) { 433 | if ($line =~ /namingContexts: DC=DomainDnsZones/ or $line =~ /namingContexts: DC=ForestDnsZones/) { 434 | $parent = 1; 435 | } elsif ($line =~ /namingContexts:\s+(DC=[^,]+,DC=.*)/) { 436 | my $long_domain = $1; 437 | $long_domain =~ s/DC=//g; 438 | $long_domain =~ s/,/./g; 439 | print_plus("Long domain name for $global_target: $long_domain\n"); 440 | } 441 | } 442 | 443 | if ($parent == 1) { 444 | print_plus("$global_target appears to be a root/parent DC\n"); 445 | } else { 446 | print_plus("$global_target appears to be a child DC\n"); 447 | } 448 | 449 | } 450 | 451 | # See if we can connect using a null session or supplied credentials 452 | sub make_session { 453 | print_heading("Session Check on $global_target"); 454 | my $command = "smbclient -W '$global_workgroup' //'$global_target'/ipc\$ -U'$global_username'\%'$global_password' -c 'help' 2>&1"; 455 | print_verbose("Attempting to make null session using command: $command\n") if $verbose; 456 | my $os_info = `$command`; 457 | chomp $os_info; 458 | if ($os_info =~ /protocol negotiation failed: NT_STATUS_CONNECTION_RESET/) { 459 | print_error("Protocol mismatch. smbclient doesn\'t support the same protocol versions as the server. You likely need to install a later version of Samba.\n"); 460 | } 461 | if ($os_info =~ /case_sensitive/) { 462 | print_plus("Server $global_target allows sessions using username '$global_username', password '$global_password'\n"); 463 | } else { 464 | print_error("Server doesn't allow session using username '$global_username', password '$global_password'. Aborting remainder of tests.\n"); 465 | exit 1; 466 | } 467 | 468 | # Use this info to set workgroup if possible 469 | unless ($global_workgroup) { 470 | ($global_workgroup) = $os_info =~ /Domain=\[([^]]*)\]/; 471 | print_plus("Got domain/workgroup name: $global_workgroup\n"); 472 | } 473 | } 474 | 475 | # Get OS info 476 | sub get_os_info { 477 | print_heading("OS information on $global_target"); 478 | 479 | 480 | my $command = "smbclient -W '$global_workgroup' //'$global_target'/ipc\$ -U'$global_username'\%'$global_password' -c 'q' 2>&1"; 481 | print_verbose("Attempting to get OS info with command: $command\n") if $verbose; 482 | my $os_info = `$command`; 483 | chomp $os_info; 484 | 485 | if (defined($os_info)) { 486 | if ($os_info =~ /(Domain=[^\n]+)/s) { 487 | ($os_info) = $os_info =~ /(Domain=[^\n]+)/s; 488 | print_plus("Got OS info for $global_target from smbclient: "); 489 | print "$os_info\n"; 490 | } else { 491 | print_error("Can't get OS info with smbclient\n"); 492 | } 493 | } 494 | 495 | $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' -c 'srvinfo' '$global_target' 2>&1"; 496 | print_verbose("Attempting to get OS info with command: $command\n") if $verbose; 497 | $os_info = `$command`; 498 | if (defined($os_info)) { 499 | if ($os_info =~ /error: NT_STATUS_ACCESS_DENIED/) { 500 | print_error("Can't get OS info with srvinfo\n"); 501 | } else { 502 | print_plus("Got OS info for $global_target from srvinfo: "); 503 | print "$os_info\n"; 504 | } 505 | } 506 | } 507 | 508 | sub enum_password_policy { 509 | print_heading("Password Policy Information for $global_target"); 510 | my $command = "polenum '$global_username':'$global_password'\@'$global_target' 2>&1"; 511 | unless ($odp_present{"polenum"}) { 512 | print_error("Dependent program \"polenum\" not present. Skipping this check. Download polenum from http://labs.portcullis.co.uk/application/polenum/\n\n"); 513 | return 0; 514 | } 515 | print_verbose("Attempting to get Password Policy info with command: $command\n") if $verbose; 516 | my $passpol_info = `$command`; 517 | chomp $passpol_info; 518 | if (defined($passpol_info)) { 519 | if ($passpol_info =~ /Account Lockout Threshold/) { 520 | print $passpol_info; 521 | } elsif ($passpol_info =~ /Error Getting Password Policy: Connect error/) { 522 | print_error("Can't connect to host with supplied credentials.\n"); 523 | } else { 524 | print_error("Unexpected error from polenum:\n"); 525 | print $passpol_info; 526 | } 527 | } else { 528 | print_error("polenum gave no output.\n"); 529 | } 530 | $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' '$global_target' -c \"getdompwinfo\" 2>&1"; 531 | print_verbose("Attempting to get Password Policy info with command: $command\n") if $verbose; 532 | $passpol_info = `$command`; 533 | chomp $passpol_info; 534 | print "\n"; 535 | if (defined($passpol_info) and $passpol_info !~ /ACCESS_DENIED/) { 536 | print_plus("Retrieved partial password policy with rpcclient:\n\n"); 537 | if ($passpol_info =~ /password_properties: 0x[0-9a-fA-F]{7}0/) { 538 | print "Password Complexity: Disabled\n"; 539 | } elsif ($passpol_info =~ /password_properties: 0x[0-9a-fA-F]{7}1/) { 540 | print "Password Complexity: Enabled\n"; 541 | } 542 | if ($passpol_info =~ /min_password_length: (\d+)/) { 543 | my $minlen = $1; 544 | print "Minimum Password Length: $minlen\n"; 545 | } 546 | } else { 547 | print_error("Failed to get password policy with rpcclient\n"); 548 | } 549 | print "\n"; 550 | } 551 | 552 | sub enum_lsa_policy { 553 | print_heading("LSA Policy Information on $global_target"); 554 | print_error("Not implemented in this version of enum4linux.\n"); 555 | } 556 | 557 | sub enum_machines { 558 | print_heading("Machine Enumeration on $global_target"); 559 | my @dm_rids; 560 | 561 | # First, get the RID list 562 | my $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' -c 'querygroupmem 0x203' '$global_target' 2>&1"; 563 | print_verbose("Running command: $command\n") if $verbose; 564 | my $output = `$command`; 565 | 566 | if ($output) { 567 | # Clean up the output and extract RIDs 568 | my @rids_hex = $output =~ /rid:\[(0x[a-fA-F0-9]+)\]/g; 569 | @dm_rids = @rids_hex; 570 | print_verbose("The array contains " . scalar(@dm_rids) . " items\n") if $verbose; 571 | 572 | # Set the array chunk sizes 573 | my $maxarraycount = scalar(@dm_rids); 574 | my $arraystart = 0; 575 | my $arraycount = 500; 576 | 577 | while ($arraystart < $maxarraycount) { 578 | my $arrayend = ($arraystart + $arraycount > $maxarraycount) ? $maxarraycount : $arraystart + $arraycount; 579 | my @temparray = @dm_rids[$arraystart..($arrayend - 1)]; 580 | 581 | print_verbose("Testing from $arraystart to $arrayend\n") if $verbose; 582 | 583 | # Flatten the array into a space-separated string 584 | my $tempstring = join(' ', @temparray); 585 | 586 | # Run the rpcclient command for this batch of RIDs 587 | my $samlookup_cmd = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' -c 'samlookuprids domain $tempstring' '$global_target' 2>&1"; 588 | print_verbose("Running command: $samlookup_cmd\n") if $verbose; 589 | my $result = `$samlookup_cmd`; 590 | 591 | # Extract both machine names and corresponding RIDs 592 | while ($result =~ /rid\s(0x[a-fA-F0-9]+):\s(\S+\$)/g) { 593 | my $rid = $1; 594 | my $machine = $2; 595 | print "machine:[$machine] rid:[$rid]\n"; 596 | } 597 | 598 | # Increment for the next batch 599 | $arraystart += $arraycount; 600 | } 601 | } else { 602 | print_error("No response using rpcclient querygroupmem\n"); 603 | } 604 | print "\n"; 605 | } 606 | 607 | sub enum_names { 608 | print_heading("Name Enumeration on $global_target"); 609 | print_error("Not implemented in this version of enum4linux.\n"); 610 | } 611 | 612 | sub enum_groups { 613 | print_heading("Groups on $global_target"); 614 | foreach my $grouptype ("builtin", "domain") { 615 | # Get list of groups 616 | my $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' '$global_target' -c 'enumalsgroups $grouptype' 2>&1"; 617 | if ($grouptype eq "domain") { 618 | print_verbose("Getting local groups with command: $command\n") if $verbose; 619 | print_plus("Getting local groups:\n"); 620 | } else { 621 | print_verbose("Getting $grouptype groups with command: $command\n") if $verbose; 622 | print_plus("Getting $grouptype groups:\n"); 623 | } 624 | my $groups_string = `$command`; 625 | if ($groups_string =~ /error: NT_STATUS_ACCESS_DENIED/) { 626 | if ($grouptype eq "domain") { 627 | print_error("Can't get local groups: NT_STATUS_ACCESS_DENIED\n"); 628 | } else { 629 | print_error("Can't get $grouptype groups: NT_STATUS_ACCESS_DENIED\n"); 630 | } 631 | } else { 632 | ($groups_string) = $groups_string =~ /(group:.*)/s; 633 | $groups_string = "" unless defined($groups_string); 634 | print $groups_string; 635 | } 636 | 637 | # Get group members 638 | my %rid_of_group = $groups_string =~ /\[([^\]]+)\]/sg; 639 | if ($grouptype eq "domain") { 640 | print_plus("Getting local group memberships:\n"); 641 | } else { 642 | print_plus("Getting $grouptype group memberships:\n"); 643 | } 644 | foreach my $groupname (keys %rid_of_group) { 645 | $groupname =~ s/'/'\\''/g; 646 | $rid_of_group{$groupname} =~ s/^0x//; 647 | $rid_of_group{$groupname} = hex($rid_of_group{$groupname}); 648 | $command = "net rpc group members '$groupname' -W '$global_workgroup' -I '$global_target' -U'$global_username'\%'$global_password' 2>&1\n"; 649 | print_verbose("Running command: $command\n") if $verbose; 650 | my $members = `$command`; 651 | my @members = split "\n", $members; 652 | foreach my $m (@members) { 653 | print colored("Group: ", 'magenta'); 654 | print "$groupname' (RID: " . $rid_of_group{$groupname} . ") has member: $m\n"; 655 | } 656 | } 657 | if ($global_detailed) { 658 | foreach my $groupname (keys %rid_of_group) { 659 | print_plus("Getting detailed info for group $groupname (RID: " . $rid_of_group{$groupname} . ")\n"); 660 | get_group_details_from_rid($rid_of_group{$groupname}); 661 | } 662 | } 663 | } 664 | } 665 | 666 | sub enum_dom_groups { 667 | # Get list of groups 668 | my $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' '$global_target' -c \"enumdomgroups\" 2>&1"; 669 | print_verbose("Getting domain groups with command: $command\n") if $verbose; 670 | print_plus("Getting domain groups:\n"); 671 | 672 | my $groups_string = `$command`; 673 | if ($groups_string =~ /error: NT_STATUS_ACCESS_DENIED/) { 674 | print_error("Can't get domain groups: NT_STATUS_ACCESS_DENIED\n"); 675 | } else { 676 | ($groups_string) = $groups_string =~ /(group:.*)/s; 677 | $groups_string = "" unless defined($groups_string); 678 | print $groups_string; 679 | } 680 | 681 | # Get group members 682 | my %rid_of_group = $groups_string =~ /\[([^\]]+)\]/sg; 683 | print_plus("Getting domain group memberships:\n"); 684 | 685 | foreach my $groupname (keys %rid_of_group) { 686 | $groupname =~ s/'/'\\''/g; 687 | $rid_of_group{$groupname} =~ s/^0x//; 688 | $rid_of_group{$groupname} = hex($rid_of_group{$groupname}); 689 | $command = "net rpc group members '$groupname' -W '$global_workgroup' -I '$global_target' -U'$global_username'\%'$global_password' 2>&1\n"; 690 | print_verbose("Running command: $command\n") if $verbose; 691 | my $members = `$command`; 692 | my @members = split "\n", $members; 693 | foreach my $m (@members) { 694 | print colored("Group: ", 'magenta'); 695 | print "'$groupname' (RID: " . $rid_of_group{$groupname} . ") has member: $m\n"; 696 | } 697 | } 698 | if ($global_detailed) { 699 | foreach my $groupname (keys %rid_of_group) { 700 | print_plus("Getting detailed info for group $groupname (RID: " . $rid_of_group{$groupname} . ")\n"); 701 | get_group_details_from_rid($rid_of_group{$groupname}); 702 | } 703 | } 704 | } 705 | 706 | sub enum_groups_unauth { 707 | print_heading("Groups on $global_target via RID cycling"); 708 | print_error("Not implemented in this version of enum4linux.\n"); 709 | } 710 | 711 | sub enum_shares { 712 | # Share enumeration 713 | print_heading("Share Enumeration on $global_target"); 714 | print_verbose("Attempting to get share list using authentication\n") if $verbose; 715 | # my $shares = `net rpc share -W '$global_workgroup' -I '$global_target' -U'$global_username'\%'$global_password' 2>&1`; 716 | my $command = "smbclient -W '$global_workgroup' -L //'$global_target' -U'$global_username'\%'$global_password' 2>&1"; 717 | my $shares = `$command`; 718 | if (defined($shares)) { 719 | if ($shares =~ /NT_STATUS_ACCESS_DENIED/) { 720 | print_error("Can't list shares: NT_STATUS_ACCESS_DENIED\n"); 721 | } else { 722 | print "$shares"; 723 | } 724 | } 725 | 726 | print_plus("Attempting to map shares on $global_target\n"); 727 | my @shares = $shares =~ /^[\t ]*?([ \S]+?)[\t ]*?(?:Disk|IPC|Printer)[^\n]*/gms; 728 | foreach my $share (@shares) { 729 | my ($mapping_result, $listing_result, $writing_result) = ("N/A","N/A","N/A"); 730 | 731 | $share =~ s/'/'\\''/g; 732 | my $command = "smbclient -W '$global_workgroup' //'$global_target'/'$share' -U'$global_username'\%'$global_password' -c dir 2>&1"; 733 | print_verbose("Attempting map to share //$global_target/$share with command: $command\n") if $verbose; 734 | my $output = `$command`; 735 | 736 | if ($output =~ /NT_STATUS_ACCESS_DENIED listing/ || 737 | $output =~ /do_list:.*NT_STATUS_ACCESS_DENIED/ ) { 738 | $mapping_result="OK"; $listing_result="DENIED"; 739 | } elsif ($output =~ /tree connect failed: NT_STATUS_ACCESS_DENIED/) { 740 | $mapping_result="DENIED"; $listing_result="N/A"; 741 | } elsif ($output =~ /NT_STATUS_NO_SUCH_FILE listing/) { 742 | $mapping_result="N/A"; $listing_result="N/A"; 743 | } elsif ($output =~ /\n\s+(\.\.|.*?)\s+D.*\d{4}\n/) { 744 | $mapping_result="OK" ; $listing_result="OK"; 745 | } else { 746 | print_error("Can't understand response:\n"); 747 | print $output; 748 | } 749 | if ($mapping_result eq "OK") { 750 | if ($aggressive) { 751 | print "testing write access " . $share . "\n"; 752 | # check for write access 753 | my @chars = ("A".."Z", "a".."z", "0".."9"); 754 | my $random_string; 755 | $random_string .= $chars[rand @chars] for 1..8; 756 | 757 | $command = "smbclient -W '$global_workgroup' //'$global_target'/'$share' -U'$global_username'\%'$global_password' -c 'mkdir $random_string' 2>&1"; 758 | print_verbose("Checking write access to share //$global_target/$share with command: $command\n") if $verbose; 759 | $output = `$command` ; 760 | if ($output =~ /NT_STATUS_ACCESS_DENIED making/) { 761 | $writing_result="DENIED" ; 762 | } elsif (length $output) { 763 | # the command should not give any output, if something was output maybe it's a failure 764 | my $command2 = "smbclient -W '$global_workgroup' //'$global_target'/'$share' -U'$global_username'\%'$global_password' -c dir 2>&1"; 765 | print_verbose("Attempting check for directory $random_string on //$global_target/$share with command: $command2\n") if $verbose; 766 | my $output2 = `$command2`; 767 | if ($output2 =~ /.*$random_string.*/) { 768 | $writing_result="OK"; 769 | } else { 770 | print_error("Can't understand initial response:\n"); 771 | print $output; 772 | print_error("Can't understand second response:\n"); 773 | print $output2; 774 | } 775 | } else { 776 | $writing_result="OK"; 777 | } 778 | if ($writing_result ne "DENIED") { 779 | # remove the directory we created 780 | $command = "smbclient -W '$global_workgroup' //'$global_target'/'$share' -U'$global_username'\%'$global_password' -c 'rmdir $random_string' 2>&1"; 781 | print_verbose("Removing created directory on share //$global_target/$share with command: $command\n") if $verbose; 782 | $output=`$command` ; 783 | if (length $output) { 784 | print_error("rmdir command returned the following:\n"); 785 | print $output ; 786 | } 787 | } 788 | } 789 | } 790 | # print results 791 | print "//$global_target/$share\t"; 792 | print colored("Mapping: ", 'magenta'); 793 | print $mapping_result ; 794 | print colored("Listing: ", 'magenta'); 795 | print $listing_result ; 796 | print colored("Writing: ", 'magenta'); 797 | print $writing_result ; 798 | print "\n" ; 799 | } 800 | } 801 | 802 | sub enum_shares_unauth { 803 | print_heading("Brute Force Share Enumeration on $global_target"); 804 | print_verbose("Attempting to get share list using bruteforcing\n") if $verbose; 805 | my $shares_file = $global_share_file; 806 | open SHARES, "<$shares_file" or die "[E] Can't open share list file $shares_file: $!\n"; 807 | my @shares = ; 808 | for (@shares) {chomp}; 809 | 810 | foreach my $share (@shares) { 811 | # Untaint $share 812 | if ($share =~ /^([a-zA-Z0-9\._\$\-]+)$/) { 813 | $share = $1; 814 | } else { 815 | print_error("Share name $share contains some illegal characters\n"); 816 | exit 1; 817 | } 818 | 819 | my $result = `smbclient -W '$global_workgroup' //'$global_target'/'$share' -c dir -U'$global_username'\%'$global_password' 2>&1`; 820 | if ($result =~ /blocks of size .* blocks available/) { 821 | print "$share EXISTS, Allows access using username: '$global_username', password: '$global_password'\n"; 822 | } elsif ($result =~ /NT_STATUS_BAD_NETWORK_NAME/) { 823 | print "$share doesn't exist\n" if $debug; 824 | } elsif ($result =~ /NT_STATUS_ACCESS_DENIED/) { 825 | print "$share EXISTS\n"; 826 | } else { 827 | print $result; 828 | } 829 | } 830 | } 831 | 832 | sub enum_users_rids { 833 | print_heading("Users on $global_target via RID cycling (RIDS: $global_rid_range)"); 834 | 835 | my $sid; 836 | my %sids = (); 837 | my $logon; 838 | my $cleansid; 839 | # Get SID - try other known usernames if necessary 840 | foreach my $known_username (@global_known_usernames) { 841 | my $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' '$global_target' -c 'lookupnames $known_username' 2>&1"; 842 | print_verbose("Attempting to get SID from $global_target with command: $command\n") if $verbose; 843 | print_verbose("Assuming that user \"$known_username\" exists\n") if $verbose; 844 | $logon = "username '$global_username', password '$global_password'"; 845 | $sid = `$command`; 846 | if ($sid =~ /NT_STATUS_ACCESS_DENIED/) { 847 | print_error("Couldn't get SID: NT_STATUS_ACCESS_DENIED. RID cycling not possible.\n"); 848 | last; 849 | } elsif ($sid =~ /NT_STATUS_NONE_MAPPED/) { 850 | print_verbose("User \"$known_username\" doesn't exist. User enumeration should be possible, but SID needed...\n") if $verbose; 851 | next; 852 | } elsif ($sid =~ /S-1-5-21-[\d-]+-\d+\s+/) { 853 | ($cleansid) = $sid =~ /(S-1-5-21-[\d-]+)-\d+\s+/; 854 | if (defined($sids{$cleansid})) { 855 | print_info("Found new SID: "); 856 | print "$cleansid\n"; 857 | } 858 | $sids{$cleansid} = 1; 859 | next; 860 | } elsif ($sid =~ /S-1-5-[\d-]+-\d+\s+/) { 861 | ($cleansid) = $sid =~ /(S-1-5-[\d-]+)-\d+\s+/; 862 | if (defined($sids{$cleansid})) { 863 | print_info("Found new SID: "); 864 | print "$cleansid\n"; 865 | } 866 | $sids{$cleansid} = 1; 867 | next; 868 | } elsif ($sid =~ /S-1-22-[\d-]+-\d+\s+/) { 869 | ($cleansid) = $sid =~ /(S-1-22-[\d-]+)-\d+\s+/; 870 | if (defined($sids{$cleansid})) { 871 | print_info("Found new SID: "); 872 | print "$cleansid\n"; 873 | } 874 | $sids{$cleansid} = 1; 875 | next; 876 | } else { 877 | next; 878 | } 879 | } 880 | 881 | # Get some more SIDs (hopefully) 882 | my $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' '$global_target' -c lsaenumsid 2>&1"; 883 | print_verbose("Attempting to get SIDs from $global_target with command: $command\n") if $verbose; 884 | my $sids = `$command`; 885 | foreach my $sid ($sids =~ /(S-[0-9-]+)/g) { 886 | print_verbose("Processing SID $sid\n") if $verbose; 887 | if ($sid =~ /NT_STATUS_ACCESS_DENIED/) { 888 | print_error("Couldn't get SID: NT_STATUS_ACCESS_DENIED. RID cycling not possible.\n"); 889 | next; 890 | } elsif ($sid =~ /S-1-5-21-[\d-]+-\d+/) { 891 | ($cleansid) = $sid =~ /(S-1-5-21-[\d-]+)-\d+/; 892 | if (defined($sids{$cleansid})) { 893 | print_info("Found new SID: "); 894 | print "$cleansid\n"; 895 | } 896 | $sids{$cleansid} = 1; 897 | next; 898 | } elsif ($sid =~ /S-1-5-[\d-]+-\d+/) { 899 | ($cleansid) = $sid =~ /(S-1-5-[\d-]+)-\d+/; 900 | if (defined($sids{$cleansid})) { 901 | print_info("Found new SID: "); 902 | print "$cleansid\n"; 903 | } 904 | $sids{$cleansid} = 1; 905 | next; 906 | } elsif ($sid =~ /S-1-22-[\d-]+-\d+/) { 907 | ($cleansid) = $sid =~ /(S-1-22-[\d-]+)-\d+/; 908 | if (defined($sids{$cleansid})) { 909 | print_info("Found new SID: "); 910 | print "$cleansid\n"; 911 | } 912 | $sids{$cleansid} = 1; 913 | next; 914 | } else { 915 | next; 916 | } 917 | } 918 | 919 | foreach my $sid (keys %sids) { 920 | if (! defined($sid) and $global_username) { 921 | print_verbose("WARNING: Can\'t get SID. Maybe none of the 'known' users really exist. Try others with -k. Trying null session.\n") if $verbose; 922 | foreach my $known_username (@global_known_usernames) { 923 | my $command = "rpcclient -W '$global_workgroup' -U% '$global_target' -c 'lookupnames $known_username' 2>&1"; 924 | print_info("Assuming that user $known_username exists\n"); 925 | print_verbose("Trying null username and password: $command\n") if $verbose; 926 | $sid=`$command`; 927 | if ($sid =~ /error: NT_STATUS_ACCESS_DENIED/) { 928 | print_error("Couldn't get SID: NT_STATUS_ACCESS_DENIED\n"); 929 | next; 930 | } else { 931 | last; 932 | } 933 | } 934 | ($sid) = $sid =~ /(S-1-5-21-[\d-]+)-\d+\s+/; 935 | unless (defined($sid)) { 936 | print_error("Can't get SID using either a null username or the username \"$global_username\"\n"); 937 | exit 1; 938 | } 939 | $logon = "username '', password ''" 940 | } 941 | unless (defined($sid)) { 942 | print_error("Couldn't find SID. Aborting RID cycling attempt.\n\n"); 943 | return 1; 944 | } 945 | print_plus("Enumerating users using SID $sid and logon $logon\n"); 946 | 947 | # RID Cycle; 948 | my $last_range = 0; 949 | my @ranges = split(",", $global_rid_range); 950 | foreach my $rid_range (@ranges) { 951 | $last_range = 1 if $rid_range eq $ranges[scalar(@ranges) - 1]; 952 | my ($start_rid, $end_rid); 953 | 954 | # Check range is of form n-m (n,m integers) 955 | if ($rid_range =~ /\d+-\d+/) { 956 | ($start_rid, $end_rid) = $rid_range =~ /^(\d+)-(\d+)$/; 957 | 958 | # Check range is of form n (n integer) 959 | } elsif ($rid_range =~ /^\d+$/) { 960 | ($start_rid, $end_rid) = ($rid_range, $rid_range); 961 | 962 | # Invalid range 963 | } else { 964 | print "WARNING: RID range $rid_range isn't valid. Should be like 10-20 or 1199. Ignoring this range\n"; 965 | next; 966 | } 967 | 968 | # Check we have an ascending range 969 | if ($start_rid > $end_rid) { 970 | print "WARNING: RID range $rid_range seems to be reversed. Automatically reversing.\n"; 971 | ($start_rid, $end_rid) = ($end_rid, $start_rid); 972 | } 973 | 974 | if ($global_search_until_fail) { 975 | $end_rid = 500000; 976 | } 977 | 978 | my $fail_count = 0; 979 | if ($global_search_until_fail and $last_range) { 980 | $end_rid = $heighest_rid; 981 | } 982 | foreach my $rid ($start_rid..$end_rid) { 983 | my $output = `rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' '$global_target' -c 'lookupsids $sid-$rid' 2>&1`; 984 | my ($sid_and_user) = $output =~ /(S-\d+-\d+-\d+-[\d-]+\s+[^\)]+\))/; 985 | if ($sid_and_user) { 986 | $sid_and_user =~ s/\(1\)/(Local User)/; 987 | $sid_and_user =~ s/\(2\)/(Domain Group)/; 988 | $sid_and_user =~ s/\(2\)/(Domain User)/; 989 | $sid_and_user =~ s/\(4\)/(Local Group)/; 990 | 991 | # Samba servers sometimes claim to have user accounts 992 | # with the same name as the UID/RID. We don't report these. 993 | if ($sid_and_user =~ /-(\d+) .*\\\1 \(/) { 994 | $fail_count++; 995 | } else { 996 | print "$sid_and_user\n" if $sid_and_user =~ /\((Local|Domain) User\)/; 997 | print "$sid_and_user\n" if $sid_and_user =~ /\((Local|Domain) Group\)/; 998 | $fail_count = 0; 999 | get_user_details_from_rid($rid) if $sid_and_user =~ /\((Local|Domain) User\)/; 1000 | get_group_details_from_rid($rid) if $sid_and_user =~ /\((Local|Domain) Group\)/; 1001 | } 1002 | } else { 1003 | $fail_count++; 1004 | } 1005 | 1006 | if ($global_search_until_fail) { 1007 | last if $fail_count > $global_fail_limit; 1008 | } 1009 | } 1010 | } 1011 | } # foreach sid 1012 | } 1013 | 1014 | sub enum_users { 1015 | my @rids; 1016 | my @rids2; 1017 | 1018 | print_heading("Users on $global_target"); 1019 | my $command = "rpcclient -W '$global_workgroup' -c querydispinfo -U'$global_username'\%'$global_password' -d 10 '$global_target' 2>&1"; 1020 | print_verbose("Attempting to get userlist with command: $command\n") if $verbose; 1021 | my $users = `$command`; 1022 | if ($users ne "") { 1023 | my $continue = 1; 1024 | if ($users =~ /NT_STATUS_ACCESS_DENIED/) { 1025 | print_error("Couldn't find users using querydispinfo: NT_STATUS_ACCESS_DENIED\n"); 1026 | } else { 1027 | ($users) = $users =~ /(index:.*)/s; 1028 | print $users; 1029 | $continue = 0; 1030 | } 1031 | my @rids_hex = $users =~ /RID:\s+0x([a-fA-f0-9]+)\s/gs; 1032 | @rids = map { hex($_) } @rids_hex; 1033 | } else { 1034 | print_error("No response using rpcclient querydispinfo\n"); 1035 | } 1036 | 1037 | print "\n"; 1038 | $command = "rpcclient -W '$global_workgroup' -c enumdomusers -U'$global_username'\%'$global_password' -d 10 '$global_target' 2>&1"; 1039 | print_verbose("Attempting to get userlist with command: $command\n") if $verbose; 1040 | $users = `$command`; 1041 | if ($users ne "") { 1042 | if ($users =~ /NT_STATUS_ACCESS_DENIED/) { 1043 | print_error("Couldn't find users using enumdomusers: NT_STATUS_ACCESS_DENIED\n"); 1044 | } else { 1045 | ($users) = $users =~ /(user:.*)/s; 1046 | print $users; 1047 | } 1048 | my @rids_hex2 = $users =~ /rid:\[0x([A-Fa-f0-9]+)\]/gs; 1049 | @rids2 = map { hex($_) } @rids_hex2; 1050 | } else { 1051 | print_error("No response using rpcclient enumdomusers\n"); 1052 | } 1053 | 1054 | my %rids; 1055 | foreach my $rid (@rids, @rids2) { 1056 | $rids{$rid} = 1; 1057 | } 1058 | foreach my $rid (keys %rids) { 1059 | get_user_details_from_rid($rid); 1060 | } 1061 | } 1062 | 1063 | sub get_group_details_from_rid { 1064 | my $rid = shift; 1065 | if (invalid_rid($rid)) { 1066 | print_error("Invalid RID passed: $rid\n"); 1067 | return 0; 1068 | } 1069 | return unless $global_detailed; 1070 | my $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' -c 'querygroup $rid' '$global_target' 2>&1"; 1071 | print_verbose("Attempting to get detailed group info with command: $command\n") if $verbose; 1072 | my $group_info = `$command`; 1073 | ($group_info) = $group_info =~ /([^\n]*Group Name.*Num Members[^\n]*)/s; 1074 | if (defined($group_info)) { 1075 | print "$group_info\n\n"; 1076 | } else { 1077 | print_error("No info found\n\n"); 1078 | } 1079 | } 1080 | 1081 | sub get_user_details_from_rid { 1082 | my $rid = shift; 1083 | if (invalid_rid($rid)) { 1084 | print_error("Invalid RID passed: $rid\n"); 1085 | return 0; 1086 | } 1087 | return unless $global_detailed; 1088 | my $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' -c 'queryuser $rid' '$global_target' 2>&1"; 1089 | print_verbose("Attempting to get detailed user info with command: $command\n") if $verbose; 1090 | my $user_info = `$command`; 1091 | ($user_info) = $user_info =~ /([^\n]*User Name.*logon_hrs[^\n]*)/s; 1092 | if (defined($user_info)) { 1093 | print "$user_info\n\n"; 1094 | my ($acb_info) = $user_info =~ /acb_info\s+:\s+0x([0-9a-fA-F]+)/; 1095 | if ($acb_info) { 1096 | my $acb_int = hex($acb_info); 1097 | my $pad = "\t"; 1098 | if ($acb_int & 0x00000001) { 1099 | printf $pad . "%-25.25s: %s\n", "Account Disabled", "True"; 1100 | } else { 1101 | printf $pad . "%-25.25s: %s\n", "Account Disabled", "False"; 1102 | } 1103 | if ($acb_int & 0x00000200) { 1104 | printf $pad . "%-25.25s: %s\n", "Password does not expire", "True"; 1105 | } else { 1106 | printf $pad . "%-25.25s: %s\n", "Password does not expire", "False"; 1107 | } 1108 | if ($acb_int & 0x00000400) { 1109 | printf $pad . "%-25.25s: %s\n", "Account locked out", "True"; 1110 | } else { 1111 | printf $pad . "%-25.25s: %s\n", "Account locked out", "False"; 1112 | } 1113 | if ($acb_int & 0x00020000) { 1114 | printf $pad . "%-25.25s: %s\n", "Password expired", "True"; 1115 | } else { 1116 | printf $pad . "%-25.25s: %s\n", "Password expired", "False"; 1117 | } 1118 | if ($acb_int & 0x00000040) { 1119 | printf $pad . "%-25.25s: %s\n", "Interdomain trust account", "True"; 1120 | } else { 1121 | printf $pad . "%-25.25s: %s\n", "Interdomain trust account", "False"; 1122 | } 1123 | if ($acb_int & 0x00000080) { 1124 | printf $pad . "%-25.25s: %s\n", "Workstation trust account", "True"; 1125 | } else { 1126 | printf $pad . "%-25.25s: %s\n", "Workstation trust account", "False"; 1127 | } 1128 | if ($acb_int & 0x00000100) { 1129 | printf $pad . "%-25.25s: %s\n", "Server trust account", "True"; 1130 | } else { 1131 | printf $pad . "%-25.25s: %s\n", "Server trust account", "False"; 1132 | } 1133 | if ($acb_int & 0x00002000) { 1134 | printf $pad . "%-25.25s: %s\n", "Trusted for delegation", "True"; 1135 | } else { 1136 | printf $pad . "%-25.25s: %s\n", "Trusted for delegation", "False"; 1137 | } 1138 | } 1139 | print "\n"; 1140 | } else { 1141 | print_error("No info found\n\n") 1142 | } 1143 | } 1144 | 1145 | sub invalid_rid { 1146 | my $rid = shift; 1147 | if ($rid =~ /^\d+$/) { 1148 | return 0; 1149 | } else { 1150 | return 1; 1151 | } 1152 | } 1153 | 1154 | sub get_printer_info { 1155 | print_heading("Getting printer info for $global_target"); 1156 | my $command = "rpcclient -W '$global_workgroup' -U'$global_username'\%'$global_password' -c 'enumprinters' '$global_target' 2>&1"; 1157 | print_verbose("Attempting to get printer info with command: $command\n") if $verbose; 1158 | my $printer_info = `$command`; 1159 | # ($group_info) = $group_info =~ /([^\n]*Group Name.*Num Members[^\n]*)/s; 1160 | if (defined($printer_info)) { 1161 | print "$printer_info\n\n"; 1162 | } else { 1163 | print_error("No info found\n\n"); 1164 | } 1165 | 1166 | } 1167 | 1168 | sub nbt_to_human { 1169 | my $nbt_in = shift; # multi-line 1170 | my @nbt_in = split (/\n/, $nbt_in); 1171 | my @nbt_out = (); 1172 | foreach my $line (@nbt_in) { 1173 | if ($line =~ /\s+(\S+)\s+<(..)>\s+-\s+?()?\s+?[A-Z]/) { 1174 | my $line_val = $1; 1175 | my $line_code = uc $2; 1176 | my $line_group = defined($3) ? 0 : 1; # opposite 1177 | 1178 | foreach my $info_aref (@nbt_info) { 1179 | my ($pattern, $code, $group, $desc) = @$info_aref; 1180 | # print "Matching: line=\"$line\", val=$line_val, code=$line_code, group=$line_group against pattern=$pattern, code=$code, group=$group, desc=$desc\n"; 1181 | if ($pattern) { 1182 | if ($line_val =~ /$pattern/ and $line_code eq $code and $line_group eq $group) { 1183 | push @nbt_out, "$line $desc"; 1184 | last; 1185 | } 1186 | } else { 1187 | if ($line_code eq $code and $line_group eq $group) { 1188 | push @nbt_out, "$line $desc"; 1189 | last; 1190 | } 1191 | } 1192 | } 1193 | } else { 1194 | push @nbt_out, $line; 1195 | } 1196 | } 1197 | return join "\n", @nbt_out; 1198 | } 1199 | 1200 | sub print_heading { 1201 | my $string = shift; 1202 | my $output = "$string"; 1203 | my $maxlen = 100; 1204 | my $len = $maxlen - length($output); 1205 | print "\n"; 1206 | print colored(" " . "=" x ($len / 2) . "( ", 'blue'); 1207 | print colored("$output", 'green'); 1208 | print colored(" )" . "=" x ($len / 2) . "\n\n", 'blue'); 1209 | } 1210 | 1211 | sub print_verbose { 1212 | my $string = shift; 1213 | my $output = "$string"; 1214 | print colored("\n[V] ", 'yellow'); 1215 | print colored("$output\n", 'magenta'); 1216 | } 1217 | 1218 | sub print_plus { 1219 | my $string = shift; 1220 | my $output = "$string"; 1221 | print colored("\n[+] ", 'yellow'); 1222 | print colored("$output\n", 'green'); 1223 | } 1224 | 1225 | sub print_info { 1226 | my $string = shift; 1227 | my $output = "$string"; 1228 | print colored("\n[I] ", 'yellow'); 1229 | print colored("$output\n", 'cyan'); 1230 | } 1231 | 1232 | sub print_error { 1233 | my $string = shift; 1234 | my $output = "$string"; 1235 | print colored("\n[E] ", 'yellow'); 1236 | print colored("$output\n", 'red'); 1237 | } 1238 | -------------------------------------------------------------------------------- /share-list.txt: -------------------------------------------------------------------------------- 1 | a$ 2 | b$ 3 | c$ 4 | d$ 5 | e$ 6 | f$ 7 | g$ 8 | h$ 9 | i$ 10 | j$ 11 | k$ 12 | l$ 13 | m$ 14 | n$ 15 | o$ 16 | p$ 17 | q$ 18 | r$ 19 | s$ 20 | t$ 21 | u$ 22 | v$ 23 | w$ 24 | x$ 25 | y$ 26 | z$ 27 | logon 28 | admin$ 29 | home 30 | tools 31 | share 32 | admin 33 | data 34 | dfs$ 35 | raid 36 | ipc$ 37 | public 38 | temp 39 | tmp 40 | code 41 | lp 42 | a 43 | b 44 | c 45 | d 46 | e 47 | f 48 | g 49 | h 50 | i 51 | j 52 | k 53 | l 54 | m 55 | n 56 | o 57 | p 58 | q 59 | r 60 | s 61 | t 62 | u 63 | v 64 | w 65 | x 66 | y 67 | z 68 | images 69 | --------------------------------------------------------------------------------