From 505a921190ba53027b383e8efd8df163423ee81e Mon Sep 17 00:00:00 2001 From: perp Date: Mon, 29 Aug 2022 18:23:03 +0100 Subject: [PATCH] -e --- .gitignore | 2 + yoink.py | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 .gitignore create mode 100644 yoink.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71752fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +keys.txt +valid.txt diff --git a/yoink.py b/yoink.py new file mode 100644 index 0000000..a8e80c2 --- /dev/null +++ b/yoink.py @@ -0,0 +1,134 @@ +import argparse +import aiohttp +import asyncio + +from rich.tree import Tree +from rich.text import Text +from rich import print as rprint + +class Yoink: + """ + Yoink is a program to verify Shodan keys + """ + + def __init__(self, file, filt, output): + """ + Constructor. + + Args: + file: string, Shodan keys + filt: string, Filter for Shodan keys + output: string, Output file to write + """ + + self.file = file + self.filter = filt + self.output = output + self.tree = Tree("[bold yellow]Shodan Keys", guide_style="bold yellow") + self.tasks = [] + self.valid = [] + self.checked = 0 + + async def add_tree(self, key, query_credits, scan_credits, plan): + """ + Add the key to a tree + + Args: + key: string, Current valid key + query_credits: int, Query credits left + scan_credits: int, Scan credits left + plan: str, Current plan + """ + + self.valid.append(key) + text = self.tree.add(f"[green]Key: [bold blue]{key}") + text.add(f"[green]Plan: [blue]{plan}") + text.add(f"[green]Query Credits: [blue]{query_credits}") + text.add(f"[blue]Scan Credits: [green]{scan_credits}") + + + async def verify(self, session, key): + """ + Verify the key by a GET request. + + Args: + session: object, AioHTTP ClientSession + key: str, Shodan key + """ + + # Loop forever (Ratelimit retries) + while True: + # GET request to API + async with session.get(f"https://api.shodan.io/api-info?key={key}") as request: + # 200 worked + if request.status == 200: + # Parse the JSON + json = await request.json() + query_credits = json["query_credits"] + scan_credits = json["scan_credits"] + plan = json["plan"] + + # We don't want empty credits + if scan_credits != 0 or query_credits != 0: + # Check the plan with filter + match plan: + case "oss": + if self.filter == "oss": + await self.add_tree(key, query_credits, scan_credits, plan) + + case "dev": + if self.filter == "dev": + await self.add_tree(key, query_credits, scan_credits, plan) + + case "edu": + if self.filter == "edu": + await self.add_tree(key, query_credits, scan_credits, plan) + + case _: + await self.add_tree(key, query_credits, scan_credits, plan) + break + + # 429 ratelimited + elif request.status == 429: + await asyncio.sleep(2) + continue + + self.checked += 1 + + async def run(self): + """ + Creates AioHTTP ClientSession, open the file, add each key as a task, gathers the tasks. + """ + + # Create a reusable session + async with aiohttp.ClientSession() as session: + # Open the keys file + with open(self.file, "r") as file: + # Create each task & append + for key in file.readlines(): + task = asyncio.ensure_future(self.verify(session, key.strip())) + self.tasks.append(task) + + # Start each task + await asyncio.gather(*self.tasks) + + rprint(self.tree) + rprint(f"Checked [bold blue]{self.checked}[reset], Valid/Filtered [bold green]{len(self.valid)}[reset]") + + if self.output != None: + # Save to output file + with open(self.output, "a") as file: + for key in self.valid: + file.write(key+"\n") + +if __name__ == "__main__": + # Add arguments & parse + parser = argparse.ArgumentParser(description="Yoink is a program to verify Shodan keys") + parser.add_argument("-f", "--file", help="Path to Shodan keys", required=True) + parser.add_argument("-t", "--filter", help="Filter type of Shodan plan (oss, dev, edu)", required=False) + parser.add_argument("-o", "--output", help="Path to output", required=False) + args = parser.parse_args() + + # Create event loop & run + loop = asyncio.new_event_loop() + loop.run_until_complete(Yoink(args.file, args.filter, args.output).run())