├── requirements.txt ├── examples ├── check.png ├── file.png ├── scrape.png ├── search.png ├── search1.png ├── getarchive.png ├── sensitive.png ├── strrange.png └── userpage.png ├── misc └── art │ ├── art6.txt │ ├── art7.txt │ ├── art8.txt │ ├── art1.txt │ ├── art5.txt │ ├── art2.txt │ ├── art9.txt │ ├── art3.txt │ ├── art10.txt │ └── art4.txt ├── LICENSE ├── README.md └── pasta.py /requirements.txt: -------------------------------------------------------------------------------- 1 | bs4 2 | argparse 3 | requests 4 | colored 5 | -------------------------------------------------------------------------------- /examples/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr0ff/Pasta/main/examples/check.png -------------------------------------------------------------------------------- /examples/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr0ff/Pasta/main/examples/file.png -------------------------------------------------------------------------------- /examples/scrape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr0ff/Pasta/main/examples/scrape.png -------------------------------------------------------------------------------- /examples/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr0ff/Pasta/main/examples/search.png -------------------------------------------------------------------------------- /examples/search1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr0ff/Pasta/main/examples/search1.png -------------------------------------------------------------------------------- /examples/getarchive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr0ff/Pasta/main/examples/getarchive.png -------------------------------------------------------------------------------- /examples/sensitive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr0ff/Pasta/main/examples/sensitive.png -------------------------------------------------------------------------------- /examples/strrange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr0ff/Pasta/main/examples/strrange.png -------------------------------------------------------------------------------- /examples/userpage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr0ff/Pasta/main/examples/userpage.png -------------------------------------------------------------------------------- /misc/art/art6.txt: -------------------------------------------------------------------------------- 1 | 2 | ______ _ _______ 3 | (_____ \ /\ | | (_______) /\ 4 | _____) ) \ \ \ _ / \ 5 | | ____/ /\ \ \ \| | / /\ \ 6 | | | | |__| |_____) ) |_____| |__| | 7 | |_| |______(______/ \______)______| 8 | -------------------------------------------------------------------------------- /misc/art/art7.txt: -------------------------------------------------------------------------------- 1 | 2 | dBBBBBb dBBBBBb .dBBBBP dBBBBBBP dBBBBBb 3 | dB' BB BP BB 4 | dBBBP' dBP BB `BBBBb dBP dBP BB 5 | dBP dBP BB dBP dBP dBP BB 6 | dBP dBBBBBBBdBBBBP' dBP dBBBBBBB 7 | -------------------------------------------------------------------------------- /misc/art/art8.txt: -------------------------------------------------------------------------------- 1 | 2 | ______ _______ ______ _______ _______ 3 | (_____ (_______)/ _____|_______|_______) 4 | _____) )______( (____ _ _______ 5 | | ____/ ___ |\____ \ | | | ___ | 6 | | | | | | |_____) ) | | | | | | 7 | |_| |_| |_(______/ |_| |_| |_| 8 | -------------------------------------------------------------------------------- /misc/art/art1.txt: -------------------------------------------------------------------------------- 1 | 2 | __________ _____ _________________________ 3 | \______ \/ _ \ / _____/\__ ___/ _ \ 4 | | ___/ /_\ \ \_____ \ | | / /_\ \ 5 | | | / | \/ \ | |/ | \ 6 | |____| \____|__ /_______ / |____|\____|__ / 7 | \/ \/ \/ 8 | -------------------------------------------------------------------------------- /misc/art/art5.txt: -------------------------------------------------------------------------------- 1 | 2 | 888 88e e Y8b dP"8 88P'888'Y88 e Y8b 3 | 888 888D d8b Y8b C8b Y P' 888 'Y d8b Y8b 4 | 888 88" d888b Y8b Y8b 888 d888b Y8b 5 | 888 d888888888b b Y8D 888 d888888888b 6 | 888 d8888888b Y8b 8edP 888 d8888888b Y8b 7 | -------------------------------------------------------------------------------- /misc/art/art2.txt: -------------------------------------------------------------------------------- 1 | 2 | __ __ _____ ______ _______ _____ 3 | /_/\__/\ /\___/\ / ____/\/\_______)\ /\___/\ 4 | ) ) ) ) )/ / _ \ \ ) ) __\/\(___ __\// / _ \ \ 5 | /_/ /_/ / \ \(_)/ / \ \ \ / / / \ \(_)/ / 6 | \ \ \_\/ / / _ \ \ _\ \ \ ( ( ( / / _ \ \ 7 | )_) ) ( (_( )_) ))____) ) \ \ \ ( (_( )_) ) 8 | \_\/ \/_/ \_\/ \____\/ /_/_/ \/_/ \_\/ 9 | -------------------------------------------------------------------------------- /misc/art/art9.txt: -------------------------------------------------------------------------------- 1 | 2 | _/\/\/\/\/\________/\/\________/\/\/\/\/\__/\/\/\/\/\/\______/\/\_____ 3 | _/\/\____/\/\____/\/\/\/\____/\/\______________/\/\________/\/\/\/\___ 4 | _/\/\/\/\/\____/\/\____/\/\____/\/\/\/\________/\/\______/\/\____/\/\_ 5 | _/\/\__________/\/\/\/\/\/\__________/\/\______/\/\______/\/\/\/\/\/\_ 6 | _/\/\__________/\/\____/\/\__/\/\/\/\/\________/\/\______/\/\____/\/\_ 7 | ______________________________________________________________________ 8 | -------------------------------------------------------------------------------- /misc/art/art3.txt: -------------------------------------------------------------------------------- 1 | 2 | 8888888b. d8888 .d8888b. 88888888888 d8888 3 | 888 Y88b d88888 d88P Y88b 888 d88888 4 | 888 888 d88P888 Y88b. 888 d88P888 5 | 888 d88P d88P 888 "Y888b. 888 d88P 888 6 | 8888888P" d88P 888 "Y88b. 888 d88P 888 7 | 888 d88P 888 "888 888 d88P 888 8 | 888 d8888888888 Y88b d88P 888 d8888888888 9 | 888 d88P 888 "Y8888P" 888 d88P 888 10 | -------------------------------------------------------------------------------- /misc/art/art10.txt: -------------------------------------------------------------------------------- 1 | 2 | MM"""""""`YM MMP"""""""MM MP""""""`MM M""""""""M MMP"""""""MM 3 | MM mmmmm M M' .mmmm MM M mmmmm..M Mmmm mmmM M' .mmmm MM 4 | M' .M M `M M. `YM MMMM MMMM M `M 5 | MM MMMMMMMM M MMMMM MM MMMMMMM. M MMMM MMMM M MMMMM MM 6 | MM MMMMMMMM M MMMMM MM M. .MMM' M MMMM MMMM M MMMMM MM 7 | MM MMMMMMMM M MMMMM MM Mb. .dM MMMM MMMM M MMMMM MM 8 | MMMMMMMMMMMM MMMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMM MMMMMMMMMMMM 9 | -------------------------------------------------------------------------------- /misc/art/art4.txt: -------------------------------------------------------------------------------- 1 | 2 | ,ggggggggggg, ,ggg, ,gg, ,ggggggggggggggg ,ggg, 3 | dP"""88""""""Y8, dP""8I i8""8idP""""""88""""""" dP""8I 4 | Yb, 88 `8b dP 88 `8,,8'Yb,_ 88 dP 88 5 | `" 88 ,8PdP 88 `88' `"" 88 dP 88 6 | 88aaaad8P",8' 88 dP"8, 88 ,8' 88 7 | 88""""" d88888888 dP' `8a 88 d88888888 8 | 88 __ ,8" 88 dP' `Yb 88 __ ,8" 88 9 | 88 dP" ,8P Y8 _ ,dP' I8gg, 88dP" ,8P Y8 10 | 88 Yb,_,dP `8b,"888,,____,dP "Yb,,8PYb,_,dP `8b, 11 | 88 "Y8P" `Y8a8P"Y88888P" "Y8P' "Y8P" `Y8 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Kr0ff 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | Pasta is a python 3 tool which performs PasteBin scraping without the use of PasteBin's scraping API. This makes Pasta free and doesn't require an acccount making it suitable for everyone. 3 | 4 | It is not as powerful as the PastaBin scraping API but should suffice with providing enough information to look for usernames, passwords, emails, IP addresses and maybe more. 5 | 6 | [![license](https://img.shields.io/github/license/Kr0ff/Pasta)](https://opensource.org/licenses/MIT) 7 | [![contributions](https://img.shields.io/badge/contribution-welcome-green)](https://github.com/Kr0ff/PenDock/issues) 8 | ![last commit](https://img.shields.io/github/last-commit/Kr0ff/Pasta?color=yellow&logo=Github) 9 | [![twitter](https://img.shields.io/twitter/follow/CptXrat?style=social)](https://twitter.com/CptXrat) 10 | [![github](https://img.shields.io/github/followers/Kr0ff?style=social)](https://github.com/Kr0ff) 11 | 12 | # Features 13 | 14 | * Ability to generate random 8 characters long strings similar to those identifying real PasteBin entries 15 | 16 | strrange 17 | 18 | * Ability to use the randomly generated strings and bruteforce PasteBin for possible hidden valid pastebins 19 | 20 | search 21 | 22 | * Ability to view the contents of PasteBin entry 23 | 24 | check 25 | 26 | * Ability to scrape the most recent archive of PasteBin 27 | 28 | scrape 29 | 30 | * Ability to look for sensitive information in downloaded pastebins [emails, usernames, IP addresses] 31 | 32 | sensitive 33 | 34 | * Ability to retrieve all pastebins of user's account from all available pages 35 | 36 | userpage 37 | 38 | * Ability to select which file to search for sensitive information 39 | 40 | file 41 | 42 | * Ability to select how many threads you want to use [-s, -d, -u] 43 | 44 | # Installation 45 | 46 | Installing the tool is as simple as running the following commands in the terminal: 47 | 48 | ```sh 49 | git clone https://github.com/Kr0ff/Pasta 50 | cd pasta 51 | chmod +x pasta.py 52 | ./pasta -h 53 | ``` 54 | 55 | This should greet you with the help menu of the tool 56 | 57 | ``` 58 | ______ _______ ______ _______ _______ 59 | (_____ (_______)/ _____|_______|_______) 60 | _____) )______( (____ _ _______ 61 | | ____/ ___ |\____ \ | | | ___ | 62 | | | | | | |_____) ) | | | | | | 63 | |_| |_| |_(______/ |_| |_| |_| 64 | 65 | ver: 0.3 66 | 67 | 68 | usage: pasta.py [-h] [-s] [-r RANGE_STR] [-c CHECK] [-g] [-d] [-e] [-u USERBIN] [-p PAGE] [-f FILE] [-t THREADS] 69 | 70 | Pasta - A PasteBin Scraper 71 | 72 | optional arguments: 73 | -h, --help show this help message and exit 74 | -s, --search Search PasteBin with a set of strings 75 | -r RANGE_STR, --range_str RANGE_STR 76 | How many strings to generate 77 | -c CHECK, --check CHECK 78 | Check contents of a specific PasteBin entry 79 | -g, --get_archive Get most recent PasteBin archive 80 | -d, --scrape Scrape the most recent archive and save each Pastebin 81 | -e, --sensitive Search for sensitive info from downloaded Pastebins 82 | -u USERBIN, --userbin USERBIN 83 | Retrieve the PasteBin posts of a user 84 | -p PAGE, --page PAGE Page number of user's PasteBins 85 | -f FILE, --file FILE Search PasteBin with a set of strings 86 | -t THREADS, --threads THREADS 87 | How many threads to use 88 | ``` 89 | 90 | # Liability 91 | This script has been created for academic purposes only and the developer takes no responsibility of its use ! 92 | -------------------------------------------------------------------------------- /pasta.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | try: 4 | import requests 5 | import argparse 6 | import sys 7 | import string 8 | import random 9 | import os 10 | import re 11 | 12 | from concurrent.futures import ThreadPoolExecutor 13 | from concurrent.futures.thread import BrokenThreadPool 14 | from colored import fg, attr 15 | from bs4 import BeautifulSoup 16 | except ImportError as i: 17 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Some libraries are missing !") 18 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Python error: {i}") 19 | 20 | # Disable insecure SSL warnings 21 | # requests.urllib3.disable_warnings() 22 | 23 | def random_ascii(): 24 | files = os.listdir("./misc/art/") 25 | random_ = random.choice(files) 26 | try: 27 | with open(f"./misc/art/{random_}", "r") as asciiart_: 28 | return asciiart_.read() 29 | except OSError: 30 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Cannot read/open {fg(134)}{random_}{attr(0)} !") 31 | 32 | def ascii(): 33 | 34 | art_ = random_ascii() 35 | printAscii_ = f"""{attr(1)}{fg(45)} 36 | {art_}{attr(0)} 37 | {fg(179)}ver: {attr(0)}{fg(106)}0.3{attr(0)} 38 | 39 | """ 40 | print(printAscii_) 41 | 42 | ''' 43 | Class to provide threading to other functions 44 | ''' 45 | class Threading: 46 | 47 | def __init__(self, prog, threads): 48 | self.threads = threads 49 | self.prog = prog 50 | 51 | def threadit(prog, threads): 52 | try: 53 | with ThreadPoolExecutor(max_workers=threads) as executer: 54 | executer.submit(prog) 55 | except Exception as e: 56 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Exception hit: [{fg(189)}{e}{attr(0)}]") 57 | 58 | ''' 59 | Class to search PasteBin with randomly generated 60 | 8 character string. 61 | 62 | The class can generate number of strings: 63 | - (Search.randomize_alpha()) 64 | 65 | The class can send a request for each generated 66 | string: 67 | - (Search.search_request()) 68 | ''' 69 | class Search: 70 | 71 | def __init__(self, str_range): 72 | self.str_range = int(str_range) 73 | 74 | # LA = Length of Alphabet 75 | # Essentially what string will be send to PasteBin 76 | def randomize_alpha(LA=8, str_range=0): 77 | 78 | alpha = string.ascii_letters + string.digits 79 | try: 80 | if str_range == 0: 81 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Number of strings can't be - {fg(13)}0{attr(0)}") 82 | sys.exit(1) 83 | 84 | elif str_range == 0: 85 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} No strings to use to search PasteBin !") 86 | print(f"{attr(1)}{fg(4)}[*]{attr(0)} Generating {fg(119)}100{attr(0)} to use...") 87 | Search.randomize_alpha(8, 100) 88 | 89 | except Exception as e: 90 | raise Exception(e) 91 | 92 | # Check if strings.txt exists where random strings will be inserted 93 | if not os.path.isfile("./strings.txt") and not os.path.exists("./strings.txt"): 94 | 95 | print(f"{attr(1)}{fg(129)}[?]{attr(0)} File {fg(13)}strings.txt{attr(0)} doesn't exist !") 96 | print(f"{attr(1)}{fg(4)}[*]{attr(0)} Making {fg(13)}strings.txt{attr(0)} !") 97 | 98 | strings_file = open("strings.txt", "w+") 99 | strings_file.close() 100 | 101 | else: 102 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} File {fg(13)}strings.txt{attr(0)} exists !") 103 | 104 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Writing {str_range} strings in {fg(13)}strings.txt{attr(0)} !") 105 | try: 106 | with open("./strings.txt", "w") as strings_file: 107 | for strings in range(str_range): 108 | strings = ''.join(random.sample(alpha, LA)) 109 | strings_file.write(strings) 110 | # Just need to apend a newline between each string 111 | strings_file.write('\n') 112 | 113 | strings_file.close() 114 | except OSError: 115 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Cannot read/open {fg(134)}strings.txt{attr(0)} !") 116 | 117 | def search_request(threads, str_range=0): 118 | 119 | if str_range != 0: 120 | Search.randomize_alpha(8, str_range) 121 | 122 | elif str_range == 0: 123 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} No strings to use to search PasteBin !") 124 | print(f"{attr(1)}{fg(4)}[*]{attr(0)} Generating {fg(119)}100{attr(0)} to use...") 125 | Search.randomize_alpha(8, 100) 126 | 127 | else: 128 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Something went wrong with generating strings to search PasteBin !") 129 | sys.exit(1) 130 | 131 | # Safari cuz why not look fancy :P 132 | user_agent = { 133 | "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15" 134 | } 135 | URL = "https://pastebin.com/raw/" 136 | 137 | # Initiallise GET request 138 | r = requests.Session() 139 | search = r.get(URL, 140 | headers=user_agent, 141 | # verify=False 142 | ) 143 | 144 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Using {threads} threads !") 145 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Requesting the following IDs\r\n") 146 | # Check each string in the strings.txt file 147 | try: 148 | with open("./strings.txt", "r") as strings_file: 149 | for string in strings_file: 150 | 151 | s = string.strip() 152 | search = r.get(f"{URL}{s}", 153 | headers=user_agent, 154 | # verify=False 155 | ) 156 | 157 | try: 158 | try: 159 | # Perform GET 160 | Threading.threadit(search, 161 | threads) 162 | except BrokenThreadPool: 163 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Threading exception hit !") 164 | 165 | # Find out what's the response code 166 | if search.status_code == 404: 167 | print(f"{attr(1)}{fg(3)}[!]{attr(0)} Response {fg(1)}404{attr(0)} for - {fg(1)}{s}{attr(0)}") 168 | 169 | elif search.status_code == 200: 170 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Response {fg(2)}200{attr(0)} for - {fg(6)}{s}{attr(0)}") 171 | print(f"- URL: {URL+s}\r\n") 172 | 173 | else: 174 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Response is different that 404 or 200 for - {fg(13)}{s}{attr(0)}") 175 | sys.exit(1) # Not sure if we should exit here...?? 176 | 177 | except KeyboardInterrupt: 178 | raise Exception(f"{attr(1)}{fg(203)}[x]{attr(0)} Killing the script...\r\n") 179 | 180 | strings_file.close() 181 | 182 | except OSError: 183 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Cannot read/open {fg(134)}strings.txt{attr(0)} !") 184 | 185 | ''' 186 | The class is able to get the most recent archive from PasteBin. 187 | It is able to view the contents of a specific PasteBin, 188 | for example: $ pasta.py -c KHK2ndnC 189 | - CheckBin.get_recent_archive() 190 | 191 | The class is able to check the contents of a user-provided ID. 192 | - CheckBin.view_pastebin(string) // Where string == KHK2ndnC 193 | ''' 194 | class CheckBin: 195 | 196 | # def __init__(self, archive): 197 | # self.archive = archive 198 | 199 | def get_recent_archive(archive): 200 | 201 | if not archive: 202 | 203 | # Set some variables 204 | HREF_REGEX = r"(.*?)<\/a>" 205 | user_agent = { 206 | "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15" 207 | } 208 | 209 | ARCHIVE_URL = requests.get('https://pastebin.com/archive', 210 | # verify=False, 211 | headers=user_agent) 212 | 213 | soup = BeautifulSoup(ARCHIVE_URL.content, 'html.parser') 214 | pastes = soup.find_all('a') 215 | 216 | # prints the necessary values using the HREF_REGEX above 217 | pastes_findall = re.findall(HREF_REGEX, str(pastes)) 218 | 219 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Grabbing a most recent PasteBin archive !\r\n") 220 | 221 | # Will grab only the title and id of each PasteBin in the recent archive 222 | try: 223 | # id = PasteBin ID - KHK2ndnC 224 | # t = PasteBin Title associated to the ID 225 | for id, t in pastes_findall: 226 | 227 | output = f"{t} -> {id}" 228 | get_valid = r'(.*?) \-\> ([A-Za-z\d+]{8})' 229 | final = re.search(get_valid, output) 230 | 231 | # Will check if the object type is NoneType 232 | # and will skip that object 233 | if final is None: 234 | pass 235 | 236 | else: 237 | final = final.group(0) 238 | print(f"{fg(186)}{attr(1)}{final}{attr(0)}") 239 | 240 | # Again, if there's an IndexError it's skipped 241 | except IndexError: 242 | pass 243 | 244 | elif archive: 245 | 246 | ARCHIVE_URL = "https://pastebin.com/archive/" 247 | HREF_REGEX = r"(.*?)<\/a>" 248 | user_agent = { 249 | "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15" 250 | } 251 | 252 | URL_REQUEST = requests.get(f'{ARCHIVE_URL}{archive}', 253 | # verify=False, 254 | headers=user_agent) 255 | 256 | soup = BeautifulSoup(URL_REQUEST.content, 'html.parser') 257 | pastes = soup.find_all('a') 258 | 259 | # prints the necessary values using the HREF_REGEX above 260 | pastes_findall = re.findall(HREF_REGEX, str(pastes)) 261 | 262 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Grabbing most recent PasteBin archive of {fg(166)}{archive}{attr(0)}\r\n") 263 | 264 | try: 265 | for id, t in pastes_findall: 266 | 267 | output = f"{t} -> {id}" 268 | get_valid = r'(.*?) \-\> ([A-Za-z\d+]{8})' 269 | final = re.search(get_valid, output) 270 | 271 | if final is None: 272 | pass 273 | 274 | else: 275 | final = final.group(0) 276 | print(f"{fg(186)}{attr(1)}{final}{attr(0)}") 277 | except IndexError: 278 | pass 279 | 280 | def view_pastebin(string): 281 | 282 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Checking the contents of {fg(12)}{string}{attr(0)}") 283 | 284 | # Simple check if the user-provided string is 8 chars long 285 | if string == "" or len(string) < 8 or len(string) > 8: 286 | print(f"{attr(1)}{fg(3)}[!]{attr(0)} An 8 character string has to be provided.") 287 | print(f"{attr(1)}{fg(3)}[!]{attr(0)} Example: {sys.argv[0]} -c \"KHK2ndnC\"") 288 | sys.exit(1) 289 | 290 | elif string != "" and len(string) == 8: 291 | 292 | r = requests.Session() 293 | RAW_URL = f"https://pastebin.com/raw/{string}" 294 | user_agent = { 295 | "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15" 296 | } 297 | 298 | search = r.get( 299 | RAW_URL, 300 | headers=user_agent, 301 | # verify=False 302 | ) 303 | 304 | # If the HTTP response is 200, write the contents of the PasteBin 305 | if search.status_code == 200: 306 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Saving the contents of {fg(12)}{string}{attr(0)} to {fg(3)}output/{string}.pastebin.txt{attr(0)}") 307 | if not os.path.isdir("output") and not os.path.exists("output"): 308 | print(f"{attr(1)}{fg(129)}[?]{attr(0)} Folder 'output' doesn't exist !") 309 | print(f"{attr(1)}{fg(4)}[*]{attr(0)} Making folder 'output' !") 310 | 311 | try: 312 | os.mkdir("output") 313 | except FileExistsError: 314 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Directory {fg(13)}output{attr(0)} exists !") 315 | 316 | with open(f"output/{string}.pastebin.txt", "w") as pastebin_entry: 317 | pastebin_entry.write(search.text) 318 | pastebin_entry.close() 319 | 320 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Showing the contents of {fg(12)}{string}{attr(0)} PasteBin entry !") 321 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Content:") 322 | print(50 * "-") 323 | print(search.text) 324 | sys.exit(0) 325 | 326 | elif search.status_code == 404: 327 | print(f"{attr(1)}{fg(3)}[!]{attr(0)} Response {fg(1)}404{attr(0)} for - {fg(1)}{string}{attr(0)}") 328 | sys.exit(1) 329 | 330 | else: 331 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Response is different that 404 or 200 for - {fg(13)}{string}{attr(0)}") 332 | sys.exit(1) 333 | 334 | else: 335 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Something is not right ! Try again !") 336 | sys.exit(1) 337 | 338 | ''' 339 | The class can check the contents of the PasteBins 340 | - CheckAllBin.contents_of_pastes(id) // Where id == ID of PasteBin 341 | 342 | The class can check for sensitive data such as emails, usernames & IP addresses 343 | - CheckAllBin.search_sensitive_data() 344 | ''' 345 | class CheckAllBin: 346 | 347 | def __init__(self, threads): 348 | self.threads = threads 349 | 350 | def contents_of_pastes(id, threads): 351 | 352 | ARCHIVE_URL = "https://pastebin.com/archive" 353 | RAW_URL = "https://pastebin.com/raw/" 354 | 355 | HREF_REGEX = r"(.*?)<\/a>" 356 | get_valid_id = r'\(\'([A-Za-z\d+]{8})\'' 357 | user_agent = { 358 | "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15" 359 | } 360 | 361 | URL_ARCHIVE = requests.get(ARCHIVE_URL, 362 | # verify=False, 363 | headers=user_agent) 364 | 365 | soup = BeautifulSoup(URL_ARCHIVE.content, 'html.parser') 366 | pastes = soup.find_all('a') 367 | 368 | # Prints the necessary values using the regex above 369 | pastes_findall = re.findall(HREF_REGEX, str(pastes)) 370 | pastes_id = re.findall(get_valid_id, str(pastes_findall)) 371 | 372 | if not os.path.isdir("output") and not os.path.exists("output"): 373 | print(f"{attr(1)}{fg(129)}[?]{attr(0)} Folder {fg(13)}output{attr(0)} doesn't exist !") 374 | print(f"{attr(1)}{fg(4)}[*]{attr(0)} Making folder {fg(13)}output{attr(0)} !") 375 | 376 | try: 377 | os.mkdir("output") 378 | except FileExistsError: 379 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Directory {fg(13)}output{attr(0)} exists !") 380 | 381 | # Directory 'pastebins' will be created 382 | if os.path.exists('output/pastebins') and os.path.isdir('output/pastebins'): 383 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Directory {fg(13)}pastebins{attr(0)} exists !") 384 | 385 | else: 386 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Directory {fg(13)}pastebins{attr(0)} doesn't exist, making it !") 387 | try: 388 | os.mkdir('output/pastebins') 389 | except NotADirectoryError or FileExistsError: 390 | raise Exception(f"{attr(1)}{fg(3)}[-]{attr(0)} Directory creation of {fg(13)}pastebins{attr(0)} failed !") 391 | 392 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Using {threads} threads !") 393 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Grabbing most recent PasteBin archive !\r\n") 394 | try: 395 | # A for loop to check the contents of each ID. 396 | for id in pastes_id: 397 | URL_RAW = requests.get(f"{RAW_URL}{id}", 398 | # verify=False, 399 | headers=user_agent) 400 | 401 | try: 402 | with open(f"output/pastebins/Pastebin-{id}.txt", "w") as pastebin: 403 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Saving the contents of {fg(12)}{id}{attr(0)} to {fg(3)}output/pastebins/Pastebin-{id}.txt{attr(0)}") 404 | try: 405 | Threading.threadit(pastebin.write(URL_RAW.text), threads) 406 | Threading.threadit(pastebin.close(), threads) 407 | except Exception as e: 408 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Threading exception hit: [{fg(189)}{e}{attr(0)}]") 409 | except OSError: 410 | pastebin.close() 411 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Cannot read/open ./output/pastebins/Pastebin-{fg(134)}{id}{attr(0)} !") 412 | 413 | except KeyboardInterrupt: 414 | raise Exception(f"{attr(1)}{fg(203)}[x]{attr(0)} Killing the script...\r\n") 415 | 416 | def search_sensitive_data(f): 417 | 418 | # Some regex variables 419 | USERNAME_REGEX = r"^[a-z0-9_-]{3,15}$" 420 | EMAIL_REGEX = r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)" 421 | IP_REGEX = r"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}" 422 | 423 | if not f: 424 | for file in os.listdir("./output/pastebins/"): 425 | # For each file check if it's a directory instead of file 426 | # If yes, exit 427 | try: 428 | if os.path.isdir(f"./output/pastebins/{file}"): 429 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} {fg(134)}{attr(1)}{file}{attr(0)} is a directory not a file !") 430 | sys.exit(0) 431 | except Exception as e: 432 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Something went wrong [{fg(187)}{e}{attr(0)}]") 433 | 434 | try: 435 | # Read each file and search for emails, usernames, IP addresses 436 | with open(f"./output/pastebins/{file}", "r") as pastebin: 437 | 438 | # For each of the read files, look for the matching regex 439 | for line in pastebin.readlines(): 440 | 441 | email_search = re.search(EMAIL_REGEX, str(line)) 442 | if email_search: 443 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Found emails in {fg(3)}output/pastebins/{file}{attr(0)}") 444 | print(f"{email_search.group(0)}\r\n") 445 | 446 | ip_search = re.search(IP_REGEX, str(line)) 447 | if ip_search: 448 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Found IP addresses in {fg(3)}output/pastebins/{file}{attr(0)}") 449 | print(f"{ip_search.group(0)}\r\n") 450 | 451 | username_search = re.search(USERNAME_REGEX, str(line)) 452 | if username_search: 453 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Found username in {fg(3)}output/pastebins/{file}{attr(0)}") 454 | print(f"{username_search.group(0)}\r\n") 455 | 456 | pastebin.close() 457 | except OSError: 458 | pastebin.close() 459 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Cannot read/open ./output/pastebins/{fg(134)}{file}{attr(0)} !") 460 | 461 | # Choose a file in ./output/ and check for sensitive info 462 | # using regex above 463 | else: 464 | try: 465 | if os.path.isdir(f"./output/{f}"): 466 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} {fg(134)}{attr(1)}{f}{attr(0)} is a directory not a file !") 467 | sys.exit(0) 468 | except Exception as e: 469 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Something went wrong [{fg(187)}{e}{attr(0)}]") 470 | 471 | try: 472 | with open(f"./output/{f}", "r") as file_to_read: 473 | 474 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Searching for sensitive info in {fg(3)}output/{f}{attr(0)}") 475 | file = file_to_read.readlines() 476 | 477 | for line in file: 478 | email_search = re.search(EMAIL_REGEX, str(line)) 479 | if email_search: 480 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Found emails in {fg(3)}output/{f}{attr(0)}") 481 | print(f"{email_search.group(0)}\r\n") 482 | 483 | ip_search = re.search(IP_REGEX, str(line)) 484 | if ip_search: 485 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Found IP addresses in {fg(3)}output/{f}{attr(0)}") 486 | print(f"{ip_search.group(0)}\r\n") 487 | 488 | username_search = re.search(USERNAME_REGEX, str(line)) 489 | if username_search: 490 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Found username in {fg(3)}output/{f}{attr(0)}") 491 | print(f"{username_search.group(0)}\r\n") 492 | 493 | file_to_read.close() 494 | except OSError: 495 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Cannot read/open ./output/{fg(134)}{f}{attr(0)} !") 496 | 497 | 498 | ''' 499 | The class is capable of going through all PasteBins of 500 | a user and grabbing all PasteBins posted by that person 501 | - search_person() 502 | ''' 503 | # Users to use for debugging: 504 | # - 7d2dlauncher (short list) 505 | # - desislava_topuzakova (long list) 506 | class Pastebiner: 507 | 508 | def pastebiner(u, p, threads): 509 | 510 | RAW_URL = "https://pastebin.com/raw/" 511 | USER_URL = "https://pastebin.com/u/" 512 | 513 | HREF_REGEX = r"(.*?)<\/a>" 514 | get_valid_id = r"\(\'([A-Za-z\d+]{8})\'" 515 | 516 | r = requests.Session() 517 | user_agent = { 518 | "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15" 519 | } 520 | 521 | request_user = r.get( 522 | USER_URL+u, 523 | headers=user_agent, 524 | # verify=False 525 | ) 526 | 527 | # Is the user parameter empty ? 528 | if not u: 529 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} User cannot be empty !") 530 | 531 | # Directory 'users' will be created if not existing 532 | if os.path.exists(f'output/users') and os.path.isdir(f'output/users'): 533 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Directory {fg(13)}users{attr(0)} exists !") 534 | 535 | else: 536 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Directory {fg(13)}users{attr(0)} doesn't exist, making it !") 537 | try: 538 | os.mkdir('output/users') 539 | except NotADirectoryError or FileExistsError: 540 | raise Exception(f"{attr(1)}{fg(3)}[-]{attr(0)} Directory creation of {fg(13)}users{attr(0)} failed or already exists !") 541 | 542 | # Check if user exists in PasteBin 543 | if request_user.status_code == 404: 544 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} User {fg(134)}{attr(1)}{u}{attr(0)} doesn't exist") 545 | sys.exit(0) 546 | 547 | # When user is present make a dir with their name 548 | if request_user.status_code == 200: 549 | if os.path.exists(f'output/users/{u}') and os.path.isdir(f'output/users/{u}'): 550 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Directory of user {fg(13)}{u}{attr(0)} exists !") 551 | 552 | else: 553 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Directory of user {fg(134)}{u}{attr(0)} doesn't exist, making it !") 554 | try: 555 | os.mkdir(f'output/users/{u}') 556 | except NotADirectoryError or FileExistsError: 557 | raise Exception(f"{attr(1)}{fg(3)}[-]{attr(0)} Directory creation of user {fg(134)}{u}{attr(0)} failed or already exists !") 558 | 559 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Requesting page {fg(44)}{attr(1)}{p}{attr(0)}") 560 | try: 561 | get_page = r.get( 562 | f"{USER_URL}{u}/{p}", 563 | headers=user_agent, 564 | # verify=False 565 | ) 566 | 567 | soup = BeautifulSoup(get_page.content, 'html.parser') 568 | pastes = soup.find_all('a') 569 | 570 | # Prints the necessary values using the regex above 571 | pastes_findall = re.findall(HREF_REGEX, str(pastes)) 572 | pastes_id = re.findall(get_valid_id, str(pastes_findall)) 573 | 574 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Using {threads} threads !\r\n") 575 | for id in pastes_id: 576 | URL_RAW = requests.get(f"{RAW_URL}{id}", 577 | # verify=False, 578 | headers=user_agent) 579 | try: 580 | with open(f"output/users/{u}/Pastebin-{id}.txt", "w") as pastebin: 581 | print(f"{attr(1)}{fg(2)}[+]{attr(0)} Saving the contents of {fg(12)}{id}{attr(0)} to {fg(3)}output/users/{fg(134)}{u}{attr(0)}{fg(3)}/Pastebin-{id}.txt{attr(0)}") 582 | try: 583 | Threading.threadit(pastebin.write(URL_RAW.text), threads) 584 | Threading.threadit(pastebin.close(), threads) 585 | except Exception as e: 586 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Threading exception hit: [{fg(189)}{e}{attr(0)}]") 587 | sys.exit(0) 588 | except OSError: 589 | raise Exception(f"{attr(1)}{fg(1)}[-]{attr(0)} Cannot read/open ./output/users/{fg(134)}{u}{attr(0)}") 590 | 591 | except Exception as e: 592 | print(f"{attr(1)}{fg(1)}[-]{attr(0)} Exception hit: [{fg(189)}{e}{attr(0)}]") 593 | 594 | #Initilize parser for arguments 595 | def argparser(): 596 | 597 | parser = argparse.ArgumentParser(description='Pasta - A PasteBin Scraper') 598 | parser.add_argument("-s", 599 | "--search", 600 | help="Search PasteBin with a set of strings", 601 | action="store_true", 602 | required=False 603 | ) 604 | 605 | parser.add_argument("-r", 606 | "--range_str", 607 | help="How many strings to generate", 608 | type=int, 609 | required=False 610 | # default=5 611 | ) 612 | 613 | parser.add_argument("-c", 614 | "--check", 615 | help="Check contents of a specific PasteBin entry", 616 | type=str, 617 | required=False 618 | ) 619 | 620 | parser.add_argument("-g", 621 | "--get_archive", 622 | help="Get most recent PasteBin archive", 623 | required=False, 624 | #action='store_true' 625 | nargs="?" 626 | ) 627 | 628 | parser.add_argument("-d", 629 | "--scrape", 630 | help="Scrape the most recent archive and save each Pastebin", 631 | required=False, 632 | action='store_true' 633 | ) 634 | 635 | parser.add_argument("-e", 636 | "--sensitive", 637 | help="Search for sensitive info from downloaded Pastebins", 638 | required=False, 639 | action='store_true' 640 | ) 641 | 642 | parser.add_argument("-u", 643 | "--userbin", 644 | help="Retrieve the PasteBin posts of a user", 645 | required=False, 646 | type=str 647 | ) 648 | 649 | parser.add_argument("-p", 650 | "--page", 651 | help="Page number of user's PasteBins", 652 | required=False, 653 | type=str 654 | ) 655 | 656 | parser.add_argument("-f", 657 | "--file", 658 | help="Search PasteBin with a set of strings", 659 | required=False, 660 | type=str 661 | ) 662 | 663 | parser.add_argument("-t", 664 | "--threads", 665 | help="How many threads to use", 666 | required=False, 667 | type=int 668 | ) 669 | 670 | #Show help menu if no arguments provided 671 | args = parser.parse_args(args=None if sys.argv[1:] else ['-h']) 672 | 673 | if args.search: 674 | 675 | if args.threads: 676 | threads = args.threads 677 | else: 678 | threads = 5 679 | 680 | if args.range_str: 681 | str_range = args.range_str 682 | else: 683 | str_range = 0 684 | 685 | Search.search_request(threads, str_range) 686 | 687 | if args.range_str and not args.search: 688 | str_range = args.range_str 689 | Search.randomize_alpha(8, str_range) 690 | 691 | if args.check: 692 | string = args.check 693 | CheckBin.view_pastebin(string) 694 | 695 | if args.get_archive is not None: 696 | archive = args.get_archive 697 | CheckBin.get_recent_archive(archive) 698 | else: 699 | CheckBin.get_recent_archive(None) 700 | 701 | if args.scrape: 702 | if args.threads: 703 | threads = args.threads 704 | else: 705 | threads = 5 706 | 707 | CheckAllBin.contents_of_pastes(id, threads) 708 | 709 | # These go together ############################ 710 | if args.sensitive and not args.file: 711 | f = None 712 | CheckAllBin.search_sensitive_data(f) 713 | elif args.sensitive and args.file: 714 | CheckAllBin.search_sensitive_data(args.file) 715 | ################################################ 716 | 717 | # These go together #################### 718 | if args.userbin and not args.page: 719 | u = args.userbin 720 | p = 0 721 | 722 | if args.threads: 723 | threads = args.threads 724 | else: 725 | threads = 5 726 | Pastebiner.pastebiner(u, p, threads) 727 | 728 | if args.userbin and args.page: 729 | u = args.userbin 730 | p = args.page 731 | 732 | if args.threads: 733 | threads = args.threads 734 | else: 735 | threads = 5 736 | Pastebiner.pastebiner(u, p, threads) 737 | ######################################## 738 | 739 | # Checks for parameters used alone which shouldn't be 740 | # -p parameter (user page) 741 | if args.page: 742 | print(f"{attr(1)}{fg(4)}[*]{attr(0)} Parameter {fg(155)}-p{attr(0)} cannot be used alone !") 743 | print("Usage in combination with: \r\n") 744 | print("-u/--userbin USER - Retrieve the PasteBin posts of a user") 745 | # print("-t/--threads THREADS - How many threads to use") 746 | sys.exit(0) 747 | 748 | # -t threads 749 | if args.threads: 750 | print(f"{attr(1)}{fg(4)}[*]{attr(0)} Parameter {fg(155)}-t{attr(0)} cannot be used alone !") 751 | print("Usage in combination with: \r\n") 752 | print("-u/--userbin USER - Retrieve the PasteBin posts of a user") 753 | # print("-t/--threads THREADS - How many threads to use") 754 | print("-d/--scrape - Scrape the most recent archive and save each Pastebin") 755 | print("-s/--search - Search PasteBin with a set of strings") 756 | sys.exit(0) 757 | 758 | if __name__ == "__main__": 759 | ascii() 760 | argparser() 761 | --------------------------------------------------------------------------------