The opinions expressed in this blog are my own and do not represent those of my current employer

Heap overflow bug can potentionaly lead to alter heap in that way, that you can rule on its allocation / deallocation mechanism. Nowdays it is litle bit harder, because you need to fullfill some subset of prerequisities for choosen technique, and it is in more than less case not possible.

This post will describe how to break even LFH trough plugin, custom PoC for IE10 on win8 CP, vulnerable to winXP-8CP backend attack.

Prerequisites for this blogpost is to read details about introduced exploitation technique :

parsing file can cause creating another small same sized objects (with vtable) on the heap!

(at least one ) heap buffer overflow bug

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

__checkReturn boolCEnigmaPlugIn::CollectBlockFilters(

__in_bcount(size)constvoid*buff,

__in size_t size,BYTEdeep/*= 0*/)

{

//...

if(m_temp0.GetSize()>=block->StringSize)

{

block_filter->ReHash();

*((ULONG_PTR*)m_temp0.GetMemory()+1)=

block_filter->GetProxyHS()->Hash;

//overflow only in special case of size!!

memcpy(

(WCHAR*)m_temp0.GetMemory()+2*sizeof(ULONG_PTR),

block_filter->GetProxyHS()->UniString.Buffer,

block_filter->GetProxyHS()->UniString.Length*sizeof(WCHAR)

);

//overflow of (2 * sizeof(ULONG_PTR)) * sizeof(WCHAR))

//overwrite m_leak_ultiSentinel

returntrue;

}

...

}

Introduced BackEnd exploitation & fooling LFH :

Initial state of plugin custom heap :

C++

1

2

3

4

5

6

CAutoMalloc m_temp0;//can be overflowed

CAutoMalloc m_leak_ultiSentinel;//overflow results to overwrite

CAutoMalloc m_temp1;

CAutoMalloc m_duplo;

CAutoMalloc m_temp2;

CAutoMalloc m_unlinkerForever;

kinda weird, but it will be exaplained soon …

Due to present heap overflow bug, resizable chunk, and nature of file buffer used in plugin code, is possible to do small leak & reusing already used memory – for details of this technique read mentioned materials

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

classCAutoMalloc

{

public:

CAutoMalloc(__in size_t size)

{

m_size=0;

m_mem=MEMORY.alloc(size);

if(m_mem)

m_size=size;

}

~CAutoMalloc()

{

if(m_mem)

MEMORY.free(m_mem);

}

__checkReturn boolResize(__in size_t size)

{

void*t_mem=MEMORY.alloc(size);

if(t_mem)

{

if(m_mem)

{

//memcpy(t_mem, m_mem, min(size, m_size));

MEMORY.free(m_mem);

}

m_mem=t_mem;

m_size=size;

returntrue;

}

m_size=0;

returnfalse;

}

//...

}

__checkReturn boolCEnigmaPlugIn::CollectBlockFilters(

__in_bcount(size)constvoid*buff,...

)

{

//...

while(5*m_filterPos/4>=m_leak_ultiSentinel.GetSize()/2)

{

m_leak_ultiSentinel.Resize(m_leak_ultiSentinel.GetSize()*2);

m_leak_ultiSentinel.Resize(m_leak_ultiSentinel.GetSize()*2);

}

//...

}

voidCEnigmaPlugIn::ReLoadBlockList()

{

CFileReader file("c:/blocklist.log");

if(file.GetSize()>0x100000)

return;

CAutoMalloc auto_mem(file.GetSize());

void*file_buff=auto_mem.GetMemory();

if(file_buff)

{

file.ReadFrom(file_buff,auto_mem.GetSize(),0);

CollectBlockFilters(file_buff,auto_mem.GetSize());

}

}

As i mentioned in plugin are created small vtable objects on the fly

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

#define MIN_URL_SIZE (1 << 7)

structHASH_STRING

{

ULONG_PTR Hash;

WSTRING UniString;

private:

WCHAR buff[MIN_URL_SIZE+1];

};

classCFilter

{

public:

virtualboolGetFilter(__inout void*buff)=0;

};

classCBlockFilter:publicCFilter

{

//..functions..

HASH_STRING m_hstr;

};

//..

__checkReturn boolCEnigmaPlugIn::CollectBlockFilters(

__in_bcount(size)constvoid*buff,...

)

{

//..

CBlockFilter*block_filter=(CBlockFilter*)New(sizeof(CBlockFilter));

::new(block_filter)CBlockFilter((BYTE*)(block+1)+

block->StringPos,

block->StringSize);

//..

}

size of object CBlockFilter is small, and with old know 0x12 consecutive allocations is possible to trigger creation of LFH userdata block. So final plan is :

when is trigerred LFH some additional pre-allocation is performed and _HEAP_LIST_LOOKUP.ArraySize is updated (depending if ListHints contains bigger chunk than LFH try to alloc).

In this state of heap is performed another search -> by using ListsInUseUlong!

Search by walking trough ListHints is validation free approach, and in that case we have no problem

But search by walking trough ListsInUseUlong, is kinda another approach

again no validating, this counts for us, but to the ListsInUseUlong is memory chunk inserted when it is freed and also cleared when it is allocated. Problem is, that we already allocated our memory chunk and due to this it is cleared from ListsInUseUlong, and in attemp to find chunk for LFH userdata block is used ListsInUseUlong… So how to insert it back ?

ListsInUseUlong is just bitmap and thats it! Bitmap is able to cover just one deputy per size, and due this have to be clear another option how to link something back even it is already used…

In other words, if _HEAP_ENTRY(FLink).Size is same size then bit is not cleared and

Conclusions : As was mentioned in presentation How Safe is your Link ? security implementation needs to be implemented whithout shorcuts.
As you can see ListInUseUlong bitmaps usage and logic is imeplemented correctly*. Set and clear bitmap ensures that in _HEAP_LIST_LOOKUP.ListHints are only valid memory chunks and that implies secure alloc / free. But ‘non-secure’ FreeListSearch algo introduced in previous post allow to bypass ListInUseUlong safe mechanism.
So keep in mind that even small security hole can cause troubles and break down another secure processing…

Vulnerable plugin, and .py script for crafting data for this plugin as well, are both just illustrative and not important too much, so i did not it include to sources on github. These was used just for illustrating of idea itself – but if you want to see that, i will provide it to you, just ping me on my email

* AGAIN except missed validation check when checked if FLink is same sized .