Merge branch 'resolutions' into main

This commit is contained in:
AccentuSoft
2022-08-09 06:18:02 +03:00
6 changed files with 396 additions and 3 deletions

View File

@@ -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() != '')

View File

@@ -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',

View File

@@ -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',

View 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

View 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

View 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=Thats not the right password.", "text=Welcome Back"],
"account_missing_locator": "text=Couldnt 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
}
]
}