For the best chance of success in payload development we highly recommend reading all of the available documentation, but here is a cheat-sheet for speedrunning understanding payloads.

Interpreter line

Every shell script starts with a special line, which tells Linux what interpreter to use to run the script (in our case, bash, for other scripts this could be Python, zsh, or others).

Payloads on the WiFi Pineapple are run under a specially configured environment which always executes under Bash; the interpreter line is not required. Including it, however, will not cause a problem.

If present, an interpreter line starts with #! and includes the path to the shell interpreter:

  #!/bin/bash
  

Comments

Comments in payloads are indicated by the hash symbol: #. Anything following a hash is ignored as a comment.

  # This whole line is a comment

echo foo        # from here on is a comment
  

Comments are a good way to indicate intent and organize code, but remember - what matters is what the code does, not what the comments say! When reading a payload to learn what it does, trust the code!

Payload information

Payload authorship and information is configured with a set of standard comments at the top of the payload:

  # Title: An awesome payload title
# Description: A longer description about the payload functionality
# Author: Your Name <yourname@youremail.com>
  

The information comments are used by the UI to show more information about a payload and to give credit in the payload repository.

Variables

Variables store data under a name for use later in a script.

There are multiple types of variables in a Payload:

  1. Environment variables: These variables are set by the shell and are available to all programs that run in the shell environment. Examples include $PATH, which contains a list of directories to search for executable files, and $HOME, which contains the user’s home directory. Environment variables are used in Payloads to send extra data in alert and recon payloads.
  2. User-defined variables: These variables are created by the user in the script and can be used to store any type of data. They are typically created using the syntax varname=value, where varname is the name of the variable and value is the value to be assigned to it. For example, name="John" creates a variable called name with the value "John".
  3. Positional parameters: These variables are used to store arguments passed to a script or function when it is launched. The first argument is stored in $1, the second argument in $2, and so on. For example, if a script is called with the command ./myscript.sh arg1 arg2, then $1 would contain "arg1" and $2 would contain "arg2". Payloads are not executed with arguments, so the positional parameters will always be empty, but positional arguments are also used for functions.
  4. Process and result variables: These variables are set automatically by bash to reflect the behavior of recently executed processes. Among others, bash manages the interval variables $! which holds the process ID of the last backgrounded process, $? which holds the exit status of the last command, and $$ which holds the process ID of the currently running script itself. These allow scripts to execute background commands, retrieve the results of a command, and manage commands and functions run in the background.

Variables can be referenced in a script using the syntax $varname, where varname is the name of the variable. For example, echo $name would print the contents of the variable "name" to the screen. Variables can also be used in calculations or as arguments to other commands.

It’s important to note that variable names are case-sensitive in bash!

Variables can also be printed with the syntax ${varname}, such as echo ${varname}. This works the same as $varname.

Quotes

Quotes have special meaning.

Double quotes (")

Double quotes ensure a string is treated as a single argument. This is important in several ways:

  1. Some commands expect specific argument ordering. If you want to pass multiple words to an argument, they need to be enclosed in quotes!
  2. Some characters have special meaning (like ', #, ;). Using quotes makes sure the payload treats them as text!
  echo "I'm a sentence with special characters; this wouldn't work without quotes!"
  

Within double-quotes, variables are still treated normally.

  myvar="beans"
echo "I want to print some ${beans}"
  

Single quotes ("’")

Single quotes ensure a string is treated as a single argument, and disable any interpretation of special characters. This means variable expansion, command execution, and other special features are not processed!

  myvar="beans"
echo 'This will print literally ${beans}, not the content of the variable!'
  

Tests

The most basic test is if. There are many ways to write an if statement, however the simplest is to use the if [ test ]; then ... fi syntax.

  value=10
if [ $value -lt 20 ]; then
    echo "Less than 20!"
fi
  

Testing command success

When a command or function exits, it sets a return code. A return code of 0 indicates no error, while any other return code indicates an error.

The return code of a process is stored in the special variable $?.

To compare a number we use the comparison -ne (not equal):

  CONFIRMATION_DIALOG "Are you sure you want to continue?"
if [ $? -ne 0 ]; then
    LOG "User said no"
    exit 0
fi
  

You may also see a simpler syntax used: || automatically runs the next block of code if the command fails, and && runs the next block if the command succeeds.

  CONFIRMATION_DIALOG "Are you sure you want to continue?" || {
    LOG "User said no"
    exit 0
}
  

Often this is represented in an even shorter form - if no other action is required besides exiting:

  CONFIRMATION_DIALOG "Are you sure?" || exit 0
  

Getting the output of a command

Many DuckyScript commands print a result when the user has selected something.

In Payloads, this can be done with $(command...). Notice this uses normal parenthesis $(...), not curly braces!

  user_ip=$(IP_PICKER "Pick an IP" "1.2.3.4")

echo ${user_ip}
  

Combining output and success

The output of a command can be captured and the error code checked simultaneously! For example, to exit if a user cancels the IP picker…

  user_ip=$(IP_PICKER "Pick an IP" "1.2.3.4") || exit 0
  

Exiting payloads

The same return code which indicates if a command succeeded or not is used to determine if a payload executed properly.

The return code is set via the exit function. A return code of 0 is considered a success, while any other number is considered a failure.

If a payload does not explicitly return a successful status, the status of the last command is sent.

To avoid the Pager reporting there was a problem running your payload, make sure to always include an exit 0:

  
# Title: Example

... do some things

exit 0