The QNX_info ELF Section

When poking at binaries on a QNX-based system, you may run into an interesting ELF header: The so-called QNX_info section!

A listing of sections in a QNX-based ELF binary.

This header section is included by default when building QNX binaries, and is intended to hold the “build properties” associated with the given ELF file. An interesting side point: in QNX’s own documentation, you can see they specifically don’t strip this section from IFS images created using mkifs.

Why do they not strip these sections? Not sure…

As an example of the kind of juicy information you can get from the QNX_info section, the figure below shows data I fetched from the “NBTMediaMainApp” binary from a BMW NBT HU EVO infotainment system (running QNX 6.5.0).

The QNX_info section dumped from the binary NBTMediaMainApp

I’ve transcribed the information below to make it easier to view/parse:

  • NAME=NBTMediaMainApp

  • DATE=2020-06-05Coordinated Universal Time-15:22:22

  • HOST=HIBUCP530765

  • USER=RDamian

  • DESCR=Main Application for Media domain , loads other Media Dependencies . Implements entire media Pres Ctrl / DevCtrl/Commco Layers

  • CPU=ARMv7

  • TARGET=B140

  • TARGET_OS=QNX

  • IDE=MOMENTICS_6_5_0_SP1

  • GCC_VERSION=4_4_2

  • OPTIMIZE=OPT_FOR_SIZE

  • TRACING=TraceSvr

  • DEBUG=NODEBUGFLAG

  • VERSION=UNKNOWN

  • TAGID=UNKNOWN

  • OS_VERSION_LABEL=UNKNOWN

  • MOCCA_VERSION=NoVersion

  • APP_VERSION_LABEL=UNKNOWN

  • MM_VARIANTCONFIG=NoVariant

This provides quite a bit of information that would be of interest to a security researcher! We have:

  • The date the binary was originally compiled

  • The hostname of the machine used to build the binary

  • The username of the user who initiated the build process

  • A full user-readable description of the binary’s function

  • Information on the targeted CPU, board, and OS

  • The specific version of the IDE/GCC build chain that was used to compile the binary

  • Information about whether or not the binary was compiled with tracing or debugging enabled

When reverse engineering black-box QNX-based embedded devices, this can give you a huge leg up in understanding confusing or unknown binaries. While working on understanding this particular BMW system, that QNX_info section is the first thing I dump any time I run into a weird binary I haven’t seen before. It’s just so helpful!

Development Attribution

In addition to being a useful bit of info when working on reverse engineering, it also holds a second interesting function for security researchers: development attribution!

Not only can you determine when/where/by whom a given binary was compiled, but you can use that information to build a bigger picture of which teams developed entire chunks of device functionality! This can be extremely helpful when doing security research - as an example, if you find that one developer commonly makes mistakes with their buffer sizing, you can use this debug information to track down other binaries on the system that were compiled around the same time, or by the same developer.

A real-world example

For example, compare the two QNX_info sections below:

A comparison of the QNX_info sections of two binaries - adjinfo, and arp.

(Apologies if it’s a pain to enlarge that image - I hate Squarespace’s gallery tools.)

In comparing the two QNX_info sections, one can immediately discern a LOT of info:

  • They were compiled on two hosts that have completely different naming schemes - perhaps at entirely different companies?

  • The ARP binary was compiled almost 3 years before the adjinfo binary!

  • The ARP binary was compiled by a generic “builder” user, while the adjinfo binary was compiled by the much more telling “BMW_L6_SW_Integratio” user

Additionally, you can combine these observations with one additional piece of context: The “adjinfo” binary is a BMW-specific binary for storing car parameters and settings in the so-called “adjustment block” of the ECU. The ARP binary is simply the built-in QNX utility for controlling the ARP cache contents, as far as I am aware.

Based on this information, you can likely conclude that the left binary’s QNX_info is much more telling of the BMW/Harman build chain, while the right binary’s QNX_info likely points to the plain QNX SDP (Software Development Platform) or OS image that they used as a base for their product.

To confirm this information, I checked it against a few other system components - sure enough, many of the basic components (fs-qnx4.so, cat, fileset, etc.) contained the same plain QNX_info, while proprietary components (CSI_NBT, NbtEvoOmapDiagHUHighApp, etc.) contained the BMW/Harman-styled QNX_info!

(PS: A bit of unconfirmed research, but I think that in this case, the build name of “PSP_networking” would imply that it is part of QNX’s Priority Support Plan, or Priority Support Patch. This may mean that it was part of a software release compiled directly by QNX and delivered to Harman as a software release, since QNX’s PSP provides you a “dedicated support developer with elevated priority”. Interesting!)

Why is that security-relevant?

So, we tracked down the differences between the Harman/BMW and base QNX system build processes - but why would this be relevant to a security researcher? That’s simple: speeding up your scoping!

While pentesting any given system, you’re generally the most limited by time. If you want to look for high-risk issues, you may be better off seeking out binaries that have signs of BMW/Harman’s build chain.

Also, this isn’t meant as an insult to BMW/Harman - it’s just a fact of operating systems and their role in security in general (at least, in my opinion).

Any large-scale operating system (like QNX) is distributed in hundreds of products, by a multitude of companies. This ensures that the OS gets lots of pentesting coverage and many eyes on it, as a multitude of companies have a vested reason to want to make sure the OS is secure. Harman may run their own testing on it before using it, but four or five other OEMs or suppliers may as well!

By comparison, an infotainment unit like the NBT HU EVO is only released as a single product, by a single company - there aren’t dozens of companies, hundreds of products, or nearly the same number of eyes (or the same bank roll for paying for pentests…) as there would be with QNX itself.

Additionally, factor in deadlines: QNX has been developed over decades and decades - by comparison, an infotainment unit has to be newly developed to meet strict customer requirements over a short multi-year period, before the development team effectively dissolves and everyone moves on to work on new projects/products.

This doesn’t mean that the application code that was written during this time is bad, it’s just code that is likely to have more issues than the well-vetted code that comprises the OS itself.

Interesting Metadata: Learning about Build Machines

While I’m discussing the QNX_info section and it’s juicy info, why not dive into another fun project with it?

Another interesting capability you gain when playing with this info is the ability to build a picture of the developer’s build environment, based solely on their included build information.

As an example, I used the command ‘find’ combined with strings and grep to dump a list of every single build hostname from the NBT HU EVO infotainment filesystem:

find . -type f -exec sh -c “strings {} | grep ‘^HOST=’” \; > all_build_hostnames.txt

I dumped all of the hostnames using ‘find’ and some string manipulation.

In total, there were 1,481 binaries that contained the QNX_info header with a build hostname that could be extracted.

Paring these down to only unique hostnames, there were 53 total hostnames used to build all of the software on this particular infotainment unit.

To generate some statistics on how often each machine was used, we can count duplicate entries. To do this, I plugged the list into a cool tool made by Somacon that can count duplicates in a list (I’m sure there’s a way to do it with a Linux one-liner, but admittedly, this was faster).

The top few build machines used in the NBT HU EVO.

So, out of the 1,481 binaries installed on the system, exactly 777 were built by the top 5 build machines:

  • media2

  • gusbuild8

  • HIULWSP612

  • slave3

  • mainbuild

From here, we can start to work our way backwards: What kind of functionality did each host build?

I ran a quick grep to look for the media2 host:

grep -r "HOST=media2" .

The results of grepping for binaries built by "media2”.

Parsing through the results, a pattern quickly emerged: Every binary built by media2 lived at one of two paths:

  • /opt/mm/

  • /opt/conn/

These are the paths for Harman’s “Multimedia” functionality (mm), and “Connectivity” functionality (conn). This tells us that “media2” is likely a Harman-owned build machine, and any binary built by media2 is likely part of Harman’s Multimedia or Connectivity services.

In Conclusion…

This isn’t exactly a sparkly zero day, or the most groundbreaking research - but in my searching online, I couldn’t find anyone else talking about using “QNX_info” to gather recon information during a penetration assessment. So, of course I wanted to blog about it!

That’s all for today - stay hacky!

Raw Data

I’ve included a dump of the raw data/statistics below in case anyone is interested. It has each of the raw build machine names and their overall count as they appeared on my system.

(Side note: I think there’s a good amount of doubling going on, due to the presence of the /repository/istep/ directories that have a mirror image of the base filesystem… these numbers might be slightly inflated - YMMV.)

Count Build Machine Name
426 HOST=media2
130 HOST=gusbuild8
112 HOST=HIULWSP612
110 HOST=slave3
99 HOST=mainbuild
76 HOST=HIKAWSBLD03
66 HOST=Cinemo
66 HOST=pspbuildvm
58 HOST=gusbuild4
44 HOST=OABLN642
34 HOST=DEMDWSBLD03
24 HOST=OEKAN403
22 HOST=DEMUWSP501
16 HOST=OABLN803
14 HOST=HIMUWSP504
14 HOST=OABLN660
12 HOST=OASH-P132
12 HOST=OEKAN402
10 HOST=linux_clone_2
8 HOST=HIBUCP530765
8 HOST=HIGAP198
8 HOST=OEKAP3BD
6 HOST=gusbuild
6 HOST=OEKAN48D
6 HOST=pspbuild
4 HOST=DEKAP802057
4 HOST=HICD-P051
4 HOST=NTSHH-PC-OBRUEG
4 HOST=OABLN004
4 HOST=OABLN093
4 HOST=OABLN445
4 HOST=OABLN692
4 HOST=OABLN883
4 HOST=OABLN939
4 HOST=OABLP005
4 HOST=OASH-P134
4 HOST=OEKAP2DL
4 HOST=OEKAP3DV
4 HOST=OEKAP3J2
4 HOST=OEKAP72K
4 HOST=OEKAWSAP66
4 HOST=OEMUP214
4 HOST=OEULP645
4 HOST=servicesbld
2 HOST=gus#0.
2 HOST=HIBUCPLUX012
2 HOST=HIULWSP644
2 HOST=LinuxMint16x64vm
2 HOST=localhost
2 HOST=OABLN1878
2 HOST=OAFHN0326EOP
2 HOST=pc
2 HOST=vm
  • 1481 Total Lines
  • 53 Distinct Lines


Next
Next

Teardown: The BMW / Harman NBT HU Infotainment Unit