xorl %eax, %eax

OPSEC fail: Reality Winner & The Intercept

leave a comment »

I always advice everyone to never trust journalists but this case took it to whole new level. This was a double OPSEC failure by both NSA contractor Reality Winner and the popular online news website The Intercept. Most people probably remember the case as it was very recent (June-July 2017) but it is still worth to document it for future reference.



On 5 June 2017 The Intercept published the “Top-Secret NSA Report Details Russian Hacking Effort Days Before 2016 Election”. I will avoid any political comments (as this appears to be intention of that article) and go directly to the issue. The article included a five pages long scanned PDF document that neither the whistleblower, nor The Intercept bothered to sanitize. You can find it here.



The TOP SECRET NSA report included a very nicely structured link-analysis diagram (see below) which shows that that an email address relating to a targeted phising attack was registered with a personal cell phone number which allegedly belonged to a GRU employee. This email address was also used to send the first phising email (probably testing) to the personal email account of the same GRU employee. This resulted in the attribution of this cyber-attack attempt to the Russian government. Now let’s move back to the OPSEC failure.



As you probably already know, since mid-80s all printers have digital watermarks (most commonly known as “yellow dots”). Those are some tiny yellow dots with a standard encoding, which are unique to each printer and are being included in all documents printed. Their official name is Machine Identification Code (MIC) and you can find more about it on Wikipedia and EFF.



So, long story short, neither The Intercept nor the whistleblower performed a basic sanitization of the stolen document. The whistleblower printed it on printer belonging to an NSA office, and sent it to The Intercept. You can easily find this on your own. Download the document, zoom in (500%-600% is sufficient), load this to your favorite image editing software, change the color hue & saturation, and there you have it.



Using EFF’s decoder you can find some details around it. However, you will quickly notice that you need to rotate (180 degrees) the MIC to properly decode it. You can see the result here. Basically, it is the printer’s serial number (535218 or 29535218), and date & time it was printed (9 May 2017 06:20). More than enough information for an intelligence agency to locate the whistleblower.



And this is exactly what happened there. Literally the next day after the news article was published, on 6 June 2017, the FBI arrested Reality Winner who was working as NSA contractor at that time. The trail that resulted to her arrest as FBI explained was the printer’s digital watermark along by NSA’s office printers’ logging. Basically, they knew the printer it came from, the date & time so the only thing left was to check the logs to see who used it at that time. That simple.



This was a major OPSEC failure. A technology that is known since the 80s was completely ignored by both an NSA contractor and a popular news agency. On the other hand, it is worth noting that this case must act as an important lesson for all businesses as many of them do not keep an inventory of the MICs of their printers. Something which can be used to detect insider threats as this case demonstrated in the best possible way. Maybe something you can keep in mind if you haven’t done it already.

Written by xorl

November 21, 2017 at 21:25

Posted in opsec

OpenBSD STI integer overflow on HPPA

leave a comment »

Going through the ChangeLog of OpenBSD 6.0 I noticed this security fix. The vulnerability has very limited real world impact as it affects only Hewlett Packard Precision Architecture (HPPA) systems. Nevertheless, it is an interesting vulnerability in STI display driver that is definitely worth analysing. The code of the STI display driver is located at sys/dev/ic/sti.c and below you can see the vulnerable code snippet.

int
sti_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
	struct sti_screen *scr = (struct sti_screen *)v;
	struct wsdisplay_fbinfo *wdf;
	struct wsdisplay_cmap *cmapp;
	u_int mode, idx, count;
	int ret;

	ret = 0;
	switch (cmd) {
    ...
	case WSDISPLAYIO_GETCMAP:
		if (scr->putcmap == NULL || scr->scr_bpp > 8)
			return ENODEV;
		cmapp = (struct wsdisplay_cmap *)data;
		idx = cmapp->index;
		count = cmapp->count;
		if (idx >= STI_NCMAP || idx + count > STI_NCMAP)
			return EINVAL;
		if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count)))
			break;
		if ((ret = copyout(&scr->scr_gcmap[idx], cmapp->green, count)))
			break;
		if ((ret = copyout(&scr->scr_bcmap[idx], cmapp->blue, count)))
			break;
		break;
    ...
	case WSDISPLAYIO_PUTCMAP:
		if (scr->putcmap == NULL || scr->scr_bpp > 8)
			return ENODEV;
		cmapp = (struct wsdisplay_cmap *)data;
		idx = cmapp->index;
		count = cmapp->count;
		if (idx >= STI_NCMAP || idx + count > STI_NCMAP)
			return EINVAL;
		if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count)))
			break;
		if ((ret = copyin(cmapp->green, &scr->scr_gcmap[idx], count)))
			break;
		if ((ret = copyin(cmapp->blue, &scr->scr_bcmap[idx], count)))
			break;
		ret = scr->putcmap(scr, idx, count);
		break;
    ...
	return (ret);
}

As you can see, “idx” and “count” are both defined as unsigned integers. In both cases, their values are derived from the user controlled “data” pointer. Below you can see the exact definition of the user controlled “wsdisplay_cmap” structure as defined in sys/dev/wscons/wsconsio.h header file.

/* Colormap operations.  Not applicable to all display types. */
struct wsdisplay_cmap {
	u_int	index;				/* first element (0 origin) */
	u_int	count;				/* number of elements */
	u_char	*red;				/* red color map elements */
	u_char	*green;				/* green color map elements */
	u_char	*blue;				/* blue color map elements */
};

Going back to the vulnerable code we see that OpenBSD developers added a bounds check before executing the copyout() and copyin() operations. However, the bounds check can result in an integer overflow that will completely bypass it. As you can see below, “idx” should not be larger than 256 (the value of STI_NCMAP) or the “idx” plus “count” should not be larger than 256. However, if “idx” is, for example, 256 but “count” is 4294967295, the addition will result in an integer overflow with the result being 255. This means that the bounds check will be bypassed but the copyin() and copyout() operations will result in buffer overflows as they are using “count” as the counter for the amount of bytes to copy.

if (idx >= STI_NCMAP || idx + count > STI_NCMAP)
	return EINVAL;

As you can see below, the patch is simply checking that “count” does not exceed “256” minus the value of the “idx” variable. Since “idx” is also checked that it does not exceed STI_NCMAP and since there is no arithmetic operation between the two user controlled integers, there is no more possibility of integer overflow and the check remains the same.

@@ -1130,7 +1130,7 @@ sti_ioctl(void *v, u_long cmd, caddr_t d
 		cmapp = (struct wsdisplay_cmap *)data;
 		idx = cmapp->index;
 		count = cmapp->count;
-		if (idx >= STI_NCMAP || idx + count > STI_NCMAP)
+		if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
 			return EINVAL;
 		if ((ret = copyout(&scr->scr_rcmap[idx], cmapp->red, count)))
 			break;
@@ -1146,7 +1146,7 @@ sti_ioctl(void *v, u_long cmd, caddr_t d
 		cmapp = (struct wsdisplay_cmap *)data;
 		idx = cmapp->index;
 		count = cmapp->count;
-		if (idx >= STI_NCMAP || idx + count > STI_NCMAP)
+		if (idx >= STI_NCMAP || count > STI_NCMAP - idx)
 			return EINVAL;
 		if ((ret = copyin(cmapp->red, &scr->scr_rcmap[idx], count)))
 			break;

As I mentioned in the beginning, low impact vulnerability due to its target architecture and display driver. However, very interesting case study of integer overflow and probably easily exploitable as it is directly accessible via IOCTL with WSDISPLAYIO_GETCMAP or WSDISPLAYIO_PUTCMAP commands.

Written by xorl

November 20, 2017 at 20:49

Posted in vulnerabilities

Reverse Engineering isDebuggerPresent()

leave a comment »

Disclaimer: I am not an experienced Windows guy. I know just the basics and still learning.

There have been tons of articles on how to bypass isDebuggerPresent(), the most widely used anti-debugging method in Windows. However, here we will go a little bit into what isDebuggerPresent() does internally. As we can read in Microsoft’s documentation, it comes with a very simple prototype from Kernel32 library.

BOOL WINAPI IsDebuggerPresent(void);

What we need to know is that isDebuggerPresent() is designed to perform just one task. Return a non-zero value if the current process is running in a user-mode debugger, and a zero value if it is not running in a user-mode debugger. If we load up the Kernel32 DLL (Dynamic-Link Library), we can quickly find the export of this routine. Basically, it is just a jump to an internal offset from DS (Data Segment) register.



This makes sense as Microsoft has moved a lot of the functionality from kernel32.dll and advapi32.dll to kernelbase.dll. So, if we load kernelbase.dll we will quickly locate the actual code behind isDebuggerPresent() which consists of a very simple operation.



Literally, the entire isDebuggerPresent() function is three assembly instructions. First, it stores the value of fs:30h register to EAX register, then copies the value of EAX+2 to the EAX register and lastly, it returns the value that EAX has.

mov     eax, large fs:30h
movzx   eax, byte ptr [eax+2]
retn

The question now becomes, what does the FS segment register store in offset 0x30? The answer is common to any Windows people out there. In Windows, the FS segment register points to the Win32 TIB (Windows 32-bit Thread Information Block), a data structure that describes the currently running thread. In the 0x30 offset we have the linear address of the Process Environment Block (PEB). If you are interested in the rest of the TIB you can check the full mapping on Wikipedia.



This means that the first instruction retrieves the address of PEB data structure. The second instruction fetches the value that is stored two Bytes after the beginning of the PEB structure. Reading Microsoft’s documentation on PEB solves this mystery as this is where “BeingDebugged” is located. So, technically isDebuggerPresent() is returning whatever value “BeingDebugged” has.

typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
} PEB, *PPEB;

The question now becomes, what can set _PEB.BeingDebugged to a non-zero value and why. The answer to this is the debugging API of Windows. When a request is made to attach a debugger to a process such as DebugActiveProcess() it will result to a call to DbgUiDebugActiveProcess() from the Windows Native API, known as NTDLL. Here is the equivalent disassembled code.



What we care about as you can easily guess, is the call to _NtDebugActiveProcess() function. This internal API call results in a system call (hex value 0x800C5) to “NtDebugActiveProcess” which is invoked via Wow64SystemServiceCall(). This is part of the NT Operating System kernel (ntoskrnl.exe), also known as the Windows kernel image. If we load the ntoskrnl.exe to IDA and find this system call’s code, we will see exactly how “BeingDebugged” is set.



As you can see “NtDebugActiveProcess” system call will eventually result in the invocation of DbgkpSetProcessDebugObject() function. A function that takes four arguments and is defined as you see below in the Windows internal kernel API prototype.

NTSTATUS NTAPI DbgkpSetProcessDebugObject(IN PEPROCESS Process,
		IN PDEBUG_OBJECT DebugObject,
		IN NTSTATUS      MsgStatus,
		IN PETHREAD  	 LastThread 
) 	

This routine is also part of ntoskrl.exe and what is interesting to us is at the very bottom of its code. You can see the exact snippet below. What we care about is the call to DbgkpMarkProcessPeb() function.



As it is suggested by its name, DbgkpMarkProcessPeb() will update the PEB of the process that it received as an argument to mark it as under debugging. Below you can see exactly where the “BeingDebugged” flag is set to TRUE (or FALSE) within DbgkpMarkProcessPeb().



The above code updates “Process->PEB->BeingDebugged” based on the value of “DebugPort”. If the “DebugPort” is enabled, it will set “Process->PEB->BeingDebugged” to the value of “DebugPort”, otherwise it will remain unset. The “DebugPort” is a value of the PEB structure which is initialized if the parent process (like a debugger) or the kernel was asked to to associate this process with a debug object. You can see the function that does this below.



Basically, this means that any time a debug object is created on the kernel for a process, the DbgkpMarkProcessPeb() will be invoked to ensure that “BeingDebugged” is set to TRUE in the PEB data structure of this specific process. Then, isDebuggerPresent() will simply fetch that value and return it to the user-space when called. As I mentioned in the intro, the scope of this post was not how to defeat the isDebuggerPresent() anti-debugging technique, but to understand how it works. Knowing the above should be sufficient to give you some ideas on how to do it. Just for reference, below are some ideas with a few different methods to bypass this check.

Written by xorl

November 20, 2017 at 16:23

CVE-2017-1081: FreeBSD ipfilter use-after-free

leave a comment »

The SA-17:04 FreeBSD security advisory describes a logic flaw that results in a use-after-free situation in ipfilter. The vulnerability was reported by Cy Schubert and affects all FreeBSD releases prior to 11.0-STABLE, 11.0-RELEASE-p10, 10.3-STABLE, and 10.3-RELEASE-p19. Let’s have a look at sys/contrib/ipfilter/netinet/ip_frag.c to better understand the vulnerability.

/* ------------------------------------------------------------------------ */
/* Function:    ipfr_frag_new                                               */
/* Returns:     ipfr_t * - pointer to fragment cache state info or NULL     */
/* Parameters:  fin(I)   - pointer to packet information                    */
/*              table(I) - pointer to frag table to add to                  */
/*              lock(I)  - pointer to lock to get a write hold of           */
/*                                                                          */
/* Add a new entry to the fragment cache, registering it as having come     */
/* through this box, with the result of the filter operation.               */
/*                                                                          */
/* If this function succeeds, it returns with a write lock held on "lock".  */
/* If it fails, no lock is held on return.                                  */
/* ------------------------------------------------------------------------ */
static ipfr_t *
ipfr_frag_new(softc, softf, fin, pass, table
#ifdef USE_MUTEXES
, lock
#endif
)
    ...
	ipfr_t *fra, frag, *fran;
    ...
	/*
	 * allocate some memory, if possible, if not, just record that we
	 * failed to do so.
	 */
	KMALLOC(fran, ipfr_t *);
	if (fran == NULL) {
		FBUMPD(ifs_nomem);
		return NULL;
	}
    ...
	/*
	 * first, make sure it isn't already there...
	 */
	for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
		if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
			  IPFR_CMPSZ)) {
			RWLOCK_EXIT(lock);
			FBUMPD(ifs_exists);
			KFREE(fra);
			return NULL;
		}

	fra = fran;
	fran = NULL;
	fr = fin->fin_fr;
	fra->ipfr_rule = fr;
	if (fr != NULL) {
		MUTEX_ENTER(&fr->fr_lock);
		fr->fr_ref++;
		MUTEX_EXIT(&fr->fr_lock);
	}
    ...
}

The above code snippet is from ipfr_frag_new() which handles new fragmented packets in the fragment cache. What is important the “for” loop which is the processing of a hash table that contains the cached fragmented packets. The bcmp() will check if the packet stored in “fra” is already in the hash table (the “frag” pointer). If it’s not it will update “fra” with the memory allocated in “fran” and store the new packet there. If is already in the table, it will release the lock, free “fra” and return NULL. Well, it’s hard to notice but that’s a logic flaw as it should have freed “fran” (the not used kernel buffer) rather than the “fra” which points to the packet to be processed. As you can easily guess, the patch is pretty straightforward.

 			RWLOCK_EXIT(lock);
 			FBUMPD(ifs_exists);
-			KFREE(fra);
+			KFREE(fran);
 			return NULL;

There are few different code paths that can result in accessing the freed “fra”. One is in the ipf_frag_lookup() function which is used to look in the fragment cache for entries of the requested packet with its filter result. You can see how this can cause issues below.

static ipfr_t *
ipf_frag_lookup(softc, softf, fin, table
#ifdef USE_MUTEXES
, lock
#endif
)
	ipf_main_softc_t *softc;
	ipf_frag_softc_t *softf;
	fr_info_t *fin;
	ipfr_t *table[];
#ifdef USE_MUTEXES
	ipfrwlock_t *lock;
#endif
{
    ...
	/*
	 * check the table, careful to only compare the right amount of data
	 */
	for (f = table[idx]; f; f = f->ipfr_hnext) {
    ...
	return NULL;
}

And a second code path that can lead to use-after-free is via ipf_slowtimer() function from sys/contrib/ipfilter/netinet/fil.c. This function is used to slowly expire the state of the fragments.

void
ipf_slowtimer(softc)
	ipf_main_softc_t *softc;
{

	ipf_token_expire(softc);
	ipf_frag_expire(softc);
	ipf_state_expire(softc);
	ipf_nat_expire(softc);
	ipf_auth_expire(softc);
	ipf_lookup_expire(softc);
	ipf_rule_expire(softc);
	ipf_sync_expire(softc);
	softc->ipf_ticks++;
#   if defined(__OpenBSD__)
	timeout_add(&ipf_slowtimer_ch, hz/2);
#   endif
}

The interesting for this vulnerability call is the one to ipf_frag_expire() which is designed to expire entries from the fragment cache table. To achieve this, ipf_frag_expire() utilizes the internal ipf_frag_delete() routine which is shown below.

static void
ipf_frag_delete(softc, fra, tail)
	ipf_main_softc_t *softc;
	ipfr_t *fra, ***tail;
{
	ipf_frag_softc_t *softf = softc->ipf_frag_soft;

	if (fra->ipfr_next)
		fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
	*fra->ipfr_prev = fra->ipfr_next;
	if (*tail == &fra->ipfr_next)
		*tail = fra->ipfr_prev;

	if (fra->ipfr_hnext)
		fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
	*fra->ipfr_hprev = fra->ipfr_hnext;

	if (fra->ipfr_rule != NULL) {
		(void) ipf_derefrule(softc, &fra->ipfr_rule);
	}

	if (fra->ipfr_ref <= 0)
		ipf_frag_free(softf, fra);
}

Due to the logic error in ipfr_frag_new() the above could result in attempting to delete an entry that has already been freed. Interesting vulnerability and kind of hard to catch from static code analysis.

Written by xorl

November 19, 2017 at 18:30

Posted in vulnerabilities

SharkFest’17 Europe

leave a comment »

This was my first time in SharkFest Europe, a conference that aims in knowledge and experience sharing among Wireshark developers and power users. The event took place in the second week of November 2017 in Estoril, Portugal. An truly beautiful location with interesting history.



The event was split in three simultaneous sessions but unfortunately, only one of the three conference rooms were recording the talks. You can find those recordings as well as some of the slides from other presentations here and here. Below is a list of the ones that I attended.

  • Keynote: Wireshark: Past, Preent & Future – Gerald Combs & Friends
  • Using Wireshark to Solve Real Problems for Real People: Step-by-Step Case Studies in Packet Analysis – Kary Rogers
  • Troubleshooting WLANs (Part 1): Layer 1 & 2 Analysis Using AirPcap, Wi-Spy & Other Tools – Rolf Leutert
  • Troubleshooting WLANs (Part 2): Using 802.11 Management & Control Frames – Rolf Leutert
  • SMB Handshake: The Devil Lies in the Detail – Eduard Blenkers
  • SSL/TLS Decryption: uncovering secrets – Peter Wu
  • extcap – Packet Capture beyond libpcap/winpcap: Bluetooth sniffing, Android dumping & other fun stuff – Ronald Knall
  • Turning Wireshark into a Traffic Monitoring Tool: Moving from packet details to the big picture – Luca Deri
  • The Network is Slow! Finding the Root Cause of Slow Application Performance – Lorna Robertshaw
  • How Did They Do That? Network Forensic Case Studies – Phill Shade
  • Developer Bytes Lightning Talks-Usage Track – Wireshark Core Developers
  • Real World Troubleshooting Tales – Graeme Bailey
  • Sneaking in by the Back Door – Hacking the Non-Standard Layers with Wireshark – Phill Shade



Both the location and the event were great. Some of the attendees were network analysts with decades of experience. If you are interested in network analysis (including security as the exact same principles apply there too), SharkFest is a very nice conference to attend (hint: it is taking place on different place every year).

Written by xorl

November 19, 2017 at 17:42

Posted in conferences

Threat Analysis: How fraudsters avoid fingerprinting/detection

leave a comment »

For most online businesses nowadays there is at least some method of fraud. Most companies are trying to mitigate that by implementing “smart” fingerprinting based on the web browsers or clients. Unfortunately, not many of them are actually researching to find out what “bad guys” are using out there. This will be a gentle introduction to a couple of anti-detection tools used by cyber-criminals.



The, so-called, anti-detect web browsers have been around for at least the past few years. Those are typically web browser profile generators that randomize the variables that the majority of the fraud detection engines use (user agents, plugins, version, language, platform, timezone, etc.). An easy way to test your organization against this is to simply use it and see how your fraud engine behaves. Using the most popular one, the “AntiDetect”, it is relatively easy to do so due to the business model of its author. The threat actor behind “AntiDetect” web browser offers older versions for free while asking for $399 for buying the latest or a $99/month subscription model.



Before moving to the other anti-detection methods, it is worth noting that “AntiDetect” is a very popular software among Russian speaking threat actors and it has been active since May 2014. Until recently, the servers hosting this software were based in Russia but recently moved to Belize. Below you can see some screen captures of this from the community edition of RiskIQ.



In a recent (a few months ago) research on this topic I observed a switch of fraudsters from tools like “AntiDetect” to fully customized virtual machines (VM) like “FraudFox”. This one, “FraudFox”, is a Windows based VM that includes a anti-detection web browser profile generator (just like the one described above), but also some system settings and pre-installed tools to reduce detection. Furthermore, the authors of this tool say that it should be used as “software in a briefcase” by starting it when doing some fraud activity and then destroying the VM along with all of its evidence. Unlike “AntiDetect” this one is offered in a subscription based model only for $99/month.



And “FraudFox” is not the only such VM, there are more and more being sold out in the underground for different systems and configurations. All of them, though, follow similar techniques and anti-detection tools. Here you can see another one which is less popular than the above.



The past 1.5 years there was also a rise of mobile applications that offer similar services, usually exclusively to Android platform. You can see a (censored) example of such an application below.



Regardless of the above tooling that fraudsters use to evade fraud engines, it is important to continuously monitor and study the TTPs (tactics, techniques, and procedures) that those cyber-criminals employ. After studying them for a while you will definitely see some patterns that could be employed in your counter-fraud detection mechanisms. For example here are some common ones.

  • Most fraudsters will login to a stolen account, check the location of the victim and re-login via SOCKS, RDP, or VPN from the same location as the victim before committing any fraudulent activity
  • Most fraudsters will change the contact details of a stolen account, and then make a very small price transaction with a stolen credit card
  • The fingerprinting of the fraudsters will vary a lot compared to legitimate users due to the randomization of all the parameters

The above are just a couple of examples. Each business should do their own independent research on how fraudsters attack them and abuse their services to understand what preventive and detective controls they can implement to reduce their attack surface.

Written by xorl

November 18, 2017 at 17:30

CVE-2017-15306: Linux kernel KVM PowerPC NULL pointer dereference

leave a comment »

This vulnerability was reported by Greg Kurz on September 2017. The vulnerability is specific to PowerPC KVM (Kernel-based Virtual Machine) with its code being in arch/powerpc/kvm/powerpc.c source code file. Below is the vulnerable IOCTL (Input/Output Control) function from this file.

int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
{
    ...
	/* Assume we're using HV mode when the HV module is loaded */
	int hv_enabled = kvmppc_hv_ops ? 1 : 0;

	if (kvm) {
		/*
		 * Hooray - we know which VM type we're running on. Depend on
		 * that rather than the guess above.
		 */
		hv_enabled = is_kvmppc_hv_enabled(kvm);
	}
    ...
	switch (ext) {
    ...
	case KVM_CAP_PPC_HTM:
		r = cpu_has_feature(CPU_FTR_TM_COMP) &&
		    is_kvmppc_hv_enabled(kvm);
		break;
    ...
}

What Greg Kurz discovered was that if the file descriptor of the global KVM was used (that is, /dev/kvm) then “kvm” pointer is NULL. This means that the first “if” condition will fail but if the IOCTL is called with “KVM_CAP_PPC_HTM” then “kvm” will be invoked by is_kvmppc_hv_enabled() resulting in a NULL pointer dereference. You can see the equivalent code from arch/powerpc/include/asm/kvm_ppc.h here.

static inline bool is_kvmppc_hv_enabled(struct kvm *kvm)
{
	return kvm->arch.kvm_ops == kvmppc_hv_ops;
}

extern int kvmppc_hwrng_present(void);

Greg Kurz also included a simple PoC trigger code that basically opens the global KVM file descriptor and then calls the above IOCTL with the “KVM_CAP_PPC_HTM” extension. You can see that PoC code below.

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/kvm.h>

main()
{
    int fd = open("/dev/kvm", O_RDWR);
    ioctl(fd, KVM_CHECK_EXTENSION, KVM_CAP_PPC_HTM);
}

As you can easily guess, the patch for this vulnerability was to reuse the “hv_enabled” variable which is set with the same value but only if “kvm” is not NULL as we saw above. You can see the patch here.

 	case KVM_CAP_PPC_HTM:
-		r = cpu_has_feature(CPU_FTR_TM_COMP) &&
-		    is_kvmppc_hv_enabled(kvm);
+		r = cpu_has_feature(CPU_FTR_TM_COMP) && hv_enabled;
 		break;

Written by xorl

November 18, 2017 at 00:43

Posted in vulnerabilities