Skip to content

Commit

Permalink
Fix possible recursion bug. (#30)
Browse files Browse the repository at this point in the history
Resolving ATTRIBUTE_LIST recursively could get into a recursive loop.

Fixes: #29
  • Loading branch information
scudette authored Sep 21, 2020
1 parent c2a9c84 commit f5804b2
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 12 deletions.
23 changes: 12 additions & 11 deletions parser/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -681,16 +681,18 @@ func (self *ATTRIBUTE_LIST_ENTRY) Attributes(
attr_list_entry := self.Profile.ATTRIBUTE_LIST_ENTRY(
self.Reader, self.Offset+offset)

Printf("ATTRIBUTE_LIST_ENTRY %v\n",
attr_list_entry.DebugString())
Printf("%v ATTRIBUTE_LIST_ENTRY %v\n", mft_entry.Record_number(),
DebugString(attr_list_entry, ""))

// The attribute_list_entry points to a different MFT
// entry than the one we are working on now. We need
// to fetch it from there.
mft_ref := attr_list_entry.MftReference()
if ntfs.RootMFT != nil &&
attr_list_entry.MftReference() != uint64(mft_entry.Record_number()) {
mft_ref != uint64(mft_entry.Record_number()) {

Printf("Fetching from MFT Entry %v\n", attr_list_entry.MftReference())
Printf("While working on %v - Fetching from MFT Entry %v\n",
mft_entry.Record_number(), mft_ref)
attr, err := attr_list_entry.GetAttribute(ntfs)
if err != nil {
Printf("Error %v\n", err)
Expand Down Expand Up @@ -723,14 +725,13 @@ func (self *ATTRIBUTE_LIST_ENTRY) GetAttribute(
if err != nil {
return nil, err
}
for _, attr := range mft.EnumerateAttributes(ntfs) {
if attr.Type().Value == uint64(mytype) &&
attr.Attribute_id() == uint16(myid) {
return attr, nil
}
res, err := mft.GetDirectAttribute(ntfs, mytype, uint16(myid))
if err != nil {
Printf("MFT %v not found in target\n", mft.Record_number())
} else {
Printf("Found %v\n", DebugString(res, " "))
}

return nil, errors.New("No attribute found.")
return res, err
}

// The STANDARD_INDEX_HEADER has a second layer of fixups.
Expand Down
2 changes: 1 addition & 1 deletion parser/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type Debugger interface {

func DebugString(arg interface{}, indent string) string {
debugger, ok := arg.(Debugger)
if ok {
if debug && ok {
lines := strings.Split(debugger.DebugString(), "\n")
for idx, line := range lines {
lines[idx] = indent + line
Expand Down
47 changes: 47 additions & 0 deletions parser/mft.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,53 @@ func (self *MFT_ENTRY) EnumerateAttributes(ntfs *NTFSContext) []*NTFS_ATTRIBUTE
return result
}

// See https://github.com/CCXLabs/CCXDigger/issues/13

// It is possible that an attribute list is pointing to an mft entry
// which also contains an attribute list. The second attribute list
// may also point to another entry inside the first MFT entry. This
// causes an infinite loop.

// Previous versions of the code erroneously called
// EnumerateAttributes to resolve a foreign attribute reference but
// this is not strictly correct because a foreign reference is never
// indirect and so never should traverse ATTRIBUTE_LISTs recursively
// anyway.

// The GetDirectAttribute() function looks for an exact attribute and
// type inside an MFT entry without following any attribute
// lists. This breaks the recursion and is a more correct approach.

// Search the MFT entry for a contained attribute - does not expand
// ATTRIBUTE_LISTs. This version is suitable to be called from within
// an ATTRIBUTE_LIST expansion.
func (self *MFT_ENTRY) GetDirectAttribute(
ntfs *NTFSContext, attr_type uint64, attr_id uint16) (*NTFS_ATTRIBUTE, error) {
offset := int64(self.Attribute_offset())

for {
// Instantiate the attribute over the fixed up address space.
attribute := self.Profile.NTFS_ATTRIBUTE(self.Reader, offset)

// Reached the end of the MFT entry.
mft_size := int64(self.Mft_entry_size())
attribute_size := int64(attribute.Length())
if attribute_size == 0 ||
attribute_size+offset > mft_size {
break
}

if attribute.Type().Value == attr_type &&
attribute.Attribute_id() == attr_id {
return attribute, nil
}

// Go to the next attribute.
offset += int64(attribute.Length())
}
return nil, errors.New("No attribute found.")
}

// Open the MFT entry specified by a path name. Walks all directory
// indexes in the path to find the right MFT entry.
func (self *MFT_ENTRY) Open(ntfs *NTFSContext, filename string) (*MFT_ENTRY, error) {
Expand Down

0 comments on commit f5804b2

Please sign in to comment.