Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improper boundary checks in decompileSETTARGET() in decompile.c #189

Closed
bjchan9an opened this issue Nov 29, 2019 · 1 comment
Closed

Improper boundary checks in decompileSETTARGET() in decompile.c #189

bjchan9an opened this issue Nov 29, 2019 · 1 comment

Comments

@bjchan9an
Copy link

bjchan9an commented Nov 29, 2019

There are several memory leaks in decompile.c as follows:

==48795==ERROR: LeakSanitizer: detected memory leaks
...
SUMMARY: AddressSanitizer: 613842280 byte(s) leaked in 37014 allocation(s).

They seems to be similar with issue #119(CVE-2018-7869), but I found there also exists a crash. Member pointers can be controlled by crafted input.

Program received signal SIGSEGV, Segmentation fault.
__strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:62
62	../sysdeps/x86_64/multiarch/strlen-avx2.S: No such file or directory.
(gdb) bt
#0  __strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:62
#1  0x00007ffff6d814d3 in _IO_vfprintf_internal (s=s@entry=0x7fffffffbd00, format=format@entry=0x471891 "getUrl('%s',%s);", ap=ap@entry=0x7fffffffbea0) at vfprintf.c:1643
#2  0x00007ffff6dac910 in _IO_vsnprintf (string=0x6a4070 "getUrl('", '\203' <repeats 91 times>, maxlen=<optimized out>, format=0x471891 "getUrl('%s',%s);", args=0x7fffffffbea0) at vsnprintf.c:114
#3  0x00000000004670aa in vasprintf (ret=0x7fffffffc098, format=0x471891 "getUrl('%s',%s);", ap=0x7fffffffc070) at ../../util/vasprintf.c:23
#4  0x000000000043987d in println (fmt=0x471891 "getUrl('%s',%s);") at ../../util/decompile.c:218
#5  0x000000000041a09d in decompileGETURL (act=0x6af9c0) at ../../util/decompile.c:899
#6  0x0000000000415d44 in decompileAction (n=1, actions=0x6af970, maxn=2) at ../../util/decompile.c:3240
#7  0x00000000004393b7 in decompileActions (n=2, actions=0x6af970, indent=9) at ../../util/decompile.c:3494
#8  0x0000000000436c9d in decompileSETTARGET (n=2, actions=0x6af880, maxn=4, is_type2=1) at ../../util/decompile.c:3169
#9  0x0000000000418061 in decompileAction (n=2, actions=0x6af880, maxn=4) at ../../util/decompile.c:3465
#10 0x00000000004393b7 in decompileActions (n=4, actions=0x6af880, indent=8) at ../../util/decompile.c:3494
#11 0x000000000042a8a3 in decompileWITH (n=4, actions=0x6a56f0, maxn=5) at ../../util/decompile.c:2685
#12 0x0000000000416d20 in decompileAction (n=4, actions=0x6a56f0, maxn=5) at ../../util/decompile.c:3338
#13 0x00000000004393b7 in decompileActions (n=5, actions=0x6a56f0, indent=7) at ../../util/decompile.c:3494
#14 0x000000000042a8a3 in decompileWITH (n=6, actions=0x6afa20, maxn=7) at ../../util/decompile.c:2685
#15 0x0000000000416d20 in decompileAction (n=6, actions=0x6afa20, maxn=7) at ../../util/decompile.c:3338
#16 0x00000000004393b7 in decompileActions (n=7, actions=0x6afa20, indent=6) at ../../util/decompile.c:3494
#17 0x000000000042a8a3 in decompileWITH (n=4, actions=0x6afcb0, maxn=5) at ../../util/decompile.c:2685
#18 0x0000000000416d20 in decompileAction (n=4, actions=0x6afcb0, maxn=5) at ../../util/decompile.c:3338
#19 0x00000000004393b7 in decompileActions (n=5, actions=0x6afcb0, indent=5) at ../../util/decompile.c:3494
#20 0x000000000042a8a3 in decompileWITH (n=6, actions=0x6a50d0, maxn=7) at ../../util/decompile.c:2685
#21 0x0000000000416d20 in decompileAction (n=6, actions=0x6a50d0, maxn=7) at ../../util/decompile.c:3338
#22 0x00000000004393b7 in decompileActions (n=7, actions=0x6a50d0, indent=4) at ../../util/decompile.c:3494
#23 0x000000000042a8a3 in decompileWITH (n=2, actions=0x6a6490, maxn=3) at ../../util/decompile.c:2685
#24 0x0000000000416d20 in decompileAction (n=2, actions=0x6a6490, maxn=3) at ../../util/decompile.c:3338
#25 0x00000000004393b7 in decompileActions (n=3, actions=0x6a6490, indent=3) at ../../util/decompile.c:3494
#26 0x000000000042a8a3 in decompileWITH (n=4, actions=0x6a4e30, maxn=5) at ../../util/decompile.c:2685
#27 0x0000000000416d20 in decompileAction (n=4, actions=0x6a4e30, maxn=5) at ../../util/decompile.c:3338
#28 0x00000000004393b7 in decompileActions (n=5, actions=0x6a4e30, indent=2) at ../../util/decompile.c:3494
#29 0x000000000042a8a3 in decompileWITH (n=6, actions=0x6afea0, maxn=7) at ../../util/decompile.c:2685
#30 0x0000000000416d20 in decompileAction (n=6, actions=0x6afea0, maxn=7) at ../../util/decompile.c:3338
#31 0x00000000004393b7 in decompileActions (n=7, actions=0x6afea0, indent=1) at ../../util/decompile.c:3494
#32 0x000000000042a8a3 in decompileWITH (n=2, actions=0x6a5fb0, maxn=3) at ../../util/decompile.c:2685
#33 0x0000000000416d20 in decompileAction (n=2, actions=0x6a5fb0, maxn=3) at ../../util/decompile.c:3338
#34 0x00000000004393b7 in decompileActions (n=3, actions=0x6a5fb0, indent=0) at ../../util/decompile.c:3494
#35 0x0000000000438fac in decompile5Action (n=3, actions=0x6a5fb0, indent=0) at ../../util/decompile.c:3517
#36 0x000000000040d371 in outputSWF_DOACTION (pblock=0x6a49e0) at ../../util/outputscript.c:1552
#37 0x000000000040a9b1 in outputBlock (type=12, blockp=0x6a49e0, stream=0x68c260) at ../../util/outputscript.c:2083
#38 0x00000000004132cb in readMovie (f=0x68c260) at ../../util/main.c:281
#39 0x0000000000412190 in main (argc=2, argv=0x7fffffffde38) at ../../util/main.c:354
(gdb) i r rdi
rdi            0x8383838383838383	-8970181431921507453

Set breakpoint before calling println(). decompileGETURL() received a structure pointer parameter SWF_ACTION *act. However, the heap chunk was overflowed by input. So the member pointers can be controlled by crafted input data:

gdb> p sact->UrlString
$1 = (STRING) 0x8383838383838383 <error: Cannot access memory at address 0x8383838383838383>
gdb> p sact->TargetString
$2 = (STRING) 0x8383838383838383 <error: Cannot access memory at address 0x8383838383838383>

As the pointers are then dereferenced in println("getUrl('%s',%s);"..., it may result in an Information Disclosure and potentially Code Execution.

This problem exists in the released 0.4.8 and the latest commit 5009802.

POC: libming_decompile_memleak.zip

usage: ./swftophp libming_decompile_memleak

Found by bjchan9an@gmail.com

@bjchan9an bjchan9an changed the title Several memory leaks which is trigged in decompile.c Several memory leaks and resulting crash in decompile.c Nov 29, 2019
@bjchan9an bjchan9an changed the title Several memory leaks and resulting crash in decompile.c Several memory leaks and resulting crash in decompileGETURL (decompile.c:899) Nov 30, 2019
@bjchan9an bjchan9an changed the title Several memory leaks and resulting crash in decompileGETURL (decompile.c:899) Several memory leaks and heap overflow in decompileGETURL (decompile.c:899) Dec 1, 2019
@bjchan9an bjchan9an changed the title Several memory leaks and heap overflow in decompileGETURL (decompile.c:899) Heap overflow in decompileGETURL (decompile.c:899) Dec 1, 2019
@bjchan9an bjchan9an changed the title Heap overflow in decompileGETURL (decompile.c:899) Improper boundary checks in decompileSETTARGET() in decompile.c Jan 11, 2020
@bjchan9an
Copy link
Author

bjchan9an commented Jan 11, 2020

Since the issue was not received any reply or assigned a cve id for a long time, we further analyzed the cause of the vulnerability. Due to busyness and our limited capability, it may not be accurate, but I hope to provide more detailed references for identifying and fixing the vulnerability.

We found that improper boundary checking in decompileSETTARGE(int n, SWF_ACTION * actions, int maxn, int is_type2) caused the vulnerability.

In our POC, the parameters are:

  • n = 2
  • maxn = 4
  • actions: 0x5555557a0e20
    0x5555557a0e20:	0x0000000003030087	0x0000000000000066
    0x5555557a0e30:	0x0000000000000003	0x0000000000000000
    0x5555557a0e40:	0x0000000000000000	0x0000000000000000
    0x5555557a0e50:	0x0000000000000000	0x0000000000000000
    0x5555557a0e60:	0x0000000000000000	0x0000000000000000
    ----------------------------------------------------------
    0x5555557a0e70:	0x0000000000000000	0x000000000000006a
    0x5555557a0e80:	0x8383838383838383	0x8383838383838383
    0x5555557a0e90:	0x8383838383838383	0x8383838383838383
    0x5555557a0ea0:	0x8383838383838383	0x8383838383838383
    0x5555557a0eb0:	0x8383838383838383	0x8383838383838383
    ----------------------------------------------------------
    0x5555557a0ec0:	0x8383838300018320	0x000000000000006b
    0x5555557a0ed0:	0x8383838383838383	0x8383838383838383
    0x5555557a0ee0:	0x8383838383838383	0x8383838383838383
    0x5555557a0ef0:	0x8383838383838383	0x8383838383838383
    0x5555557a0f00:	0x8383838383838383	0x8383838383838383
    ----------------------------------------------------------
    0x5555557a0f10:	0x8383838308f28394	0x000000000000006c
    0x5555557a0f20:	0x0000000583830700	0x0000555555796f80
    0x5555557a0f30:	0x8383838383838383	0x8383838383838383
    0x5555557a0f40:	0x8383838383838383	0x8383838383838383
    0x5555557a0f50:	0x8383838383838383	0x8383838383838383
    ----------------------------------------------------------
    0x5555557a0f60:	0x8383838383838383	0x8383838383838383
    0x5555557a0f70:	0x8383838383838383	0x8383838383838383
    0x5555557a0f80:	0x8383838383838383	0x8383838383838383
    0x5555557a0f90:	0x8383838383838383	0x8383838383838383
    0x5555557a0fa0:	0x8383838383838383	0x8383838383838383
    0x5555557a0fb0:	0x8383838383838383	0x0000000000000291
    0x5555557a0fc0:	0x0000000000010007	0x0000000000000052
    

According to the size of "union SWF_ACTION" 0x50, we divide the actions in actions[] with dashed lines. As maxn limits, there are 4 in total.

The program then checks each action as follows until one of them meets the if condition or action_cnt + n> = maxn.

while(action_cnt+n<maxn)
{
	if (OpCode(actions, n+1+action_cnt, maxn)==SWFACTION_SETTARGET || ... || ...)
	{
		break;
	}
	action_cnt++;
}
decompileActions(action_cnt,&actions[n+1],gIndent+1);

We consider the boundary checking of the above code to be problematic. When action_cnt + n == maxn-1, it is still in the loop, and it will perform OpCode judgment on actions [maxn]. It obviously visits a non-existing action

What's worse, it doesn't crash here, but calls decompileActions (2, & actions [3], ...), mistakes a block of memory starting with 0x5555557a0f60 as an action and calls decompileAction().

The data at this position is read from the input file, which means that a fake action can be constructed directly in the input. In the POC we provide, the low byte of the position 0x83 tellsdecompileAction () that it is a SWFACTION_GETURL type action, so decompileGETURL() will be called and result in an Information Exposure.

Faking other types of actions, such as which calling outputSWF_ACTION(), may execute a fake function pointer, resulting in Code Execution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant