Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Wednesday, August 16, 2017

Java Deserialization HOWTO

 

How to Exploit Java Deserialization Flaws


Intro

After reading NickstaDB excellent article on Attacking Java Deserialization I was inspired to really learn about this attack technique. Be sure to read the article first to understand Java Deserialization.  I had read about it briefly before this article and really wanted to dive in. I decided to write this post to explain the steps to execute the attack. The article does an awesome job of explaining everything, so I won't rehash any of that material. Instead, I wanted to write a guide to step through the actual exploit. I have many years of Java experience and the OSCE certification, but I have to admit there was some learning curve to these techniques since there is some different terminology to understand. I will save you a few hours of your life and step you through the process. Spoiler Alert - I explain how to exploit his DeserLab vulnerable server.

 

Requirements

DeserLab vulnerable application (README link to pre-built JAR):
https://github.com/NickstaDB/DeserLab

ysoserial for generating deserialized payloads
https://github.com/frohoff/ysoserial/
or download the pre-built JAR

Wireshark to capture the network traffic
https://www.wireshark.org/#download

HxD Hexedit (or use your favorite)
https://mh-nexus.de/downloads/HxDen.zip

NikstaDB SerialBrute Python
https://github.com/NickstaDB/SerialBrute/

Netcat (nc) for Windows or Linux 

 

Long (difficult) Method

After going through the extended path of exploiting this I found his also excellent python script SerialBrute.py that automated some of the tasks. I'm going to explain the more detailed and manual method first, since it will give you a better understanding of how to exploit this flaw on your next pentest.  Before exploiting the vulnerable server, I decided to develop a POC of re-playing a captured communication between the server and client to verify that could be done successfully which would then be leverage to substitute the exploit payload.

The server binds to an IP address on an port with the following command:
java -jar DeserLab.jar -server 192.168.1.5 1234

The client will connect to the server and prompt for a few questions to then send data to the server:
java -jar DeserLab.jar -client 192.168.1.5 1234

1. The first step was to fire up the server
2. Then Wireshark was started and set to monitor port 1234 traffic
3. The client was then run to completion to get a fun capture of the traffic
4. After the communication, right-click and choose Follow > TCP Stream














5. In the drop down list pick only the client side of the traffic, pick save data as "Raw" and Save as... the file to 'comms.bin'.

















6. Using netcat (nc -nv 192.168.1.5 1234 < comms.bin) we send the comms.bin capture file to the server and it responds like normal verifying the replay works:










Let's Exploit !!!

1. Follow the same rules as the POC, but this time only send the first variable (not the hash):










2. Stop capturing with Wireshark because we only want to get the Hello and first string communications. After this we append the exploit data to send to the vulnerable part of the application.
3. In Wireshark, Follow > TCP Stream and save the client side of the communication in raw format to 'hello.bin'.
4. Generate attack payload:   java -jar ysoserial.jar Groovy1 calc.exe >calc.exploit

The DeserLab application includes Groovy in the classpath, so that was the chosen payload here and we are spawing calculator. At this point we have the preamble/hello conversation and the attack so we are going to merge them into a single file to send in the same way as the POC excercise.

5. Open 'hello.bin' in HxD. It should look like this (Notice the 0xAC, 0xED, 0x00, 0x55 as described in the article):







6. Copy into the clipboard all the characters after this from 0x77 to 0x74:







7. Open 'calc.exploit' in HxD (notice the same 0xAC 0xED 0x00 0x05 characters?)
8. Put the cursor between the 4th (05) and 5th(73) characters, then right-click and chose 'Paste insert' and answer yes to the question about increasing the size of the file.
9. The pasted hex characters from 'hello.bin' should now be added after the magic number sequence and in front  of the exploit payload and look like this (pasted characters highlighted in red):







10. Save this file as 'payload.bin' and repeat the steps using netcat to send this payload to the server
11. If everything was done correctly, calculator should pop!


Slightly Shorter (easier) Method

1. Go back to Wireshark and open the communications...the one from the exploit above that captured preample, hello and sending the first variable (not the full communication from the POC).
2. Follow > TCP stream. Leave the whole conversation and pick 'Raw' from the drop down so your screen should look like this:


The client communication is in blue and the server is in red. You will use this hex communication to create a TCP replay file for the SerialBrute.py python script.

3. Following the instructions in the SerialBrute.py script create a text file with the input that mimics the communication in Wireshark:

aced0005
RECV
7704
f000baaa
RECV
7702
0101
7706
000474657374
RECV
PAYLOADNOHEADER


The TCP replay file mimics the communications between the client and the server and the script then handles the heavy lifting. For example, our TCP replay script:
client receives data, sends 0x77 0x44, then sends 0xff 0x00 0xba 0xaa, receives data, etc.

4. Save this text to a file 'communication.txt'
5. Lauch the attack:
python SerialBrute.py -p communication.txt -c calc.exe -t 192.168.1.5:1234 -g Groovy1

6. The result should be the same:



Thursday, October 18, 2012

Using Java to Convert MS Office to PDF with OpenOffice

Introduction

I'm working on a project to convert MS Office documents, slide, spreadsheets, etc. into PDF.  The project actually involves reading email in .eml format, extracting the attachment and then converting the file to PDF, but I will skip that portion, since it is somewhat trivial with JavaMail - javax.mail (if there are enough requests i could show it in a later post).
I first tried all the usual paths with some success and some frustration:
  • Apache POI
  • Apache FOP / XSL-FO
  • iText
  • Docx4j
Each solution seemed to have some different limitations such as:
  • Can only convert the newer OpenXML formats of docx, pptx, etc.
  • Cannot read older binary format of .doc, etc.
  • No direct path from PowerPoint to PDF (pptx > svg > pdf)
  • Or just plain annoying to code
I started reading about OpenOffice running as a service and using the JODConverter library to interface from Java to OpenOffice. I was able to mock up a prototype relatively quickly (couple hours), which was very exciting.  Then I wanted a webpage with a decent interface, so people could actually use it.  Its been a long time since I looked at writing a Servlet, so I had to re-learn and put it all together.

Requirements

If you want to do everything I did, then you are going to need everything on the list.  If you want to just pick different pieces for your needs then feel free.  You may be able to get different versions of software to work, but this is what I used
  • Apache Tomcat Server 6 (6.0.24-45)
  • OpenJDK 1.6 (1.6.0_24 / IcedTea6 1.11.4)
  • JODConverter 2.2.2
  • OpenOffice (LibreOffice 3.4.5.2-16.1)
  • Apache Commons FileUpload / Commons IO (for handling file uploads)
Very Important
OpenOffice needs to be installed on the local machine and running as a service listening for connections.  It is similar on Windows and Unix, but we were using Unix for the prototype.  In a separate window, you can start OpenOffice listening on the localhost IP address and port 8100 with the following command:

soffice --headless --accept="socket,host=127.0.0.1,port=8100;urp;" --nofirststartwizard

The Code

Quick disclaimer...this code was just for a prototype and all of the necessary error checking has not been done. This was written just to get the basic functionality working.

Outline

package mypackage;
 
import java.io.*
import java.util.List;
 

import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.servlet.*;
import org.apache.commons.fileupload.disk.*;

import org.apache.commons.io.FilenameUtils;

import javax.servlet.*;
import javax.servlet.http.*;
 
import com.artofsolving.jodconverter.*;
import com.artofsolving.jodconverter.openoffice.connection.*;
import com.artofsolving.jodconverter.openoffice.converter.*;


 public class PDFConverter extends HttpServlet {
 
    public PDFConverter() {
     //required for servlet, not used
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws 

       ServletException, IOException

    //required for servlet, we will use to do the actual file upload process and converting
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws  
        ServletException, IOException 

    //our code to send the converted file back to the user
    protected void streamFile(File outFile, HttpServletResponse response)
  
    //our code to save the uploaded file to a place we can use and with correct extension
    protected File saveFile(InputStream input, String inFilename) throws IOException

    //our code that connect to openoffice and does the conversion
    protected boolean PDFConvert(File inFile, File outFile)

    //our code to create a temp file and return file handle
    protected File createTempFile(String inFilename)
  
    //another version where the extension is given since we have to change to pdf
    protected File createTempFile(String inFilename, String tmpFileExt)

    //our code to get the file extension based on the string
    protected String getFileExt(String fileName)
 
}

Upload HTML page

Just a simple HTML page that allows the user to browse for a file and upload it.  You can create any page you want, but this is the minimum to create an interface for the user and tie the convert button to the servlet running at "/upload/PDFConverter".  Depending how you deploy to your Application Server (such as tomcat) this location may be different.
 
<html>
  <head><title>PDF Converter</title></head>
  <body>
    <form action="/upload/PDFConverter" method="post" enctype="multipart/form-data">
     Select file to convert:
    <input type="file" name="file" />
    <br/>
    <input type="submit" value="Convert to PDF"/>
    </form>
  </body>

</html>

doPost()

This is where it finally gets interesting.  The user uploads a file using the web page and it is processed by this routine in the servlet.  The doPost() function performs the following:
  1. Saves the upload and assigns it to the variable: tempInFile
  2. Creates a temp output file for the PDF: tempOutFile
  3. Converts to PDF with function PDFConvert() - the PDF file is now in tempOutFile
  4. Returns headers for PDF Content-Type and the filename
  5. Reads the PDF file from the disk and streams if with streamFile()

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException  {
        
        try {
            List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
            for (FileItem item : items) {
                if (item.isFormField()) {
                    // Process regular form field (input type="text|radio|checkbox|etc", select, etc).
                } else {
                    // Process form file field (input type="file").
                    

                    // Save the uploaded file into a place OpenOffice will be able to read and with the right extension
                    File tempInFile = saveFile(item.getInputStream(),FilenameUtils.getName(item.getName()));

 
                    // Create a temp file with the correct extension of pdf so we can pass to openoffice
                    File tempOutFile = createTempFile(FilenameUtils.getName(item.getName()), ".pdf" );
                  
                    //our wrapper code to convert to PDF with OpenOffice
                    PDFConvert(tempInFile,tempOutFile);

                    //set response headers to PDF
                    response.setContentType("application/pdf");
                    response.addHeader("Content-Disposition", "attachment; filename=" + tempOutFile.getName());

                    //stream the output
                    streamFile(tempOutFile, response);
                }
            }
        } catch (FileUploadException e) {
            throw new ServletException("Cannot parse multipart request.", e);
        }

    }

 

saveFile()

This function just takes the uploaded file and saves it into a location we can pass to OpenOffice.  When files are uploaded they are given an extension of .tmp.  OpenOffice uses the file extension to figure out what the file is, so we make sure it is correct according to the file that was uploaded.  Not much to explain here, we could have probably just moved and/or renamed the file.

protected File saveFile(InputStream input, String inFilename) throws IOException {
    //our code which requests a temp file

    File tmpFile = createTempFile(inFilename);

    FileOutputStream fos = new FileOutputStream(tmpFile);

    BufferedOutputStream bos = new BufferedOutputStream(fos);

    BufferedInputStream bis = new BufferedInputStream(input);
    int aByte;
    while((aByte = bis.read()) != -1) {
        bos.write(aByte);
    }

    bos.flush();
    bos.close();
    bis.close();

    return(tmpFile);
}



PDFConvert()

And finally, this is the interface to JODConverter.  Just a note, as mentioned earlier, You need to start OpenOffice as a service on the local machine before this process with work.  Version 3 of JODConverter takes care of this, but we were using version 2 here. The process is very simple:
  1. Make a socket connection to OpenOffice on port 8100
  2. Instantiate an OpenOfficeDocumentConverter()
  3. convert the file passing the original (inFile) and our target (ourFile)
  4. The calling routine already has the outFile reference so we only need to notify if it worked or not
protected boolean PDFConvert(File inFile, File outFile) {
   try {
       // connect to an OpenOffice.org instance running on port 8100
       OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
       connection.connect();

       // convert
       DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
       converter.convert(inFile, outFile);

       // close the connection
       connection.disconnect();
           
       return(true);
   }
   catch(ConnectException ce) {
       ce.printStackTrace();
       return(false);
   }
}


The Rest of the Functions

The last 3 functions are included here, since they do not relate directly to the PDF conversion, but were used to assist with functionality.

//calls the other createTempFile with extension set to null
protected File createTempFile(String inFilename) {
    return( createTempFile(inFilename, null));
}
   
protected File createTempFile(String inFilename, String tmpFileExt) {
    try {
        String tmpFileStr = "converted_" + inFilename;
           
        // if extension wasnt given figure it out
        if(tmpFileExt == null){
            tmpFileExt = "." + getFileExt(inFilename);
        }
           
        File tmpFile = File.createTempFile(tmpFileStr, tmpFileExt);
       
        return(tmpFile);
    }
    catch(IOException e) {
        e.printStackTrace();
        return(null);
    }
       
}
   
protected String getFileExt(String fileName) {
    int pos = fileName.lastIndexOf('.');
    String ext = fileName.substring(pos+1);
       
    return(ext);

}

Wrapping It All Up

Here is the basic process flow of the program:
  1. When a user visits the starting page, they will be presented with a browse button or location input box to enter a file on the location disk.  
  2. When the convert button is pressed, the Servlet executes doPost().  
  3. doPost() copies the uploaded file to another location with the same extension as the uploaded file.
  4. createTemplFile() creates a new file with the extension of .pdf
  5. PDFConvert() is run with the uploaded file and the pdf file
  6. Content headers are returned to the browser
  7. The PDF file is streamed from the disk back through the response instance of the Servlet
Many additions can be made to the program, but this is the basic flow.  We really need a lot of error checking and good responses to any problems that will occur.  It would probably help to have some reasonable timeouts as well.

I hope this helps some people out.  This program was the culminations of several hours of researching on the web and pulling example code from many different locations.