elfmaster / libelfmaster Goto Github PK
View Code? Open in Web Editor NEWSecure ELF parsing/loading library for forensics reconstruction of malware, and robust reverse engineering tools
Home Page: http://www.bitlackeys.org
Secure ELF parsing/loading library for forensics reconstruction of malware, and robust reverse engineering tools
Home Page: http://www.bitlackeys.org
Currently the elf_shared_object_iterator API which is contained within both libelfmaster.c and internal.c, is already fairly well developed with several flags that determine the behavior, method, and performance of the iterator that can be used based on the use-case. Nevertheless it still requires several important capabilities:
DT_RUNPATH
DT_ORIGIN
/lib/x86_64-linux-gnu/
/usr/lib/x86_64-linux-gnu/
/usr/lib
/lib
Describe the bug
A bad elf file which can lead elf_open_object() to a segmentation fault.
Poc here:
poc5.zip
To Reproduce
$ ./elfparse ./segv4
Expected behavior
Parse elf file without segmentation fault because segmentation fault can cause a Denial of Service (Dos).
Environment (please complete the following information):
Additional context
ASAN says:
=================================================================
==38155==ERROR: AddressSanitizer: SEGV on unknown address 0x0000000003b8 (pc 0x559f08fb4fcf bp 0x7ffc3e0c5010 sp 0x7ffc3e0c5010 T0)
==38155==The signal is caused by a READ memory access.
==38155==Hint: address points to the zero page.
#0 0x559f08fb4fce in section_name_cmp /home/ubuntu/some_c_test/libelfmaster/src/internal.c:125
#1 0x559f08f954f1 in bsearch /usr/include/x86_64-linux-gnu/bits/stdlib-bsearch.h:33
#2 0x559f08f954f1 in elf_section_by_name /home/ubuntu/some_c_test/libelfmaster/src/libelfmaster.c:1261
#3 0x559f08f8d1d8 in main /home/ubuntu/some_c_test/libelfmaster/examples/elfparse.c:209
#4 0x7fee4dc77c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
#5 0x559f08f8dc19 in _start (/home/ubuntu/some_c_test/libelfmaster/fuzz/elfparse+0x8c19)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/ubuntu/some_c_test/libelfmaster/src/internal.c:125 in section_name_cmp
==38155==ABORTING
[root@promote ~]# unzip libelfmaster-master.zip
Archive: libelfmaster-master.zip
1879e92
creating: libelfmaster-master/
inflating: libelfmaster-master/.gitignore
inflating: libelfmaster-master/ELF_STRUCTURE_MODIFICATION.md
inflating: libelfmaster-master/Makefile.in
inflating: libelfmaster-master/PARSING_DETAILS.md
inflating: libelfmaster-master/README.md
inflating: libelfmaster-master/TODO
creating: libelfmaster-master/build/
inflating: libelfmaster-master/build/libelfmaster.build.in
extracting: libelfmaster-master/build/libelfmaster.build.x86_64
inflating: libelfmaster-master/build/libelfmaster.pc
inflating: libelfmaster-master/build/libelfmaster.pc.in
inflating: libelfmaster-master/configure
creating: libelfmaster-master/examples/
inflating: libelfmaster-master/examples/Makefile
inflating: libelfmaster-master/examples/checksec.c
inflating: libelfmaster-master/examples/eh_frame.c
inflating: libelfmaster-master/examples/elf_text.c
inflating: libelfmaster-master/examples/elfparse.c
inflating: libelfmaster-master/examples/ldd.c
inflating: libelfmaster-master/examples/merged.c
inflating: libelfmaster-master/examples/modify_dynsym.c
inflating: libelfmaster-master/examples/modify_section.c
inflating: libelfmaster-master/examples/modify_segment.c
inflating: libelfmaster-master/examples/modify_symbol.c
extracting: libelfmaster-master/examples/nostdlib.c
inflating: libelfmaster-master/examples/objdump_libelfmaster.c
inflating: libelfmaster-master/examples/plt_dump.c
inflating: libelfmaster-master/examples/plt_dump2.c
inflating: libelfmaster-master/examples/pltgot.c
inflating: libelfmaster-master/examples/pointers.c
inflating: libelfmaster-master/examples/pointers.s
inflating: libelfmaster-master/examples/read_mem.c
inflating: libelfmaster-master/examples/scount.c
inflating: libelfmaster-master/examples/sections.c
inflating: libelfmaster-master/examples/symbols.c
inflating: libelfmaster-master/examples/test.c
inflating: libelfmaster-master/examples/test2.c
creating: libelfmaster-master/include/
extracting: libelfmaster-master/include/configure.h
extracting: libelfmaster-master/include/configure.h.in
inflating: libelfmaster-master/include/dwarf.h
inflating: libelfmaster-master/include/internal.h
inflating: libelfmaster-master/include/libelfmaster.h
inflating: libelfmaster-master/include/misc.h
inflating: libelfmaster-master/libelfmaster_talk_hushcon.odp
inflating: libelfmaster-master/libelfmaster_talk_hushcon.pdf
creating: libelfmaster-master/regressions/
extracting: libelfmaster-master/regressions/*.c
inflating: libelfmaster-master/regressions/Makefile.in
creating: libelfmaster-master/src/
inflating: libelfmaster-master/src/Makefile.in
inflating: libelfmaster-master/src/internal.c
inflating: libelfmaster-master/src/libelfmaster.c
creating: libelfmaster-master/utils/
inflating: libelfmaster-master/utils/stripx.c
[root@promote ~]# cd libelfmaster-master
[root@promote libelfmaster-master]# ls
build include PARSING_DETAILS.md TODO
configure libelfmaster_talk_hushcon.odp README.md utils
ELF_STRUCTURE_MODIFICATION.md libelfmaster_talk_hushcon.pdf regressions
examples Makefile.in src
[root@promote libelfmaster-master]# ./configure \
Detecting operating system.......success [linux]
Detecting machine architecture...success [x86_64]
Finding dirname command..........success [/usr/bin/dirname]
Determining build directory......success [/root/libelfmaster-master]
Finding gzip tool................success [/bin/gzip]
Finding suitable C compiler......success [/usr/bin/cc]
Finding suitable C++ compiler....success [/usr/bin/g++]
Package ck was not found in the pkg-config search path.
Perhaps you should add the directory containing ck.pc' to the PKG_CONFIG_PATH environment variable No package 'ck' found Package libelfmaster was not found in the pkg-config search path. Perhaps you should add the directory containing
libelfmaster.pc'
to the PKG_CONFIG_PATH environment variable
No package 'libelfmaster' found
Checking header file usability...success [stdint.h]
Checking header file usability...success [stdlib.h]
Checking header file usability...success [string.h]
Checking header file usability...success [errno.h]
Checking header file usability...success [sys/types.h]
Checking dynamic libraries.......success [dl]
Checking dynamic libraries.......ignored [@LIBJEMALLOC@]
Checking dynamic libraries.......ignored [@LIBTCMALLOC@]
Generating build files...........success
VERSION = 0.1.0
BUILD_DIR = /root/libelfmaster-master
INSTALL_PREFIX = /opt/elfmaster
SRC_DIR = /root/libelfmaster-master
SYSTEM = linux
PROFILE = x86_64
CC = /usr/bin/cc
CXX = /usr/bin/g++
COMPILER = gcc
CFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE -D_BSD_SOURCE -std=gnu99 -Wall -W -Wundef -Wendif-labels -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline -Wdisabled-optimization -fstrict-aliasing -O2 -pipe -Wno-parentheses -g -rdynamic -fno-omit-frame-pointer -I/root/libelfmaster-master/include -I/root/libelfmaster-master/include -I/opt/elfmaster/include -m64 -fPIC
CXXFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE -D_BSD_SOURCE -std=gnu++98 -Wall -W -Wundef -Wendif-labels -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Winline -Wdisabled-optimization -fstrict-aliasing -O2 -pipe -Wno-parentheses -g -rdynamic -fno-omit-frame-pointer -I/root/libelfmaster-master/include -I/root/libelfmaster-master/include -I/opt/elfmaster/include -m64
PTHREAD_CFLAGS = -pthread
LD = /usr/bin/cc
LDFLAGS = -Wl,-rpath,/opt/elfmaster/lib -Wl,-rpath-link,/opt/elfmaster/lib -fPIC
GZIP = /bin/gzip -c
MAKE = make
LDOBJECT = /usr/lib64/libdl.so
Headers will be installed in /opt/elfmaster/include
Libraries will be installed in /opt/elfmaster/lib
Documentation will be installed in /opt/elfmaster/share/man
[root@promote libelfmaster-master]# mjake
bash: mjake: command not found
[root@promote libelfmaster-master]# make
make -C src all || exit
make[1]: Entering directory /root/libelfmaster-master/src' /usr/bin/cc -D_DEFAULT_SOURCE -D_GNU_SOURCE -D_BSD_SOURCE -std=gnu99 -Wall -W -Wundef -Wendif-labels -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Winline -Wdisabled-optimization -fstrict-aliasing -O2 -pipe -Wno-parentheses -g -rdynamic -fno-omit-frame-pointer -I/root/libelfmaster-master/include -I/root/libelfmaster-master/include -I/opt/elfmaster/include -m64 -fPIC -I/root/libelfmaster-master/include -I/root/libelfmaster-master/include -m64 -D__x86_64__ -ggdb -O2 -I/root/libelfmaster-master/include -c -o /root/libelfmaster-master/src/libelfmaster.o /root/libelfmaster-master/src/libelfmaster.c /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_symtab_modify’: /root/libelfmaster-master/src/libelfmaster.c:207: warning: declaration of ‘index’ shadows a global declaration /usr/include/string.h:304: warning: shadowed declaration is here /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_dynsym_modify’: /root/libelfmaster-master/src/libelfmaster.c:251: warning: declaration of ‘index’ shadows a global declaration /usr/include/string.h:304: warning: shadowed declaration is here /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_segment_modify’: /root/libelfmaster-master/src/libelfmaster.c:294: warning: declaration of ‘index’ shadows a global declaration /usr/include/string.h:304: warning: shadowed declaration is here /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_dynamic_modify’: /root/libelfmaster-master/src/libelfmaster.c:344: warning: declaration of ‘index’ shadows a global declaration /usr/include/string.h:304: warning: shadowed declaration is here /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_section_modify’: /root/libelfmaster-master/src/libelfmaster.c:395: warning: declaration of ‘index’ shadows a global declaration /usr/include/string.h:304: warning: shadowed declaration is here /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_phdr_table_size’: /root/libelfmaster-master/src/libelfmaster.c:559: warning: unused variable ‘phdr_size’ /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_scop_text_filesz’: /root/libelfmaster-master/src/libelfmaster.c:602: warning: implicit declaration of function ‘__glibc_unlikely’ /root/libelfmaster-master/src/libelfmaster.c:602: warning: nested extern declaration of ‘__glibc_unlikely’ /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_reloc_type_string’: /root/libelfmaster-master/src/libelfmaster.c:771: error: ‘R_386_SIZE32’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:771: error: (Each undeclared identifier is reported only once /root/libelfmaster-master/src/libelfmaster.c:771: error: for each function it appears in.) /root/libelfmaster-master/src/libelfmaster.c:773: error: ‘R_386_TLS_GOTDESC’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:775: error: ‘R_386_TLS_DESC_CALL’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:777: error: ‘R_386_TLS_DESC’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:780: error: ‘R_386_IRELATIVE’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:837: error: ‘R_X86_64_PC64’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:839: error: ‘R_X86_64_GOTOFF64’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:841: error: ‘R_X86_64_GOTPC32’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:843: error: ‘R_X86_64_GOT64’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:845: error: ‘R_X86_64_GOTPCREL64’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:847: error: ‘R_X86_64_GOTPC64’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:849: error: ‘R_X86_64_GOTPLT64’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:851: error: ‘R_X86_64_PLTOFF64’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:853: error: ‘R_X86_64_SIZE32’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:855: error: ‘R_X86_64_SIZE64’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:857: error: ‘R_X86_64_GOTPC32_TLSDESC’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:859: error: ‘R_X86_64_TLSDESC_CALL’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:861: error: ‘R_X86_64_TLSDESC’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:863: error: ‘R_X86_64_IRELATIVE’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c:866: error: ‘R_X86_64_RELATIVE64’ undeclared (first use in this function) /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_segment_by_index’: /root/libelfmaster-master/src/libelfmaster.c:880: warning: declaration of ‘index’ shadows a global declaration /usr/include/string.h:304: warning: shadowed declaration is here /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_section_by_index’: /root/libelfmaster-master/src/libelfmaster.c:1129: warning: declaration of ‘index’ shadows a global declaration /usr/include/string.h:304: warning: shadowed declaration is here /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_section_name_by_index’: /root/libelfmaster-master/src/libelfmaster.c:1165: warning: declaration of ‘index’ shadows a global declaration /usr/include/string.h:304: warning: shadowed declaration is here /root/libelfmaster-master/src/libelfmaster.c: In function ‘elf_symbol_by_index’: /root/libelfmaster-master/src/libelfmaster.c:1215: warning: declaration of ‘index’ shadows a global declaration /usr/include/string.h:304: warning: shadowed declaration is here make[1]: *** [libelfmaster.o] Error 1 make[1]: Leaving directory
/root/libelfmaster-master/src'
make: *** [all] Error 2
[root@promote libelfmaster-master]#
I would like to point out that identifiers like “_LIBELFMASTER_H_
” and “_MISC_H_
” do eventually not fit to the expected naming convention of the C language standard.
Would you like to adjust your selection for unique names?
Can this library parse out the struct definition for one of these symbols, and if not, how can I solve it.
The following is the ELF file that I use IDA pro tool to parse, which can parse out the structure definition corresponding to the symbol, can we achieve this function in this library? Below is the screenshot.looking forward to your reply,thank you.
Found via fuzzing;
https://github.com/elfmaster/libelfmaster/blob/85e949c51b219594c0b3f4014cb09037f1442996/src/inte
rnal.c#L1329
This check will cause a malformed object to perform a (0 - 0) - 6
which will cause a very large number to be compared against i
. Resulting in crashes often when ins[i]
is used by the memcmp
-- there needs to be a check to prevent this, likely returning 0
.
Unsure if this needs to throw / catch extra issues downstream?
Describe the bug
A bad elf file which can lead elf_open_object() to a heap-buffer-overflow(read) issue.
Poc here:
poc1.zip
To Reproduce
$ ./elfparse ./overflow
Expected behavior
The code snippet where the issue happened should avoid the out-bounds read operation.
Environment (please complete the following information):
Additional context
ASAN says:
=================================================================
==37927==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7f93d6cbc9b0 at pc 0x56104361d25c bp 0x7ffeecb3fb30 sp 0x7ffeecb3fb20
READ of size 4 at 0x7f93d6cbc9b0 thread T0
#0 0x56104361d25b in build_dynsym_data /home/ubuntu/some_c_test/libelfmaster/src/internal.c:304
#1 0x5610436130af in elf_open_object /home/ubuntu/some_c_test/libelfmaster/src/libelfmaster.c:3285
#2 0x5610435efb04 in main /home/ubuntu/some_c_test/libelfmaster/examples/elfparse.c:38
#3 0x7f93d5834c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
#4 0x5610435f1c19 in _start (/home/ubuntu/some_c_test/libelfmaster/fuzz/elfparse+0x8c19)
0x7f93d6cbc9b0 is located 0 bytes to the right of 197040-byte region [0x7f93d6c8c800,0x7f93d6cbc9b0)
allocated by thread T0 here:
#0 0x7f93d5ce2d28 in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xded28)
#1 0x7f93d592fbeb in hcreate_r (/lib/x86_64-linux-gnu/libc.so.6+0x11cbeb)
#2 0x5610435efb04 in main /home/ubuntu/some_c_test/libelfmaster/examples/elfparse.c:38
#3 0x7ffeecb41219 (<unknown module>)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ubuntu/some_c_test/libelfmaster/src/internal.c:304 in build_dynsym_data
Shadow bytes around the buggy address:
0x0ff2fad8f8e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ff2fad8f8f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ff2fad8f900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ff2fad8f910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0ff2fad8f920: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0ff2fad8f930: 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa fa fa
0x0ff2fad8f940: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0ff2fad8f950: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0ff2fad8f960: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0ff2fad8f970: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0ff2fad8f980: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==37927==ABORTING
bool
elf_segment_by_index(struct elfobj *obj, uint64_t index, struct elf_segment *segment)
{
switch(elf_class(obj)) {
case elfclass32:
if (index >= obj->ehdr32->e_phnum)
return false;
segment->type = obj->phdr32[index].p_type;
segment->flags = obj->phdr32[index].p_flags;
segment->offset = obj->phdr32[index].p_offset;
segment->vaddr = obj->phdr32[index].p_vaddr;
segment->paddr = obj->phdr32[index].p_paddr;
segment->filesz = obj->phdr32[index].p_filesz;
segment->memsz = obj->phdr32[index].p_memsz;
segment->align = obj->phdr32[index].p_align;
break;
case elfclass64:
if (index >= obj->ehdr64->e_phnum)
return false;
segment->type = obj->phdr64[index].p_type;
segment->flags = obj->phdr64[index].p_flags;
segment->offset = obj->phdr64[index].p_offset;
segment->vaddr = obj->phdr64[index].p_vaddr;
segment->paddr = obj->phdr64[index].p_paddr;
segment->filesz = obj->phdr64[index].p_filesz;
segment->memsz = obj->phdr64[index].p_memsz;
segment->align = obj->phdr64[index].p_align;
break;
default:
return false;
}
return true;
}```
```C
struct elf_segment {
uint32_t type;
uint32_t flags;
uint64_t offset;
uint64_t paddr;
uint64_t vaddr;
uint64_t filesz;
uint64_t memsz;
uint64_t align;
unsigned int index;
};
Results in undefine behavior when accessing segment.index
in the local instance of stuct elf_segment segment
.
[sad0p@Arch-Deliberate tmp]$ ./elfmaster_test2 /bin/ls
0x6 && index => 0x2e42c0
0x3 && index => 0x2e42c0
0x1 && index => 0x2e42c0
0x1 && index => 0x2e42c0
0x1 && index => 0x2e42c0
0x1 && index => 0x2e42c0
0x2 && index => 0x2e42c0
0x4 && index => 0x2e42c0
0x4 && index => 0x2e42c0
0x6474e553 && index => 0x2e42c0
0x6474e550 && index => 0x2e42c0
0x6474e551 && index => 0x2e42c0
0x6474e552 && index => 0x2e42c0
[sad0p@Arch-Deliberate tmp]$ cat elfmaster_test2.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <elf.h>
#include <sys/types.h>
#include <search.h>
#include <sys/time.h>
#include "libelfmaster.h"
#define ERROR -1
int main(int argc, char **argv) {
elfobj_t obj;
elf_error_t error;
struct elf_segment segment;
if (!elf_open_object(argv[1], &obj, ELF_LOAD_F_FORENSICS,&error)) {
printf("%s\n", elf_error_msg(&error));
exit(ERROR);
}
int i = 0;
while(elf_segment_by_index(&obj, i, &segment)) {
printf("0x%x && index => 0x%x\n", segment.type, segment.index);
i++;
}
elf_close_object(&obj);
return 0;
}
[sad0p@Arch-Deliberate tmp]$ readelf -l /bin/ls
Elf file type is DYN (Position-Independent Executable file)
Entry point 0x5eb0
There are 13 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000002d8 0x00000000000002d8 R 0x8
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000003520 0x0000000000003520 R 0x1000
LOAD 0x0000000000004000 0x0000000000004000 0x0000000000004000
0x0000000000013991 0x0000000000013991 R E 0x1000
LOAD 0x0000000000018000 0x0000000000018000 0x0000000000018000
0x00000000000075e8 0x00000000000075e8 R 0x1000
LOAD 0x000000000001ffb0 0x0000000000020fb0 0x0000000000020fb0
0x00000000000012c8 0x00000000000025b0 RW 0x1000
DYNAMIC 0x0000000000020a98 0x0000000000021a98 0x0000000000021a98
0x00000000000001c0 0x00000000000001c0 RW 0x8
NOTE 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000050 0x0000000000000050 R 0x8
NOTE 0x0000000000000388 0x0000000000000388 0x0000000000000388
0x0000000000000044 0x0000000000000044 R 0x4
GNU_PROPERTY 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000050 0x0000000000000050 R 0x8
GNU_EH_FRAME 0x000000000001ce14 0x000000000001ce14 0x000000000001ce14
0x00000000000005c4 0x00000000000005c4 R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x000000000001ffb0 0x0000000000020fb0 0x0000000000020fb0
0x0000000000001050 0x0000000000001050 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn
03 .init .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .data.rel.ro .dynamic .got .data .bss
06 .dynamic
07 .note.gnu.property
08 .note.gnu.build-id .note.ABI-tag
09 .note.gnu.property
10 .eh_frame_hdr
11
12 .init_array .fini_array .data.rel.ro .dynamic .got
[sad0p@Arch-Deliberate tmp]$
libelfmaster fails to compile with musl
gcc -I ./ -static shiva.o shiva_util.o shiva_signal.o shiva_ulexec.o shiva_auxv.o shiva_module.o shiva_trace.o shiva_trace_thread.o shiva_error.o shiva_maps.o shiva_analyze.o shiva_callsite.o shiva_target.o shiva_xref.o shiva_transform.o shiva_so.o shiva_post_linker.o /nix/store/rl8bajlymj1md1000f91gjhnvz0nrpwq-libelfmaster-0.4-alpha-unstable-2023-02-23/lib/libelfmaster.a /nix/store/jagvcafr5xbnriwg6xajw2brvcjxcwi1-capstone-4.0.2/lib/libcapstone.a -o './build'/shiva
/nix/store/a1kgwwyad44q620sym78yx5cwprgwqgs-binutils-2.40/bin/ld: /nix/store/rl8bajlymj1md1000f91gjhnvz0nrpwq-libelfmaster-0.4-alpha-unstable-2023-02-23/lib/libelfmaster.a(libelfmaster.o): in function `elf_scop_text_filesz':
(.text+0x3314): undefined reference to `__glibc_unlikely'
fix
# fix: undefined reference to `__glibc_unlikely'
#define __glibc_unlikely(cond) __builtin_expect ((cond), 0)
substituteInPlace include/libelfmaster.h \
--replace-fail \
'#define peu_probable __glibc_unlikely' \
'#define peu_probable(cond) __builtin_expect ((cond), 0)' \
$ grep -r -w __glibc_unlikely libelfmaster/
libelfmaster/include/libelfmaster.h:#define peu_probable __glibc_unlikely
based on gear-lib/gear-lib/libdebug/gcc.macro
#define __glibc_unlikely(cond) __builtin_expect ((cond), 0)
I just wanted to see the resilient of libelfmaster against malformed ELF (I struggled with ELF while implementing stuff in radare2). After, a bit of coding review I realized that sh_name
is never checked against maximum values - the function elf_section_string
is intended for that but however not used.
As such, for example, within sort_elf_sections
a malformed file will cause oob read. Unfortunately, is widespread throughout libelfmaster.
ryzen:examples alvaro$ ASAN_OPTIONS=symbolize=1 ./elfparse fuzz/elfparse/out/queue/id:000000,orig:004d_000000006528c481_0000000000000000.inp
AddressSanitizer:DEADLYSIGNAL
=================================================================
==5745==ERROR: AddressSanitizer: SEGV on unknown address 0x7f4ea08c54c6 (pc 0x7f4da76cd621 bp 0x7ffcec9f5630 sp 0x7ffcec9f4db8 T0)
==5745==The signal is caused by a READ memory access.
#0 0x7f4da76cd620 (/lib/x86_64-linux-gnu/libc.so.6+0x15c620)
#1 0x43ae4f in __interceptor_strdup /home/alvaro/tools/llvm/llvm/projects/compiler-rt/lib/asan/asan_interceptors.cc:443:29
#2 0x55c727 in sort_elf_sections /home/alvaro/projects/reverse/libelfmaster/src/internal.c:2008:8
#3 0x53d0c1 in elf_open_object /home/alvaro/projects/reverse/libelfmaster/src/libelfmaster.c:2321:6
#4 0x52a2c2 in main /home/alvaro/projects/reverse/libelfmaster/examples/elfparse.c:38:6
#5 0x7f4da759509a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)
#6 0x41e409 in _start (/home/alvaro/projects/reverse/libelfmaster/examples/elfparse+0x41e409)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libc.so.6+0x15c620)
I tested with one of the files from https://github.com/radare/radare2-regressions/tree/master/bins/fuzzed. I don't submit a patch because I believe you are working on a new version and probably you are already aware of this but let me know if you would like a PR.
A bad ELF File which can lead elf_segment_iterator_next() to access out of bound memory or memory leak due to malformed e_phnum value.
Note: Most of them are just my laziness, usually I just copy/paste the environment values.
CC=afl-cc CXX=afl-c++ CFLAGS="-g -flto=auto" CXXFLAGS=-g CPPFLAGS=-g PKG_CONFIG_PATH=./build ./configure --prefix=$PWD
deleted dl from required packages
CC=afl-cc CXX=afl-c++ CFLAGS="-g -flto=auto" CXXFLAGS=-g CPPFLAGS=-g AR=llvm-ar make -j24 all
export AFL_LLVM_CMPLOG=1
export AFL_LLVM_LAF_ALL=1
export AFL_USE_CFISAN=1
Parse and Detect the e_phnum anomaly, refuse to allocate memory for non-existent segments and exit gracefully.
Linux 6.2.10-zen1-1-zen x86_64 GNU/Linux, clang version 15.0.7
examples/elfparse
Found more bugs with the dead_bytes.bin
binary that is produced by libgolf.h as one and only unique seed but they need more time to triage.
Curently the API functions and the internal functions are all in libelfmaster. This is not good for users who use the code as documentation. So lets put all of the functions that begin with 'static' (As they are the internal ones) into src/internal.c
Does not parse go binaries compiled on lubuntu 18.10
sblip@latitude:~/elf/libelfmaster/examples$ ./sections ~/go/src/github.com/Binject/binjection/binjection
failed to build dynamic segment data
sblip@latitude:~/elf/libelfmaster/examples$ readelf -d ~/go/src/github.com/Binject/binjection/binjection
Dynamic section at offset 0x1e8100 contains 19 entries:
Tag Type Name/Value
0x0000000000000004 (HASH) 0x5409c0
0x0000000000000006 (SYMTAB) 0x540e80
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000005 (STRTAB) 0x540a80
0x000000000000000a (STRSZ) 493 (bytes)
0x0000000000000007 (RELA) 0x540620
0x0000000000000008 (RELASZ) 24 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x0000000000000003 (PLTGOT) 0x5e8000
0x0000000000000015 (DEBUG) 0x0
0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000006ffffffe (VERNEED) 0x540960
0x000000006fffffff (VERNEEDNUM) 2
0x000000006ffffff0 (VERSYM) 0x540900
0x0000000000000014 (PLTREL) RELA
0x0000000000000002 (PLTRELSZ) 696 (bytes)
0x0000000000000017 (JMPREL) 0x540638
0x0000000000000000 (NULL) 0x0
sblip@latitude:~/elf/libelfmaster/examples$ gcc --version
gcc (Ubuntu 8.2.0-7ubuntu1) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
sblip@latitude:/elf/libelfmaster/examples$ ld --version/elf/libelfmaster/examples$
GNU ld (GNU Binutils for Ubuntu) 2.31.1
Copyright (C) 2018 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
sblip@latitude:
function elf_plt_entry_by_name()
will return incorrect PLT entry addresses because it relies on section header entry size information for .PLT
section. The 64-bit entry size is correct and thus returns the correct address for each PLT entry, however using entry size for 32-bit bins leads to incorrect addresses. The code below I propose the following calculation method
actual_plt_entry_size = plt.size / num_plt_entries
Where num_plt_entries
is calculated by iterating over .rel.plt
for the R_*_JUMP_SLOT
relocation type and increment num_plt_entries
for each one found. In addition to that we account for PLT-0
in binaries not implementing .plt.sec
.
bool
build_plt_data(struct elfobj *obj)
{
ENTRY e, *ep;
struct elf_section plt;
struct elf_relocation_iterator r_iter;
struct elf_relocation r_entry;
struct elf_plt_node *plt_node;
uint64_t plt_addr;
elf_iterator_res_t res;
bool secure_plt = false;
uint64_t num_plt_entries = 0;
uint64_t actual_plt_entry_size;
/*
* Must check for .plt.sec first to handle -fcf-protection
*/
if (elf_section_by_name(obj, ".plt.sec", &plt) == false) {
if (elf_section_by_name(obj, ".plt", &plt) == false) {
return false;
}
} else {
secure_plt = true;
}
/*
* We can use the relocation iterator at this point, since all of its
* necessary components have been set already within elfobj *
*/
if (elf_relocation_iterator_init(obj, &r_iter) == false) {
printf("elf_relocation_iterator_init\n");
return false;
}
plt_node = malloc(sizeof(*plt_node));
if (plt_node == NULL) {
perror("malloc");
return false;
}
/*
* The First PLT entry is always PLT-0, even though objdump always
* names it with same symbol name as the next PLT entry.
* (NOTE: if .plt.sec is in use then there isn't a PLT-0)
*/
if (secure_plt == false) {
/*
* Insert a PLT entry into the list and the hash
* for "PLT-0"
*/
plt_node->addr = plt.address;
plt_node->symname = (char *)"PLT-0";
LIST_INSERT_HEAD(&obj->list.plt, plt_node, _linkage);
e.key = (char *)plt_node->symname;
e.data = (void *)plt_node;
hsearch_r(e, ENTER, &ep, &obj->cache.plt);
num_plt_entries++; //account for PLT-0
}
for (;;) {
res = elf_relocation_iterator_next(&r_iter, &r_entry);
if (res == ELF_ITER_ERROR)
return false;
if (res == ELF_ITER_DONE)
break;
if (r_entry.type != ELF_RELOC_JUMP_SLOT)
continue;
num_plt_entries++;
}
actual_plt_entry_size = plt.size / num_plt_entries;
plt_addr = (secure_plt == true) ? plt.address : plt.address + actual_plt_entry_size;
if (elf_relocation_iterator_init(obj, &r_iter) == false) {
printf("elf_relocation_iterator_init\n");
return false;
}
for (;;) {
res = elf_relocation_iterator_next(&r_iter, &r_entry);
if (res == ELF_ITER_ERROR)
return false;
if (res == ELF_ITER_DONE)
break;
if (r_entry.type != ELF_RELOC_JUMP_SLOT)
continue;
plt_node = malloc(sizeof(*plt_node));
if (plt_node == NULL)
return false;
plt_node->addr = plt_addr;
plt_node->symname = r_entry.symname;
LIST_INSERT_HEAD(&obj->list.plt, plt_node, _linkage);
e.key = (char *)plt_node->symname;
e.data = (void *)plt_node;
hsearch_r(e, ENTER, &ep, &obj->cache.plt);
plt_addr += actual_plt_entry_size;
}
return true;
}```
There's an absents of out->type = obj->shdr32[index].sh_type
and out->shdr64[index].sh_type
for 32 and 64-bit binaries in elf_section_by_index()
.
bool
elf_section_by_index(struct elfobj *obj, uint32_t index,
struct elf_section *out)
{
switch(obj->e_class) {
case elfclass32:
if (index >= obj->ehdr32->e_shnum)
return false;
out->name = &obj->shstrtab[obj->shdr32[index].sh_name];
out->link = obj->shdr32[index].sh_link;
out->info = obj->shdr32[index].sh_info;
out->flags = obj->shdr32[index].sh_flags;
out->align = obj->shdr32[index].sh_addralign;
out->entsize = obj->shdr32[index].sh_entsize;
out->offset = obj->shdr32[index].sh_offset;
out->address = obj->shdr32[index].sh_addr;
break;
case elfclass64:
if (index >= obj->ehdr64->e_shnum)
return false;
out->name = &obj->shstrtab[obj->shdr64[index].sh_name];
out->link = obj->shdr64[index].sh_link;
out->info = obj->shdr64[index].sh_info;
out->flags = obj->shdr64[index].sh_flags;
out->align = obj->shdr64[index].sh_addralign;
out->entsize = obj->shdr64[index].sh_entsize;
out->offset = obj->shdr64[index].sh_offset;
out->address = obj->shdr64[index].sh_addr;
break;
default:
return false;
}
return true;
}
Looking for SHT_PROGBITS (set to 1 in elf.h)
[sad0p@Arch-Deliberate tmp]$ cat elfmaster_test1.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <elf.h>
#include <sys/types.h>
#include <search.h>
#include <sys/time.h>
#include "libelfmaster.h"
#define ERROR -1
int main(int argc, char **argv) {
elfobj_t obj;
elf_error_t error;
struct elf_section section;
unsigned int index;
if(argc != 3) {
printf("Usage: %s <test-bin-path> <section index>\n", *argv+2);
exit(ERROR);
}
index = atoi(argv[2]);
if (!elf_open_object(argv[1], &obj, ELF_LOAD_F_FORENSICS,&error)) {
printf("%s\n", elf_error_msg(&error));
exit(ERROR);
}
elf_section_by_index(&obj, index, §ion);
printf("Section Name: %s\n", section.name);
printf("Section Type: %u\n", section.type);
elf_close_object(&obj);
}
[sad0p@Arch-Deliberate tmp]$ cc elfmaster_test1.c -o elfmaster_test1 -I /opt/elfmaster/include/ -L /opt/elfmaster/lib/ -lelfmaster
[sad0p@Arch-Deliberate tmp]$ ./elfmaster_test1 ~/projects/libelfmaster/bindings/go/libelfmaster/test_bins/helloworld-intel64 14
Section Name: .text
Section Type: 4294967295
[sad0p@Arch-Deliberate tmp]$ ./elfmaster_test1 ~/projects/libelfmaster/bindings/go/libelfmaster/test_bins/helloworld-intel32 14
Section Name: .text
Section Type: 4294967295
[sad0p@Arch-Deliberate tmp]$ readelf -S ~/projects/libelfmaster/bindings/go/libelfmaster/test_bins/helloworld-intel64 | grep .text -A 1
[14] .text PROGBITS 0000000000001040 00001040
0000000000000118 0000000000000000 AX 0 0 16
[sad0p@Arch-Deliberate tmp]$ readelf -S ~/projects/libelfmaster/bindings/go/libelfmaster/test_bins/helloworld-intel32 | grep .text
[14] .text PROGBITS 00001060 001060 00016d 00 AX 0 0 16
Updated libelfmaster locally to initialize the field
bool
elf_section_by_index(struct elfobj *obj, uint32_t index, struct elf_section *out)
{
switch(obj->e_class) {
case elfclass32:
if (index >= obj->ehdr32->e_shnum)
return false;
out->name = &obj->shstrtab[obj->shdr32[index].sh_name];
out->type = obj->shdr32[index].sh_type;
out->link = obj->shdr32[index].sh_link;
out->info = obj->shdr32[index].sh_info;
out->flags = obj->shdr32[index].sh_flags;
out->align = obj->shdr32[index].sh_addralign;
out->entsize = obj->shdr32[index].sh_entsize;
out->offset = obj->shdr32[index].sh_offset;
out->address = obj->shdr32[index].sh_addr;
break;
case elfclass64:
if (index >= obj->ehdr64->e_shnum)
return false;
out->name = &obj->shstrtab[obj->shdr64[index].sh_name];
out->type = obj->shdr64[index].sh_type;
out->link = obj->shdr64[index].sh_link;
out->info = obj->shdr64[index].sh_info;
out->flags = obj->shdr64[index].sh_flags;
out->align = obj->shdr64[index].sh_addralign;
out->entsize = obj->shdr64[index].sh_entsize;
out->offset = obj->shdr64[index].sh_offset;
out->address = obj->shdr64[index].sh_addr;
break;
default:
return false;
}
return true;
}
Test run harness again with the updated libelfmaster returns the correct uint32_t
value that indicates section type SHT_PROGBITS
.
[sad0p@Arch-Deliberate tmp]$ ./elfmaster_test1 ~/projects/libelfmaster/bindings/go/libelfmaster/test_bins/helloworld-intel64 14
Section Name: .text
Section Type: 1
[sad0p@Arch-Deliberate tmp]$ ./elfmaster_test1 ~/projects/libelfmaster/bindings/go/libelfmaster/test_bins/helloworld-intel32 14
Section Name: .text
Section Type: 1
[sad0p@Arch-Deliberate tmp]$
#Update:
Also missing out->size = obj->shdr64[index].sh_size;
and out->size = obj->shdr32[index].sh_size;
diff@larry:~/libelfmaster $ make regressions
make -C regressions all || exit
make[1]: Entering directory '/home/diff/libelfmaster/regressions'
make[1]: *** No rule to make target 'parse_elfmaster.c', needed by 'parse_elfmaster'. Stop.
make[1]: Leaving directory '/home/diff/libelfmaster/regressions'
Makefile:23: recipe for target 'regressions' failed
make: *** [regressions] Error 2
diff@larry:~/libelfmaster $ cd regressions
diff@larry:~/libelfmaster/regressions $ ls -l
total 8
-rwxrwxr-x 1 diff diff 0 Dec 30 17:22 '*.c'
-rw-rw-r-- 1 diff diff 1120 Dec 30 17:22 Makefile
-rwxrwxr-x 1 diff diff 985 Dec 30 17:22 Makefile.in
diff@larry:~/libelfmaster/regressions $ file *
*.c: empty
Makefile: makefile script, ASCII text
Makefile.in: makefile script, ASCII text
Missing parse_elfmaster.c
at a minimum.
Please write a libelfmaster program that allows you to overwrite a specific .got.plt entry with a uintptr_t sized address. This address will either point into an absolute address range of a shared library due to prelinking, or it should point to some parasitic code within the binary itself, i.e. within a padding infection of some type.
The purpose of this tool is to essentially compliment the https://github.com/elfmaster/dt_infect program when it is using DT_DEBUG overwrite mode which does not create an automatic symbol hijacking since there is no interposition.
when using elf_symbol_value()
the logic in libelfmaster.c
doesn't account for the symbol value (represented by addr
in code below) being equal to symbol.value + symbol.size
. This will become an issue when the symbol.size
is 0
.
while (elf_dynsym_iterator_next(&dynsym_iter, &symbol) == ELF_ITER_OK) {
if (addr >= symbol.value && addr < symbol.value + symbol.size) {
memcpy(out, &symbol, sizeof(symbol));
return true;
}
}
elf_symtab_iterator_init(obj, &symtab_iter);
while (elf_symtab_iterator_next(&symtab_iter, &symbol) == ELF_ITER_OK) {
if (addr >= symbol.value && addr < symbol.value + symbol.size) {
memcpy(out, &symbol, sizeof(symbol));
return true;
}
}
Describe the bug
A bad elf file which can lead elf_open_object() to a segmentation fault.
Poc here:
poc3.zip
To Reproduce
$ ./elfparse ./segv2
Expected behavior
Parse elf file without segmentation fault because segmentation fault can cause a Denial of Service (Dos).
Environment (please complete the following information):
Additional context
ASAN says:
ASAN:DEADLYSIGNAL
=================================================================
==37981==ERROR: AddressSanitizer: SEGV on unknown address 0x7f9e2fbfa000 (pc 0x558fe2223c2c bp 0x7ffd4012e440 sp 0x7ffd4012e420 T0)
==37981==The signal is caused by a READ memory access.
#0 0x558fe2223c2b in resolve_plt_addr /home/ubuntu/some_c_test/libelfmaster/src/internal.c:1340
#1 0x558fe22287d6 in reconstruct_elf_sections /home/ubuntu/some_c_test/libelfmaster/src/internal.c:1917
#2 0x558fe221097a in elf_open_object /home/ubuntu/some_c_test/libelfmaster/src/libelfmaster.c:3237
#3 0x558fe21ecb04 in main /home/ubuntu/some_c_test/libelfmaster/examples/elfparse.c:38
#4 0x7f3e27be4c86 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21c86)
#5 0x558fe21eec19 in _start (/home/ubuntu/some_c_test/libelfmaster/fuzz/elfparse+0x8c19)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/ubuntu/some_c_test/libelfmaster/src/internal.c:1340 in resolve_plt_addr
==37981==ABORTING
Hello 👋
I run a security community that finds and fixes vulnerabilities in OSS. A researcher (@echel0nn) has found a potential issue, which I would be eager to share with you.
Could you add a SECURITY.md
file with an e-mail address for me to send further details to? GitHub recommends a security policy to ensure issues are responsibly disclosed, and it would help direct researchers in the future.
Looking forward to hearing from you 👍
(cc @huntr-helper)
I'm wondering how much work it'll take to support various architectures like ARM and AArch64 on top of what we already have.
Any ideas or suggestions on this?
Any thoughts or advice on this would be awesome
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.