vuln.sg  

vuln.sg Vulnerability Research Advisory

Lhaca におけるバッファオーバーフローの脆弱性

by Tan Chew Keong タン チュー ケオン
Release Date: 2007-07-01

   [en] [jp]

概要

Lhaca にバッファオーバーフローの脆弱性があります。悪意のある人は、この脆弱性を利用し Lhaca ユーザのシステムに、任意のコードを実行ことがで きます。


問題を確認したバージョン

  • Lhaca version 1.21

問題

Symantec Security Response が 2007年06月25日に Trojan.Lhdropper の情報を公開しました。それは、脆弱性を修正した Lhaca version 1.21 が 2007年06月26日にリリースしました。Lhaca のウェブサイトによると、Lhaca version 1.21 で strcpy のバッファーオーバーフロー脆弱性を修正しました。

しかし、Lhaca version 1.21 では、まだ修正しないバッファーオーバーフローの脆弱性が発見しました。 巧妙に細工された LZH ファイルをオープンしたとき、バッファオーバーフローが発生します。悪意のある 攻撃者は、この問題を利用し Lhaca を実行するユーザの権限で任意のコードを実行できる可能性があります。

Lhaca は、LZH ファイルから 「Extended Header Size」 を読みました。しかし、「Extended Header Size」 をチェックしないで、スタックバッファへ「Extended Header Data」 コピーしました。 LZH ファイルには、大きすぎる 「Extended Header Size」 があると、バッファオーバーフローが発生します。strncat の誤った使用も、存在します。

下記の Ollydbg 画面は、バッファオーバーフローを示す。

 

バッファオーバーフローの脆弱性が Lhaca.exe の以下の似ているの function にあります。

function_40D974(FILE *fp, char *outbuffer)
{
char var_1408[4096];
char overflowedBuffer[255]; //var_408

char var_309[769];
DWORD var_8;
DWORD var_4;


var_4 = 0;
memset(outbuffer, 0, 0x12c); // clear 300-byte buffer
...
...
fseek(fp, 1, SEEK_SET);
...
...
if(fread(&var_1408[1], 1, 0x24, fp) < 0x24)
{
// exit with error "Invalid header (LHarc file ?)"
}

globalReadBufPtr = &var_1408[20]; // header-level byte position
outbuffer[0x15] = *globalReadBufPtr;

globalReadBufPtr++;

if(outbuffer[0x15] != 2) // check header level
{
if(fread(&var_1408[0x25], 1, 2, fp) < 2) // read length of extended header
{
// exit with error "Invalid header (LHarc file ?)"
}
}

if(outbuffer[0x15] >= 3)
{
// exit with error "Unknown level header"
}

globalReadBufPtr = &var_1408[2];

outbuffer[0] = 0x25;
memcpy(&outbuffer[1], &var_1408[2], 5);
...
...
...
// globalReadBufPtr points within the var_1408 buffer and currently points
// to the filename read from the LZH header.
40DAB9_copy_filename_in_lzh_header_to_outbuffer(&outbuffer[0x16],
globalReadBufPtr,
length_of_filename);
...
...
...
while(...) // loc_40DC67 (loop that reads all headers)
{
// globalReadBufPtr points within the var_1408 buffer and currently points to
// the next Extended Header Size field (two-bytes) that was read from the LZH file.
// The getNextExtendedHeaderSize() function will increment the "globalReadBufPtr"
// pointer by two bytes.

hdrSize = getNextExtendedHeaderSize(globalReadBufPtr);

// stop processing if the next header size is 0
if(hdrSize == 0)
break;

if(outbuffer[0x15] != 2) // header level
{
// This code checks that there is enough space to read header.
// The result of overflowedBuffer - globalReadBufPtr can be up
// to 0xFD9 (4057 bytes).
// So up the 4057 bytes can be read in this buffer. i.e. "hdrSize"
// can be up to 0xFD9.
// Note that globalReadBufPtr points within var_1408.


if(overflowedBuffer - globalReadBufPtr >= hdrSize)
{
if(fread(globalReadBufPtr, 1, hdrSize, fp) != hdrSize)
{
// exit with error "Invalid header (LHa file ?)"
}

switch(*globalReadBufPtr)
{
globalReadBufPtr++;

case 40: // MS-DOS attribute header : 0x40
{
...
}

case 2: // Directory name header : 0x02
{
// BUFFER OVERFLOW.
// (hdrSize - 3)-bytes of directory name in the
// extended header is copied from the buffer
// pointed to by globalReadBufPtr into
// overflowedBuffer.

// From above, it should be noted that up to
// 0xFD9 (4057) bytes can be read into the buffer
// pointed to by globalReadBufPtr. i.e. hdrSize
// can be up to 0xFD9.

// The size of overflowedBufer is only 0xFF (255).
// Note that there is another buffer below
// overflowedBuffer, so more than 0x408 (1032)
// bytes must be copied into overflowedBuffer to
// overwrite the saved EIP. This is possible since
// 4057 bytes can be read into globalReadBufPtr.


if(hdrSize-3 > 0)
{
copyloop(overflowedBuffer, globalReadBufPtr,
hdrSize-3);
}
...

}
...
}
}
else
{
// exit with error "Invalid header (LHa file ?)"
}
}
}

if(outbuffer[0x15] != 2) // header level
{
...
}

// &outbuffer[0x16] points to the filename read from the LZH header
// WRONG USE OF strncat() !!!!
// "overflowedBuffer" already contains the directory name copied from
// the extended header. So fixing strncat()'s length argument at
// 0xFF allows more bytes to be appended into the buffer that is already
// overflowed.


strncat(overflowedBuffer, &outbuffer[0x16], 0xFF);

strncpy(&outbuffer[0x16], overflowedBuffer, 0xFF);
...
...
...
...
}


脆弱性のテストファイル

これは脆弱性のテストのためのファイルです。この LZH ファイルは、バッファオーバーフローを利用し calc.exe を実行します。この LZH ファイルは、英語版の WinXP SP2 か 日本語版の Windows 2000 SP4 が必要です。

  • lhaca121-EXP.lzh (バッファオーバーフローを利用し、英語版の WinXP SP2 で calc.exe を実行します)
  • lhaca121-EXP2.lzh (バッファオーバーフローを利用し、日本語版の Windows 2000 SP4 で calc.exe を実行します)
  • lhaca121-EXP3.lzh (バッファオーバーフローを利用し、日本語版と英語版の Win2K SP4/WinXP SP2 で calc.exe を実行します)
  • lhaca121-CRASH.lzh (バッファオーバーフローを利用し、Lhaca を異常終了にします)

Instructions:

  1. 「c:\test」 ディレクトリにこの LZH ファイルを保存してください。
  2. Explorer で 「c:\test」 ディレクトリをオープンします。
  3. LZH ファイルをダブルクリックしてください。
  4. Successful exploit will run calculator (calc.exe). Failed exploit will crash Lhaca.
 


対策

Version 1.23 へのバージョンアップをしてください。修正版のダウンロード


発見と報告の経緯

2007年06月25日 - Symantec Security Response が Trojan.Lhdropper の情報を公開しました。
2007年06月26日 - ベンダーは修 正版の Lhaca version 1.21 をリリースしました。
2007年06月29日 - Lhaca version 1.21 で、まだ修正しないバッファーオーバーフローの脆弱性が発見しました。
2007年06月29日 - ベンダーに報告しました。
2007年06月30日 - ベンダーから答えを受け取りました。
2007年07月01日 - ベンダーは修正版をリリースしました。
2007年07月01日 - 本脆弱性の公開。


Contact
For further enquries, comments, suggestions or bug reports, simply email them to