SSD Advisory – IRDA Linux Driver UAF

Vulnerabilities Summary
The following advisory describes two vulnerabilities in the Linux Kernel. By combining these two vulnerabilities a privilege escalation can be achieved. The two vulnerabilities are quite old and have been around for at least 17 years, quite a few Long Term releases of Linux have them in their kernel. While the assessment of the Linux kernel team is that they only pose a denial of service, that is incorrect, we will provide here proof that they can run code with a bit of effort and some luck (the probability of success of gaining root privileges is above 50%).

Vendor Response
“Memory leak in the irda_bind function in net/irda/af_irda.c and later in drivers/staging/irda/net/af_irda.c in the Linux kernel before 4.17 allows local users to cause a denial of service (memory consumption) by repeatedly binding an AF_IRDA socket. (CVE-2018-6554) The irda_setsockopt function in net/irda/af_irda.c and later in drivers/staging/irda/net/af_irda.c in the Linux kernel before 4.17 allows local users to cause a denial of service (ias_object use-after-free and system crash) or possibly have unspecified other impact via an AF_IRDA socket. (CVE-2018-6555)”

https://lists.ubuntu.com/archives/kernel-team/2018-September/095137.html

CVE
CVE-2018-6554
CVE-2018-6555

Credit
An independent security researcher, Mohamed Ghannam, has reported this vulnerability to Beyond Security’s SecuriTeam Secure Disclosure program.

Affected systems
The vulnerability was introduced in 2.4.17 (21 Dec 2001) Affecting all kernel versions up to 4.17 (IrDA subsystem as removed).

Vulnerability Details
The first bug affects IRDA socket since its birth in Linux Kernel, it relies to the general queue implementation called “hashbin”.

Bug analysis:

(1) – self->ias_obj takes the allocated object directly
(2) – in our point of view it checks if the socket is already bound
(3) – if not, insert the allocated object into global hashtable irias_objects, which keeps track of all allocated irias objects

There is a problem in (1), if we call bind() twice, self->ias_obj loses the reference of the first allocated object, so it has no power to free it, and the object will persist in irias_objects hashtable, this allows us of course to exhaust the memory of the system, This will be useful when we combine it with another bug.

Here is another bug :

(4) – the comment made by the developer is self explanatory
(5) – the object is inserted in the queue

The problem here is we can insert the same object again, because this only can be done if a new object is created, or an object already allocated by the user (via setsockopt), and only root can do this, so we can consider it as a security bypass.

Combining these two bugs, we can re-insert an object several times, and free it later, which makes a freed object in irias_objects hash table.

Exploiting this bug requires two things :
1. Reliably spraying the heap to take control of the freed object
2. A target pointer to be overwritten with userdata, this can be achieved by leaking some kernel memory or using global variables.

1.Reliably spraying the heap to take control of the freed object
The freed object is allocated in kmalloc-96, we should search for a good primitive to take control over it:

Our target is taking control of q_next and q_prev, which is a good read/write primitive through irias_insert_object() Most of known techniques i.e : sendm(m)sg, msgsnd(), add_key() will not work in our case, sendmsg/msgsnd require a well crafted header, add_key() frees the payload when it finishes and corrupt our payload with a freelist pointer and zeros the payload since this commit : 57070c850a03ee0cea654fc22cb8032fc3139d39)

Luckily, XFRM socket gives us a good primitive to make a consistent spray and controlling the top of our target object, Once we control the freed object, we have a write primitive to any kernel address.

enqueue_first() is responsible for inserting a new object into the queue, since we are controlling the previous queued object, we can write a pointer (with controlled data) to any kernel memory as shown below :

Here is the output:

So Here the process of controlling the execution:
– Create 4 socket files via socket()
– bind socket 1 to 3 , this will allocate and insert objects into irias_objects
– bind 1 again , this will trigger the first bug
– insert socket 2 & 3 many times (~5)
– close socket 2, then 3 , this will free sockets and you should see the ias object of socket 3 freed but still queued in the list
– Spray the heap to fill the freed object with our payload, now we have control over obj->q.q_(next/prev)
– bind socket 4 , this is ‘what’ pointer to put in the controlled object (obj->q.q_prev)
– close socket 4 to free the last object
– Spray the heap again to control the object
– Trigger the overwritten pointer , and you’ll get RIP

Here is a crash PoC showing that we’ve overwritten net_sysctl_root.set_ownership

In order to completely control the execution, we must look for an object holds a pointer to a function pointers, which can be achieved by information leak.

The first “bug” (double bind and losing the reference to ias_obj) is not required to exploit UAF (reinsertion on the same object into the hashbin queue). It has no relevance to the exploitation chain demonstrated in the PoC and UAF can be exploited without it.

Binding the same socket would result in the following path taken (since self->tsap is already set):

In the PoC, binding socket 1 twice would simply leave the first allocated object in the queue and set self->ias_obj (for socket 1) to NULL.

The exploitation procedure detailed before in this post is different from the actual PoC:
– Create 4 socket files via socket()
– bind socket 1 to 3 , this will allocate and insert objects into irias_objects
– bind 1 again , this will trigger the first bug
– insert socket 2 & 3 many times (~5)
– close socket 2, then 3 , this will free sockets and you should see the ias object of socket 3 freed but still queued in the list [!]– Spray the heap to fill the freed object with our payload, now we have control over obj->q.q_(next/prev)
– bind socket 4 , this is ‘what’ pointer to put in the controlled object (obj->q.q_prev)
– close socket 4 to free the last object
– Spray the heap again to control the object
– Trigger the overwritten pointer , and you’ll get RIP

[!] step is different from the PoC which closes sock 3 first and then sock 2. That makes a big difference. Closing sock 2 first would leave a single obj_ias for sock 3 in the queue (links to sock 1 object will be lost). This will not lead to an exploitable UAF case.

Reinserting ias_obj for sock 2 & 3 many times (~5) is not needed. You’re repeating the same operations without affecting the queue layout. To make the whole process clearer here’s the original PoC with comments:

Here is a crash PoC showing that we’ve overwritten net_sysctl_root.set_ownership” doesn’t make sense based on the produced oops message showing that there was an attempt to execute NX memory address. What this oops message shows is that you’ve overwritten some function ptr (mostly due to luck) with address of the new ias_object (when binding) and then tried to execute that pointer in the original path.

Exploit

If you want to look at a Presentation with detailed graphical explanation about the vulnerabilities go to:
beVX – Dissecting a 17 year old (Vitaly Nikolenko)



*** This is a Security Bloggers Network syndicated blog from SecuriTeam Blogs authored by SSD / Ori Nimron. Read the original post at: https://blogs.securiteam.com/index.php/archives/3759