CVE-2017-2786
A denial of service vulnerability exists in the psnotifyd application of the Pharos PopUp printer client version 9.0. A specially crafted packet can be sent to the victim’s computer and can lead to an out of bounds read causing a crash and a denial of service.
Pharos PopUp Printer Client 9.0
https://pharos.com/products-services/
5.3 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
CWE-125 - Out-of-bounds Read
Pharos PopUp Printer client is printing software that is widely used in Universities all over the United States. This client is a way to manage multiple connections to a single printing point and is constantly listening in the background for a packet from the printer. It is also running with root privilege for easy access to any privileged drivers. These all make this an excellent target where a vulnerability could have a high impact.
The vulnerability begins inside of the DecodeString function. The packet strings are sent to the program encoded in an encoding format. This function parses the string from the packet and increments the packet pointer to the next data. It does this by reading in the length of the string from the packet just before the string to be parsed. It then adds this value to its current location to position itself at the next data to be parsed. This code is shown below.
__text:0000000100005E21 mov rsi, [rbx+PSComDecodePacket.end_of_str] [1]
__text:0000000100005E28 movzx ecx, byte ptr [rsi]
__text:0000000100005E2B mov eax, ecx
__text:0000000100005E2D and eax, 3Fh
__text:0000000100005E30 cmp eax, 10
__text:0000000100005E33 jnz short loc_100005E98
__text:0000000100005E35 lea rax, [rsi+1]
__text:0000000100005E39 mov [rbx+PSComDecodePacket.end_of_str], rax
__text:0000000100005E40 mov al, 1
__text:0000000100005E42 test cl, cl
__text:0000000100005E44 js short loc_100005E74
__text:0000000100005E46 mov edx, [rsi+1] [2]
__text:0000000100005E49 add rsi, 5
__text:0000000100005E4D mov [rbx+PSComDecodePacket.end_of_str], rsi
__text:0000000100005E54 mov [r14], rsi
__text:0000000100005E57 add [rbx+PSComDecodePacket.end_of_str], rdx ; [3]
__text:0000000100005E5E test cl, 40h
__text:0000000100005E61 jz short loc_100005E72
Starting at [1], we see the string location being loaded from a struct and moved into RSI. A few checks are made on the data which is controlled by the attacker and can be easily bypassed. Then at [2], we see some data being moved directly from the attacker controlled packet and into EDX. Further down, [3], we see this attacker controlled length directly added to the pointer. Later in the code a call to CheckPacketEnd is made and the pointer is used again. The code is below.
__text:0000000100006194 CheckPacketEnd proc near ; CODE XREF: DecodeString+24p
__text:0000000100006194 ; DecodeBinary+2Ap ...
__text:0000000100006194
__text:0000000100006194 push rbp
__text:0000000100006195 mov rbp, rsp
...
__text:00000001000061B7 mov rbx, [r15+PSComDecodePacket.end_of_str] [1]
__text:00000001000061BE cmp byte ptr [rbx], 0 [2]
At location [1], the pointer for the end of the string is moved into RBX. It is then immediately dereferenced and compared against zero, [2]. This pointer is never validated and indeed points out of bounds after being manipulated in the previous function. This leads to an out of bounds access and a denial of service condition.
./exc_handler ./psnotifyd
2017-01-24 13:57:10.602 psnotifyd[32275:8783881] Notify listening thread started
2017-01-24 13:57:10.603 psnotifyd[32275:8783881] Listening on socket 4
2017-01-24 13:57:10.607 psnotifyd[32275:8783877] CFSocketSetAddress bind failure: 48
2017-01-24 13:57:10.607 psnotifyd[32275:8783877] Telling any existing Notify processes that psnotifyd has started up.
2017-01-24 13:57:17.372 psnotifyd[32275:8783881] New notify connection incoming
2017-01-24 13:57:17.372 psnotifyd[32275:8783881] Spawning a new notify request handler thread
2017-01-24 13:57:17.372 psnotifyd[32275:8783881] Listening on socket 4
2017-01-24 13:57:17.372 psnotifyd[32275:8784052] New request handler thread started
2017-01-24 13:57:17.372 psnotifyd[32275:8784052] I got some stuff goin' on
Crashed thread log =
0 psnotifyd 0x00000001000061be 0x100000000 + 25022
1 psnotifyd 0x0000000100005e21 0x100000000 + 24097
2 psnotifyd 0x00000001000029c4 0x100000000 + 10692
3 psnotifyd 0x0000000100002392 0x100000000 + 9106
4 com.apple.Foundation 0x00007fff89e3de64 __NSThread__start__ + 1351
5 libsystem_pthread.dylib 0x00007fff997ec99d _pthread_body + 131
6 libsystem_pthread.dylib 0x00007fff997ec91a _pthread_start + 168
7 libsystem_pthread.dylib 0x00007fff997ea351 thread_start + 13
log name is: ./crashlogs/lollipo.crashlog.txt
---
exception=EXC_BAD_ACCESS:signal=11:is_exploitable= no:instruction_disassembly=cmpb $CONSTANT,(%rbx):instruction_address=0x00000001000061be:access_type=read:access_address=0x00000002004fa582:
Crash accessing invalid address.
2017-02-07 - Vendor Disclosure
2017-03-07 - Public Release
Discovered by Tyler Bohan of Cisco Talos. Talos would also like to thank NYU Osiris Lab for helping out with some of the reversing.