Avast! - Authenticode Parsing Memory Corruption







Source: https://code.google.com/p/google-security-research/issues/detail?id=668

The attached PE file causes memory corruption in Avast, it looks related to authenticode parsing.

(474.c0c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=128be364 ebx=30303030 ecx=12555e70 edx=128bd032 esi=30303030 edi=00000000
eip=740b4454 esp=10cedfa8 ebp=12555e70 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
740b4454 8b06            mov     eax,dword ptr [esi]  ds:002b:30303030=????????
0:080> ub
740b4445 55              push    ebp
740b4446 56              push    esi
740b4447 57              push    edi
740b4448 33ff            xor     edi,edi
740b444a 8be9            mov     ebp,ecx
740b444c 85db            test    ebx,ebx
740b444e 7447            je      aswCmnBS_74080000!StreamHashClose+0x7e17 (740b4497)
740b4450 8b742418        mov     esi,dword ptr [esp+18h]
0:080> dd esp+18 L1
10cedfc0  30303030

# It looks like this address was a parameter, lets skip up a frame and see where it comes from
0:080> kvn 3
 # ChildEBP RetAddr  Args to Child..............
 WARNING: Stack unwind information not available. Following frames may be wrong.
 00 10cedfb4 740b483e 30303030 30303030 a00be921 aswCmnBS_74080000!StreamHashClose+0x7dd4
 01 10cedfe8 740c37e7 12481a88 00cf0400 00000008 aswCmnBS_74080000!StreamHashClose+0x81be
 02 10cee028 740aa2f5 12481a90 00001730 00030408 aswCmnBS_74080000!asw::root::CGenericFile::seekreadin+0xf7
 0:080> .frame /c 1
 01 10cedfe8 740c37e7 aswCmnBS_74080000!StreamHashClose+0x81be
 eax=128be364 ebx=30303030 ecx=12555e70 edx=128bd032 esi=30303030 edi=00000000
 eip=740b483e esp=10cedfbc ebp=73e1dca8 iopl=0         nv up ei pl nz na pe nc
 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
 740b483e 8bf8            mov     edi,eax
 0:080> ub.
 740b482a 0000            add     byte ptr [eax],al
 740b482c 0001            add     byte ptr [ecx],al
 740b482e 0000            add     byte ptr [eax],al
 740b4830 00ff            add     bh,bh
 740b4832 7044            jo      aswCmnBS_74080000!StreamHashClose+0x81f8 (740b4878)
 740b4834 8bce            mov     ecx,esi
 740b4836 ff7040          push    dword ptr [eax+40h]
 740b4839 e802fcffff      call    aswCmnBS_74080000!StreamHashClose+0x7dc0 (740b4440)

# The parameter comes from eax+40:
 0:080> dd eax+40 L1
 128be3a4  30303030

# What is that address?

 0:080> !address @eax
 Mapping file section regions...
 Mapping module regions...
 Mapping PEB regions...
 Mapping TEB and stack regions...
 Mapping heap regions...
 Mapping page heap regions...
 Mapping other regions...
 Mapping stack trace database regions...
 Mapping activation context regions...

 Usage:                  Heap
 Base Address:           128b8000
 End Address:            128ea000
 Region Size:            00032000
 State:                  00001000   MEM_COMMIT
 Protect:                00000004   PAGE_READWRITE
 Type:                   00020000   MEM_PRIVATE
 Allocation Base:        12150000
 Allocation Protect:     00000004   PAGE_READWRITE
 More info:              heap owning the address: !heap 0x120000
 More info:              heap segment
 More info:              heap entry containing the address: !heap -x 0x128be364

# It's a heap buffer, is it valid?

 0:080> !heap -x 0x128be364
 Entry     User      Heap      Segment       Size  PrevSize  Unused    Flags
 128bd038  128bd040  00120000  122ef5e0      1408      -           3f  LFH;busy.

# Looks okay to me, where does that buffer come from?

0:080> .frame /c 2
02 10cee028 740aa2f5 aswCmnBS_74080000!asw::root::CGenericFile::seekreadin+0xf7
eax=128be364 ebx=30303030 ecx=12555e70 edx=128bd032 esi=30303030 edi=00000000
eip=740c37e7 esp=10cedff0 ebp=128be364 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
740c37e7 83c40c          add     esp,0Ch
0:080> ub
740c37d3 0000            add     byte ptr [eax],al
740c37d5 0000            add     byte ptr [eax],al
740c37d7 8b464c          mov     eax,dword ptr [esi+4Ch]
740c37da 57              push    edi
740c37db 0345e8          add     eax,dword ptr [ebp-18h]
740c37de 50              push    eax
740c37df ff7510          push    dword ptr [ebp+10h]
740c37e2 e88bc70000      call    aswCmnBS_74080000!BZ2_bzerr+0x1d62 (740cff72)
0:080> dd ebp-18 L1
128be34c  57d9ddea

That is a really strange offset! And that DWORD appears in the input file at offset 316b3h:

│000316a0 a8 65 18 e9 79 40 62 25-96 6e c7 c7 37 6a 83 21 |?e??y@b%?n??7j?!|...
│000316b0 08 8e 41 ea dd d9 57 3f-1d 77 49 87 2a 16 06 5e |??A???W??wI?*??^|...
│000316c0 a6 38 6a 22 12 a3 51 19-83 7e b6 00 00 31 82 04 |?8j"??Q??~?  1??|...

This looks like broken authenticode parsing to me.

Proof of Concept: