seemoo-lab / nexmon

The C-based Firmware Patching Framework for Broadcom/Cypress WiFi Chips that enables Monitor Mode, Frame Injection and much more
GNU General Public License v3.0
2.4k stars 450 forks source link

Injecting Frame with RPi 3B - libnexmon.so #463

Open DennisHerell opened 3 years ago

DennisHerell commented 3 years ago

Hi, first of all I want to say thank you for the great tools provided by seemoo-lab. I have managed to extract CSI using a raspberry pi (RPi 3B+), and now I want to inject frame using another RPi (3B with bcm43430a1) from which I can collect the CSI. I am new to this field, so I have a hard time implementing the frame injection.

Firstly, I want to clarify my understanding of injecting frame. I've gone through the many discussions here, and from what I gathered, there are many way to inject frame. We can use the aireplay-ng to inject frame for example, and I've managed to inject frame using that. However, injecting frame this way is not really relevant for the purpose of extracting CSI. Nexmon has provided functions to implement frame injection that allow us to control several parameter such as:

From what I understand the function to send frame are defined in sendframe.c and injection.c, and to implement it I need to write an ioctl that call those function, am I right? An example of ioctl code that implement frame injection can be seen in https://github.com/seemoo-lab/wisec2017_nexmon_jammer_demo_firmware/blob/master/src/ioctl_5xx.c#L489

After writing the necessary ioctl code, I need to write my injection program that send the ioctl message. Finally, I run the injection by putting the bash command: LD_PRELOAD=libnexmon.so [INJECTION_PROGRAM]

So my questions are:

  1. Am I correct so far? I feel like I'm misunderstanding many things.
  2. What is libnexmon.so for? By using LD_PRELOAD, that mean when the program is looking for a function definition it will look through libnexmon.so first, right? I tried to compile it, but the makefile seem to only work for android. I tried to compile it myself but failed. Is libnexmon necessary for injecting frame?
  3. Now... I think I'm misunderstanding many thing by saying this, but - The injection program is needed to send the command to inject frame through ioctl message, nexutil is what used in nexmon_csi to send that message, can I also use nexutil to inject frame?

I hope someone can help me clarify these issues. Thanks!

jlinktu commented 3 years ago

You do not need LD_PRELOAD=libnexmon.so on the RPi. It is used on Android devices to fake a monitor mode interface.

Here is a code snipped for transmitting a fixed data frame using 20MHz and MCS 4 that can be triggered using an IOCTL call. The code should be placed inside ioctl.c. This will end up in the firmware.

...
// additional includes
#include <rates.h>
#include <sendframe.h>
// a data frame, dst and src are 00:11:22:33:44:55
static char packet_bytes[] = {
0x88, 0x42, 0x2c, 0x00,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
0x20, 0x21, 0x00, 0x00,
0x46, 0x09, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
0x32, 0xf5, 0x22, 0xdf, 0xf1, 0xb2, 0xf5, 0x9b,
0x19, 0x20, 0x0e, 0x56, 0x9e, 0x27, 0xac, 0x7c,
0x6c, 0xb0, 0xca, 0x4b, 0x56, 0x10, 0x10, 0x51,
0x8e, 0xe2, 0x19, 0x75, 0x4f, 0x80, 0x44, 0x7d,
0x87, 0x73, 0xc1, 0x0e, 0x2f, 0xf5, 0x2e, 0x7c,
0xdc, 0x05, 0xba, 0x91, 0x3e, 0xe0, 0x94, 0xd3,
0x82, 0x2a, 0x25, 0x3c, 0xe1, 0xbb, 0xb4, 0xef,
0x83, 0x60, 0xef, 0x3e, 0xf0, 0x79
};
...
wlc_ioctl_hook(...
...
    // define a new ioctl
    case 599:
    {
        // suppress scanning
        set_scansuppress(wlc, 1);
        // disable minimal power consumption
        set_mpc(wlc, 0);
        // get length of packet
        int len = sizeof(packet_bytes);
        // reserve a packet buffer with header space
        sk_buff *p = pkt_buf_get_skb(wlc->osh, len + 202);
        // pull header space
        char *packet_skb = (char *) skb_pull(p, 202);
        // copy packet bytes to buffer
        memcpy(packet_skb, &packet_bytes, len);
        // send packet with specific rate
        uint32 rate = RATES_BW_20MHZ | RATES_OVERRIDE_MODE | RATES_ENCODE_VHT | RATES_VHT_MCS(4) | RATES_VHT_NSS(1);
        sendframe(wlc, p, 1, rate);
        ret = IOCTL_SUCCESS;
        break;
    }

To trigger this code you can use an IOCTL call, e.g. using nexutil:

nexutil -s599

It is also possible to pass data along with an IOCTL call. Inside wlc_ioctl_hook you can access it via the arg argument and its length via len. This can e.g. be used to pass the packet bytes and/or rate settings dynamically to the firmware. nexutil already provides you options to do this easily, see its help output for more. For example code have a look at how we pass configuration parameters to the firmware via IOCTL 500 for the nexmon_csi patch.

DennisHerell commented 3 years ago

Thank you very much for the response! The comment for each function really help, I'll try to implement it for now

DennisHerell commented 3 years ago

May I know what is the purpose of set_scansuppress(wlc,1)? I tried to install nexmon with the change you've given to the ioctl.c, but it failed to compile. I found out the set_scansuppress in helper.c does not include bcm43430a1. I tried to just add bcm43430a1, but helper.c failed to compile after that change.

So I tried installing it without the set_scansuppress function, and it successfully compile. However, after calling nexutil -599 nothing seem to happen. Is bcm43430a1 not supported for frame injection?

Edit: I tried installing it in rpi 3b+ with bcm43455c0 and this time everything compiled successfully, however I found no indicator that the injection work. What I did was:

Am I using it correctly? Did I miss something? I assume calling nexutil -s599 only transmit once, so I did it many times.

Maybe it need to be done with timer? I tried incorporating the sendframe_with_timer but it didn't work. I realize the sendpacket function in [https://github.com/seemoo-lab/mobisys2018_nexmon_covert_channel/blob/de4e3823eb2262ae1391e2aa80d513e6700adeed/src/ioctl_7xx.c#L344] is very similar, but it use rate = RATES_RATE_6M instead of the various parameters. Are the rates I'm using correct? @jlinktu your help would be really appreciated

Monjur-Mahathir commented 2 years ago

You do not need LD_PRELOAD=libnexmon.so on the RPi. It is used on Android devices to fake a monitor mode interface.

Here is a code snipped for transmitting a fixed data frame using 20MHz and MCS 4 that can be triggered using an IOCTL call. The code should be placed inside ioctl.c. This will end up in the firmware.

...
// additional includes
#include <rates.h>
#include <sendframe.h>
// a data frame, dst and src are 00:11:22:33:44:55
static char packet_bytes[] = {
0x88, 0x42, 0x2c, 0x00,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
0x20, 0x21, 0x00, 0x00,
0x46, 0x09, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
0x32, 0xf5, 0x22, 0xdf, 0xf1, 0xb2, 0xf5, 0x9b,
0x19, 0x20, 0x0e, 0x56, 0x9e, 0x27, 0xac, 0x7c,
0x6c, 0xb0, 0xca, 0x4b, 0x56, 0x10, 0x10, 0x51,
0x8e, 0xe2, 0x19, 0x75, 0x4f, 0x80, 0x44, 0x7d,
0x87, 0x73, 0xc1, 0x0e, 0x2f, 0xf5, 0x2e, 0x7c,
0xdc, 0x05, 0xba, 0x91, 0x3e, 0xe0, 0x94, 0xd3,
0x82, 0x2a, 0x25, 0x3c, 0xe1, 0xbb, 0xb4, 0xef,
0x83, 0x60, 0xef, 0x3e, 0xf0, 0x79
};
...
wlc_ioctl_hook(...
...
    // define a new ioctl
    case 599:
    {
        // suppress scanning
        set_scansuppress(wlc, 1);
        // disable minimal power consumption
        set_mpc(wlc, 0);
        // get length of packet
        int len = sizeof(packet_bytes);
        // reserve a packet buffer with header space
        sk_buff *p = pkt_buf_get_skb(wlc->osh, len + 202);
        // pull header space
        char *packet_skb = (char *) skb_pull(p, 202);
        // copy packet bytes to buffer
        memcpy(packet_skb, &packet_bytes, len);
        // send packet with specific rate
        uint32 rate = RATES_BW_20MHZ | RATES_OVERRIDE_MODE | RATES_ENCODE_VHT | RATES_VHT_MCS(4) | RATES_VHT_NSS(1);
        sendframe(wlc, p, 1, rate);
        ret = IOCTL_SUCCESS;
        break;
    }

To trigger this code you can use an IOCTL call, e.g. using nexutil:

nexutil -s599

It is also possible to pass data along with an IOCTL call. Inside wlc_ioctl_hook you can access it via the arg argument and its length via len. This can e.g. be used to pass the packet bytes and/or rate settings dynamically to the firmware. nexutil already provides you options to do this easily, see its help output for more. For example code have a look at how we pass configuration parameters to the firmware via IOCTL 500 for the nexmon_csi patch.

Hi, can you kindly tell me to pass parameters to the firmware in details? I see the struct params in the IOCTL 500, but how do I pass the params from nexutil -s500 command?