Skip to content

Instantly share code, notes, and snippets.

@abhisek
Created May 28, 2012 08:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save abhisek/2818018 to your computer and use it in GitHub Desktop.
Save abhisek/2818018 to your computer and use it in GitHub Desktop.
MS12-027 Analysis: Encrypted Word Document Structure
Crash Stack Trace:
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012eaa0 275c8a0a 0012eacc 00208008 00008282 MSCOMCTL!DllGetClassObject+0x41a87
0012ead4 27583c30 00000000 01000000 c279eb90 MSCOMCTL!DllGetClassObject+0x41cc6
00000000 00000000 00000000 00000000 00000000 MSCOMCTL!DllCanUnloadNow+0xc7d
Crash Instruction:
275c87cb f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
0:000> r @ecx
ecx=00001b53
0:000> r @edi
edi=00130000
0:000> !address @edi-1
00030000 : 00107000 - 00029000
Type 00020000 MEM_PRIVATE
Protect 00000004 PAGE_READWRITE
State 00001000 MEM_COMMIT
Usage RegionUsageStack
Pid.Tid 120.ac
^^ Looks like a controlled copy (stack overflow as mentioned in MS12-027)
Tracking Back:
0:000> uf 275c876d
MSCOMCTL!DllGetClassObject+0x41a29:
275c876d 55 push ebp
275c876e 8bec mov ebp,esp
275c8770 51 push ecx
275c8771 53 push ebx
[....]
MSCOMCTL!DllGetClassObject+0x41a7a:
275c87be 8b750c mov esi,dword ptr [ebp+0Ch]
275c87c1 8bcf mov ecx,edi
275c87c3 8b7d08 mov edi,dword ptr [ebp+8]
275c87c6 8bc1 mov eax,ecx
275c87c8 c1e902 shr ecx,2
275c87cb f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
[....]
edi = [ebp+8] : 0012eacc (Stack)
esi = [ebp+c] : 00208008 (Heap)
ebp = 0012eaa0
Crash Stack Trace:
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0012eaa0 275c8a0a 0012eacc 00208008 00008282 MSCOMCTL!DllGetClassObject+0x41a87
0012ead4 27583c30 00000000 01000000 c279eb90 MSCOMCTL!DllGetClassObject+0x41cc6
00000000 00000000 00000000 00000000 00000000 MSCOMCTL!DllCanUnloadNow+0xc7d
Crash Instruction:
275c87cb f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
0:000> r @ecx
ecx=00001b53
0:000> r @edi
edi=00130000
0:000> !address @edi-1
00030000 : 00107000 - 00029000
Type 00020000 MEM_PRIVATE
Protect 00000004 PAGE_READWRITE
State 00001000 MEM_COMMIT
Usage RegionUsageStack
Pid.Tid 120.ac
^^ Looks like a controlled copy (stack overflow as mentioned in MS12-027)
Tracking Back:
0:000> uf 275c876d
MSCOMCTL!DllGetClassObject+0x41a29:
275c876d 55 push ebp
275c876e 8bec mov ebp,esp
275c8770 51 push ecx
275c8771 53 push ebx
[....]
MSCOMCTL!DllGetClassObject+0x41a7a:
275c87be 8b750c mov esi,dword ptr [ebp+0Ch]
275c87c1 8bcf mov ecx,edi
275c87c3 8b7d08 mov edi,dword ptr [ebp+8]
275c87c6 8bc1 mov eax,ecx
275c87c8 c1e902 shr ecx,2
275c87cb f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
[....]
edi = [ebp+8] : 0012eacc (Stack)
esi = [ebp+c] : 00208008 (Heap)
ebp = 0012eaa0
- #<Dirent:"Root Entry">
|- #<Dirent:"Data" size=4096 data="\xF2\xF33V\xD5...">
|- #<Dirent:"1Table" size=4096 data="\x02\x00\x02\x00\x04...">
|- #<Dirent:"\u0001CompObj" size=109 data="\x01\x00\xFE\xFF\x03...">
|- #<Dirent:"encryption" size=8332 data="\xF2\xD32VY...">
|- #<Dirent:"WordDocument" size=4145 data="\xEC\xA5\xC1\x00#...">
\- #<Dirent:"\u0005DocumentSummaryInformation" size=4096 data="\xFE\xFF\x00\x00\x05...">
$:.unshift "./lib"
require 'fib'
class EncryptionVerifier
def initialize(buf)
@buf = buf.dup
@keys = SequencedHash.new
@keys['SaltSize'] = @buf.slice!(0, 4).unpack('V').first
@keys['Salt'] = @buf.slice!(0, 16)
@keys['EncryptedVerifier'] = @buf.slice!(0, 16)
@keys['VerifierHashSize'] = @buf.slice!(0, 4).unpack('V').first
@keys['VerifierHashSize'] = @buf.slice!(0, @keys['VerifierHashSize'])
end
def print
@keys.each_pair do |k, v|
if v.is_a? String
puts "EncryptionVerifier::#{k} [" + v.inspect + "]"
else
puts "EncryptionVerifier::#{k} 0x%08x" % [v]
end
end
end
end
# ECMA-376 document encryption [ECMA-376] and Office binary document RC4 CryptoAPI encryption use
# the EncryptionHeader structure to specify encryption properties for an encrypted stream.
# http://msdn.microsoft.com/en-us/library/dd926359(v=office.12).aspx
class EncryptionHeader
def initialize(buf)
@buf = buf.dup
@keys = SequencedHash.new
@keys['Flags'] = @buf.slice!(0, 4).unpack('V').first
@keys['SizeExtra'] = @buf.slice!(0, 4).unpack('V').first
@keys['AlgID'] = @buf.slice!(0, 4).unpack('V').first
@keys['AlgIDHash'] = @buf.slice!(0, 4).unpack('V').first
@keys['KeySize'] = @buf.slice!(0, 4).unpack('V').first
@keys['ProviderType'] = @buf.slice!(0, 4).unpack('V').first
@keys['Reserved1'] = @buf.slice!(0, 4).unpack('V').first
@keys['Reserved2'] = @buf.slice!(0, 4).unpack('V').first
@keys['CSPName'] = read_unicode_str(@buf)
end
def print
@keys.each_pair do |k, v|
if k == "CSPName"
puts "EncryptionHeader::#{k} [" + remove_null(v) + "]"
else
puts "EncryptionHeader::#{k} 0x%08x" % [v]
end
end
end
private
def read_unicode_str(d)
d.split("\x00\x00")[0]
end
def remove_null(v)
v.gsub("\x00", "")
end
end
# http://msdn.microsoft.com/en-us/library/dd945648(v=office.12).aspx
# http://msdn.microsoft.com/en-us/library/dd922755(v=office.12).aspx
class Encryption
def initialize(buf)
@buf = buf.dup
@keys = SequencedHash.new
@keys['EncryptionVersionInfo'] = @buf.slice!(0, 4).unpack('V').first
@keys['EncryptionHeaderFlags'] = @buf.slice!(0, 4).unpack('V').first
@keys['EncryptionHeaderSize'] = @buf.slice!(0, 4).unpack('V').first
@keys['EncryptionHeader'] = EncryptionHeader.new(@buf.slice!(0, @keys['EncryptionHeaderSize']))
@keys['EncryptionVerifier'] = EncryptionVerifier.new(@buf)
end
def print
print_header_flags
puts ""
@keys.each_pair do |k, v|
if v.is_a? EncryptionHeader
v.print
elsif v.is_a? EncryptionVerifier
v.print
else
puts "#{k} 0x%08x" % [v]
end
end
end
def print_header_flags
flags = SequencedHash.new
flags['fCryptoAPI'] = [2]
flags['fDocProps'] = [3]
flags['fExternal'] = [4]
flags['fAES'] = [5]
flags.each_pair do |k, v|
if ((@keys['EncryptionHeaderFlags'] >> v[0]) & 0x01) == 1
puts "Header Flags Set: #{k}"
end
end
end
end
if __FILE__ == $0
ole = Ole::Storage.new(ARGV[0])
fib = Word::FIB.load(ole)
unless ((fib.fDot << 7) != 1)
raise "File not encrypted"
end
puts "lKey: #{fib.lKey}"
ts = ole.file.read("/1Table")
puts "Table Stream Size: #{ts.size}"
enc = Encryption.new(ts[0, fib.lKey])
enc.print
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment