├── 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/HEAD/examples/check.png
--------------------------------------------------------------------------------
/examples/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kr0ff/Pasta/HEAD/examples/file.png
--------------------------------------------------------------------------------
/examples/scrape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kr0ff/Pasta/HEAD/examples/scrape.png
--------------------------------------------------------------------------------
/examples/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kr0ff/Pasta/HEAD/examples/search.png
--------------------------------------------------------------------------------
/examples/search1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kr0ff/Pasta/HEAD/examples/search1.png
--------------------------------------------------------------------------------
/examples/getarchive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kr0ff/Pasta/HEAD/examples/getarchive.png
--------------------------------------------------------------------------------
/examples/sensitive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kr0ff/Pasta/HEAD/examples/sensitive.png
--------------------------------------------------------------------------------
/examples/strrange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kr0ff/Pasta/HEAD/examples/strrange.png
--------------------------------------------------------------------------------
/examples/userpage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kr0ff/Pasta/HEAD/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 | [](https://opensource.org/licenses/MIT)
7 | [](https://github.com/Kr0ff/PenDock/issues)
8 | 
9 | [](https://twitter.com/CptXrat)
10 | [](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 |
17 |
18 | * Ability to use the randomly generated strings and bruteforce PasteBin for possible hidden valid pastebins
19 |
20 |
21 |
22 | * Ability to view the contents of PasteBin entry
23 |
24 |
25 |
26 | * Ability to scrape the most recent archive of PasteBin
27 |
28 |
29 |
30 | * Ability to look for sensitive information in downloaded pastebins [emails, usernames, IP addresses]
31 |
32 |
33 |
34 | * Ability to retrieve all pastebins of user's account from all available pages
35 |
36 |
37 |
38 | * Ability to select which file to search for sensitive information
39 |
40 |
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 |
--------------------------------------------------------------------------------