Skip to content
STIMSMITH

SOURCE ARCHIVE

SHA256: f6f0d9a910e6e41d7d02b9d3ff081935445d2f18de6d41b44c01ba9282611640
TYPE: application/pdf
SIZE: 3110.2 KB
FETCHED: 7/19/2026, 10:16:18 AM
EXTRACTOR: liteparse
CHARS: 30,697

EXTRACTED CONTENT

30,697 chars

Low Power, High Risk: Fuzzing the Chips Behind IoT

Noah Holmdin & Ravishankar Borgaonkar Hardwear.IO 2025 Amsterdam, Netherlands 20.11.2025

    About Me – Noah Holmdin & Ravishankar Borgaonkar

Noah Holmdin- NTNU / Aalto University Security enthusiast interested in both technical and strategical dimensions of information security • Last year MSc in Information security student at the Norwegian University of Science and Technology (NTNU) • Currently on an exchange term at Aalto University • BSc in Computer Science, Linköping University

Ravishankar Borgaonkar - Senior Research Scientist (SINTEF AS) 15+ years of research in telecom/cyber security research, with experience at: • University of Oxford, Oxford, UK / TU Berlin / Aalto University • Deutsche Telekom Labs ( T-Labs), Berlin, Germany / Intel ICRI, Helsinki, Finland

Focus areas: • ICT Security architecture & vulnerability analysis • Contributed to 4G/5G (3GPP) security improvements Feel free to reach out: • Recognized by Google, GSMA, Qualcomm, Huawei (Hall of Fame) Email: Noah.Holmdin@outlook.com Email: Ravi.Borgaonkar@sintef.no 2 LinkedIn: linkedin.com/in/noah-holmdin-112579252

wall Fuzzing 101

3

Fuzzing 101 75 years

      Al TOOLS WRITE
    FIRMWARE CODE NOW
       Sh)
       =
       / ZN |] 1

               A
       7 y 1 | He
    1
    QUERY

4

 Fuzzing Technique

Why Fuzzing • Automates security testing by sending malformed inputs to uncover bugs and vulnerabilities • Critical for IoT and embedded systems due to complex code, broad attack surfaces, & limited OSisolation • Proactive approach: identify vulnerabilities before attackers exploit them

What • Repeatedly executes target software with random or mutated inputs to trigger faults or crashes • Embedded/firmware fuzzing is unique: inputs delivered via hardware peripherals (MMIO, interrupts, DMA) rather than standard interfaces How • Coverage-guided fuzzing: leverages feedback on code paths explored during execution • Emulation/re-hosting: simulates firmware in virtual environments (e.g., QEMU, Unicorn) to enable fuzzing without physical hardware

5

 Why Fuzz anything?

Usual CPU fuzzing • Targets OS-based binaries and user-space software (e.g., browsers, kernels) • Benefits from standard I/O, memory management, process isolation, and high execution speed

IoT/Microcontroller Unit (MCU) fuzzing challenges • No OS protection: monolithic firmware with constrained memory and non-standard I/O • Inputs delivered through Memory-Mapped I/O (MMIO) registers, interrupts, and DMA • Hardware dependency prevents firmware from running easily off-device

Low power bluetooth IoT MCUs • Built on SoCs like Nordic nRF52 • Complex peripheral behavior, timing sensitivity, and radio events add fuzzing complexity • On-device fuzzing impractical (slow and potentially destructive); emulation-based re-hosting is essential

6

        FUZZWARE** Tool for

Overview
•   Combines lightweight program analysis, firmware re-hosting, and coverage-guided fuzzing
•   Novelty: Precise MMIO modeling that eliminates input overhead by focusing only on meaningful
    hardware-generated values – best for MCUs





                Fuzzware: Using Precise MMIO Modeling
                    for Effective Firmware Fuzzing

Tobias Scharnowski, Nils Bars, and Moritz Schloegel, Ruhr-Universitat Bochum; Eric Gustafson, UC Santa Barbara; Marius Muench, Vrije Universiteit Amsterdam; Giovanni Vigna, UC Santa Barbara and VMware; Christopher Kruegel, UC Santa Barbaro; Thorsten Holz and Ali Abbasi, Bochum https//www.usenix,org/conference/usenixsecurity22/presentation/scharnowski

    ** Soruce - https://www.usenix.org/system/files/sec22-scharnowski.pdf
7

FUZZWARE main() Logic                                                    Fuzzware: Using Precise MMIO Modeling
                                                                         for Effective Firmware Fuzzing

SINTEF Tobias Scharnowski, Nils Bars, and Moritz Schloegel, Ruhr-Universitat Bochum; Marius Gustafson, 75 year Eric UC Santa Barbara; Muench, Vrije Universiteit Amsterdam; Giovanni Vigna, UC Santa Barbara and VMware; Christopher Kruegel, UC Santa Barbara; Thorsten Holz and Ali Abbasi, Bochum Main Components https//www.usenix.org/conference/usentxsecurity22/presentation/scharnowski

• Fuzzing Engine: Generates random or mutated input data to test | how the firmware reacts. It also monitors which parts of the code Hardware: io Access are executed (coverage feedback). enerate Value • Raw Input: The sequence of bytes produced by the fuzzer, e.g. like - Joost fake sensor readings or control signals. Fuzzware Emulator nl • MMIO Access Model: Converts chunks of the raw input into — “hardware-like” responses. e.g, when firmware tries to read from a sensor register, the MMIO model provides a realistic fake value. Fuzzing Engine Feedback • ISA Emulator: Runs the firmware binary as if it were on a real Figure 4: FUZZWARE's MMIO access handling design. The fuzzing engine microcontroller, using the fake MMIO responses. generates a raw input file. Upon MMIO accesses, chunks of the input file are • Coverage Feedback: After each run, the emulator reports which consumed by MMIO access models and translated into (potentially larger) hardware-generated values, which are then served to the emulated firmware. new code blocks were executed, helping the fuzzer learn and refine Once the raw input is exhausted, coverage feedback is provided to the fuzzing future inputs. engine to guide the fuzzing process.

Source - https://www.usenix.org/system/files/sec22-scharnowski.pdf 8

Run Fuzzware

UNE

Jr. if A fe Hi₀ »

AFT

§

a oi JY ( 1587.

oa i Ry ful

9

    Fuzzing Project Work

01 02 03

Improving the user- Motivated by Secondary goal: friendliness of using previous research Analyze crashes Fuzzware on nRF52 regarding feasibility that are deemed devices of Fuzzing potential embedded devices vulnerabilities

10

   Initial Experiments

Configuration issues

• Fuzzerware’s automatic configuration tool did not create a valid memory map for our target binary • The configuration did not include the FICR and UICR mmio memory sections → Could not emulate the binary • UICR = a user-programmable configuration memory that can influence how the chip boots • FICR = holds read-only factory data about the chip.

Initial Experiments
Manual Configuration

Manually created configuration which could be emulated, but:

Slow Identified Difficult to execution crashes in the know how to time emulation move forward

gual The Aurora-Fuzz workflow
    A simple, but structured workflow for starting a fuzzing process.



If new version


If emulation failed




If coverage meaningful






            If coverage not meaningful

,  encountered

Analyze Crash / Crashes If crash caused by configuration

13

The Aurora-Fuzz Workflow

• Through the iterative process, we improved our configuration by: ‒ Adding static/constant mmio reads in bootloader → Quicker path to “user code” ‒ Identified and patched delay functions → Improved speed significantly ‒ Identified and patched “wait-for-flag” conditions

14

   The Aurora-Fuzz Configuration Script      ;

• Enabling simple automation of : Ce Fuzzware’s configuration process for nRF52 binaries = • Python script developed in response to feature requests from our industry partners 0x1000 ‒ One-click tool: generate configuration + i start fuzzing as Va ri 15 em = o

               The Aurora-Fuzz                                python3    configuration_tool.py   ../testing test.bin

—75years— Configuration Script Ue Retr leva Found binary file: ../testing/test.bin Do you want to load an existing config, or generate a new based on template? Key Features 0. Exit ‒ Command-line tool for creating and 1. Generate a new config 2. Load from ../testing directory modifying Fuzzware configurations re BE pt ‒ Start fuzzing sessions directly from the script Note, the configuration will not be saved unless explictily choosing the save option ‒ Filtering certain MMIO reads from 1. Print Memory Map Softdevice 2. Modify Memory Map 3. Skip Softdevice Noise ‒ Load static UICR/FICR state of from hex 4. Add Symbols S. Load UICR/FICR preset file file, or directly from USB connected chip 6. Modify BOOT i t ‒ Run flags that can be used to 8. Modify Interrupt Config 9. Modify Return Handlers automatically patch certain delay 10. Modify Exit At Model functions 11. Save config 12. Test Fuzzing Configuration 13. Start Fuzzing Session

                                                 0.   Exit

16 Enter menu choice: J]

SINTEF Framework Evaluation

Experiment against a nrf52 binary, Translation Blocks Visited Over Time id with three configurations created oe with the configuration script: • Config 1: basic configuration 2000 • Config 2: automatic optimization i • Config 3: automatic + manual § optimizations 5 oo

                                                  —
                                            —— Session2 -       config2.log
                                  0         —— Session3 -       config3.log

                                      0     10      15      20  25
                                            Elapsed Time (Hours)

17

SINTEF Framework Evaluation

                                        Translation Blocks Visited Over Time

Takeaways: gai • Aurora-Fuzz capable of generating 4000 05 working configuration • Optimizations discovered through 2 3000 the iterative Aurora-fuzz workflow 2 significantly improved coverage 2000 • Defining “good” coverage in embedded firmware remains 1000 difficult —— Session: 1 - configl.log • Complexity of architecture still —— Session2 - 3 config2.log 0 — og Session config3 cause emulator to plateau early ° i eed Time (ours) 2

18

SINTEF From Project Work to Bug Hunting

  |    Shifting focus to analyze crashes

~ a encountered during our experiments ee • We encountered similar crashes early —_ in program execution during fuzzing of several binaries

: | AK

  Image generated with ChatGPT

19

SINTEF

   Crash Analysis                                                        Calling  function:    delay     machine code.6 from  nrfx_coredep delay  us (PC=0x3e850,   LR=0x2643d)
                                                                         Basic  Block:  addr=                           (1r=0x2643d)

                                                                         Basic  Block:  addr=   0x000000000002643c      (1r=0x2643d)
       An initial overview                                               Basic  Block:  addr=                           (1r=0x2643d)
                                                                                  >>>  Read:   addr=                           size=4                     [(pc
                                                                         Basic  Block:  addr=                           (1r=0x2643d)
                                                                                  >>>  Read:   addr=     0x2003ffbc[SP:-0004]  size=4    data=0x0000002b   (pc  0x000266b8)

• Using Fuzzware’s built in functionalities to: >>> Write: addr= 0x2003ffbc[SP:-0004] size=4 data=0x0000002a (pe (pc >>> Read: addr= 0x2003ffbc[SP:-0004] size=4 0x000266be)

  1. Gather crash buckets                                                  Basic  Block:  addr=   0x00000000000266b0      (1r=0x2643d)
                                                                          Calling  function:    nrfx_coredep delay   us  from              ms (PC=0x2641c,      LR=0x266b9)
    
    ‒ Maps crashes based on their instruction pointer and link registers Basic Block: addr= 0x000000000002641c (1r=0x266b9) ‒ Creates paths that can be used to replay the crash >>> Write: addr= 0x2003ffb4[SP:+0004] size=4 (pc >>> Write: addr= size=4 data=0x000003e8 (pc
  2. Replay crash traces                                                   Basic    >>>  Read:   addr=     0x2003ffa4[SP:-0004]  size=4    data=0x000003e8   (pc  0x00026422)
                                                                                 Block:  addr=   0x0000000000026428      (1r=0x266b9)
    
    ‒ Outputs path taken in emulator up until the crash, including >>> Read: addr= 0x0000000000026448 size=4 data=0x0003e850 (pc 0x00026428) ▪ MMIO interactions, and >>> Write: addr= 0x2003ffac[SP:-000c] size=4 (pc ▪ code blocks visited >>> Read: addr= 0x2003ffa4[SP:-0004] size=4 data=0x000003e8 (pc 0x00026430) >>> Write: addr= 0x2003ffa8[SP:-0008] size=4 (pc 0x00026434) >>> Read: addr= 0x2003ffac[SP:-000c] size=4 data=0x0003e851 (pc 0x00026436) >>> Read: addr= 0x2003ffa8[SP:-0008] size=4 (pc 0x00026438)

→ Gives an initial overview of the crash Calling function: delay machine code.6 from nrfx_coredep delay us (PC=0x3e850, LR=0x2643d) Basic Block: addr= 0x000000000003e850 (1r=0x2643d) Basic Block: addr= 0x000000000003e854 (1r=0x2643d) Basic Block: addr= (1r=0x2643d) Basic Block: addr= (1r=0x2643d) Instruction pointer (EIP, PC) = The instruction pointer tells >>> Read: addr= size=4 (pc the CPU what instruction to execute next. Basic Block: addr= (1r=0x2643d) >>> Read: addr= size=4 data=0x0000002a (pc 0x000266b8) Link register = The link register stores the return address — >>> Write: addr= 0x2003ffbc[SP:-0004] size=4 data=0x00000029 (pc where the CPU should go back to after finishing a function Basic >>> Read: addr= 0x2003ffbc[SP:-0004] size=4 data=0x00000029 (pc 0x600266be) Block: addr= (1r=0x2643d) Calling function: nrfx_coredep delay us from nrf delay ms (PC=0x2641c, LR=0x266b9)

  Crash Analysis      Instruction Pointer values at crashes
  An initial overview

→ In our case: • Crashes occurred at around the same stage of EIP: 0x55555555 execution, but with different instruction pointer values • Mostly related to the emulator trying to read from unallocated memory sections ‒ Repeating values in stack pointer, ex: 0xA5A5A5A5 • All crashes showed a consistent sequence of code blocks leading up to the failure • So we needed to dig deeper into this shared execution pattern to understand what those blocks were doing

SINTEF Crash Analysis 75 year Going deeper

                              4%     oo                                  ©
                                                                             [ll           BES          0050c - (packedup)  |
                          data                        77                     A                  i
                                                      EE
                                                          sequen
Utilized the reverse                              ane ora       outs     acm Good et                akin
engineering tool ghidra   Br        00400090.        00
                          8 fini_array    P       aa      ELf64_Endr                            9   bool
                          mm                                FE
                          B fini        00400005  01        dedb      n   e_ident_data     i            -  topkey for      << 0c)

= sn

  • 00400018 0 04 40 0 60 dh In Hd! 1s; Th od GHIDRA Sa + cous dg entry o_phoff 4 1 ite Givers 1s

1+ JO | ‒ Enabled us to find the § FUN00400500 oo 7 b¥ars = 18 < 0; instructions causing the Tce red 0 60 ohn 3 arty) Cn 1+ 101 = i ri crash ie El ec ‒ Related to MMIO reads » jd Eo | writell, Yep! jou got the flag 1 from the UICR memory sari os ot ror +7 section, in the SoftDevice 1x BEE 1 part of the binary er mm co. HHH

                                       <                                                      >

                                       =                                                                                                 adix


                                Fier.
   2!                                                 Source: https://commons.wikimedia.org/w/index.php?curid=77146565

Crash Analysis Understanding the root cause

                                Fuzzed UICR READ:
                                 0xA1A1A1A1
                                                     SP: 0xA1A1A1A1
                                      Crash path    EIP: 0xFFAAFFAA

                  JUMP block
                                  SP

SP: 0x20001000 SP: 0x20001000 SP: 0x20001000 Path determined by UICR read EIP: 0x00000000 EIP: 0x00000008 EIP: 0x0000000F

                                  EIP

                                      Intended path  SP: 0x20001000        MAIN
                                                    EIP: 0x00210000

                  Fuzzed UICR READ:
                                 0xFFAAFFAA

Reminder: UICR = a user-programmable configuration memory that can influence how the chip boots

SINTEF

75 years.

Crash Analysis Creating an emulation PoC

Modified the Fuzzware configuration with a static MMIO read at the exact instruction pointer in the JUMP block → Read 0x00000000 → EIP set to 0x00000000 Result

        SP: 0x20001000    SP: 0x20001000    SP: 0x20001000   = Path determined by UICR read

Loop path EIP: 0x00000000 EIP: 0x00000008 EIP: 0x0000000F

  = Infinite loop                           EIP      Intended path   SP: 0x20001000        MAIN
                                                                     EIP: 0x00210000
                                            Static UICR READ:
                                            0x00000000

At this stage

Confirmed weakness in the emulated environment

Next: Does the weakness also affect the actual hardware? =

|}

Problem: How should we manipulate a MMIO read? )

Generated with ChatGPT

25

SINTEF Deciding on an approach Target: NRF52840 development kit +4 fay 4 ed Two potential approaches: ® pi 2 I §

  1. Hardware glitching – voltage/power fault injection =
    • Realistic pt fv
    • Complex pen
  2. Debug mode – Inject value UICR through the nrfjprog utility
    • Feasible fre : x
    • Controlled but less realistic

Chosen method: Debug mode Hi 5 i nRF52840-DK 89 26 Source: https://www.nordicsemi.com/Products/Development-hardware/nRF52840-DK

SINTEF — Creating the PoC { attribute ((used)) malicious ( ) leds_init();

                                                        for  (     =0;  j   <   16; j++)

• Added a hidden “malicious” function to modified { for blinky firmware • Compiled the firmware and located the function bsp_board led nrf_delay address in Ghidra — 0); • Injected that address into the UICR register read at == 15 & i >= 2 the JUMP block (using nrfjprog) ‒ To test whether the MCU would jump to the “mov re, %[vall i unreachable code

                                                                            "re"
                                                                    ii
     main (       )                                             }
   {
                                                        }
                                                        bsp_board  led  on(0);
                                                                   led  on(1);
                                                        bsp_board  led  on(2);
     if   (*          *)0x20003000 == 0xA2B3C4D5)                  led  on(3);
     {
          malicious();                                  nrf_delay
     }                                                  bsp_board  led  off(0);
                                                        bsp_board  led  off(2);
     for  (;;)                                          nrf_delay  ms(3000);
     {

          idle    state handle();                       buffer   underwrite();
     }                }

27

Demo https://youtu.be/9nBUH_oLk9E SINTEF - FM SOK 15... Q = =Nov20B x1539 Gow v « 8 @ = B a 9 sh program₊ BF Trees | | v X 2840 x Ts a B deta 1 WIG: stain @&= B 08 c7 cz 00 PIM WARNING bals starting wil [B® DAT Sh B on sack J A

[© observers nm 1a 23 00 20

segment. hstrtab 14 undefined [Program ree | = | 78 c1 62 60 our} i bap

x| 8 wi J PT T our) a “ned tes 1 Pom 5

os \ void 2 dw { em cote a = aris wid FUE page do{ Ri + 01 18 41 3 ” 20 H

§ 34 4d13 ot bo u - = ofa 18 61 i 17 Salts 40 45 10 01 03 7 41 10 00 03 ne NEE | la of

Types 00620208 ze de out 00 2 84 » 45 » 0002a20¢ cb 18 00 90 #8}= 47 bsp on(2) 5 48

re mom bo L ST cs 34 id | add

  • Scripting. x

    28 El 15 Corso % | % | maiicious [push

    —75 years — Demo

https://youtube.com/shorts/YnC6WsLTQ3k https://www.youtube.com/shorts/LrtDehPDt 8U

   CLE     EB     te 5     i

29

Implications

If we can manipulate the specific UICR read, then we gain control of both the instruction pointer and the stack pointer →Remote Code Execution →Denial of Service →Stack Overflow

Next step: report the findings to the manufacturer

30

Bug(?) Reporting

Wrote vulnerability report and sent in through Nordic’s vulnerability disclosure form ➢ Weeks without answer Uploaded private blog post on Nordic’s forum ➢ Quick response, referring us to the disclosure form Tried gaining access to their private bug bounty program ➢ Could not get an invite Eventually established direct contact with their security team and prepared to submit the report via PGP ➢ While PGP may offer Pretty Good Privacy, it also offered Pretty Difficult Privacy Takeaway: Do not report vulnerabilities during the summer in the nordics 31

 SINTEF Is this a vulnerability?

Yes/No, but interesting a i • Our PoC required debug mode, the behavior is not i exploitable in the same way for production devices ae ‒ And in debug mode, even worse things can be done • Using values from UICR to set PC/SP is an intended (( )) feature for customer customization • Feature vs potential security issue BUG FEATURE Source: https://www.reddit.com/r/ProgrammerHumor/comments/1w1u3o/bug_vs_feature/

32

SINTEF    Is this a vulnerability?

What about other injection approaches?
‒  NRF52 family has been shown vulnerable to glitching    \    |       \ |
   attacks
   ▪  CVE-2020-27211                                                PN    Pa
   ▪  "MEDICAL DEVICE Security Analysis", Cc-sw, Available:               ie
      https://cc-sw.com/medical-device-security-analysis/               svi,
This means the code path we identified might be                     \\
reachable under real-world glitching conditions          BUG        FEATURE

• Shows that there is a thin line between feature and Source: https://www.reddit.com/r/ProgrammerHumor/comments/1w1u3o/bug_vs_feature/ flaw ‒ Removing the feature improves security… ‒ …but may break legitimate customer use cases 33

Take Aways

• At it’s core, Fuzzware is good for finding vulnerabilities, but lacks some usability aspects  Not “plug and play” • Our approach for improving user-friendliness makes starting a fuzzing process easier. But, the analysis still demands manual analysis of analyzing outputs. Which requires a good understanding memory layouts and assembly instructions • Fuzzing Bluetooth devices is time consuming due to reliance on MMIO communication. To get good coverage • There is some cases a thin line between feature and security flaw (Again!) • Vulnerability disclosure - Do not report vulnerabilities in the Scandinavia during the summer

34 27/08/2025

Questions?

Feel free to reach out: © Email: Noah.Holmdin@outlook.com © Email: Ravi.Borgaonkar@sintef.no ¢ LinkedIn: linkedin.com/in/noah-holmdin-112579252

Special Thanks for :

TELEMETRY EU Project (https://telemetry-project.eu/) Norwegian Research Council funded RAKSHA Project - 312122 Norwegian Research Council funded NORCICS Project –310105