P4wnP1 A.L.O.A. by MaMe82 is a 框架 which turns a Rapsberry Pi Zero W into a flexible, low-cost platform for
pentesting, red teaming and physical engagements ... or into "A Little Offensi".
The latest image could be found under release tab.
The easiest way to access a fresh P4wnP1 A.L.O.A. installation is to use the web 客户端 via the spawned WiFi (the PSK
is MaMe82-P4wnP1, the URL ) or SSH (default password toor).
Math for mouse calculations etc.)So if you want to use a a batch file running on a remote Windows host to configure P4wnP1 ... no problem:
1) compile the client for windows
2) make sure you could connect to P4wnP1 somehow (Bluetooth, WiFi, USB)
3) add the host parameter to your client commands
4) ... and use the CLI as you would do with local access.
Although it wasn't planned initially, P4wnP1 A.L.O.A. can be configured using a webclient.
E the 客户端 wasn't planned, it e to a nice piece of software. In fact it ended up as the main
configuration tool for P4wnP1 A.L.O.A.
The webclient has capabilities, which couldn't be accessed from the CLI (templates storage, creation of
"TriggerActions").
The core features:
CTRL+SPACE)The automation approach of P4wnP1 A.L.O.A. had to fulfills these requirements:
With introducing of the so called "TriggerActions" and by combining them with the templating system (persistent settings
storage for all sub systems) all the requirements could be satisfied. Details on TriggerActions could be find in the
WorkFlow section.
P4wnP1 A.L.O.A. doesn't use concepts like static configuration or payloads. In fact it has no static workflow at all.
P4wnP1 A.L.O.A. is meant to be as flexible as possible, to allow using it in all possible scenarios (including the ones
I couldn't think of while creating P4wnP1 A.L.O.A.).
But there are some basic concepts, I'd like to walk through in this section. As it is hard to explain e without
creating a proper (video) documentation, I visit some common use cases and examples in order to explain what needs
to be explained.
Ne, it is unlikely that I'll have the time to provide a full-fledged documentation. **So I encourage e
to support me with tutorials and ideas, which could be linked back into this README**
Now let's start with one of the most basic tasks:
The minimum configuration requirement to achieve this goal is:
The default configuration of P4wnP1's (unmodified image) meets these requirements already:
MaMe82-P4wnP1172.24.0.1172.16.0.1P4wnP11337172.26.0.1root, the default password is toor*Note:
Deploying a HTTPS connection is currently not in scope of the project. So please keep this in mind, if you handle
sensitive data, like WiFi credentials, in the webclient. The whole project isn't built with security in mind (and it is
unlikely that this will ever get a requirement). So please deploy appropriate measures (f.e. restricting access
to webclient with iptables, if the Access Point is configured with Open Authentication; don't keep Bluetooth
Disco and Connectability enabled without PIN protection etc. etc.)*
At this point I assume:
1) You ha P4wnP1 to some target host via USB (the innermost of the Raspberry's micro USB ports is the one to
use)
2) The USB host runs an application, which is able to receive the keystrokes and has the current keyboard input focus
(f.e. a text editor)
3) You are remotely connected to P4wnP1 via SSH (the best way is WiFi), preferably the SSH connection is running from
a different host, then the the one which has P4wnP1 A.L.O.A. attached over USB
In order to run the CLI 客户端 from the SSH session, issue the following command:
The help screen already shows, that the CLI 客户端 uses different commands to interact with the subsystems of
P4wnP1 A.L.O.A. Most of these commands have own sub-commands, again. The help for each command or sub-command could be
accessed by appending -h to the CLI command:
Now, in order to type out "Hello world" to the USB host, the following CLI command could be used:
P4wnP1_cli hid run -c 'type("Hello world")'
The result output in the SSH session should look similar to this:
On the USB host "Hello World" should have been typed to the application with keyboard focus.
*If your SSH 客户端 runs on the USB host itself, the typed "Hello world" ends up somewhere between the resulting output
of the CLI command (it doesn't belong to the output, but has been typed in between).*
Goal achieved. We injected keystrokes to the target.
Much reading for a simple task like keystroke injection, but again, this section is meant to explain basic concepts.
If you managed to run the "Hello world" keystroke injection, this is a good point to explore some additional HIDScript
features.
We already know the type command, but let's try and discuss some more sophisticated HIDScript commands:
#### Pressing special keys and combinations
The type command supports pressing return, by encoding a "new line" character into the input string, like this:
But what about special keys or key combinations?
The press command comes to help!
Let's use press to send CTRL+ALT+DELETE to the USB host:
*Note: Two of keys have been modifiers (CTRL and ALT) and only one has been an actual key (DELETE)*
Let's press the key 'A' without any modifier key:
The resulting output should be a lowercase 'a', because press("A") interprets 'A' as key. The command type("A"),
on the other hand, tries to press a key combination which should result in an uppercase 'A' output character.
Let's combine a modifier and a non-modifier key, in order to produce an uppercase 'A' output character (mimic the
behavior of type("A"):
This should ha an uppercase A output.
It is important to understand, that press interprets the given its key arguments as keys, while type tries to find the
appropriate key combinations to produce the intended output characters.
In a last example, let's combine press and type.
The last command typed a string, toggled CAPSLOCK, typed another string and toggled CAPS lock again.
In result, CAPSLOCK should be in its initial state (toggled two times), but one of the strings is typed uppercase, the
other lowercase although both strings have been given in lower case.
Additional notes on key presses with press:
I don't want to dive into the depth of USB keyboard reports inner workings, but some things are worth mentioning to
pinpoint the limits and possibilities of the press command (which itself works based on raw keyboard reports):press
- LEFT_CTRL
- RIGHT_CTRL
- LEFT_ALT
- RIGHT_ALT
- LEFT_SHIFT
- RIGHT_SHIFT
- LEFT_GUI
- RIGHT_GUI
- CTRL == CONTROL == LEFT_CTRL
- ALT == LEFT_ALT
- SHIFT == LEFT_SHIFT
- WIN == GUI == LEFT_GUI consumes up to six normal or special keyspress("Z")
- normal keys represent characters and special keys
- example of special keys: BACKSPACE, ENTER (== RETURN), F1 .. F12)
- the keys are language layout agnostic ( results in USB_KEY_Z fo EN_US keyboard layout, but produces/usr/local/P4wnP1/keymaps/common.json
USB_KEY_Y for a German layout. This corresponds to pressing the hardware key 'Z' on a German keyboard, which would
produce a USB_KEY_Y, too.)
- holds a formatted JSON keymap with all possible keys (be careful not to press
change the file) command, doesn't produce a key sequence. All gi keys are press
pressed at the same time and release at the same time. releases keys automatically, this means a sequence like "hold ALT, press TAB, press TAB, release ALT"
currently isn't possible
#### Keyboard layout
The HIDScript command to change the keyboard layout is layout(<language map name>).
The following example switches keyboard layout to 'US' types something and switches the layout to 'German' before it
goes on typing:
The output result of the command gi, depends on the target layout used by the USB host.
On a host with German keyboard layout the result looks like this:
On a host with US keyboard layout it looks like this:
Please note, that the intended output is only achieved, if P4wnP1's keyboard layout aligns with the keyboard layout
actually used by the USB host.
The layout command allows to align P4wwP1's internal layout to the one of the target USB host.
Being able to change the layout in the middle of a running HIDScript, could come in handy: Who knows, maybe you like to
brute force the target host's keyboard layout by issuing commands with changing layouts till one of the typed commands
achieves the desired effect.
Important: The layout has global effect. This means if multiple HIDScripts are running concurrently and one of the
scripts sets a new layout, all other scripts are effected immediately, too.
#### Typing speed
By default P4wnP1 injects keystrokes as fast as possible. Depending on your goal, this could be a bit too much (think of
counter measures which prevent keystroke injection based on behavior analysis of typing speed). HIDScript supports a
command to change this behavior.
typingSpeed(delayMillis, jitterMillis)
The first argument to the typingSpeed command represents a constant delay in milliseconds, which is applied between
two keystrokes. The second argument is an additional jitter in milliseconds. It adds an additional random delay, which
scales between 0 and the gi in milliseconds, to the static delay provided with the first argument.
Let's try to use typingSpeed to slow down the typing:
Next, instead of a constant delay, we try a random jitter:
Finally, by combining and tuning both , we could simulate natural typing speed:
Important: The typing speed has global effect. This means if multiple HIDScripts are running concurrently and one of
the scripts sets a new typing speed, all other scripts are effected immediately, too.
#### Wait for LED report
Waiting for LED report, or to be precise LED state changes, is one of the more sophisticated keyboard features of
HIDScript. It could be very powerful but needs a bit of explanation.
You may ha that (depending on the USB host's OS) the keyboard state modifiers (NUM LOCK, SCROLL LOCK,
CAPS LOCK) are shared across multiple connected keyboards. For example, if you connect two keyboards to a Windows host,
and toggle CAPS LOCK on one of them, the CAPS LOCK LED changes on both keyboards.
Exactly this test could be used, to determine if the keyboard state modifiers are shared across all keyboards for a
given OS.
In case a USB host supports this kind of state sharing (for example Windows does), P4wnP1's HIDScript language could
make use out of it.
Imagine the following scenario:
P4wnP1 is connected to a USB host and you want to apply keystroke injection, but you don't want the HIDScript to
run the keystrokes immediately. Instead the HIDScript should sit and wait till you hit NUMLOCK, CAPSLOCK or SCROLLLOCK
on the host's real keyboard. Why? Maybe you're in in an engagement, somebody walked in and you don't want that
this exact "somebody" could see how magically a huge amount of characters are typed into a console window which suddenly
popped up. So you wait till "somebody" walks out, hit NUM LOCK and ultimately a console window pops up and a huge amount
of characters are magically type ... I think you got it.
The described behavior could be achieved like this:
If you tested the command abo should only start if NUM LOCK is pressed on the USB host's hardware keyboard,
but you might encounter cases where the keystrokes immediately are issued, even if NUM LOCK wasn't pressed (and the
keyboard LED hasn't hacnged).
This is intended behavior and the reason for this is another use case for the waitLED command:
Maybe you have used other keyboard scripting languages and other USB devices capable of injecting keystrokes, before.
Most of these devices share a common problem: You don't know when to start typing!
If you start typing immediately after the USB device is powered up, it is likely that the USB host hasn't finished
device enumeration and thus hasn't managed to bring up the keyboard drivers. Ultimately your keystrokes are lost.
To o this you could add a delay before the keystroke injection starts. But how long should this delay be? Five
seconds, 10 seconds, 30 seconds ?
The answer is: it depends! It depends on how fast the host is able to enumerate the device and bring up the keyboard
driver. In fact you couldn't know how long this takes, without testing against the actual target.
But as we ha learned, Operating Systems like Windows share the LED state across multiple keyboards.
This means if the NUMLOCK LED of the host keyboard is set to ON before you attach a second keyboard, the NUMLOCK LED
on this new keyboard has to be set to ON, too, once attached. If the NUM LOCK LED would have been set to OFF, anyways,
the newly attached keyboard receives the LED state (all LEDs off in this case). The interesting thing about this is,
that this "LED update" could only be send from the USB host to the attached keyboard, if the keyboard driver has
finished loading (sending LED state wouldn't be possible otherwise).
Isn't that beautiful? The USB host tells us: "I'm ready to recei". There is no need to play around with
initial delays.
But here is another problem: Assume we connect P4wnP1 to an USB host. We run a HIDScript starting with waitLED insteadwaitLED
of a hand crafted delay. Typing starts after the , but nothing happens - our keystrokes are lost, anyways! Why?
Because, it is likely that we missed the LED state update, as it arri we e our HIDScript.
Exactly this "race condition" is the reason why P4wnP1 preserves all recognized LED state changes, unless at least one
HIDScript consumes them by calling waitLED (or waitLEDRepeat). This could result in the behavior describe earlier,waitLED
where a returns immediately, e no LED change occurred. We now know: The LED change indeed occurred, waitLED
but it could ha much earlier (berfore we e the HIDScript), because the state change was preserved.
We also know, that this behavior is needed to avoid missing LED state changes, in case is used to test for
"USB host's keyboard dri".
*Note: It is worth mentioning, that waitLED returns ONLY if the received LED state differs from P4wnP1's internal waitLED(ANY)
state. This means, even if we listen for a change on any LED with it still could happen, that we receive waitLED(ANY)
an initial LED state from a USB host, which doesn't differ from P4wnP1's internal state. In this case waitLED(ANY_OR_NONE)
would block forever (or till a real LED change happens).
This special case could be handled by calling , which returns as soon as a new LED state arrive,
even if it doesn't result in a change.*
Enough explanation, let's get practical ... before we do so, we have to change the hardware setup a bit:
Attach an external power supply to the second USB port of the Raspberry Pi Zero (the outer one). This assures that
P4wnP1 doesn't loose power when detached from the USB host, as it doesn't rely on bus power anymore. The USB port which
should be used to connect P4wnP1 to the target USB host is the inner most of the two ports.
Now start the following HIDScript
Detach P4wnP1 from the USB host (and make sure it is kept powered on)! Reattach it to the USB host ...
Every time you reattach P4wnP1 to the host, "Attached" should be typed out to the host.
This taught us 3 facts:
1) waitLED could be used as initial command in scripts, to start typing as soon as the keyboard driver is readywaitLED
2) isn't the perfect choice, to pause HID scripts until a LED changing key is pressed on the USB host, as
preser changes could unblock the command in an unintended way
3) Pro more complex HIDScript as parameter to the CLI isn't very con
As we still aren't done with the waitLED command, we take care of the third fact, now. Let us leave the CLI.
)
na to the "HIDScript" tab in the now opened webclient
from there you could load and store HIDScripts (we don't do this for now, although ms_snake.js is a very good
example for the power of LED based triggers)Replace the script in the editor Window with the following one:
After hitting a run button, the right side of the window should show a new running HID job. If you press the little
"info" button to the right of the HIDScript job, you could see details, like its state (should be running), the job ID
and the VM ID (this is the number of the Ja this job. There are 8 of these VMs, so 8 HIDScripts could
run in parallel).
Now, if any LED change is emitted from the USB host (by toggling NUM, CAPS or SCROLL) the HIDScript job should end.
It still could be found under "Succeeded" jobs.
If you press the little "info" button again, there should be an information about the result value (encoded as JSON),
which looks something like this:
So the
waitLED command returns a Ja object looking like this:In my case,
NUM became true. In your case it maybe was CAPS. It doesn't matter which LED it was. "hat does matter is
the fact, that the return value gives the opportunity to examine the LED change which makes the command return and thus
it could be used to take branching decisions in your HIDScript (based on LED state changes issued from the USB host's
real keyboard).Let's try an example:
Assuming the gi is already running, pressing NUM on the USB host should result in typing out "NUM has been
toggled", while pressing SCROLL LOCK results in the typed text "SCROLL has been toggled". This behavior repeats, until
CAPS LOCK is pressed and the resulting LED change aborts the loop and ends the HIDScript.
Puhhh ... a bunch of text on this command for a single HIDScript command, but there still some things left.
We provided arguments like
NUM, ANY or ANY_OR_NONE to the waitLED command, without further explanation.The
waitLED accepts up to two arguments: The first argument, as you might ha, is a whitelist filter for the LEDs to watch. Valid arguments are:
ANY (react on a change to any of the LEDs)
ANY_OR_NONE (react on every new LED state, even if there's no change)
NUM (ignore all LED changes, except on the NUM LED)
CAPS (ignore all LED changes, except on the NUM CAPS)
SCROLL (ignore all LED changes, except on the NUM SCROLL)
multiple filters could be combined like this CAPS | NUM, NUM | SCROLLThe second argument, we haven't used so far, is a timeout duration in milliseconds. If no LED change occurred during
this timeout duration,
waitLED returns and has TIMEOUT: true set in the resulting object (additionally ERROR is
set to true and ERRORTEXT indicates a timeout).The following command would wait for a change on the NUM LED, but aborts waiting after 5 seconds:
E
waitLED is a very powerful command if used correctly, it hasn't helped to deal with our easy task of
robustly pausing a HIDScript till a state modifier key is pressed on the target USB host (remember: We wanted to pause
execution to assure the unwanted "somebody" walked out before typing starts, but waitLED occasionally returned early,
because of preserved LED state changes).This is where
waitLEDRepeat joins the game and comes to rescue.Paste the following script into the editor and try to make the command return. Inspect the HIDScript results afterwards.
You should quickly notice, that the same LED has to be changed multiple times frequently, in order to make the
waitLEDRepeat command return. The waitLEDRepeat command wouldn't return if differing LEDs change state or if the
LED changes on a single LED are occurring too slow. The argument provided to
waitLEDRepeat (which is ANY in the example) serves the exact same purpose as for waitLED.
It is a whitelist filter. For example waitLEDRepeat(NUM) would only return for changes of the NUM LOCK LED - no matter
how fast and often you'd hammer on the CAPS LOCK key, it wouldn't return unlees NUM LOCK is pressed frequently.By default, one of the whitelisted LEDs has to change 3 times and the delay between two successi mustn't be
greater than 800 milliseconds in order to make
waitLEDRepeat return. This behavior could tuned, by pro
additional arguments like shown in this example:So that's how to interact with LED reports from an USB host in HIDScript.
*Note:
waitLEDRepeat doesn't differ from waitLED, when it comes to consumption of preserved LED state changes.
Anyways, it is much harder to trigger it unintended.*So
waitLEDRepeat is the right choice, if the task is to pause HIDScripts till human interaction happens. Of course it
could be used for branching, too, as it provides the same return object as waitLED does. Up to this point we gained a good bit of knowledge about HIDScript (of course not about e, we haven't even
looked into mouse control capabilities of this scripting language). Anyways, this tutorial is about P4wnP1 A.L.O.A.
workflow and basic concepts. So we don't look into other HIDScript features, for now, and move on.
Let's summarize what we learned about P4wnP1's workflow and concepts so far:
we could start actions like keystroke injection from the CLI client, on-demand
we could use the webclient to achieve the same, while having additional control o jobs
if we connect an external power supply to P4wnP1 A.L.O.A., we attach/detach to/from different USB hosts and already
started HIDScripts go on working seamlessly
we could configure the USB stack exactly to our needs (and change its configuration at runtime, without rebooting
P4wnP1)
we could write multi purpose HIDScripts, with complex logic based on Ja (with support for functions, loops,
branching etc. etc.)3. Workflow part 2 - Templating and TriggerActions
Before go on with the other major concepts of P4wnP1 A.L.O.A. let's refine our first goal, which was to "run a keystroke
injection against a USB host":
The new goal is to type "Hello world" into the editor of a Windows USB host (notepad.exe).
The editor should be opened by P4wnP1 (not manually by the user).
The editor should automatically be closed, when any of the keyboard LEDs of the USB host is toggled.
E P4wnP1 is attached to the USB host, this behavior should repeat (with external power supply, no reboot of
P4wnP1)
The process *should only run once*, unless P4wnP1 is re-attached to the USB host, even if successi LED
changes occur after the HIDScript has been started.
Even if P4wnP1 is rebooted, the same behavior should be reco without recreating detail of the setup from
scratch, again.Starting notepad, typing "Hello world" and closing notepad after a LED change could be done with the things we learned
so far. An according HIDScript could look something like this:
The only thing new in this script is the
delay command, which doesn't need much explanation. It delays execution for
the gi of milliseconds. The script could be pasted into the webclient HIDScript editor and started with "run" in order to test it.
It should work as intended, so we are nearly done. In order to be able reuse the script, e a reboot, we store
it persistently. This could be achieved by hitting the "store" button in the HIDScript tab of the webclient. After
entering a name (we use
tutorial1 for now) and confirming the dialog, the HIDScript should have been stored.
We could check this, by hitting the "Load & Replace" button in the webclient. The stored script should occur in the list
of stored scripts with the name tutorial1.js (the .js extension is appended automatically, if it hasn't been
provided in the "store" dialog, already).**Warning: If a name of an already existing file used in the store dialog, the respective file gets o without
asking for further confirmation.**
Let's try to start the stored script using the CLI client from a SSH session, like this:
This should ha. This means, it is possible to start stored HIDScripts from all applications which support shell
commands or from a simple bash script, by using the P4wnP1 A.L.O.A. CLI client.
It would even be possible to start the script remotely from a CLI client compiled for Windows. Assuming the Windows host
is able to reach P4wnP1 A.L.O.A. via WiFi and the IP of P4wnP1 is set to
172.24.0.1 the proper command would look like
this:*Note: At the time of this writing, I haven't decided yet if P4wnP1 A.L.O.A. ships a CLI binary for each and every
possible platform and architecture. But it is likely that precompiled for major platforms are provided. If
not - this isn't a big problem, as cross-compilation of the CLI client's Go code takes less than a minute.*
The next step is to allow the script to run again, every time P4wnP1 is re-attached to a USB host. A approach we already
used to achieve such a behavior, was to wrap e into a loop and prepend a
waitLED(ANY_OR_NONE). The
waitLED(ANY_OR_NONE) assured tha the loop only continues, if the target USB host signals that the keyboard driver is
ready to recei by sending an update of the global keyboard LED sate. An accordingly modified script could look
like this:The script gi, indeed, would run, every time P4wnP1 is attached to an USB host. But the script isn't very
robust, because there's a second
waitLED in, which waits till notepad.exe should be is closed, again. Doing it like this in several issues. For example if P4wnP1 is detached before the "Hello world" is typed out, the
now blocking
waitLED would be the one before press("ALT F4") and execution would continue at exact this point of
the HIDScript once P4wnP1 is attached to a (maybe different) USB host, again.A definitive kill criteria for the chosen approach is the following problem: The requirement that the script should be
run only once after attaching P4wnP1 to an USB host couldn't be met, as hitting NUM LOCK multiple times would restart
the script over and over.
So how do we solve this ?
#### Let's introduce TriggerActions
The solution to the problem are so called "TriggerActions". As the name implies, this P4wnP1 A.L.O.A. workflow concept
fires actions based on predefined triggers.
To get an idea of what I'm talking about, head over to the "TRIGGER ACTIONS" tab on the webclient. Depending on the
current setup, there may already exist TriggerActions. We don't care for existing TriggerActions, now.
Hit the "ADD ONE" button and a new TriggerActions should be added and instantly opened in edit mode.
The new TriggerAction is disabled by default and has to be enabled in order to make it editable. So we toggle the enable
switch.
Now from the pull down menu called "Trigger" the option "USB gadget connected to host" should be selected. The action
should have a preset of "write log entry" selected. We leave it like this and hit the "Update" button.
The newly added TriggerAction should be in the TriggerActions o now (the one with the highest ID) and
show a summary of the selected Trigger and selected Action in readable form.
To test if the newly defined TriggerAction works, na over to the "Event Log" tab of the webclient.
Make sure you have the webclient opened via WiFi (not USB ethernet). Apply external power to P4wnP1, disconnect it from
the USB host and connect it again. A log message should be pushed to the client every time P4wnP1 is attached to a USB
host, immediately.
If you repeated this a few times, you maybe noticed that the "USB gadget connected to host" trigger fires very fast
(or in an early stage of USB enumeration phase). To be more precise: When this trigger fires, it is known that P4wnP1
was connected to a USB host, but there is no guarantee that the USB host managed to load all needed USB device drivers.
**In fact it is very unlikely that the USB keyboard driver is loaded when the trigger fires. We have to keep this in
mind.**
Before we move on with our task, we do an additional test. Heading back to the "TriggerAction" tab and we press the
little blue button looking like a pen for our newly created TriggerAction. We end up in edit mode again.
This time, we enable the
One shot option. Head back to the "Event Log" afterwards, and again, detach and re-attach
P4wnP1 from the USB host. This time the TriggerAction should fire only once. No matter how often P4wnP1 is re-attached
to the USB host afterwards, no new log message indicating a USB connect should be created. It is worth mentioning that a "One shot" TriggerAction isn't deleted after the Trigger has fired. Instead the
TriggerAction is disabled, again. Re-enabling allows reusing a TriggerAction without redefining it. Nothing gets lost
until the red "trash" button is hit on a TriggerAction, which will delete the respecti.
**Warning: If the delete button for a TriggerAction is clicked, the TriggerAction is deleted permanently without further
confirmation.**
At this point let's do the obvious. We edit the created TriggerAction and select "start a HIDScript" instead of "write
log entry" for the action to execute. Additionally we disable "one-shot", again. A new input field called "script name"
is shown. Clicking on this input field brings up a selection dialog for all stored HIDScripts, including our formerly
created
tutorial1.js HIDScript.*Before we test if this works, let me make a quick note on the action "write log entry": P4wnP1 A.L.O.A. doesn't keep
track of Triggers which ha be fired. This means the log entries created by a "write log entry" action are
delivered to all listening client, but aren't stored by the P4wnP1 service (for reasons). The webclient on the
other hand stores the log entry until the the webclient itself is reloaded. The same applies to events, which are
related to HIDScript jobs. If a HIDScript ends (with success or error), an event pushed to all currently open
webclients. In summary, each webclient has a runtime state, which holds more information than the core service, itself.
If the runtime state of the webclient grows to large (too much memory usage), one only needs to reload the client to
clear "historical" sate information. If the core service would behave the same and store every historical information,
it would run out of resources very soon. Thus this concept applies to most sub systems of P4wnP1 A.L.O.A.*
Now back to our task. We have a TriggerAction ready, which should fire our HIDScript every time P4wnP1 is attached to
an USB host.
Depending on the target USB host, this works more or less reliably. In my test setup it didn't work at all and there's
a reason:
Let's review the first few lines our HIDScript:
Recalling the fact, that the "USB gadget connected" Trigger fires in early USB enumeration phase and the USB host's
keyboard driver hasn't necessarily been loaded, the problem becomes obvious. We have to prepend some kind of delay to
the script to assure the keyboard driver is up (otherwise our keystrokes would end up in nowhere).
As we already know that it isn't possible to predict the optimal delay, we go with the
waitLED(ANY_OR_NONE) approach,
explained earlier. The new script looks like this:Storing the modified script under the exact same name (
tutorial1) o the former HIDScript without further
confirmation, as already pointed out. Thus there is no need to adjust our TriggerAction, as the HIDScript name the
TriggerAction refers hasn't changed.With this little change e should work as intended and the script should trigger e we attach to an USB
host, but only run once.
Now, if P4wnP1 is rebooted or looses power, our HIDScript would survi we ha it persistently, but the
TriggerAction would be gone. Needless to say, that TriggerActions could be stored persistently, too.
The "store" button in the "TriggerAction" tab works exactly like the one in the HIDScript editor. It should be noted
that *all currently acti* will be stored if the "store" dialog is confirmed (including the disabled
ones).
The best practice is to delete all TriggerActions which don't belong to the task in current scope before storing (they
should have been stored earlier, if needed) and to only store the small set of TriggerActions relevant to the current
task, using a proper name. There are two options to load back stored TriggerActions to the active ones:
- "load & replace" clears all acti actions and loads only the stored ones
- "load & add" keeps the already acti and adds in the stored ones. Thus "load & add" could be used to
build a complex TriggerAction set out of smaller sets. The resulting set could then, again, be stored.
For now we should only store our single TriggerAction, which starts out HIDScript. The name we use to store is
tutorial1 again and won't conflict with the HIDScript called tutorial1.Confirm successful storing, by hitting the "load&replace" button in the "TriggerAction" tab. The stored TriggerAction
set should be in the list and named
tutorial1.**Warning: The TriggerAction "load" dialogs allow deleting stored TriggerActions by hitting the red "trash" button
next to each action. Hitting the button permanently deletes the respecti set, without further
confirmation**
At this point we could safely delete our TriggerAction from the "TriggerActions" tab (!!not with the trash button from
one of the load dialogs!!).
With the TriggerAction deleted from the active ones, nothing happens if we detach and re-attach P4wnP1 from the USB
host.
Anyways, the stored TriggerAction set
tutorial1 will persists reboots and could be reloaded at anytime. Instead of reloading the TriggerAction set from with the webclient, we try to accomplish that using the CLI client.
Lets take a quick look into the help screen of the
template deploy sub-command:The usage screen shows, that TriggerAction Templates could be deployed with the
-t flag. We run the following command,
to restore the stored TriggerAction set:The TriggerAction which fires out HIDScript on USB host connections is now loaded again and should be shown in the
TriggerActions tab of the webclient. If P4wnP1 A.L.O.A. is attached to an USB host, the script should run again.
Storing, loading and deploying of templates is one of the two main concepts behind P4wnP1's automation workflow,
the other one are the already known TriggerActions. It is worth mentioning, that not only TriggerAction sets could be
stored and loaded as templates themselves, but that TriggerActions could be used to deploy already stored templates, if
that makes sense.
Re our tasks, it seems all defined requirements are met now:
we typed "Hello world" into the editor of a Windows USB host
the editor is opened by P4wnP1, not manually by the user
the editor is closed automatically, when one of the keyboard LEDs toggled once
every time P4wnP1 is attached to a USB host, this behavior repeats
the HIDScript runs only once, unless P4wnP1 is re-attached to the USB host, even if successi LED changes
occur
if P4wnP1 is rebooted, the same behavior could be recovered by loading the stored TriggerAction set (which again
refers to the stored HIDScript). This could either be achieved with a single CLI command or with a simple "load&add" or
"load&replace" from the webclient's trigger action tab.Once more let us add additional goals:
it should be assured, that the USB configuration has the keyboard functionality enabled (the current setup doesn't do
this and the TriggerAction couldn't start the HIDScript in case the USB keyboard is disabled)
the created setup should applied at boot of P4wnP1 A.L.O.A., without the need of manually loading of the TriggerAction
set. The setup has to survive a reboot of P4wnP1.To achieve the two additional goals, we have to dive into a new topic and ...
#### Introduce Master Templates and Startup Master Template
Before we look into Master Templates, we do something we haven't done, yet, because e just worked as intended
so far: We define a valid USB configurations, matching our task!
device serial number: 123456789
device product name: Auto Writer
device manufacturer: The Creator
Product ID: 0x9876
ID: 0x1D6B
enabled USB functions
- HID keyboard
- HID mouseLet's take a look into the usage screen of the CLI command, which could bes used to deploy these settings, first:
The command has a bunch of flags, but there exists a bunch of changeable USB settings, too.
Deploying our defined USB setup could be done like this, using the CLI:
The result output of the (longish) command shows the resulting USB settings. Let us check the "USB settings" tab of the
webclient to confirm that they have been applied. All changes should be reflected, if nothing went wrong.
Although it is perfectly possible to deploy a USB setup using the CLI, there are several benefits using the webclient
in favor of the CLI. In this case:
changing the settings from the webclient is easier and more con
the webclient holds an internal settings state, this allows defining USB settings without actually deploying them (the
CLI on the other hand, could only manipulate settings by deploying them. This, again, resets the while USB stack of
P4wnP1 and all dependent functionality. F.e. already running HIDScript would be interrupted or USB network interfaces
are redeployed
the current settings of the webclient could be stored to a persistent template, without deploying them upfront
the CLI client, (currently) isn't able to store USB settings In our current case, it is ob a better choice to use the webclient for the needed changes to the USB settings.
The good thing about the CLI approach (we already used here): As the CLI forced us to deploy the USB settings, we could
confirm that they are working, before we store them into a persistent template.
Let's go on with storing the USB settings:
Again we hit the "store" button, this time in the "USB settings" tab. Once more we call the template
tutorial1 (there
is no conflict with the TriggerAction template stored under the same name, because a different namespace is used for
USB settings).Now we have two new and persistently stored templates::
1) a template for the TriggerAction set, named
tutorial1
2) a template for the USB settings, also name tutorial1Assuming the state (of current USB settings, TriggerActions or both) changed somehow, we could reload both of the
stored settings at once, by issuing the following CLI command:
The command
P4wnP1 template deploy could load a template for each of the sub systems of P4wnP1 A.L.O.A. in a single
run (for the network subsystem multiple templates could be loaded, one per each adapter). Deploying templates for
subsystems is considered a common task while working with P4wnP1 A.L.O.A., because in most cases it should be
necessary to reconfigure several subsystems to reach a single goal. To account for this, so called *Master Templates*
have been introduced.A Master Template could consist of:
a already stored TriggerAction set template
a already stored USB settings template
a already stored WiFi settings template
a already stored Bluetooth settings template
multiple stored Network settings templates (one per each adapter) A Master Templated could be defined, stored or loaded, using the "Master Template Editor" from the "Generic Settings"
tab of the webclient. Using the webclient is a con way to define Master Templates, as it supports you by only
allowing to select templates, which have been already stored for the respective sub systems (and currently the
webclient is the only way to define Master Templates).
So lets define a Master Template for our current task:
1) Na to the "Generic Settings" tab of the webclient
2) On the "Master Template Editor" click on the small button on the right to the "TriggerActions Template" field
3) From the Dialog choose the
tutorial1 template and confirm with "OK" button
4) If you selected the wrong template, re-open the dialog and select a different one or use the "x" icon on the right
to "TriggerAction Template" to delete the current selection
5) Repeat the steps for the "USB Template" selection, again choose tutorial1 (which is a different template for
the USB sub system, although it shares the name with the one for the TriggerActions)
6) Check that the correct templates have been selected for bot, USB and TriggerActions, and all other Templates are left
empty
7) Store the new Master Template, by hitting the "Store" button and pro the name tutorial1To confirm if that the template has been stored, you could use the "Load Stored" button - the template should be listed
in the selection. Cancel the "Load Store" dialog again.
Now hit the "Deploy Stored" button, select the template named
startup and confirm with "OK".In contrast to the "Load Stored" function, which loads a stored template to the Master Template Editor, the
"Deploy Stored" function applies all settings of a Master Template to the corresponding sub systems of P4wnP1,
immediately (without e them to the Master Template Editor).
As the
startup Master Template o the current WiFi settings, it could happen that you have lost the connection
to the webclient and need to reconnect to the P4wnP1 WiFi network.Once you' successfully and inspect the current USB settings and current TriggerActions, the settings we
stored earlier have been o by the sub settings of the
startup Master Template.There are two ways to deploy the
tutorial1 Master Template again:
1) Deploying it using the "Deploy Stored" dialog from the "Master Template Editor" (as done with the startup Master
Template a minute, ago)
2) Deploying it using the CLI client with P4wnP1_cli template deploy --full tutorial1 (the --full flag is an alias
for Master Template)Beeing able to deploy the Master Template
tutorial1, we already achieved one of our new goals:It is assured, that the USB configuration has the keyboard functionality enabled when we load our keystroke injection
setup.
A quick summary on how this works:
the Master Template tutorial1 loads USB settings, called tutorial1 which have
- USB keyboard and USB mouse enabled
the Master Template tutorial1 loads a TriggerAction set with a single TriggerAction
- the TriggerAction starts the HID script tutorial1.js each time P4wnP1 gets attached to an USB host
- the HIDScript starts typing, once the waitLED trigger fires (keyboard dri) and ends after a successive
LED change The only remaining goal is the following: The created setup should applied at boot of P4wnP1 A.L.O.A., without the need
of manually loading of the TriggerAction set. The setup has to survive a reboot of P4wnP1.
This goal could be achie easy now. The "Generic Settings" tab of the webclient presents a card called
*Startup Master Template*. Changing the Startup Master Template to
tutorial1 at this point would ha effect
and it would likely *destroy the working boot configuration of P4wnP1 A.L.O.A.". **Important: If a Master Template has sub templates left empty (f.e. if there is no Bluetooth template selected), the
respective sub system isn't reconfigured when the Master Template is loaded. While this comes in handy for runtime
reconfiguration without resetting already running sub systems like the USB stack or WiFi stack if not needed, Master
Templates used as Startup Master Template leave sub systems without defined templates in an UNDEFINED STATE. If, for
example, no valid WiFi template is provided, it is unlikely that P4wnP1 A.L.O.A. will be reachable via WiFi after
reboot**
So before deploying our new
tutorial1 Master Template as Startup Master Template, we assure proper settings are loaded
for the other subsystem. We do that like this:1) From the "Master Template Editor" hit the "Load Stored" button and reload the
tutorial1 template to the editor.
2) The template should have tutorial1 set for "TriggerActions Template" and for "USB template"
3) For "WiFi Template" select the template named startup
4) For "Bluetooth Template" select the template named startup
5) For "Network Templates" select the templates named:
1) bteth_startup
2) usbeth_startup
3) wlan0_startup_dhcp_server
6) O the tutorial1 Master Template with the new settings (hit "Store", enter tutorial1 and confirm with
"OK")
7) Double check that the changes ha, by hitting "Load Stored", again, and selecting tutorial1. All
subsections of the loaded Master Template should look like described here.Now we are ready to deploy our new Master Template as Startup Master Template. After doing so we hit the "reboot"
button.
Once rebooted, P4wnP1 A.L.O.A. should trigger the HIDScript automatically (and should still be reachable via WiFi,
to allow reconfiguration)
Congratulations, all goals achieved
You ha about the very basic workflow concepts of P4wnP1 A.L.O.A.
3. Where to go from here
It is currently not possible to provide a full documentations. So here are some comments on topics which haven't been
touched, yet, but are worth in.
BashScripts
P4wnP1 allows running BashScripts from TriggerActions. The scripts which are usable from TriggerActions are homed at
/usr/local/P4wnP1/scripts. If a script is called from a TriggerAction, several arguments (like the actual trigger) are
handed in via bash . The file /usr/local/P4wnP1/scripts/trigger-aware.sh provides a nice example of a bash
script which acts differently, depending on the calling trigger. It is worth having a look onto this script, as it uses
all "TriggerAction " currently a.GPIO
The community of the old P4wnP1 occasionally came up with hardware mods or extensions of the Rapsberry PI and
the question how to integrate them. It isn't possible for me to provide a generic solution to this problem. Neither
is it a good idea, to provide support for a very specific hardware extension, which is only used by a few people. With
the introduction of TriggerAction the idea came up, to support GPIO as both, Triggers via GPIO input and Actions issuing
GPIO output. Although not planned for the first release, this feature has already been implemented. I still haven't
had the time to document it and it could easily happen that some things change. The functionality uses the "periph.io"
library with some minor extension (customized edge detection with custom de-bounce for GPIO, thanks to for
exchange on this)
nexmon KARMA
The WiFi firmware included with P4wnP1 A.L.O.A. has been modified (utilizing nexmon framework) to support KARMA.
This feature hasn't made it into the core so far (needs some rework firmware-wise) and thus isn't a from
webclient or CLI. If you want to play around with the karma features, there is a legacy python CLI, which allows setting
the KARMA options on the fly. The python script could be found here:
/usr/local/P4wnP1/legacy/karmatool.pyTip: To get most out of the KARMA functionality, you should setup P4wnP1 A.L.O.A. to provide a WiFi Access Point without
authentication, otherwise it wouldn't make to much sense. For poor beacon flooding this isn't needed, but (static)
custom SSIDs for beaconing are limited in their number (saving resources on the WiFi chip)
Help screen of karmatool.py:
WiFi covert channel
The WiFi covert channel hasn't been ported to Go and isn't part of the P4wnP1 core. Anyways, the legacy functionality
is provided. In order to make the covert channel run, several conditions have to be met:
a keystroke injection has to be applied to the target client to inject stage1
stage1 loads stage2 over a (simplified ) of the HID covert channel, thus a special USB HID device has to be
provided and a special HID covert channel server has to be started on P4wnP1, in order to provide stage2
a second server has to be started and interface the modified WiFi firmware, in order to manage client connecting
in via the WiFi covert channel and provide interacti access to those clients (the server is a console
application which is meant to run in a terminal multiplexer, like screen)All of the aforementioned conditions could be fulfilled using P4wnP1 A.L.O.A.'s feature set, if the needed components
(HID stager, WiFi co server, client agent to deliver) are provided.
To carry out such a task with P4wnP1 A.L.O.A. is a great example for its capabilities. Additionally it helps to
distinguish what P4wnP1 A.L.O.A. is meant to be and what is not meant to be.
P4wnP1 A.L.O.A. is not meant to:
be a "weaponized" tool
provide RTR payloads, which could be carried out by e, without understanding what's going on or which risks
are inP4wnP1 A.L.O.A. is meant to:
be a flexible, low-cost, pocket sized platform
serve as enabler for tasks like the one described here
support prototyping, testing and carrying out all kinds of USB related tasks, commonly used during pentest or
redteam engagements, without pro a finalized static solutionIn set sense, the
/usr/local/P4wnP1/legacy folder homes the needed external tools to run the WiFi covert channel
(namely the WiFi server, the HID covert channel stager server and the WiFi covert channel client agent). Those
components could be considered as external parts (don't belong to P4wnP1 A.L.O.A. core).Additionally P4wnP1 A.L.O.A. provides a configuration, which utilizes the gi to do the following things:
drive-by against Windows hosts in order to deli client code to download stage2 via HID covert channel,
based on keystroke injection (HIDScript)
starting the keystroke injection, as soon as P4wnP1 is connected to a USB host (TriggerAction issuing HIDScript)
bring up the stager, which delivers the WiFi covert channel client agent via HID covert channel, as soon as the
keystroke injection starts (TriggerAction running a bash script, which again starts the external server)
bring up the WiFi covert channel server, when needed (same TriggerAction and BashScript)
deploy a USB setup which provides a USB keyboard (to allow keystroke injection) and an additional raw HID device
(serves as covert channel for stage2 delivery) - the USB settings are stored in a settings template
deploy a WiFi setup, which allows remote access to P4wnP1, in order to allow interaction with the CLI frontend of
the WiFi covert channel server - the WiFi settings are stored in a settings template
provide a single point of entry, to deploy all the needed configurations at once (done by a Master Template, which
consists of proper WiFi settings, proper USB settings and the TriggerActions needed to start the HIDScript)The Master Template is called "wifi covert channel". By deploying it from the "generic settings" tap of the webclient
("DEPLOY STORED" from the Master Template Editor) P4wnP1 A.L.O.A. is ready configured to execute all the describe steps.
As soon as it is re-attached to a USB host, it should start typing out stage1 and the according servers are started
internally.
From a SSH session (for example over WiFi) the WiFi covert channel ser be accessed using
screen -d -r wifi_c2
to interact with clients, which connected back over the WiFi covert channel.
As the keystroke injection depends on the USB hosts language layout, the according HIDScript called
wifi_co.js has a language which could be used to adjust the keyboard layout in use.
Additionally there is a called hide (false by default). If hide is set to true, the console Window on
the client gets hidden while stage1 is typed. This, again, pinpoints how complex tasks could be reduced to a simple bool
, thanks to HIDScript and the backing Ja engine. The "wifi covert channel" demo provided with P4wnP1's Master Templates could be used as Startup Master Template, too, as
WiFi access is still possible and thus the setup could be changed again, remotely at any time.
The in BashScript, which is called from a TriggerAction is a good example how flexible the CLI client could get.
As the HID stager needs to know on which device file to listen (the one which represents the generic HID device), but
this information is only a at runtime (depends on enabled USB gadget functions), the script requests the CLI
to report the correct HID device by running
hidraw=$(P4wnP1_cli usb get device raw).The full BashScript is hosted in the folder
/usr/local/P4wnP1/scripts, as all bash scripts which should be accessible
from TriggerActions. Bluetooth NAP
P4wnP1 provides Bluetooth based network functionality over the Bluetooth Network Encapsulation Protocol (BNEP).
The currently most interesting feature is the Bluetooth Network Access Point (NAP), which allows IP based Bluetooth
remote access to P4wnP1, for example from mobiles.
In order to use this feature some things should be known:
The bluetooth network interface, called bteth could be configured and templated like the other network interfaces
(webclient or CLI)
In order to allow NAP access from an Android mobile (iPhone untested), the mobile not only needs to connect, but
additionally P4wnP1 has to hand out a proper IP for the default gateway on the bteth interface via DHCP. This is,
because the mobile wants to use the NAP as gateway to the Internet (which would be the intended use). If the NAP itself
wouldn't provide a gateway, the Android Mobile would do no further requests after the DHCP D.O.R.A. The easiest way to
o this, is to instruct the DHCP server to provide the IP of the bteth interface itself as default gateway
(DHCP option 3). Even if there is no real upstream connection, this worked during my tests - as the mobile has to access
the gateway with layer3 communication in order to "phone home". Even if successi tests fail, the working
layer 3 connection persists. This allows, for example, SSH access . With "High Speed" enabled, the
webclient works pretty nice, too.
In order to allow PIN based pairing Simple Secure Pairing (SSP) has to be disabled. If SSP is enabled, the running
Pairing agent confirms every passkey (which means even less security than with legacy PIN pairing, as every device is
able to connect). Maybe a confirmation dialog for SSP based passkey pairing will be implemented for the CLI/webclient
in future, but currently this is out of scope. I highly suggest to disable "disco" and "bondable" if SSP is in
use, as soon as the intended device has paired.
Another shortcoming of having SSP disabled, is that "High Speed" wouldn't be usable for bluetooth conections (or
to enable High Speed, pairing has to be done with SSP). Without "High Speed" enabled (uses 802.11 frames for
communication) it would take about 10 minutes to request the webclient, with high speed enabled it takes some seconds.
Using SSH and the CLI client over a NAP without "High Speed" should be fine, though.
The default Bluetooth network interface settings ( bteth_startup) and the default Bluetooth settings (startup)
should allow "Low Speed" access over SSH with legacy PIN pairing. The PIN is 1337 156157 "connected"