diff --git a/README.md b/README.md index 1009baf..f53f11d 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,6 @@ - display protections - colorful - maybe display elf sections if command entered (??) + +- security: +enforce malloc secure fail diff --git a/a.out b/a.out index 33fe0fc..829193d 100755 Binary files a/a.out and b/a.out differ diff --git a/helpelf b/helpelf index 62041bf..3dec206 100755 Binary files a/helpelf and b/helpelf differ diff --git a/main.c b/main.c index 430fe32..fa9f6d3 100644 --- a/main.c +++ b/main.c @@ -44,11 +44,16 @@ #define PT_GNU_STACK 0x6474e551 #define SHT_DYNSYM 11 #define SHT_SYMTAB 2 +#define PT_GNU_RELRO 0x6474e552 +#define PT_DYNAMIC 2 +#define DT_BIND_NOW 24 +#define PT_INTERP 3 -#define Elf32_Half uint16_t -#define Elf32_Word uint32_t -#define Elf32_Addr uint32_t -#define Elf32_Off uint32_t +#define Elf32_Half uint16_t +#define Elf32_Word uint32_t +#define Elf32_Sword int32_t +#define Elf32_Addr uint32_t +#define Elf32_Off uint32_t #define Elf64_Half uint32_t #define Elf64_Word uint64_t @@ -59,6 +64,10 @@ bool verbose = false; bool pie = false; bool nx = false; bool canary = false; +bool relro = false; +bool bind_now = false; +bool stripped = true; +bool interp = false; struct Elf32_Ehdr { @@ -114,6 +123,16 @@ struct Elf32_Sym Elf32_Half st_shndx; }; +struct Elf32_Dyn +{ + Elf32_Sword d_tag; + union + { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + struct Elf64_Ehdr { unsigned char e_ident[EI_NIDENT]; @@ -181,7 +200,41 @@ void display_elf_common(unsigned char e_ident[EI_NIDENT]) } } -void display_elf32(struct Elf32_Ehdr* header) +void check_dynamic32(struct Elf32_Ehdr* header, FILE* fp) +{ + // Is dynamically linked? (has PT_INTERP program header?) + // read program headers + fseek(fp, header->e_phoff, SEEK_SET); + struct Elf32_Phdr *p_headers = malloc(header->e_phnum * sizeof(struct Elf32_Phdr)); + fread(p_headers, sizeof(struct Elf32_Phdr), header->e_phnum, fp); + + const char* interpstr = NULL; + + for (int i=0; ie_phnum; i++) + { + if (p_headers[i].p_type == PT_INTERP) + { + interp = true; + + // Get interpreter path + interpstr = malloc(p_headers[i].p_filesz); + fseek(fp, p_headers[i].p_offset, SEEK_SET); + fread((char*)interpstr, 1, p_headers[i].p_filesz, fp); + break; + } + } + + if (interp) + { + printf("dynamically linked (interpreter: %s), ", interpstr); + } + else + { + printf("statically linked, "); + } +} + +void display_elf32(struct Elf32_Ehdr* header, FILE* fp) { printf("32-bit ELF "); display_elf_common(header->e_ident); @@ -219,57 +272,51 @@ void display_elf32(struct Elf32_Ehdr* header) switch (header->e_machine) { case 0x00: - printf("No architecture,"); + printf("No architecture, "); break; case 0x01: - printf("AT&T WE 32100,"); + printf("AT&T WE 32100, "); break; case 0x02: - printf("SPARC,"); + printf("SPARC, "); break; case 0x03: - printf("i386,"); + printf("i386, "); break; case 0x04: - printf("Motorola 68000,"); + printf("Motorola 68000, "); break; case 0x05: - printf("Motorola 88000,"); + printf("Motorola 88000, "); break; case 0x07: - printf("Intel 80860,"); + printf("Intel 80860, "); break; case 0x08: - printf("MIPS RS3000,"); + printf("MIPS RS3000, "); break; case 0x09: - printf("MIPS RS4000,"); + printf("MIPS RS4000, "); break; default: - printf("Unknown architecture"); + printf("Unknown architecture, "); break; } if (verbose) { - printf("\ne_version: %d\n", header->e_version); - printf("e_entry: 0x%08x\n", header->e_entry); - printf("e_phoff: 0x%08x\n", header->e_phoff); - printf("e_shoff: 0x%08x\n", header->e_shoff); - printf("e_flags: 0x%08x\n", header->e_flags); - printf("e_ehsize: 0x%08x\n", header->e_ehsize); - printf("e_phentsize: 0x%08x\n", header->e_phentsize); - printf("e_phnum: 0x%08x\n", header->e_phnum); - printf("e_shentsize: 0x%08x\n", header->e_shentsize); - printf("e_shnum: 0x%08x\n", header->e_shnum); - printf("e_shstrndx: 0x%08x\n", header->e_shstrndx); + check_dynamic32(header, fp); } } +void check_nx32(struct Elf32_Ehdr* header, FILE* fp) +{ + +} + void check_sec32(struct Elf32_Ehdr* header, FILE* fp) { - - /* + /* NX: * Browse thru program header table (e_phnum items) from e_phoff (program header offset) * if its stack and has executable bit then we know NX isnt there */ @@ -291,7 +338,7 @@ void check_sec32(struct Elf32_Ehdr* header, FILE* fp) } } - /* + /* Stack canary: * Same for section header table (e_shnum items) from e_shoff (section header offset) * find sections .dynsym or .symtab: * and look for __stack_chk_fail (call for stack smashing) @@ -310,6 +357,9 @@ void check_sec32(struct Elf32_Ehdr* header, FILE* fp) for (size_t i=0; ie_shnum; i++) { + // additional small check for stripping as we're already browsing section headers + if (s_headers[i].sh_type == SHT_SYMTAB && s_headers[i].sh_size > 0) stripped = false; + if (s_headers[i].sh_type == SHT_DYNSYM || s_headers[i].sh_type == SHT_SYMTAB) { // load symbol table @@ -335,6 +385,50 @@ void check_sec32(struct Elf32_Ehdr* header, FILE* fp) } } } + + /* RELRO: + * Segment type PT_GNU_RELRO should be present + */ + + // Read program headers + fseek(fp, header->e_phoff, SEEK_SET); + struct Elf32_Phdr *p_headers = malloc(header->e_phnum * sizeof(struct Elf32_Phdr)); + fread (p_headers, sizeof(struct Elf32_Phdr), header->e_phnum, fp); + + Elf32_Off dyn_off = 0; + Elf32_Word dyn_size = 0; + + for (int i=0; ie_phnum; i++) + { + if (p_headers[i].p_type == PT_GNU_RELRO) + { + relro = true; + } + if (p_headers[i].p_type == PT_DYNAMIC) + { + dyn_off = p_headers[i].p_offset; + dyn_size = p_headers[i].p_filesz; + } + } + + if (dyn_off && dyn_size) + { + int n = dyn_size / sizeof(struct Elf32_Dyn); + struct Elf32_Dyn *dyns = malloc(dyn_size); + fseek(fp, dyn_off, SEEK_SET); + fread(dyns, sizeof(struct Elf32_Dyn), n, fp); + + for (int i=0; i