Skip to content
Create a gist now

Instantly share code, notes, and snippets.

anonymous /dump.py secret
Created

# -*- coding: utf-8 -*-
from string import ascii_letters, digits
from warnings import filterwarnings
from random import randint, choice
from pprint import pprint
from time import sleep
import webbrowser
import argparse
import requests
import json
import sys
import os
import re
py3 = sys.version_info[0] > 2
filterwarnings('ignore')
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in range(0, len(l), n):
yield l[i:i+n]
# https://stackoverflow.com/questions/312443/how-do-you-split-a-list-into-evenly-sized-chunks-in-python/312464#312464
def natural_sort(l):
convert = lambda text: int(text) if text.isdigit() else text.lower()
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
return sorted(l, key=alphanum_key)
# https://stackoverflow.com/questions/4836710/does-python-have-a-built-in-function-for-string-natural-sort/4836734#4836734
def has_numbers(input_string):
return any(char.isdigit() for char in input_string)
# https://stackoverflow.com/questions/19859282/check-if-a-string-contains-a-number/19859308#19859308
def is_installed(module):
try:
__import__(module)
except ImportError:
return False
return True
def fetch_captcha():
r = requests.get('https://8ch.net/8chan-captcha/entrypoint.php?mode=get&extra=abcdefghijklmnopqrstuvwxyz&nojs=true')
try:
match = 'CAPTCHA ID: [a-z]*'
captcha_cookie = re.search(match, r.text).group().split(': ')[1]
match = '<image src="data:image/png;base64,[A-Za-z0-9+/=]*">'
with open('captcha_image.png', 'wb') as f:
f.write(re.search(match, r.text).group().split(',')[1].strip('>').strip('"').decode('base64'))
webbrowser.open('captcha_image.png')
if py3:
captcha_text = input('Enter the captcha: ')
else:
captcha_text = raw_input('Enter the captcha: ')
os.remove('captcha_image.png')
data['captcha_cookie'] = captcha_cookie
data['captcha_text'] = captcha_text
except AttributeError:
print('Server error while fetching captcha')
pass
parser = argparse.ArgumentParser(description='Dump a folder to a thread')
parser.add_argument('-f', '--folder', help='Folder to upload images from', type=str, required=True)
parser.add_argument('-u', '--url', help='URL of thread', required=True)
parser.add_argument('-d', '--delay', help='Delay between posting', type=int, required=True)
parser.add_argument('-i', '--images', help='Number of images to post', type=int)
parser.add_argument('-n', '--name', help='Name to post with', type=str, default='')
parser.add_argument('-e', '--email', help='Email to post with', type=str, default='')
parser.add_argument('-p', '--progress', help='Post with dump progress? (default y)', choices=('y', 'n'), default='y')
parser.add_argument('-r', '--random', help='Post with random filenames? (default n)', choices=('y', 'n'), default='n')
parser.add_argument('-l', '--length', help='To be used with -r/--random. Maximum length of random filename (optional, default 15)', type=int, default=15)
args = vars(parser.parse_args())
# https://stackoverflow.com/questions/9234258/in-python-argparse-is-it-possible-to-have-paired-no-something-something-arg
def make_random_filename():
splitfilename = l[file].split('.')
extension = splitfilename[len(splitfilename) - 1]
return ''.join(choice(ascii_letters + digits) for _ in range(randint(1, args['length']))) + '.' + extension
delay = args['delay']
DIRECTORY = args['folder']
filelist = []
for file in os.listdir(DIRECTORY):
if os.path.splitext(file)[1].lower() in ('.jpg', '.jpeg', '.png', '.gif', '.webm', '.mp4'):
filelist.append(os.path.join(DIRECTORY, file))
# I stole this from stackoverflow somewhere, I can't find the link
if len(args['url'].split('/')) == 6:
spliturl = args['url'].split('/')
if has_numbers(spliturl[5]) and '.html' in args['url']:
url = '{}//{}'.format(spliturl[0], spliturl[2])
board = spliturl[3]
thread = spliturl[5].split('.')[0]
else:
sys.exit('\nBad URL. --u/--url should be the URL of a thread.\nExample: https://8ch.net/b/res/1.html')
else:
sys.exit('\nBad URL. --u/--url should be the URL of a thread.\nExample: https://8ch.net/b/res/1.html')
boardindex = requests.get('{}/{}/index.html'.format(url, board))
if args['images'] == None:
if is_installed('bs4') == True:
from bs4 import BeautifulSoup
soup = BeautifulSoup(boardindex.text)
script_tag = str(soup.find_all('script')[1])
print('-i/--images not specified. Defaulting to the maximum number of allowed images on this board.')
maxfiles = int(re.search('var max_images=[1-5]', script_tag).group(0).split('=')[1])
elif is_installed('bs4') == False:
sys.exit('Unable to automatically detect the maximum number of images per post, please specify -i/--images')
else:
if args['images'] >= 1 and args['images'] <= 5:
maxfiles = args['images']
else:
sys.exit('-i/--images must be between 1 and 5')
filelist = natural_sort(filelist)
total = len(filelist)
chunked_list = list(chunks(filelist, maxfiles))
r = requests.get('{}/settings.php?board={}'.format(url, board))
try:
j = json.loads(r.text)
if j['max_newlines'] != 0:
max_newlines = j['max_newlines']
else:
max_newlines = 100
except ValueError:
sys.exit('Server error while getting board settings')
data = {
'board': board,
'thread': thread,
'name': args['name'],
'email': args['email'],
'subject': '',
'body': '',
'embed': '',
'dx': '',
'dy': '',
'dz': '',
'password': 'ayylmao',
'json_response': '1',
'post': 'New Reply',
}
headers = {
'referer': '',
'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0',
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'accept-language': 'en-US,en;q=0.5',
'cache-control': 'max-age=0',
}
headers['referer'] = '{}/{}/'.format(url, board)
def fetch_dnsbl_captcha():
r = requests.get('https://8ch.net/dnsbls_bypass.php').text
try:
match = "value='[a-z]*"
captcha_cookie = re.search(match, r).group().split("'")[1]
match = '<image src="data:image/png;base64,[A-Za-z0-9+/=]*">'
with open('dnsbl_captcha_image.png', 'wb') as f:
f.write(re.search(match, r).group().split('"')[1].split(',')[1].decode('base64'))
webbrowser.open('dnsbl_captcha_image.png')
if py3:
captcha_text = input('Enter the captcha: ')
else:
captcha_text = raw_input('Enter the captcha: ')
os.remove('dnsbl_captcha_image.png')
dnsbl_data = {}
dnsbl_data['captcha_cookie'] = captcha_cookie
dnsbl_data['captcha_text'] = captcha_text
r = requests.post('{}/dnsbls_bypass.php'.format(url), data=dnsbl_data, headers=headers)
except AttributeError:
print('Server error while fetching captcha')
pass
progress = maxfiles
for chunk in range(len(chunked_list)):
number_of_files = len(chunked_list[chunk])
status = ''
while 'redirect' not in status:
for x in range(len(chunked_list[chunk])):
l = natural_sort(chunked_list[chunk])
files = []
if args['random'] == 'y':
for file in range(len(l)):
if file == 0:
files.append(['file', (make_random_filename(), open(l[file], 'rb'))])
else:
files.append(['file' + str(file), (make_random_filename(), open(l[file], 'rb'))])
else:
for file in range(len(l)):
if file == 0:
files.append(['file', open(l[file], 'rb')])
else:
files.append(['file' + str(file), open(l[file], 'rb')])
files = tuple(files)
newlines = '\n' * randint(1, max_newlines)
if progress > total:
progress = total
if args['progress'] == 'y':
data['body'] = '{}/{}{}'.format(progress, total, newlines)
else:
data['body'] = newlines
if j['captcha']['enabled'] == True:
fetch_captcha()
r = requests.post('{}/post.php'.format(url), data=data, headers=headers, files=files)
status_code = r.status_code
status = r.text
if status_code == 200:
print(status)
else:
print('{} server error'.format(status_code))
if 'dnsbls_bypass.php' in status:
fetch_dnsbl_captcha()
if 'Failed to resize image' and 'corrupt image' in status or 'XSS' in status:
print('ONE OF THE FOLLOWING IMAGES ARE CORRUPT, AND AS A RESULT, THE FOLLOWING FILES WERE NOT UPLOADED:')
pprint(l)
status = 'redirect'
if 'already exists' in status:
status = 'redirect'
if 'Maximum file size' in status:
print('THE FOLLOWING FILE(S) WERE OVER THE FILE SIZE LIMIT AND WERE NOT POSTED:')
pprint(l)
print('Consider setting -i/--images to a lower number so your files fit under the limit')
status = 'redirect'
del files
print('{}/{} - Waiting {} seconds...').format(progress, total, delay)
sleep(delay)
progress += number_of_files
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.