Windows使用技巧

从应用程序中提取TLS密钥

从应用程序中提取TLS密钥

希望能够检查电脑上运行的程序的流量,不太信任这些应用程序,在理想情况下,我想把几乎所有的程序都放入一个高度安全的沙箱中。

其中的一个程序是Oculus软件,我想对Oculus软件持谨慎态度的原因有几个:

  1. Oculus属于Facebook,这意味着Facebook可以决定Oculus软件如何处理用户的数据。
  2. 2.Oculus服务器在Facebook的基础设施上运行,这意味着Facebook可以访问上传到这些服务器的任何数据。
  3. 3.Oculus Headset有摄像头和软件,可以构建我的房间的3D地图,这可以上传到服务器。
  4. Oculus隐私政策明确指出,Oculus自动收集这些数据。

当您使用XR设备时,有关您所处的环境、身体运动和尺寸的信息。例如,当您设置Oculus Guardian系统在您接近边界时提醒您时,我们会收到您所定义的游戏区域的信息。

幸运的是,我可以使用Wireshark或tcpdump等程序来检查发送到服务器的流量。
幸运的是,Oculus使用的是TLS,所以第三方无法窥探到这些传输中的数据。
不幸的是,在这种情况下,我扮演的是 “第三方 “的角色。
幸运的是,可以读取进程内存并提取秘钥TLS会话主密钥+客户端随机和检查TLS数据。

不起作用的事情

  • 设置SSLKEYLOGFILE变量–Oculus Runtime使用的是1.0.2o版本的OpenSSL,不支持这个。
  • 使用自动调试器提取OpenSSL密钥 – Oculus Runtime使用静态链接的OpenSSL,没有调试符号。
  • 用一个可以记录密匙的OpenSSL库来替代 – 它是静态链接的。
  • 我不想添加额外的根证书和代理来检查机器上的所有TLS流量。

艰难地完成这项工作

因此,未来的计划是:

  • 找出一个可以获得会话秘密密钥的代码位置
  • 对程序进行修补或调试,以便我们能够检查和记录这些密钥

逆向工程

为了弄清代码的位置,有必要进行一些逆向工程。第一步是弄清楚Oculus Runtime使用的是哪个版本。在OculusAppFramework.dll中寻找字符串,有以下字符串。Stack part of OpenSSL 1.0.2o-fb10 27 Mar 2018,这意味着我有一个特定的版本,我是靠这个版本工作的。
在阅读了《Linux期刊上的OpenSSL编程介绍》之后,我推断出SSL_connect(以及后来的SSL_set_connect_state)可能是插手OpenSSL进行密钥提取的好地方。


我把Oculus Runtime加载到Ghidra中,打开了包含OpenSSL ssl_lib.c公共接口的源代码,并试图在这些地方找到共同点。有兴趣的东西是整数和字符串常量,可以作为地标。


一个特别值得注意的函数是SSL_get_version,它包含对多个字符串的引用。寻找TLSv1.2产生了几个位置,特别是这个位置:

看起来SSL_get_version被内联了。我怀疑这不是唯一进行TLS连接的地方,所以我不得不找一个不同的地方来工作。接下来值得注意的是,在其中一个SSL版本字符串附近,我注意到了代码路径和断言字符串:

事实证明,调试信息,如源文件名和断言表达式,也可以作为地标使用。现在我们有了更多的地标来导航OpenSSL的二进制代码,在检查附近对.\\ssl\ssl_lib.c字符串的引用时,继续给函数贴标签,我偶然发现了SSL_set_connect_statefunction。使用相同的代码模式,mov dword ptr [$register + 0x48], 0x5000 ,我也发现了SSL_connect 。SSL_connect有一个对SSL_set_connect_state的内联调用。我决定谨慎行事,把这两个函数都插进去。

提取数据

这些函数已经有指向ssl_st结构的指针,所以让我们从那里提取数据。
要做到这一点,有几个选择。

  • 使用/编写一个可编程的调试器,在这些函数上断点/检查值
  • 对DLL进行二进制修补
  • 使用DLL注入和修补内存中的DLL代码

由于我在用程序控制调试器方面的经验很差,所以我不想去使用第一个选项。这是一个我可能要改进的潜在事情。因为我不想让一个有签名的DLL失效,所以我没有打二进制补丁。最后一个选项是。

DLL注入

为了提取所有的TLS密钥,我们需要从执行的一开始就控制运行中的进程。做到这一点的一个方法是设置gflags,将DLL注入器程序作为进程的调试器。我们要调试的程序叫做OVRServer_x64.exe,所以让我们在注册表中创建HKLM\SOFTWARE\MicrosoftWindows NT\CurrentVersion\Image File Execution Options\OVRServer_x64.exekey,并将Debugger字符串值设置为我们的注入程序的命令行。
注入器不必做任何调试,但它需要用DEBUG_ONLY_THIS_PROCESS或DEBUG_PROCESS标志启动一个程序。否则,我们的调试器将被递归地生成
CreateRemoteThread DLL注入在Windows上本身就是一个简单的技术,它在WikiLeaks的文章以及其他文章中都有描述,
injector.exe的代码在这里。

从进程内部运行

DLL被注入后,它可以在内存中修补代码并记录秘密密钥。
injectee.dll的架构相当简单—修补代码,创建一个通道,用通道的接收端创建写手线程,用另一端发送不同线程的密钥。
补丁是在汇编中完成的。它可以被直观地解释成这样。

有几种方法可以提取给定的ssl_st结构的指针的键。

  • 实现一个C语言库
  • 手动行走指针
  • 将OpenSSL结构移植到所使用的语言中。

最初,我通过手工实现了指针的行走,但这是一种非常脆弱的方法。将OpenSSL结构移植到Rust是相当麻烦的,所以我实现了一个微型的C库来读取给定的ssl_st结构指针的密匙。


剩下的就是管道工程了,我们现在可以在运行的应用程序中检查TLS流量。

injectee.dll的代码在这里,如果你有兴趣,该项目的全部代码在这里

源文连接:https://m1el.github.io/oculus-tls-extract/

分享此文章