Protect your devices from Malicious Hacking with Emproof Nyx

Address memory safety issues in languages such as C/C++ and protect your systems.

Understanding and mitigating memory safety risks

In software development and security, understanding risks and mitigation strategies is crucial, especially with memory-unsafe languages like C/C++. These languages offer powerful capabilities but present significant memory management challenges that can lead to vulnerabilities.

  • Memory safety issues: C/C++ are prone to memory corruption due to manual management and risky features like pointer arithmetic.
  • Tool limitations: Static and dynamic analysis tools are essential but often miss bugs due to limited coverage and complex runtime behaviours.
  • Risk of exploitation: In case memory corruptions or other bugs are missed, these can often be misused by attackers to write exploits, putting the entire security of devices at risks.

Find out where the problem emerges and how this is exploited below.

70%

of severe security vulnerabilities in major tech companies are caused by memory safety issues.

~80%

of embedded systems will continue to rely on memory-insecure languages, such as C/C++, in the next decade.

C/C++ Source Code

C/C++ are considered memory-unsafe languages primarily due to their reliance on manual memory management, which is a common source of memory corruption and errors.

  • Complex codebases and risky features like pointer arithmetic make bugs difficult to detect.
  • Memory safety issues contribute to about 70% of severe security vulnerabilities in major tech companies.
  • Static code analysis tools often miss runtime or complex bugs and can produce false positives and negatives.
Why might static code analysis tools be insufficient for detecting memory safety issues in C/C++ code?

Static code analysis tools scan for unsafe patterns but do not execute the program, leading to limitations like false positives and false negatives. These tools often miss complex or domain-specific bugs, as they lack runtime context. For example, a study found that three static analysers together identified only 4.5% of bugs, highlighting both their usefulness and the significant number of bugs they fail to catch.

I have 100s of unit tests, am I safe?

Unit tests often fall short by missing edge cases and rarely achieving full code or value range coverage, which means they can easily overlook vulnerabilities. Even with extensive experience, developers might miss issues due to limited testing scenarios. Typically, in-house testing uncovers 10-20 defects per 1,000 lines of code, with around 0.5 defects per 1,000 lines in released products. Projects with functional safety certification show improved results. The defect rates showcase the high likelihood of memory corruption bugs in larger codebases, often reaching and surpassing the 7-digit range of lines of code.

Embedded compiler

Memory corruptions are a critical issue in software development, affecting both application code and the compilers used to build it. While compilers can add exploit mitigations, their effectiveness varies by architecture and tooling.

  • Common architectures like x86_64 and AArch64 benefit from easy-to-enable compile flags for exploit mitigations.
  • Diverse microcontroller architectures and operating systems make integrating robust exploit defences difficult.
  • Many embedded systems using open-source GCC and Clang lack sufficient exploit mitigation, leaving devices vulnerable.
But GCC has Stack Protector for Cortex-M?

This is true for some of the embedded standard libraries. By default, the stack protector uses a fixed value, which significantly decreases the effectiveness of the defence. Some manual effort is required by the developer to initialise the global canary with an unpredictable value. This required manual step is mostly neglected in the documentation or application menus of commercial development tools. Emproof Nyx uses a safe configuration and initialisation by default.

What is the overhead, especially compared to compilers?

Emproof Nyx offers similar performance and memory overheads compared to other solutions with its intelligent selection of essential functions for protection, which reduces unnecessary overhead. Additionally, Emproof Nyx provides the option to add exploit mitigations to devices where built-in support is lacking.

Firmware

Dynamic analysis tools like Clang Sanitizers, Valgrind, and fuzzing frameworks detect memory errors by running binaries, offering faster results than static analysis. However, their reduced code and value range coverage means they may still miss many bugs.

What bugs are being missed by this approach?

Bugs missed include those that occur under rare or untested conditions, complex memory corruption issues, and logical errors not triggered during testing. These issues often require specific input sequences or environmental conditions that dynamic analysis tools may not replicate during their testing process.

Why is dynamic analysis not able to identify all bugs?

Dynamic analysis can’t identify all bugs due to its limited code and value range coverage, as well as the practical constraints of testing time and resources. These tools run on specific test cases, and it is impractical to cover every possible execution path and input combination within a reasonable timeframe, leaving some bugs undetected.

Device

Dynamic analysis tools, including Clang Sanitizers, Valgrind, and fuzzing frameworks, are used to detect memory errors and record crashes by running the binary directly. These tools are integral during development and CI/CD processes, offering a quicker alternative to static analysis but with some trade-offs.

  • Although being faster than static analysis, they offer limited code and value range coverage.
  • The reduced coverage means that many bugs may still go undetected, similar to static analysis tools.
  • Bugs can persist undetected even with dynamic analysis.
Which devices are affected?
  • Bare metal or real-time operating system based embedded systems.
  • Firmware developed with the C/C++ programming languages;
  • Binaries built with GCC / Clang.
  • Device has some kind of internet and/or wireless connectivity.
  • Device handles some critical operation or processes sensitive or personal data.

Reverse engineering

In the reconnaissance phase, attackers gather as much information as possible about the target, often involving reverse engineering of binaries using tools like Ghidra, IDA Pro, or Binary Ninja. This process helps in identifying vulnerabilities through various methods and analyses.

  • Automated tools find superficial bugs, while human-assisted methods, including fuzzing and manual examination, are better for complex vulnerabilities.
  • Techniques like data-flow analysis, taint tracking, and fuzz testing are often combined for effective bug detection.
How accessible are reverse engineering tools?

Reverse engineering tools like Ghidra, IDA Pro, and Binary Ninja are widely accessible, with Ghidra being open-source and freely available. However, while these tools are accessible, using them effectively requires significant expertise and experience in reverse engineering and understanding binary code.

How easy can vulnerabilities be identified?

Identifying vulnerabilities can be challenging and varies in difficulty. Automated tools can quickly find superficial bugs, but complex vulnerabilities often require human-assisted methods, including detailed manual examination and advanced techniques like data-flow analysis, taint tracking, and fuzz testing. This combination of automated and manual methods enhances the effectiveness of bug detection but also requires significant time and expertise.

Find out more about reverse engineering tools here.

Exploit

After identifying vulnerabilities, attackers proceed to write exploit code tailored to those weaknesses. Exploits can have various objectives, such as executing unauthorized actions, escalating privileges, stealing data, or causing denial of service.

  • Attackers use advanced techniques like ROP-chains to bypass security. See our demo on buffer overflow exploitation with ROP-chains.
  • Exploits target unauthorised actions, privilege escalation, data theft, or service disruption.
  • Methods such as buffer overflows overwrite memory, while ROP-chains link code snippets to bypass security.
What are common types of exploits that could affect my systems?

Common types of exploits include buffer overflows, which overwrite memory to alter program behaviour; ROP chains, which link code snippets to bypass security mechanisms; and privilege escalation exploits, which grant unauthorised higher-level access. These exploits can lead to unauthorised actions, data theft, and service disruption.

How does a buffer overflow exploit work, and what makes it a critical security concern?

A buffer overflow exploit works by writing more data to a buffer than it can hold, which overwrites adjacent memory and can alter the execution flow of a program. This is a critical security concern because it can be used to execute arbitrary code, escalate privileges, and compromise system integrity, often allowing attackers full control over the affected system.



Prevents hacking attempts for all embedded systems

Guards against unknown vulnerabilities, ensuring your system stays secure even before patches are available.

Defends against malware attacks, which are frequently launched through exploited vulnerabilities.

Robust security measures to thwart sophisticated and persistent cyber-attacks, safeguarding sensitive data and operations.

Control Flow Integrity: The missing piece in the fight against hackers

Almost no current device, compiler, or controller has this vital exploit mitigation that blocks many attack vectors and bug classes. Control Flow Integrity (CFI) prevents malicious changes to the intended execution flow of a program. While CFI does not directly prevent exploitation of bugs, it prevents attackers from misusing bugs to overwrite function pointers. Attackers may hijack control flow by corrupting function pointers, redirecting the program to execute malicious code. Emproof Nyx automatically analyses vulnerable code segments and injects control flow checks.

Stop Buffer Overflows: How Emproof Nyx uses canaries to protect code

Buffer overflows can lead to malicious overwrites of stack-saved registers, allowing attackers to redirect execution or use ROP chains. Emproof Nyx automatically inserts randomised canaries into vulnerable functions, preventing return address overwrites without also overwriting the canary. Detected buffer overwrites trigger a user-defined exploit response (e.g., endless loop, reset). Configuration profiles for Emproof Nyx can whitelist or blacklist specific functions for protection.

Get in touch

Our functional safety compliant and trusted solution protects your embedded system.

We send out regular updates on new releases, industry insights and technical case studies

Privacy policy

© 2024 emproof B.V. All rights reserved. Design by Kava. Privacy PolicyTerms and ConditionsISO 26262 (ASIL B) certification