vSphere Development Guide 2 – vSphere Web Services API

Onedaysec
5 min read
1 views
vSphere Development Guide 2 – vSphere Web Services API — One Day Sec default thumbnail

0x00 Introduction

---

The previous article 'vSphere Development Guide 1 – vSphere Automation API' introduced methods for interacting with vCenter Server and virtual machines through the vSphere Automation API. However, some operations in the vSphere Automation API are not supported by older versions of vCenter (< vSphere 7.0U2), limiting its universality. This article will introduce a more universal implementation method – the vSphere Web Services API.

0x01 Overview

---

This article will cover the following topics:

  • Development details of the vSphere Web Services API
  • Analysis of the open-source tool SharpSphere
  • Open-source code vSphereWebServicesAPI_Manage.py

0x02 Development Details of the vSphere Web Services API

---

Reference documents:

https://code.vmware.com/apis/968

https://code.vmware.com/docs/11721/vmware-vsphere-web-services-sdk-programming-guide

References for Python implementation code:

https://github.com/vmware/pyvmomi-community-samples

To improve efficiency, we implement this based on the Python SDK pyvmomi

Specific details are as follows:

(1) Login operation

Call SmartConnect, passing in the username and plaintext password

Specific details can be viewed in the file /lib/site-packages/pyVim/connect.py after installing pyvmomi

(2) View virtual machine configuration

Query by creating a ContainerView managed object

Compared to the vSphere Automation API, the obtained content is more comprehensive

For example, vsphere-automation-sdk-python does not support obtaining the UUID corresponding to each virtual machine, but it can be obtained through pyvmomi

(3) Send files to a virtual machine

Use the method InitiateFileTransferToGuest, which requires passing in the following six parameters:

  • vm, specifying the virtual machine to operate on
  • auth, credentials for logging into the virtual machine
  • guestFilePath, the save path for the file sent to the virtual machine
  • fileAttributes, the file attributes sent to the virtual machine
  • fileSize, file size
  • overwrite, specifies whether to overwrite

Upon successful execution, returns the URI corresponding to the file

Use the PUT method to access the URI, with the data field containing the file content to be sent, which must be transmitted in binary format

The specific implementation code is as follows:

def UploadFileToVM(api_host, username, password, vm_name, guest_username, guest_user_password, local_path, guest_path):
service_instance = SmartConnect(host=api_host, user=username, pwd=password, port=443, disableSslCertValidation=True)
if not service_instance:
raise SystemExit("[!] Unable to connect to host with supplied credentials.")

creds = vim.vm.guest.NamePasswordAuthentication(username = guest_username, password = guest_user_password)

with open(local_path, 'rb') as file_obj:
data_to_send = file_obj.read()

try:

content = service_instance.RetrieveContent()
vm = get_obj(content, [vim.VirtualMachine], vm_name)
if not vm:
raise SystemExit("Unable to locate the virtual machine.")

file_attribute = vim.vm.guest.FileManager.FileAttributes()
profile_manager = content.guestOperationsManager.fileManager
res = profile_manager.InitiateFileTransferToGuest(vm, creds, guest_path, file_attribute, len(data_to_send), True)
print("[+] transfer uri: " + res)

headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0",
}
r = requests.put(res, headers = headers, data = data_to_send, verify = False)
if r.status_code ==200:
print("[+] " + r.text)
else:
print("[!]" + str(r.status_code))
print(r.text)
exit(0)

except vmodl.MethodFault as error:
print("[!] Caught vmodl fault : " + error.msg)

(4) Download files from virtual machine

Using the InitiateFileTransferFromGuest method, the following three parameters must be passed:

  • vm, specifies the virtual machine to operate on
  • auth, credentials for logging into the virtual machine
  • guestFilePath, the path of the virtual machine file to be downloaded

Upon successful execution, returns the uri corresponding to the specified file

When accessing the uri using the GET method, distinguish between text format and binary format when retrieving file content. Text format can be read using r.text, while binary format can be read using r.content

The specific implementation code is as follows:

def DownloadFileFromVM(api_host, username, password, vm_name, guest_username, guest_user_password, guest_path, type):
service_instance = SmartConnect(host=api_host, user=username, pwd=password, port=443, disableSslCertValidation=True)
if not service_instance:
raise SystemExit("[!] Unable to connect to host with supplied credentials.")

creds = vim.vm.guest.NamePasswordAuthentication(username = guest_username, password = guest_user_password)

try:

content = service_instance.RetrieveContent()
vm = get_obj(content, [vim.VirtualMachine], vm_name)
if not vm:
raise SystemExit("Unable to locate the virtual machine.")

profile_manager = content.guestOperationsManager.fileManager
res = profile_manager.InitiateFileTransferFromGuest(vm, creds, guest_path)
print("[+] transfer uri: " + res.url)
print(" size: " + str(res.size))
headers = {
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0",
}
r = requests.get(res.url, headers = headers, verify = False)
if r.status_code == 200:
if type == "text":
print("[+] result: ")
print(r.text)
else:
print("[+] save the result as temp.bin")
with open("temp.bin", "wb") as file_obj:
file_obj.write(r.content)

else:
print("[!]" + str(r.status_code))
print(r.text)
exit(0)

except vmodl.MethodFault as error:
print("[!] Caught vmodl fault : " + error.msg)

Analysis of the Open-Source Tool SharpSphere 0x03

---

https://github.com/JamesCooteUK/SharpSphere

Developed in C#, compatible with Cobalt Strike

Supports the following features:

  • Acts as a C2 server
  • Code execution
  • File upload
  • File download
  • View virtual machine configuration
  • Dump memory

The implementation process for dumping memory is as follows:

  • Obtain a virtual machine snapshot; if none exists, create a snapshot file (.vmem)
  • Download the snapshot locally via file URI creation
  • Parse the snapshot file using WinDbg and Mimikatz to extract credentials from the lsass process

Currently, operations on Linux virtual machines are not supported.

During actual use, if you encounter the following error:

Error: An error occurred while making the HTTP request to https:///. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.

You can try adding the following code to resolve it:

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

0x04 Open Source Code

---

The complete open source code has been uploaded to GitHub, with the address as follows:

https://github.com/3gstudent/Homework-of-Python/blob/master/vSphereWebServicesAPI_Manage.py

Code Applicable Version: No restrictions

Supports the following features:

  • Read virtual machine configurations
  • View virtual machine files
  • Delete virtual machine files
  • Upload files to the virtual machine
  • Download files from the virtual machine
  • Execute commands in the virtual machine

The specific commands are as follows:

  • ListVM
  • GetVMConfig
  • ListHost
  • ListVMProcess
  • CreateVMProcess
  • KillVMProcess
  • ListVMFolder
  • DeleteVMFile
  • DownloadFileFromVM
  • UploadFileToVM

For operations on virtual machines, both Windows and Linux systems are supported

0x05 Summary

---

This article introduces the method of interacting with vCenter Server and virtual machines through the vSphere Web Services API, including the open-source implementation code vSphereWebServicesAPI_Manage.py, and documents the development details.

Regarding the vSphere Web Services API, it offers greater versatility; however, due to being developed based on the SDK, the resulting tools tend to have a larger file size.

Related Questions & Answers

What Python SDK is used to implement the vSphere Web Services API examples in the article, and how do you perform a login operation?

The article uses the Python SDK `pyvmomi`, specifically calling `SmartConnect` with the vCenter host, username, and plaintext password to establish a connection. This gives access to a wider range of management objects compared to the Automation SDK. The full implementation details are in the [vSphere Development Guide 2](/news/vsphere-development-guide-2-vsphere-web-services-api) article.

What is the difference between downloading a file in text versus binary format using the `InitiateFileTransferFromGuest` method?

After `InitiateFileTransferFromGuest` returns a URI, you access it with a GET request. For text files, read the response content using `r.text`, which decodes the data as text. For binary files, use `r.content` and save it directly (e.g., as `temp.bin`) to preserve the byte stream. The choice depends on the file type being downloaded.

What technique does the SharpSphere tool use to dump credentials from a vCenter virtual machine?

SharpSphere obtains a virtual machine snapshot (or creates one if needed) to acquire the `.vmem` memory file. It then downloads the snapshot via a file URI and parses the memory dump using WinDbg and Mimikatz to extract credentials from the `lsass` process. Note that SharpSphere currently does not support Linux virtual machines.

How do you upload a file to a virtual machine using the vSphere Web Services API and pyvmomi?

You call the `InitiateFileTransferToGuest` method with parameters including the VM object, guest credentials, destination path, file attributes, file size, and an overwrite flag. The method returns a URI that you access via a PUT request with the file content in binary format to complete the upload. This is demonstrated in the open-source code [vSphereWebServicesAPI_Manage.py](/news/vsphere-development-guide-2-vsphere-web-services-api).

Why would you choose the vSphere Web Services API over the vSphere Automation API for interacting with vCenter Server?

The [vSphere Web Services API](/news/vsphere-development-guide-2-vsphere-web-services-api) offers greater universality because it supports older versions of vCenter (before vSphere 7.0U2) where the Automation API may not be fully supported. It also provides more comprehensive data, such as the ability to retrieve the UUID of each virtual machine, which the Automation SDK does not expose.

Continue Reading