๐ Art Contest
A detailed write-up of the Web challenge 'Art Contest' from WolvCTF - 2025
๐ Challenge Overview
Category Details Additional Info ๐ Event WolvCTF - 2025 Event Link ๐ฐ Category Web ๐ ๐ Points 498 Out of 500 total โญ Difficulty ๐ข Easy Personal Rating: 2/10 ๐ค Author dree Profile ๐ฎ Solves (At the time of flag submission) 9 solve rate ๐ Date 22-03-2025 WolvCTF - 2025 ๐ฆพ Solved By mH4ck3r0n3 Team: QnQSec
๐ Challenge Information
Art Contest Submit your best ascii art to win! https://art-contest-974780027560.us-east5.run.app
๐ฏ Challenge Files & Infrastructure
Provided Files
Files:
๐ Initial Analysis
First Steps
Initially, the website appears as follows:
Doing a couple of upload tests, I realized it was a
PHP
web application that only allows.txt
files to be uploaded, so some filter is applied on the extension. Since I didnโt find anything else interesting on the page, I started analyzing the attached files. I noticed there was also aC
file, namelyget_flag.c
, which performs afopen
on the fileflag.txt
and reads its content. So I thought, “this file will surely be useful for something.” After that, I analyzed theDockerfile
to see the operations performed withget_flag.c
, and I found this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# Create the uploads directory and make it unreadable but writable RUN mkdir -p /var/www/html/uploads && \ chown root:www-data /var/www/html/uploads && \ chmod 730 /var/www/html/uploads # Make /var/www/html/ only readable RUN chown root:www-data /var/www/html/ && \ chmod 750 /var/www/html/ # Copy flag.txt over COPY flag.txt /var/www/html/flag.txt RUN chown root:root /var/www/html/flag.txt && \ chmod 400 /var/www/html/flag.txt # Copy get_flag over and compile COPY get_flag.c /var/www/html/get_flag.c RUN gcc /var/www/html/get_flag.c -o /var/www/html/get_flag && \ chown root:www-data /var/www/html/get_flag && \ chmod 4755 /var/www/html/get_flag && \ rm /var/www/html/get_flag.c
From this, it is already clear that the uploaded files will be placed in the
uploads
folder. Then it makes/var/www/html/
only readable and sets the permissions on theflag.txt
file so that the owner isroot
. After that, it compilesget_flag.c
and sets the permissions withroot
as the owner and the group aswww-data
. Then it executeschmod 4755
, which sets4 -> Setuid
(making the file run with the ownerโs permissions),7 -> The owner has full permissions
,5 -> the group has read and execute permissions
,5 -> others have read and execute permissions
. So even though we arewww-data
, we can read the flag by executing theget_flag
file, as it will run withroot
permissions and will be able to open theflag.txt
file since the owner isroot
. Most likely, we will need to find a way to bypass the filter by obtaining a web shell and then executing theget_flag
file to get the flag. Next, I started analyzing theindex.php
file, where I found the full path in which the uploaded files are placed, and another interesting thing I had already seen previously in the challenge Submission which made me think it implied some sort ofBash Glob Injection
:
1 2 3 4
$target_file = basename($_FILES["fileToUpload"]["name"]); $session_id = session_id(); $target_dir = "/var/www/html/uploads/$session_id/"; $target_file_path = $target_dir . $target_file;
As we can see, the upload path is built as
/uploads/session_id/filename
. So we will need to use thePHPSESSID
cookie to access the uploaded file:
1 2 3 4 5
$old_path = getcwd(); chdir($target_dir); // make unreadable - the proper way shell_exec('chmod -- 000 *'); chdir($old_path);
This is the part of the code also present in the
Submission
challenge, which made me think of aBash Glob Injection
. From that challenge, I learned that any filename starting with.
bypasses thechmod 000 *
that sets all permissions to none on the file. Therefore, accessing the route/uploads/session_id/filename
will only result inForbidden
. So, to bypass this, we can simply upload a file like.foo.txt
and access/uploads/session_id/foo.txt
to read it. However, to executeget_flag
, we need anRCE
which we can only get by uploading a file with a.php
extension. So I tried the usual techniques (HackTricks) for extension bypass, but I didn’t get anywhere. Moving on to the next phase with all the information gathered.
๐ฌ Vulnerability Analysis
Potential Vulnerabilities
- Unrestricted File Upload
- RCE (Remote Code Execution)
๐ฏ Solution Path
Exploitation Steps
Initial setup
I tried all the bypass methods for uploading a
.php
file, but nothing worked. So I took another look at the code, focusing on the part where the extension is checked:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
$lastDotPosition = strrpos($target_file, '.'); // If the file contains no dot, evaluate just the filename if ($lastDotPosition == false) { $filename = substr($target_file, 0, $lastDotPosition); $extension = ''; } else { $filename = substr($target_file, 0, $lastDotPosition); $extension = substr($target_file, $lastDotPosition + 1); } // Ensure that the extension is a txt file if ($extension !== '' && $extension !== 'txt') { echo "Sorry, only .txt extensions are allowed.\n"; $uploadOk = 0; }
I noticed that in the
if
statement, when$lastDotPosition == false
, the extension is assigned to''
, so it will bypass the next check. I thought, “How can I get that specific condition?” If I were to send a file like1.txt
:As we can see,
$lastDotPosition = 1
, but I need it to be equal to0
since0 == false
:It evaluates to
True
. The only way to achieve this is if the dot is at position0
, so by sending afilename=.php
, we can bypass both the extension check and thechmod
because the filename starts with a.
. Let’s move on to the exploitation.
Exploitation
The first thing I did was write a PHP web shell taken from (revshell), specifically
php cmd
, and I saved it as.php
. I uploaded it and extracted thePHPSESSID
to reconstruct the upload path:As we can see, the upload was successful, so I reconstructed the path (https://art-contest-974780027560.us-east5.run.app/uploads/7c2fa3bdc5c51f329206c594cf9a809c/.php) and visited the page:
I obtained my web shell. By sending
cd ../../;./get_flag
, I obtained the flag. I encountered problems since it seems executing executables that are two directories up (../../get_flag
) doesn’t work.
Flag capture
๐ ๏ธ Exploitation Process
Approach
The automatic exploit performs a POST request to upload the PHP web shell with
filname=.php
as seen previously. Then, it extracts the session ID and uses it to construct the upload path for the files. Next, it sends a request to the uploaded web shell with the parametercmd=cd ../../;./get_flag
to execute theget_flag
file and print the flag. Finally, it extracts the flag from the response using a regex.
๐ฉ Flag Capture
Flagwctf{m1ss3d_m3_chm0d_:3}
Proof of Execution
๐ง Tools Used
Tool Purpose Python Exploit
๐ก Key Learnings
Skills Improved
- Binary Exploitation
- Reverse Engineering
- Web Exploitation
- Cryptography
- Forensics
- OSINT
- Miscellaneous
๐ References & Resources
Similar Challenges
Learning Resources
๐ Final Statistics
Metric | Value | Notes |
---|---|---|
Time to Solve | 00:15 | From start to flag |
Global Ranking (At the time of flag submission) | 16/325 | Challenge ranking |
Points Earned | 498 | Team contribution |
Created: 22-03-2025 โข Last Modified: 22-03-2025 Author: mH4ck3r0n3 โข Team: QnQSec