如何将YubiKey武器化:从认证设备到键盘注入工具

本文详细介绍了如何将YubiKey重新编程为类似USB Rubber Ducky的键盘注入设备,包括扫描码识别、payload构建以及突破信息亭限制外壳的实际应用案例。

如何将YubiKey武器化

Michael Allen //

几年前,我的一枚YubiKey受到安全漏洞影响,Yubico免费给我寄了一枚全新的YubiKey。由于收到新钥匙后不再使用旧的进行认证,我决定尝试能否将其改造成类似USB Rubber Ducky的设备——一种模拟键盘的USB设备,插入后会向计算机发送一系列预编程的按键。

结果我成功了。尽管标准版YubiKey并非理想的USB丢弃攻击工具,但它便于日常携带,通常比U盘更不显眼,并多次在我手头没有其他工具时,临时用于突破信息亭的限制外壳。

本文将介绍我如何识别美式键盘布局下标准YubiKey可生成的所有按键,并利用这些按键构建payload。

第一步:下载YubiKey个性化工具

YubiKey在其网站上提供了一个名为YubiKey个性化工具(YPT)的程序,可用于在Linux、Windows或Mac上自定义YubiKey的不同功能。本文使用Linux版本,但Windows和Mac版本操作类似。

下载YubiKey个性化工具

第二步:用静态密码编程YubiKey

默认配置下,YubiKey每次使用时都会输入一个唯一的认证令牌,且每次都会变化。但YubiKey也可以编程为输入用户定义的静态密码。由于YubiKey像普通键盘一样向计算机输入数据,我想知道除了标准字母、数字和符号外,它是否能按下更有趣的键,如CTRL、ALT或Windows键。为了测试,我启动了YPT,从顶部栏选择了“静态密码”选项。然后在静态密码页面上,点击了标有“扫描码”的按钮。

为了解工作原理,我先用非常简单的静态密码“abcdef”编程YubiKey。在静态密码窗口中选择了以下选项:

  • 配置槽:配置槽1
  • 键盘:美式键盘
  • 密码:abcdef

我注意到在密码字段输入时,右侧的扫描码字段开始显示十六进制值。我记下了这一点,并决定在用静态密码编程YubiKey后,下一步是识别每个要输入按键的十六进制值。这样或许能编程无法在密码字段输入的按键,如CTRL和ALT。

以下截图显示了我上述所有设置及输入密码生成的扫描码:

接着,点击“写入配置”将静态密码写入YubiKey。首次操作时,弹出一个对话框要求确认是否覆盖YubiKey上槽1的当前配置。我勾选了“不再显示此消息”,点击“是”将更改写入设备。

警告:如果您用自己的YubiKey跟随操作,请确保它不是当前用于认证的钥匙。将新配置写入YubiKey会擦除所选配置槽中的设置,您必须重新编程YubiKey并在使用的服务中重新注册才能再次用于多因素认证。如果YubiKey上仅使用一个配置槽进行认证,或许可以安全覆盖另一个槽。但如果不确定,最好先从所有服务中注销YubiKey,或使用不同的YubiKey。

写入更改后,我打开文本编辑器,按下YubiKey上的硬件按钮。YubiKey按预期在屏幕上输入了密码“abcdef”。

第三步:识别YubiKey的十六进制键码

确认可以让YubiKey输入一系列预定义按键后,下一步是弄清能否通过在YPT中指定十六进制“扫描码”让其按下更有趣的键。为了将扫描码映射到对应的按键,我从非常低技术的方法开始:在YPT的密码字段中输入字母“a”到“z”,并观察扫描码字段中的结果。这导致十六进制值04到1D出现在扫描码字段中。

我对键盘上所有其他可打印键以及每个键的大写版本重复了此过程。我记下了收集的所有十六进制值以及尚未匹配到键盘上按键的值范围。将能够解码的所有字符组织成表格后,我注意到了一个模式:扫描码似乎从中间分开,小写字符全部位于00-7F之间,而大写或“键+Shift”版本位于80-FF之间的相同位置。下表更清晰地展示了这一点。

扫描码 键+Shift 扫描码
a 04 A 84
b 05 B 85

现在剩下的就是识别每个未知范围中十六进制值生成的按键。由于在YPT的扫描码字段中输入十六进制值不会显示任何输出,且我预计未知范围中的许多按键不会生成任何可打印输出(例如CTRL键),我需要一种方法来捕获YubiKey生成的原始按键。为此,我决定使用Linux工具xinput和我的xinput-keylog-decoder脚本来解码输出。

如果您不熟悉xinput,它是一个命令行工具,通常包含在许多Linux发行版的图形桌面环境中。它也常在系统受损时被滥用为键盘记录器,我创建xinput-keylog-decoder工具正是为此目的。

由于YubiKey本质上是一个键盘,我开始捕获其按键的第一件事是识别其在xinput中的ID号。我通过运行不带参数的xinput命令检查了这一点,并确定其ID为16,如下输出所示:

1
2
3
4
5
6
7
$ xinput
⎡ Virtual core pointer                    	id=2	[master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer              	id=4	[slave  pointer  (2)]
⎜   ↳ Yubico Yubikey NEO OTP+U2F+CCID        	id=16	[slave  pointer  (2)]
⎣ Virtual core keyboard                   	id=3	[master keyboard (2)]
    ↳ Virtual core XTEST keyboard             	id=5	[slave  keyboard (3)]
    ↳ Yubico Yubikey NEO OTP+U2F+CCID        	id=16	[slave  keyboard (3)]

默认情况下,xinput-keylog-decoder附带的示例脚本记录系统上所有键盘的输入,但知道YubiKey的ID让我在解析输出时能够针对该设备。

接下来,我打开三个终端窗口,运行命令来记录和分析YubiKey生成的按键。以下截图后解释了每个命令的目的:

  • 顶部终端:停止任何当前运行的xinput进程,启动新的xinput进程,并开始无限循环读取键盘输入。这是我在YubiKey向系统输入按键时保持选中的终端窗口,这样它输入的任何内容不会干扰其他终端窗口。

    1
    
    ./stop-logging.sh >0; rm *txt; ./start-logging.sh; while true; do read; sleep 0.1; done
    
  • 中间终端:每秒钟在屏幕上显示test-output.16.txt的原始输出。test-output.16.txt是自动保存键盘ID 16按键的文件。显示xinput输出的原始键码让我在xinput-keylog-decoder.py未能解码第三个终端窗口中的按键时获得更多信息。

    1
    
    watch -n 1 tail test-output.16.txt
    
  • 底部终端:每秒钟解码键日志文件并将其显示为人类可读文本。

    1
    
    watch -n 1 ./xinput-keylog-decoder.py test-output.16.txt
    

最后,在将十六进制扫描码编程到YubiKey中时,我首先在两个已知字符之间输入它们——通常是“a”(扫描码04)和“b”(扫描码05)。这样我可以确认目标按键前后确实按下了键,并能够识别按键是否对这些其他键产生了任何影响。以下是以扫描码“2A”为目标的过程示例。

在第一张截图中,您可以看到未识别的扫描码“2A”夹在“a”和“b”的扫描码之间。您可能还会注意到密码字段中“a”和“b”之间的明显空白。

在下一张截图中,我选择了顶部终端并按下了YubiKey上的按钮。乍一看,似乎只按下了“b”键而省略了“a”。然而,检查中间窗口后,您可以看到三个键依次按下和释放。在第三个窗口中,中间窗口的键码被解码为人类可读格式,很明显按下的键是“a”、退格键和“b”。这解释了为什么“a”没有出现在第一个窗口中,并将目标扫描码“2A”识别为退格键。

以这种方式识别键后,接下来我所做的只是按CTRL+C停止顶部窗口中的运行循环,再次运行命令(清除日志并重新启动记录器),然后重复上述过程。对每个未识别的十六进制值重复这些步骤后,我确认了每个可能扫描码生成的按键,并将它们收集在下表中。

扫描码
2A 退格

在解码扫描码时,我还观察到YubiKey在某些按键序列末尾会自动按下Enter键。在某些情况下,我能够通过以扫描码“00”终止序列来防止这种行为,但这并不总是有效。为了演示,以下是YubiKey配置为输入字母“a”到“z”的截图,以及按下YubiKey按钮后的输出截图。请注意,“z”键(扫描码“1D”)是编程到YubiKey中的最后一个键,但YubiKey仍在字符串末尾按下了Enter键。这与之前示例中解码退格键代码时观察到的行为不同,那时没有按下Enter键。

按键序列的长度和YubiKey的输出速度(可在YPT的设置屏幕中配置)似乎都会影响这种行为。在我的测试中,额外Enter键没有出现在少于23个键且以标准输出字符速率输入的序列中。然而,将字符速率减慢60毫秒会导致自动按下Enter键的序列短至一次按键。如果您不希望YubiKey在末尾自动按下Enter,在创建payload时请注意这一点。

第四步:创建有用的payload

将所有扫描码与它们按下的键匹配后,我准备好开始构建payload。不幸的是,我测试的扫描码都没有按下我希望能找到的CTRL、ALT或Windows键;因此,虽然它可以用于输入长的一行命令,但它并不理想作为完全自动化的命令注入工具或像Rubber Ducky或Teensy那样的USB丢弃攻击工具。

尽管YubiKey不会按下CTRL、ALT或Windows键,它仍然可以访问其他几个可能有趣的键,包括:

  • Shift(通过使用“Shift + 无效果”扫描码之一)
  • 功能键(F1-F12)
  • 菜单键(相当于鼠标右键单击)
  • Escape
  • Shift键与所有已识别键的组合

尽管这些键可能不是向目标系统注入可执行payload的首选,但一种它们极其有用的场景是尝试突破计算机信息亭的限制外壳。

由于完全保护信息亭软件的困难,信息亭制造商通常从键盘上物理移除键,从指向设备上移除右键单击按钮,或完全移除这两个设备而支持触摸屏。但信息亭上的USB端口通常仍然暴露,以便技术人员连接自己的键盘进行故障排除。在这种情况下,武装有自己的键盘(或这里的YubiKey)的攻击者只需将键盘插入信息亭,并使用多种众所周知的方法之一突破限制外壳并控制计算机。

从信息亭的限制外壳中逃脱的第一步通常是打开一个新的应用程序窗口——无论是对话框、新浏览器窗口还是其他任何东西。这通常是键盘最有帮助的一步,因为攻击的其余部分通常可以用最少的指向设备输入完成。下表描述了YubiKey可以注入以尝试执行第一步的按键。

按键 对计算机信息亭的影响
Escape 退出当前窗口
按Shift五次 打开Windows的粘滞键对话框
F1 在许多应用程序和操作系统中打开帮助对话框
F6 选择Web浏览器地址栏
F10, Down Arrow 在许多应用程序中打开应用程序菜单
F10, Down Arrow, “n” 在Chrome、Firefox和Windows资源管理器中打开新窗口
F10, Down Arrow, “p” 在许多应用程序中打开打印对话框
F11 退出全屏模式。可能显示Web浏览器的地址栏
F12, Esc 打开Web开发工具并选择JavaScript控制台
Shift + F10 鼠标右键单击。打开快捷菜单
Shift + Menu Shift + 右键单击。在Windows资源管理器中打开带有运行命令提示符或PowerShell扩展选项的快捷菜单
其他功能键(F1-F12) 在许多应用程序中的额外功能。某些信息亭软件中的隐藏功能/菜单
Print Screen 在某些系统上打开截图对话框

考虑到这些功能,我创建了以下三个payload,将我的YubiKey用作信息亭突破设备。

YubiKey Payloads

Payload 1 – 简单功能键和粘滞键测试

  • 扫描码:522c3a3b3c3d3e3f404142434445e6e6e6e6e6e652
  • 输出字符速率:标准
  • 执行的按键:
    • 激活粘滞键对话框中的超链接(如果存在):上箭头,空格键
    • 按下每个功能键:F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12
    • 通过按Shift五次打开粘滞键对话框,为安全起见加一次:Shift, Shift, Shift, Shift, Shift, Shift
    • 选择粘滞键对话框中的超链接,并尝试阻止Enter键关闭窗口(如果按下):上箭头

Payload 2 – 浏览器热键和粘滞键

  • 扫描码:3f2a06b3a83f4dca06b3283c443e3b3d40ab2c29e5115128454142435113113ae6e6e6e6e652
  • 输出字符速率:减慢60毫秒
  • 执行的按键:
    • 在新浏览器窗口中打开“c:”:F6, Backspace, 输入“c:”, Shift+Enter
    • 在Chrome中打开“c:”:F6, End, Shift+Home, “c:”, Enter
    • 按下功能键:F3, F11, F5, F2, F4
    • 尝试F7并在对话框出现时关闭:F7, Shift+Tab, Space, Esc
    • 打开新浏览器窗口:Shift+Menu, n, Down, Enter
    • 尝试F12/Web开发控制台:F12
    • 尝试F8和F9:F8, F9
    • 打开打印对话框或新浏览器:F10, Down, p, n
    • 尝试F1/帮助:F1
    • 打开粘滞键对话框:Shift, Shift, Shift, Shift, Shift
    • 阻止Enter键关闭粘滞键对话框:Up

Payload 3 – Shift+右键单击

  • 扫描码:e5
  • 输出字符速率:标准
  • 执行的按键:Shift+菜单键

第一个payload非常简单:它按下上箭头、空格键、每个功能键(F1-F12),然后按Shift键六次,再次按上箭头。此payload的目的是测试每个功能键,看是否提供访问信息亭上额外功能的方式,然后重复按Shift键打开粘滞键对话框。一旦粘滞键对话框打开,可以第二次按下YubiKey上的按钮,上箭头和空格键按键将打开对话框中的超链接,导航到Windows的轻松访问设置。这是我为YubiKey创建的第一个payload,在现场多次成功突破多个平台上的限制外壳。

第二个payload尝试通过调整功能键的使用以反映它们在常见Web浏览器中的功能来改进第一个payload。例如,按F7后立即尝试F8没有意义,因为在大多数浏览器中按F7会导致提示出现,有效阻止在浏览器上下文中按下F8。与第一个payload一样,仍然按下每个功能键以及粘滞键序列。包含额外键以尝试自动选择菜单选项并提供浏览器交叉兼容性。此payload是我在撰写本文时组装的新payload,因此尚未在现场使用。在实验室环境中到目前为止效果良好——尤其是在多次运行时。

最后,第三个payload仅按下Shift加菜单键。这实际上与按住Shift键并用鼠标右键单击相同。它让我能够向信息亭添加右键鼠标按钮,以便在获得初始立足点后右键单击不同事物。如果可以在资源管理器窗口内右键单击,它还提供快速快捷方式到PowerShell或命令提示符。我通常将此payload保留在YubiKey的槽2中,其他payload之一在槽1中。

结论

尽管YubiKey是出色的双因素认证设备,但它肯定缺少一些使其成为理想USB HID攻击工具的功能,并且已有其他产品更好地完成这项工作。YubiKey作为攻击工具的主要优势可能是它看起来像YubiKey。在不允许U盘的高安全环境中,或许可以走私YubiKey;在近距离社会工程场景中,说服员工打开公共互联网信息亭的机柜以便“认证”到您的电子邮件账户可能比插入某些无法识别的设备更容易。

在我看来,这是实验YubiKey的主要收获。只需一点努力和相对较少的技术知识,甚至可信的电子设备也可以变成攻击工具。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计