├── .gitignore ├── screenshots ├── credE.png ├── results.png └── screenshot.png ├── settings.json.example ├── Gemfile ├── Gemfile.lock ├── CredE.rb ├── lib ├── e.rb └── x.rb ├── README.md └── CredX.rb /.gitignore: -------------------------------------------------------------------------------- 1 | settings.json 2 | -------------------------------------------------------------------------------- /screenshots/credE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pry0cc/CredCatch/HEAD/screenshots/credE.png -------------------------------------------------------------------------------- /screenshots/results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pry0cc/CredCatch/HEAD/screenshots/results.png -------------------------------------------------------------------------------- /screenshots/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pry0cc/CredCatch/HEAD/screenshots/screenshot.png -------------------------------------------------------------------------------- /settings.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "breachcompilation_path": "~/Documents/Dumps/BreachCompilation/" 3 | } 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' do 2 | gem 'selenium-webdriver' 3 | gem 'nokogiri' 4 | gem 'ruby-progressbar' 5 | end -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | childprocess (0.9.0) 5 | ffi (~> 1.0, >= 1.0.11) 6 | ffi (1.9.25) 7 | mini_portile2 (2.3.0) 8 | nokogiri (1.8.5) 9 | mini_portile2 (~> 2.3.0) 10 | ruby-progressbar (1.10.0) 11 | rubyzip (1.2.2) 12 | selenium-webdriver (3.141.0) 13 | childprocess (~> 0.5) 14 | rubyzip (~> 1.2, >= 1.2.2) 15 | 16 | PLATFORMS 17 | ruby 18 | 19 | DEPENDENCIES 20 | nokogiri! 21 | ruby-progressbar! 22 | selenium-webdriver! 23 | 24 | BUNDLED WITH 25 | 1.16.2 26 | -------------------------------------------------------------------------------- /CredE.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'mechanize' 4 | require 'nokogiri' 5 | require 'namae' 6 | require 'optparse' 7 | require 'ruby-progressbar' 8 | require './lib/e.rb' 9 | 10 | trap "SIGINT" do 11 | puts "\nBye Bye, thanks for using CredE :)" 12 | exit 130 13 | end 14 | 15 | ARGV << '-h' if ARGV.empty? 16 | 17 | options = {} 18 | optparse = OptionParser.new do|opts| 19 | # Set a banner, displayed at the top 20 | # of the help screen. 21 | opts.banner = "Usage: CredE.rb " 22 | # Define the options, and what they do 23 | options[:company] = false 24 | opts.on( '-c', '--company "Company, Inc"', 'Name of Company on LinkedIn' ) do|company| 25 | options[:company] = company 26 | end 27 | 28 | options[:domain] = false 29 | opts.on( '-d', '--domain company.com', 'Domain name used with Email' ) do|domain| 30 | options[:domain] = domain 31 | end 32 | 33 | options[:format] = false 34 | opts.on( '-f', '--format "{first}.{last}@{domain}"', 'Format of email' ) do|email_format| 35 | options[:format] = email_format 36 | end 37 | 38 | options[:outfile] = false 39 | opts.on( '-o', '--outfile emails.txt', 'File to save the results' ) do|outfile| 40 | options[:outfile] = outfile 41 | end 42 | # This displays the help screen, all programs are 43 | # assumed to have this option. 44 | opts.on( '-h', '--help', 'Display this screen' ) do 45 | puts opts 46 | exit 47 | end 48 | end 49 | 50 | optparse.parse! 51 | 52 | if options[:domain] and options[:company] and options[:format] 53 | puts "[*] Initializing CredE..." 54 | credE = CredE.new(options[:domain], options[:company], options[:format]) 55 | puts "[+] Starting scan against #{options[:company]}" 56 | emails = credE.scan() 57 | puts "" 58 | puts "[*] Scan complete! Generated #{emails.length} emails!" 59 | puts "" 60 | 61 | if options[:outfile] 62 | file = File.open(options[:outfile], "w+") 63 | emails.each do |email| 64 | file.write(email + "\n") 65 | end 66 | file.close 67 | puts "[+] Emails saved to #{options[:outfile]}" 68 | else 69 | puts emails 70 | end 71 | end 72 | 73 | 74 | -------------------------------------------------------------------------------- /lib/e.rb: -------------------------------------------------------------------------------- 1 | class CredE 2 | def initialize(domain, company, email_format) 3 | @email_format = email_format 4 | @domain = domain 5 | @company = company 6 | @agent = Mechanize.new 7 | @agent.user_agent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36' 8 | end 9 | 10 | def format_email(first, last) 11 | domain = @domain 12 | f = first[0] 13 | l = last[0] 14 | 15 | # Since we're doing a sketchy eval statement, the gsub simply converts {} to #{} so that eval can understand it. 16 | # This is the secret sauce to {first}{last}@{domain} 17 | email = eval("email = \"#{@email_format.gsub('{', '#{')}\"") 18 | 19 | email 20 | end 21 | 22 | def pull(start = 1) 23 | data = {} 24 | html = @agent.get("https://www.bing.com/search?q=site%3Alinkedin.com%2Fin%20%22#{@company}%22&first=#{start}&afj=100&FORM=PERE").body 25 | page = Nokogiri::HTML(html) 26 | data['count'] = page.css('.sb_count').text 27 | data['names'] = [] 28 | page.css('li.b_algo').each do |result| 29 | data['names'].push(result.css('h2').css('a').text) 30 | end 31 | data 32 | end 33 | 34 | def parse_linkedstrings(string) 35 | firstchunk = string.split(' - ')[0] 36 | backup = firstchunk 37 | firstchunk.split(' ').each do |chunk| 38 | if chunk == chunk.upcase 39 | backup.gsub!(chunk, '') 40 | elsif chunk.include? '[' 41 | backup.gsub!(chunk, '') 42 | end 43 | end 44 | names = backup.tr(',.[]()@', '').split(' ') 45 | names 46 | end 47 | 48 | def scan() 49 | results = [] 50 | initial_pull = pull(1) 51 | results.push(*initial_pull['names']) 52 | total = initial_pull['count'].delete(',').split(' ')[0].to_i 53 | current_page = initial_pull['names'].length - 1 54 | 55 | 56 | # use whatever is smaller 57 | top = 500 >= total ? total : 500 58 | progressbar = ProgressBar.create(:format => '%a %e %B %p%% %t') 59 | 60 | until current_page >= top 61 | perc = (current_page.to_f / top.to_f) * 100 62 | progressbar.progress = perc 63 | 64 | this_pull = pull(current_page) 65 | results.push(*this_pull['names']) 66 | current_page = results.length - 1 67 | end 68 | 69 | emails = [] 70 | 71 | results.each do |result| 72 | data = {} 73 | group = parse_linkedstrings(result) 74 | begin 75 | data['first'] = group[0].capitalize 76 | data['last'] = group[-1].capitalize 77 | rescue StandardError 78 | # puts "opps" 79 | end 80 | begin 81 | emails.push(format_email(data["first"].downcase, data["last"].downcase)) 82 | rescue StandardError 83 | # puts "uber oops" 84 | end 85 | end 86 | 87 | return emails.uniq! 88 | end 89 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # THIS REPOSITORY HAS BEEN DEPRECATED SINCE WELEAKS CHANGED THEIR LAYOUT 2 | # CredX has become primarily a email generation tool and will be continued at github.com/navisecdelta/ 3 | 4 | 5 | # CredCatch - Dump + Leak Scanning 6 | --- 7 | 8 | CredCatch is a collection of tools for generating emails from Bing Dorks and scanning password dumps for emails in bulk. 9 | 10 | After you've got yourself a list of emails generated by PasswordSpraying toolkit, or many of the email generation/gathering tools, run this tool against those emails and it will scrape dump information from WeLeaksInfo using selenium. 11 | 12 | If you have a valid account, you can login and get plaintext credentials. 13 | 14 | 15 | --- 16 | # Usage 17 | 18 | ## CredE 19 | CredE is for Email generation, similar to https://github.com/byt3bl33d3r/SprayingToolkit, but fully headless, no more mitmdump, and no more clicking through 27 pages of Google, (no disrespect byt3bl33d3r :) 20 | 21 | ``` 22 | ./CredE.rb -c "Company, Inc" -d "company.com" -f "{f}{last}@{domain}" -o company_emails.txt 23 | ``` 24 | 25 | Easy as that! 26 | 27 | 28 | ## CredX 29 | CredX is for searching breaches and pulling plaintext credientials. It uses selenium-webdriver, so you will need that. There are multiple ways to use CredX. 30 | 31 | CredX can be used exclusively without using CredE, however CredE is nice if you want emails by themselves. You can also use the `-o` flag with CredX to save emails during a `--find` scan. 32 | 33 | #### You have a few options: 34 | 1. Just pull breaches (Like HIBP for multiple emails) -> Pulls from WeLeaks, no plaintext credientials 35 | 2. Pull breaches and then pull plaintext credientials from BreahCompilation (See Breachcompilation integration) 36 | 3. Pull breaches and plaintext credientials from Weleaks (you need a paid account), this uses the session token. 37 | 4. Do any of the following, except perform the email scraping/generation at the same time. (--find) 38 | 39 | --- 40 | 41 | ## Examples: 42 | ### Option 1. 43 | 44 | ``` 45 | ./CredX.rb --find -c "Company Name" -d "company.com" -f "{f}{last}@{domain}" 46 | ``` 47 | 48 | or 49 | 50 | ``` 51 | ./CredX.rb emails.txt 52 | ``` 53 | 54 | ### Option 2. 55 | 56 | (If you specify the path in the settings.json, then specifying it is not needed) 57 | 58 | ``` 59 | ./CredX.rb --find -c "Company Name" -d "company.com" -f "{f}{last}@{domain} --breachpath /path/to/breachcompilation" 60 | ``` 61 | 62 | or 63 | 64 | ``` 65 | ./CredX.rb --breachpath /path/to/breachcompilation emails.txt" 66 | ``` 67 | 68 | ### Option 3. 69 | ``` 70 | ./CredX.rb -s session_token emails.txt 71 | ``` 72 | 73 | or 74 | 75 | ``` 76 | /CredX.rb -s session_token --find -c "Company Name" -d "company.com" -f "{first}.{last}@{domain}" 77 | ``` 78 | 79 | 80 | ### Configurating BreachCompilation Integration 81 | If you've ever used the BreachCompilation database, you'll know it has some good stuff in it. If you don't have it, you can download it with this magnet link: 82 | 83 | ``` 84 | magnet:?xt=urn:btih:7ffbcd8cee06aba2ce6561688cf68ce2addca0a3&dn=BreachCompilation&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Fglotorrents.pw%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337 85 | ``` 86 | 87 | Once you've got this saved, you can either specify it's path with the `./CredCatch.rb -b /path/to/breachcompilation`, or `cp settings.json.example settings.json`, and add in your path to settings.json. 88 | 89 | # Screenshots 90 | --- 91 | ## CredE 92 | ![](https://raw.githubusercontent.com/pry0cc/CredCatch/master/screenshots/credE.png) 93 | 94 | ## Running 95 | ![](https://raw.githubusercontent.com/pry0cc/CredCatch/master/screenshots/screenshot.png) 96 | 97 | ## Results 98 | ![](https://raw.githubusercontent.com/pry0cc/CredCatch/master/screenshots/results.png) 99 | 100 | -------------------------------------------------------------------------------- /CredX.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'selenium-webdriver' 4 | require 'nokogiri' 5 | require 'json' 6 | require 'optparse' 7 | require 'mechanize' 8 | require 'ruby-progressbar' 9 | require './lib/x.rb' 10 | require './lib/e.rb' 11 | 12 | trap "SIGINT" do 13 | puts "\nBye Bye, thanks for using CredX :)" 14 | exit 130 15 | end 16 | 17 | ARGV << '-h' if ARGV.empty? 18 | 19 | options = {} 20 | optparse = OptionParser.new do|opts| 21 | # Set a banner, displayed at the top 22 | # of the help screen. 23 | opts.banner = "Usage: CredX.rb [options] emails.txt" 24 | # Define the options, and what they do 25 | options[:breachpath] = false 26 | opts.on( '-l', '--breachpath FILE', 'Path of BreachCompliation Location' ) do|file| 27 | options[:breachpath] = file 28 | end 29 | options[:session_id] = false 30 | opts.on( '-s', '--session TOKEN', 'PHP_SESSION Cookie Value' ) do|session_id| 31 | options[:session_id] = session_id 32 | end 33 | 34 | options[:find] = false 35 | opts.on('--find', 'Scrape Emails using CredE' ) do 36 | options[:find] = true 37 | end 38 | 39 | # Options that are used with the --find flag 40 | 41 | options[:company] = false 42 | opts.on( '-c', '--company "Company, Inc"', 'Name of Company on LinkedIn' ) do|company| 43 | options[:company] = company 44 | end 45 | 46 | options[:domain] = false 47 | opts.on( '-d', '--domain company.com', 'Domain name used with Email' ) do|domain| 48 | options[:domain] = domain 49 | end 50 | 51 | options[:format] = false 52 | opts.on( '-f', '--format "{first}.{last}@{domain}"', 'Format of email' ) do|email_format| 53 | options[:format] = email_format 54 | end 55 | 56 | options[:outfile] = false 57 | opts.on( '-o', '--outfile emails.txt', 'File to save the results' ) do|outfile| 58 | options[:outfile] = outfile 59 | end 60 | 61 | # This displays the help screen, all programs are 62 | # assumed to have this option. 63 | opts.on( '-h', '--help', 'Display this screen' ) do 64 | puts opts 65 | exit 66 | end 67 | end 68 | 69 | optparse.parse! 70 | 71 | filename = ARGV[0] 72 | 73 | 74 | if options[:breachpath] 75 | if File.exist?("settings.json") 76 | @settings = JSON.parse(File.open("settings.json").read()) 77 | if !File.exist?(@settings["breachcompilation_path"] + "/query.sh") 78 | @settings["breachcompilation_path"] = false 79 | puts "That breach compilation path doesn't exist or query.sh doesn't exist. Please check the readme." 80 | end 81 | else 82 | @settings = {} 83 | @settings["breachcompilation_path"] = false 84 | end 85 | 86 | else 87 | @settings = {} 88 | @settings["breachcompilation_path"] = false 89 | end 90 | 91 | if options[:session_id] 92 | @settings["session_id"] = options[:session_id] 93 | puts "[+] Session key specified! Will pull from WeLeakInfo rather than from BreachCompliation" 94 | else 95 | @settings["session_id"] = false 96 | end 97 | 98 | if options[:find] 99 | if options[:domain] and options[:company] and options[:format] 100 | puts "[*] Email Generation Option Selected..." 101 | puts "[*] Initializing CredE..." 102 | credE = CredE.new(options[:domain], options[:company], options[:format]) 103 | puts "[+] Starting scan against #{options[:company]}" 104 | emails = credE.scan() 105 | puts "" 106 | 107 | # Do Scan with these emails 108 | if emails.length > 0 109 | puts "[*] Scan complete! Generated #{emails.length} emails!" 110 | puts "[*] Initializing CredX...." 111 | thebot = CredX.new(@settings) 112 | puts "[+] Loading #{filename}" 113 | thebot.ingest_emails(emails) 114 | puts "[*] Beginning scan" 115 | thebot.scan_all() 116 | puts "[*] Scan complete!" 117 | thebot.get_summary() 118 | thebot.end() 119 | else 120 | puts "[-] Sorry... We couldn't find any emails. Try tweaking the company name." 121 | end 122 | 123 | if options[:outfile] 124 | file = File.open(options[:outfile], "w+") 125 | emails.each do |email| 126 | file.write(email + "\n") 127 | end 128 | file.close 129 | puts "[+] Emails saved to #{options[:outfile]}" 130 | end 131 | else 132 | puts "[-] You didn't specify enough args" 133 | end 134 | else 135 | if File.exist?(filename) 136 | puts "[*] Initializing CredGet...." 137 | thebot = CredX.new(@settings) 138 | puts "[+] Loading #{filename}" 139 | thebot.load_emails(filename) 140 | puts "[*] Beginning scan" 141 | thebot.scan_all() 142 | puts "[*] Scan complete!" 143 | thebot.get_summary() 144 | thebot.end() 145 | else 146 | puts "Whoops that file doesn't exit..." 147 | end 148 | end 149 | -------------------------------------------------------------------------------- /lib/x.rb: -------------------------------------------------------------------------------- 1 | class CredX 2 | 3 | def initialize(settings) 4 | @breachcompilation_path = settings["breachcompilation_path"] 5 | @session_id = settings["session_id"] 6 | @data = {} 7 | @data["scanned"] = 0 8 | @emails = {} 9 | @summary = {} 10 | @driver = Selenium::WebDriver.for :firefox 11 | 12 | @driver.navigate.to "https://weleakinfo.com/" 13 | 14 | wait = Selenium::WebDriver::Wait.new(timeout: 30) 15 | wait.until { @driver.find_element(name: "query") } 16 | if @session_id 17 | self.login(@session_id) 18 | end 19 | end 20 | 21 | def login(session_id) 22 | cookies = @driver.manage.all_cookies() 23 | cookies.each do |cookie| 24 | if cookie[:name] == "PHP_SESSION" 25 | cookie[:value] = session_id 26 | @driver.manage.delete_cookie("PHP_SESSION") 27 | @driver.manage.add_cookie(opts = cookie) 28 | end 29 | end 30 | @driver.navigate.to "https://weleakinfo.com/" 31 | end 32 | 33 | def end() 34 | @driver.close() 35 | end 36 | 37 | def load_emails(filename) 38 | @filename = filename 39 | f = File.open(filename).read() 40 | f.split("\n").each do |email| 41 | @emails[email.gsub("'", "")] = [] 42 | end 43 | end 44 | 45 | def ingest_emails(emails) 46 | emails.each do |email| 47 | @emails[email] = [] 48 | end 49 | end 50 | 51 | def scan_all() 52 | progressbar = ProgressBar.create(:format => '%a %e %B %p%% %t') 53 | @data["total"] = @emails.length 54 | @emails.each do |email, data| 55 | if @session_id 56 | res = self.logged_in_search(email, "email") 57 | else 58 | res = self.search(email, "email") 59 | end 60 | @data["scanned"] += 1 61 | # puts "Scanned = #{@data["scanned"]} total = #{@data["total"]}" 62 | percentage = (@data["scanned"].to_f / @data["total"].to_f) * 100 63 | 64 | progressbar.progress = percentage 65 | @emails[email] = res 66 | end 67 | end 68 | 69 | def get_results_raw() 70 | return @emails 71 | end 72 | 73 | def get_summary() 74 | @emails.each do |email, results| 75 | if results.length > 0 76 | @summary[email] = results 77 | end 78 | end 79 | 80 | puts "---- Results for #{@filename} ----" 81 | 82 | @summary.each do |email, results| 83 | puts "\n#{email}" 84 | results.each do |result| 85 | puts "--> #{result}" 86 | end 87 | end 88 | puts "-----------------------------------" 89 | end 90 | 91 | def get_creds(email) 92 | 93 | script = @breachcompilation_path + "/query.sh" 94 | res = `#{script} #{email} 2>/dev/null` 95 | 96 | creds = [] 97 | 98 | res.split("\n").each do | cred | 99 | creds.push(cred) 100 | end 101 | 102 | if creds.length < 1 103 | creds = "" 104 | end 105 | 106 | return creds 107 | end 108 | 109 | def search(query, type) 110 | sleep 0.2 111 | @driver.execute_script("window.scrollTo(0,0)") 112 | sleep 0.5 113 | @driver.find_element(name: "query").send_keys query 114 | @driver.find_element(:name, "type").find_element(:css,"option[value='#{type}']").click 115 | @driver.find_element(:name, "search").click 116 | 117 | src = @driver.page_source 118 | res = Nokogiri::HTML(src).css(".poorfag") 119 | 120 | results = [] 121 | 122 | res.each do |breach| 123 | database = breach.css(".database").text 124 | 125 | results.push(database) 126 | end 127 | 128 | 129 | if @breachcompilation_path 130 | creds = self.get_creds(query) 131 | if creds != "" 132 | results.push(creds) 133 | end 134 | end 135 | 136 | return results 137 | end 138 | 139 | def logged_in_search(query, type) 140 | element = @driver.find_element(name: "query") 141 | sleep 0.2 142 | @driver.execute_script("window.scrollTo(0,0)") 143 | sleep 0.5 144 | 145 | element.send_keys query 146 | 147 | @driver.find_element(:name, "type").find_element(:css,"option[value='#{type}']").click 148 | @driver.find_element(:name, "search").click 149 | 150 | src = @driver.page_source 151 | results = Nokogiri::HTML(src).css(".result") 152 | 153 | breaches = [] 154 | 155 | results.each do |result| 156 | breach = {} 157 | title = result.css(".panel-title").text.split("Copy to Clipboard")[0] 158 | breach["title"] = title 159 | items = result.css("pre").text.split("\n") 160 | items.each do |item| 161 | key, value = item.split(": ") 162 | breach[key] = value 163 | end 164 | breaches.push(breach) 165 | end 166 | 167 | return breaches 168 | end 169 | 170 | end --------------------------------------------------------------------------------