mirror of
https://github.com/keklick1337/StealthHTML.git
synced 2026-01-09 02:50:30 -06:00
first commit
This commit is contained in:
7
LICENSE
Normal file
7
LICENSE
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright 2025 Vladislav Tislenko
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
110
README.md
Normal file
110
README.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# StealthHTML
|
||||
|
||||
Hey, welcome to **StealthHTML**! This little tool is all about scrambling your HTML code to make it a bit more... sneaky. Want to keep your code under wraps or just throw off anyone trying to peek under the hood? StealthHTML’s here to help you turn your HTML into a cryptic masterpiece, all while keeping it looking normal on the surface.
|
||||
|
||||
## What’s This All About?
|
||||
|
||||
HTML obfuscation is like putting your code through a blender—it still works and looks the same, but good luck to anyone trying to figure it out. Whether you’re hiding something clever or just having a laugh, StealthHTML throws in tricks like invisible characters, random junk, and shuffled styles to keep things interesting.
|
||||
|
||||
## Cool Stuff It Does
|
||||
|
||||
StealthHTML’s got a bunch of neat features to play with:
|
||||
|
||||
- **Random Text**: Generates innocent-looking filler text from safe word lists.
|
||||
- **Invisible Characters**: Slips in zero-width characters to spice things up without changing the look.
|
||||
- **CSS Shuffle**: Jumbles your CSS properties so it’s a total guessing game.
|
||||
- **Extra Bits**: Adds random classes, IDs, and hidden elements to throw people off.
|
||||
- **Link & Image Twists**: Tosses in random link parameters and sneaky invisible images.
|
||||
- **Word Lists**: Pick from `general`, `technical`, or `marketing` dictionaries to match your style.
|
||||
- **Your Rules**: Tweak how wild you want the obfuscation to get.
|
||||
|
||||
## How to Get It Running
|
||||
|
||||
Setting up is super simple:
|
||||
|
||||
1. **Grab the Code**:
|
||||
```bash
|
||||
git clone https://github.com/keklick1337/StealthHTML.git
|
||||
```
|
||||
|
||||
2. **Jump In**:
|
||||
```bash
|
||||
cd StealthHTML
|
||||
```
|
||||
|
||||
3. **Load It Up**:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## How to Use It
|
||||
|
||||
Once you’re good to go, it’s a piece of cake:
|
||||
|
||||
- **Make a Sneaky File**:
|
||||
```bash
|
||||
python stealthhtml.py input.html -o output.html
|
||||
```
|
||||
This spits out a scrambled `output.html` from your `input.html`.
|
||||
|
||||
- **Quick Peek**:
|
||||
```bash
|
||||
python stealthhtml.py input.html
|
||||
```
|
||||
See the magic right in your terminal.
|
||||
|
||||
### Tweak It Your Way
|
||||
|
||||
You’ve got options to mess with the obfuscation:
|
||||
|
||||
- `--min_words`: Shortest random text length. (Default: 2 words)
|
||||
- `--max_words`: Longest random text length. (Default: 5 words)
|
||||
- `--invisible_char_prob`: Chance of sneaking in invisible characters. (Default: 15%)
|
||||
- `--span_prob`: Odds of tossing in a hidden `<span>`. (Default: 40%)
|
||||
- `--comment_count`: How many random comments to add. (Default: 1)
|
||||
- `--meta_count`: Number of extra meta tags. (Default: 1)
|
||||
- `--table_count`: How many hidden tables to sneak in. (Default: 1)
|
||||
- `--style_count`: Number of random style tags. (Default: 1)
|
||||
- `--image_count`: How many invisible images to drop. (Default: 1)
|
||||
- `--script_count`: Number of random script tags. (Default: 1)
|
||||
- `--rare_tag_count`: How many weird tags (like `<article>`) to throw in. (Default: 1)
|
||||
- `--header_count`: Number of hidden headers (like `<h1>`) to add. (Default: 1)
|
||||
- `--dictionary`: Word list to use: `general`, `technical`, or `marketing`. (Default: `general`)
|
||||
|
||||
## Some Fun Examples
|
||||
|
||||
Here’s how you might play around with it:
|
||||
|
||||
1. **Basic Scramble**:
|
||||
```bash
|
||||
python stealthhtml.py template.html -o obfuscated.html
|
||||
```
|
||||
Turns `template.html` into a sneaky `obfuscated.html`.
|
||||
|
||||
2. **Custom Chaos**:
|
||||
```bash
|
||||
python stealthhtml.py template.html -o obfuscated.html --comment_count 3 --dictionary technical --invisible_char_prob 0.2
|
||||
```
|
||||
Adds 3 comments, uses techy words, and ups the invisible character chance to 20%.
|
||||
|
||||
3. **Terminal Teaser**:
|
||||
```bash
|
||||
python stealthhtml.py template.html
|
||||
```
|
||||
Shows off the scrambled HTML in your console.
|
||||
|
||||
## Wanna Chip In?
|
||||
|
||||
Love to have you onboard! Here’s how to contribute:
|
||||
|
||||
1. Fork the repo.
|
||||
2. Start a new branch (`git checkout -b cool-idea`).
|
||||
3. Make your tweaks and commit (`git commit -m 'Added something awesome'`).
|
||||
4. Push it up (`git push origin cool-idea`).
|
||||
5. Open a pull request.
|
||||
|
||||
Just keep it clean and maybe toss in some tests if you can.
|
||||
|
||||
## License
|
||||
|
||||
This is under the [MIT License](LICENSE). Use it, tweak it, share it—just give a nod back to us.
|
||||
286
generate_emails.py
Executable file
286
generate_emails.py
Executable file
@@ -0,0 +1,286 @@
|
||||
#!/usr/bin/env python3
|
||||
# HTML Obfuscator by Vladislav Tislenko aka keklick1337
|
||||
|
||||
import copy
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
import argparse
|
||||
from bs4 import BeautifulSoup, Comment
|
||||
|
||||
# Dictionaries of safe words
|
||||
DICTIONARIES = {
|
||||
'general': [
|
||||
'news', 'update', 'info', 'alert', 'notice', 'message', 'reminder', 'notification',
|
||||
'report', 'summary', 'announcement', 'bulletin', 'memo', 'brief', 'digest', 'release',
|
||||
'statement', 'communication', 'dispatch', 'correspondence', 'letter', 'note', 'post',
|
||||
'article', 'piece', 'item', 'story', 'feature', 'column', 'editorial'
|
||||
],
|
||||
'technical': [
|
||||
'code', 'system', 'data', 'network', 'server', 'software', 'hardware', 'update',
|
||||
'patch', 'bug', 'feature', 'release', 'version', 'protocol', 'interface', 'module',
|
||||
'function', 'algorithm', 'process', 'thread', 'query', 'database', 'backup', 'log',
|
||||
'monitor', 'config', 'deploy', 'test', 'build', 'compile'
|
||||
],
|
||||
'marketing': [
|
||||
'offer', 'deal', 'sale', 'discount', 'promo', 'gift', 'bonus', 'special', 'event',
|
||||
'campaign', 'launch', 'product', 'service', 'brand', 'exclusive', 'limited', 'free',
|
||||
'trial', 'benefit', 'value', 'opportunity', 'package', 'subscription', 'plan',
|
||||
'feature', 'highlight', 'trend', 'news', 'update', 'announce'
|
||||
]
|
||||
}
|
||||
|
||||
# Safe fonts
|
||||
SAFE_FONTS = [
|
||||
'Arial', 'Helvetica', 'Times New Roman', 'Courier New', 'Verdana', 'Georgia',
|
||||
'Trebuchet MS', 'Comic Sans MS', 'Impact', 'Lucida Sans'
|
||||
]
|
||||
|
||||
# Function to generate random text
|
||||
def generate_random_text(min_words=2, max_words=5, dictionary='general'):
|
||||
count = random.randint(min_words, max_words)
|
||||
return ' '.join(random.choice(DICTIONARIES[dictionary]) for _ in range(count))
|
||||
|
||||
# Function to generate a random class or ID name
|
||||
def generate_random_class():
|
||||
return ''.join(random.choices(string.ascii_lowercase, k=random.randint(5, 10)))
|
||||
|
||||
# Function to generate a random color
|
||||
def generate_random_color():
|
||||
return random.choice([
|
||||
f"#{random.randint(0, 255):02x}{random.randint(0, 255):02x}{random.randint(0, 255):02x}",
|
||||
f"rgb({random.randint(0, 255)}, {random.randint(0, 255)}, {random.randint(0, 255)})"
|
||||
])
|
||||
|
||||
# Function to shuffle CSS properties
|
||||
def shuffle_styles(style_string):
|
||||
styles = [s.strip() for s in style_string.split(';') if s.strip()]
|
||||
random.shuffle(styles)
|
||||
return '; '.join(styles) + ';'
|
||||
|
||||
# Function to create a random hidden element
|
||||
def insert_random_hidden_element(soup, dictionary='general'):
|
||||
hidden_span = soup.new_tag('span', style='font-size:0px; display:inline;')
|
||||
hidden_span.string = generate_random_text(1, 3, dictionary)
|
||||
hidden_span['class'] = generate_random_class()
|
||||
hidden_span['id'] = generate_random_class()
|
||||
hidden_span[f'data-{generate_random_class()}'] = str(random.randint(0, 1000))
|
||||
return hidden_span
|
||||
|
||||
# Function to insert invisible characters
|
||||
def insert_invisible_chars(text, invisible_char_prob=0.15):
|
||||
invisible_chars = ['\u200B', '\u200C', '\u200D', '\uFEFF', '\u2060']
|
||||
result = ''
|
||||
for char in text:
|
||||
result += char
|
||||
if random.random() < invisible_char_prob:
|
||||
result += random.choice(invisible_chars)
|
||||
return result
|
||||
|
||||
# Function to add random attributes
|
||||
def add_random_attributes(tag):
|
||||
if random.random() < 0.6:
|
||||
tag['class'] = ' '.join([generate_random_class() for _ in range(random.randint(1, 3))])
|
||||
if random.random() < 0.4:
|
||||
tag['data-' + generate_random_class()] = str(random.randint(0, 1000))
|
||||
if random.random() < 0.2:
|
||||
tag['id'] = generate_random_class()
|
||||
|
||||
# Function to insert random comments
|
||||
def insert_random_comments(soup, count=1, dictionary='general'):
|
||||
for _ in range(count):
|
||||
comment = Comment(generate_random_text(3, 7, dictionary))
|
||||
soup.body.insert(random.randint(0, len(soup.body.contents)), comment)
|
||||
|
||||
# Function to add random meta tags
|
||||
def add_random_meta(soup, count=1, dictionary='general'):
|
||||
for _ in range(count):
|
||||
meta = soup.new_tag('meta')
|
||||
meta['name'] = generate_random_class()
|
||||
meta['content'] = generate_random_text(1, 3, dictionary)
|
||||
soup.head.append(meta)
|
||||
|
||||
# Function to add random parameters to links
|
||||
def add_random_link_params(soup):
|
||||
for a in soup.find_all('a', href=True):
|
||||
if '?' not in a['href']:
|
||||
a['href'] += '?' + '&'.join(f"{generate_random_class()}={random.randint(0, 999)}" for _ in range(random.randint(1, 3)))
|
||||
|
||||
# Function to insert random tables
|
||||
def insert_random_tables(soup, count=1, dictionary='general'):
|
||||
for _ in range(count):
|
||||
table = soup.new_tag('table', style=f'display:none;color:{generate_random_color()};font-family:{random.choice(SAFE_FONTS)};')
|
||||
for _ in range(random.randint(1, 3)):
|
||||
tr = soup.new_tag('tr')
|
||||
for _ in range(random.randint(1, 3)):
|
||||
td = soup.new_tag('td')
|
||||
td.string = generate_random_text(1, 2, dictionary)
|
||||
tr.append(td)
|
||||
table.append(tr)
|
||||
soup.body.append(table)
|
||||
|
||||
# Function to add random styles
|
||||
def add_random_styles(soup, count=1):
|
||||
for _ in range(count):
|
||||
style_tag = soup.new_tag('style')
|
||||
style_tag.string = f".{generate_random_class()} {{ {shuffle_styles(f'color:{generate_random_color()};display:none;font-family:{random.choice(SAFE_FONTS)};')} }}"
|
||||
soup.head.append(style_tag)
|
||||
|
||||
# Function to add random images
|
||||
def add_random_images(soup, count=1):
|
||||
for _ in range(count):
|
||||
img = soup.new_tag('img', src='data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==', style=f'display:none;border:{random.randint(0, 1)}px solid {generate_random_color()};')
|
||||
soup.body.append(img)
|
||||
|
||||
# Function to add random scripts
|
||||
def add_random_scripts(soup, count=1, dictionary='general'):
|
||||
for _ in range(count):
|
||||
script = soup.new_tag('script')
|
||||
script.string = f"// {generate_random_text(3, 7, dictionary)}"
|
||||
soup.body.append(script)
|
||||
|
||||
# Function to insert random rare tags
|
||||
def insert_random_rare_tags(soup, count=1, dictionary='general'):
|
||||
rare_tags = ['article', 'section', 'footer', 'aside', 'nav']
|
||||
for _ in range(count):
|
||||
tag = soup.new_tag(random.choice(rare_tags), style=f'display:none;color:{generate_random_color()};font-family:{random.choice(SAFE_FONTS)};')
|
||||
tag.string = generate_random_text(2, 4, dictionary)
|
||||
soup.body.insert(random.randint(0, len(soup.body.contents)), tag)
|
||||
|
||||
# Function to insert random headers
|
||||
def insert_random_headers(soup, count=1, dictionary='general'):
|
||||
for _ in range(count):
|
||||
header = soup.new_tag(f'h{random.randint(1, 6)}', style=f'display:none;color:{generate_random_color()};font-size:0;')
|
||||
header.string = generate_random_text(2, 5, dictionary)
|
||||
soup.body.append(header)
|
||||
|
||||
# Main function to generate the email
|
||||
def generate_emails(args):
|
||||
input_file = args.input_file
|
||||
output = args.output
|
||||
min_words = args.min_words
|
||||
max_words = args.max_words
|
||||
invisible_char_prob = args.invisible_char_prob
|
||||
span_prob = args.span_prob
|
||||
comment_count = args.comment_count
|
||||
meta_count = args.meta_count
|
||||
table_count = args.table_count
|
||||
style_count = args.style_count
|
||||
image_count = args.image_count
|
||||
script_count = args.script_count
|
||||
rare_tag_count = args.rare_tag_count
|
||||
header_count = args.header_count
|
||||
dictionary = args.dictionary
|
||||
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
html_template = f.read()
|
||||
|
||||
soup = BeautifulSoup(html_template, 'html.parser')
|
||||
|
||||
# Randomizing the title
|
||||
title = soup.find('title')
|
||||
if title:
|
||||
title.string = insert_invisible_chars(generate_random_text(min_words, max_words, dictionary), invisible_char_prob)
|
||||
|
||||
# Hidden content with randomization
|
||||
hidden_div = soup.new_tag('div', style=f"display:none;font-size:0;line-height:0;{shuffle_styles(f'opacity:0;color:{generate_random_color()};font-family:{random.choice(SAFE_FONTS)}')}")
|
||||
hidden_div.string = insert_invisible_chars(generate_random_text(5, 10, dictionary), invisible_char_prob)
|
||||
hidden_span = soup.new_tag('span')
|
||||
hidden_span.string = str(random.random())
|
||||
hidden_div.append(hidden_span)
|
||||
body = soup.find('body')
|
||||
if body:
|
||||
body.insert(0, hidden_div)
|
||||
body.append(copy.deepcopy(hidden_div)) # Clone to add at the end
|
||||
|
||||
# Shuffling styles
|
||||
for el in soup.find_all(style=True):
|
||||
el['style'] = shuffle_styles(el['style'])
|
||||
|
||||
# Randomizing text while preserving <p> tag structure
|
||||
for p_tag in soup.find_all('p'):
|
||||
text_nodes = [node for node in p_tag.contents if isinstance(node, str)]
|
||||
if not text_nodes:
|
||||
continue
|
||||
|
||||
new_content = []
|
||||
for text in text_nodes:
|
||||
words = text.split()
|
||||
for i, word in enumerate(words):
|
||||
new_content.append(soup.new_string(insert_invisible_chars(word, invisible_char_prob)))
|
||||
if random.random() < span_prob:
|
||||
hidden_element = insert_random_hidden_element(soup, dictionary)
|
||||
new_content.append(hidden_element)
|
||||
if i < len(words) - 1:
|
||||
new_content.append(soup.new_string(' ')) # Preserve spaces
|
||||
|
||||
# Clear the content of <p> and add new content
|
||||
p_tag.clear()
|
||||
for item in new_content:
|
||||
p_tag.append(item)
|
||||
|
||||
# Adding random attributes to all tags
|
||||
for tag in soup.find_all():
|
||||
add_random_attributes(tag)
|
||||
|
||||
# Inserting random comments
|
||||
insert_random_comments(soup, comment_count, dictionary)
|
||||
|
||||
# Inserting random empty tags
|
||||
for _ in range(random.randint(1, 4)):
|
||||
empty_tag = soup.new_tag(random.choice(['div', 'span', 'p']), style=shuffle_styles(f'display:none;opacity:0;color:{generate_random_color()};'))
|
||||
soup.body.insert(random.randint(0, len(soup.body.contents)), empty_tag)
|
||||
|
||||
# Adding random meta tags
|
||||
add_random_meta(soup, meta_count, dictionary)
|
||||
|
||||
# Randomizing links
|
||||
add_random_link_params(soup)
|
||||
|
||||
# Inserting random tables
|
||||
insert_random_tables(soup, table_count, dictionary)
|
||||
|
||||
# Adding random styles
|
||||
add_random_styles(soup, style_count)
|
||||
|
||||
# Adding random images
|
||||
add_random_images(soup, image_count)
|
||||
|
||||
# Adding random scripts
|
||||
add_random_scripts(soup, script_count, dictionary)
|
||||
|
||||
# Adding random rare tags
|
||||
insert_random_rare_tags(soup, rare_tag_count, dictionary)
|
||||
|
||||
# Adding random headers
|
||||
insert_random_headers(soup, header_count, dictionary)
|
||||
|
||||
# Save the file or print to stdout
|
||||
if output == '-':
|
||||
print(str(soup))
|
||||
else:
|
||||
os.makedirs(os.path.dirname(output) or '.', exist_ok=True)
|
||||
with open(output, 'w', encoding='utf-8') as f:
|
||||
f.write(str(soup))
|
||||
print(f"Saved to {output}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Generator of randomized HTML emails to bypass spam filters')
|
||||
parser.add_argument('input_file', help='Path to the input HTML file')
|
||||
parser.add_argument('-o', '--output', default='-', help='Output file path (default: - for stdout)')
|
||||
parser.add_argument('--min_words', type=int, default=2, help='Minimum number of words in generated text (default: 2)')
|
||||
parser.add_argument('--max_words', type=int, default=5, help='Maximum number of words in generated text (default: 5)')
|
||||
parser.add_argument('--invisible_char_prob', type=float, default=0.15, help='Probability of inserting an invisible character (default: 0.15)')
|
||||
parser.add_argument('--span_prob', type=float, default=0.4, help='Probability of inserting a span tag (default: 0.4)')
|
||||
parser.add_argument('--comment_count', type=int, default=1, help='Number of random comments (default: 1)')
|
||||
parser.add_argument('--meta_count', type=int, default=1, help='Number of random meta tags (default: 1)')
|
||||
parser.add_argument('--table_count', type=int, default=1, help='Number of random tables (default: 1)')
|
||||
parser.add_argument('--style_count', type=int, default=1, help='Number of random styles (default: 1)')
|
||||
parser.add_argument('--image_count', type=int, default=1, help='Number of random images (default: 1)')
|
||||
parser.add_argument('--script_count', type=int, default=1, help='Number of random scripts (default: 1)')
|
||||
parser.add_argument('--rare_tag_count', type=int, default=1, help='Number of random rare tags (default: 1)')
|
||||
parser.add_argument('--header_count', type=int, default=1, help='Number of random headers (default: 1)')
|
||||
parser.add_argument('--dictionary', choices=['general', 'technical', 'marketing'], default='general', help='Dictionary for text generation (default: general)')
|
||||
|
||||
args = parser.parse_args()
|
||||
generate_emails(args)
|
||||
1
requirements.txt
Normal file
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
||||
beautifulsoup4
|
||||
Reference in New Issue
Block a user