Quick Start¶
Installation¶
From PyPI:
pip install pyrace
From GitHub:
git clone https://github.com/llamasoft/pyrace.git
cd pyrace
python setup.py install
Basic Usage¶
To get pyrace up and running, all you need is a Driver and a work_queue.
- The
work_queuedefines theRequests that eachThreadshould execute. - The
Drivercreates theThreads and drives them through theirwork_queues in a synchronized manner.
The following is taken from examples/basic.py:
import requests
import pyrace
# The `Driver` class creates `Thread`s, provides them with a `work_queue`,
# and drives them through their `work_queue`s in a synchronized manner.
driver = pyrace.Driver()
# The `work_queue` list represents the work that each `Thread` should execute.
# The elements of a `work_queue` can be `Request`s or callable functions.
request = requests.Request('GET', 'https://now.httpbin.org')
work_queue = [request]
# The `process` method creates the specified number of worker `Thread`s,
# provides them each with a copy of the `work_queue`, then drives them
# through the `work_queue` tasks in a synchronized manner.
# The method returns a list of the `Thread` instances used.
result_threads = driver.process(work_queue, thread_count = 3)
# The primary `Thread` attributes we are interested in are `response` and `all_responses`.
# The `response` attribute contains the most recently returned `Response`.
# The `all_responses` attribute is a list of all `Response`s, in order.
# For information on `Response` objects, see Requests documentation:
# http://docs.python-requests.org/en/master/user/quickstart/#response-content
for thread in result_threads:
json_response = thread.response.json()
epoch_time = json_response['now']['epoch']
print("{:.4f}".format(epoch_time))
Regarding Thread Count¶
Less is more when it comes to the number of parallel threads!
Using too many threads may yield inconsistent results. This library sends requests as precise as possible, but networks can interfere with when the requests are received by the target server. Typically, request timing follows a normal distribution; most requests arrive very close together, but a few may arrive early and a few may arrive late.
Knowing this, choose your thread_count value accordingly:
If the target is meant to allow an action once (e.g. sending items, deleting a post), then successful race condition exploitation only depends on the timing of the first few requests. Using a large number of threads increases the chance that a request to arrive too early, preventing the other requests from having an effect. In these situations, you should only use two or three threads.
If the target is meant to allow an action multiple times (e.g. returning search results, uploading a file) then successful race condition exploitation only depends on the timing of any two requests. A large number of parallel requests may result in variability, but due to the tendancy for requests to arrive in groups, the chance of any two requests colliding increases. In these situations, the number of threads depends mainly on your network connection. A thread count between four and ten is reasonable but more may be used if your network allows.
Note
Be careful to not use too many threads as your burst of requests may result in (or be viewed as) a denial of service attack.
Advanced Usage¶
Keyword Arguments¶
pyrace supports passing custom parameters to the Thread and BaseConnection
classes by providing extra keyword arguments to the process() method.
These keywords are passed to the classes via race_args.
- do_eval:
- Evaluates statements embedded in
Requestfields. Seeexamples/eval.pyfor example usage. - save_sent_cookies:
- Saves user-defined
Requestcookies to the currentSession. Seeexamples/cookies.pyfor example usage. - send_kwargs:
- Dict of extra arguments to pass to
requests.Session.send(). See linked documentation’s source code for all possible values. Common values includeverifyandproxies. - connect_mode:
- Determine which IP address threads connect to for a given hostname.
If a hostname resolves to multiple IP addresses, this allows you to specify that
all threads should connect to the same, different, or random IP addresses.
See
example/timing.pyfor example usage.
For a full list of valid race_args keywords, or for additional details
on the above keywords, see Thread and BaseConnection
documentation.
Callbacks¶
In addition to Requests, the work_queue also supports callable functions.
These functions are passed a single argument: the calling Thread instance (i.e. self).
This gives the user total control over the Thread, allowing you to do such things as:
- Dynamically adding new
Requests to theThread‘swork_queuebased on previousResponses. - Modifying the
Thread‘sSessionto edit headers or cookies. - Literally anything a
Threadcan do, you can control using callable functions.
For an example of callbacks in action, see example/callbacks.py.