Merge branch 'resolutions' into main
This commit is contained in:
@@ -32,7 +32,7 @@ class GetWebsiteText:
|
||||
return True
|
||||
|
||||
def text_from_html(body):
|
||||
soup = BeautifulSoup(body, 'html.parser')
|
||||
soup = BeautifulSoup(body, 'lxml')
|
||||
texts = soup.findAll(text=True)
|
||||
visible_texts = filter(tag_visible, texts)
|
||||
return u" ".join(t.strip() for t in visible_texts if t.strip() != '')
|
||||
|
||||
@@ -13,7 +13,7 @@ class ShodanSearch:
|
||||
'plans: https://account.shodan.io/billing',
|
||||
'type': 'String',
|
||||
'value': '',
|
||||
'globals': True},
|
||||
'global': True},
|
||||
|
||||
'Number of results': {'description': 'Enter the maximum number of results you want returned.',
|
||||
'type': 'String',
|
||||
|
||||
@@ -14,7 +14,7 @@ class ShodanSearchCertSerial:
|
||||
'plans: https://account.shodan.io/billing',
|
||||
'type': 'String',
|
||||
'value': '',
|
||||
'globals': True},
|
||||
'global': True},
|
||||
|
||||
'Number of results': {'description': 'Enter the maximum number of results you want returned.',
|
||||
'type': 'String',
|
||||
|
||||
101
Modules/Username_Crosscheck/DoTheyExist.py
Normal file
101
Modules/Username_Crosscheck/DoTheyExist.py
Normal file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
class DoTheyExist:
|
||||
name = "JS-Based Account Check"
|
||||
category = "Online Identity"
|
||||
description = "Check if an email, username or phone number exists as part of an account in certain sites. " \
|
||||
"The checks involve sites that do not explicitly respond to enumeration attempts in a way that can " \
|
||||
"be detected without Javascript."
|
||||
originTypes = {'Email Address', 'Phone Number', 'Phrase'}
|
||||
resultTypes = {'Domain'}
|
||||
|
||||
parameters = {'Include Noisy Checks': {'description': 'Should we check for accounts in domains that will notify '
|
||||
'the user that someone is investigating them?',
|
||||
'type': 'SingleChoice',
|
||||
'value': {'Include noisy sites', 'Do not include noisy sites'},
|
||||
'default': 'Do not include noisy sites'}}
|
||||
|
||||
def resolution(self, entityJsonList, parameters):
|
||||
import json
|
||||
import tldextract
|
||||
from pathlib import Path
|
||||
from playwright.sync_api import sync_playwright, Error
|
||||
from time import sleep
|
||||
|
||||
directory = Path(__file__).parent.resolve()
|
||||
with open(directory / 'js_web_accounts_json.json') as web_accounts_list:
|
||||
file = json.load(web_accounts_list)
|
||||
noisyParameter = parameters['Include Noisy Checks'] == 'Do not include noisy sites'
|
||||
|
||||
returnResults = []
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.firefox.launch(headless=True)
|
||||
context = browser.new_context(
|
||||
viewport={'width': 1920, 'height': 1080}
|
||||
)
|
||||
page = context.new_page()
|
||||
|
||||
for entity in entityJsonList:
|
||||
uid = entity['uid']
|
||||
entityType = entity['Entity Type']
|
||||
primaryField = entity[list(entity)[1]]
|
||||
|
||||
for site in file['sites']:
|
||||
if not site['enabled']:
|
||||
continue
|
||||
if (entityType == 'Email Address' and not site['accepts_email']) or \
|
||||
(entityType == 'Phrase' and not site['accepts_username']) or \
|
||||
(entityType == 'Phone Number' and not site['accepts_phone']):
|
||||
continue
|
||||
if site['noisy'] and noisyParameter:
|
||||
continue
|
||||
try:
|
||||
siteURL = site['login_page']
|
||||
page.goto(siteURL)
|
||||
sleep(1)
|
||||
|
||||
for preparationLocator in site['preparation_locators']:
|
||||
if preparationLocator[1]:
|
||||
page.frame_locator(preparationLocator[1]).locator(preparationLocator[0]).click()
|
||||
else:
|
||||
page.locator(preparationLocator[0]).click()
|
||||
|
||||
page.locator(site['login_username_locator']).fill(primaryField)
|
||||
|
||||
usernameSubmitLocator = site['username_submit_locator']
|
||||
if usernameSubmitLocator:
|
||||
page.locator(usernameSubmitLocator).click()
|
||||
|
||||
passwordLocator = site['password_locator']
|
||||
if passwordLocator:
|
||||
page.locator(passwordLocator).fill('aaaaaa')
|
||||
page.locator(site['login_submit_locator']).click()
|
||||
|
||||
try:
|
||||
page.locator(site['account_missing_locator']).focus(timeout=10000)
|
||||
# If we hit the missing locator, then move on to the next site to check.
|
||||
continue
|
||||
except Error:
|
||||
# If we can't find the missing locator, continue as normal.
|
||||
pass
|
||||
|
||||
for successLocator in site['account_existence_locators']:
|
||||
try:
|
||||
# We've already waited 10 secs for the missing locator, we can speed through finding
|
||||
# the success locator.
|
||||
page.locator(successLocator).focus(timeout=500)
|
||||
returnResults.append([{'Domain Name': tldextract.extract(siteURL).fqdn,
|
||||
'Entity Type': 'Domain'},
|
||||
{uid: {'Resolution': 'Account Found',
|
||||
'Notes': ''}}])
|
||||
break
|
||||
except Error:
|
||||
pass
|
||||
except Error:
|
||||
continue
|
||||
|
||||
sleep(5)
|
||||
|
||||
return returnResults
|
||||
86
Modules/Username_Crosscheck/PinterestUsersSearch.py
Normal file
86
Modules/Username_Crosscheck/PinterestUsersSearch.py
Normal file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
|
||||
class PinterestUsersSearch:
|
||||
name = "Pinterest People Search"
|
||||
category = "Online Identity"
|
||||
description = "Use Pinterest's search to find user profiles using Email Addresses, Phone Numbers or Phrases."
|
||||
originTypes = {'Email Address', 'Phrase', 'Phone Number'}
|
||||
resultTypes = {'Social Media Handle'}
|
||||
|
||||
parameters = {}
|
||||
|
||||
def resolution(self, entityJsonList, parameters):
|
||||
from playwright.sync_api import sync_playwright, Error
|
||||
from time import sleep
|
||||
from bs4 import BeautifulSoup
|
||||
from PySide6.QtCore import QByteArray, QBuffer, QIODevice, QSize
|
||||
from PySide6.QtGui import QImage
|
||||
from random import random
|
||||
import requests
|
||||
|
||||
baseURL = "https://www.pinterest.com/search/users/?q="
|
||||
|
||||
returnResults = []
|
||||
|
||||
with sync_playwright() as p:
|
||||
browser = p.firefox.launch()
|
||||
context = browser.new_context(
|
||||
viewport={'width': 1920, 'height': 1080}
|
||||
)
|
||||
page = context.new_page()
|
||||
try:
|
||||
page.goto(baseURL)
|
||||
except Error:
|
||||
return "Error occurred when trying to navigate to Pinterest."
|
||||
|
||||
for entity in entityJsonList:
|
||||
uid = entity['uid']
|
||||
primaryField = entity[list(entity)[1]]
|
||||
|
||||
try:
|
||||
page.goto(baseURL + primaryField, wait_until="networkidle", timeout=60000)
|
||||
# Wait until everything is 100% loaded, just in case.
|
||||
sleep(10)
|
||||
|
||||
soup = BeautifulSoup(page.content(), "lxml")
|
||||
listElements = soup.find_all(attrs={'role': 'listitem'})
|
||||
|
||||
for listElement in listElements:
|
||||
username = listElement.find('a')['href'][1:-1]
|
||||
href = "https://www.pinterest.com/" + username + "/"
|
||||
imgElement = listElement.find('img')
|
||||
textStrings = listElement.findAll(text=True)
|
||||
prettyName = textStrings[0]
|
||||
followerNumber = textStrings[1]
|
||||
|
||||
childIconByteArrayFin = None
|
||||
if imgElement:
|
||||
try:
|
||||
childPinterestAccIconRequest = requests.get(imgElement['src'])
|
||||
childIconByteArray = QByteArray(childPinterestAccIconRequest.content)
|
||||
childIconImageOriginal = QImage().fromData(childIconByteArray)
|
||||
childIconImageScaled = childIconImageOriginal.scaled(QSize(40, 40))
|
||||
childIconByteArrayFin = QByteArray()
|
||||
childImageBuffer = QBuffer(childIconByteArrayFin)
|
||||
childImageBuffer.open(QIODevice.WriteOnly)
|
||||
childIconImageScaled.save(childImageBuffer, "PNG")
|
||||
childImageBuffer.close()
|
||||
except Exception:
|
||||
childIconByteArrayFin = None
|
||||
|
||||
returnResults.append([{'User Name': username,
|
||||
'Pretty Name': prettyName,
|
||||
'Profile URL': href,
|
||||
'Instagram Followers': followerNumber,
|
||||
'Entity Type': 'Social Media Handle',
|
||||
'Icon': childIconByteArrayFin},
|
||||
{uid: {'Resolution': 'Account Found',
|
||||
'Notes': ''}}])
|
||||
except Error:
|
||||
pass
|
||||
|
||||
# Wait a bit before moving on to the next query.
|
||||
sleep(2 + random())
|
||||
|
||||
return returnResults
|
||||
206
Modules/Username_Crosscheck/js_web_accounts_json.json
Normal file
206
Modules/Username_Crosscheck/js_web_accounts_json.json
Normal file
@@ -0,0 +1,206 @@
|
||||
{
|
||||
"license": [
|
||||
"Copyright (C) 2022 AccentuSoft",
|
||||
"This work is licensed under AGPL version 3. A copy of the licence can be found here: ",
|
||||
"https://www.gnu.org/licenses/agpl-3.0.en.html"
|
||||
],
|
||||
"authors": [
|
||||
"AccentuSoft"
|
||||
],
|
||||
"categories": [
|
||||
"tech",
|
||||
"travel",
|
||||
"art",
|
||||
"hobby",
|
||||
"social"
|
||||
],
|
||||
"sites": [
|
||||
{
|
||||
"name": "AirBnB",
|
||||
"login_page": "https://www.airbnb.com/signup_login",
|
||||
"preparation_locators": [["[data-testid=\"social-auth-button-email\"]", ""]],
|
||||
"login_username_locator": "[data-testid=\"email-login-email\"]",
|
||||
"username_submit_locator": "",
|
||||
"password_locator": "",
|
||||
"login_submit_locator": "[data-testid=\"signup-login-submit-btn\"]",
|
||||
"account_existence_locators": ["[data-testid=\"forgot-password-link\"]", "text=Welcome "],
|
||||
"account_missing_locator": "[data-testid=\"email-signup-user\\[first_name\\]\"]",
|
||||
"category": "tech",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": false,
|
||||
"accepts_username": false,
|
||||
"noisy": false,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Duolingo",
|
||||
"login_page": "https://www.duolingo.com/",
|
||||
"preparation_locators": [["[data-test=\"have-account\"]", ""]],
|
||||
"login_username_locator": "[data-test=\"email-input\"]",
|
||||
"username_submit_locator": "",
|
||||
"password_locator": "[data-test=\"password-input\"]",
|
||||
"login_submit_locator": "[data-test=\"register-button\"]",
|
||||
"account_existence_locators": ["text=Wrong Password. Please try again."],
|
||||
"account_missing_locator": "text=There is no Duolingo account associated with",
|
||||
"category": "hobby",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": false,
|
||||
"accepts_username": true,
|
||||
"noisy": false,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Etsy",
|
||||
"login_page": "https://www.etsy.com/",
|
||||
"preparation_locators": [["text=Accept", ""], ["text=Sign in", ""]],
|
||||
"login_username_locator": "input[name=\"email\"]",
|
||||
"username_submit_locator": "",
|
||||
"password_locator": "input[name=\"password\"]",
|
||||
"login_submit_locator": "button[name=\"submit_attempt\"]",
|
||||
"account_existence_locators": ["text=Password was incorrect"],
|
||||
"account_missing_locator": "text=Email address is invalid.",
|
||||
"category": "hobby",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": false,
|
||||
"accepts_username": false,
|
||||
"noisy": false,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Facebook",
|
||||
"login_page": "https://www.facebook.com/login/identify/?ctx=recover&ars=facebook_login&from_login_screen=0",
|
||||
"preparation_locators": [["text=Only allow essential cookies", ""]],
|
||||
"login_username_locator": "[placeholder=\"Email or mobile number\"]",
|
||||
"username_submit_locator": "",
|
||||
"password_locator": "",
|
||||
"login_submit_locator": "button:has-text(\"Search\")",
|
||||
"account_existence_locators": ["text=How do you want to receive the code to reset your password?"],
|
||||
"account_missing_locator": "text=No search results",
|
||||
"category": "social",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": true,
|
||||
"accepts_username": false,
|
||||
"noisy": false,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Flickr",
|
||||
"login_page": "https://www.flickr.com/",
|
||||
"preparation_locators": [["text=Reject All", ".truste_popframe"], ["text=Close", ".truste_popframe"], ["text=Log In", ""]],
|
||||
"login_username_locator": "[data-testid=\"identity-email-input\"]",
|
||||
"username_submit_locator": "[data-testid=\"identity-form-submit-button\"]",
|
||||
"password_locator": "[data-testid=\"identity-password-input\"]",
|
||||
"login_submit_locator": "[data-testid=\"identity-form-submit-button\"]",
|
||||
"account_existence_locators": ["text=Invalid password"],
|
||||
"account_missing_locator": "text=Invalid email or password.",
|
||||
"category": "hobby",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": false,
|
||||
"accepts_username": false,
|
||||
"noisy": false,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Github",
|
||||
"login_page": "https://github.com/join",
|
||||
"preparation_locators": [],
|
||||
"login_username_locator": "input[name=\"user\\[email\\]\"]",
|
||||
"username_submit_locator": "",
|
||||
"password_locator": "",
|
||||
"login_submit_locator": "input[name=\"user\\[password\\]\"]",
|
||||
"account_existence_locators": ["dd:has-text(\"Email is invalid or already taken\")"],
|
||||
"account_missing_locator": "input[name=\"user\\[email\\]\"].form-control.input.py-1.is-autocheck-successful",
|
||||
"category": "social",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": false,
|
||||
"accepts_username": false,
|
||||
"noisy": false,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Gravatar",
|
||||
"login_page": "https://en.gravatar.com/",
|
||||
"preparation_locators": [["text=Sign in", ""]],
|
||||
"login_username_locator": "input[name=\"usernameOrEmail\"]",
|
||||
"username_submit_locator": "",
|
||||
"password_locator": "",
|
||||
"login_submit_locator": "text=Email Address or UsernamePasswordBy continuing, you agree to our Terms of Servic >> button",
|
||||
"account_existence_locators": ["label:has-text(\"Password\")", "text=Please log in using your WordPress.com username instead of your email address."],
|
||||
"account_missing_locator": "text=User does not exist. Would you like to create a new account?",
|
||||
"category": "social",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": false,
|
||||
"accepts_username": true,
|
||||
"noisy": false,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Instagram",
|
||||
"login_page": "https://www.instagram.com/accounts/login/",
|
||||
"preparation_locators": [["text=Only allow essential cookies", ""]],
|
||||
"login_username_locator": "[aria-label=\"Phone number\\, username\\, or email\"]",
|
||||
"username_submit_locator": "",
|
||||
"password_locator": "[aria-label=\"Password\"]",
|
||||
"login_submit_locator": "button:has-text(\"Log In\") >> nth=0",
|
||||
"account_existence_locators": ["text=Sorry, your password was incorrect."],
|
||||
"account_missing_locator": "text=The username you entered doesn",
|
||||
"category": "social",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": true,
|
||||
"accepts_username": true,
|
||||
"noisy": false,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "LinkedIn",
|
||||
"login_page": "https://www.linkedin.com/",
|
||||
"preparation_locators": [["a:has-text(\"Sign in\")", ""]],
|
||||
"login_username_locator": "[aria-label=\"Email or Phone\"]",
|
||||
"username_submit_locator": "",
|
||||
"password_locator": "[aria-label=\"Password\"]",
|
||||
"login_submit_locator": "[aria-label=\"Sign in\"]",
|
||||
"account_existence_locators": ["text=That’s not the right password.", "text=Welcome Back"],
|
||||
"account_missing_locator": "text=Couldn’t find a LinkedIn account associated with this email. Please try again.",
|
||||
"category": "social",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": true,
|
||||
"accepts_username": false,
|
||||
"noisy": false,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Notion",
|
||||
"login_page": "https://www.notion.so/login",
|
||||
"preparation_locators": [],
|
||||
"login_username_locator": "[placeholder=\"Enter your email address\\.\\.\\.\"]",
|
||||
"username_submit_locator": "",
|
||||
"password_locator": "",
|
||||
"login_submit_locator": "text=Continue with email",
|
||||
"account_existence_locators": ["text=We just sent you a temporary login code."],
|
||||
"account_missing_locator": "text=We just sent you a temporary sign up code.",
|
||||
"category": "tech",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": false,
|
||||
"accepts_username": false,
|
||||
"noisy": true,
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Pinterest",
|
||||
"login_page": "https://www.pinterest.com/",
|
||||
"preparation_locators": [["[data-test-id=\"simple-login-button\"] button:has-text(\"Log in\")", ""]],
|
||||
"login_username_locator": "[placeholder=\"Email\"]",
|
||||
"username_submit_locator": "",
|
||||
"password_locator": "",
|
||||
"login_submit_locator": "[data-test-id=\"registerFormSubmitButton\"] button:has-text(\"Log in\")",
|
||||
"account_existence_locators": ["text=The password you entered is incorrect."],
|
||||
"account_missing_locator": "text=The email you entered does not belong to any account.",
|
||||
"category": "art",
|
||||
"accepts_email": true,
|
||||
"accepts_phone": false,
|
||||
"accepts_username": false,
|
||||
"noisy": false,
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user