Virtual Machine (VM) detection is nothing new. Malware has been doing it for over a decade now. Over time the techniques have advanced as defenders learned new ways of avoiding VM detection.
A while back a friend and I were working on a project related to exploit delivery via a web application for redteaming purposes. I wanted a way to fingerprint visitors of the site and hash the fingerprint data so I could look for potential repeat visitors. While investigating fingerprinting I stumbled upon something pretty interesting. I was looking at some code that collected information about WebGL capabilities. I quickly realized that some of the fingerprinting information could be useful for VM detection because vendor names were exposed. In this particular instance the string "VMWare" was contained within the WebGL information. After some more testing I also discovered that VirtualBox reported the same kind of information.
Once I realized it was potentially possible to detect VMs from the browser I started to dig deeper and began searching for other research related to this discovery. I found a pretty well researched academic paper  related to tracking users across multiple browsers. This gave me some other potential techniques that could be applied to VM detection.
The end goal of this research is to have multiple techniques for VM detection. Multiple techniques lead to much more accurate detection. Since some techniques are more false-positive prone than others, a weighting system can be applied to the detection capabilities. This allows us to generate detection confidence scoring. This can help account for inaccuracies of certain detection methods. Given enough testing and data it would then be possible to come up with a reasonable threshold value. If a browser scores above the threshold then it would most likely be within a VM. Alternatively, if the browser scored below the threshold value it could be considered to be running on physical hardware.
Now that I have covered some of the background information and history leading up to this blog post we can start to dig into the actual techniques.
As mentioned prior in the introduction, WebGL can provide a lot of information about the OpenGL implementation including vendor information. The WEBGL_debug_renderer_info extension  can be used to query for debug information such as the WebGL vendor and rendered.
var canvas = document.createElement('canvas'); var gl = canvas.getContext('webgl'); var debugInfo = gl.getExtension('WEBGL_debug_renderer_info'); var vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL); var renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL); console.log(vendor); console.log(renderer);
Additionally, extension availability can be queried using the getExtension method on a WebGL context. I have not fully explored this avenue but it might be possible to detect certain WebGL implementations provided by VMs based on the extensions available. Though this idea is likely very false-positive prone.
Below is a screenshot from  WebGLReport a website dedicated to fingerprinting WebGL.
VirtualBox Windows 10 x64 VM Google Chrome Visiting webglreport.com
Now, it is important to note that this depends on how the VM is configured. In Virtual Box for example, setting the graphics controller setting under Display to VMSVGA will report cause WebGL to use CPU based implementations of OpenGL which is browser dependent. However, this could still be a useful indicator that the client machine is running in a VM because most modern hardware has integrated GPUs and can provide access to OpenGL natively. Just keep in mind that CPU based OpenGL implementations do not necessarily mean it is a VM outright.
VirtualBox Windows 10 x64 VM Google Chrome Using VMSVGA Visiting webglreport.com
This screenshot depicts Google Chrome utilizing the CPU based OpenGL implementation renderer Google SwiftShader .
var width = screen.width; var height = screen.height; var color_depth = screen.colorDepth; var bitspp = screen.pixelDepth;
More details on the screen object can be found at .
var ram = navigator.deviceMemory;
VirtualBox Windows 10 x64 VM Google Chrome 2 CPU Cores Tested with Core Estimator
It is interesting to see that academics and various other researchers have applied some of the same concepts toward fingerprinting and privacy issues.
(Cross-)Browser Fingerprinting via OS and Hardware Level Features http://yinzhicao.org/TrackingFree/crossbrowsertracking_NDSS17.pdf
MDN web-docs WEBGL_debug_renderer_info https://developer.mozilla.org/en-US/docs/Web/API/WEBGL_debug_renderer_info
WebGL Report https://webglreport.com
Google Swiftshader Github https://github.com/google/swiftshader
W3 Device Memory Specification https://www.w3.org/TR/device-memory/
W3 Schools - The Screen Object https://www.w3schools.com/jsref/obj_screen.asp
Core Estimator Demo https://oswg.oftn.org/projects/core-estimator/demo/
Core Estimator Github https://github.com/oftn-oswg/core-estimator