Flows
Flows are the main concept in Raider, used to
define the HTTP information exchange. Each request you want to
send needs its own Flow object. Inside the request
attribute of
the object, needs to be a Request
object containing the definition of the request
.
This definition can contain Plugins
whose value will be used when sending the HTTP Request. In
this case, the Plugins
will act as
inputs.
When using Plugins
in the outputs
attribute, they will act as outputs, and the value
will be
extracted for later use.
There are two types of Flow, the regular one using the Flow
class, and the authentication Flows using the
AuthFlow
class. Only difference is
that AuthFlow ones are treated as changing the authentication state
while the regular ones don’t. Use AuthFlow to define the process
necessary to reach from unauthenticated state to authenticated
one. Use regular Flows for any other requests you want to test using
Raider.
Flow class holding the information exchanged between server and client.
- class Flow(request, outputs=None, operations=None)[source]
Class dealing with the information exchange from HTTP communication.
A Flow object in Raider defines all the information about one single HTTP information exchange. It contains one
request
, theresponse
, theoutputs
that needs to be extracted from the response, and a list ofoperations
to be run when the exchange is over.Use this only when working with requests that DON’t change the authentication state. It’s used in the
Functions
class to run arbitrary actions when it doesn’t affect the authentication state.- response
A
requests.model.Response
object. It’s empty until the request is sent. When the HTTP response arrives, it’s stored here.
- outputs
A list of
Plugin
objects detailing the pieces of information to be extracted from the response. Those will be later available for other Flow objects.
- operations
A list of
Operation
objects to be executed after the response is received and outputs are extracted. Should contain aNext
operation if another Flow is expected.
- __init__(request, outputs=None, operations=None)[source]
Initializes the Flow object.
Creates the Flow object with the associated Request, the outputs to be extracted, and the operations to be run upon completion.
- execute(pconfig)[source]
Sends the request and extracts the outputs.
Given the user in context and the global Raider configuration, sends the HTTP request and extracts the defined outputs.
Iterates through the defined outputs in the Flow object, and extracts the data from the HTTP response, saving it in the respective
Plugin
object.- Parameters
user – An object containing all the user specific data relevant for this action.
config – The global Raider configuration.
- Return type
None
- run_operations()[source]
Runs the defined
operations
.Iterates through the defined
operations
and executes them one by one. Iteration stops when the firstNext
operations is encountered.- Return type
Optional
[str
]- Returns
A string with the name of the next flow to run or None.
Examples
Create the variable initialization
with the AuthFlow. It’ll send a
GET request to https://example.com/admin/
. If the HTTP response
code is 200 go to next stage login
.
(setv initialization
(AuthFlow
:request (Request
:method "GET"
:url "https://example.com/admin/")
:operations [(Http
:status 200
:action (NextStage "login"))]))
Define AuthFlow login
. It will send a POST request to
https://example.com/admin/login
with the username and the password
in the body. Extract the cookie PHPSESSID
and store it in the
session_id
plugin. If server responds with HTTP 200 OK, print
login successfully
, otherwise quit with the error message login
error
.
(setv username (Variable "username"))
(setv password (Variable "password"))
(setv session_id (Cookie "PHPSESSID"))
(setv login
(AuthFlow
:request (Request
:method "POST"
:url "https://www.example.com/admin/login"
:data
{"password" password
"username" username})
:outputs [session_id]
:operations [(Http
:status 200
:action (Print "login successfully")
:otherwise (Error "login error"))]))
Define another login
Flow. Here what’s different is the
csrf_name
and csrf_value
plugins. In this application both the
name and the value of the token needs to be extracted, since they change
all the time. They were defined as Html
objects. Later they’re being used in the body of the Request
.
If the HTTP response code is 200 means the MFA was enabled and the multi_factor
stage
needs to run next. Otherwise, try to log in again. Here the password
is asked from the user by a Prompt
.
Also define the regular Flow named get_nickname
to extract the
username of the logged in user. This request doesn’t affect the
authentication state which is why Flow is used instead of AuthFlow.
;; Gets `username` from active user's object defined in `users`.
(setv username (Variable "username"))
;; Gets the password by manual input.
(setv password (Prompt "password"))
;; Gets `PHPSESSID` from the cookie.
(setv session_id (Cookie "PHPSESSID"))
;; Gets the OTP code by manual input.
(setv mfa_code (Prompt "OTP code"))
;; Extract nickname from the HTML code. It looks for a tag like this:
;; <input id="nickname" value="admin">
;; and returns `admin`.
(setv nickname
(Html
:name "nickname"
:tag "input"
:attributes
{:id "nickname"}
:extract "value"))
;; Extracts the name of the CSRF token from HTML code. It looks
;; for a tag similar to this:
;; <input name="0123456789" value="0123456789012345678901234567890123456789012345678901234567890123" type="hidden">
;; and returns 0123456789.
(setv csrf_name
(Html
:name "csrf_name"
:tag "input"
:attributes
{:name "^[0-9A-Fa-f]{10}$"
:value "^[0-9A-Fa-f]{64}$"
:type "hidden"}
:extract "name"))
;; Extracts the value of the CSRF token from HTML code. It looks
;; for a tag similar to this:
;; <input name="0123456789" value="0123456789012345678901234567890123456789012345678901234567890123" type="hidden">
;; and returns 0123456789012345678901234567890123456789012345678901234567890123.
(setv csrf_value
(Html
:name "csrf_value"
:tag "input"
:attributes
{:name "^[0-9A-Fa-f]{10}$"
:value "^[0-9A-Fa-f]{64}$"
:type "hidden"}
:extract "value"))
;; Defines the `login` AuthFlow. Sends a POST request to
;; https://example.com/login.php. Use the username, password
;; and both the CSRF name and values in the POST body.
;; Extract the new CSRF values, and moves to the next stage
;; if HTTP response is 200.
(setv login
(AuthFlow
:request (Request
:method "POST"
:url "https://example.com/login.php"
:cookies [session_id]
:data
{"password" password
"username" username
csrf_name csrf_value})
:outputs [csrf_name csrf_value]
:operations [(Http
:status 200
:action (NextStage "multi_factor")
:otherwise (NextStage "login"))]))
;; Defines the `multi_factor` AuthFlow. Sends a POST request to
;; https://example.com/login.php. Use the username, password,
;; CSRF values, and the MFA code in the POST body.
(setv multi_factor
(AuthFlow
:request (Request
:method "POST"
:url "https://example.com/login.php"
:cookies [session_id]
:data
{"password" password
"username" username
"otp" mfa_code
csrf_name csrf_value})
:outputs [csrf_name csrf_value]))
;; Extracts the nickname and print it. Send a GET request to
;; https://example.com/settings.php and extract the nickname
;; from the HTML response.
(setv get_nickname
(Flow
:request (Request
:method "GET"
:url "https://example.com/settings.php"
:cookies [session_id])
:outputs [nickname]
:operations [(Print nickname)]))
Plugins
Plugins in Raider are pieces of code that are
used to get inputs from, and put them in the HTTP Request,
and/or to extract some value
from the Response. This is
used to facilitate the information exchange
between Flows. Plugins act as inputs
when used inside the Flow’s request
attribute, and
as outputs when used in the outputs
attribute.
Below there’s a list of predefined Plugins. The users are also encouraged to write their own plugins.
Common
Users most often won’t need to use those unless they’re writing their own Plugins. Common Plugins are mostly used as parent classes for other Plugins.
Plugin
Use this class only when creating new Plugins. Either when writing custom plugins in hylang or when adding new plugins to the Raider main code. Check the repository for inspiration.
Plugin
objects can be used BOTH as inputs in HTTP
Requests and outputs from HTTP Responses.
Plugin’s behaviour can be controlled with following flags:
NEEDS_USERDATA |
0x01 |
NEEDS_RESPONSE |
0x02 |
DEPENDS_ON_OTHER_PLUGINS |
0x04 |
NAME_NOT_KNOWN_IN_ADVANCE |
0x08 |
Combine the flags with boolean OR if you want to set more flags, for example:
class MyPlugin(Plugin):
def __init__(self, name):
super().__init__(
name=name,
function=self.extract_html_tag,
flags=Plugin.NEEDS_USERDATA|Plugins.NEEDS_RESPONSE,
)
[...]
- class Plugin(name, function=None, value=None, flags=0)[source]
Parent class for all
Plugins
.Each
Plugin
class inherits from here.get_value
function should be called when extracting thevalue
from thePlugin
, which will then be stored in thevalue
attribute.Plugin's
behaviour can be controlled using following flags:NEEDS_USERDATA
= 0x01When set, the
Plugin
will get itsvalue
from the user’s data, which will be sent to the function defined here. Use whenPlugin's
value
depends on things defined in theUser
class, like the username or password.NEEDS_RESPONSE
= 0x02When set, the
Plugin's
value
can only be extracted from a previous HTTP response.DEPENDS_ON_OTHER_PLUGINS
= 0x04When set, the
Plugin's
value
can only be extracted from otherPlugins
. Use this when combiningPlugins
.NAME_NOT_KNOWN_IN_ADVANCE
= 0x08When set, the name of the
Plugin
is not known in advance, and will be set when thePlugin
runs. Useful when the name changes and can only be matched with a regex.
- function
A Callable which will be called to extract the
value
of thePlugin
when used as an input in a Flow. The function should setself.value
and also return it.
- name_function
A Callable which will be called to extract the
name
of thePlugin
when it’s not known in advance and the flagNAME_NOT_KNOWN_IN_ADVANCE
is set.
- plugins
A List of
Plugins
whose value needs to be extracted first before currentPlugin's
value can be extracted. Used when the flagDEPENDS_ON_OTHER_PLUGINS
is set.
- __init__(name, function=None, value=None, flags=0)[source]
Initializes a
Plugin
object.Creates a
Plugin
object, holding afunction
defining how to extract thevalue
.- Parameters
name (
str
) – A String with the unique identifier of thePlugin
.function (
Optional
[Callable
[...
,Optional
[str
]]]) – An Optional Callable that will be used to extract thePlugin's
value
.value (
Optional
[str
]) – An Optional String with the predefinedvalue
of thePlugin
.flags (
int
) – An Integer containing the flags that define thePlugin's
behaviour. No flags are set by default
- get_value(pconfig)[source]
Gets the
value
from thePlugin
.Depending on the
Plugin's
flags, extract and return itsvalue
.- Parameters
userdata – A Dictionary with the user specific data.
- Return type
Optional
[str
]- Returns
An Optional String with the value of the
Plugin
. Returns None if no value can be extracted.
- extract_value_from_response(response)[source]
Extracts the
value
of thePlugin
from the HTTP response.If
NEEDS_RESPONSE
flag is set, thePlugin
will extract itsvalue
upon receiving the HTTP response, and store it inside thevalue
attribute.- Parameters
response (
Optional
[Response
]) – Anrequests.models.Response
object with the HTTP response.- Return type
None
- extract_name_from_response(response)[source]
Extracts the name of the
Plugin
from the HTTP response.If
NAME_NOT_KNOWN_IN_ADVANCE
flag is set, thePlugin
will set its name after receiving the HTTP response, and store it inside thename
attribute.- Parameters
response (
Optional
[Response
]) – Anrequests.models.Response
object with the HTTP response.- Return type
None
- extract_value_from_userdata(pconfig)[source]
Extracts the
Plugin
value
from userdata.Given a dictionary with the userdata, return its
value
with the same name as the “name” attribute from thisPlugin
.- Parameters
data – A Dictionary with user specific data.
- Return type
Optional
[str
]- Returns
An Optional String with the
value
of the variable found. Returns None if it cannot be extracted.
- return_value()[source]
Returns
Plugin's
value
.This is used when needing a function just to return the
value
.- Return type
Optional
[str
]- Returns
An Optional String with the stored
value
. Returns None ifvalue
is empty.
- property needs_userdata: bool
Returns True if the
NEEDS_USERDATA
flag is set.- Return type
bool
- property needs_response: bool
Returns True if the
NEEDS_RESPONSE
flag is set.- Return type
bool
- property depends_on_other_plugins: bool
Returns True if the
DEPENDS_ON_OTHER_PLUGINS
flag is set.- Return type
bool
- property name_not_known_in_advance: bool
Returns True if the
NAME_NOT_KNOWN_IN_ADVANCE
flag is set.- Return type
bool
Parser
The Parser
Plugin
takes other Plugins
as input, parses it, and extracts the piece of information
for further use. Parser
Plugins
can
ONLY be used as inputs.
- class Parser(name, function, value=None)[source]
Parent class for
Parser
Plugins
.Use the
Parser
Plugin
when needing to take anotherPlugin
as input, build a data structure out of it, and extracting some parts you’re interested in. The simplest example would be parsing a URL to extract the domain name from it.- function
A Callable which will be called to parse the
value
of parentPlugin
and extract the newvalue
. The function should setself.value
and also return it.
- name_function
A Callable which will be called to extract the
name
of thePlugin
when it’s not known in advance and the flagNAME_NOT_KNOWN_IN_ADVANCE
is set. By default not used inParser
Plugin
.
- plugins
A List of
Plugins
whose value needs to be extracted first before currentPlugin's
value can be extracted. Used when the flagDEPENDS_ON_OTHER_PLUGINS
is set, which it is by default forParsers
.
- flags
An Integer containing the flags that define the
Plugin's
behaviour. By default only theDEPENDS_ON_OTHER_PLUGINS
flag is set.
- __init__(name, function, value=None)[source]
Initializes the
Parser
Plugin
.Creates a
Parser
object, holding afunction
defining how to parse the parentPlugin
in order to extract thevalue
. Only the flagDEPENDS_ON_OTHER_PLUGINS
is preset, since it needs to extract thevalue
from otherPlugins
, and those need to be extracted first.
Processor
The Processor
Plugin
encodes, decodes and otherwise
processes other Plugins
. Processor
Plugins
can ONLY be used as inputs.
- class Processor(name, function, value=None)[source]
Parent class for
Processor
Plugins
.Use the
Processor
Plugin
when needing to take anotherPlugin
as input, and modify (process) it to get the neededvalue
. For example by encoding/decoding or doing other kinds of modifications to thevalue
extracted from the parentPlugin
.- function
A Function which will be called to process the
value
of the parentPlugin
and get the newvalue
. The function should setself.value
and also return it.
- name_function
A Callable which will be called to extract the
name
of thePlugin
when it’s not known in advance and the flagNAME_NOT_KNOWN_IN_ADVANCE
is set. By default not used inParser
Plugin
.
- plugins
A List of
Plugins
whose value needs to be extracted first before currentPlugin's
value can be extracted. Used when the flagDEPENDS_ON_OTHER_PLUGINS
is set, which it is by default forProcessors
.
- value
A String containing the
Processors's
outputvalue
to be used as input in the HTTP Requests.
- flags
An Integer containing the flags that define the
Plugin's
behaviour. By default only the flagDEPENDS_ON_OTHER_PLUGINS
is set.
- __init__(name, function, value=None)[source]
Initializes the
Processor
Plugin
.Creates a
Processor
object, holding afunction
defining how to process the parentPlugin
to get thevalue
. Only the flagDEPENDS_ON_OTHER_PLUGINS
is preset, since it needs to extract thevalue
from otherPlugins
, and those need to be extracted first.
Empty
The Empty
Plugin
is unique in that it contains no
function or value
. Its only use is when fuzzing but no previous
value
is needed. Empty
Plugin
can ONLY be
used as inputs.
- class Empty(name)[source]
-
Use the
Empty
Plugin
when you don’t care about the actualvalue
of thePlugin
, and only want to have a placeholder to use for fuzzing.- function
A Callable which will be called to process the
value
of the parentPlugin
and get the newvalue
. The function should setself.value
and also return it.
- name_function
A Callable which will be called to extract the
name
of thePlugin
when it’s not known in advance and the flagNAME_NOT_KNOWN_IN_ADVANCE
is set. Not used inEmpty
Plugin
.
- plugins
A List of
Plugins
whose value needs to be extracted first before currentPlugin's
value can be extracted. Used when the flagDEPENDS_ON_OTHER_PLUGINS
is set. Not used inEmpty
Plugin
.
- value
A string containing the
Processors's
outputvalue
to be used as input in the HTTP Requests. Not used inEmpty
Plugin
.
Example:
(setv placeholder (Empty "placeholder"))
(setv attack
(Flow
:request
(Request
:method "POST"
:url "https://example.com/"
:data
{"item" "123"
"filename" placeholder ;; Sends empty filename by default.
;; When fuzzing use the payload string instead.
}
Basic
Basic Plugins
are the most commonly used ones, that
don’t depend on other plugins to get its value
. Basic
Plugins
can be used BOTH as inputs and outputs.
Variable
The Variable
Plugin
extracts the value
defined in the User
object. Use it to get the username/password or other extra information
about the User
. Variable
Plugins
can ONLY be used
as inputs.
- class Variable(name)[source]
Plugin
to extract data from theUser
Use this when the
value
of the plugin should be extracted from the user data.username
andpassword
are mandatory and can be accessed with(Variable "username")
and(Variable "password")
respectively. Other data can be accessed similarly.
Example:
(setv users
(Users
[{"admin" ;; username
"password" ;; password
:nickname "admin" ;; extra optional data
:email "admin@example.com"}
{"user1" "password1"
:attribute "blah"
:nickname "mynickname"
:email "abc@example.com"}]))
(setv username (Variable "username"))
(setv password (Variable "password"))
(setv nickname (Variable "nickname"))
(setv login
(AuthFlow
:request
(Request
:method "POST"
:url "https://www.example.com/login"
:data
{"username" username ;; Sends the active user's credentials
"password" password ;; and the email in the respective fields.
"email" email}
Prompt
The prompt plugin accepts user input mid-flow. Use it when you don’t
know in advance the data you will need to send, like in case of
multi-factor authentication (MFA). Prompt
Plugins
can ONLY be used
as inputs.
- class Prompt(name)[source]
Plugin
to prompt the user for some data.Use this
Plugin
when thevalue
cannot be known in advance, for example when asking for multi-factor authentication (MFA) code that is going to be sent over SMS or E-mail.- name
A String used both as an identifier for this
Prompt
Plugin
and as a prompt message on the terminal.
Example:
(setv username (Variable "username"))
(setv password (Variable "password"))
(setv mfa_code (Prompt "Input code here:")) ;; Asks user for the MFA code.
(setv multifactor
(AuthFlow
:request
(Request
:method "POST"
:url "https://www.example.com/login"
:data
{"username" username
"password" password
"otp" mfa_code} ;; Sends the data from user's input in `otp`.
Header
The Header
Plugin
extracts and sets new headers. Cookie
Plugins
can be used BOTH as inputs and
outputs.
- class Header(name, value=None, function=None, flags=2)[source]
Plugin
dealing with theHeaders
in HTTP Requests and Responses.Use the
Header
Plugin
when working with the data found in HTTPHeaders
.- function
A Callable which will be called to extract the
value
of theHeader
when used as an input in a Flow. The function should setself.value
and also return it.
- name_function
A Callable which will be called to extract the
name
of theHeader
when it’s not known in advance and the flagNAME_NOT_KNOWN_IN_ADVANCE
is set.
- plugins
A List of
Plugins
whosevalue
needs to be extracted first before currentHeader's
value can be extracted. Used when the flagDEPENDS_ON_OTHER_PLUGINS
is set.
- __init__(name, value=None, function=None, flags=2)[source]
Initializes the
Header
Plugin
.Creates a
Header
Plugin
, either with predefinedvalue
, or by using afunction
defining how thevalue
should be generated on runtime.- Parameters
name (
str
) – A String with the name of theHeader
.value (
Optional
[str
]) – An Optional String with thevalue
of theHeader
in case it’s already known.function (
Optional
[Callable
[...
,Optional
[str
]]]) – A Callable which is used to get thevalue
of theHeader
on runtime.flags (
int
) – An integer containing theflags
that define thePlugin's
behaviour. By default onlyNEEDS_RESPONSE
flag is set.
- extract_header_from_response(response)[source]
Returns the
Header
with the specified name from the response.
- __str__()[source]
Returns a string representation of the
Header
.Used for logging purposes only.
- Return type
str
- classmethod regex(regex)[source]
Extracts the
Header
using regular expressions.When the name of the
Header
is unknown in advance, but can be matched against a regular expression, you can useHeader.regex
to extract it. Thename
of theHeader
should be supplied as a regular expression inside a group, i.e. between(
and)
.For example the following code will match the
Header
whosename
is a 10 character string containing letters and digits:(setv csrf_token (Header.regex "([a-zA-Z0-9]{10})"))
- classmethod basicauth(username, password)[source]
Creates a basic authentication
Header
.Given the username and the password for the basic authentication, returns the
Header
object with the propervalue
, i.e. with thename
asAuthorization
and thevalue
asBasic `` followed by base64 encoded ``username:password
.For example:
(setv my_function (Flow :request (Request :method "GET" :url "https://www.example.com/my_function" :headers [(Header.basicauth "username" "password")])))
- classmethod bearerauth(access_token)[source]
Creates a bearer authentication
Header
.Given the
access_token
as aPlugin
, extracts itsvalue
and returns aHeader
object with the correctvalue
to be passed as the Bearer Authorization string in theHeader
, i.e. with thename
asAuthorization
and thevalue
as ``Bearer `` followed by the value from parentPlugin
For example if we extract the
access_token
from JSON:(setv access_token (Json :name "access_token" :extract "token")) (setv get_token (Flow :request (Request :method "POST" :url "https://www.example.com/login" :data {"username" "username" "password" "password"}) :outputs [access_token]))
And use it later as a bearer authentication
Header
:(setv my_function (Flow :request (Request :method "GET" :url "https://www.example.com/my_function" :headers [(Header.bearerauth access_token)])))
- classmethod from_plugin(parent_plugin, name)[source]
Creates a
Header
from anotherPlugin
.Given another
Plugin
, and aname
, create aHeader
. Unlikebasicauth()
andbearerauth()
no string will be added to the beginning ofHeader
value
, so this class method can be used for other arbitraryHeaders
not justAuthorization
ones.
Example:
(setv access_token
(Regex
:name "access_token" ;; Extracts `access_token` using
:regex "\"accessToken\":\"([^\"]+)\"")) ;; regular expressions.
(setv user_id
(Json ;; Uses the Json Plugin
:name "user_id" ;; To extract `user_id`.
:extract "user_id"))
(setv authheader (Header.bearerauth access_token)) ;; Defines bearer authorization header.
(setv useragent (Header "User-Agent" "Mozilla/5.0")) ;; Static user agent.
(setv username (Variable "username"))
(setv password (Variable "password"))
(setv login
(AuthFlow
:request
(Request
:method "POST"
:url "https://www.example.com/login"
:headers [useragent ;; Sets the user agent.
(Headers.from_plugin ;; Creates new header from ``user_id``
user_id ;; Plugin and uses it in the value of
"X-identification") ;; X-identification customer header.
:data
{"username" username
"password" password})
:outputs [access_token])) ;; Extracts the `access_token`.
(setv my_function
(Flow
:name "my_function"
:request (Request
:method "GET"
:url "https://www.example.com/my_function"
:headers [authheader])))
File
The File plugin sets the plugin’s value
to the contents of a provided file
and allows string substitution within the content.
- class File(path, function=None, flags=0)[source]
Plugin
used for getting data from the filesystem.Use
File
:Plugin
when needing to upload something, or sending a Request with lots of data that would better be stored on the filesystem instead of hyfiles.- function
A Callable which will be called to extract the
value
of thePlugin
when used as an input in a Flow. The function should setself.value
and also return it. By default forFile
Plugins
it puts the unmodified contents of theFile
found in thepath
.
- name_function
A Callable which will be called to extract the
name
of thePlugin
when it’s not known in advance and the flagNAME_NOT_KNOWN_IN_ADVANCE
is set.File
doesn’t use this.
- plugins
A List of
Plugins
whosevalue
needs to be extracted first before currentCookie's
value can be extracted. Used when the flagDEPENDS_ON_OTHER_PLUGINS
is set.
- value
A string containing the
File's
outputvalue
to be used as input in the HTTP Requests which is just theFile
contents.
- flags
An integer containing the flags that define the
Plugin's
behaviour. ForFile
:class:`Plugins no flags are set by default.
- __init__(path, function=None, flags=0)[source]
-
Creates a
File
Plugin
, and populates itsvalue
with the contents of aFile`
from the filesystem.- Parameters
- read_file()[source]
Sets the
Plugin's
value
to the file contents.- Return type
bytes
- Returns
A Bytes string containing the raw file contents.
- classmethod replace(path, old_value, new_value)[source]
Read a
File
and replace strings with new ``value``s.Use this in case the
File
is a template that needs some part of it replaced with a new string, for example:If we have the file
data.json
:{"data": "username": $USERNAME$, "nickname": "nickname", [...] }
And we want to replace
$USERNAME$
with the real username, we can use:(File.replace "/path/to/data.json" "$USERNAME$" "admin")
To replace every instance of
$USERNAME$
with our chosenvalue
innew_value
.
Command
The Command plugin runs shell commands and extracts their output.
- class Command(name, command)[source]
Use this to run a shell command and extract the output.
- __init__(name, command)[source]
Initializes the Command Plugin.
The specified command will be executed with os.popen() and the output with the stripped last newline, will be saved inside the
value
.- Parameters
name (
str
) – A unique identifier for the plugin.command (
str
) – The command to be executed.
- run_command()[source]
Runs a command and returns its
value
.Given a dictionary with the predefined variables, return the
value
of the with the same name as the “name” attribute from this Plugin.- Parameters
data – A dictionary with the predefined variables.
- Return type
Optional
[str
]- Returns
A string with the
value
of the variable found. None if no such variable has been defined.
Example:
(setv mfa_code (Command
:name "otp"
:command "pass otp personal/app1"))
Regex
The Regex plugin extracts a matched expression from the HTTP response.
- class Regex(name, regex, function=None, flags=2)[source]
Plugin class to extract regular expressions.
This plugin will match the regex provided, and extract the
value
inside the first matched group. A group is the string that matched inside the brackets.For example if the regular expression is:
“accessToken”:”([^”]+)”
and the text to match it against contains:
“accessToken”:”0123456789abcdef”
then only the string “0123456789abcdef” will be extracted and saved in the
value
attribute.- regex
A string containing the regular expression to be matched.
- __init__(name, regex, function=None, flags=2)[source]
Initializes the Regex Plugin.
Creates a Regex Plugin with the given regular expression, and extracts the matched group given in the “extract” argument, or the first matching group if not specified.
- Parameters
name (
str
) – A string with the name of the Plugin.regex (
str
) – A string containing the regular expression to be matched.
- extract_regex_from_response(response)[source]
Extracts regex from a HTTP response.
- Return type
Optional
[str
]
- extract_regex(text)[source]
Extracts defined regular expression from a text.
Given a text to be searched for matches, return the string inside the group defined in “extract” or the first group if it’s undefined.
- Parameters
text (
str
) – A string containing the text to be searched for matches.- Return type
Optional
[str
]- Returns
A string with the match from the extracted group. Returns None if there are no matches.
Example:
(setv access_token
(Regex
:name "access_token"
:regex "\"accessToken\":\"([^\"]+)\""))
Html
The Html plugin extracts tags matching attributes specified by the user.
- class Html(name, tag, attributes, extract)[source]
This Plugin will find the HTML “tag” containing the specified “attributes” and store the “extract” attribute of the matched tag in its
value
attribute.- tag
A string defining the HTML tag to look for.
- attributes
A dictionary with attributes matching the desired HTML tag. The keys in the dictionary are strings matching the tag’s attributes, and the
value``s are treated as regular expressions, to help match tags that don't have a static ``value
.
- extract
A string defining the HTML tag’s attribute that needs to be extracted and stored inside
value
.
- __init__(name, tag, attributes, extract)[source]
Initializes the Html Plugin.
Creates a Html Plugin with the given “tag” and “attributes”. Stores the “extract” attribute in the plugin’s
value
.- Parameters
name (
str
) – A string with the name of the Plugin.tag (
str
) – A string with the HTML tag to look for.attributes (
Dict
[Keyword
,str
]) – A hy dictionary with the attributes to look inside HTML tags. The ``value``s of dictionary elements are treated as regular expressions.extract (
str
) – A string with the HTML tag attribute that needs to be extracted and stored in the Plugin’s object.
- extract_html_tag(response)[source]
Extract data from an HTML tag.
Given the HTML text, parses it, iterates through the tags, and find the one matching the attributes. Then it stores the matched
value
and returns it.- Parameters
text – A string containing the HTML text to be processed.
- Return type
Optional
[str
]- Returns
A string with the match as defined in the Plugin. Returns None if there are no matches.
Example:
(setv csrf_token
(Html
:name "csrf_token"
:tag "input"
:attributes
{:name "csrf_token"
:value "^[0-9a-f]{40}$"
:type "hidden"}
:extract "value"))
Json
The Json plugin extracts fields from JSON tables.
- class Json(name, extract, function=None, flags=2)[source]
The “extract” attribute is used to specify which field to store in the
value
. Using the dot.
character you can go deeper inside the JSON object. To look inside an array, use square brackets [].Keys with special characters should be written inside double quotes
"
. Keep in mind that when written insidehyfiles
, it’ll already be between double quotes, so you’ll have to escape them with the backslash character\
.Examples
env.production[0].field
production.keys[1].x5c[0][1][0]."with space"[3]
- extract
A string defining the location of the field that needs to be extracted. For now this is still quite primitive, and cannot access data from JSON arrays.
- __init__(name, extract, function=None, flags=2)[source]
Initializes the Json Plugin.
Creates the Json Plugin and extracts the specified field.
- Parameters
name (
str
) – A string with the name of the Plugin.extract (
str
) – A string with the location of the JSON field to extract.
- extract_json_from_response(response)[source]
Extracts the json field from a HTTP response.
- Return type
Optional
[str
]
- extract_json_from_plugin()[source]
Extracts the json field from a plugin.
- Return type
Optional
[str
]
- extract_json_field(text)[source]
Extracts the JSON field from the text.
Given the JSON body as a string, extract the field and store it in the Plugin’s
value
attribute.- Parameters
text (
str
) – A string with the JSON body.- Return type
Optional
[str
]- Returns
A string with the result of extraction. If no such field is found None will be returned.
Modifiers
Alter
The Alter plugin extracts and alters the value
of other plugins.
- class Alter(parent_plugin, alter_function=None)[source]
If the value extracted from other plugins cannot be used in it’s raw form and needs to be somehow processed, Alter plugin can be used to do that. Initialize it with the original plugin and a function which will process the string and return the modified value.
- alter_function
A function which will be given the plugin’s value. It should return a string with the processed value.
- __init__(parent_plugin, alter_function=None)[source]
Initializes the Alter Plugin.
Given the original plugin, and a function to alter the data, initialize the object, and get the modified value.
- Parameters
plugin – The original Plugin where the value is to be found.
alter_function (
Optional
[Callable
[[str
],Optional
[str
]]]) – The Function with instructions on how to alter the value.
- process_value()[source]
Process the original plugin’s value.
Gives the original plugin’s value to
alter_function
. Return the processed value and store it in self.value.- Return type
Optional
[str
]- Returns
A string with the processed value.
Combine
The Combine plugin concatenates the value
of other plugins.
Parsers
Urlparser
The URLParser plugin parses URLs and extracts elements from it.
- class Urlparser(parent_plugin, element)[source]
Parse the URL and extract elements from it.
Use this when needing to extract some piece of information from the URL.
- __init__(parent_plugin, element)[source]
Initializes the
Parser
Plugin
.Creates a
Parser
object, holding afunction
defining how to parse the parentPlugin
in order to extract thevalue
. Only the flagDEPENDS_ON_OTHER_PLUGINS
is preset, since it needs to extract thevalue
from otherPlugins
, and those need to be extracted first.- Parameters
name – A String with the unique identifier of the
Parser
.function – A Callable function that will be used to extract the
Parser's
value
.value – A String with the extracted
value
from thePlugin
.
Processors
Urlencode
The Urlencode plugin URL encodes a processor plugin.
Urldecode
The Urldecode plugin URL decodes a processor plugin.
B64encode
The B64encode plugin base64 encodes a processor plugin.
B64decode
The B64decode plugin base64 decodes a processor plugin.
Writing custom plugins
In case the existing plugins are not enough, the user can write their own to add the new functionality. Those new plugins should be written in the project’s configuration directory in a “.hy” file. To do this, a new class has to be defined, which will inherit from Raider’s Plugin class:
Let’s assume we want a new plugin that will use unix password store to extract the OTP from our website.
(defclass PasswordStore [Plugin]
;; Define class PasswordStore which inherits from Plugin
(defn __init__ [self path]
;; Initiatialize the object given the path
(.__init__ (super)
:name path
:function (. self run_command)))
;; Call the super() class, i.e. Plugin, and give it the
;; path as the name identifier, and the function
;; self.run_command() as a function to get the value.
;;
;; We don't need the response nor the user data to use
;; this plugin, so no flags will be set.
(defn run_command [self]
(import os)
;; We need os.popen() to run the command
(setv self.value
((. ((. (os.popen
(+ "pass otp " self.path))
read))
strip)))
;; set self.value to the output from "pass otp",
;; with the newline stripped.
(return self.value)))
And we can create a new variable that will use this class:
(setv mfa_code (PasswordStore "personal/reddit"))
Now whenever we use the mfa_code
in our requests, its value
will
be extracted from the password store.
Operations
Raider operations are pieces of code that will be executed when the HTTP response is received. The most important one is NextStage which controls the authentication flow. But anything can be done with the operations, and Raider allows writing custom ones in hylang to enable users to add functionality that isn’t supported by the main code.
NextStage
Inside the Authentication object NextStage is used to define the next step of the authentication process. It can also be used inside “action” attributes of the other Operations to allow conditional decision making.
(NextStage "login")
Print
When this Operation is executed, it will print each of its elements in a new line.
(Print
"This will be printed first"
access_token
"This will be printed on the third line")
(Print.body)
(Print.headers)
(Print.headers "User-agent")
(Print.cookies)
(Print.cookies "PHPSESSID")
- class Print(*args, flags=4, function=None)[source]
Operation that prints desired information.
When this Operation is executed, it will print each of its elements in a new line.
- \*args
A list of Plugins and/or strings. The plugin’s extracted values will be printed.
- __init__(*args, flags=4, function=None)[source]
Initializes the Print Operation.
- Parameters
*args (
Union
[str
,Plugin
]) – Strings or Plugin objects to be printed.
Save
When this Operation is executed, it will save its elements in a file.
(Save "/tmp/access_token" access_token)
(Save "/tmp/session" session_id :append True)
(Save.body "/tmp/body")
- class Save(filename, plugin=None, save_function=None, flags=0)[source]
Operation to save information to files.
- filename
The path to the file where the data should be saved.
- __init__(filename, plugin=None, save_function=None, flags=0)[source]
Initializes the Save operation.
- Parameters
filename (
str
) – The path of the file where data should be saved.plugin (
Optional
[Plugin
]) – If saving Plugin’s value, this should contain the plugin.save_function (
Optional
[Callable
[...
,None
]]) – A function to use when writing the file. Use when needing some more complex saving instructions.flags (
int
) – Operation’s flags. No flag is set by default. Set WILL_APPEND if needed to append to file instead of overwrite.
- save_to_file(content)[source]
Saves a string or plugin’s content to a file.
Given the content (a string or a plugin), open the file and write its contents. If WILL_APPEND was set, append to file instead of overwrite.
- Parameters
content (
Union
[str
,Plugin
,Response
]) – A string or a Plugin with the data to be written.- Return type
None
- classmethod body(filename, append=False)[source]
Save the entire HTTP body.
If you need to save the entire body instead of extracting some data from it using plugins, use
Save.body
. Given a filename, and optionally a booleanappend
, write the body’s contents into the file.- Parameters
filename (
str
) – The path to the file where to write the data.append (
bool
) – A boolean which when True, will append to existing file instead of overwriting it.
- Return type
- Returns
A Save object which will save the response body.
Error
Operation that will exit Raider and print the error message.
(Error "Login failed.")
Http
(Http
:status 200
:action
(NextStage "login")
:otherwise
(NextStage "multi_factor"))
- class Http(status, action, otherwise=None)[source]
Operation that runs actions depending on the HTTP status code.
A Http object will check if the HTTP response status code matches the code defined in its “status” attribute, and run the Operation inside “action” if it matches or the one inside “otherwise” if not matching.
- status
An integer with the HTTP status code to be checked.
- action
An Operation that will be executed if the status code matches.
- otherwise
An Operation that will be executed if the status code doesn’t match.
- __init__(status, action, otherwise=None)[source]
Initializes the Http Operation.
- Parameters
status (
int
) – An integer with the HTTP response status code.action (
Union
[Operation
,List
[Operation
],None
]) – An Operation object to be run if the defined status matches the response status code.otherwise (
Union
[Operation
,List
[Operation
],None
]) – An Operation object to be run if the defined status doesn’t match the response status code.
Grep
(Grep
:regex "TWO_FA_REQUIRED"
:action
(NextStage "multi_factor")
:otherwise
(Print "Logged in successfully"))
- class Grep(regex, action, otherwise=None)[source]
Operation that runs actions depending on Regex matches.
A Grep object will check if the HTTP response body matches the regex defined in its “regex” attribute, and run the Operation inside “action” if it matches or the one inside “otherwise” if not matching.
- regex
A string with the regular expression to be checked.
- action
An Operation that will be executed if the status code matches.
- otherwise
An Operation that will be executed if the status code doesn’t match.
Writing custom operations
In case the existing operations are not enough, the user can write their own to add the new functionality. Those new operations should be written in the project’s configuration directory in a “.hy” file. To do this, a new class has to be defined, which will inherit from Raider’s Operation class:
- class Operation(function, flags=0, action=None, otherwise=None)[source]
Parent class for all operations.
Each Operation class inherits from here.
- function
A callable function to be executed when the operation is run.
- flags
An integer with the flags which define the behaviour of the Operation. For now only two flags are allowed: NEEDS_RESPONSE and IS_CONDITIONAL. If NEEDS_RESPONSE is set, the HTTP response will be sent to the “function” for further processing. If IS_CONDITIONAL is set, the function should return a boolean, and if the return value is True the Operation inside “action” will be run next, if it’s False, the one from the “otherwise” will be run.
- action
An Operation object that will be run if the function returns True. Will only be used if the flag IS_CONDITIONAL is set.
- otherwise
An Operation object that will be run if the function returns False. Will only be used if the flag IS_CONDITIONAL is set.
- __init__(function, flags=0, action=None, otherwise=None)[source]
Initializes the Operation object.
- Parameters
function (
Callable
[...
,Any
]) – A callable function to be executed when the operation is run.flags (
int
) – An integer with the flags that define the behaviour of this Operation.action (
Union
[Operation
,List
[Operation
],None
]) – An Operation object that will be run when the function returns True.otherwise (
Union
[Operation
,List
[Operation
],None
]) – An Operation object that will be run when the function returns False.
- run(pconfig, response)[source]
Runs the Operation.
Runs the defined Operation, considering the “flags” set.
- Parameters
response (
Response
) – A requests.models.Response object with the HTTP response to be passed to the operation’s “function”.- Return type
Optional
[str
]- Returns
An optional string with the name of the next flow.
- run_conditional(response)[source]
Runs a conditional operation.
If the IS_CONDITIONAL flag is set, run the Operation’s “function” and if True runs the “action” next, if it’s False runs the “otherwise” Operation instead.
- Parameters
response (
Response
) – A requests.models.Response object with the HTTP response to be passed to the operation’s “function”.- Return type
Optional
[str
]- Returns
An optional string with the name of the next flow.
- property needs_response: bool
Returns True if the NEEDS_RESPONSE flag is set.
- Return type
bool
- property needs_userdata: bool
Returns True if the NEEDS_USERDATA flag is set.
- Return type
bool
- property is_conditional: bool
Returns True if the IS_CONDITIONAL flag is set.
- Return type
bool
- property will_append: bool
Returns True if the WILL_APPEND flag is set.
- Return type
bool
Users
Use the Users
class when setting up your users in hyfiles
like this:
(setv users
(Users
[{"admin" ;; username
"password" ;; password
:nickname "admin"} ;; extra optional data
{"user1" "password1"
:attribute "blah"
:nickname "mynickname"
:email "admin@example.com"}]))
Create the Users object by giving it a list where
each list item is a dictionary
with user data. Each user entry is required to have at least on
key:value
pair which is assumed to be username:password
and
can therefore be accessed by the Variable
Plugin
as (Variable "username")
and
(Variable "password")
respectively.
To use the optional user data, do the same but replace
username/password with the symbol name you specified earlier, for
example (Variable "nickname")
will return admin
if the first
user is active and mynickname
if the second one is.
- class Users(users=None, active_user='DEFAULT')[source]
Class holding all the users of the application.
Users inherits from
DataStructure
, and contains the users set up in hyfiles. Each user is anUser
object. The data from aUsers
object can be accessed same way like from theDataStore
.
The Users
class inherits from DataStore
where each element is a User
class containing data about a single user:
- class User(username=None, password=None, **kwargs)[source]
Class holding user related information.
User
objects are created inside theUsers
. EachUser
object contains at least theusername
and thepassword
. Every time aPlugin
generates an output, it is saved in theUser
object. If thePlugin
is aCookie
or aHeader
, the output will be stored in the thecookies
andheaders
attributes respectively. Otherwise they’ll be saved insidedata
.- username
A string containing the user’s email or username used to log in.
- password
A string containing the user’s password.
- cookies
A
CookieStore
object containing all of the collected cookies for this user. TheCookie
plugin only writes here.
- headers
A
HeaderStore
object containing all of the collected headers for this user. TheHeader
plugin only writes here.
- __init__(username=None, password=None, **kwargs)[source]
Initializes a
User
object.Creates an object for easy access to user specific information. It’s used to store the
username
,password
,cookies
,headers
, and otherdata
extracted from thePlugin
objects.- Parameters
username (
Optional
[str
]) – A string with the username used for the login process.password (
Optional
[str
]) – A string with the password used for the login process.**kwargs (
Dict
[str
,str
]) – A dictionary with additional data about the user.
- set_cookie(cookie)[source]
Sets the
cookies
for the user.Given a
Cookie
object, update the user’scookies
attribute to include thisCookie's
value.
- set_cookies_from_dict(data)[source]
Set user’s
cookies
from a dictionary.Given a dictionary of cookie values as strings, convert them to
Cookie
objects, and load them in theUser
object respectively.- Parameters
data (
Dict
[str
,str
]) – A dictionary of strings corresponding to cookie keys and values.- Return type
None
- set_header(header)[source]
Sets the
headers
for the user.Given a
Header
object, update the user’sheaders
attribute to include this header value.
- set_headers_from_dict(data)[source]
Set user’s
headers
from a dictionary.Given a dictionary of header values as strings, convert them to
Header
objects, and load them in theUser
object respectively.- Parameters
data (
Dict
[str
,str
]) – A dictionary of strings corresponding to header keys and values.- Return type
None
- set_data(data)[source]
Sets the
data
for the user.Given a
Plugin
, update the user’sdata
attribute to include this data.
Warning
Fuzzing isn’t yet functional in Raider
Fuzzing
- class Fuzz(project, flow, fuzzing_point, flags=0)[source]
Fuzz an input.
- __init__(project, flow, fuzzing_point, flags=0)[source]
Initialize the Fuzz object.
Given a
Flow
, a fuzzing point (in case of Raider this should be aPlugin
), and a function, run the attack. The function is used to generate the strings to be used for fuzzing. Thefuzzing_point
attribute should contain the name of the plugin.- Parameters
project (
Project
) – AnProject
object.fuzzing_point (
str
) – The name given to thePlugin
which should be fuzzed.fuzzing_generator – A function which returns a Python generator, that will create the strings that will be used for fuzzing. The function should accept one argument. This will be the value of the plugin before fuzzing. It can be considered when building the fuzzing list, or ignored.
- set_input_file(filename, prepend=False, append=False)[source]
Sets the input file for the fuzzer.
Uses the input file to generate fuzzing strings, and sets the generator function to return those values.
- Return type
None
- attack_function()[source]
Attacks a flow defined in
_functions
.Fuzz blindly the Flow object. It doesn’t take into account the authentication process, so this function is useful for fuzzing stuff as an already authenticated user.
- attack_authentication()[source]
Attacks a Flow defined in
_authentication
.Unlike
attack_function
, this will take into account the finite state machine defined in the hyfiles. This should be used when the authentication process can be altered by the fuzzing, for example if some token needs to be extracted again from a previous authentication step for fuzzing to work.It will first follow the authentication process until reaching the desired state, then it will try fuzzing it, and if a
Next
operation is encountered, it will follow the instruction and move to this flow, then continue fuzzing.- Return type
None
- property is_authentication: bool
Returns True if the IS_AUTHENTICATION flag is set.
- Return type
bool
Main Raider class
- class Raider(name=None, flags=0, args=None)[source]
Main class used as the point of entry.
The Raider class should be used to access everything else inside Raider. For now it’s still not doing much, but for the future this is where all of the features available to the end user should be.
- project
An
Project
object with the currently active project.
- config
A Config object containing all of the necessary settings.
- user
A User object containing the active user of the active project.
- functions
A Functions object containing the defined functions of the active project.
- __init__(name=None, flags=0, args=None)[source]
Initializes the Raider object.
Initializes the main entry point for Raider. If the name of the project is supplied, this project will be used, otherwise the last used project will be chosen.
- Parameters
name (
Optional
[str
]) – A string with the name of the project.flags (
int
) – An integer with the flags. Only SESSION_LOADED is supported now. It indicates the authentication was not performed from the start, but loaded from a previously saved session file, which means the plugins should get their value from userdata.
- fuzz(flow_name, fuzzing_point)[source]
Fuzz a function with an authenticated user.
Given a function name, a starting point for fuzzing, and a function to generate the fuzzing strings, run the attack.
- fix_function_plugins(function)[source]
Given a function name, prepare its Flow to be fuzzed.
For each plugin acting as an input for the defined function, change its flags and function so it uses the previously extracted data instead of extracting it again.
- Return type
None
- property flowstore: FlowStore
Returns the Authentication object
- Return type
FlowStore
- property session_loaded: bool
Returns True if the SESSION_LOADED flag is set.
- Return type
bool
Config
Config class holding global Raider configuration.
- class Config[source]
Class dealing with global Raider configuration.
A Config object will contain all the information necessary to run Raider. It will define global configurations like the web proxy and the logging level, but also the data defined in the active project configuration files.
- proxy
An optional string to define the web proxy to relay the traffic through.
- verify
A boolean flag which will let the requests library know whether to check the SSL certificate or ignore it.
- loglevel
A string used by the logging library to define the desired logging level.
- user_agent
A string which will be used as the user agent in HTTP requests.
- active_project
A string defining the current active project.
- project_config
A dictionary containing all of the local variables defined in the active project’s hy configuration files.
- logger
A logging.RootLogger object used for debugging.
- __init__()[source]
Initializes the Config object.
Retrieves configuration from “common.hy” file, or populates it with the default values if it doesn’t exist.