Hacking HP Display Monitors via Monitor Control Command Set (CVE-2023-5449)
Have you ever wondered how display monitor software can change various settings like brightness over a simple display cable? As it turns out, this relies on a standard protocol that can lead to interesting vulnerabilities. Here’s how I found and exploited CVE-2023-5449 in dozens of HP display monitors.
你有没有想过显示监视器软件如何通过简单的显示电缆改变各种设置,如亮度?事实证明,这依赖于可能导致有趣漏洞的标准协议。以下是我在数十台 HP 显示器中发现并利用 CVE-2023-5449 的方法。
Display Monitor Software
显示监视器软件 🔗
One day, I connected my computer to a HP display. Annoyingly, I noticed that Windows auto-installed the HP Display Center software without any prompts, likely because it was a trusted Windows Store application. Later, I noticed that even when I was using a monitor from a different manufacturer, HP Display Center could still interact and control certain basic settings like brightness.
有一天,我把电脑连接到了一台惠普显示器。令人讨厌的是,我注意到 Windows 在没有任何提示的情况下自动安装了 HP Display Center 软件,这可能是因为它是一个受信任的 Windows 应用商店应用程序。后来,我注意到,即使我使用不同制造商的显示器,HP Display Center 仍然可以交互和控制某些基本设置,例如亮度。
Curious, I decided to take a look at the internals of the software. Fortunately, it was a .NET Framework application that could be easily reversed into close-to-original C# code. Within the code, I noticed a few interesting functions that were called whenever a display setting was changed, like ExecuteSetVcp
. In turn, these functions called lower-level Windows APIs that presumably handled the actually hardware-level communication.
出于好奇,我决定看看软件的内部结构。幸运的是,它是一个 .NET Framework 应用程序,可以很容易地反转为接近原始的 C# 代码。在代码中,我注意到一些有趣的函数,每当更改显示设置时都会调用这些函数,例如 ExecuteSetVcp
.反过来,这些函数调用较低级别的 Windows API,这些 API 可能处理实际的硬件级通信。
A few searches later, I found out that Vcp
referred to Virtual Control Panel. Within the Monitor Control Command Set (MCCS) protocol, each VCP corresponds to a specific monitor setting, such as a brightness VCP, contrast VCP, and so on. But first, I needed to understand MCCS better.
几次搜索后,我发现它 Vcp
指的是虚拟控制面板。在监视器控制命令集 (MCCS) 协议中,每个 VCP 对应于特定的监视器设置,例如亮度 VCP、对比度 VCP 等。但首先,我需要更好地了解 MCCS。
Monitor Control Command Set (MCCS)
监视器控制命令集 (MCCS) 🔗
The reason why we can use display monitors fairly interchangeably without having to change cables, drivers, and so on is because of various standards developed by the Video Electronics Standards Association (VESA). Yes, that VESA is behind the VESA mount, but beyond physical standards VESA also specifies firmware and software standards like MCCS.
我们之所以可以相当互换地使用显示器,而不必更换电缆、驱动程序等,是因为视频电子标准协会 (VESA) 制定了各种标准。是的,VESA 位于 VESA 支架后面,但除了物理标准之外,VESA 还指定了固件和软件标准,如 MCCS。
As the name suggests, MCCS specifies how hosts connected to a display monitor can control the monitor through various commands. MCCS runs over the lower-level Display Data Channel Command Interface (DDC/CI) standard, which can be implemented on various cables like HDMI.
顾名思义,MCCS 指定连接到显示监视器的主机如何通过各种命令控制监视器。MCCS 在较低级别的显示数据通道命令接口 (DDC/CI) 标准上运行,该标准可以在 HDMI 等各种电缆上实现。
In particular, MCCS defines three types of VCP controls:
具体而言,MCCS 定义了三种类型的 VCP 控件:
- Continuous: Values from 0 to a specified maximum, such as brightness (0 to 100).
连续:从 0 到指定最大值的值,例如亮度(0 到 100)。 - Non-continuous: Values within a limited set (in other words an enum/boolean), such as color preset.
非连续:有限集(即枚举/布尔值)内的值,例如颜色预设。 - Table: Blocks of data (custom structs). For example, the “Source Timing Mode” VCP has a 5 byte data structure: flags for DMT timing modes (0), flags for CEA DTV timing modes (1), CVT descriptor bytes (2-4). Yes, that’s a lot of acronyms I did not bother to look up.
表:数据块(自定义结构)。例如,“源定时模式”VCP 具有 5 字节数据结构:DMT 定时模式的标志 (0)、CEA DTV 定时模式的标志 (1)、CVT 描述符字节 (2-4)。是的,这是我懒得去查找的很多首字母缩略词。
In addition, these controls can be read-only, write-only, or read-write (this will be important later). You can check published MCCS documents to get the full list of VCP codes.
此外,这些控件可以是只读的、只写的或读写的(这在后面会很重要)。您可以查看已发布的 MCCS 文档以获取 VCP 代码的完整列表。
To set a writeable VCP control, Windows provides the following API:
若要设置可写 VCP 控件,Windows 提供了以下 API:
_BOOL SetVCPFeature(
[in] HANDLE hMonitor, // handle to display monitor instance
[in] BYTE bVCPCode, // VCP control code
[in] DWORD dwNewValue // New VCP control code value
);
Although MCCS already pre-defines many common VCP controls from control code 0x00 to 0xDF, it also leaves the door open for manufacturer-specific controls:
尽管 MCCS 已经预定义了从控制代码0x00到 0xDF 的许多常见 VCP 控件,但它也为制造商特定的控件敞开了大门:
The 32 control codes E0h through FFh have been allocated to allow manufacturers to issue their own specific controls either where the defined VCP codes do not provide a required function or where the added function is considered proprietary.
分配了 32 个控制代码 E0h 到 FFh,以允许制造商在定义的 VCP 代码未提供所需功能或附加功能被视为专有的情况下发布自己的特定控制。
Caution: Use of these codes has the risk of causing incompatibility and / or unpredictable behavior. Example: Consider the case when two display manufacturers choose to use the same ‘manufacturer VCP code’ for different functions (or different implementations of the same function) but the user chooses not to use the specific software support supplied or recommended for his particular display – he may use a general purpose MCCS support application, native support built into the operating system or a MCCS support application intended for a different display model. In this case, the resulting behavior is unpredictable, ranging from no support for the function which uses a ‘manufacturer VCP code’ to incorrect control and adjustment of the function. In all cases this will likely result in an annoyed user and a service call, in extreme cases it may result in a situation where the user cannot return the display to normal operation.
注意:使用这些代码有导致不兼容和/或不可预知行为的风险。示例:考虑以下情况:当两个显示器制造商选择对不同的功能(或同一功能的不同实现)使用相同的“制造商 VCP 代码”,但用户选择不使用为其特定显示器提供或推荐的特定软件支持时,他可能会使用通用 MCCS 支持应用程序、操作系统内置的本机支持或用于不同显示器型号的 MCCS 支持应用程序。在这种情况下,产生的行为是不可预测的,从不支持使用“制造商 VCP 代码”的功能到不正确地控制和调整功能。在所有情况下,这都可能导致用户恼火和服务呼叫,在极端情况下,可能会导致用户无法将显示器恢复正常操作的情况。
It is recommended that these codes are used with caution and only when strictly necessary.
建议谨慎使用这些代码,并且仅在绝对必要时使用。
Despite this dire warning, as I found out with the iCalendar standard, vendors tend to err on the other side of caution in order to differentiate their products built on a common standard. For example, you will find display monitors that go far beyond simply showing nice pictures – they can include integrated webcams, microphones, and more.
尽管有这个可怕的警告,正如我在iCalendar标准中发现的那样,供应商往往会谨慎行事,以便区分他们基于通用标准的产品。例如,您会发现显示显示器远远超出了简单地显示精美图片的范围 – 它们可以包括集成的网络摄像头、麦克风等。
Some of this information supported by a monitor is sent via a capability string during initialization that allows software to understand which VCP controls are supported by that monitor.
监视器支持的某些信息在初始化期间通过功能字符串发送,使软件能够了解该监视器支持哪些 VCP 控件。
HP’s Proprietary VCP Codes
HP 专有的 VCP 代码 🔗
You may notice that with only 16 different VCP codes allocated to manufacturer-specific controls, there is not actually a lot of space to add new controls.
您可能会注意到,由于只有 16 个不同的 VCP 代码分配给特定于制造商的控件,因此实际上没有太多空间来添加新控件。
However, HP had an ingenious solution for this.
但是,惠普对此有一个巧妙的解决方案。
For continuous controls, their codes followed the usual paradigm of <VCP CODE> <VALUE>
.
对于连续控制,它们的代码遵循通常的 <VCP CODE> <VALUE>
范式。
However, this is a waste of bytes for non-continuous controls, since the enum typically only takes a handful of possible values. For example, there may be a few color profiles that correspond to specific byte values: Gaming (0), Movie (1), Warm (2), Cool (3). However, a byte can take up to 256 values.
但是,对于非连续控件来说,这是浪费字节,因为枚举通常只接受少数几个可能的值。例如,可能有几个颜色配置文件对应于特定的字节值:游戏 (0)、电影 (1)、暖色 (2)、冷色 (3)。但是,一个字节最多可以接受 256 个值。
Instead, for proprietary non-continuous controls, HP created sub-VCP codes contained within a catch-all VCP code. When setting this VCP control, the values could then range from SetColorProfileGaming
(0), SetColorProfileMovie
(1), SetColorProfileWarm
(2), SetColorProfileCool
(3), then include additional non-continuous controls like SetScreenOrientation0
(4), SetScreenOrientation90
(5), SetScreenOrientation180
(6), and so on. This way, rather than X number of non-continuous controls taking up X precious proprietary control codes, they can take up only 1.
相反,对于专有的非连续控制,HP 创建了包含在包罗万象的 VCP 代码中的子 VCP 代码。设置此 VCP 控件时,这些值的范围可以从 (0)、(1)、(2)、(3) 不等,然后包括其他非连续控件,如 SetScreenOrientation0
(4)、(5)、 SetScreenOrientation90
SetScreenOrientation180
SetColorProfileGaming
SetColorProfileMovie
SetColorProfileCool
(6) 等。 SetColorProfileWarm
这样一来,X 个非连续控制装置占用 X 个宝贵的专有控制代码,它们只能占用 1 个。
Theft Deterrence 盗窃威慑 🔗
It was difficult to reverse these codes from the firmware, which largely contained monitor chipset-specific (Genesis) instructions. Some research by Red Balloon Security has been done previously on a proprietary “GProbe” protocol that ran over DDC as well that convinced me not to take that route.
很难从固件中反转这些代码,固件主要包含特定于显示器芯片组的 (Genesis) 指令。Red Balloon Security 之前曾对专有的“GProbe”协议进行过一些研究,该协议也运行在 DDC 上,这说服了我不要走这条路。
Instead, thanks to the ready availability of display monitor control software, it was far easier to reverse the clients and figure out the functionality of VCP control codes from the function names, dynamic debugging while using the GUI, and logging messages.
相反,由于显示器监控控制软件的现成可用性,反转客户端并从函数名称、使用 GUI 时的动态调试和记录消息中找出 VCP 控制代码的功能要容易得多。
One of the interesting features I noticed from the GUI was HP’s theft deterrence mechanism. Users can set a 4-to-6 digit PIN on the monitor such that if the monitor is stolen and connected to a new computer without entering the PIN, after 5 minutes the screen will dim and show a message “Theft Mode is Enabled”.
我从 GUI 中注意到的一个有趣的功能是 HP 的盗窃威慑机制。用户可以在显示器上设置一个 4 到 6 位的 PIN,这样,如果显示器被盗并连接到新计算机而不输入 PIN,5 分钟后屏幕将变暗并显示消息“盗窃模式已启用”。
To support this feature, HP implements the following control commands:
为了支持此功能,HP 实施了以下控制命令:
- TheftTimeOut (251): Continuous value that denotes the time in minutes before the anti-theft mechanism is triggered if no PIN is entered.
TheftTimeOut (251):连续值,表示在未输入 PIN 的情况下触发防盗机制之前的时间(以分钟为单位)。 - TheftLowPin (252): Continuous value that denotes the low 3 digits of the PIN
TheftLowPin (252):表示 PIN 的低 3 位数字的连续值 - TheftHighPin (253): Continuous value that denotes the high 3 digits of the PIN.
TheftHighPin (253):表示 PIN 的高 3 位数字的连续值。 - TheftDeterrence (250): Non-continuous value that denotes the status of the theft deterrence mechanism. Can be TheftDisabled (0), TheftEnabledConsumer (1), or TheftEnabledEnterPrise (2).
TheftDeterrence (250):表示盗窃威慑机制状态的非连续值。可以是 TheftDisabled (0)、TheftEnabledConsumer (1) 或 TheftEnabledEnterPrise (2)。
When turning on anti-theft deterrence, the HP Display Center software takes in user input for the PIN, then sends the following write MCCS commands:
打开防盗威慑时,HP Display Center 软件会接收用户输入的 PIN,然后发送以下写入 MCCS 命令:
- TheftLowPin = LowPin: Monitor sets LowPin.
TheftLowPin = LowPin:监视器设置 LowPin。 - TheftHighPin = HighPin: Monitor sets HighPin.
TheftHighPin = HighPin:监视器设置 HighPin。 - TheftDeterrence = TheftEnabledConsumer: Monitor turns on anti-theft deterrence.
TheftDeterrence = TheftEnabledConsumer:Monitor 打开防盗威慑。
When turning off anti-theft deterrence, it sends the following write MCCS commands:
关闭防盗威慑时,它会发送以下写入 MCCS 命令:
- TheftLowPin = LowPin: Monitor checks LowPin.
TheftLowPin = LowPin:监视器检查 LowPin。 - TheftHighPin = HighPin: Monitor checks HighPin.
TheftHighPin = HighPin:监视器检查 HighPin。 - TheftDeterrence = TheftDisabled: If previous 2 steps were correctly checked, monitor turns off anti-theft deterrence.
TheftDeterrence = TheftDisabled:如果前 2 个步骤已正确选中,监视器将关闭防盗威慑。
On the firmware side, TheftDeterrence is correctly configured such that it is read-only (RO) when the monitor has not yet received correct TheftLowPin and TheftHighPin commands. Unfortunately, the TheftLowPin and TheftHighPin control command values are not set to write-only (WO) but are actually read and write (RW). This allows an attacker to actually read the values of the pin even when anti-theft deterrence has been triggered.
在固件端,TheftDeterrence 已正确配置,以便在监视器尚未收到正确的 TheftLowPin 和 TheftHighPin 命令时为只读 (RO)。遗憾的是,TheftLowPin 和 TheftHighPin 控制命令值未设置为只写 (WO),而是实际读取和写入 (RW)。这允许攻击者实际读取引脚的值,即使触发了防盗威慑。
It is important to note that HP’s implementation interprets read and write rather loosely. For example, when attempting to unlock the monitor, pin values are sent using a write command, but these values do not actually overwrite the stored PIN values. It is simply that in order to send values over MCCS, a write command must be sent.
需要注意的是,HP 的实现对读取和写入的解释相当松散。例如,当尝试解锁显示器时,使用 write 命令发送 PIN 值,但这些值实际上不会覆盖存储的 PIN 值。简单地说,为了通过 MCCS 发送值,必须发送写入命令。
MCCS Fuzzing and Exploitation
MCCS 模糊测试和利用 🔗
Of course, in order to actually send the malicious series of control commands, you still need to use the low-level APIs to communicate with the monitor. It can be quite a hassle to custom code this in C++. Fortunately, some work has already been done in Rust via the ddcset
project (https://github.com/arcnmx/ddcset-rs) to make it easy to manipulate messages sent over DDC/CI. This is a good base to developer your own custom tooling and fuzzers as well.
当然,为了真正发送恶意的一系列控制命令,您仍然需要使用底层 API 与监视器进行通信。在 C++ 中自定义代码可能会很麻烦。幸运的是,Rust 已经通过 ddcset
项目 (https://github.com/arcnmx/ddcset-rs) 完成了一些工作,以便于操作通过 DDC/CI 发送的消息。这也是开发自己的自定义工具和模糊器的良好基础。
For a simple bug like theft deterrence, this can be exploited by sending the messages directly.
对于像盗窃威慑这样的简单错误,可以通过直接发送消息来利用它。
- Using HP Display Center software, go to Advanced tab and set the PIN to
123123
and enable anti-theft deterrence.
使用 HP Display Center 软件,转到“高级”选项卡,将 PIN 设置为并123123
启用防盗威慑。 - Plug the monitor into another computer. You have 5 minutes before the anti-theft deterrence is triggered.
将显示器插入另一台计算机。在触发防盗威慑之前,您有 5 分钟的时间。 - Run
ddcset -b winapi getvcp 252
to read the TheftLowPin. It should return:
运行ddcset -b winapi getvcp 252
以读取 TheftLowPin。它应该返回:
Display on winapi:
ID: Generic PnP Monitor
Feature 0xfc = 123 / 65535
- Run
ddcset -b winapi getvcp 253
to read the TheftHighPin. It should also return the same values.
运行ddcset -b winapi getvcp 253
以读取 TheftHighPin。它还应返回相同的值。 - This demonstrates that you have successfully read the PIN from a “stolen” monitor. If anti-theft deterrence is triggered, simply enter the leaked PIN using HP Display Center.
这表明您已成功从“被盗”显示器读取 PIN。如果触发了防盗威慑,只需使用 HP Display Center 输入泄露的 PIN 码即可。
Conclusion 结论 🔗
I coordinated disclosure with HP on CVE-2023-5449. It was interesting to observe how much more difficult patching hardware, especially specialized ones like display monitors, can be.
我与 HP 协调了 CVE-2023-5449 的披露。有趣的是,观察修补硬件的难度有多大,尤其是像显示器这样的专用硬件。
This simple vulnerability only scratches the surface of more interesting bugs that can be found in proprietary MCCS VCP controls, especially if table type values are used which are likelier to trigger memory corruption issues. As VESA warns, this can lead to permanent damage of monitors.
这个简单的漏洞只是触及了专有 MCCS VCP 控件中发现的更有趣的错误的表面,尤其是在使用更有可能触发内存损坏问题的表类型值时。正如 VESA 警告的那样,这可能会导致显示器的永久性损坏。
As display monitors add more features in both hardware and software like integrated webcams, I suspect we may begin to see more serious vulnerabilities emerge in this space.
随着显示器在硬件和软件(如集成网络摄像头)中添加更多功能,我怀疑我们可能会开始看到这个领域出现更严重的漏洞。
原文始发于spaceraccoon:Hacking HP Display Monitors via Monitor Control Command Set (CVE-2023-5449)
转载请注明:Hacking HP Display Monitors via Monitor Control Command Set (CVE-2023-5449) | CTF导航