IronCTF2024 web/b64SiteViewer
My solution for IronCTF2024 web/b64SiteViewer challenge
Challenge overview
The b64SiteViewer challenge involves a Flask-based web application with two main endpoints that performed URL fetching and command execution. The goal is to bypass the security checks to ultimately retrieve a flag from the server.
Application structure
Home route allows the user to enter a URL and then tries to fetch its contents using urllib.request.urlopen()
. It checks the URL scheme and hostname against a blacklist to prevent accessing internal or dangerous resources.
Blacklisted schemes: file
, gopher
, php
, ftp
, dict
, data
Blacklisted hostnames: 127.0.0.1
, localhost
, 0.0.0.0
, ::1
, ::ffff:127.0.0.1
If the provided scheme or hostname matches the blacklist, the request is blocked. If the URL is allowed, the server fetches it and returns the content in base64 format.
Admin route only allows access from 127.0.0.1
or localhost
and provides the functionality to execute a command using the cmd parameter. If accessed successfully, the command is executed with subprocess.run()
. The command undergoes basic filtering to prevent certain specific dangerous commands or characters.
Analysis
The application code presents two main vulnerabilities:
Hostname blacklist bypass
The application checks the hostname against a specific list of restricted addresses (127.0.0.1
,localhost
, etc.). However, variations oflocalhost
, like127.1
, are not on the blacklist and still can point to the loopback address.Insecure command execution
The/admin
route allows for command execution usingsubprocess.run()
. Although basic filtering is applied, it’s not fully prevent command injection. The lack of sufficient checks enables an attacker to execute commands that are not explicitly blacklisted.
Identifying the vulnerabilities
Hostname check bypass
The blacklist restricts specific localhost addresses, but using an IP variation (127.1
) bypass the check while still resolving to localhost.
Command injection on /admin
The /admin
endpoint permitts arbitrary command execution if the IP check is bypassed. The command validation logic has a weak filtering that allows for the execution of benign commands, which eventually revealed sensitive data, including the flag.
Crafting the exploit
Bypass the localhost check
The hostname blacklist are not include all variations of localhost. By using http://127.1:5000/admin?cmd={command}
, access to the /admin
route can be achieved without triggering the blacklist.
1
2
3
4
POST / HTTP/2
Host: b64siteviewer.1nf1n1ty.team
[...]
url=http://127.1:5000/admin?cmd=set
Execute commands
After accessing the /admin
endpoint, a command like set
can be passed in the URL to test if commands could be executed. The response contains environment variables, including the flag.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
IFS='
'
LC_CTYPE='C.UTF-8'
OLDPWD='/'
OPTIND='1'
PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PPID='2'
PS1='$ '
PS2='> '
PS4='+ '
PWD='/home/user'
SHLVL='1'
WERKZEUG_SERVER_FD='3'
_='/usr/local/bin/python'
flag='ironCTF{y0u4r3r0ck1n6k33ph4ck1n6}'
Flag:ironCTF{y0u4r3r0ck1n6k33ph4ck1n6}
Conclusion
This challenge demonstrates how weak input validation and reliance on blacklists for security can be bypassed by clever variations. By exploiting the blacklist limitations on localhost variations, and insecure command handling, the flag can be successfully retrieved.
Key takeaways
- Blacklisting can be ineffective: Instead of blacklisting specific IPs or hostnames, a better approach is whitelisting only the acceptable hosts.
- Dangerous command execution: Avoid running shell commands directly based on user input, or use stricter filtering and sanitization.
- Thorough input validation: Always consider all possible variations when implementing input validation to ensure comprehensive security.