eliben / pyelftools

Parsing ELF and DWARF in Python
Other
1.99k stars 508 forks source link

KeyError when e_version is a bad number #467

Closed echel0nn closed 1 year ago

echel0nn commented 1 year ago

Describe the Bug

Eventhough e_version is mostly ignored by the Linux loader, A malicious ELF File with malformed e_version value which can prevent itself from being analyzed (if pyelftools is in-use for it).

To Reproduce

1) A dummy file with ELF format and malformed e_version.

00000000: 7f45 4c46 0102 7f45 4c46 0202 0202 0202  .ELF...ELF......
00000010: 0202 0202 0218 0202 01e7 027f 7f7f 7f7f  ................
00000020: 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f 7f7f  ................
00000030: 7f7f 0000 0010 7f02 0202 0202 0220       .............

2) run with readelf.py -e sample.bin

Expected Behaviour

Parse e_version value, return "unknown" if it's not a regular value.

Environment

Additional Comments

and

def describe_e_version_numeric(x):
    # the valid values are only 0 and 1, will return int if it's _unknown
    return hex(x) if type(x) == int else hex(ENUM_E_VERSION.get(x, _unknown))

I can create a PR, if the possible fix seems okay. After fix:

$ python readelf.py -e /bin/ls # normal
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x5f70
  Start of program headers:          64 (bytes into file)
  Start of section headers:          136120 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         27
  Section header string table index: 26

$ python readelf.py -e readelf/fuzzer07/crashes/id\:000001\,sig\:10\,src\:000007+000021\,time\:928602\,execs\:34224\,op\:splice\,rep\:2 # malformed
ELF Header:
  Magic:   7f 45 4c 46 01 02 7f 45 4c 46 02 02 02 02 02 02
  Class:                             ELF32
  Data:                              2's complement, big endian
  Version:                           <unknown>
  OS/ABI:                            <unknown>
  ABI Version:                       76
  Type:                              <unknown>
  Machine:                           <unknown>
  Version:                           0x2180202
  Entry point address:               0x1e7027f
  Start of program headers:          2139062143 (bytes into file)
  Start of section headers:          2139062143 (bytes into file)
  Flags:                             0x7f7f7f7f
  Size of this header:               32639 (bytes)
  Size of program headers:           32639 (bytes)
  Number of program headers:         32639
  Size of section headers:           32639 (bytes)
  Number of section headers:         32639
  Section header string table index: 0

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
sevaa commented 1 year ago

Um, how is it a bug if the library throws an exception on a malformed file? There are many ways a complex format like ELF can be malformed, and introducing a special case for each would be unfeasible. Now, readelf.py, being an interactive piece rather than a library, would do well to catch the exception and display a friendly error message, but a parser library is under no obligation to work around bogus content (unless it's known to be the kind emitted by a popular toolchain :). That said, descriptions.py is pretty much the back-end of readelf.py rather than a part of the parser proper. Tricky case, I guess. Let @eliben decide :)

echel0nn commented 1 year ago

yes, when I think about it again, the idea I mentioned is very shallow and very specific case:) yet I still opened an issue because I thought that it should not prevent readelf.py to continue even if keyerror is not handled directly.

eliben commented 1 year ago

Yes, throwing an exception is fine in this case.