CVE-2019-7315: Genie Access WIP3BVAF IP Camera Directory Traversal

We have discovered a directory traversal vulnerability that affects Genie Access’ WIP3BVAF WISH IP 3MP IR Auto Focus Bullet Camera.  This security vulnerability can act as the first step to full device compromise and has been assigned CVE-2019-7315.

Proof of concept (PoC) of path traversal vulnerability discovered

The directory traversal vulnerability can be exploited via the web management interface for the IP camera, using a URL as follows:

http://www.example.com/../../../../../etc/shadow

Here is a screenshot showing the contents of the shadow file for a WIP3BVAF IP camera, including the root password hash:

As the WIP3BVAF IP camera makes use of a weak hashing algorithm (DES), it is relatively easy to brute force the hash and obtain the cleartext password, especially if a weak password is in use. Once the password has been recovered, it is possible to obtain a root shell on the camera via telnet:

From here, the username and plaintext password for the web interface can be retrieved by using a tool such as strings against the /mnt/mtd/flash/config.dat file. Once these have been obtained, administrative access to the management interface is possible, where the camera feeds can be viewed and disabled, or the camera configuration adjusted.

Models with the directory traversal vulnerability

All firmware versions for this particular model (3.x.x) are affected.

While a firmware version (4.2.1) has been released to address the security vulnerability in later camera models, this version is not transferable to the WIP3BVAF model. This is due to the fact that the WIP3BVAF model is based on H.264 encoding, while later models of camera manufactured by Genie Access make use of H.265 encoding.

The WIP3BVAF is no longer manufactured by Genie Access and can be considered as end of life. According to the manufacturer, no patch addressing this vulnerability will be released.

Conclusion

As demonstrated, the path traversal vulnerability can be the potential starting point for complete compromise of the WIP3BVAF camera.

Since no fix will be forthcoming due to the camera being end of life and no longer manufactured, it is advisable to refrain from using this model. If this isn’t an option, a sufficiently isolated VLAN should be considered for the camera to prevent it being easily accessible, and a strong, unique password should be set for the root user.

Genie Access Directory Traversal Vulnerability Timeline

  • Vulnerability discovered: 7 Jan 2019
  • Genie Access informed: 13 Jan 2019
  • Genie Access response detailing no fix would be forthcoming: 16 Jan 2019
  • Nettitude public disclosure: 29 May 2019

Operational Security with PoshC2 Framework

This post describes a new capability that has been deployed within PoshC2, which is designed to assist with revealing a wider set of target environment variables at the dropper stage, as part of operational security controls.

Imagine the following scenario.  You’ve deployed IP address white-listing on a proxy in order to limit implant installation to a specific environment.  A connection arrives back from a host that’s not associated with your target environment, so the connection is dropped and PoshC2 never sees the incoming connection attempt.  By adding some additional logging on the proxy, and utilising the new CookieDecrypter.py script, you can now reveal specific environment variables about where the dropper was executed.  This information allows for better decision making on what to do next in this scenario.  It yields greater situational awareness.

The background

When carrying out red team testing, a number of safety checks are required to:

  1. Environmentally key the implant to the target environment variables.
  2. Make sure only those targeted assets are compromised.

The purpose of this post is not to discuss these safety measures in depth.  Rather, it is to instead focus on the problem wherein a target environment has been IP white-listed on the attacking infrastructure, but a connection has come back from an IP address not already on that approved list of target environments.  Large organisations do not always readily or thoroughly understand their full external IP address range, or do not force tunnelling of all traffic across a VPN.  It is therefore not uncommon to receive legitimate connect backs from non-whitelisted sources.

As a simulated attacker, you now have a decision to make; you have sent very unique malicious links to a target employee and those have been verified as followed, and certain local checks have been satisfied, but the connection is coming from an IP address that’s not on your white-list. The dropper must have been executed and has consequently called back to your attacking infrastructure to download the core implant from the PoshC2 server.  Now what?

Further detail

PoshC2’s implant is a staged implant and utilises a dropper to satisfy certain criteria before calling back to the C2 server to pick up a core implant. The dropper uses a unique encryption key specific to the PoshC2 instance, but not unique to each dropper. Each dropper shares the same encryption key; it is only when the core implant is sent down that each implant is uniquely keyed for all further communication.

Generally, the following infrastructure is set up to support a PoshC2 instance. This includes a number of redirectors or Internet Proxies that forward C2 communications back to the PoshC2 instance, limiting exposure of the C2 servers and allowing a flexible approach to building many redirectors to combat take-downs or blocked URL’s.

The redirectors can be made up of any infrastructure or technology, whether it be cloud based redirectors such as CloudFront, or applications running on a host such as Socat, python or Apache, to name a few.

Apache is a preference for its rewrite rules, which can be used to make smart decisions on traffic traversing the proxy. White-listing the X-forwarded-for address is one common method and can be written into rewrite rules using a RewriteMap, as follows.

Something you might not know

The configuration of the dropper has now been modified to retry multiple times after a timeout, if the connection returns a HTTP 404 response. This provides extra time to make a decision on whether to add the IP address to the white-list, without losing the implant. If the IP address is then added to the white-list, then when the dropper connects back, it will be allowed to traverse to the PoshC2 server instance and download the core implant.

Extra help

The CookieDecrypter.py script was created to assist in decision making by providing more information. The connection from the dropper includes a cookie value that details useful environment variables such as those detailed below, however it is encrypted with the key created on initialisation of the PoshC2 instance.

  • Domain
  • User Account
  • Hostname
  • Implant Architecture
  • Process ID
  • URL

Capturing the cookie

By default the cookie value will not be stored anywhere on the proxy server. As previously mentioned, Apache is powerful and includes a number of options to assist, one of which is ModSecurity.

Installing ModSecurity:

apt install libapache2-modsecurity

Enabling the configuration to capture cookies for requests that are returned a HTTP 404 response:

Now if a dropper connects and gets a 404 response, the following log entry will be created in “/var /log/apache2/sec.log”:

The script

The script CookieDecrypter.py has been created to ingest the log file and parse the ‘SessionID’ from the log file, then connect to the PoshC2 database to retrieve the encryption keys and use the encryption functions to reverse the cookie value. It has to be executed on the PoshC2 server.

python CookieDecrypter.py log.txt

Conclusion

With increased visibility comes better decision making.  Knowledge of the workstations domain and the user generally provides most, if not all, of the information you need to assess whether an asset is in scope.  We have multiple layers of protection in our approach to risk management to ensure that we stay on the right side of the rules of engagement, and this is just one of them.  We recommend that you develop your own set of risk management procedures too.

 

CVE-2017-18019: Privilege Escalation via a Kernel Pointer Dereference

A little while ago, I discovered a vulnerability, CVE-2017-18019, affecting a kernel driver of multiple K7 Computing security products, as well as the products of Defenx, both for Windows.  Both were affected because they were using the same anti virus engine, and both are now patched.

The proof of concept was based on an invalid kernel pointer dereference, which led to a blue screen of death.  That research and the subsequent coordinated disclosure process were, at the time, sponsored and handled by SecuriTeam.  It turns out that the proof of concept could be exploited further, and turned into local privilege escalation.  So, with the permission of SecuriTeam, I decided to create a write-up of that local privilege escalation development process.

Targeting

This article targets the following 64-bit Windows versions: Windows 7 SP1 – Windows 10 v1809.

A Medium integrity level is required in order to exploit this vulnerability in the way that is demonstrated through this article. In order to exploit this from a Low integrity level, you will have to do extra work in order to leak some kernel pointers. This can be done either though other IOCTLs handlers of the target driver itself, or through other Windows driver kernel memory leak bugs.

Bug Analysis

The root cause of this issue is that the author of the following function trusts a pointer to read data from, originating from a user-supplied input buffer, as long as it references an address inside the kernel address space.

The vulnerable function fetches a pointer from the IOCTL’s input buffer and checks if it is greater or equal to nt!MmHighestUserAddress (0x00007ffffffeffff in x64). If that’s true, then the function will proceed by dereferencing that pointer and evaluating the first byte located at that memory address.

Clearly, the purpose (even though the implementation is buggy) of this check is to verify that the pointer address from where further information will be read resides in kernel memory of which, from the developer’s perspective, its virtual address and contents are not supposed to be known and controlled by the user. This, of course, is not entirely true because kernel object addresses may be leaked, and also they may reference directly or indirectly user-supplied data.

The following screenshot shows (in grouped nodes) what we described above.

Figure 1 – Verify it is a kernel pointer.

We can easily crash the host by supplying an arbitrary kernel pointer that references a non-allocated memory page.

The following image shows the output from Windbg the moment the memory access violation occurs.

Figure 2. Arbitrary kernel pointer dereference.

Further Analysis

What we know at this point is that we have a denial of service bug that can be triggered by any user in order to crash the host. So, we analysed this function further in order to find out if there is something more that we can do with it.

The following graph-view screenshot continues directly from what is shown in Figure 1.

Figure 3. Kernel memory buffer data checks.

Assuming that RCX points to a valid kernel address where the first byte is 0x4B, so that the previous check succeeds (cmp byte ptr [rcx], 4Bh), we arrive at the second part of the vulnerable function as shown above.

Here we notice further byte value checks, and specifically the second byte of the buffer referenced by RCX should be 0xFF in order to access the final part of our analysis.

Figure 4. Arbitrary Function Pointer Call.

A couple of pointer dereferences later, we see that the function is treating the last one as a function pointer. We also notice that the first and second parameters passed to RCX and RDX respectively can also be controlled.

To be more specific, the first parameter is taken from the buffer referenced by the arbitrary kernel pointer that we control, and the second one is pointing inside our user-input buffer that is defined through the call to DeviceIoControl function.

Setting things up

At this point, we have all the information we need in order to proceed with the exploitation of the vulnerability. To do that, we must know the address of a kernel object and also control its contents, to a certain extent. As we discussed, the initial pointer from where the rest of data is read leading to a function pointer called, must reference an address inside the kernel address space. This is also the developer’s assumption around the safety of that decision.

In a previous article we talked about Private Namespaces and the ability to insert user-defined data in the body of the associated kernel object. We will be using this type of objects in order to exploit the vulnerability, as they can be used reliably in this case as well.

In order to exploit this vulnerability, we will be using two kernel objects of the aforementioned type. The first object will be used for controlling the subsequent pointer dereferences that allow us to call an arbitrary function pointer, while the second object will be used in order to control the initial kernel pointer check that must reference a known kernel object in memory (first object).

Exploitation in Windows 7 SP1 x64

In the absence of exploitation mitigation such as SMEP (Supervisor Mode Execution Protection), taking advantage of this vulnerability is quite straight forward. We can execute our payload function in userland without taking any additional steps, such as temporarily disable SMEP. We just need to control the instruction pointer and that would be enough.

To start with, we will create a Private Namespace object using a random boundary name and we will use NtQuerySystemInformation function to leak its address.

Figure 5. 1st Object (Win7 SP1 x64).

Then, we will create another object of the same type with a crafted boundary name.

The first and second bytes must be 0x4B and 0xFF respectively (see Figures 1 and 3) to satisfy the byte value checks. Also, in the offset 0x0A (Figure 4 – first pointer dereference) of the crafted boundary name, we will be inserting the address of the first object + the distance in bytes (0x1a0) between that address and the location of the boundary name in that object + an arbitrary offset (0x1A) that contains a value that can be translated to a userland pointer, which satisfies the proof of concept for this version of Windows. Note that we take into account that at the result of the previous calculation, the value 0x0C will be added in order to reach the userland pointer value (Figure 4 – second pointer dereference).

Figure 6. 2nd Object (Win7 SP1 x64).

Let’s have a closer look at how these two objects are ‘inter-connected’.

Figure 7. Objects Interconnection (Win7 SP1 x64).

Finally, we can see the function pointer being called, in order to execute our payload at address 0x1010000.

Figure 8. Call Payload-Function Pointer (Win7 SP1 x64).

Exploitation in Windows 8.1 – 10 v1809 x64

In more recent Windows versions, exploiting a kernel driver bug is more challenging due to exploitation mitigations that have been added. In this case, we take control over the execution flow by calling an arbitrary function. However, due to the SMEP we are not able to directly execute code that resides in the user address space from kernel mode, so we will have to take another approach.

A common solution is to attempt to temporarily disable SMEP by clearing the 20th bit in CR4 register of a specific processor and lock our threads execution to only run on that one, so that we can execute our payload in userland as before. However, we would have to restore CR4 in order to avoid KPP (Kernel Patch Protection/PatchGuard) killing the host.

Another way, which we will be using in this write-up, is to take advantage of the execution flow control in order to turn it into a “write-what-where” primitive, which will enable us to modify arbitrary data in kernel memory. Once that is achieved, there are, again, two common ways of taking advantage of this in order to elevate our privileges.

The first method is to overwrite with a NULL value the SD (Security Descriptor) pointer in the object header of an elevated process running as SYSTEM. This will allow a non-privileged process to inject and execute malicious code in the same security context. However, this method will only work up to Windows 10 v1511 (Build 10586), as described in this article.

Another way to take advantage of a “write-what-where” primitive is to enable privileges in the primary token of a non-privileged process in order to enable it to again inject and execute code in the security context of a process running as SYSTEM. This method still works fine, but it requires a minor modification from Windows 10 v1709 (Build 15063) onwards, as described here. What we are about to describe here can also be used in Windows 7.

Going back to what we have described so far, we have noted that we are also able to control the first two parameters (see Figure 4) passed in RCX and RDX respectively, once our arbitrary function is called. We are going to take advantage of this capability in a moment.

In this case, we first need to leak the address of the primary token of our process, where will be enabling additional privileges. We will be using that address as the target of our exploitation primitive. As in Windows 7, NtQuerySystemInformation can be used for the same purpose from the standard ‘Medium Integrity’ of a user process in order to leak the kernel object and function addresses that we will be using.

We will then create our first Private Namespace object with a custom boundary name, where the first 8 bytes will be set to the kernel address that we will be using as our ‘gadget’ to modify arbitrary kernel data. So, instead of executing a payload in userland, we will be redirecting the execution to kernel function, nt!RtlCopyLuid that will enable us to modify arbitrary kernel data.

Figure 9. nt!RtlCopyLuid.

Since we control both the RCX and RDX registers, we can use this function to complete our “write-what-where” primitive.

We will be needing, again, a second Private Namespace object with a custom boundary name which at offset 0x0A of the name data (Figure 8 – first pointer dereference) must contain the address of the first object + the distance in bytes (0x1a0) between that address and the location of the boundary name in that object. Remember that at the first 8 bytes of the boundary name of the first Private Namespace object, we have inserted the address of nt!RtlCopyLuid. Note that as before, we must take into account that at the result of the previous calculation, the value 0x0C will be added in order to reach our arbitrary kernel function pointer value, loaded at the R10 register (Figure 8 – second pointer dereference).

So, this is how it should look:

*(ULONG_PTR*)(boundaryName + 0x0A) = customPrivNameSpaceAddress + boundaryNameOffsetInDireObject - 0x0C;

Then, we need to take control of the first two parameters.

The first parameter loaded in RCX is read again from our custom boundary name, at offset 2 (the first two bytes of our custom boundary name must be 0x4B,0xFF). So, we will be setting there the address of our process’ token object + the offset (0x40) to reach the nt!_SEP_TOKEN_PRIVILEGES structure member.

Figure 10. nt!_SEP_TOKEN_PRIVILEGES.

It should look as follows:

*(ULONG_PTR*)(boundaryName + 0x02) = tokenAddress + 0x40;

Finally, we can also control RDX since the value of R12 is copied over, which points at the address of our userland input buffer + 0x10 (see Figure 1 – 6th node). This is where we read the data from, to write into an arbitrary kernel address. In this case we will overwrite the ‘Enabled and ‘Present’ privileges members of the aforementioned structure (Figure 10).

It should look like this:

*(unsigned __int64*)(inputBuf + 0x10) = _ULLONG_MAX;

So, our exploit will have to reach the vulnerable function twice in order to complete the attack.

Figure 11. Objects Interconnection – Write-What-Where Primitive.

The image above shows how the two objects are ‘interconnected’ in order to complete our “write-what-where” primitive to finalize the exploit.

Conclusion

This was an interesting bug to examine and exploit, as it shows once more that no input data should ever be blindly trusted. From the developer’s perspective, trusting a kernel pointer to read data from, presumably out of user’s control, was a ‘safe’ decision to take. However, it turned out to become a serious vulnerability in multiple products of two different vendors that use the same SDK.

Introducing PoshC2 v4.8 – includes C# dropper, task management and more! – Part One

We recently released version 4.8 of PoshC2, which includes a number of fixes and improvements that help facilitate simulated attacks. This is the first post in a series of posts that will include some of the details around the fixes and updates, alongside a number of other posts which will show some of the other cool features we have been working on in the background.

C Sharp (#)

As of PoshC2 version 4.6, a C# implant has been available. The main driver behind this implementation was to stay clear of System.Management.Automation.dll when an environment is heavily monitored and the EDR product can detect loaded modules inside a running process. Granted, not all EDR products are currently doing this, as it can create a hit on performance at the endpoint level, but its important to understand the OPSEC implications of running different C2 droppers.

This has been a work in progress since the release and is continually improving, and we believe this will be the way forward in months to come against advanced blue teams with a good detection and response capability across the organisation. Currently the implant is fully functional and allows an operator to load any C# assembly and execute this in the running process. This allows the user to extend the functionality massively because they’re able to load all the great modules out there in the wild, created by other infosec authors. The way this is loaded uses the System.Reflection namespace. The code can then be called using .NET reflection, which searches inside the current AppDomain for the assembly name and attempts to either run the entry point given or the main method of the executable. An example usage is as follows, for both run-exe and run-dll:

run-exe:

run-dll:

Task Management

One of the issues we’ve overcome in this release was around tracking tasks; there was no way to determine what output related to which issued command. This was largely due to the implant not using task ID’s that were tracked throughout the entire command process flow.

Typically, this was fine because you know what command you’re running, but when multiple people are working on the same instance, or if multiple similar commands are run, then it could be difficult to figure out what output came from which command. This also made tracking failed commands fairly difficult if not impossible to find. The following screenshots shows the output inside the C2Server and the CompletedTasks HTML file:

Figure 1: How commands were issued and returned against an implant

Figure 2: The old format of the tasks report

Furthermore, tasks were only logged in the database when the implant responded with some output. Now, tasks are inserted as soon as they are picked up by the implant with a start time, and updated with a completed time and the desired output when they return. This allows us to track tasks even if they kill the implant or error and never return, and to see how long they took. It also allows us to reference tasks by ID, allowing us to match them in the C2Server log and to only refer to the task by its ID in the response, decreasing message length and improving operational security. An example of the output is shown below:

Figure 3: The new task logging

The generated report then looks like this:

Figure 4: The new report format

User Logging

The astute amongst you will have noticed the new User column in the report above. Another improvement that has been made in relation to tracking tasks is user logging. Now when you start the ImplantHandler you are prompted for a username; it is possible to leave this blank if required, but when PoshC2 is being used as a centralised C2Server with multiple users it’s important to track which user ran which task as shown in the examples below:

Figure 5: You are now prompted for a username when you start the ImplantHandler

All tasks issued from that ImplantHandler instance will be logged as that user, both in the C2Server log and in the report.

Figure 6: If a username is set it is logged in the task output

Figure 7: The username is also logged for the task in the report

For scripting and/or ease of use, the ImplantHandler can also be started with the -u or --user option, which sets the username, avoiding the prompt:

python ImplantHandler.py --user "bobby b"

Beacon Timing

The way beacon sleep times were handled was inconsistent amongst implants, so now we’ve standardised it. All beacon times must now be in the format of value and unit, such as 5m, 10s or 2h. This is then displayed as such for all implant types in the ImplantHandler. As seen below, the fourth column states the current beacon time in seconds, whereas now we show only the output in the newer format.

Figure 8: The old beacon time format

Figure 9: The new beacon time format

Validation has also been added for these, so attempting to set an invalid beacon time will print a suitable error message and do nothing.

Figure 10: The validation message if an invalid format is set

We’ve also changed the implant colour coding so that they are only flagged as timing out if they haven’t checked in for a multiple of their beacon time, as opposed to a hard coded value.

Previously the implants would be coloured as yellow if they hadn’t checked in for 10 minutes or more, and red for 60 minutes or more. Now they are coloured yellow if they have not checked in for 3x beacon time, and red for 10x beacon time, granting far more accurate and timely feedback to the operator.

Figure 11: Implant colour coding has been improved so that the colour is dependent on the beacon time

C2Viewer

The C2Viewer was a legacy script used to just print the C2Server log, useful when multiple people want to be able to view and manipulate the output independently.

There were a few issues with the implementation however, and there was a possibility that it would miss output as it polled the database. Additionally, as this was an additional script, it added maintenance headaches for updates to task output.

This file has now been removed, and instead if you want to view the output in the same way, we recommend that you run the C2Server and pipe it to a log file. You can print the log to stdout and a log file using tee:

python -u C2Server.py | tee -a /var/log/poshc2_server.log

This output can then be viewed and manipulated by anyone, such as by using tail:

tail -f -n 50 /var/log/poshc2_server.log

This method has the added benefit of storing all server output. While all relevant data is stored in the database, having a backup of the output actually seen in the log during usage can be extremely useful.

Further details can be found in the README.md.

Internal Refactoring

We’re also making strides to improve the internals for PoshC2, refactoring files for clarity, and cutting cyclic dependencies. We aim to modularise the entire code base in order to make it more accessible and easier to maintain, including making changes, but as this is a sizeable change we’ll be doing it incrementally to limit the impact.

Conclusion

There have been quite a few changes made, and we’re aiming to not only improve the technical capabilities of PoshC2, but also the usability and maintainability.

Naturally, any changes come with a risk of breaking things no matter how thorough the testing, so please report any issues found on the GitHub page at: https://github.com/nettitude/PoshC2.

The full list of changes is below, but as always keep an eye out on the changelog as we update this with any changes for each version to make tracking easier. This is the first blog of a series of blogs on some additional features and capability within PoshC2. Stay tuned for more information.

  • Insert tasks when first picked up by the implant with start time
  • Update task when response returned with output and completed time
  • Log task ID in task sent/received
  • Add ability to set username and associate username to tasks issued
  • Print user in task information when the username is not empty
  • Improved error handling and logging
  • Rename CompletedTasks table to Tasks table
  • Method name refactoring around above changes
  • Pull out implant cores into Implant-Core.py/.cs/.ps1
  • Rename 2nd stage cores into Stage2-Core.py/.ps1
  • Stage2-Core.ps1 (previously Implant-Core.ps1 ) is no longer flagged by AMSI
  • Use prepared statements in the DB
  • Refactoring work to start to break up dependency cycle
  • Rename DB to Database in Config.py to avoid name clashes
  • Pull some dependency-less functions into Utils.py to aid dependency management
  • Fix download-file so that if the same file is downloaded multiple times it gets downloaded to name-1.ext name-2.ext etc
  • Adjust user/host printing to always be domain\username @ hostname in implants & logs
  • Fix CreateRawBase payload creation, used in gzip powershell stager and commands like get-system
  • Added ImplantID to Tasks table as a foreign key, so it’s logged in the Tasks report
  • Added Testing.md for testing checklist/methodology
  • Fix Get-ScreenshotAllWindows to return correct file extension
  • Fix searchhelp for commands with caps
  • Implant timeout highlighting is now based on beacon time – yellow if it’s not checked in for 3x beacon time and red if not checked in for 10x beacon time
  • Setting and viewing beacon time is now consistent across config and implant types – always 50s/10m/1h format
  • Added validation for beacon time that it matches the correct format
  • Fix StartAnotherImplant command for python implant
  • Rename RandomURI column in html output to Context, and print it as domain\username @ hostname
  • Move service instructions to readme so that poshc2.service can just be copied to /lib/systemd/system
  • Removed C2Viewer.py and added instructions for same functionality to readme just using system commands