{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Project 3 - Search-Based Web Fuzzer " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import fuzzingbook_utils" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction\n", "\n", "Fuzzing web applications can be challenging. A simple web form requires a specific input format for each field, this format needs to be fulfilled for a valid web interaction (e.g. an email field is expected to fulfill the following regex pattern `r'^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$')`.\n", "\n", "In this project, we demonstrate how to apply a search-based algorithm to generate specific test inputs for web interfaces. The generated inputs should exercise the web application by fulfilling the input validation requirements of all fields required to reach specific web pages (both normal and error pages). \n", "\n", "The task is to employ a genetic algorithm (GA) for fuzzing, your implementation is expected to generate inputs that match the expected pattern or constraints of the input field (e.g. email fuzzingbook@gmail.com fulfils the expected email regex pattern `r'^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$')`. This is to be achieved by searching the input space starting from an initially (random) input. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from WebFuzzer import init_db, SimpleHTTPRequestHandler\n", "from http.server import HTTPServer, HTTPStatus " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Objective\n", "\n", "The goal of this project is to _implement a search-based fuzzing algorithm that generates specifically formatted inputs which fulfil the input validation requirements of a web form_. \n", "\n", "You will apply techniques learned in the lecture ([SBST](SBST.ipynb) and [WebFuzzer](WebFuzzer.ipynb)) to automatically fill web forms by producing inputs that improve the reachability of web pages. \n", "\n", "The goal of your Fuzzer is to cleverly search the input space until the input validation format of the input field is achieved. Consequently, fulfilling (or not fulfilling) such input validation schemes achieves the reachability of specific web pages and improves the coverage of the site map. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Web Application\n", "\n", "We create a (HTML only) web application for placing an order of items, similar to the order form in the [WebFuzzer](WebFuzzer.ipynb) lecture.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Input Validation\n", "\n", "We create a `ProjectHTTPRequestHandler` class that provides a web order form with input validation schemes for all input formats. \n", "\n", "First, we create a sample set of regex for input validation of each input field in our order form. \n", "\n", "__Note that your implementation shall be evaluated with a _secret set of regex_ other than the ones provided below.__\n", "\n", "For some input fields, we have provided other sample regexes you may use to test your implementation, other regexes are provided to inform you of the nature of the regexes which may be used to evaluate your final solution. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "itemList = [r'^(tshirt|drill|lockset)\\Z', r'^(lockset)\\Z' ]\n", "\n", "name_regex = [r'^[A-Za-z.\\'\\-\\p{L}\\p{Zs}\\p{Lu}\\p{Ll}\\']+$', r'^([A-Z]{1}+[a-z\\-\\.\\']*+[\\s]?)*$']\n", "\n", "email_regex = [r'^([a-z0-9_\\.-]+)@(yahoo\\.com|gmail\\.com|cispa\\.saarland)$',\\\n", " r'[a-zA-Z0-9_\\.\\+-]+\\[at\\]\\[](25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\[dot\\](25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\]$']\n", "\n", "zip_regex = [r'^[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z][ ]?\\d[ABCEGHJ-NPRSTV-Z]\\d$', \\\n", " r'^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\\d{1,4}$'] \n", "\n", "city_regex = [r'^[a-zA-Z]+(?:[\\s-][a-zA-Z]+)*$', r'^\\b(\\w+)\\b(?=.*\\1)$']\n", "\n", "terms_regex = r'^on\\Z'\n", "\n", "\n", "list_regex = [itemList[0], name_regex[0], email_regex[0], city_regex[0], zip_regex[0], terms_regex]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"len name_regex: \", len(name_regex))\n", "print(\"len email_regex: \", len(email_regex))\n", "print(\"len zip_regex: \", len(zip_regex))\n", "print(\"len city_regex: \", len(city_regex))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We define diagnostic error messages for each error page." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "error_msg_list = [\"INCOMPLETE INPUT: \\n All fields have to be filled \",\\\n", " \"INVALID INPUT: \\n Item is not in item list\",\\\n", " \"INVALID INPUT: \\n Name does not match expected pattern :\\n \",\\\n", " \"INVALID INPUT: \\n Email does not match expected pattern :\\n \",\\\n", " \"INVALID INPUT: \\n City does not match expected pattern :\\n \",\\\n", " \"INVALID INPUT: \\n Zip does not match expected pattern :\\n \",\\\n", " \"INVALID INPUT: \\n Terms and Conditions have to be checked \"\n", " ]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We override the `handle_order()` method, to validate the values of each input field using the pre-defined regex patterns above. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We use the [regex parser](https://pypi.org/project/regex/), specifically version 2.5.23, instead of Python's native `re`, because `re` does not support the `\\p{}` syntax. Confirm regex version using: " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!pip install regex \n", "import regex\n", "print(regex.__version__)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class ProjectHTTPRequestHandler(SimpleHTTPRequestHandler):\n", " def handle_order(self): \n", " values = self.get_field_values()\n", "\n", " if len(values) < 6:\n", " error_type = error_msg_list[0]\n", " self.internal_server_error(error_type)\n", " \n", " elif regex.match(list_regex[0], values[\"item\"]) and regex.match(list_regex[1], values[\"name\"]) and \\\n", " regex.match(list_regex[2], values[\"email\"]) and regex.match(list_regex[4], values[\"zip\"]) and \\\n", " regex.match(list_regex[3], values[\"city\"]) and regex.match(list_regex[5], values[\"terms\"]):\n", " self.store_order(values)\n", " self.send_order_received(values)\n", "\n", " elif not regex.match(list_regex[0], values[\"item\"]):\n", " error_type = error_msg_list[1]\n", " self.internal_server_error(error_type) \n", " \n", " elif not regex.match(list_regex[1], values[\"name\"]):\n", " error_type = error_msg_list[2] + list_regex[1] \n", " self.internal_server_error(error_type)\n", " \n", " elif not regex.match(list_regex[2], values[\"email\"]):\n", " error_type = error_msg_list[3] + list_regex[2]\n", " self.internal_server_error(error_type)\n", " \n", " elif not regex.match(list_regex[3], values[\"city\"]):\n", " error_type = error_msg_list[4] + list_regex[3]\n", " self.internal_server_error(error_type)\n", " \n", " elif not regex.match(list_regex[4], values[\"zip\"]):\n", " error_type = error_msg_list[5] + list_regex[4]\n", " self.internal_server_error(error_type)\n", " \n", " elif not regex.match(list_regex[5], values[\"terms\"]):\n", " error_type = error_msg_list[6]\n", " self.internal_server_error(error_type)\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Internal Errors\n", "For diagnostic (and identification) purposes, the internal server error pages include the error message indicating the input validation scheme that failed." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "HTML_INTERNAL_SERVER_ERROR = \"\"\"\n", "\n", "
\n", " Internal Server Error\n", "

\n", " The server has encountered an internal error. Go to our order form.\n", "

{error_message}
\n", "

\n", "
\n", "\n", " \"\"\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import sys\n", "import traceback\n", "\n", "class ProjectHTTPRequestHandler(ProjectHTTPRequestHandler):\n", " def internal_server_error(self, error_type=None):\n", " self.send_response(HTTPStatus.OK, \"Internal Error\")\n", "\n", " self.send_header(\"Content-type\", \"text/html\")\n", " self.end_headers()\n", "\n", " exc = traceback.format_exc()\n", " self.log_message(\"%s\", exc.strip())\n", "\n", " message = HTML_INTERNAL_SERVER_ERROR.format(error_message=error_type)\n", " self.wfile.write(message.encode(\"utf8\"))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from fuzzingbook_utils import HTML \n", "HTML(HTML_INTERNAL_SERVER_ERROR)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Storing Orders" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similar to the [WebFuzzer](WebFuzzer.ipynb) lecture, we store orders using a *database* stored in the file `orders.db`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "FUZZINGBOOK_SWAG = {\n", " \"tshirt\": \"One FuzzingBook T-Shirt\",\n", " \"drill\": \"One FuzzingBook Rotary Hammer\",\n", " \"lockset\": \"One FuzzingBook Lock Set\"\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import sqlite3, os\n", "\n", "ORDERS_DB = \"orders.db\"\n", "\n", "class ProjectHTTPRequestHandler(ProjectHTTPRequestHandler):\n", " def store_order(self, values):\n", " db = sqlite3.connect(ORDERS_DB)\n", " db.execute(\"INSERT INTO orders VALUES (?, ?, ?, ?, ?, ?)\",\n", " (values['item'], values['name'], values['email'], values['city'], values['zip'], values['terms']))\n", " db.commit()\n", "\n", " def send_order_received(self, values):\n", " values[\"item_name\"] = FUZZINGBOOK_SWAG[values[\"item\"]]\n", " confirmation = HTML_ORDER_RECEIVED.format(**values).encode(\"utf8\")\n", "\n", " self.send_response(HTTPStatus.OK, \"Order received\")\n", " self.send_header(\"Content-type\", \"text/html\")\n", " self.end_headers()\n", " self.wfile.write(confirmation)\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def init_db():\n", " if os.path.exists(ORDERS_DB):\n", " os.remove(ORDERS_DB)\n", "\n", " db_connection = sqlite3.connect(ORDERS_DB)\n", " db_connection.execute(\"DROP TABLE IF EXISTS orders\")\n", " db_connection.execute(\"CREATE TABLE orders (item text, name text, email text, city text, zip text, terms text)\")\n", " db_connection.commit()\n", "\n", " return db_connection\n", "\n", "db = init_db()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(db.execute(\"SELECT * FROM orders\").fetchall())\n", "\n", "db.execute(\"INSERT INTO orders \" +\n", " \"VALUES ('lockset', 'Jane Lee Doe', 'jane@doe.com', 'Saarbrucken', '66125', 'on')\")\n", "db.commit()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(db.execute(\"SELECT * FROM orders\").fetchall())\n", "\n", "\n", "db.execute(\"DELETE FROM orders WHERE name = 'Walter White'\")\n", "db.commit()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(db.execute(\"SELECT * FROM orders\").fetchall())" ] }, { "cell_type": "markdown", "metadata": { "toc-hr-collapsed": false }, "source": [ "### Order Confirmation\n", "\n", "Once we have gotten an order, we show a confirmation page, which is instantiated with the customer information submitted before." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "button": false, "new_sheet": false, "run_control": { "read_only": false }, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "HTML_ORDER_RECEIVED = \"\"\"\n", "\n", "
\n", " Thank you for your Fuzzingbook Order!\n", "

\n", " We will send {item_name} to {name} in {city}, {zip}
\n", " A confirmation mail will be sent to {email}.\n", "

\n", "

\n", " Want more swag? Use our order form!\n", "

\n", "
\n", "\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Logging \n", "\n", "Similar to the [WebFuzzer](WebFuzzer.ipynb) lecture, we provide a logging infrastructure for debugging purposes. We implement the following:\n", "- `print_httpd_messages()` prints all messages accumulated in the queue\n", "- `clear_httpd_messages()` discards all pending messages\n", "- `log_message()` store messages in the queue " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from multiprocessing import Queue, Process\n", "from fuzzingbook_utils import rich_output, terminal_escape, unicode_escape, HTML\n", "\n", "HTTPD_MESSAGE_QUEUE = Queue()\n", "\n", "def display_httpd_message(message):\n", " if rich_output():\n", " display(\n", " HTML(\n", " '
' +\n",
    "                message +\n",
    "                \"
\"))\n", " else:\n", " print(terminal_escape(message))\n", "\n", "def print_httpd_messages():\n", " while not HTTPD_MESSAGE_QUEUE.empty():\n", " message = HTTPD_MESSAGE_QUEUE.get()\n", " display_httpd_message(message)\n", "\n", "def clear_httpd_messages():\n", " while not HTTPD_MESSAGE_QUEUE.empty():\n", " HTTPD_MESSAGE_QUEUE.get()\n", "\n", "class ProjectHTTPRequestHandler(ProjectHTTPRequestHandler):\n", " def log_message(self, format, *args):\n", " message = (\"%s - - [%s] %s\\n\" %\n", " (self.address_string(),\n", " self.log_date_time_string(),\n", " format % args))\n", " HTTPD_MESSAGE_QUEUE.put(message)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Extend `webbrowser()` method to prints log messages produced by the server:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from Carver import webbrowser as simple_webbrowser\n", "\n", "def webbrowser(url, mute=False):\n", " try:\n", " contents = simple_webbrowser(url)\n", " finally:\n", " if not mute:\n", " print_httpd_messages()\n", " else:\n", " clear_httpd_messages()\n", "\n", " return contents" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running the Web Application\n", "Similar to the [WebFuzzer](WebFuzzer.ipynb) lecture, to run the web application we implement the following:\n", "\n", "* `run_httpd_forever()`\n", "* `start_httpd()`\n", "* `print_url()`\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def run_httpd_forever(handler_class):\n", " host = \"127.0.0.1\" # localhost IP\n", " for port in range(8800, 9000):\n", " httpd_address = (host, port)\n", "\n", " try:\n", " httpd = HTTPServer(httpd_address, handler_class)\n", " break\n", " except OSError:\n", " continue\n", "\n", " httpd_url = \"http://\" + host + \":\" + repr(port)\n", " HTTPD_MESSAGE_QUEUE.put(httpd_url)\n", " httpd.serve_forever()\n", "\n", "def start_httpd(handler_class=ProjectHTTPRequestHandler):\n", " clear_httpd_messages()\n", "\n", " httpd_process = Process(target=run_httpd_forever, args=(handler_class,))\n", " httpd_process.start()\n", "\n", " httpd_url = HTTPD_MESSAGE_QUEUE.get()\n", " return httpd_process, httpd_url\n", "\n", "httpd_process, httpd_url = start_httpd(ProjectHTTPRequestHandler)\n", "\n", "def print_url(url):\n", " if rich_output():\n", " display(HTML('
%s
' % (url, url)))\n", " else:\n", " print(terminal_escape(url))\n", "\n", "print_url(httpd_url)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note**: The above URL only works if you are running the Jupyter notebook server on the local host." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Testing the Web Application\n", "### Input Format\n", "\n", "When the user clicks `Submit` on the order form, the Web browser creates and retrieves a URL of the form:\n", "\n", "```\n", "/order?item=value_1&name=value_2&email=value_3&city=value_4&zip=value_5&terms=value_6\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We test standard behavior:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "standard_order = \"/order?item=tshirt&name=Jane+Lee+Doe&email=doe%40cispa.saarland&city=Seattle&zip=A1A1A1&terms=on\"\n", "contents = webbrowser(httpd_url + standard_order)\n", "HTML(contents)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "assert contents.find(\"Thank you\") and contents.find(\"We will send\") and contents.find(\"A confirmation mail will be sent to\") > 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We test erroneous behavior - terms and conditions not checked:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "error_order = \"/order?item=tshirt&name=Jane+Lee+Doe&email=doe%40cispa.saarland&city=Seattle&zip=A1A1A1&terms=off\"\n", "contents = webbrowser(httpd_url + error_order)\n", "HTML(contents)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "assert contents.find(\"Internal Server Error\") and contents.find(error_msg_list[6]) > 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We test incomplete order behavior:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "incomplete_order = \"/order?item=tshirt&name=Jane+Lee+Doe&email=doe%40example.com&city=Seattle&zip=98104\"\n", "contents = webbrowser(httpd_url + incomplete_order)\n", "HTML(contents)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "assert contents.find(\"Internal Server Error\") and contents.find(error_msg_list[0]) > 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To test for another input validation regex (e.g. the second regex pattern for each field - index 1), use:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Obtaining Coverage\n", "\n", "We define the `target_list` for each web page accordingly:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\"\"\"\n", "target_list:\n", " ISE_Name = Internal Server Error Web Page for \"Name\" field error, analogously for ISE_Item, ISE_City, etc..\n", " ISE_INC = Internal Server Error Web Page for \"Incomplete Input\" \n", " PNF = Page Not Found Web Page\n", " CONF = CONFIRMATION_PAGE\n", "\"\"\"\n", "target_list = [\"ISE_INC\", \"ISE_Item\", \"ISE_Name\", \"ISE_Email\", \"ISE_City\",\"ISE_Zip\", \"ISE_Terms\", \"CONF\", \"PNF\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To obtain the overall coverage achieved by the GA's resulting population, we implement the following web reachability function. \n", "\n", "For each target, we compute:\n", "* _validity_ score: the number of valid inputs in the generated population that reach the target, and\n", "* _reachability_ score: we score the number of inputs that reach the each page. \n", "\n", "The reachability scores for the number of inputs reaching the target is based on the perceived difficulty to reach the page:\n", "* 2 points for each input reaching an error page\n", "* 5 points for each input reaching the confirmation page\n", "* 1 point for each input reaching the page not found page\n", "\n", "**Note**: we expect each run of your genetic algorithm to produce 10 inputs maximum." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def get_web_reachability(orders, target):\n", " global httpd_process, httpd_url\n", " num_reached_pages = dict() \n", " reachability, validity = 0, 0\n", " conf_msg = [\"Thank you\", \"We will send\", \"A confirmation mail will be sent to\"]\n", " page_not_found = \"This page does not exist\"\n", " \n", " for order in orders:\n", " try:\n", " clear_httpd_messages()\n", " contents = webbrowser(httpd_url + order, mute=True)\n", " HTML(contents)\n", " \n", " # obtain 2 reachability points for each input reaching an error page\n", " if contents.find(\"Internal Server Error\") > 0:\n", " if target_list.index(target) <= 6:\n", " msg = error_msg_list[target_list.index(target)]\n", " if contents.find(msg) > 0: \n", " if not msg in num_reached_pages:\n", " num_reached_pages[msg] = 2\n", " else:\n", " num_reached_pages[msg] += 2\n", " validity += 1\n", "\n", " # obtain 5 reachability points for each input reaching confirmation page\n", " if target == target_list[7] and contents.find(conf_msg[0]) > 0 and contents.find(conf_msg[1]) > 0 \\\n", " and contents.find(conf_msg[2]) > 0:\n", " if not conf_msg[0] in num_reached_pages:\n", " num_reached_pages[conf_msg[0]] = 5\n", " else:\n", " num_reached_pages[conf_msg[0]] += 5\n", " validity += 1\n", "\n", " # obtain 1 reachability point for each input reaching a non-existent page\n", " if target == target_list[8] and contents.find(page_not_found) > 0:\n", " if not page_not_found in num_reached_pages:\n", " num_reached_pages[page_not_found] = 1\n", " else:\n", " num_reached_pages[page_not_found] += 1\n", " validity += 1\n", " \n", " except Exception as e:\n", " e.__traceback__ = None\n", " traceback.clear_frames(e.__traceback__)\n", " pass\n", " \n", " \n", " if len(num_reached_pages) > 0:\n", " reachability = sum(num_reached_pages.values())\n", " return reachability, validity" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We test the `get_web_reachability` function for the `confirmation` page target with a sample list of test order URLs. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "test_orders = [\"/order?item=tshirt&name=Jane+Lee+Doe&email=doe%40example.com&city=Seattle&zip=98104&terms=off\",\\\n", " \"/order?item=tshirt&name=Jane+Lee+Doe&email=doe%40example.com&city=Seattle&zip=98104&terms=on\",\\\n", " \"/order\", \"/none\",\\\n", " \"/order?item=lockset&name=Jane+lee+Doe&email=doe%40example.com&city=Seattle&zip=98104&terms=on\",\\\n", " \"/order?item=tshirt&name=Jane+Lee+Doe&email=doe%40cispa.saarland&city=Seattle&zip=98104&terms=on\",\\\n", " \"/order?item=book&name=Jane+Lee+Doe&email=doe%40example.com&city=Seattle&zip=98104&terms=on\",\\\n", " \"/order?item=tshirt&name=Jane+Lee+Doe&email=doe%40example.com&city=Seattle&zip=98104&terms=on\",\\\n", " \"/order?item=tshirt&name=Jane+Lee+Doe&email=doe%40example.com&city=Seattle&zip=498104&terms=on\",\\\n", " \"/order?item=tshirt&name=Jane+Lee+Doe&email=doe%40example.com&city=Neunkirchen&zip=98104&terms=on\",\\\n", " ]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Test for the reachability of confirmation page (\"CONF\") using the above order inputs:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "get_web_reachability(test_orders, \"CONF\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Search Based Fuzzing\n", "\n", "We demonstrate how a specific input format can be generated with a simple search-based algorithm and a naive fitness function. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We assume an input url with an invalid name format error:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import random, string\n", "invalid_name_order = \"/order?item=tshirt&name=Jane+Lee+Doe1&email=doe%40example.com&city=Seattle&zip=98104&terms=on\"\n", "contents = webbrowser(httpd_url + invalid_name_order)\n", "HTML(contents)\n", "assert contents.find(\"Internal Server Error\") and contents.find(error_msg_list[2]) > 0" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import urllib.parse\n", "test_name = urllib.parse.parse_qs(invalid_name_order, keep_blank_values=True)[\"name\"][0] " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We implement a naive distance function for \"name\" input field:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def naive_calculate_name_distance(name):\n", " name_regex = r'[A-Z][a-z]+ [A-Z][a-z]+ [A-Z][a-z]+'\n", " res = 1\n", " if len(name.split()) == 3 and check_ascii_letters(name) and \\\n", " check_word_size(name) and name.istitle():\n", " res = 0\n", " else:\n", " if len(name.split()) == 3:\n", " res -= 0.4\n", " if check_ascii_letters(name):\n", " res -= 0.35\n", " if check_word_size(name):\n", " res -= 0.15\n", " if name.istitle():\n", " res -= 0.10\n", " return res \n", "\n", "def check_ascii_letters(name):\n", " res = True\n", " for char in name.replace(\" \", \"\"):\n", " if not (char in string.ascii_letters):\n", " res = False\n", " break\n", " return res\n", "\n", "def check_word_size(name):\n", " res = True\n", " for word in name.split():\n", " if len(word) < 2:\n", " res = False\n", " break\n", " return res" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We implement a naive fitness function for the name input. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def get_naive_fitness(name):\n", " global distance\n", " distance = naive_calculate_name_distance(name)\n", " fitness = distance\n", " return fitness" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We implement a simple mutation function `flip_random_character` for the name input. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def flip_random_character(s):\n", " pos = random.randint(0, len(s) - 1)\n", " new_c = chr(random.randrange(65, 130))\n", " return s[:pos] + new_c + s[pos + 1:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We implement a simple search-based algorithm -`randomized_hillclimber()`, to run for a maximum of 5000 iterations :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def randomized_hillclimber(name):\n", " fitness = get_naive_fitness(name)\n", " print(\"Initial value: %s at fitness %.4f\" % (name, fitness))\n", " iterations = 0\n", "\n", " while fitness > 0 and iterations < 5000:\n", " iterations += 1\n", " \n", " mutated = flip_random_character(name)\n", " new_fitness = get_naive_fitness(mutated)\n", " if new_fitness <= fitness:\n", " name = mutated\n", " fitness = new_fitness\n", "\n", " if iterations < 5000:\n", " print(\"Optimum at %s after %d iterations\" % (name, iterations))\n", " else:\n", " print(\"# iterations is: %d, stop!!!\" % (iterations))\n", " return name, iterations" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in range(0, 5):\n", " new_name, no_iterations = randomized_hillclimber(test_name) \n", " if no_iterations < 5000:\n", " new_name = new_name.replace(\" \", \"+\")\n", " new_order = \"/order?item=tshirt&name=\" + new_name + \"&email=doe%40cispa.saarland&city=Seattle&zip=A1A1A1&terms=on\"\n", " new_order\n", " break\n", " new_name = new_name.replace(\" \", \"+\")\n", " new_order = \"/order?item=tshirt&name=\" + new_name + \"&email=doe%40cispa.saarland&city=Seattle&zip=A1A1A1&terms=on\"\n", " new_order" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "new_order" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "clear_httpd_messages()\n", "contents = webbrowser(httpd_url + new_order)\n", "HTML(contents)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "assert contents.find(\"Thank you\") and contents.find(\"We will send\") and contents.find(\"A confirmation mail will be sent to\") > 0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Genetic Algorithm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Genetic Algorithm template\n", "\n", "The basic template of the genetic algorithm is based on the [SBST](SBST.ipynb) from the lecture.\n", "\n", "This template uses your implemented fitness, selection, mutation and crossover functions for the population of input urls. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from multiprocessing import Process\n", "import traceback\n", "\n", "def run_with_limited_time(func, args, kwargs, time):\n", " p = Process(target=func, args=args, kwargs=kwargs)\n", " p.start()\n", " p.join(time)\n", " if p.is_alive():\n", " p.terminate()\n", " return False\n", "\n", " return True\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def evaluate_population(population, target, list_regex):\n", " fitness = [get_fitness(x, target, list_regex) for x in population]\n", " return list(zip(population, fitness))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def terminal_repr(s):\n", " return terminal_escape(repr(s))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import time\n", "\n", "def genetic_algorithm(population, target, list_regex, return_dict):\n", " # Generate and evaluate initial population\n", " generation = 0\n", " fitness = evaluate_population(population, target, list_regex)\n", " best = min(fitness, key=lambda item: item[1])\n", " best_individual = best[0]\n", " best_fitness = best[1]\n", "\n", " start_time = time.time()\n", " time_spent = 0\n", " \n", " # Stop when optimum found, or we run out of patience, i.e. 1000 iterations or 1 hour max\n", " while best_fitness > 0 and generation < 1000 and (time_spent <= 3600):\n", "\n", " # The next generation will have the same size as the current one\n", " new_population = []\n", " while len(new_population) < len(population):\n", " \n", " # Selection\n", " try:\n", " if run_with_limited_time(selection, (fitness, 10,), {}, 2):\n", " offspring1 = selection(fitness, 10)\n", " except Exception as e:\n", " e.__traceback__ = None\n", " traceback.clear_frames(e.__traceback__)\n", " pass\n", " \n", " try:\n", " if run_with_limited_time(selection, (fitness, 10,), {}, 2):\n", " offspring2 = selection(fitness, 10)\n", " except Exception as e:\n", " e.__traceback__ = None\n", " traceback.clear_frames(e.__traceback__)\n", " pass\n", "\n", " # Crossover\n", " if random.random() < 0.7:\n", " try:\n", " if run_with_limited_time(crossover, (offspring1, offspring2,), {}, 2):\n", " (offspring1, offspring2) = crossover(offspring1, offspring2)\n", " except Exception as e:\n", " e.__traceback__ = None\n", " traceback.clear_frames(e.__traceback__)\n", " pass\n", "\n", " # Mutation\n", " try:\n", " if run_with_limited_time(mutate, (offspring1,), {}, 2):\n", " offspring1 = mutate(offspring1)\n", " except Exception as e:\n", " e.__traceback__ = None\n", " traceback.clear_frames(e.__traceback__)\n", " pass\n", " \n", " try:\n", " if run_with_limited_time(mutate, (offspring2,), {}, 2):\n", " offspring2 = mutate(offspring2)\n", " except Exception as e:\n", " e.__traceback__ = None\n", " traceback.clear_frames(e.__traceback__)\n", " pass\n", " \n", "\n", " new_population.append(offspring1)\n", " new_population.append(offspring2)\n", "\n", " # Once full, the new population replaces the old one\n", " generation += 1\n", " population = new_population\n", " \n", " try:\n", " if run_with_limited_time(evaluate_population, (population, target, list_regex,), {}, 10):\n", " fitness = evaluate_population(population, target, list_regex)\n", " except Exception as e:\n", " e.__traceback__ = None\n", " traceback.clear_frames(e.__traceback__)\n", " pass\n", "\n", " best = min(fitness, key=lambda item: item[1])\n", " best_individual = best[0]\n", " best_fitness = best[1]\n", " \n", " \n", " end_time = time.time()\n", " time_spent = end_time - start_time\n", " \n", " return_dict[target] = population, generation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Your Tasks\n", "For each input, you are epxected to produce a set of urls to reach a targeted web page, i.e. generate inputs that will fulfill the input validation requirements necessary to reach a specific web page. Overall, all web pages will be targets, i.e. both error and normal pages. \n", "\n", "Your task is to implement your own custom selection, fitness and mutation functions for the genetic algorithm, in order to fulfill the input validation and web reachabilty requirements." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tips\n", "\n", "* Your fitness function should target a specific web page,e.g. a specific error page like an invalid name error page. \n", "* For input (fragment) distance consider using a (fuzzy/approximate) regex matching distance of the input to the expected regex.\n", "* You are allowed to use the `fuzzingbook` module, any of the [inbuilt python modules](https://docs.python.org/3/py-modindex.html) and the [regex module](https://pypi.org/project/regex/). \n", "* __Do not import external modules other than the afore-mentioned modules, and do not use (parts of) open source code__.\n", "* You can develop any type of mutation, selection and crossover functions.\n", "* Ensure that your implementation accounts for any arbitrary regex and any random initial population of inputs.\n", "* For debugging purposes: unmute the `webbrowser()` to obtain logging information, i.e. set `webbrowser(url, mute=False)` \n", "* Do not implement in any other section except the section below. \n", "* Gracefully handle exceptions and errors resulting from your impelementation.\n", "* __Remember the input validation regex and initial input population could be arbitrary, do not hard code for a specific regex or input__." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Your Code" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the following section implement the following:\n", "* __Fitness Function(s)__: define a (set of) fitness function for an order URL to validate/invalidate each input field to reach specific pages (target). \n", "\n", "* __Selection Function__: define a selection function for the given generated population of URLs.\n", "\n", "* __Crossover Function__: define a crossover function for two parent input URLs.\n", "\n", "* __Mutate Function__: define a mutate function for our input URL.\n", "\n", "Implement your own fitness, selection and mutation functions for the GA algorithm below:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\"\"\"\n", "INSERT YOUR CODE BELOW\n", "\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Evaluation code\n", "\n", "The code in the following section will be used to evaluate your impelementation." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Random Population of Inputs\n", "We randomly generated an `initial_population` of 20 set of inputs for our order web form, with (4) varying levels of difficulty (or garbage). Each populations of input URL contains 10 input URLs for orders.\n", "\n", "__Note that the url path population which will be used for evaluation may be different from those provided as example.__" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "code_folding": [ 4, 15, 26, 37, 48, 62, 73, 84, 95, 106, 118, 129, 140, 151, 162, 174, 185, 196, 207, 218 ] }, "outputs": [], "source": [ "\"\"\"\n", "Final Evaluation Population \n", "\"\"\"\n", "\n", "easy_population_1 = ['/order?item=drills&name=[Jc{_kWmegnEkeAGtSLBELU]uGA^rBiBqG{r]N`IoetX+dLC]d{edp]GvxcxMBvb[jV{WW`Ihy}mdoWAKj_XnFRwMF`PJ+`k{mtsa]p]zxqbI^tJE`J~_k}[C&email=rmbhbgudcludejtmmpirjn%40mdx&city=V{Tl~&zip=77011&terms=checked',\n", " '/order?item=drills&name=zxBjCtPVYywPxTdHff\\\\`HAWJYj[]+f{[NUQ{GusHnC{B_z`JfbQ|~opk~uZOW]ml}iPqzf`JWObf+vsb]BUKpv}OyOCCTsLw&email=wrwgyudtzzugpiqbxkvpsdnsn%40ffhzk&city=qBHizzZUc&zip=0051&terms=undefined',\n", " '/order?item=lockset&name=CJvhKs+dlTOcfhCxXqN{+Rf_getneyFKVbyDpmcRBFqK~Von^{|EhlFZjkixVzAQkvJ&email=vnadrrlxdxbumxh%40pvdr&city=ryVOms&zip=04381&terms=on',\n", " '/order?item=Drill&name=DDLIoB|SlUNLjhd\\\\maS[gfYyCtL{s+VPJlNEpJ`CKzEjVd^tT~`JQlO_UEzXKOWsoLh_phRl{TsyOi+smi_Pcmaai\\\\r]giveM_heEs}A~fCRjd_EAue\\\\WviMHi&email=zeeznfn%40jrth&city=VI&zip=57548&terms=checked',\n", " '/order?item=tshirts&name=N{CiIzVPusVZbhBMBgmJJuGz|a{LASwJoio]Cd{F}x^+}iVDDK{`oruK\\\\[jfSiKaE~+k`kZTjlFxUioOGsyKGFS][JpR}d|HszWF]MVTEblLBiLZE&email=kesqhzlvhlximqjbccgiyzncpxj%40nbw&city=UDTXRB&zip=33811&terms=off',\n", " '/order?item=tshirt&name=pgn{LAtPbybM^iKCsaqoyJTTlqgj|Nlj}JqBke+gH\\\\_wiCw`hbifqv^kZIQQNnmB{}+Oy~mASjADyscGkHRIjeHCyOqJWzduuUY^cvjxloyEzLAjjB|^&email=mgbzugwtrrfhxxzmrho%40mgrw&city=n\\\\fTDv&zip=77430&terms=checked',\n", " '/order?item=lockseR&name=CtZ\\\\nmdILfq+Mr\\\\MT|TWgU]nlm`CsH|plOiQlqep+Nx|X`ATl&email=ynddkdata%40iofw&city=gRSFaG&zip=20425&terms=checked',\n", " '/order?item=drills&name=WCeAK[dalkWlb|o+~^gyG|bPob^^CyD{uhfGXhKGuBDFFNO+wiTjUweb}SpWlqPCcqFZcw`WapU&email=xpxc%40xgr&city=|kX}YdbS&zip=2115&terms=on',\n", " '/order?item=Tshirt&name=pH^O_JkIXXiGfM{f}w+`E`GRZkSj`pLs}CJ+wc}SxgcjVULzn{\\\\KoYsa}PVYWosNtl[_bDjUBIM&email=gvqsbvybsqvyyqeymaayhygeey%40mm&city=wvX`ejL&zip=1737&terms=on',\n", " '/order?item=drill&name=t{FYfvEISENrA{oX`SuL}zRuk+VVPAp\\\\kI]~VV`|FGv+XxwrB^CPrmA&email=qqabjqecyyrebipafywb%40sl&city=AM^[&zip=3572&terms=checked']\n", "\n", "easy_population_2 = ['/order?item=tshirts&name=jyqSzuLrz]iNPnPnabk{tDl|UHrYyyYsW~O[}npUbR+AP|yOVW|a}wWVlWBUVB{jgZZ[z`Q+agpxKdcHUhhR|z}mhSLubCP&email=mgfzfcbswarlq%40pnnb&city=kJ&zip=81082&terms=checked',\n", " '/order?item=tshirts&name=upcsILr~Q~OswbduJDNHVqEj\\\\[pFad|xbgrh{yiZ[O~K^ZB+jk~eiQ~lvnr_lOPn+GqVJmLEQtavXM`rmXhbEsOvC[b|[LXRDr`ZvqVI&email=jszvmovdeszjixxrqkgvl%40yz&city=lXqDREY&zip=38824&terms=undefined',\n", " '/order?item=tshirts&name=iV_[ub|^gT^Eb+x]dQ~zgyHo|[|RHtO[d+RngZ}CY{QzBghqMtIq\\\\e\\\\kyCqPMqfS_Uhs[t&email=ckgowplsmqxizngylvlozlpwajbb%40zievm&city=rSZkK&zip=7841&terms=off',\n", " '/order?item=Drill&name=^yPjoCqJaotBNh_zdKeXbry`Tj{_uV[sTa}a+`oornirHtmvZR[rQ{v[kWzR_yWLXmnFMuamkWSKljuZZr+|DK]C|YTXiSsLyigbNnPkWC}pJd}~TBh}erh&email=ogbnfdbdziafbaszhktnam%40mozw&city=KGklxeWR&zip=1860&terms=on',\n", " '/order?item=lockseR&name=}yrZkmLMeNLq`tv\\\\NAE|+\\\\EvE`LvTIwljOaw^FE{LTH]HtSP]aswb[Vtf\\\\yUGErO|WrE+sxuTSqt_Dqk`h}dptYBWQNMC~gpS^JH~rXTtMbUqmlkfwQg&email=bfmiirhnfexlo%40da&city=hWymOn_uV&zip=70770&terms=undefined',\n", " '/order?item=lockSet&name=QuhI~Q\\\\QKx_rrPuihA|BGyFaTr+XfGsd]K`I{ChyD~he+B~kW~psGF|uBfj|_MQGBxp_QOA|c&email=jskkldilypp%40ksgkt&city=IsxJ&zip=4120&terms=undefined',\n", " '/order?item=Tshirt&name=aoyTkw|Djhj{wC+uBxmQEP`C~\\\\n`cxgTj~ZNURdQc\\\\EbHlhgoxAswBifEJ+DYsuhk]SFz|ZcarS[IwuJKkgu\\\\fxU~_ZcSjpDSW[&email=aaziuncgowqzms%40my&city=UjtbtZJno&zip=12448&terms=off',\n", " '/order?item=lockset&name=GRceQw+u^jsV]vezGy{hSk`gZnMPKlzOQHG{SGOaJ+`~ddDKxYIeUEyVWURdYVtonkQSrbLZi&email=myryaifhoguezpaaeifjqbqxadso%40jinx&city=vGK&zip=4143&terms=off',\n", " '/order?item=drill&name=bytJ`NvVPjxXMB_bxF`CmvzxotHdIFWJr+}vGZU^lkmQxfyYZz+U`Rdvgxe\\\\IPyEkgFYXnvmnoYC|_Bc}xkhMFxn}I}~dJhte&email=icwld%40nzjr&city=P\\\\FpLwjU&zip=7036&terms=undefined',\n", " '/order?item=tshirts&name=JsIvB{pT\\\\LhHyI`F_kpfFoeTwGjW^Ah|cHOgnENQKy{{tr+ZXezy^bL}zAlTb^VP}ppCGfAu_hONu^ekOwJDg\\\\SW`Br+{b[{mCCsNmnRlP~k[B[sMX^DLbE^[aikyRi[kBZFSrorPcR]&email=hdnsshlkjpxkptyurtd%40lncyj&city=u^P&zip=1462&terms=off']\n", "\n", "easy_population_3 = ['/order?item=lockset&name=jeBAuzgCQBCPOKkBNKO[pSGBSdlxp\\\\tIW]+{nL]aX\\\\x`zJiVdsTAkcEeCO]EmTonmnmJL{+VsSDk^nW]Oj~ct|[JfmEvzoI^S&email=gzlijnpirchhavgufpkkb%40olprc&city=w\\\\y&zip=1532&terms=undefined',\n", " '/order?item=tshirt&name=[UOdGfc~COPBKNl`grGIPX^fIYJu+Hr\\\\j]bVFLLj\\\\|_gPbaqa[Btgx~MR\\\\~SHMc+ZJl{E`Yzqd{jdHJN|]NNcmryGT{\\\\PhE[RRjNeXM&email=rifdnmmayojpixjswyzeoncw%40sama&city=QR&zip=3431&terms=on',\n", " '/order?item=lockset&name=wIu}Dq+Pyhb]SvOohQZvRbtwp~~xtb]QLkbd`TxACuVRt+nRxYDJzVUosE{H{WKzsvJ&email=dbpnnhe%40zj&city=as&zip=3277&terms=on',\n", " '/order?item=drill&name=LKCODOKtdum+gm~gQKH}m_vay}wt^COcoD~z|ZhPT~Q`+Pdqffn}z|MZujYneIiWoPtNAPNFScrlIJ|emSR}{g&email=dhqouyp%40vmiy&city=EvuI^R&zip=2174&terms=checked',\n", " '/order?item=tshirts&name=Lg\\\\zSvsyKs{K\\\\~THi{Av~wWW{kzkgfZzvCft_dsxJ+D{Xzb}ZZh^wrMNzKTZHY\\\\uM[gL~ccPnvFL^zL+RrJ`E~Xd_b]M`NFgP&email=xzkmrojdcgvfmqfruzfrhqwqm%40jn&city=H}Rb&zip=6874&terms=on',\n", " '/order?item=lockset&name=kANS]xfFAIyY+ll|EE]WE+tZxDK~oQ[kWCo~fFQD{&email=wrcsyvqywvfcvzmkfeorxdieknlv%40gwog&city=Q~x&zip=26836&terms=checked',\n", " '/order?item=lockseR&name=zSC~K+OFQHFOaoE\\\\}gtHJbYBiLjLxYQoLd_X|BhQ+sI\\\\\\\\^\\\\Wt\\\\IUnicyJChzVoDF|VfnygrGMGITyvd&email=rxmbjfcaymadv%40wfv&city=ADWvzJ|f&zip=4256&terms=undefined',\n", " '/order?item=lockset&name=q`Zeffjyo{yWnSUvr|vr~WDktnK~Yj\\\\teW+slbPLe`rHxbdTMlCeM`^ZSIx}mSdaM]PSYcxeIUwiB+Xk]`dyLXA_zf~}itaBQvPd|PHwGe~&email=bwvguxlgquqkyjsljtbckgczkxvq%40exsum&city=jc`ggDch`&zip=8216&terms=on',\n", " '/order?item=drill&name=TMHOIiC^SPdB|UWDJN|a[ErV_zKR+}FPq]F{h``ok`w^RkvYyKMdbQnUJ\\\\QRkSmHd]}VW|+Cef[miTOYE&email=webzcfhbayiqslodbfshnbtcnqkut%40wnkt&city=]~|dauE&zip=6442&terms=undefined',\n", " '/order?item=drills&name=kMaiRRVXsaXBbKOuDmI+Zy]ue_SxnTNcgievkK_+Oono|uR]Kvax{MLvMbjJyaE`l_XnjFvMIS&email=oijzvennraqwzayfvzkqxbcbz%40wc&city=pFER`e|h&zip=16668&terms=on']\n", "\n", "easy_population_4 = ['/order?item=Tshirt&name=vNUwFBAoyAT+oZ_sm~N_E\\\\V[qeM`TDiGbhS`QgZYhvZVow+zgiR[BJMESzT_Q_W`tOLFoSdP|ggyouSzUGrOnvVaswceS&email=ewgwntvibdrztrdwmuthfsp%40zv&city=nBPxcVf\\\\&zip=20734&terms=on',\n", " '/order?item=tshirts&name=MwljgKvHGWLa|jt~K_+kn^fCwDhfoqcSa\\\\}WsBm|hmkoOwDJF}K\\\\T\\\\h^nU+RVcqfEHeQCMEf}ZGn{gcjxNX|vI|}SU&email=migbpfryy%40yiqzk&city=fl&zip=55703&terms=off',\n", " '/order?item=tshirt&name=M^PPvbjohBmY~lP{aXk]Hi+}efWl_UTFw[rH[Hco_qLW{+K^K}_gf[MEw^iprEyUAj_NnzcE}pr{hgeRzXyJ&email=ayscfyqtmkefnjrxrgr%40qp&city=vvGjZJ&zip=1133&terms=checked',\n", " '/order?item=drills&name=`qPZcXZcy_bPShz`|qoRGez_wkJmaApX~wwzpi[]]+NQ[ANDZA\\\\cBvAfVJ}y^UTXYmo^sf|SoKUPPv]`i+jtvTptCaFbSM`S&email=wuvqyclw%40vtflj&city=]Gs{eG&zip=6628&terms=off',\n", " '/order?item=lockset&name=ZGlUzW}Huwdpsu`JoFhmo~GKic]jpEOG~+BvDVsxZLA^tvJoxphFM+ueToMlNh&email=nfxm%40ot&city=DjCfLp&zip=4132&terms=checked',\n", " '/order?item=drill&name=uD][V+ADSY_bFc[wG^We+]qc`AakXb{aPdc}YjHuKbJ|^ctcfdsq^eOuz^DyBzjo&email=ppbmnnq%40jhdkw&city=TKXy|vJT_&zip=87376&terms=on',\n", " '/order?item=lockSet&name=DOMvOOQVKxLSbQ^AxOXJXrpjUgiym+BWVwgYzAOgsDTIOwS|SPbgQrICM~soqJCeOzdDI\\\\h+SgPZkLp]^q__VNMNI]~uVQqV^z&email=cbvduqcgsyq%40zj&city=Zk}~zA&zip=77175&terms=undefined',\n", " '/order?item=tshirts&name=vqPA_gOwWU`jAHi{JWwD[gX|m}[H+ogrJAbsTAp~~g_ZcqLfZKhyIqdUFfFmzPebwHfAoJ|iZNNM+IKTVzwW^oNq~VOfgpOULUEzobC|&email=hcvb%40vjc&city=Ru&zip=23406&terms=on',\n", " '/order?item=tshirts&name=ojbDYmz]eNe\\\\nAIwllU{F]fZSRM^MExQgZQtTOy_DEJbcSDn+^J]A\\\\^Ry`S^gnWK`trokGKExBBupZtzGNmBPIn_KwC+zx_bz&email=baaq%40dy&city=uJ&zip=0534&terms=undefined',\n", " '/order?item=tshirts&name=]VYBcvLR`ts[iaM{y[R]Z[ZtPnaKufwkSeg+heGEcfP+wtZLWLU&email=zsrzop%40ap&city=XsUrWw&zip=3624&terms=checked']\n", "\n", "easy_population_5 = ['/order?item=drill&name=FQdnpJbweAtSsGSPYZayD]JNVvKl[vQpfHwTGeOW}~tH+G|hAeTX~lj\\\\`ttVlt[[qOm]BDRrzBjBkEfmsOSThaAM+FinRR]UaYhY|qzGgqGSIcfzJnEl}[HL{JHbK&email=nyffowiojoc%40rta&city=|VlMDI&zip=87744&terms=on',\n", " '/order?item=tshirts&name=Vt}lTM~TTWoiDa`XRDqgmOmzWbSYq{t{Sy+V_sswVHhsS+NmiJnKekBdIG[kk}BR_PPgZ&email=pfdi%40euthk&city=bi&zip=7710&terms=on',\n", " '/order?item=drill&name=nBblOQGqSEN\\\\VRdF|+w_vAHOrp+_VKMfP&email=jmpbbbejepvzwpsthrgieo%40vambs&city=P|uFjK^&zip=0563&terms=on',\n", " '/order?item=tshirts&name=hJe]u[NHvyMeH^[+eRvR`b{j_yKmWJun{BFpxy\\\\EQctgl{maLorCEGoE+GSrzJVvNTxm}[~OnoBez&email=nzmijelcdfxbemdnhqnpcyoqb%40oeql&city=wEuJXO}^E&zip=3610&terms=checked',\n", " '/order?item=lockSet&name=aJYAEtOfkrI[DKFcY^+BU_bGmOMPZkJf_hHLsjs+lwJ}up\\\\&email=mbwelwhftruh%40pt&city=f\\\\RAYzhnT&zip=5046&terms=undefined',\n", " '/?item=lockset&name=BLr|kgu[euunEoovRm^i_n&email=U^Oe&city=_p_U`Vw`F{k`OozIw[wRe&zip=IPvAQ&terms=Y[S',\n", " '/?item=drills&name=Yz`bKiAgsUBinT`eE\\\\~ug\\\\~thWB{ECEZfy{znh`{heQ&email=YkTvUeLiHbOvBsgwNlEf[qXw&city=xAmbhYD^i}]HgAskVoX~|&zip=xw4HE&terms=}H_',\n", " '/order?item=tshirrts&name=fbP{wjcJdY}_{zTziLnfLGnnXH]_h&email=|LlGcV_gTOfzw&city=OgtmYN[BKEB_tPWZhvK&zip=L92eb&terms=~__',\n", " '/?item=lockset&name=[F}YCSsksjLOAOGk|hyXk~C[{dB]z&email=ZRpwPe[L`nlgq_g}Q&city=i]]MKVVkdTc~TQPTjayWmyR&zip=Nom6P&terms=mbaGe',\n", " '/order?item=drills&name=XEpTafkfXmw}njN\\\\MPsIoeYMXRPxD`LvOYQogWlJvWB&email=vqaIy{\\\\DoL|HP|ZUTKxBEvjThTKFw&city=nn|SywGDWMcuopb&zip=XAFB1&terms=_{Q']\n", "\n", "\n", "\n", "\n", "medium_population_1 = ['/order?item=lickseR&name=Nv]^VUHB`]WjPO{SAN|k[gYOcaP]Bt}S|}{NHgHez&email=|dULjBHA]jiiu[`QjUo&city={a^}Ral|qA&zip=Gx6tF&terms=ezB]',\n", " '/order?item=lickseR&name=UJBZFlPeCJTcYctzq}{^mP_\\\\zUsxcoSRszJrzSpw\\\\&email=_f]WnKsnB&city=AslSw|&zip=tXE8W&terms=t}]CQ',\n", " '/order?item=lockset&name=T]eedREnfN]ju~MzGLplUfptr|NvqJW`E~VL~gwXTlk}fcb^v&email=ueejOE]x~bBhgu[sVuL|mCR_mpLdw&city=Nmx&zip=1azve&terms=`FmX',\n", " '/order?item=P0ckSet&name=HehiRcff[HBpHMU^h}\\\\uZmDWuvwXYEEJvklCr|dCy_qkAm&email=^WfO_s]RMkNOXnSEM~&city=TzLYRJO\\\\}S^Ny&zip=l9xGt&terms=iVF',\n", " '/order?item=tshirt&name=kCeS~KROqPOBjHa&email=BUjQXOto&city=gKgL\\\\[IQ&zip=uBal1&terms=d^k',\n", " '/order?item=_uafJe&name=跳\\uf2f9콹⏽뢂\\uf376潄\\ue843휞蚱㖰갏冡줳啬܂髯魜&email=庆헑ꠘ뮱炕뭓ᛑꔀ♖㷌氲ˉ澘릟\\u082e㠊䡡缲ᥔ釺&city=KX|{Lh&zip=exkh3G9q&terms=FRl',\n", " '/order?item=WAsyfae\\\\&name=禃摪\\ue25c\\uefc4㶂閴㹪ᐤ嶂乴鲟暛\\uda85㏴\\uf063螤韼&email=鄻ꍥ콸ﳂγ뮻혷☂&city=sEkgFIXt{aLdmP[GwFd&zip=lJ8MDpln&terms=p\\\\HzT',\n", " '/order?item=FaDKt|KVb&name=勇觾\\uf1e1㈭揧\\uec9cƟ䑼ꄆ\\u0a3bꓺ簀鑖\\ufbcd띾㢑鮇Ꞡ㾘℣娃ㅟ缛鶃ᎈᅪ⋃鰅踱\\ud98f⋎迩\\uf4ee색Ᏹិ텶\\ue049≺哝&email=궉Ⱆ赯ꊔ娴㉁礞甚吵ᝀႨ\\udcb1㬅䫒첼֞\\u1759啤≌ជꓰ&city=zX~b~ZY`_G{&zip=O41ZXboQ&terms=Z}Z',\n", " '/order?item=dV{]_oF&name=㑶䨒큼ꆱ흯\\u1b7f\\udf59\\ue501\\ue299䟸㥆г✍述鈯糥䑹㹆ന\\udc5c䚉幹咀貓쏒뇈d鴊닭啡䓋ᒓ鯀汹粡થ◪沯\\uf20a夣궯噌鋔遱셒咲&email=렐\\uf544姑꺏\\ue465삈젾淘汩ば&city=pNhs&zip=w52yAb8J&terms=PYv',\n", " '/order?item=Z`t&name=汱ꚼ\\udf98➤\\uf73d\\udf4c涏慜\\ud818&email=ꮀ칎抪ꨈ汿庡단ḱ\\udf58鎏X\\udb88涊ᬌ蠎\\uf74e钰嵲&city=uYRsU{s_YpTfuikm&zip=4ct0XYyx&terms=fdmc']\n", "\n", "medium_population_2 = ['/order?item=tshirt&name=aB_WY]RyymZEXsCskHnDlWpQxqk&email=HDEH|fW~cud&city=vavAa}x[&zip=tP4Zi&terms=FSBIU',\n", " '/order?item=P0ckSet&name={Xkhgy|rfYp&email=zS[JlgUNq~Gk&city=p&zip=wBDpn&terms=nATbo',\n", " '/order?item=dr5ill&name=CgrmENev}O&email=NUvw|TEwEipTQUbSIQobidUPMj&city=NIuh{sK|tH&zip=txbEI&terms=The^',\n", " '/order?item=Tshirt&name=SkyHWqVQTxxQ[OFeP_ELyjf&email=L\\\\Jz{Nyrik&city=sCyw&zip=QyN3S&terms={{UR|',\n", " '/order?item=lockSet&name=ru~B_iUjL_`aUbW^Jm]bms&email=Rb]veODjSKdTV}W_Xf&city=UG`OUDUPywD^OIxILti~`Lq&zip=Ywpiu&terms=}Qso',\n", " '/order?item=mjWaUej&name=㇍쀳尴쵓\\udda2䯆ᬶ韸∝陂\\udc01鼂㡖㗉毟ꋓ꙾\\uf0c4䴈읶숤\\uf1c8&email=\\ue7cf\\uda22ⴘ煾ၯ쾉&city=_\\\\JK`EPzz[ICpQhEtZcNYF&zip=GVRVYQm7&terms=rh^Z',\n", " '/order?item=CSKv&name=\\uf763㕍\\ude11ச捺䩜嵨⻇\\ud895\\uf5c8롶䰧ﹽ츱䚫쩄讍ᔰ\\ueef3\\uea8e饟\\udef7\\uf2ad鞣⪤밯姸&email=揸鮟銁쿱碅ᢉ묺냸ꎏ쳀胜灼膅뢝ȝ읺\\u1ada㊏鹹ꈾ騪ᅫ쯏㟫㥒ੌ墑垊메&city=tjQdDYp_qO^kOM&zip=UgDfW6u0&terms=jQt',\n", " '/order?item=E\\\\xKsWCS&name=ᯝ錫烘쯖钷캃\\ud987\\uda0d誧徫ﯯ墪ᔑ淂抇섴﮵垷Ϊ껞敫䖦䣣燬굌佖\\udbc1㎈쾂﮵骠䗌\\uf440禭\\ue085疻ꩈ鍫웝鯽\\ud94a摘\\ue070&email=ﳝ帼斦ᑳ朚˄漟⑿⋩\\ufb1b矷&city=gAX}sVsxnYB\\\\LQsE~TP&zip=reiWkahv&terms=ERns',\n", " '/order?item=qtV&name=\\ue3c6沏莄犢倕侐ퟏ㶣ຂᣄ嗺툩꽚㨹ۮ\\uf42e뵻\\uda62\\ue71e줖&email=籟쐖鷋崹줿墢罔쉈팑퇨垬塀曖Ⲅ䘅뒧끘\\udf0cថ䖘ᑑ&city=osQjg]jk[yU&zip=pIKp7EjL&terms=PfP|',\n", " '/order?item=NGIMl~sT_&name=嵠㹑Ά䥢ᴢ茥抭썡叜\\ue781\\ud863캿紑냎컪㔾죫戨⢻㖻Ⲓ倳牢ﰰ⡒\\uf579Ⴉ桺\\udc65狭ᧁ갖渜ᮋ囓ꜭ\\ue0ce緄﴾璈艷\\uebd1浄昳퀴䨀⟹&email=ꃾ갾뫉斿\\uf857몵\\ue34b\\ued0d㾳撦堖\\ude85㈳\\u173c怏&city=~pBZRtWQvLKChMuxAa&zip=VwhpHD0G&terms=KwoH']\n", "\n", "medium_population_3 = ['/order?item=7rill&name=oG[[L&email=WZHJRJMM\\\\eZ|xOdmm&city=IKYBeKcFxjbjWO^t\\\\kxQHz&zip=OEoHC&terms=LDu',\n", " '/order?item=lickseR&name=fy`\\\\WZobiN~gEvl{U&email=OGzRU|wAvs]FG[Ee}LxmwWHj`C\\\\&city=oEEjA^OflQxos&zip=zcaur&terms=KNJb',\n", " '/order?item=lickseR&name=HXKl`yh&email=l]{H_A|jXVzJ|up]&city=V|IVmZ}cFi&zip=vbRQy&terms=JRuhM',\n", " '/order?item=lockseR&name=tir[f`hrfhNIre&email=]pdzL^yPYVSxJNcg}V&city=xZAf{JmF~[kRJYvlRH&zip=IkRvF&terms=[xaa',\n", " '/order?item=PLockset&name=^T`AymfTR&email=fQ`COORt_ua^&city=dNRzl\\\\gnZFD&zip=zHuhB&terms=V~q`',\n", " '/order?item=SFU&name=呯९엯뢡뽡Ǚ鼉&email=윴\\ua7c7뮫뽆ᦒ剆팞障︥ᓧ㖬\\u0ff6W깈Ը\\u1758촌⡳튽퀱\\ued74㎳吥⳿ᭈ\\u0ea0\\uf09f&city=Vc_Z{\\\\DWvv`z&zip=6s1nQlbE&terms=oKFPu',\n", " '/order?item=JNNCbu_&name=箒ᔮ콩\\ue2f7鳧\\uf393띻\\u0ef0茵繬혏\\ue07f羭囝偠䄆吜럎近&email=ᢊ⍉戽㌸勶㶧봹䌹쐇ꋲ\\ueb43阉蒧硴\\uf2d7샫쪿Ɦ鐘巫㉁\\uec60뇨獪獯₤맲猝&city=jKliVjtAzl\\\\^K^wITrbqQ&zip=uRHWxacu&terms=aKq',\n", " '/order?item=u`[Iq\\\\yL&name=\\uf07b얢\\uf80f\\uee8a\\uf6e8\\uda99ꦨ\\uf5c6熓\\uf536㟂䜧筒㢙&email=ޔ쟞賤懯쏜萏コ\\ue09eꃊ鉩ⅅ싉䥇\\u2cf8\\uf83e䁱ẛ螰ӹ柘\\udda7&city=jbuijouf`eXdt|eiRDiuCARf&zip=7x9gnnq5&terms=C~J',\n", " '/order?item=OiJvac]{z&name=슋ᖧ㹕藶̀⠨狈&email=뚰\\ua7d3䞻瞹㹊闋잩&city=GTZwC|\\\\&zip=wnD2RnoB&terms=vdoX',\n", " '/order?item=^JBTNtap&name=♏\\ue9a0\\ue87e혯囐꺂罱娞鿕\\uf734箁컓❑釚罂跣Ԥ⑺黋涸睵̉匌脌詣컳퀧㒋؆᷄ͭ䁳愹큯쁪㼗ၽ&email=ന垁販\\uec99\\udc2d౩淝៝⊾圑頣쟈(弾뺣st\\ue998汣\\udd45輔ይꖒ&city=MaZhkR[QR_&zip=YDNXbBTW&terms=I^YYG']\n", "\n", "medium_population_4 = ['/order?item=Drill&name=ZCmOvTtitkkEac]Ro[Fnu|qqYDcznL&email=Lt]Z{^OjQinuXxU^lMAU[&city=qDuMpz_TlzkZqfEZ&zip=ytz6q&terms=|YVw',\n", " '/?item=Drill&name=MbClV|ctOCq&email=k`mY_}&city=yOoX^rz`GUxSjufolrOVbm&zip=SVqIy&terms=YtL',\n", " '/?item=dr5ill&name=srWhCPAWQPR[LbssRFRBlRtIeoKo&email=|NC^CG]QJY[fsWPfh`\\\\BxGIcv&city=RMXCru&zip=wBYrK&terms=Jnq]Z',\n", " '/?item=lockset&name=JeYTjG`XWXLPwTWJdcIHLdRun`ToNAiT`YIGZa`zNqXjR&email=bwUxAHfuTq`bmh&city=grQMZOjadHV}oZj&zip=yG56x&terms=RJ^z',\n", " '/?item=drills&name=]VYnf&email=pAoQRjgX{uaoyHJyTESrhQ`&city=OsW\\\\FeDtWz`uJVqLJ&zip=zIn13&terms=gMLO',\n", " '/order?item=tvLnc&name=㑬荦돡\\uda99굍鯲↫뙫훓곈䥤귷䎻楣է堳䑽릤샑㈇\\ue755\\uf093둞\\uf268⎳콡\\ude68᮰鶾씉\\ud976\\udd12쐡Ḙ俆\\ue7b4迖&email=ꌙㆍ亮ᙸ\\ue4cb\\uf258\\uefc3駅&city=}z]HKR&zip=b7jD5nTw&terms=^ugNO',\n", " '/order?item={Hxp&name=缱⃜魵\\uf731졃翳Ꙃ靖雀袂贮켂\\uef02\\udaa0䎓㙓䞩ꃳ糹緕鼖\\ue887쪸納훴싙␥찲䘹奞糽ⱆ薃䉘䚡&email=㖝퍺忡씤겈寕\\u9ff6礸ꨔ덬힏&city=FqMH&zip=W17uf7PH&terms=cex',\n", " '/order?item=S^uvYog&name=闋臎\\ude91箷ꉲ폎㕞㙪\\uf5b6㯣ኢᤕ붿켐ꏨ\\uf869㶤㠴爔㍕\\ufd47瘸ᐻ佑褠宽\\ue77d稦倍ꕢ㲠\\ude2b侠\\uf73f䆰峃⦕ꔂ䵪滼ァ炵㕜빥&email=鷞Ⰱ癁灗᮪놆칈&city=RArKQALEiq}VXkhJqU}nFN&zip=y9PjT06R&terms=pjXX',\n", " '/order?item=Nuo&name=ζ뎹灒㷄樔\\ue4a2탚樓⠺뽞\\udefc橉⮑श쾠ऐ\\uefc9⩈䂧\\ud823衐稏ꋽ콒昿\\uf223䃛宬죴\\ue142褅Ỽ둥䦞㐱桹嗖켰䡚鄞爯迯榁ﳅ茛蜮&email=尉窋᠓놌ൿ㢱㡙놃퐻퍱\\udbed\\uf617ꇬ둎⽴ꖿᎯ\\ue892鯉㰜遭\\udb4a迏䥐璋ゆ쀡汒䑘&city=~C&zip=uQ8GPioq&terms=VvBfQ',\n", " '/order?item=Bmfe}eEu&name=쎆㹽ሱ寿ꪢ➻쯧撀미㇁㹿&email=籙ꝙ\\u1942飿냔죵ڗ\\uf105횷趹濍杳㤔葘֗鍰\\uee9b\\ue590&city=hPkI&zip=GJrqmVxx&terms=jR]S']\n", "\n", "medium_population_5 = ['Qgn&email=~ZiPMHb[GEz|Ni}NoUXvvuA&city=aRl&zip=BV8lA&terms=cqMI',\n", " '/order?item=Drill&name=MMeYHk\\\\FFbMSdtndL&email=wgjkeU_SttXWn]ljX&city=BJrKP`IR\\\\禭zip=ZXYrW&terms=m|r[',\n", " '/order?item=lickseR&name=bS_cgaPBg[q_t{mKj~\\\\Zp~F&email=vBnzh&city=TBFGhxJq]WYsPS&zip=W8GfM&terms=|hzpX',\n", " '/?item=lockset&name=}mp[OcP\\\\qbVJt~I~PRbbQqlv|K&email=sy}oq]aEd|}NukUB`IIg}XYn&city=|ir[^O&zip=JVjOG&terms=YlGd`',\n", " '/order?item=lickseR&name=|giDSaCk|sYmWSjHLjnRp&email=Dpro{okHqE|wFLU}geAmnP|sXi{&city={\\\\tooFFgaHMG&zip=cwwgL&terms=I_XZ',\n", " '/order?item=`oPG&name=\\uf0c7缧쑁祫궣ꈽ멟\\uf389杭Ↄ뀆㧤\\udf8b띜䔛&email=䠧오働ᡗ௴ꉱ&city=Rq_FcrLF}JcLcJsKpQST~a&zip=NLyhFZ6a&terms=_WkQ',\n", " '/order?item=wFZg^]d]z&name=힄邕\\ue6a0氿ᦉ汘ᅱ屮㒔啩檶\\uda18᷾谍瘂㰊&email=Ɫ췣摣恐ʺ犣\\udd96୰穟⿳褿먖苹̃罷\\uf526勲앯\\uf04eꌶ驞뙣ੰᶤ⡜&city=JF_AOudckPxTLiKPintEdMfU&zip=Oc0lXCcV&terms=DAwvT',\n", " '/order?item=RKccDK&name=嫲瘪貼햾趒䩴뼍恔ɠꇐ\\u2d2a⃐䷭担⼬촎瑿∢꿹䃡簈荋㺄࠙˝\\uefc1뤏&email=\\uebac鰃썿걤髼Ⴭ\\u1755펬ô\\u1c9d랅㵱䰵恾㏺疬붵\\x9b\\udb2a䣧鐀端䱥\\ue943᳖&city=YvbnadWX_&zip=inXdnuTv&terms=w]bB[',\n", " '/order?item=gORg&name=朘뫫ꔻ˵\\u2065떥K싫ɸ蕪⮱讘⏗厀狼胮⣗錣&email=ԃ䪂㻭Ģ篠\\ue0bcᷪ\\u0b34\\ud946맻鐤鎖켱緽秇좉\\ufddb\\ue1bc鬕\\ue557⺖뢛蔊㱖齲愪&city=DCofKvy\\\\IxTqoyN[[C]sjB&zip=q7tfVgik&terms=Qo[',\n", " '/order?item=XM_Q_N&name=혞骵▇ᅇ≛ᮝᬔ\\ue4cc&email=\\uf30dㅥ鶙뜸\\ud9e3\\ue5a1舘\\u0dcc纤㹠\\u200f&city=XPUkQAEnq&zip=buHfdaON&terms=nQ|d']\n", "\n", "\n", "hard_population_1 = ['/order?item=t[PHhU&name=퉒忳\\uf163ꕆপǬ懰鱯ῳ㼩閗♫\\ue655靰\\ueb12荦痿ⱨ䁥蠎쑿䬭㉍휥视麍봘ꡦ&email=鮉딫䳶䳟َ䡠㵶痏諭⛁ﱱᠲ上遶㣜&city=AGido|kXenKaWhrri|~EI^&zip=BCBTtm2V&terms=ZLL\\\\N',\n", " '/order?item=rCVk]jFH&name=銽畹\\ue84c♖㒂\\uf4d3健ᰱ\\uebf5쀥\\uee18\\ue571ؖ諹ꦏ흇൨\\ue84a玞縆䚃שּׂ\\ue1d8락곝ڗ㗉羗ො쮟\\udf8fᇂ땈\\ue754稛⊂&email=⺺ᶇ鞺㑸㏋\\uedc6辂螰\\ue065볱㟢Ⲁ\\uefcb蛘⟭Ⱡ\\uea8f竚ୣᦈ艒⦊&city=bskbcN&zip=Tl7f5FOy&terms=KqKw',\n", " '/order?item=]lh`ht|jD&name=槶뵎\\uf58c눉\\uf634\\ue384\\uf669﹤\\ue7e4껝榏䏿\\uf35f엒ꯐ槨㐁ᬅ뒃༞䦚㔯뼌鄁蝜퓙&email=釟̀꺀佳ꛜꋀ䪢\\ue4a8䫠૬稜櫳⠡\\ue053㠗ᢥ褺&city=BvjGLXk&zip=5v3x6H15&terms=vn_e',\n", " '/order?item=`{UqMpPm{&name=㦶䓏ᬔ䌰ꕺ蒝䋱띫༩邧\\ue8d8Ḉ慷右ઙ㝵炱痯곆㾙奞邁槾ᕚ嚺秙ዔ泫찛ﺺ䈯瑎▼㎢鳮&email=痺\\udb4f헞ᐆ舊\\uef20䰃졹놟\\uebe5沈\\uef44䈖储◍归繌Ꞝ攭ꋳ儡橴\\ud914㒒웪玾벩긦&city=oWBze[qrXK~|G&zip=cL26Iq0S&terms=BnM',\n", " '/order?item=eTCCj`XiO&name=\\uf381䜜ᄊ\\ue8b5섕䄲䷲灗䰉聪䧢戤\\uea30繅ꠞ\\ue53dༀ雅\\uaa4e材뵇㍥\\uf58f\\ue9e2颯ꍻ\\ua6f9殄禭厨\\ue634嬥标ṥ幍訹ꖠ\\u0db2ꃄொላ뷅\\ue18dპⳡ&email=ꅛ쓯묷喥葇蜿뱼앪ື堅ᘎ⒊&city=snz~XvtVe^HVymPhBx&zip=iZjtUVxy&terms={zrW',\n", " '/order?item=\\u0d11\\u05fb&name=ꩌ吀ࡍ麯ေ\\uf0e4ƶᑞ\\ue1b8&email=垗㐸\\u9ff1\\ufddb㻤&city=끱勀鱖俢ꓖ\\u07b2⊑&zip=8VcSQ>TUw]&terms=㏄\\uf2fd',\n", " '/order?item=棔㱘ⱨ&name=๎坢⼫៴焍⭃졫\\ua4ce渆\\ue4aa\\ud971鳝闇饗詩ܯ꿕梥\\ue1cd꼪\\ue120\\ue502櫓퇐ﶢꆐ㣺\\ud9e8\\udb52낟솆됻Ċ䐻ꤵ鐵胄㡿ນ鄘ᅺ\\uf7f6휎햘턍॰칟፞㕹&email=ꢾ창\\x1bⰨ쏣噜⣇\\uf2c0蟯⒭욆냠ㄜ䪱᠇꒧̺⣌\\ud803ᐳ畆ꪹ臸밐磀Ɦ瓃&city=䱙墨ሜ뀸権渧瓫웏㫿ਫ਼&zip=s4sEc@h{\\\\0&terms=㌟',\n", " '/order?item=粃䐁&name=ꆈ띣駣\\uee82儰ᛧ肣\\ue6abꢅ⁶匍然Ꚙ瓫屼⎋ᎆ겟䇯▭ꕜ輻ᴄ\\ueac6ㆱᔳ葙J戗輠፯\\u0ae4衙얭歼\\ue714쎮껦\\uec0e\\uea74&email=\\uda48\\ufadc釥뼫鵝ꖽ\\ud91b⻦\\u1fd5託㠎鬰\\u0e98㝞蘲&city=쓞♊℻锐佲&zip=u_}tqHc7R(&terms=\\uebb2猬\\ue545',\n", " '/order?item=藿褚\\ude99\\ude840ᛎ仸겔&name=\\ud86b㷐Ģ‱礡탱\\udc4e伫\\uea92Ⳡ繗䥏ꎫ柆ჾつ雁弮篊&email=鍀⺼逕䉳绪뤿\\ue2c0虥洘觅賚㝤LJ࡙н县졩\\ue07bප硢橼迼专寵稳ᓸ鷤儍\\uf593&city=ݵ講蜈㴌\\ue745\\uee91\\uf7d1&zip=L>bbG2r9w5&terms=\\uaac6턧동',\n", " '/order?item=\\uf0af뒈&name=껪\\uf04d坡㐫⒤䮀ԡ曯r贶\\uf02c嚔㌞壠ᮁ같屧俪殭䜊韜\\udf41尪嗽&email=\\uf5d6鲌☬\\uf25d꣘翄\\ue9b8ﯽծ建\\ueac7紙埣빟꿎\\x8b\\uaac8ࠜ㝥蹞夳漢\\udd23&city=剓\\uf170銑\\ueeb8⪥湅\\u2d71&zip=0]il?aL2KC&terms=읔㈤']\n", "\n", "hard_population_2 = ['/order?item=sDw[brJ~&name=⢦甏虾輔\\ua8cc鏷᥉㦐䷮䟦嵫뛤爕ꎑ㕘僸Ꙕ㩽᠄銿ﯻ쥜&email=䉷恴뺘㎪氼Ꙕ\\ue4cf쯖Ⓙ齌\\ue2b0\\u242b\\udafa̪䟗&city=GHa{HVmkFTEPUoSF&zip=rrhnx1hI&terms=cNGCQ',\n", " '/order?item=][wrIbW^&name=昆ꢁ麌\\u205f෫썼얳슢䔊&email=べ髗宊ཤኹ䢞꜑ፘ犫ﻄ氼หシ퓓㑝䬪\\u1ccf묖哾&city=`pUBH&zip=929mzmfM&terms=^}iea',\n", " '/order?item=^qXGVtWU&name=䬀諷\\uea31\\u0d3c;&email=ཉꔺ欽㎉迨㟻䮕ᤄ&city=XysF[&zip=pRY9DC7r&terms=Bjzdi',\n", " '/order?item=ELXcZPR&name=硗㍄狞歞롬\\uef9e๒ⲙᦛ쪓\\uf7e3ິో䲖绔샃젪ᖑ膡쟹\\uf585\\ue254⫕춦쮻瘭뷤\\u086d蚉叏땟\\ue0bb띴㓟娳≀\\ud85a덑緟\\uf4b2曆삷&email=鮧逾載䟨탪펪쭜棱䏬쉈腈༗⢶顼\\u1b7e楬ᤣ\\udbff\\ud9f0쥇Ἓ傀\\ue59e瑚鑣&city=WB}`jgtWqJG[nX&zip=S1HcPBho&terms=G`l~',\n", " '/order?item=vw`&name=袄ԉ딄੧␥\\ue192붥됸ﯤ쒹⑉滫\\ue62e⏑\\ue2f2\\udf59籱ﻙ芦&email=➒\\uf7c5糈ڱ麫⣓\\ue2f8꺥鬙\\uedfa毜핑៕\\ue0c0⊺ꢷ\\u1caa㴓ቶ㰸쩋홮埌Ɯ돺\\ud807&city=iQkCp}yXU|bjyYe~_S~Y&zip=7yvWCxyv&terms=BDk',\n", " '/order?item=ٯ綮眏餣雘ꢏ&name=㒆\\udcd4莤붪ஆ匛癫䃝\\uf221깬\\uf379\\u1878Ꞇ薆\\ufbc3萳㑬\\uf418嵚購\\ueadc菘梲䫺넫쯠忇력\\udcf9楣\\uf6beˮ쾡\\uf1be⤯곟n\\ud89d䣒&email=䟟檖\\u088cﴹ\\uec80\\uf340讪\\u088b䝰鸯䜏ꗟᦫ斸㥡㐵钒챩뚉聻\\uef3c狛鎋䳾╈얺證\\uf47f&city=၎\\uf3d7ઞ㱡걡\\ue750❞\\ue44b㻳쪂婔縓༶릍좐沜ṏ㾙&zip=)c#TSMsq=7&terms=',\n", " '/order?item=⊈\\uf0e1ꧢ煚攻쌻춊㹣ꯠ&name=䭹偽ԧ&email=浝ﺴ홭䢀ᩮ\\uf6bd桅\\uf3f4&city=\\ue8db\\ued3a\\ue921㫗懦춺鷳\\ue98d낢᙮蛗\\ue8c8\\udef8簕䵢\\ue107跖炒&zip=]Wn~XrrFp0&terms=뒱펡Ƙ묂',\n", " '/order?item=駠⿳袲&name=벟\\u2bd7潉隌\\ue0ae\\ueb17់凷橵ᵩ뛼뭛댴催\\ue452챡\\udef8짉\\ufbcc얨ⴸঢ䍮穚造\\uf441㦖륬ዯ䁏콲缐♶ꠓ㞤춶宎\\ue0a5錓訶螈&email=慥&city=䝕뮫丩\\udbc4凷✭讉ﷁ鎛꒶檕醟\\uddc0평柼䒾羱\\ue42b\\u1757&zip=}U5[l~gtD_&terms=㼿Ὡۄ⇀㾦',\n", " \"/order?item=❉\\ue7a6껈忛&name=郁齉\\uf678阣灤裑몂據櫂롪낗삭랅፼ⵤㅑឲ끽鶉㪰秌耙莜꛱䤀暾ໂ\\u1aeeﰡ䋉&email=뮜ᄽ뤨Ꙫ쿖硺\\ue5eb풠煬\\u19ac&city=뿛ﵕ\\uf239ᵝ\\uf181鋹\\uda99臸⠍ဩ\\u2435跄繦&zip=2'3nNDfsB(&terms=榓ﹶ豚콇႐\",\n", " '/order?item=⢈\\uf88e翹ꦓ겾燂鉐&name=\\uda33ﶁ\\ue313꾊ᨼ祗ᦪ좺\\ue9fc붥厑蠴䡙䆃闉⾯鷨횞蒫䜔繀궪幍툁ۭ\\uf008ᠲ\\ue546ᵭ싎&email=濩祹튨\\udd4c局촲ꐊ䶔旎ꄈ鱌ᦽ纘퓣녲얧ᅾ㭆磸썟咃㖙綪\\ue29a祇ꔖ攀託&city=紋䯕⢶&zip=h4nt!f)B~U&terms=\\ue7a4ۘ⥬\\uf80a\\ued73']\n", "\n", "hard_population_3 = ['/?item=VbqKp&name=ꕂ\\uf637悀\\uf0f5Ꮄ䅡⪅䘱ᬽࣖ⮬컚撒ﰥᙚ䰪꿽嵠⫼脔굥\\ue5f7\\ued71㎵ꤽ偢湲펍㋭侁ﱊ碾刜괤乪麦쑑ﮟꬨ뻜擺\\ued46&email=\\uf7ff㈏ꈸ妁\\udcb6뾘嗂ᢴథ⼚㨲\\uf051ᕃꇔ䰁\\uf4df\\uf428项緗\\uda27K쭚\\u10c6햚䅔짲&city=Oq^a]fq^fC_B~noNsLWDTG&zip=3zejH7DR&terms=SaSfs',\n", " '/order?ite',\n", " 'VTsPPK&terms=~Vv',\n", " '/?item=r`Y&name=稼㕑妑ⷮ㑫ᯱ徫貏뱓⍼᷻뜂湌䩙蜤ﵞ鬑殽떚\\udd47ꅌ褭뤓㈎■擈\\uf42b垍奎᪣霮葁邟\\uf870㴽ᱞ䞇ᙒ룵&email=ﻗʋ⸃畳齻ꢟ겪뱎䭀ꊯ͋⪼ꈺﯙ媒࿐\\uf7d5㿱陔崀抦ు枚絭⛻쉐㨫兙&city=qBWWy^&zip=2jZyOYHH&terms=OaG',\n", " '/?item=ffBUq&name=洸\\uef92騇ﲛ\\ue660鳥췙ὦፚ덵坑樀浽檪枧濹鿕✚쑲ꐷ⽫塵䚌콁\\uf493\\uedffⲊ鎁숲☠㉤孝㓦翆Ļ\\udb17헿\\uebcd켙踑鑪ﴣி\\uea06畨騺쨾⪅&email=ೲㆰᡎ⌘┏揳ê\\ue86aⴝ벞騎ⲹ⩍괜ᡄ骿郆䤪亀㣛뭾ʷꔿ\\ueb27眪\\ue5deȣ&city=D}z}Kd&zip=2ENrfDgK&terms=NWP',\n", " '/?item=葹&name=ຊ⃒肪矿䜔&email=&city=煪\\uecbeꌿ\\ue96c峃䀱챭佥뮨雝萢\\uf704&zip=F/u`?!LUFn&terms=㞑',\n", " '/?item=텊ᕘ諞펝懆&name=唗춙爩Ḻ⤔Ⱉ崓溳驞ﴸ⸎㭑숱ቱ쬜㔿\\uf068幖뷤\\ue2a1&email=\\ua7bcᖏ\\u1df7ꢜ煤ⶰ觧旭羯\\ue45f\\u2b97昩\\u2e62䉳\\ue141焏&city=\\udbc3⤅跈즹ꕳ&zip=2lY#yEq}&terms=',\n", " 'y=\\udb07椃煏茇ধ\\ue8f1\\ude23跤ᔥĭ網\\ud95d₥裖㐊畣싲珆&zip={AnE/0D_*S&terms=',\n", " '/order?item=&name=錏㨛\\udb14홅俐혘췟핻鷂改し糨ᙅ껹䭌硍绱ωꨣ\\ue05c岆䠧享⾭&email=Ɥ㌦랟ⱐ녟쇛扖閙墴깴\\uee88\\udfb1&city=⯀侒ꯕ⨬\\ua7dc뇄㨦칸꜃먯⛡﮹㉴튲&zip=iUr^a}qyKM&terms=晈',\n", " '/order?item=\\ue0f6䓉瞊\\uef41\\udb91ᱳ漊ḝ&name=뾖\\uf64c⌒\\uf3fb&email=敻喤ꕮȺ꽞\\u173b狄匣綵央&city=雾㶻乯꩞렎┫賊⸵\\uf2c6﹂꧟崞ᚣ\\udedc錐繗ꄄ䎦턳뛀䇙\\uf3cc\\uf75bﳖ&zip=2wxhC2-}+U&terms=\\uf80f\\u2fe1뙖',\n", " '/order?item=&name=翨钉\\u2003찯渪雠鳨⊅폀噶㶚朡ឞ碌응㤸\\uea12蔻潬ﰸ䪩\\ue9ad㕽㞣玗甏⛣\\uef56\\ueae2ꤿ㹼ླྀ矮䨶킻쿓\\u2bbc\\ue880&email=麍㰴\\ue4ad浼잂팠佷투浧뮬鬎ﵒ튴罇썴ኣ旁&city=ჟ謬┑栐䃝욹撌킁礪㠭墵̚㱬\\u0a7f鶃诓꽠쵾\\ue5c3㺟렁歵&zip=u9tCM:up\"7&terms=䘃',\n", " '/order?item=꾢ᐚ遟鸱뱣뇲셮鱋͑&name=䦓꽧ꜛ\\ue469䍰\\ud9fb룗惥\\ue858级ঝ㖜軺伮ꡅ\\ue13b訍妰㩤ㆮ墴ᥙ줎ᏽ\\uea38\\ue061鉵婎隶ૣ뫣&email=想㬒\\ue74b涛컺좆\\uefa2窟ͱᒽ鞻蠩்쿷읪&city=ㄇ梓짉歞\\ud896긄&zip=kmw:C),[Jt&terms=ꝵ﹖奯쎣⟟',\n", " \"/order?item=纋렋ꩈ&name=\\ued39㖀\\u1771콙屗饒谛ꎜ릘㑮쀤䥪큱ꯟ\\u2fe8홳惐\\u1c8a䠶Ἦ뮂崗젦撱㱛꺺㘜鳐ᑗ栏釲\\ud999恪텨槍軾㵫&email=馊㖦&city=\\uf4b1\\u3102샬ㄲ淫맄᧫\\ue300듲﮾긢\\u2bfd\\ue9cc⢕斉띞&zip=>]2'5Cws\\\\u&terms=偑\",\n", " '/order?item=솇Ꙋ쾒薚鋲贕겥ᩑ쯏&name=镑ᘐ긪\\ue87eⷦ食\\udf4a\\udab6뽐\\uf4c5䁖\\u0e85\\ue665᧴\\uef81ኑ䗲涩亮⼂腚峥\\uda8e䂉蝤ⅲ<ழꍫ仼쁌悂&email=\\ueb18ꆓ囯\\udf76䊩㵈\\u0bbbꗣ٢艨ꖙꛛ粑\\uf84dⰍ撫弹\\uf032洞㷔&city=蓵狔쯁&zip=5z>`{DD|5_&terms=묰ᖱ',\n", " '/order?item=槛靍耗ऽ㊥阩耷&name=옅ᰵ\\ue509鵨걅\\uf62d㷷෪眦돘ㆣ䭍嬮騗˷ം钘&email=ﶪࠔ굡ꋪ筼爻䄗蔯雁垭ࣺ뾿뚍烛&city=ᚽ㈐粰\\uf8b4旔创ᆫ\\udde9꾋낢鸐迒ᴋꩺ⍙\\uab2f兞凭쪴熽崌ၤ&zip=~MWq*0|y+Q&terms=',\n", " '/order?item=촡뚩櫏&name=塠곊욈鋴ཻ뗨搵䅲Č㤿낾㡮\\udbcd\\ue787㰗浕哮쁓\\uf8f6\\udb7b냱&email=咪蔖諍\\ued5a媪赌磊뜜婐웰ꗑ㇀槁\\ud923癬&city=젩►ธꅈ凈효\\udece೭⺕\\uf11eᘠ&zip=+2?NqyQ-`e[7eF>&terms=/order?item=',\n", " 'ms=҆/order?item=륙&name=[䵣侙⦳摦롄䃦榷靇噎繲腟鎞膾\\uf72f柵箍묻㌉୩\\uf32b径䊻祉维ڱ㮿殶禃ꬌꑎ瑫ᒽ&email=ȋ燇ἴ囻磮摭︂ヾヰ⢻᪬ꚯ属楴薒&city=㆖ꎝ줵\\uec8cȕ\\uf83f辧\\uf5ee爰\\uf579콡稪䅉搏遱쿿娐犚눾&zip=xm_L&terms=븴⌓눾녤掄',\n", " 'er?item=\\u086d悧涖糆&name=簇ル녩Ⲙ텍莽氊\\ufdd1䴑ﴍ鎍轰&email=㤲\\ue4ce뚰嫍뗨\\udf42钺봻䩈䔓㵮\\ue511댔閆轎㊸볿嬌\\ue372⫨\\ue5ca\\udff1퐎䓨&city=契ࠬ㒅&zip=TmUO11D,|!&terms=佻뭡',\n", " '/order?item=&name=谲둔\\uea73\\udf56㐲鑪\\ud8f1\\uf826ꈎ퐱팠礬ꨀ\\uf217㛲ῧﱒ塆䔿⅃갃ᔡ\\ue419']\n", "\n", "complex_population_4 = ['/order?item=&name=뵒ₜ共&email=镬苳܃ư柗龻䱆ꉦ䕙䨫寐睤朻ँ뤌┬\\u0991&city=緁⮁쨚\\u0fea窖襾陉帻筸䩈&zip=',\n", " 'ty=\\ue2c9熌ᐷ\\uf1fdⵑꨪ샮Њꋌ渉烕훗緾&zip=v_c9%#z6|o&terms=\\ue0e3\\ue32b쳜️焘/order?item=ά㠴\\u1b7d儧踱狫&name=ݬ獙ᩢ洛\\ud9e0䤬\\ud8c2\\ue1ed⤗쎟⃣墾\\udacd諻⿷㤚ꀚᶴֿ㱭\\ue575蒿ͽ쪒\\udad5\\ue9bb急돪缑朓ⵜ\\ue9eb䯋䢃\\ue000䃚\\ue95b\\udd73늞&email=\\ue567㳼꭛㔕䲉䷶⤮闱ꔵⱻ⍂\\udf6a&c',\n", " '/order?item=躢嘙ぃ噭\\uf49c佹ᅔ\\u0cf9name=㽃卵䘗٤嚆㜆褙簅꺯ʌ\\ue6b0땿䌼↭懵Ӄ쨬ᔑ鄚\\ufdfe頊삆㪜email=ꆹ\\udd7d朣켪㹯갇샹ꁷ嵥\\ue91b䞯\\ud92b晼ꌽ兄\\ue4d1\\ue37c횉鮡苃⍺琞䈂䌞垓鄠즲city=\\uf3b9\\uf876Ѷ䴽틒㎖㥣\\ue9d6zip=R;PNwz,v5aterms=ᅩ疻\\uf1ac㉄',\n", " '/order?item=ᷞ⧬㧥옖&name=៴\\udf88苂䙧⌏\\uef65',\n", " '/order?item=㘒\\ue72dؾname=쬂맴蘃ᰎ셨䛳\\udcde눘\\ue795∓跋\\ue476躲ꐐ摓尉䁜ེ艴엃洆釤ᘏ䌝偧ﯗ彸뱒\\ue4d6ུᖀ\\ue68eㇿ랝⧔촇牋浪꛶澑玙ᴵ⿁욾ϐ剓暭䖘㪨email=\\u2d73줇\\ue085夙⬇\\u07bc걤㾵ᇻ⮩鶸\\u173d箣䌙裘紛뙅☷\\uf6bfꬅ㰽\\ue0f7夣쪼city=맄鸫zip=4X9>\"/\\\\N,?terms=㞋',\n", " \"/order?item=┈\\udd1e&name=習臗\\udd2b팴慵變楗퀷ᯢȘ䕔닅뎗䠇\\ueec9❨㉪ꩳ偡헢劑뮬涬ꮑ譽\\ue5e0\\ue2caሌ㠒鉪\\uf88dἡ\\ue186ﲦ&emaㅔl=⺈\\u18ff捯龡巒봁ꎏ\\ue591袎\\uf1de쿒欣᯾\\uf04d莫鈾樓&city=蔶䴵刺槣칶&zip=z!z'sVf`JN&terms=\\ued82㒛ꐏ馸駱\",\n", " \"/?item=ᗡ⏏㟗ᯣ&name=&email=댰鱔&city=鍎ႜ붠惬\\uda92욗ﳹ\\udeadϘ\\ue967옮\\uec2a聘㬃蜴퇌翗뚣뭶ໆ낢ܐ蛊&zip=uucF57]'ft&terms=둓ⓨ鶽糥\",\n", " '/order?item=ﰮ믘聖垾&name=텼\\uf817ه珝剴譐\\ude8aⱘ&email=\\uf6de⋲릅늄┰ꋃ䜍\\uf365텃⸜\\ueef9엘蠟ᆮ㌬澞寢&city=摫铝葳鐟嬀驲䰷풥s\\uf204뀽쁸&zip=yu;?Ms~;[S&terms=㢓弼',\n", " '/order?item=쿻&name=෯Ǥ∱컬䈁݇&email=⾞ꖦ鏋ⓩ맶\\udda8뗢隿ⶮ◘蟜혵&city=霭ퟯǷ\\u0a7b씀&zip=dco7`n;N%.&terms=鳹䡔鴗',\n", " '/order?item=\\u0ad3쑝鐽囖恁ꖺ譕&name=䮌ṧꘋ죽ዥ\\u4dbbꕑཆ嚍뎗᯳⮁睸烵\\uf727퀘驃頽&email=逛ꇟ潑ﺷゞ녁\\uf52ag镃\\uf57b᭨ꐜ䍮跌\\ud8f8ῆ\\udc42⻱\\ueeb2暟춘ƃ饣濐萓佷᭻&city=준筪\\ued01&zﺻp=+1)FF_GdsI&terms=掌젪킼']\n", "\n", "complex_population_5 = ['/order?item=盘ொ\\udb99柋ꂌ\\ue655name=璮卑ꌭ㵡\\uef1cं┧樯❏骤셞乢玁뼁\\ue214額㶅▶ő黕뫓隷䞺\\ua9da\\u09b1東물樯侤뫩덷竁Ⴆ闀鎼꙳ጪጃ减묆鐝⤎规email=䲩늫猭䭗\\ud8ec鑆셡ԗ䊟city=ﶨ偏zip=J>f0-|\"Vvjterms=ᴐ街\\uedba➩\\ue12f',\n", " '/order?item=\\ue03bᦱ⍽㎉瓧&name=〡ⶒ虯밌\\x0c椀풬嫤쌗ꔻ犔鲾\\udca8参縹ഹᄌ癡쩚峻㻐屏壑玌ᖠ풀\\ue5c7薯셴꺱찏\\u0b00㘑ꊑ\\ud928䱜钑璿勦䇲\\ue558桌ູ쁮ᱴ\\ue8e6\\ued13勸&email=롚讍\\uf69c천䞰꯵斛ڠ⊑ɝ꽔畐綎趝ᅨ変泙菑㯊빍詇\\ueafb侫ᒉꃏ&\\ueb55ity=᧼ꇢ7㜃\\u181c\\udd55肖⩴㨤O家껉筌㯋︳\\uda7a嫃&zip=YWMYq\"3zTT&terms=猱',\n", " \"炾䨣ꖂ㶢&city=鰺謺㦐&zip=2'6;L#terms=〢쒼',\n", " '/?item=⇶퀍侵⠜䱤㧋岀ﻝ&name=疨\\uf06b䃭\\ueac2壻頧\\u2d6d絗\\uda83\\udf6e䷓㡅&email=ƿ◇ᐞⓝ罆⺙蒛得\\ue0c1\\uec88䭌\\uf61e\\ue85a\\uf3ec格&city=锜䂉\\uedf9\\u089dᴄ큨毯ꬥ⌞〘\\uee00䯣梬蔔눍澐耯茖䑨孬&zip=5S8WT^Tsw9&terms=귨Ꝛ巣']\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "prefix = [\"easy\", \"medium\", \"hard\", \"complex\"]\n", "\n", "for i in range(1,6):\n", " for j in range(0,4):\n", " str_pop = prefix[j] + \"_population_\" + str(i)\n", " assert(len(eval(str_pop)) == 10), print(\"{0}: {1}\".format(str_pop, len(eval(str_pop))))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "initial_population = [easy_population_1, easy_population_2, easy_population_3, easy_population_4, easy_population_5, \\\n", " medium_population_1, medium_population_2, medium_population_3, medium_population_4, medium_population_5] \n", "\n", "harder_population = [hard_population_1, hard_population_2, hard_population_3, hard_population_4, hard_population_5, \\\n", " complex_population_1, complex_population_2, complex_population_3, complex_population_4, complex_population_5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Scoring\n", "\n", "For each URL input in the population and its corresponding target, your implementaton should generate a list of test inputs, __maximum of 10 inputs__. These inputs will be executed on the server and graded based on:\n", "\n", "* Number of iterations of your GA algorithm (less is better)\n", "* Number of reached target pages , i.e. error pages, confirmation page and page not found\n", "* Number of resulting valid inputs for each target page.\n", "\n", "\n", "__Note__\n", "* __For each target, we expect at least _one_ valid generated input to pass the target, out of maximum 10 generated inputs__.\n", " \n", "* __Your implementation will be tested with a _secret_ (possibly more complicated) population which may contain inputs other than the ones provided in the project.__ " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Grading framework\n", "\n", "For grading:\n", " * __To pass__, your implementation should produce valid inputs that reach the confirmation page, page not found and all error pages for the `easy_population` and `medium_population`.\n", " __Points__ will be assigned based on the number of reached pages, reaching the confirmation page, number of resulting valid inputs and the number of iterations of your GA algorithms. \n", " * __To obtain extra points__, your implementation should produce valid inputs that reach the confirmation page, page not found and all error pages for all or some of the `hard_population`. \n", " __Points__ will be assigned based on the number of reached pages, reaching the confirmation page, number of resulting valid inputs and the number of iterations of your GA algorithms.\n", " * __Bonus Points__, your implementation should produce valid inputs that reach the confirmation page, page not found and all error pages for all or some of the `complex_population`. \n", " __Points__ will be assigned based on the number of reached pages, reaching the confirmation page, number of resulting valid inputs and the number of iterations of your GA algorithms." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import multiprocessing\n", "from multiprocessing import Process\n", "\n", "def run_genetic_algorithm_limited_time(func, args_1, args_2, args_3, kwargs, time):\n", " manager = multiprocessing.Manager()\n", " return_dict = manager.dict()\n", " p = Process(target=func, args=(args_1, args_2, args_3, return_dict), kwargs=kwargs)\n", " p.start()\n", " p.join(time)\n", " if p.is_alive():\n", " p.terminate()\n", " return False\n", "\n", " return True, return_dict.values()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def compute_results(population, num_regex):\n", " global httpd_process, httpd_url, list_regex\n", " resulting_population = [] \n", " num_generations = 0\n", " num_valid, num_invalid, validity_score, reachability_score = 0,0,0,0\n", " \n", " reachability_list, validity_list = [],[] \n", " gen_list, pass_list = [], []\n", " \n", " dash = '-' * 115\n", " print(dash)\n", " print('{:<8s}{:<8s}{:<10s}{:>8s}{:>12s}{:>12s}{:>18s}{:>12s}{:>20s}'.format(\"pop_id\", \"reg_id\", \"target\", \"#gens\", \"#val\", \"#inval\", \"reachability\", \"validity(%)\", \"Pass(1)/Fail(0)\"))\n", " print(dash)\n", " \n", " itn = 0 \n", " \n", " reg_ind = num_regex\n", " list_regex = [itemList[reg_ind], name_regex[reg_ind], email_regex[reg_ind], city_regex[reg_ind], zip_regex[reg_ind], terms_regex]\n", " httpd_process, httpd_url = start_httpd(ProjectHTTPRequestHandler)\n", "\n", " for test_population in population:\n", " itn += 1\n", " for target in target_list:\n", "\n", " try:\n", " ret = run_genetic_algorithm_limited_time(genetic_algorithm, test_population, target, list_regex, {}, 3600) \n", " if ret: \n", " resulting_population = ret[1][0][0]\n", " num_generations = ret[1][0][1]\n", " except Exception as e:\n", " e.__traceback__ = None\n", " traceback.clear_frames(e.__traceback__)\n", " pass\n", "\n", "\n", " if len(resulting_population) <= 10:\n", " reachability_score, num_valid = get_web_reachability(resulting_population, target)\n", " num_invalid = len(test_population) - num_valid\n", " validity_score = (num_valid/len(test_population)) * 100 \n", "\n", " gen_list.append(num_generations)\n", "\n", " reachability_list.append(reachability_score)\n", " validity_list.append(validity_score)\n", "\n", " pass_list.append(bool(validity_score > 1))\n", "\n", " print('{:<8d}{:<8d}{:<10s}{:>8d}{:>10d}{:>12d}{:>16d}{:>16d}{:>16b}'\\\n", " .format(itn, reg_ind + 1, target, num_generations, num_valid, num_invalid, int(reachability_score), int(validity_score), \\\n", " validity_score > 1))\n", " else:\n", " raise ValueError(\"Number of generated inputs ({0}) is greater than 10 \".format(len(resulting_population)))\n", " httpd_process.terminate()\n", "\n", " total = len(population) * len(target_list)\n", " \n", " per_passed = (sum(pass_list)/total) * 100\n", " per_failed = ((total - sum(pass_list))/ total) * 100\n", " reachability = sum(reachability_list)\n", " avg_validity = (sum(validity_list)/ len(validity_list))\n", " avg_gens = sum(gen_list)/len(gen_list)\n", "\n", " return per_passed, per_failed, reachability, avg_validity, avg_gens, \\\n", " total, len(reachability_list), validity_list, gen_list" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "easy_population = [easy_population_1, easy_population_2, easy_population_3, easy_population_4, easy_population_5]\n", "medium_population = [medium_population_1, medium_population_2, medium_population_3, medium_population_4, medium_population_5] \n", "hard_population = [hard_population_1, hard_population_2, hard_population_3, hard_population_4, hard_population_5]\n", "complex_population = [complex_population_1, complex_population_2, complex_population_3, complex_population_4, complex_population_5]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "easy_per_passed_0, easy_per_failed_0, easy_reachability_0, easy_avg_validity_0, easy_avg_gens_0, \\\n", "easy_total_0, easy_len_reachability_list_0, easy_validity_list_0, easy_gen_list_0 = compute_results(easy_population, 0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"EASY REGEX 1\")\n", "print(\"Percent passed: {0:.2f}%\".format(easy_per_passed_0))\n", "print(\"Percent failed: {0:.2f}%\".format(easy_per_failed_0))\n", "print(\"avg % validity: {0:.2f}%\".format(easy_avg_validity_0))\n", "print(\"avg gen_list: {0:.2f}\".format(easy_avg_gens_0))\n", "print(\"Reachability: {0:.2f}\".format(easy_reachability_0))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "medium_per_passed_0, medium_per_failed_0, medium_reachability_0, medium_avg_validity_0, medium_avg_gens_0, \\\n", "medium_total_0, medium_len_reachability_list_0, medium_validity_list_0, medium_gen_list_0 = compute_results(medium_population, 0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"MEDIUM REGEX 1\")\n", "print(\"Percent passed: {0:.2f}%\".format(medium_per_passed_0))\n", "print(\"Percent failed: {0:.2f}%\".format(medium_per_failed_0))\n", "print(\"avg % validity: {0:.2f}%\".format(medium_avg_validity_0))\n", "print(\"avg gen_list: {0:.2f}\".format(medium_avg_gens_0))\n", "print(\"Reachability: {0:.2f}\".format(medium_reachability_0))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hard_per_passed_0, hard_per_failed_0, hard_reachability_0, hard_avg_validity_0, hard_avg_gens_0, \\\n", "hard_total_0, hard_len_reachability_list_0, hard_validity_list_0, hard_gen_list_0 = compute_results(hard_population, 0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"HARD REGEX 1\")\n", "print(\"Percent passed: {0:.2f}%\".format(hard_per_passed_0))\n", "print(\"Percent failed: {0:.2f}%\".format(hard_per_failed_0))\n", "print(\"avg % validity: {0:.2f}%\".format(hard_avg_validity_0))\n", "print(\"avg gen_list: {0:.2f}\".format(hard_avg_gens_0))\n", "print(\"Reachability: {0:.2f}\".format(hard_reachability_0))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "complex_per_passed_0, complex_per_failed_0, complex_reachability_0, complex_avg_validity_0, complex_avg_gens_0, \\\n", "complex_total_0, complex_len_reachability_list_0, complex_validity_list_0, complex_gen_list_0 = compute_results(complex_population, 0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"COMPLEX REGEX 1\")\n", "print(\"Percent passed: {0:.2f}%\".format(complex_per_passed_0))\n", "print(\"Percent failed: {0:.2f}%\".format(complex_per_failed_0))\n", "print(\"avg % validity: {0:.2f}%\".format(complex_avg_validity_0))\n", "print(\"avg gen_list: {0:.2f}\".format(complex_avg_gens_0))\n", "print(\"Reachability: {0:.2f}\".format(complex_reachability_0))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "final_per_passed = (easy_per_passed_0 + medium_per_passed_0 + hard_per_passed_0 + complex_per_passed_0) / 4\n", "final_per_failed = (easy_per_failed_0 + medium_per_failed_0 + hard_per_failed_0 + complex_per_failed_0) / 4\n", "final_reachability = easy_reachability_0 + medium_reachability_0 + hard_reachability_0 + complex_reachability_0 \n", "final_val_list = easy_validity_list_0 + medium_validity_list_0 + hard_validity_list_0 + complex_validity_list_0\n", "final_avg_validity = sum(final_val_list)/len(final_val_list)\n", "final_gen_list = easy_gen_list_0 + medium_gen_list_0 + hard_gen_list_0 + complex_gen_list_0\n", "final_avg_gens = sum(final_gen_list)/len(final_gen_list)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"Percent passed: {0:.2f}%\".format(final_per_passed))\n", "print(\"Percent failed: {0:.2f}%\".format(final_per_failed))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"avg % validity: {0:.2f}%\".format(final_avg_validity))\n", "print(\"avg gen_list: {0:.2f}\".format(final_avg_gens))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"Reachability: {0:.2f}\".format(final_reachability))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.6" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }