P4wnP1 A.L.O.A. 由 MaMe82 开发,是一个将树莓派 Zero W 转变为灵活、低成本的渗透测试、红队和物理接触平台的框架……或者说是一个“小型进攻型设备”。
最新镜像可在 Releases 标签下找到。
访问全新 P4wnP1 A.L.O.A. 安装最简单的方式是通过生成的 WiFi 使用 Web 客户端(预共享密钥为 MaMe82-P4wnP1,URL 为 http://172.24.0.1:8000)或 SSH(默认密码 toor)。
Math 进行鼠标计算等)这里不多赘述,P4wnP1 A.L.O.A. 基于 KALI Linux,因此一切所需工具都已就绪(或可通过 apt 安装)
因此,如果你想在远程 Windows 主机上使用批处理文件配置 P4wnP1……没问题:
host 参数尽管最初并未计划,P4wnP1 A.L.O.A. 现在可以通过 Web 客户配置。 即便最初未规划,这个客户端却发展成了一款不错的软件。实际上,它已成为配置 P4wnP1 A.L.O.A. 的主要工具。 Web 客户端具备 CLI 无法访问的功能(模板存储、创建“触发器动作”)。
核心特性:
CTRL+SPACE)旧版 P4wnP1 的自动化方法(静态 bash 脚本)已不再适用。
P4wnP1 A.L.O.A. 的自动化方法需满足以下要求:
通过引入所谓的“触发器动作”,并将其与模板系统(所有子系统的持久设置存储)结合,所有需求均得到满足。有关触发器动作的详细信息,请参阅“工作流程”部分。
P4wnP1 A.L.O.A. 不使用静态配置或载荷等概念。实际上,它根本没有静态工作流程。
P4wnP1 A.L.O.A. 旨在尽可能灵活,以便在可能的所有场景中使用(包括我在开发 P4wnP1 A.L.O.A. 时未能想到的场景)。
但本节将讲解一些基本概念。由于很难在不制作完整(视频)文档的情况下解释所有内容,我将通过一些常见用例和示例来解释需要说明的内容。
尽管如此,我不太可能抽出时间提供完整的文档。因此,我鼓励大家提供教程和想法,这些内容可以链接回本 README
现在从最基本的任务开始:
实现此目标的最低配置要求是:
P4wnP1(未修改镜像)的默认配置已满足这些要求:
MaMe82-P4wnP1172.24.0.1172.16.0.1P4wnP11337172.26.0.1root,默认密码为 toor注意: 部署 HTTPS 连接目前不在项目范围内。因此,如果在 Web 客户端中处理敏感数据(如 WiFi 凭证),请务必注意这一点。整个项目并非以安全为首要目标(而且未来也不太可能将其作为需求)。请采取适当措施(例如,如果接入点配置为开放认证,则使用 iptables 限制对 Web 客户端的访问;在没有 PIN 保护的情况下,不要启用蓝牙可发现和可连接等)
至此,我假设:
要从 SSH 会话运行 CLI 客户端,请执行以下命令:``` root@kali:~# P4wnP1_cli The CLI client tool could be used to configure P4wnP1 A.L.O.A. from the command line. The tool relies on RPC so it could be used remotely.
Version: v0.1.0-alpha1
Usage: P4wnP1_cli [command]
Available Commands: db Database backup and restore evt Receive P4wnP1 service events help Help about any command hid Use keyboard or mouse functionality led Set or Get LED state of P4wnP1 net Configure Network settings of ethernet interfaces (including USB ethernet if enabled) system system commands template Deploy and list templates trigger Fire a group send action or wait for a group receive trigger usb USB gadget settings wifi Configure WiFi (spawn Access Point or join WiFi networks)
Flags: -h, --help help for P4wnP1_cli --host string The host with the listening P4wnP1 RPC server (default "localhost") --port string The port on which the P4wnP1 RPC server is listening (default "50051")
Use "P4wnP1_cli [command] --help" for more information about a command.
帮助屏幕已经显示,CLI客户端使用不同的命令来与P4wnP1 A.L.O.A.的各种子系统进行交互。这些命令大多又有自己的子命令。每个命令或子命令的帮助可以通过在CLI命令后附加`-h`来访问:```
root@kali:~# P4wnP1_cli hid run -h
Run script provided from standard input, commandline parameter or by path to script file on P4wnP1
Usage:
P4wnP1_cli hid run [flags]
Flags:
-c, --commands string HIDScript commands to run, given as string
-h, --help help for run
-r, --server-path string Load HIDScript from given path on P4wnP1 server
-t, --timeout uint32 Interrupt HIDScript after this timeout (seconds)
Global Flags:
--host string The host with the listening P4wnP1 RPC server (default "localhost")
--port string The port on which the P4wnP1 RPC server is listening (default "50051")
现在,为了向USB主机输出"Hello world",可以使用以下CLI命令:
P4wnP1_cli hid run -c 'type("Hello world")'
在SSH会话中的输出结果应该类似于:``` TempFile created: /tmp/HIDscript295065725 Start appending to 'HIDscript295065725' in folder 'TMP' Result: null
在USB主机上,应当在具有键盘焦点的应用程序中输入了"Hello World"。
*如果你的SSH客户端运行在USB主机本身上,那么键入的"Hello world"会出现在CLI命令的输出之间(它不属于输出,而是在中间键入的)。*
**目标达成。我们向目标注入了按键。**
对于一个简单的按键注入任务来说,阅读量很大,但同样,本节旨在解释基本概念。
### 2.2 进一步了解HIDScript的高级语言特性
如果你成功运行了"Hello world"按键注入,那么现在是探索一些额外HIDScript特性的好时机。
我们已经了解了`type`命令,但让我们尝试讨论一些更高级的HIDScript命令:
#### 按下特殊键和组合键
`type`命令支持通过将"换行"字符编码到输入字符串中来按下回车键,如下所示:```
P4wnP1_cli hid run -c 'type("line 1\nline 2\nline 3 followed by pressing RETURN three times\n\n\n")'
但是特殊键或组合键呢?
press 命令来帮忙!
让我们使用 press 向 USB 主机发送 CTRL+ALT+DELETE:```
P4wnP1_cli hid run -c 'press("CTRL ALT DELETE")'
*注意:有两个键是修饰键(CTRL 和 ALT),只有一个键是实际键(DELETE)*
让我们在不使用任何修饰键的情况下按下键 'A':```
P4wnP1_cli hid run -c 'press("A")'
结果输出应该是小写字母 'a',因为 press("A") 将 'A' 解释为按键。而命令 type("A") 则尝试按下按键组合,从而产生大写字母 'A' 输出字符。
让我们组合一个修饰键和一个非修饰键,以产生大写字母 'A' 输出字符(模仿 type("A") 的行为):```
P4wnP1_cli hid run -c 'press("SHIFT A")'
这应该已经产生了一个大写字母A的输出。
重要的是要理解,`press`将其给定的键参数解释为键,而`type`则尝试找到合适的按键组合以产生预期的输出字符。
在最后一个例子中,让我们结合使用`press`和`type`。```
P4wnP1_cli hid run -c 'type("before caps\n"); press("CAPS"); type("after caps\n"); press("CAPS");'
最后一个命令输入了一个字符串,切换了CAPSLOCK,又输入了另一个字符串并再次切换了CAPSLOCK。 结果,CAPSLOCK应该回到初始状态(切换了两次),但其中一个字符串是大写输入,另一个是小写输入,尽管两个字符串都是小写给出的。
关于使用 press 按键的附加说明:
我不想深入探讨USB键盘报告的内部工作原理,但有些东西值得提及,以明确 press 命令的限制和可能性(该命令本身基于原始键盘报告工作):
press 最多可同时按下六个普通键或特殊键
press("Z") 在美式键盘布局下对应 USB_KEY_Z,但在德式布局下产生 USB_KEY_Y。这相当于在德式键盘上按下硬件键'Z',也会产生 USB_KEY_Y。)/usr/local/P4wnP1/keymaps/common.json 中包含一个格式化的JSON键映射,包含所有可能的键(注意不要修改该文件)press 命令中添加多个键并不会产生按键序列。 所有给定的键会同时按下并同时释放。press 会自动释放按键,这意味着像“按住ALT,按TAB,再按TAB,释放ALT”这样的序列目前无法实现用于更改键盘布局的HIDScript命令是 layout(<语言映射名称>)。
以下示例将键盘布局切换为'US',输入一些内容,然后在继续输入之前将布局切换为'German':``` P4wnP1_cli hid run -c 'layout("us"); type("Typing with EN_US layout\n");layout("de"); type("Typing with German layout supporting special chars üäö\n");'
上述命令的输出结果,取决于USB主机使用的目标布局。
在使用德语键盘布局的主机上,结果如下所示:```
Tzping with EN?US lazout
Typing with German layout supporting special chars üäö
在带有美式键盘布局的主机上,它看起来像这样:``` Typing with EN_US layout Tzping with German lazout supporting special chars [';
请注意,只有 P4wnP1 的键盘布局与实际使用的 USB 主机的键盘布局一致时,才能达到预期输出。
`layout` 命令允许将 P4wwP1 的内部布局与目标 USB 主机的布局对齐。
能够在运行 HIDScript 的中途更改布局可能会派上用场:谁知道呢,也许您想通过发出更改布局的命令来暴力破解目标主机的键盘布局,直到其中一个键入的命令达到预期效果。
**重要提示:** 布局具有全局影响。这意味着如果有多个 HIDScript 同时运行,并且其中一个脚本设置了新布局,则所有其他脚本也会立即受到影响。
#### 打字速度
默认情况下,P4wnP1 会尽可能快地注入击键。根据您的目标,这可能有点太快了(想想那些基于打字速度行为分析来防止击键注入的应对措施)。HIDScript 支持一个命令来更改此行为。
`typingSpeed(delayMillis, jitterMillis)`
`typingSpeed` 命令的第一个参数表示两次击键之间应用的固定延迟(以毫秒为单位)。第二个参数是额外的抖动(以毫秒为单位)。它会在第一个参数提供的静态延迟基础上,增加一个介于 0 到给定抖动毫秒值之间的随机延迟。
让我们尝试使用 `typingSpeed` 来减慢打字速度:```
P4wnP1_cli hid run -c 'typingSpeed(100,0); type("Hello world")'
接下来,我们尝试使用随机抖动,而不是固定延迟。``` P4wnP1_cli hid run -c 'typingSpeed(0,500); type("Writing with random jitter up to 500 milliseconds")'
最后,通过结合和调整这两个值,我们可以模拟自然的打字速度:```
P4wnP1_cli hid run -c 'typingSpeed(100,150); type("Writing with more natural speed")'
重要提示: 打字速度具有全局影响。这意味着如果多个HIDScript同时运行,且其中一个脚本设置了新的打字速度,所有其他脚本会立即受到影响。
等待LED报告,更准确地说等待LED状态变化,是HIDScript中较为高级的键盘功能之一。它可能非常强大,但需要一些说明。
你可能已经注意到(取决于USB主机操作系统),键盘状态修饰符(NUM LOCK、SCROLL LOCK、CAPS LOCK)在多台连接的键盘之间是共享的。例如,如果你将两个键盘连接到Windows主机,并在其中一个键盘上切换CAPS LOCK,那么两个键盘上的CAPS LOCK LED都会变化。
正是这个测试可以用来判断给定操作系统下键盘状态修饰符是否在所有键盘之间共享。
如果USB主机支持这种状态共享(例如Windows支持),P4wnP1的HIDScript语言就可以利用它。
想象以下场景:
P4wnP1连接到USB主机,你想要进行按键注入,但你不希望HIDScript立即执行按键操作。相反,HIDScript应该等待,直到你在主机真实键盘上按下NUMLOCK、CAPSLOCK或SCROLLLOCK。为什么?也许你正在参与一次渗透测试,有人走了进来,你不希望这个“某人”看到大量字符突然神奇地输入到弹出的控制台窗口中。所以你可以等“某人”走出去,然后按下NUM LOCK,最终控制台窗口弹出,大量字符神奇地输入……我想你明白意思了。
上述行为可以通过以下方式实现:``` P4wnP1_cli hid run -c 'waitLED(NUM); type("A huge amount of characters\n")'
如果您测试了上面的命令,只有在 USB 主机的硬件键盘上按下 NUM LOCK 时才会开始输入,
但您可能会遇到这样的情况:即使没有按下 NUM LOCK(且键盘 LED 没有变化),按键也会立即发出。
这是预期行为,原因是 `waitLED` 命令的另一个用例:
也许您之前使用过其他键盘脚本语言和其他能够注入按键的 USB 设备。
这些设备大多面临一个共同问题:您不知道何时开始输入!
如果在 USB 设备上电后立即开始输入,很可能 USB 主机尚未完成设备枚举,从而无法加载键盘驱动程序。最终您的按键会丢失。
为了解决这个问题,您可以在按键注入开始前添加延迟。但这个延迟应该多长?五秒、十秒、三十秒?
答案是:视情况而定!这取决于主机枚举设备和加载键盘驱动程序的速度。事实上,如果不针对实际目标进行测试,您无法知道需要多长时间。
但正如我们之前所学,像 Windows 这样的操作系统会在多个键盘之间共享 LED 状态。
这意味着,如果您在连接第二个键盘之前将主机键盘的 NUMLOCK LED 设置为 ON,那么一旦连接,这个新键盘上的 NUMLOCK LED 也必须设置为 ON。如果 NUM LOCK LED 本来就是 OFF,那么新连接的键盘也会收到 LED 状态(在此情况下所有 LED 都关闭)。有趣的是,只有当键盘驱动程序完成加载后,USB 主机才能向连接的键盘发送这个“LED 更新”(否则无法发送 LED 状态)。
这难道不美妙吗?USB 主机告诉我们:“我已准备好接收按键”。再也不需要纠结于初始延迟了。
但这里还有另一个问题:假设我们将 P4wnP1 连接到 USB 主机。我们运行一个以 `waitLED` 开头而不是手动延迟的 HIDScript。在 `waitLED` 之后开始输入,但什么也没有发生——我们的按键仍然丢失了!为什么?因为很可能我们在 HIDScript 启动之前就已经错过了 LED 状态更新。
正是这个“竞争条件”导致 P4wnP1 会保留所有被识别的 LED 状态变化,直到至少有一个 HIDScript 通过调用 `waitLED`(或 `waitLEDRepeat`)消耗它们。这就是前面描述的行为的原因:`waitLED` 立即返回,即使没有发生 LED 变化。现在我们知道:LED 变化确实发生了,但可能发生得更早(在我们启动 HIDScript 之前),因为状态变化被保留了下来。我们还知道,这种行为是必要的,以避免在 `waitLED` 用于测试“USB 主机键盘驱动程序就绪”时错过 LED 状态变化。
*注意:值得提及的是,`waitLED` 只有在接收到的 LED 状态与 P4wnP1 的内部状态不同时才返回。这意味着,即使我们使用 `waitLED(ANY)` 监听任何 LED 的变化,仍有可能收到来自 USB 主机的初始 LED 状态,而该状态与 P4wnP1 的内部状态没有区别。在这种情况下,`waitLED(ANY)` 将永远阻塞(或者直到真正的 LED 变化发生)。
这种情况可以通过调用 `waitLED(ANY_OR_NONE)` 来处理,该命令一旦收到新的 LED 状态就会返回,即使该状态没有导致变化。*
**解释得够多了,让我们实际动手吧……在此之前,我们需要稍微改变一下硬件设置:**
将外部电源连接到 Raspberry Pi Zero 的第二个 USB 端口(外侧的那个)。这可以确保当 P4wnP1 从 USB 主机断开时不会断电,因为它不再依赖总线供电。用于将 P4wnP1 连接到目标 USB 主机的 USB 端口是两个端口中内侧的那个。
现在启动以下 HIDScript```
P4wnP1_cli hid run -c 'while (true) {waitLED(ANY);type("Attached\n");}'
将 P4wnP1 从 USB 主机上拔下(并确保它保持通电状态)!然后重新连接到 USB 主机…… 每次重新连接 P4wnP1 到主机时,应该会在主机上输入出 "Attached"。
这告诉我们三个事实:
waitLED 可以在脚本中用作初始命令,以便在键盘驱动程序就绪后立即开始输入waitLED 并非最佳选择,无法暂停 HID 脚本直到在 USB 主机上按下改变 LED 的按键,因为保留的状态变化可能会以非预期的方式解除命令阻塞由于我们仍在处理 waitLED 命令,现在我们来处理第三个事实。让我们离开 CLI。
http://172.24.0.1:8000)ms_snake.js 是一个很好的例子,展示了基于 LED 触发器的强大功能)将编辑器窗口中的脚本替换为以下内容:``` return waitLED(ANY);
点击运行按钮后,窗口右侧应会显示一个新的正在运行的HID任务。如果你按下HIDScript任务右侧的小“信息”按钮,你可以看到详细信息,例如其状态(应为“运行中”)、任务ID和VM ID(这是运行此任务的JavaScript VM的编号。共有8个这样的VM,因此可以并行运行8个HIDScript)。
现在,如果USB主机发出任何LED变化(通过切换NUM、CAPS或SCROLL),HIDScript任务应结束。它仍可在“已完成”任务下找到。
如果你再次按下小“信息”按钮,应会显示关于结果值的信息(编码为JSON),内容大致如下:```
{"ERROR":false,"ERRORTEXT":"","TIMEOUT":false,"NUM":true,"CAPS":false,"SCROLL":false,"COMPOSE":false,"KANA":false}
所以 waitLED 命令返回一个类似这样的 JavaScript 对象:```
{
ERROR: false, // gets true if an error occurred (f.e. HIDScript was aborted, before waitLED could return)
ERRORTEXT: "", // corresponding error string
TIMEOUT: false, // gets true if waitLED timed out (more on this in a minute)
NUM: true, // gets true if NUM LED had changed before waitLED returned
CAPS: false, // gets true if CAPS LED had changed before waitLED returned
SCROLL: false, // gets true if SCROLL LED had changed before waitLED returned
COMPOSE: false, // gets true if COMPOSE LED had changed before waitLED returned (uncommon)
KANA: false // gets true if KANA LED had changed before waitLED returned (uncommon)
}
在我的例子中,`NUM` 变成了真。在你的例子中,可能是 `CAPS`。具体是哪个 LED 并不重要。重要的是,返回值提供了检查导致命令返回的 LED 变化的机会,因此可以用于在 HIDScript 中做出分支决策(基于 USB 主机真实键盘发出的 LED 状态变化)。
让我们尝试一个例子:```
while (true) {
result = waitLED(ANY);
if (result.NUM) {
type("NUM has been toggled\n");
}
if (result.SCROLL) {
type("SCROLL has been toggled\n");
}
if (result.CAPS) {
break; //exit loop
}
}
假设给定的脚本已经在运行,在USB主机上按下NUM键应导致输入"NUM has been toggled",而按下SCROLL LOCK则输入"SCROLL has been toggled"。此行为会重复,直到按下CAPS LOCK,其产生的LED变化将中止循环并结束HIDScript。
呼……关于这个命令的一大堆文字,只是针对一个HIDScript命令,但还有一些事情尚未说明。
我们曾向waitLED命令提供过NUM、ANY或ANY_OR_NONE等参数,但未进一步解释。
waitLED最多接受两个参数:
第一个参数,你可能已经猜到,是一个用于监视LED的白名单过滤器。有效的参数有:
ANY(对任何LED的变化做出反应)ANY_OR_NONE(对每一个新的LED状态做出反应,即使没有变化)NUM(忽略所有LED变化,除了NUM LED)CAPS(忽略所有LED变化,除了CAPS LED)SCROLL(忽略所有LED变化,除了SCROLL LED)CAPS | NUM、NUM | SCROLL第二个参数,我们尚未使用过,是一个以毫秒为单位的超时时间。如果在该超时时间内没有发生LED变化,waitLED将返回,并在结果对象中将TIMEOUT设为true(此外ERROR设为true,ERRORTEXT指示超时)。
以下命令将等待NUM LED的变化,但在5秒后中止等待:``` waitLED(NUM,5000)
尽管如果使用得当,`waitLED`是一个非常强大的命令,但它无法帮助我们完成那个简单的任务:稳健地暂停HIDScript,直到目标USB主机上按下了状态修饰键(记住:我们想暂停执行,以确保不受欢迎的“某人”在输入开始前离开,但`waitLED`偶尔因为保留的LED状态变化而过早返回)。
这就是`waitLEDRepeat`登场并解救我们的地方。
将以下脚本粘贴到编辑器中,并尝试让命令返回。之后检查HIDScript的结果。```
return waitLEDRepeat(ANY)
你应该会很快注意到,同一个LED必须频繁地多次改变,才能使waitLEDRepeat命令返回。如果不同的LED改变状态,或者单个LED上的变化发生得太慢,waitLEDRepeat命令就不会返回。
提供给waitLEDRepeat的参数(示例中是ANY)与waitLED的作用完全相同。它是一个白名单过滤器。例如,waitLEDRepeat(NUM)只会返回NUM LOCK LED的变化——无论你多么快速和频繁地敲击CAPS LOCK键,它都不会返回,除非NUM LOCK被频繁按下。
默认情况下,白名单中的一个LED必须改变3次,并且两次连续变化之间的延迟不能超过800毫秒,才能使waitLEDRepeat返回。可以通过提供额外的参数来调整此行为,如下例所示:```
filter = ANY; // same filters as for waitLED
num_changes = 5; // how often the SAME LED has to change, in order to return from waitLEDRepeat
max_delay = 800; // the maximum duration between two LED changes, which should be taken into acccount (milliseconds)
timeout = 10000; // timeout in milliseconds
waitLEDRepeat(filter, num_changes, max_delay); //wait till a LED frequently changed 5 times, no timeout waitLEDRepeat(filter, num_changes, max_delay, timeout); //wait till a LED frequently changed 5 times, abort after 10 seconds
So that's how to interact with LED reports from an USB host in HIDScript.
*Note: `waitLEDRepeat` 与 `waitLED` 在使用上并无不同,都是用于处理已保存的 LED 状态变化。
但 `waitLEDRepeat` 更难被意外触发。*
因此,如果任务是暂停 HIDScript 直到用户交互发生,`waitLEDRepeat` 是合适的选择。当然,它也可以用于分支判断,因为它返回的对象与 `waitLED` 相同。
到目前为止,我们对 HIDScript 有了不少了解(当然并非全部,我们甚至还没涉及该脚本语言的鼠标控制功能)。不过,本教程关注的是 P4wnP1 A.L.O.A. 的工作流程和基本概念。所以,我们暂时不深入 HIDScript 的其他特性,继续往下学习。
我们来总结一下目前关于 P4wnP1 工作流程和概念学到的内容:
- 我们可以通过 CLI 客户端按需启动按键注入等操作
- 我们可以使用 Web 客户端实现同样的功能,同时对 HIDScript 任务有额外的控制
- 如果为 P4wnP1 A.L.O.A. 连接外部电源,则在不同 USB 主机间插拔时,已启动的 HIDScript 可以无缝继续运行
- 我们可以根据需求精确配置 USB 堆栈(并能在运行时更改配置,无需重启 P4wnP1)
- 我们可以编写多用途的 HIDScript,借助 JavaScript 实现复杂逻辑(支持函数、循环、分支等)
### 3. 工作流程第二部分 - 模板与触发动作
在继续讨论 P4wnP1 A.L.O.A. 的其他主要概念之前,我们先精炼一下最初的目标——“针对 USB 主机执行按键注入”:
- 新目标是:在 Windows USB 主机的编辑器(notepad.exe)中键入“Hello world”。
- 编辑器应由 P4wnP1 自动打开(而非用户手动操作)。
- 当 USB 主机的任意键盘 LED 被切换时,编辑器应自动关闭。
- 每次 P4wnP1 连接到 USB 主机时,该行为应重复执行(使用外部电源,无需重启 P4wnP1)。
- 除非 P4wnP1 重新连接到 USB 主机,否则该进程*应仅运行一次*,即使在 HIDScript 启动后连续发生键盘 LED 变化也是如此。
- 即使 P4wnP1 重启,也应能恢复相同的配置,而无需从头重建安装细节。
启动 notepad、键入“Hello world”并在 LED 变化后关闭 notepad,这些都可以用我们已学的内容实现。相应的 HIDScript 可能如下所示:```
// Starting notepad
press("WIN R"); // Windows key + R, to open run dialog
delay(500); // wait 500ms for the dialog to open
type("notepad.exe\n"); // type 'notepad.exe' to the run dialog, append a RETURN press
delay(2000); // wait 2 seconds for notepad to come up
// Type the message
type("Hello world") // Type "Hello world" to notepad
// close notepad after LED change
waitLED(ANY); // wait for a single LED change
press("ALT F4"); // ALT+F4 shortcut to close notepad
//as we changed content, there will be a confirmation dialog before notepad exits
delay(500); // wait for the confirmation dialog
press("RIGHT"); // move focus to next button (don't save) with RIGHT ARROW
press("SPACEBAR"); // confirm dialog with space
本脚本中唯一的新内容是 delay 命令,它无需过多解释。该命令会将执行延迟指定毫秒数。
可以将脚本粘贴到 Web 客户端的 HIDScript 编辑器中,并通过点击“run”来启动测试。
脚本应能按预期工作,因此我们已接近完成。为了能够在重启后重复使用该脚本,我们需要将其持久化存储。这可以通过点击 Web 客户端 HIDScript 选项卡中的“store”按钮来实现。输入名称(此处我们使用 tutorial1)并确认对话框后,HIDScript 即被存储。我们可以通过点击 Web 客户端中的“Load & Replace”按钮来检查。存储的脚本应以名称 tutorial1.js 出现在存储脚本列表中(如果在“store”对话框中未提供,则 .js 扩展名会自动添加)。
警告:如果在存储对话框中使用了已存在的文件名,则相应文件会被覆盖且不会再次询问确认。
让我们尝试通过 SSH 会话使用 CLI 客户端启动存储的脚本,如下所示:``` P4wnP1_cli hid run tutorial1.js
这应该已经生效了。这意味着,通过使用P4wnP1 A.L.O.A. CLI客户端,可以从所有支持shell命令的应用程序或简单的bash脚本启动存储的HIDScripts。
甚至可以从为Windows编译的CLI客户端远程启动脚本。假设Windows主机能够通过WiFi访问P4wnP1 A.L.O.A.,并且P4wnP1的IP设置为`172.24.0.1`,那么正确的命令应该是这样的:```
P4wnP1_cli.exe --host 172.24.0.1 hid run tutorial1.js
注:在撰写本文时,我尚未决定是否要为每一种可能的平台和架构提供 P4wnP1 A.L.O.A. CLI 二进制文件。但很可能会为主流平台提供预编译版本。如果没有——这也不是大问题,因为 CLI 客户端的 Go 代码交叉编译只需不到一分钟。
下一步是让脚本在每次 P4wnP1 重新连接到 USB 主机时都能再次运行。为了实现这种行为,我们曾采用的一种方法是将所有内容包裹在一个循环中,并在前面加上 waitLED(ANY_OR_NONE)。waitLED(ANY_OR_NONE) 确保只有当目标 USB 主机通过发送全局键盘 LED 状态的更新来表明键盘驱动程序已准备好接收输入时,循环才会继续。相应修改后的脚本可能如下所示:```
while (true) {
waitLED(ANY_OR_NONE); // wait till keyboard driver sends the initial LED state
// Starting notepad press("WIN R"); // Windows key + R, to open run dialog delay(500); // wait 500ms for the dialog to open type("notepad.exe\n"); // type 'notepad.exe' to the run dialog, append a RETURN press delay(2000); // wait 2 seconds for notepad to come up
// Type the message type("Hello world") // Type "Hello world" to notepad
// close notepad after LED change waitLED(ANY); // wait for a single LED change press("ALT F4"); // ALT+F4 shortcut to close notepad
//as we changed content, there will be a confirmation dialog before notepad exits delay(500); // wait for the confirmation dialog press("RIGHT"); // move focus to next button (don't save) with RIGHT ARROW press("SPACEBAR"); // confirm dialog with space }
上面给出的脚本确实会在每次 P4wnP1 连接到 USB 主机时运行。但这个脚本不太健壮,因为其中还涉及另一个 `waitLED`,它会等待记事本程序关闭。
这样做会带来几个问题。例如,如果 P4wnP1 在“Hello world”被输入完毕之前就被断开,那么此时阻塞的 `waitLED` 将是 `press("ALT F4")` 之前的那一个,并且执行会在 HIDScript 的这一点继续,下次 P4wnP1 再连接到(可能是不同的)USB 主机时继续执行。
所选方法的一个明确终止标准是以下问题:脚本只应在 P4wnP1 连接到 USB 主机后运行一次这一要求无法满足,因为多次按 NUM LOCK 会反复重启脚本。
那么如何解决这个问题呢?
#### 引入 TriggerActions
解决方案是所谓的“TriggerActions”。顾名思义,这种 P4wnP1 A.L.O.A. 工作流概念基于预定义的触发器触发动作。
要了解我在说什么,请转到 Web 客户端的“TRIGGER ACTIONS”选项卡。根据当前配置,可能已经存在一些 TriggerActions。我们现在不关心已有的 TriggerActions。
点击“ADD ONE”按钮,一个新的 TriggerAction 将被添加并立即进入编辑模式。默认情况下,新的 TriggerAction 是禁用的,需要启用才能编辑。所以我们切换启用开关。
现在从名为“Trigger”的下拉菜单中选择“USB gadget connected to host”。动作应预设为“write log entry”。我们保持这样,然后点击“Update”按钮。
新添加的 TriggerAction 现在应该显示在 TriggerActions 概览中(ID 最高的那个),并以可读的形式显示所选触发器和所选动作的摘要。
要测试新定义的 TriggerAction 是否工作,请导航到 Web 客户端的“Event Log”选项卡。确保通过 WiFi(而非 USB 以太网)打开 Web 客户端。给 P4wnP1 接上外部电源,将其从 USB 主机断开,再重新连接。每当 P4wnP1 连接到 USB 主机时,应该立即向客户端推送一条日志消息。
如果你重复几次,可能会注意到“USB gadget connected to host”触发器触发得非常快(或者在 USB 枚举阶段的早期)。更准确地说:当此触发器触发时,已知 P4wnP1 已连接到 USB 主机,但不能保证 USB 主机已成功加载所有必需的 USB 设备驱动程序。**事实上,当触发器触发时,USB 键盘驱动程序几乎不可能已加载。我们必须牢记这一点。**
在继续我们的任务之前,我们做一个额外的测试。回到“TriggerAction”选项卡,点击我们新创建的 TriggerAction 旁边那个看起来像笔的小蓝色按钮。我们再次进入编辑模式。
这次,启用 `One shot` 选项。之后回到“Event Log”,再次断开并重新连接 P4wnP1 与 USB 主机。这次 TriggerAction 应该只触发一次。无论之后 P4wnP1 被重新连接多少次,都不会再产生指示 USB 连接的日志消息。
值得一提的是,“One shot” TriggerAction 在触发器触发后不会被删除。相反,TriggerAction 会被再次禁用。重新启用可以重复使用 TriggerAction 而无需重新定义。在点击 TriggerAction 上的红色“trash”按钮之前,不会丢失任何内容,该按钮会永久删除相应的 TriggerAction。
**警告:如果点击某个 TriggerAction 的删除按钮,该 TriggerAction 将被永久删除,且不会进一步确认。**
此时,让我们做一些显而易见的事情。我们编辑已创建的 TriggerAction,并选择“start a HIDScript”而不是“write log entry”作为要执行的动作。此外,我们再次禁用“one-shot”。会出现一个名为“script name”的新输入字段。点击此输入字段会弹出一个选择对话框,显示所有存储的 HIDScript,包括我们先前创建的 `tutorial1.js` HIDScript。
*在测试是否有效之前,让我快速说明一下“write log entry”动作:P4wnP1 A.L.O.A. 不会跟踪已经触发过的触发器。这意味着由“write log entry”动作创建的日志条目会传递给所有监听客户端,但不会由 P4wnP1 服务存储(出于多种原因)。另一方面,Web 客户端会存储日志条目,直到 Web 客户端本身被重新加载。这同样适用于与 HIDScript 作业相关的事件。如果 HIDScript 结束(无论成功或失败),会向所有当前打开的 Web 客户端推送一个事件。总结来说,每个 Web 客户端都有一个运行时状态,它包含比核心服务本身更多的信息。如果 Web 客户端的运行时状态变得过大(内存使用过多),只需重新加载客户端即可清除“历史”状态信息。如果核心服务也存储所有历史信息,它很快就会耗尽资源。因此,这个概念适用于 P4wnP1 A.L.O.A. 的大多数子系统。*
现在回到我们的任务。我们已经准备好一个 TriggerAction,它应该在每次 P4wnP1 连接到 USB 主机时触发我们的 HIDScript。
根据目标 USB 主机的不同,这或多或少可靠。在我的测试设置中,它根本不起作用,原因如下:
让我们回顾一下 HIDScript 的前几行:```
// Starting notepad
press("WIN R"); // Windows key + R, to open run dialog
delay(500); // wait 500ms for the dialog to open
type("notepad.exe\n"); // type 'notepad.exe' to the run dialog, append a RETURN press
... snip ...
回想一下事实,即"USB gadget connected"触发器在早期USB枚举阶段触发,此时USB主机的键盘驱动程序不一定已加载,问题就变得很明显。我们必须在脚本前面添加某种延迟,以确保键盘驱动程序已启动(否则我们的击键将无处可去)。
由于我们已经知道无法预测最佳延迟,因此采用之前解释过的 waitLED(ANY_OR_NONE) 方法。新脚本如下:```
waitLED(ANY_OR_NONE); //assure keyboard driver is ready
// Starting notepad press("WIN R"); // Windows key + R, to open run dialog delay(500); // wait 500ms for the dialog to open type("notepad.exe\n"); // type 'notepad.exe' to the run dialog, append a RETURN press delay(2000); // wait 2 seconds for notepad to come up
// Type the message type("Hello world") // Type "Hello world" to notepad
// close notepad after LED change waitLEDRepeat(ANY); // wait for a single LED change press("ALT F4"); // ALT+F4 shortcut to close notepad
//as we changed content, there will be a confirmation dialog before notepad exits delay(500); // wait for the confirmation dialog press("RIGHT"); // move focus to next button (don't save) with RIGHT ARROW press("SPACEBAR"); // confirm dialog with space
以完全相同名称(`tutorial1`)存储修改后的脚本会覆盖之前的HIDScript,且不再另行确认,这一点已指出。因此无需调整我们的 TriggerAction,因为 TriggerAction 引用的 HIDScript 名称没有改变。
经过这一小改动,一切应能按预期工作,脚本应在每次连接 USB 主机时触发,但仅运行一次。
现在,如果 P4wnP1 重启或断电,我们的 HIDScript 会保留下来,因为我们已将其持久化存储,但 TriggerAction 会消失。不用说,TriggerAction 也可以持久化存储。
“TriggerAction”选项卡中的“存储”按钮与 HIDScript 编辑器中的按钮功能完全相同。需要注意的是,如果确认“存储”对话框,*所有当前激活的 TriggerAction* 都会被存储(包括已禁用的那些)。
最佳实践是:在存储前删除所有不属于当前范围任务的 TriggerAction(如果需要,它们应该事先已存储),并仅使用适当的名称存储与当前任务相关的一小部分 TriggerAction。有两种方法可以将已存储的 TriggerAction 加载回激活状态:
- “加载并替换”会清除所有激活的 TriggerAction,仅加载已存储的那些
- “加载并添加”会保留已激活的 TriggerAction,并加入已存储的。因此,“加载并添加”可用于从较小的集合构建复杂的 TriggerAction 集。生成的集合随后可以再次存储。
目前我们只存储单个 TriggerAction,它启动我们的 HIDScript。存储时使用的名称同样是 `tutorial1`,不会与名为 `tutorial1` 的 HIDScript 冲突。
通过点击“TriggerAction”选项卡中的“加载并替换”按钮,确认存储成功。已存储的 TriggerAction 集应出现在列表中,名称为 `tutorial1`。
**警告:TriggerAction 的“加载”对话框中允许通过点击每个动作旁边的红色“垃圾桶”按钮删除已存储的 TriggerAction。点击该按钮将永久删除相应的 TriggerAction 集,且不会进一步确认**
至此,我们可以安全地从“TriggerActions”选项卡中删除我们的 TriggerAction(注意:不要使用加载对话框中的垃圾桶按钮)。
如果从激活项中删除了 TriggerAction,那么断开并重新连接 P4wnP1 到 USB 主机时,不会发生任何操作。
无论如何,存储的 TriggerAction 集 `tutorial1` 会在重启后保留,并可在任何时候重新加载。
我们尝试不通过 Web 客户端重新加载 TriggerAction 集,而是使用 CLI 客户端来完成。
快速看一下 `template deploy` 子命令的帮助屏幕:```
root@kali:~# P4wnP1_cli template deploy -h
Deploy given gadget settings
Usage:
P4wnP1_cli template deploy [flags]
Flags:
-b, --bluetooth string Deploy Bluetooth template
-f, --full string Deploy full settings template
-h, --help help for deploy
-n, --network string Deploy network settings template
-t, --trigger-actions string Deploy trigger action template
-u, --usb string Deploy USB settings template
-w, --wifi string Deploy WiFi settings templates
Global Flags:
--host string The host with the listening P4wnP1 RPC server (default "localhost")
--port string The port on which the P4wnP1 RPC server is listening (default "50051")
使用界面显示,TriggerAction 模板可以通过 -t 标志部署。我们运行以下命令来恢复存储的 TriggerAction 集合:```
P4wnP1_cli template deploy -t tutorial1
The TriggerAction which fires out HIDScript on USB host connections is now loaded again and should be shown in the
TriggerActions tab of the webclient. If P4wnP1 A.L.O.A. is attached to an USB host, the script should run again.
现在,在 USB 主机连接时触发 HIDScript 的 TriggerAction 已重新加载,并应显示在 webclient 的 TriggerActions 选项卡中。如果 P4wnP1 A.L.O.A. 连接到 USB 主机,该脚本应再次运行。
Storing, loading and deploying of templates is one of the two main concepts behind P4wnP1's automation workflow,
the other one are the already known TriggerActions. It is worth mentioning, that not only TriggerAction sets could be
stored and loaded as templates themselves, but that TriggerActions could be used to deploy already stored templates, if
that makes sense.
存储、加载和部署模板是 P4wnP1 自动化工作流的两大核心概念之一,另一个是已知的 TriggerActions。值得一提的是,不仅 TriggerAction 集本身可以作为模板存储和加载,而且 TriggerActions 也可用于部署已存储的模板(如果这样做有意义的话)。
Revisiting our tasks, it seems all defined requirements are met now:
- we typed "Hello world" into the editor of a Windows USB host
- the editor is opened by P4wnP1, not manually by the user
- the editor is closed automatically, when one of the keyboard LEDs toggled once
- every time P4wnP1 is attached to a USB host, this behavior repeats
- the HIDScript runs only once, unless P4wnP1 is re-attached to the USB host, even if successive keyboard LED changes
occur
- if P4wnP1 is rebooted, the same behavior could be recovered by loading the stored TriggerAction set (which again
refers to the stored HIDScript). This could either be achieved with a single CLI command or with a simple "load&add" or
"load&replace" from the webclient's trigger action tab.
回顾我们的任务,所有定义的需求似乎都已满足:
- 我们在 Windows USB 主机的编辑器中输入了"Hello world"
- 编辑器由 P4wnP1 打开,而非用户手动操作
- 当键盘 LED 闪烁一次时,编辑器自动关闭
- 每次 P4wnP1 连接到 USB 主机时,此行为重复
- HIDScript 仅运行一次,除非 P4wnP1 重新连接到 USB 主机,即使后续发生键盘 LED 变化
- 如果 P4wnP1 重启,可通过加载已存储的 TriggerAction 集(该集再次引用已存储的 HIDScript)恢复相同行为。这可以通过一条 CLI 命令或通过 webclient 的 trigger action 选项卡中的简单"load&add"或"load&replace"来实现。
Once more let us add additional goals:
- it should be assured, that the USB configuration has the keyboard functionality enabled (the current setup doesn't do
this and the TriggerAction couldn't start the HIDScript in case the USB keyboard is disabled)
- the created setup should applied at boot of P4wnP1 A.L.O.A., without the need of manually loading of the TriggerAction
set. The setup has to survive a reboot of P4wnP1.
再次让我们增加额外目标:
- 应确保 USB 配置已启用键盘功能(当前设置未启用,如果 USB 键盘被禁用,TriggerAction 将无法启动 HIDScript)
- 创建的设置应在 P4wnP1 A.L.O.A. 启动时应用,无需手动加载 TriggerAction 集。该设置必须在 P4wnP1 重启后依然有效。
To achieve the two additional goals, we have to dive into a new topic and ...
为了实现这两个额外目标,我们必须深入探讨一个新主题,并且……
#### Introduce Master Templates and Startup Master Template
#### 引入主模板和启动主模板
Before we look into Master Templates, we do something we haven't done, yet, because everything just worked as intended
so far: We define a valid USB configurations, matching our task!
在研究主模板之前,我们先做一件迄今尚未做过的事(因为一切都在按预期工作):我们定义一个与任务匹配的有效的 USB 配置!
- device serial number: 123456789
- device product name: Auto Writer
- device manufacturer: The Creator
- Product ID: 0x9876
- Vendor ID: 0x1D6B
- enabled USB functions
- HID keyboard
- HID mouse
- 设备序列号:123456789
- 设备产品名称:Auto Writer
- 设备制造商:The Creator
- 产品 ID:0x9876
- 供应商 ID:0x1D6B
- 启用的 USB 功能
- HID 键盘
- HID 鼠标
Let's take a look into the usage screen of the CLI command, which could bes used to deploy these settings, first:
首先,让我们看看可用于部署这些设置的 CLI 命令的使用界面:```
root@kali:~# P4wnP1_cli usb set -h
set USB Gadget settings
Usage:
P4wnP1_cli usb set [flags]
Flags:
-e, --cdc-ecm Use the CDC ECM gadget function
-n, --disable If this flag is set, the gadget stays inactive after deployment (not bound to UDC)
-h, --help help for set
-k, --hid-keyboard Use the HID KEYBOARD gadget function
-m, --hid-mouse Use the HID MOUSE gadget function
-g, --hid-raw Use the HID RAW gadget function
-f, --manufacturer string Manufacturer string (default "MaMe82")
-p, --pid string Product ID (format '0x1347') (default "0x1347")
-o, --product string Product name string (default "P4wnP1 by MaMe82")
-r, --rndis Use the RNDIS gadget function
-s, --serial Use the SERIAL gadget function
-x, --sn string Serial number (alpha numeric) (default "deadbeef1337")
-u, --ums Use the USB Mass Storage gadget function
--ums-cdrom If this flag is set, UMS emulates a CD-Rom instead of a flashdrive (ignored, if UMS disabled)
--ums-file string Path to the image or block device backing UMS (ignored, if UMS disabled)
-v, --vid string Vendor ID (format '0x1d6b') (default "0x1d6b")
Global Flags:
--host string The host with the listening P4wnP1 RPC server (default "localhost")
--json Output results as JSON if applicable
--port string The port on which the P4wnP1 RPC server is listening (default "50051")
该命令有许多标志,但也存在许多可更改的USB设置。可以通过使用CLI来部署我们定义的USB设置,如下所示:``` root@kali:~# P4wnP1_cli usb set \
--sn 123456789
--product "Auto Writer"
--manufacturer "The Creator"
--pid "0x9876"
--vid "0x1d6b"
--hid-keyboard
--hid-mouse Successfully deployed USB gadget settings Enabled: true Product: Auto Writer Manufacturer: The Creator Serialnumber: 123456789 PID: 0x9876 VID: 0x1d6b
Functions: RNDIS: false CDC ECM: false Serial: false HID Mouse: true HID Keyboard: true HID Generic: false Mass Storage: false
(较长的)命令的输出结果显示了最终的USB设置。我们来检查一下webclient的“USB设置”选项卡,以确认这些设置已被应用。如果一切顺利,所有更改都应得到反映。
虽然完全可以通过CLI部署USB设置,但使用webclient相比CLI有几个好处。在这种情况下:
- 通过webclient更改设置更方便、更便捷
- webclient维护了内部设置状态,这使得可以在不实际部署的情况下定义USB设置(而CLI只能通过部署来操作设置。这样又会重置P4wnP1的整个USB栈及其所有依赖功能。例如,已运行的HIDScript会被中断,或者USB网络接口会重新部署)
- webclient的当前设置可以存储到持久化模板中,而无需事先部署
- CLI客户端(目前)无法存储USB设置
在当前情况下,选择使用webclient进行USB设置的更改显然是更好的选择。CLI方法(我们已经在这里使用过)的好处是:由于CLI强制我们部署USB设置,我们可以在将它们存储到持久化模板之前确认它们正常工作。
接下来我们继续存储USB设置:
再次点击“存储”按钮,这次是在“USB设置”选项卡中。我们再次将模板命名为`tutorial1`(与同名的TriggerAction模板没有冲突,因为USB设置使用了不同的命名空间)。
现在我们有了两个新的持久化存储模板:
1) 一个用于TriggerAction集合的模板,名为`tutorial1`
2) 一个用于USB设置的模板,也名为`tutorial1`
假设当前设置(USB设置、TriggerAction或两者)发生了某种变化,我们可以通过执行以下CLI命令一次性重新加载这两个存储的设置:```
P4wnP1_cli template deploy --usb tutorial1 --trigger-actions tutorial1
The command P4wnP1 template deploy 可以一次性为 P4wnP1 A.L.O.A. 的每个子系统加载模板(对于网络子系统,可以为每个适配器加载多个模板)。为各个子系统部署模板是使用 P4wnP1 A.L.O.A. 时的常见任务,因为在大多数情况下,需要重新配置多个子系统才能达到单一目标。为此,引入了所谓的 Master Templates(主模板)。
一个 Master Template 可以包含:
可以通过 Web 客户端的“Generic Settings”选项卡中的“Master Template Editor”来定义、存储或加载 Master Template。使用 Web 客户端是定义 Master Template 的便捷方式,因为它只允许选择已为各个子系统存储的模板(目前 Web 客户端是定义 Master Template 的唯一方式)。
因此,让我们为当前任务定义一个 Master Template:
tutorial1 模板,并点击“OK”按钮确认tutorial1(这是针对 USB 子系统的不同模板,尽管名称与 TriggerActions 的模板相同)tutorial1,保存新的 Master Template要确认模板是否已存储,可以使用“Load Stored”按钮——该模板应出现在选择列表中。然后取消“Load Store”对话框。
现在点击“Deploy Stored”按钮,选择名为 startup 的模板,然后点击“OK”确认。
与“Load Stored”功能(将已存储的模板加载到 Master Template Editor)不同,“Deploy Stored”功能会立即将 Master Template 的所有设置应用于 P4wnP1 的相应子系统(甚至不加载到 Master Template Editor 中)。
由于 startup Master Template 会覆盖当前的 WiFi 设置,您可能会失去与 Web 客户端的连接,需要重新连接到 P4wnP1 WiFi 网络。
一旦成功重新连接并检查当前的 USB 设置和当前的 TriggerActions,我们之前存储的设置已被 startup Master Template 的子设置覆盖。
有两种方法可以再次部署 tutorial1 Master Template:
startup Master Template 所做的那样)P4wnP1_cli template deploy --full tutorial1 进行部署(--full 标志是 Master Template 的别名)能够部署 Master Template tutorial1,我们已经实现了我们新目标之一:
确保在加载按键注入设置时 USB 配置启用了键盘功能。
快速总结工作原理:
tutorial1 加载名为 tutorial1 的 USB 设置,其中:
tutorial1 加载一个包含单个 TriggerAction 的 TriggerAction 集
tutorial1.js
waitLED 触发器触发(键盘驱动程序就绪)后开始输入,并在连续的 LED 变化后结束剩余的唯一目标是:创建的设置应在 P4wnP1 A.L.O.A. 启动时自动应用,无需手动加载 TriggerAction 集。该设置必须能够在 P4wnP1 重启后持续生效。
现在这个目标可以很容易地实现。Web 客户端的“Generic Settings”选项卡中有一个名为 Startup Master Template 的卡片。此时将 Startup Master Template 更改为 tutorial1 会立即生效,并且很可能 破坏 P4wnP1 A.L.O.A. 当前正常工作的启动配置。
重要提示:如果 Master Template 中有子模板留空(例如,未选择蓝牙模板),则在加载该 Master Template 时,相应的子系统不会被重新配置。虽然这在运行时重新配置时很方便(无需重置已运行的子系统,如 USB 堆栈或 WiFi 堆栈),但用作 Startup Master Template 的 Master Template 会将未定义模板的子系统置于未定义状态。例如,如果未提供有效的 WiFi 模板,P4wnP1 A.L.O.A. 在重启后很可能无法通过 WiFi 访问。
因此,在将我们新的 tutorial1 Master Template 部署为 Startup Master Template 之前,我们要确保其他子系统已加载适当的设置。操作如下:
tutorial1 模板重新加载到编辑器中。tutorial1。startup 的模板。startup 的模板。bteth_startupusbeth_startupwlan0_startup_dhcp_servertutorial1 Master Template(点击“Store”,输入 tutorial1,然后点击“OK”确认)。tutorial1,检查更改是否已应用。加载的 Master Template 的所有子部分应与此处描述的一致。现在我们可以将新的 Master Template 部署为 Startup Master Template。完成后,点击“reboot”按钮。
重启后,P4wnP1 A.L.O.A. 应自动触发 HIDScript(并且仍可通过 WiFi 访问,以便重新配置)。
恭喜,所有目标均已实现
您已经了解了 P4wnP1 A.L.O.A. 非常基本的工作流程概念。
目前无法提供完整的文档。因此,这里有一些尚未涉及但值得研究的话题的注释。
P4wnP1 允许从 TriggerActions 运行 Bash 脚本。可从 TriggerActions 使用的脚本位于 /usr/local/P4wnP1/scripts。如果从 TriggerAction 调用脚本,多个参数(如实际触发器)将通过 bash 变量传入。文件 /usr/local/P4wnP1/scripts/trigger-aware.sh 提供了一个很好的示例,展示了根据调用触发器行为不同的 bash 脚本。这个脚本值得一看,因为它使用了当前所有可用的“TriggerAction 变量”。
旧版 P4wnP1 的社区偶尔会提出 Raspberry PI 的硬件修改或扩展,以及如何集成它们的问题。我无法提供通用的解决方案,也不适合为仅少数人使用的非常特定的硬件扩展提供支持。随着 TriggerAction 的引入,支持 GPIO 作为触发器(通过 GPIO 输入)和动作(发出 GPIO 输出)的想法出现了。虽然第一个版本未计划此功能,但它已经实现。我还没有时间记录它,并且某些内容可能会发生变化。该功能使用了“periph.io”库,并带有一些小的扩展(自定义边缘检测和自定义去抖动,感谢 @marcaruel 对此的交流)。
P4wnP1 A.L.O.A. 附带的 WiFi 固件已被修改(利用 nexmon 框架)以支持 KARMA。此功能尚未进入核心(需要在固件方面进行一些重写),因此无法从 Web 客户端或 CLI 使用。如果您想尝试 KARMA 功能,有一个遗留的 Python CLI,可以动态设置 KARMA 选项。该 Python 脚本位于:
/usr/local/P4wnP1/legacy/karmatool.py
提示:为了充分利用 KARMA 功能,您应该将 P4wnP1 A.L.O.A. 设置为提供无需认证的 WiFi 接入点,否则意义不大。对于低效的信标泛滥,这不是必需的,但用于信标的(静态)自定义 SSID 数量有限(节省 WiFi 芯片资源)
karmatool.py 的帮助屏幕:
Usage: karmatool.py [options]
Options:
-h, --help show this help message and exit
--info Print info on current settings
--whitelist=WHITELIST
Add MAC to whitelist (comma separated list)
--blacklist=BLACKLIST
Add MAC to blacklist (comma separated list)
--enable-karma Enable KARMA
--disable-karma Disable KARMA
--enable-beacon Enable beacon flooding (if KARMA is on)
--disable-beacon Disable beacon flooding
--enable-deauth Enable deauth flooding (if KARMA is on)
--disable-deauth Disable deauth flooding
--beacon-interval=BEACON_INTERVAL
Set beacon interval in ms (default 100)
--beacon-count=BEACON_COUNT
Set number of SSIDs to beacon (default 40)
--beacon-ssid=BEACON_SSID
Add custom SSID to beacon list
--karma-ssid=KARMA_SSID
Set the KARMA SSID (default "KARMA_SSID")
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
### WiFi covert channel
WiFi隐蔽通道尚未移植到Go,也不是P4wnP1核心的一部分。不过,遗留功能仍然提供。要使隐蔽通道运行,需要满足几个条件:
- 必须对目标客户端执行击键注入以植入stage1
- stage1通过(简化版的)HID隐蔽通道加载stage2,因此需要在P4wnP1上提供一个特殊的USB HID设备,并启动一个专门的HID隐蔽通道服务器来提供stage2
- 需要启动第二个服务器,并与修改后的WiFi固件交互,以管理通过WiFi隐蔽通道连接的客户端,并为这些客户端提供交互式shell访问(该服务器是一个控制台应用程序,旨在终端多路复用器中运行,如`screen`)
如果提供了所需的组件(HID加载器、WiFi隐蔽通道服务器、待交付的客户端代理),则可以使用P4wnP1 A.L.O.A.的功能集满足上述所有条件。
使用P4wnP1 A.L.O.A.执行此类任务是其能力的绝佳示例。此外,它有助于区分P4wnP1 A.L.O.A.的设计目标与非目标。
P4wnP1 A.L.O.A.不旨在:
- 成为一种“武器化”工具
- 提供无需理解背后原理或风险即可执行的RTR载荷
P4wnP1 A.L.O.A.旨在:
- 成为一个灵活、低成本、口袋大小的平台
- 为类似此处描述的任务提供支持
- 支持对渗透测试或红队任务中常见的各种USB相关任务进行原型设计、测试和执行,而不提供固定的静态解决方案
在某种意义下,`/usr/local/P4wnP1/legacy`文件夹存放了运行WiFi隐蔽通道所需的外部工具(即WiFi服务器、HID隐蔽通道加载服务器和WiFi隐蔽通道客户端代理)。这些组件可视为外部部分(不属于P4wnP1 A.L.O.A.核心)。
此外,P4wnP1 A.L.O.A.提供了一种配置,利用给定组件完成以下操作:
- 针对Windows主机进行路过式攻击,通过基于击键注入(HIDScript)的HID隐蔽通道交付内存中的客户端代码以下载stage2
- 一旦P4wnP1连接到USB主机,立即启动击键注入(TriggerAction执行HIDScript)
- 当击键注入开始时,启动加载器,通过HID隐蔽通道交付WiFi隐蔽通道客户端代理(TriggerAction运行bash脚本,该脚本又启动外部服务器)
- 在需要时启动WiFi隐蔽通道服务器(相同的TriggerAction和BashScript)
- 部署一个USB配置,提供USB键盘(用于击键注入)和一个额外的原始HID设备(用于stage2交付的隐蔽通道)——USB设置存储在设置模板中
- 部署一个WiFi配置,允许远程访问P4wnP1,以便与WiFi隐蔽通道服务器的CLI前端交互——WiFi设置存储在设置模板中
- 提供单一入口点,一次性部署所有所需配置(通过一个主模板完成,该模板包含适当的WiFi设置、适当的USB设置以及启动HIDScript所需的TriggerActions)
主模板名为“wifi covert channel”。通过从Web客户端的“generic settings”标签页部署该模板(从主模板编辑器选择“DEPLOY STORED”),P4wnP1 A.L.O.A.即可配置完毕以执行上述所有步骤。
一旦重新连接到USB主机,它应开始键入stage1,并内部启动相应的服务器。
通过SSH会话(例如通过WiFi),可以使用`screen -d -r wifi_c2`访问WiFi隐蔽通道服务器,以与通过WiFi隐蔽通道回连的客户端交互。
由于击键注入依赖于USB主机的语言布局,相应的HIDScript(名为`wifi_covert_channel.js`)有一个变量`language`,可用于调整使用的键盘布局。此外还有一个名为`hide`的变量(默认为false)。如果`hide`设置为true,则在键入stage1时,客户端上的控制台窗口会被隐藏。这再次说明了如何借助HIDScript及其背后的JavaScript引擎,将复杂任务简化为一个简单的布尔变量。
P4wnP1主模板提供的“wifi covert channel”演示也可用作启动主模板,因为WiFi访问仍然可行,因此可以随时远程更改设置。
从TriggerAction调用的相关BashScript是CLI客户端灵活性的良好示例。由于HID加载器需要知道监听哪个设备文件(代表通用HID设备的文件),但此信息仅在运行时可用(取决于启用的USB gadget功能),因此脚本通过运行`hidraw=$(P4wnP1_cli usb get device raw)`请求CLI报告正确的HID设备。
完整的BashScript存放在`/usr/local/P4wnP1/scripts`文件夹中,所有应从TriggerAction访问的bash脚本均存放于此。
### Bluetooth NAP
P4wnP1通过蓝牙网络封装协议(BNEP)提供基于蓝牙的网络功能。当前最有趣的功能是蓝牙网络接入点(NAP),它允许基于IP的蓝牙远程访问P4wnP1,例如从移动设备访问。
使用此功能时需了解以下几点:
- 蓝牙网络接口名为`bteth`,可像其他网络接口一样进行配置和模板化(通过Web客户端或CLI)
- 要允许从Android手机(iPhone未测试)进行NAP访问,手机不仅需要连接,P4wnP1还需通过DHCP在`bteth`接口上提供正确的默认网关IP。这是因为手机希望将NAP用作互联网网关(这是预期的用途)。如果NAP本身不提供网关,Android手机在DHCP D.O.R.A.之后不会进一步请求。最简单的解决方法是指示DHCP服务器将`bteth`接口自身的IP作为默认网关(DHCP选项3)。即使没有真正的上游连接,我的测试中也能正常工作——手机必须通过层3通信访问网关以进行“回连”。即使后续的连接测试失败,工作的层3连接仍然存在。这允许例如通过蓝牙进行SSH访问。启用“High Speed”后,Web客户端也能很好地工作。
- 要允许基于PIN的配对,必须禁用简单安全配对(SSP)。如果启用SSP,运行的配对代理会确认每个密码(这意味着安全性甚至比传统PIN配对更差,因为任何设备都可以连接)。或许未来会为CLI/Web客户端实现SSP密码配对的确认对话框,但目前超出范围。如果使用SSP,我强烈建议在目标设备配对后立即禁用“discoverable”和“bondable”。
- 禁用SSP的另一个缺点是“High Speed”将无法用于蓝牙连接(或要启用High Speed,必须使用SSP进行配对)。如果未启用“High Speed”(使用802.11帧进行通信),请求Web客户端大约需要10分钟;启用High Speed后只需几秒。不过,通过SSH和CLI客户端在未启用“High Speed”的NAP上访问应该没问题。
- 默认的蓝牙网络接口设置(`bteth_startup`)和默认蓝牙设置(`startup`)应允许通过传统PIN配对进行“Low Speed”SSH访问。PIN为`1337`,可通过Web客户端更改。
### TriggerAction Groups
TriggerActions有一个很好的分组功能,称为“Groups”。我未能及时提供功能演示示例,但我计划包含一个基于LED的4位二进制计数器示例(使用GPIO、拨动开关和4个LED)。
分组的概念如下:
假设您希望4个TriggerActions(TAs)在同一触发器上触发(例如“连接到USB主机时”)。您可以通过创建4个TAs,每个都带触发器“连接到USB主机时”来实现。
或者,您可以创建一个TriggerAction,当“连接到USB主机时”发生时,向名为`"connected"`的分组发送值`1`。然后定义另外4个TriggerActions,当在分组`"connected"`上接收到值`1`时触发。结果相同,但目前看来意义不大(实际上多了一个TriggerAction)。目前唯一的正面效果是,由于分组名称可自由选择,TriggerActions的可读性稍有提高。
现在,您可以做的第一个高级操作是运行以下CLI命令:```
P4wnP1_cli trigger send --group-name=connected --group-value=1
此命令的效果与“连接到USB主机”的TriggerAction以及所有其他4个等待值1到达组connected的触发动作完全相同。你可能还记得,CLI客户端可以远程运行(从不同平台),因此可用于远程触发命令。
对“组通道”做出反应的触发器称为“组通道上的值”。更有趣的触发器称为“组通道上的多个值”。这种“多个值”触发器允许在触发前监听有序的值序列,或多个值中的一个,或无序序列中的所有值。
假设你想在满足以下条件时执行一个Bash脚本:
你可以为这两个事件创建TA,如下所示:
现在你可以部署第三个TriggerAction,如下所示:
在这种配置下,只有当两个“condition”触发器都已触发时,bash脚本才会启动。
如果使用“精确有序序列”而不是“所有(逻辑与)”作为类型,那么只有在WiFi AP在USB连接触发器之前启动时,bash脚本才会启动(反之则不会)。结合GPIO触发器,例如,这可用于根据简单的PIN键盘输入触发动作。
我相信你们对“组”通道有一些很好的使用想法。
值得一提的是:
CLI客户端能够执行阻塞等待,直到特定值到达“组通道”,使用如下命令:``` P4wnP1_cli trigger wait --group-name=waitgroup --group-value=1
这可能用于从TriggerActions驱动脚本,利用CLI(充分发挥GPIO等能力)。
工作进度中,缺少的部分:
- HIDScript Trigger变量(从TriggerActions触发的HIDScript中传入的变量)
- HIDScript辅助函数(PowerShell函数)
- HIDScript演示贪吃蛇(鼠标)
- USB大容量存储(genimg辅助工具)
## 4. 救援:我搞砸了配置,无法访问P4wnP1 A.L.O.A.
P4wnP1 A.L.O.A. 不会保护你免受错误配置的影响,这些配置可能使其无法使用(就像root控制台不会阻止你运行`rm -rf /`一样)。
如果你搞砸了一切,这里有一些修复方法:
### 数据库备份
在对仍在运行的P4wnP1配置进行关键更改之前,创建数据库备份。这可以通过Web客户端的“通用设置”选项卡或CLI命令`P4wnP1_cli db backup`完成。
备份将存储在`/usr/local/P4wnP1/db`文件夹中,使用你选择的名称。
可以使用“恢复”功能或`P4wnP1_cli db restore`命令来恢复给定的备份。
备份包含所有存储的模板(USB、WiFi、网络、蓝牙、TriggerActions、主模板)以及设置的启动主模板。备份不包含HIDScript或BashScript,因为两者作为文件存储,便于编辑。
### 没有备份且搞砸了一切
当P4wnP1 A.L.O.A. 启动时,它会检查数据库是否存在。如果数据库不存在,它会基于P4wnP1 A.L.O.A. 附带的初始备份填充新数据库。
初始备份存储在`/usr/local/P4wnP1/db/init.db`,**永远不应被删除或覆盖**。
为了强制P4wnP1重新创建,必须删除实际数据库。这可以通过将P4wnP1 A.L.O.A. SD卡挂载到能够写入EXT分区的系统上来实现。
完成后,从SD卡根分区删除文件夹`/usr/local/P4wnP1/store`。这将删除数据库,从而在下次启动P4wnP1时强制重新创建。
### 有备份但无法访问P4wnP1来恢复
如果你无法恢复现有数据库(因为无法访问),你仍然可以按照“没有备份且搞砸了一切”中的步骤操作。除了删除`/usr/local/P4wnP1/store`之外,用你的备份文件替换`/usr/local/P4wnP1/db/init.db`(确保你备份了init.db的副本)。
这应该在重新启动P4wnP1后重新创建你的自定义数据库。
### 我搞砸了备份的启动主模板
如果你有一个备份,但其中的启动主模板不起作用,你需要执行一些额外步骤,因为无法直接在备份中更改启动模板。
首先按照“没有备份且搞砸了一切”中的步骤操作,这将会重新创建初始P4wnP1数据库。
重启P4wnP1后,你应该能够再次远程访问P4wnP1的Web客户端。
转到“通用设置”并恢复你自己的备份(带有错误启动主模板的那个)。
“启动主模板”应该显示你的“损坏”主模板已被选中。如果不是,请重新加载托管Web客户端应用的浏览器标签页。
再次导航到“通用设置”选项卡,选择一个已知能工作的启动主模板。
此时,你应该可以重启了。
### 以上方法都没有帮助
抱歉,看来你需要从干净镜像重新创建P4wnP1 A.L.O.A. SD卡。
## 5. 致谢
正在建设中,顺序随机
- @JohanBrandhorst(关于gRPC-web via gopherjs的密切交流,极其快速地实现了“用于服务器流式传输的websocket”,功能请求)
- @steevdave, @_binkybear(Kali构建脚本,讨论和持续交流)
- @Re4sonKernel(支持将P4wnP1内核更改迁移到维护良好且流行的仓库,合作修复Bluez)
- @SymbianSyMoh(无需重启即可重新触发HID攻击的灵感)
- @quasarframework(可以将其列在第三方库下,但这里所做的工作非常出色;P4wnP1 Web客户端的外观基本上基于这个漂亮库的默认组件)
- @CyberArms(P4wnP1最早的支持者之一,编写了最好的教程甚至关于此类主题的书籍)
- @LucaBongiorni(不仅是最早的支持者之一,他在硬件方面做的工作正是我只能在软件中做的;他做关于USB主题的演讲,并尊重开源解决方案,总之是一个很棒的人,给了我灵感)
- @evilsocket(他的代码块促使我转向Go,一个伟大的开源开发者,读他的代码你就明白我的意思)
- @RoganDawes和@Singe from @SensePost(鼓舞人心的人)
- @Swiftb0y(早期支持者,“旧”P4wnP1 WiKi的创建者,P4wnP1 A.L.O.A. 想法的早期测试者)
- @marcaruel(关于使用periph.io进行GPIO边沿检测的讨论)
## 6. 待办事项和支持
这不是一个完整的待办事项列表,但还有一些里程碑未完成,我很乐意在此获得社区支持
- 将完整的HID隐蔽通道功能移植到Go核心(我自己在做)
- **为CLI添加蓝牙配置命令**
- 创建额外的键盘布局(当前支持br, de, es, fr, gb, it, ru和us)
- 扩展蓝牙功能,允许连接到其他可发现设备(身份验证和信任)
- 将WiFi KARMA功能从专用的Python工具移动到P4wnP1核心(支持Web客户端)
- 为HIDScript创建完整文档(基本上只缺少鼠标部分)
- 为P4wnP1创建完整文档(希望社区参与)
- 消除对docker netlink的剩余依赖(参见`netlink`文件夹的README)
关于蓝牙的说明:
P4wnP1使用自定义绑定到Bluez API。尽管Bluez API支持低功耗蓝牙(GATT,模拟外设等),但不打算将此功能集成到P4wnP1 A.L.O.A. 中。
关于Nexmon的说明:
P4wnP1利用nexmon。大多数人知道nexmon是一种固件修改,允许为博通WiFi芯片(包括Raspberry Pi Zero W使用的BCM43430a1)启用监控模式和包注入。但nexmon远不止于此,它是一个框架,允许修改ARM固件二进制文件(经过一些逆向工程后),使用高级C代码编写的补丁。P4wnP1使用此框架对WiFi固件应用自定义补丁,以启用基于硬件的KARMA支持以及固件(和驱动程序)对WiFi隐蔽通道的支持。此修改的目的不是为内置WiFi接口提供适当的监控模式或注入支持。尽管传统的nexmon监控模式功能包含在当前WiFi固件中,但它被认为是“有错误的”,因为它会干扰P4wnP1使用的标准WiFi功能(如果接口用于站点模式等,会导致崩溃)。
## 7. 版权
P4wnP1 A.L.O.A.
版权所有 (C) 2018 Marcus Mengs
本程序是自由软件:你可以重新分发和/或修改它
遵循由自由软件基金会发布的GNU通用公共许可证条款,
无论是许可证的第3版,还是(根据你的选择)任何后续版本。
分发本程序是希望它有用,
但不提供任何保证;甚至没有默示的保证
适销性或特定用途的适用性。有关更多细节,请参阅
GNU通用公共许可证。
你应该已经收到了一份GNU通用公共许可证副本
与本程序一起。如果没有,请参见 <http://www.gnu.org/licenses/>。