2025-02-09




Inking的自留地


:: 漏洞原理


確切的說,錯誤函數為Java的Native方法Java.com.sun.media.sound.HeadspaceSoundbank.nOpenResource。該函數在拷貝文件路徑時沒有檢查字符串大小而直接進行瞭拷貝,最終導致瞭棧溢出:


// $$kk: 04.11.99: we are never calling XFileClose!!
JNIEXPORT jlong JNICALL
    Java_com_sun_media_sound_HeadspaceSoundbank_nOpenResource(JNIEnv* e, jobject thisObj, jstring path)
{
    XFILE file = NULL;
    XFILENAME xfilename;


    const char *str = (*e)->GetStringUTFChars(e, path, 0);


    TRACE0(“Java_com_sun_media_sound_HeadspaceSoundbank_nOpenResource.
“);


    XConvertNativeFileToXFILENAME((void *)str, &xfilename);
    file = XFileOpenResource(&xfilename, TRUE);


    (*e)->ReleaseStringUTFChars(e, path, str);


    TRACE1(“Java_com_sun_media_sound_HeadspaceSoundbank_nOpenResource completed, returning %lu.
“, file);


    return (jlong) (INT_PTR) file;
}


// given a native file spec (FSSpec for MacOS, and C string for WinOS, fill in a XFILENAME
void XConvertNativeFileToXFILENAME(void *file, XFILENAME *xfile)
{
    if (xfile)
{
     XSetMemory(xfile, (INT32)sizeof(XFILENAME), 0);
}
    if (file)
{
#if USE_HAE_EXTERNAL_API == TRUE
     {
   void *dest;


   dest = &xfile->theFile;
   HAE_CopyFileNameNative(file, dest);
     }
#else
#if X_PLATFORM == X_MACINTOSH
     xfile->theFile = *((FSSpec *)file);
#endif
#if ( (X_PLATFORM == X_WINDOWS)     ||
    (X_PLATFORM == X_WIN_HARDWARE) ||
    (X_PLATFORM == X_BE)     ||
    (X_PLATFORM == X_SOLARIS)    ||
    (X_PLATFORM == X_LINUX)    ||
    (X_PLATFORM == X_NAVIO) )
     XStrCpy((char *)xfile->theFile, (char *)file);
#endif
#endif
}
}



    struct XFILENAME
    {
// public platform specific
#if X_PLATFORM == X_MACINTOSH
XFILE_HANDLE     fileReference;
FSSpec     theFile;
#endif
#if ( (X_PLATFORM == X_WINDOWS)     ||
   (X_PLATFORM == X_WIN_HARDWARE) ||
   (X_PLATFORM == X_WEBTV)    ||
   (X_PLATFORM == X_BE)     ||
   (X_PLATFORM == X_SOLARIS)    ||
   (X_PLATFORM == X_LINUX)    ||
   (X_PLATFORM == X_NAVIO) )
/* $$fb 2002-02-14: itanium port */
XFILE_HANDLE     fileReference;
char     theFile[FILE_NAME_LENGTH]; // “C” string name for path
#endif


// private variables. Zero out before calling functions
INT32     fileValidID;
XBOOL     resourceFile;


XPTR     pResourceData; // if file is memory based
INT32     resMemLength; // length of memory resource file
INT32     resMemOffset; // current offset of memory resource file
XBOOL     readOnly;   // TRUE then file is read only
XBOOL     allowMemCopy; // if TRUE, when a memory based resource is
// read, a copy will be created otherwise
// its just a pointer into the larger memory resource
// file
XFILE_CACHED_ITEM memoryCacheEntry;
XFILERESOURCECACHE *pCache;   // if file has been cached this will point to it
    };
    typedef struct XFILENAME XFILENAME;
    typedef void *     XFILE;


// standard strcpy
// Copies C string src into dest
char * XStrCpy(char *dest, char *src)
{
    char *sav;


    sav = dest;
    if (src == NULL)
{
     src = “”;
}
    if (dest)
{
     while (*src)
   {
      *dest++ = *src++;
   }
     *dest = 0;
}
    return sav;
}


以上FILE_NAME_LENGTH在windows下為_MAX_PATH,也就是256,所以隻要url->filename大於256就溢出瞭。還有一個關鍵點:


HeadspaceSoundbank(URL url) throws IOException {


if(Printer.trace) Printer.trace(“HeadspaceSoundbank: constructor: url: ” + url);


String protocol = url.getProtocol();
if ( ! (protocol.equals(“file”)) ) {


     InputStream stream = url.openStream();
     try {
     initialize(stream, false);
     } catch (IllegalArgumentException e) {
     stream.close();
     throw e;
     }
} else {
     String path = url.getFile();
     initialize(path); // 來到這裡
}


if(Printer.trace) Printer.trace(“HeadspaceSoundbank: constructor: url: ” + url + ” completed”);
}


:: 漏洞利用


漏洞的原理雖然簡單,但是利用卻不是那麼容易。首先,雖然漏洞是通過IE觸發的,但是最終執行漏洞函數的進程為java.exe,所以無法通過簡單的JavaScript堆噴射來進行利用。如果要做到比較通用,直接在java.exe內進行java堆噴射會比較好,但是事實上問題也挺多的,最麻煩的就是java堆的大小默認隻有64M,而且如果進行gc的頻率過高,jvm會直接拋出異常。所以經過幾次嘗試後,暫時放棄瞭這條路。還有一條路是常規的棧溢出利用。但是這個方法也有幾個問題。比較慶幸的是我們有足夠大的空間來寫Shellcode,可以直接用JMP ESP來進行Shellcode的定位。最棘手的是字符編碼的問題,在利用的過程中,跳轉地址和Shellcode的字節大小都必須在0x80以內(java現學的,可能存在盲點),否則會因為字符集的問題而轉的亂七八糟的。Shellcode在0x80內比較好解決,因為esp剛好指向Shellcode,用alpha2編碼可以使得Shellcode最終全部為可見字符。JMP ESP(CALL ESP)就比較麻煩瞭,因為比較穩定的opcode地址很多都在kernel32和ntdll上,而這兩者的加載基址又比較鬱悶(比如kernel32.dll為0x7c800000),又不能去找類似於shell32.dll這種不是很穩定的動態鏈接庫,所以最後還是鎖定瞭java自身的幾個動態鏈接庫,希望能通過java代碼得到版本號,然後按照不同版本號來計算不同的opcode地址。


:: PoC


PoC中的opcode隨便找的,測試環境為xp sp2,jre 6.0.160.1


////////////////////////////////////////////////////////////////////////////////////////////////


import java.applet.Applet;
import java.awt.Graphics;
import java.io.CharArrayWriter;
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.net.URL;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Soundbank;
import javax.sound.midi.Synthesizer;


public class test extends Applet
{
pub

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Copyright © All rights reserved. | ChromeNews by AF themes.