#27 flip4mac wmv

9 views
Skip to first unread message

Landon Fuller

unread,
Jan 28, 2007, 6:26:47 PM1/28/07
to moab...@googlegroups.com
Attached is a proof of concept (no payload) .wmv I created for the issue. It's zip'd, as Mail.app will attempt to inline the movie (and then crash).
I figured that out the first time I tried to send this ...

Forgive the rich text, but the file header follows. The culprit is an invalid length field in the ASF header. Here's what I'm using to decipher the header:

00000000   30 26 B2 75  8E 66 CF 11  A6 D9 00 AA  00 62 CE 6C  88 0A 00 00  00 00 00 00  09 00 00 00  01 02 A1 DC  AB 8C 47 A9  CF 11 8E E4  0&.u.f.......b.l..................G.....
00000028   00 C0 0C 20  53 65 68 00  00 FF 00 00  00 00 E6 33  DD 13 40 A9  AB 48 AD 93  03 57 CF F4  3A EB 98 75  1B 00 00 00  00 00 80 C8  ... Seh........3..@..H...W..:..u........
00000050   CB AA D7 C0  C4 01 DC 04  00 00 00 00  00 00 F0 2C  EA 2A 00 00  00 00 90 B1  98 2A 00 00  00 00 B8 0B  00 00 00 00  00 00 02 00  ...............,.*.......*..............
00000078   00 00 A4 05  00 00 A4 05  00 00 F0 94  03 00 B5 03  BF 5F 2E A9  CF 11 8E E3  00 C0 0C 20  53 65 79 06  00 00 00 00  00 00 11 D2  ................._......... Sey.........
000000A0   D3 AB BA A9  CF 11 8E E6  00 C0 0C 20  53 65 06 00  4B 06 00 00  A9 46 43 7C  E0 EF FC 4B  B2 29 39 3E  DE 41 5C 85  21 00 00 00  ........... Se..K....FC|...K.)9>.A\.!...
000000C8   00 00 00 00  01 00 06 64  00 65 00 00  00 5D 8B F1  26 84 45 EC  47 9F 5F 0E  65 1F 04 52  C9 1A 00 00  00 00 00 00  00 02 01 EA  .......d.e...]..&.E.G._.e..R............
000000F0   CB F8 C5 AF  5B 77 48 84  67 AA 8C 44  FA 4C CA 5A  01 00 00 00  00 00 00 06  00 00 00 01  00 0C 00 02  00 02 00 00  00 49 00 73  ....[wH.g..D.L.Z.....................I.s
00000118   00 56 00 42  00 52 00 00  00 00 00 00  00 01 00 34  00 00 00 06  00 00 00 44  00 65 00 76  00 69 00 63  00 65 00 43  00 6F 00 6E  .V.B.R.........4.......D.e.v.i.c.e.C.o.n
00000140   00 66 00 6F  00 72 00 6D  00 61 00 6E  00 63 00 65  00 54 00 65  00 6D 00 70  00 6C 00 61  00 74 00 65  00 00 00 4C  00 32 00 00  .f.o.r.m.a.n.c.e.T.e.m.p.l.a.t.e...L.2..
00000168   00 00 00 02  00 0C 00 02  00 02 00 00  00 49 00 73  00 56 00 42  00 52 00 00  00 00 00 00  00 02 00 34  00 00 00 04  00 00 00 44  .............I.s.V.B.R.........4.......D
00000190   00 65 00 76  00 69 00 63  00 65 00 43  00 6F 00 6E  00 66 00 6F  00 72 00 6D  00 61 00 6E  00 63 00 65  00 54 00 65  00 6D 00 70  .e.v.i.c.e.C.o.n.f.o.r.m.a.n.c.e.T.e.m.p
000001B8   00 6C 00 61  00 74 00 65  00 00 00 40  00 00 00 00  00 01 00 2E  00 03 00 04  00 00 00 57  00 4D 00 2F  00 57 00 4D  00 41 00 44  .l.a.t.e...@...............W.M./.W.M.A.D
000001E0   00 52 00 43  00 50 00 65  00 61 00 6B  00 52 00 65  00 66 00 65  00 72 00 65  00 6E 00 63  00 65 00 00  00 FF 7F 00  00 00 00 01  .R.C.P.e.a.k.R.e.f.e.r.e.n.c.e..........
00000208   00 34 00 03  00 04 00 00  00 57 00 4D  00 2F 00 57  00 4D 00 41  00 44 00 52  00 43 00 41  00 76 00 65  00 72 00 61  00 67 00 65  .4.......W.M./.W.M.A.D.R.C.A.v.e.r.a.g.e
00000230   00 52 00 65  00 66 00 65  00 72 00 65  00 6E 00 63  00 65 00 00  00 36 15 00  00 74 D4 06  18 DF CA 09  45 A4 BA 9A  AB CB 96 AA  .R.e.f.e.r.e.n.c.e...6...t......E.......

asfcrash.wmv.zip
PGP.sig

Landon Fuller

unread,
Jan 28, 2007, 7:20:29 PM1/28/07
to moab...@googlegroups.com
No symbols, but here's the calling function for the memcpy. I've
annotated it as a step-through of the PoC wmv I sent.
My first question is 0x11afe3e6. Why cmovle? It almost looks like the
bug is accidental MAX() instead of MIN().

The caller of this function can be disassembled from 0x11b01708 to
0x11b017ed (i386). I'm going to start digging there next to see where
the destination argument comes from.

(gdb) disassemble 0x11afe3cc 0x11afe40b
Dump of assembler code from 0x11afe3cc to 0x11afe40b:
0x11afe3cc <MjpgDecompressorComponentDispatch+1537746>: push %ebp
0x11afe3cd <MjpgDecompressorComponentDispatch+1537747>: mov %esp,%ebp
0x11afe3cf <MjpgDecompressorComponentDispatch+1537749>: push %edi
0x11afe3d0 <MjpgDecompressorComponentDispatch+1537750>: push %esi
0x11afe3d1 <MjpgDecompressorComponentDispatch+1537751>: sub $0x10,%
esp
0x11afe3d4 <MjpgDecompressorComponentDispatch+1537754>: mov 8(%
ebp),%esi <-- function arg1, a struct pointer
0x11afe3d7 <MjpgDecompressorComponentDispatch+1537757>: mov 16(%
ebp),%edx <-- function arg3, ??, 0x10
0x11afe3da <MjpgDecompressorComponentDispatch+1537760>: mov 20(%
esi),%eax <-- struct member ??, 0x0
0x11afe3dd <MjpgDecompressorComponentDispatch+1537763>: mov 16(%
esi),%ecx <-- struct member, our provided length. (0xff000050)
0x11afe3e0 <MjpgDecompressorComponentDispatch+1537766>: sub %eax,%
ecx <-- 0x0 - 0xff000050 == 0xff000050
0x11afe3e2 <MjpgDecompressorComponentDispatch+1537768>: cmp %edx,%
ecx <-- cmp(0x10, 0xff000050)
0x11afe3e4 <MjpgDecompressorComponentDispatch+1537770>: mov %edx,%
edi <-- mov 0x10 to $edi
0x11afe3e6 <MjpgDecompressorComponentDispatch+1537772>: cmovle %ecx,%
edi <-- if (%edx < %ecx) mov %ecx,%edi [%edi is now 0xff000050. Why a
*less than* comparison??)
0x11afe3e9 <MjpgDecompressorComponentDispatch+1537775>: add 12(%
esi),%eax
0x11afe3ec <MjpgDecompressorComponentDispatch+1537778>: mov %edi,8
(%esp) <-- memcpy length, 0xff000050
0x11afe3f0 <MjpgDecompressorComponentDispatch+1537782>: mov %eax,4
(%esp) <-- memcpy source, function arg1+12
0x11afe3f4 <MjpgDecompressorComponentDispatch+1537786>: mov 12(%
ebp),%eax
0x11afe3f7 <MjpgDecompressorComponentDispatch+1537789>: mov %eax,(%
esp) <-- memcpy dest, function arg2
0x11afe3fa <MjpgDecompressorComponentDispatch+1537792>: call
0x11b7105a <dyld_stub_memcpy> memcpy(12(%ebp), struct member arg1+12,
0xff000050) <-- kaboom
0x11afe3ff <MjpgDecompressorComponentDispatch+1537797>: add %edi,20
(%esi)
0x11afe402 <MjpgDecompressorComponentDispatch+1537800>: mov %edi,%eax
0x11afe404 <MjpgDecompressorComponentDispatch+1537802>: add $0x10,%
esp
0x11afe407 <MjpgDecompressorComponentDispatch+1537805>: pop %esi
0x11afe408 <MjpgDecompressorComponentDispatch+1537806>: pop %edi
0x11afe409 <MjpgDecompressorComponentDispatch+1537807>: pop %ebp
0x11afe40a <MjpgDecompressorComponentDispatch+1537808>: ret
End of assembler dump.

PGP.sig

Landon Fuller

unread,
Jan 28, 2007, 7:50:19 PM1/28/07
to moab...@googlegroups.com

On Jan 28, 2007, at 4:20 PM, Landon Fuller wrote:

> The caller of this function can be disassembled from 0x11b01708 to
> 0x11b017ed (i386). I'm going to start digging there next to see
> where the destination argument comes from.

Sorry, wrong address. Here's a correct backtrace:

#0 0x11afe3e0 in MjpgDecompressorComponentDispatch () <-- in the
middle of the function that calls memcpy(). I'll call this function
copier()
#1 0x11b02504 in MjpgDecompressorComponentDispatch () <-- next
caller, disassembled below. We'll call this copydriver()
#2 0x11aff955 in MjpgDecompressorComponentDispatch ()
#3 0x1196d617 in MmsDataHandlerComponentDispatch ()
#4 0x11b01791 in MjpgDecompressorComponentDispatch ()
#5 0x1195dc82 in AsfMovieImportComponentDispatch ()
#6 0x11963c28 in AsfMovieImportComponentDispatch ()
#7 0x019a1f6e in CallComponentFunctionCommon ()
#8 0x1195b005 in AsfMovieImportComponentDispatch ()
#9 0x019a1a3c in CallComponentDispatch ()

Note that copydriver() allocates 0x10 on the stack at 0x11b024e1, and
then passes 0x10 as the third argument to copier() at 0x11b024f2.

(gdb) disassemble 0x11b024dc 0x11b02514
Dump of assembler code from 0x11b024dc to 0x11b02514:
0x11b024dc <MjpgDecompressorComponentDispatch+1554402>: push %ebp
0x11b024dd <MjpgDecompressorComponentDispatch+1554403>: mov %esp,%ebp
0x11b024df <MjpgDecompressorComponentDispatch+1554405>: push %edi
0x11b024e0 <MjpgDecompressorComponentDispatch+1554406>: push %esi
0x11b024e1 <MjpgDecompressorComponentDispatch+1554407>: sub $0x10,%
esp
0x11b024e4 <MjpgDecompressorComponentDispatch+1554410>: mov 8(%
ebp),%esi
0x11b024e7 <MjpgDecompressorComponentDispatch+1554413>: mov 12(%
ebp),%edi
0x11b024ea <MjpgDecompressorComponentDispatch+1554416>: lea 32(%
esi),%edx
0x11b024ed <MjpgDecompressorComponentDispatch+1554419>: mov 8(%
edi),%eax
0x11b024f0 <MjpgDecompressorComponentDispatch+1554422>: mov (%eax),
%ecx
0x11b024f2 <MjpgDecompressorComponentDispatch+1554424>: movl $0x10,8
(%esp)
0x11b024fa <MjpgDecompressorComponentDispatch+1554432>: mov %edx,4
(%esp)
0x11b024fe <MjpgDecompressorComponentDispatch+1554436>: mov %eax,(%
esp)
0x11b02501 <MjpgDecompressorComponentDispatch+1554439>: call *40(%ecx)
0x11b02504 <MjpgDecompressorComponentDispatch+1554442>: cmp $0x10,%
eax
0x11b02507 <MjpgDecompressorComponentDispatch+1554445>: je
0x11b02515 <MjpgDecompressorComponentDispatch+1554459>
0x11b02509 <MjpgDecompressorComponentDispatch+1554447>: mov
$0xffffb563,%eax
0x11b0250e <MjpgDecompressorComponentDispatch+1554452>: add $0x10,%
esp
0x11b02511 <MjpgDecompressorComponentDispatch+1554455>: pop %esi
0x11b02512 <MjpgDecompressorComponentDispatch+1554456>: pop %edi
0x11b02513 <MjpgDecompressorComponentDispatch+1554457>: pop %ebp
End of assembler dump.
(gdb)

PGP.sig

William A. Carrel

unread,
Jan 28, 2007, 8:07:42 PM1/28/07
to moab...@googlegroups.com
On 1/28/07, Landon Fuller <lan...@bikemonkey.org> wrote:
> 0x11afe3e2 <MjpgDecompressorComponentDispatch+1537768>: cmp %edx,%
> ecx <-- cmp(0x10, 0xff000050)
> 0x11afe3e4 <MjpgDecompressorComponentDispatch+1537770>: mov %edx,%
> edi <-- mov 0x10 to $edi
> 0x11afe3e6 <MjpgDecompressorComponentDispatch+1537772>: cmovle %ecx,%
> edi <-- if (%edx < %ecx) mov %ecx,%edi [%edi is now 0xff000050. Why a
> *less than* comparison??)

Actually %edx<=%ecx and since this is CMOVLE it's presuming these are
signed. So we get 0xff000050 - 0x10 to set the flags in CMP. This
might want to be CMOVBE instead, which would guarantee a memcpy of
size arg3 or less.

William A. Carrel

unread,
Jan 28, 2007, 8:11:10 PM1/28/07
to moab...@googlegroups.com
On 1/28/07, William A. Carrel <will...@carrel.org> wrote:
> On 1/28/07, Landon Fuller <lan...@bikemonkey.org> wrote:
> > 0x11afe3e2 <MjpgDecompressorComponentDispatch+1537768>: cmp %edx,%
> > ecx <-- cmp(0x10, 0xff000050)
> > 0x11afe3e4 <MjpgDecompressorComponentDispatch+1537770>: mov %edx,%
> > edi <-- mov 0x10 to $edi
> > 0x11afe3e6 <MjpgDecompressorComponentDispatch+1537772>: cmovle %ecx,%
> > edi <-- if (%edx < %ecx) mov %ecx,%edi [%edi is now 0xff000050. Why a
> > *less than* comparison??)
>
> Actually %edx<=%ecx and since this is CMOVLE it's presuming these are
> signed. So we get 0xff000050 - 0x10 to set the flags in CMP. This
> might want to be CMOVBE instead, which would guarantee a memcpy of
> size arg3 or less.

This seems especially the case since the arguments are going to
memcpy. Sending a signed length to memcpy doesn't strike me as an
astoundingly good move.

Landon Fuller

unread,
Jan 28, 2007, 9:19:03 PM1/28/07
to moab...@googlegroups.com

On Jan 28, 2007, at 5:11 PM, William A. Carrel wrote:

> This seems especially the case since the arguments are going to
> memcpy. Sending a signed length to memcpy doesn't strike me as an
> astoundingly good move.

An integer-overflow safe reimplemention:
http://moab-fixes.googlecode.com/svn/trunk/flip4mac_asf_handler.c

This works with valid .wmvs, and safely handles too-long length fields.

I haven't looked at PPC yet. I sure hope I can tweak the function
offset and re-use the fix.

-landonf

PGP.sig
Reply all
Reply to author
Forward
0 new messages