Binary Files
hacker@program-misuse~level51:~$ file /usr/bin/cat
/usr/bin/cat: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b357ed53c8c9cb1a312f83b28982304effae0135, for GNU/Linux 3.2.0, stripped
ELF contains section headers
hacker@program-misuse~level51:~$ readelf -e /usr/bin/cat
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 (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x31f0
Start of program headers: 64 (bytes into file)
Start of section headers: 41496 (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: 30
Section header string table index: 29
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000318 00000318
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.propert NOTE 0000000000000338 00000338
0000000000000020 0000000000000000 A 0 0 8
[ 3] .note.gnu.build-i NOTE 0000000000000358 00000358
0000000000000024 0000000000000000 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000037c 0000037c
0000000000000020 0000000000000000 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003a0 000003a0
000000000000006c 0000000000000000 A 6 0 8
[ 6] .dynsym DYNSYM 0000000000000410 00000410
0000000000000690 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 0000000000000aa0 00000aa0
000000000000033d 0000000000000000 A 0 0 1
[ 8] .gnu.version VERSYM 0000000000000dde 00000dde
000000000000008c 0000000000000002 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000e70 00000e70
0000000000000060 0000000000000000 A 7 1 8
[10] .rela.dyn RELA 0000000000000ed0 00000ed0
0000000000000378 0000000000000018 A 6 0 8
[11] .rela.plt RELA 0000000000001248 00001248
0000000000000498 0000000000000018 AI 6 25 8
[12] .init PROGBITS 0000000000002000 00002000
000000000000001b 0000000000000000 AX 0 0 4
[13] .plt PROGBITS 0000000000002020 00002020
0000000000000320 0000000000000010 AX 0 0 16
[14] .plt.got PROGBITS 0000000000002340 00002340
0000000000000010 0000000000000010 AX 0 0 16
[15] .plt.sec PROGBITS 0000000000002350 00002350
0000000000000310 0000000000000010 AX 0 0 16
[16] .text PROGBITS 0000000000002660 00002660
0000000000003dc2 0000000000000000 AX 0 0 16
[17] .fini PROGBITS 0000000000006424 00006424
000000000000000d 0000000000000000 AX 0 0 4
[18] .rodata PROGBITS 0000000000007000 00007000
000000000000122c 0000000000000000 A 0 0 32
[19] .eh_frame_hdr PROGBITS 000000000000822c 0000822c
00000000000002bc 0000000000000000 A 0 0 4
[20] .eh_frame PROGBITS 00000000000084e8 000084e8
0000000000000ce8 0000000000000000 A 0 0 8
[21] .init_array INIT_ARRAY 000000000000aa90 00009a90
0000000000000008 0000000000000008 WA 0 0 8
[22] .fini_array FINI_ARRAY 000000000000aa98 00009a98
0000000000000008 0000000000000008 WA 0 0 8
[23] .data.rel.ro PROGBITS 000000000000aaa0 00009aa0
0000000000000198 0000000000000000 WA 0 0 32
[24] .dynamic DYNAMIC 000000000000ac38 00009c38
00000000000001f0 0000000000000010 WA 7 0 8
[25] .got PROGBITS 000000000000ae28 00009e28
00000000000001c8 0000000000000008 WA 0 0 8
[26] .data PROGBITS 000000000000b000 0000a000
00000000000000c0 0000000000000000 WA 0 0 32
[27] .bss NOBITS 000000000000b0c0 0000a0c0
0000000000000198 0000000000000000 WA 0 0 32
[28] .gnu_debuglink PROGBITS 0000000000000000 0000a0c0
0000000000000034 0000000000000000 0 0 4
[29] .shstrtab STRTAB 0000000000000000 0000a0f4
000000000000011d 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
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
0x00000000000016e0 0x00000000000016e0 R 0x1000
LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000
0x0000000000004431 0x0000000000004431 R E 0x1000
LOAD 0x0000000000007000 0x0000000000007000 0x0000000000007000
0x00000000000021d0 0x00000000000021d0 R 0x1000
LOAD 0x0000000000009a90 0x000000000000aa90 0x000000000000aa90
0x0000000000000630 0x00000000000007c8 RW 0x1000
DYNAMIC 0x0000000000009c38 0x000000000000ac38 0x000000000000ac38
0x00000000000001f0 0x00000000000001f0 RW 0x8
NOTE 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000020 0x0000000000000020 R 0x8
NOTE 0x0000000000000358 0x0000000000000358 0x0000000000000358
0x0000000000000044 0x0000000000000044 R 0x4
GNU_PROPERTY 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000020 0x0000000000000020 R 0x8
GNU_EH_FRAME 0x000000000000822c 0x000000000000822c 0x000000000000822c
0x00000000000002bc 0x00000000000002bc R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000009a90 0x000000000000aa90 0x000000000000aa90
0x0000000000000570 0x0000000000000570 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 .rela.plt
03 .init .plt .plt.got .plt.sec .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
Program Header Types
- INTERP: 定义了需要被load的library
- LOAD: 定义了需要被放入内存的ELF 文件part
ELF Section Headers, 可能并不在ELF中。只有segments是必要的,section headers只是一些可选的metadata
.text: executable code of the program
.plt and .got: used to resolve and dispatch library calls
.data: pre-initilized global writable data
.rodata: global read-only data, such as string constants
.bss: uninitialized global writable data
常用工具:
- gcc
- readelf
- objdump: disassemble
- nm: view the symbols
- patchelf: change some properties
- objcopy: swap out ELF sections
- strip: remove some information, like symbols
- https://ide.kaitai.io/
- kaitai的解析在obj tree上
https://intezer.com/blog/research/executable-linkable-format-101-part1-sections-segments/
Overview
ELF文件通常包含以下元素:ELF Header, Sections和Segments。只有Segment是必要的
ELF Headers
General information
readelf -h main
struct Elf64_Ehdr
- e_ident: Array of 16 bytes containing identification flags about the file, which serve to decode and interpret the file’s contents. Examples of these identification flags include:
- EI_MAG0-3: ELF magicELF Header
- EI_CLASS: File class.
- EI_DATA: File’s data encoding.
- EI_VERSION: File’s version.
- EI_OSABI: OS/ABI identification.
- EI_ABIVERSION: ABI version
- EI_PAD: Start of padding bytes.
- EI_NIDENT: Size of ei_ident.
- e_type: Type of executable.
- e_machine: File’s architecture.
- e_version: Object file version.
- e_entry: Entry point of application.
- e_phoff: File offset of the Program Header Table.
- e_shoff: File offset of the Section Header Table.
- e_flags: Processor-specific flags associated with the file.
- e_ehsize: ELF header size.
- e_phentsize: Program Header entry size in Program Header Table.
- e_phnum: Number of Program Headers.
- e_shentsize: Section Header entry size in Section Header Table.
- e_shnum: Number of Section Headers.
- e_shstrndx: index in Section Header Table Denoting Section dedicated to Hold Section names.
ELF Sections
用于链接的信息
readelf -S main
struct ELF64_Shdr
- sh_name: index of section name in section header string table.ELF Header
- sh_type: section type.
- sh_flags: section attributes.
- sh_addr: virtual address of section.
- sh_offset: section offset in disk.
- sh_size: section size.
- sh_link: section link index.
- sh_Info: Section extra information.
- sh_addralign: section alignment.
- sh_entsize: size of entries contained in section.
common sections:
- .text: code.
- .data: initialised data.
- .rodata: initialised read-only data.
- .bss: uninitialized data.
- .plt: PLT (Procedure Linkage Table) (IAT equivalent).
- .got: GOT entries dedicated to dynamically linked global variables.
- .got.plt: GOT entries dedicated to dynamically linked functions.
- .symtab: global symbol table.
- .dynamic: Holds all needed information for dynamic linking.
- .dynsym: symbol tables dedicated to dynamically linked symbols.
- .strtab: string table of .symtab section.
- .dynstr: string table of .dynsym section.
- .interp: RTLD embedded string.
- .rel.dyn: global variable relocation table.
- .rel.plt: function relocation table.
ELF Segments
描述如何将ELF放入内存,在link时不需要,又名为Program Header
Program Header Table
struct ELF64_Phdr
- p_type: Segment type.ELF Header
- p_flags: Segment attributes.
- p_offset: File offset of segment.
- p_vaddr: Virtual address of segment.
- p_paddr: Physical address of segment.
- p_filesz: Size of segment on disk.
- p_memsz: Size of segment in memory.
- P_align: segment alignment in memory
常见segment type
PT_NULL: unassigned segment (usually first entry of Program Header Table).
PT_LOAD: Loadable segment.
PT_INTERP: Segment holding .interp section.
PT_TLS: Thread Local Storage segment (Common in statically linked binaries).
PT_DYNAMIC: Holding .dynamic section.
Sections and Segments
segment将sections按照类型等合在一起了
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 .rela.plt
03 .init .plt .plt.got .plt.sec .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
segment的p_align必须要是system page size的倍数,防止多个segments被放入同一个memory page中。因为不同的segments的执行属性不同
https://intezer.com/blog/malware-analysis/executable-linkable-format-101-part-2-symbols/
符号:机器码中的符号可以只用offset和address来定义,但是ELF文件中通常还包含更详尽的符号信息,用于dynamic linking和debugger。
struct Elf64_Sym{
Elf64_Word st_name; unsigned char st_info, st_other; Elf64_Half st_shndx; Elf64_Addr st_value; Elf64_Xword st_size;}
The Elements of this structure include:
- st_name: index in string table of symbol name. If this field is not initialized, then the symbol doesn’t have a name
- st_info: contains symbol bind and type attributes. Binding attributes determine the linkage visibility and behavior when a given symbol is referenced by an external object.
- The most common symbol binds are the following:
- STB_LOCAL: Symbol is not visible outside the ELF object containing the symbol definition.
- STB_GLOBAL: Symbol is visible to all object files.
- STB_WEAK: Representing global symbols, but their definition can be overridden.
- The most common symbol types are the following:
- STT_NOTYPE: symbol type is not specified
- STT_OBJECT: symbol is a data object (variable).
- STT_FUNC: symbol is a code object (function).
- STT_SECTION: symbol is a section.
- In order to retrieve these fields, a set of bitmasks are used. These bitmasks include:
- ELF64_ST_BIND(info) ((info) >> 4)
- ELF64_ST_TYPE(info) ((info) & 0xf)
- The most common symbol binds are the following:
- st_other: information about symbol visibility. Symbol visibility defines how a given symbol may be accessed once the symbol has become part of an executable or shared object. Some common symbol visibilities are the following:
- STV_DEFAULT: for default visibility symbols, its attribute is specified by the symbol’s binding type.
- STV_PROTECTED: symbol is visible by other objects, but cannot be preempted.
- STV_HIDDEN: symbol is not visible to other objects.
- STV_INTERNAL: symbol visibility is reserved.
- ELF64_ST_VISIBILITY(o) ((o) & 0x3)
- st_shndx: Every symbol entry within the Symbol Table is associated with a section. This value specifies the section index within the Section Header Table associated with the given symbol. Common values for section type field include:
- SHT_UNDEF: section is not present in current object. This value is typically set in symbols that have been imported from external objects.
- SHT_PROGBITS: section is defined in current object.
- SHT_SYMTAB, SHT_DYNSYM: Symbol Table (.symtab, .dynsym).
- SHT_STRTAB, SHT_DYNSTR: String Table (.strtab, .dynstr).
- SHT_REL: Relocation Table without explicit addends (.rel.dyn, .rel.plt).
- SHT_RELA: Relocation Table with explicit addends (.rela.dyn, .rela.plt).
- SHT_HASH: Hash Table for dynamic symbol resolution (.gnu.hash)
- SHT_DYNAMIC: section holding Dynamic Linking information (.dynamic)
- SHT_NOBITS: section takes no space in disk (.bss).
- st_value: This field specifies the symbol value for a given Symbol Table entry. The interpretation of this field can vary depending on the object type.
- For ET_REL files st_value holds a section offset. The section in which this offset resides is specified on its st_shndx field.
- For ET_EXEC / ET_DYN files, st_value holds a virtual address. If this field contains a value of 0 and the symbol’s section pointed by st_shndx has a sh_type field of type SHT_UNDEF, the symbol is an imported relocation, and its value will be resolved at runtime by the RTLD (ld.so).
- st_size: Field containing symbol’s size.
st_info
高4位是symbol binding, st_other
低2位是symbol visibility。符号可见性由该符号的宿主对象绑定,应用于任何引用它的外部对象,让static linking能够看到符号,允许override。symbol binding则是由the object that ref the symbol决定,让dynamic linking(dynamic loader)允许加载其定义,允许preempt. STB_GLOBAL
可以override STB_WEAK
。STB_GLOBAL
可被preempted
// libmath.c
int add(int a, int b) {
return a + b;
}
__attribute__((visibility("hidden")))
int subtract(int a, int b) {
return a - b;
}
STB_GLOBAL with STV_HIDDEN:
This combination is also possible. It means the symbol is globally visible (STB_GLOBAL) but not visible to other object files or shared libraries (STV_HIDDEN).
If a program tries to use this symbol, the linker will successfully resolve the symbol, but it will not be exported by the dynamic linker, making it inaccessible to other components linked against the same shared library or object file.
效果同STB_LOCAL
和STV_HIDDEN
差不多,但是可能可以被用于优化
符号表
https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
https://intezer.com/blog/malware-analysis/executable-linkable-format-101-part-4-dynamic-linking/
Linux Process Loading
Linux Process Execution
Helpful Resources
For launching programs from Python, we recommend using pwntools, but subprocess should work as well. If you are not using one of these two, you will suffer heavily when you get to input redirection (for that, check out the stdin and stdout arguments to pwn.process or subprocess.Popen).
For reading and writing directly to file descriptors in bash, check out the read and echo builtins.
You will find the env command useful, and the exec bash builtin.
Quick refreshers on fork() versus exec*() here and here and here.
Remember to wait() on your children! If you use subprocess.Popen, pwn.process, or good old fork(), your parent will keep executing and, unless it waits for the child in some way, will just terminate! This is almost never what you want.
Some documentation on networking in C.
Useful resource for pipes in C.
Useful resource for FIFOs in C.
A treatise on I/O redirection in Linux shells, which has applications in this assignment: https://web.archive.org/web/20220629044814/http://bencane.com:80/2012/04/16/unix-shell-the-art-of-io-redirection/
A guide on Linux symbolic links. https://www.nixtutor.com/freebsd/understanding-symbolic-links/
A video tutorial on FIFOs in C.
A great visual guide to I/O redirection in Linux.
An incredible pwntools cheatsheet by a pwn.college student!
A deep dive into the history and technology behind command line terminals.
Practices
继承父进程的File Descriptor可能带来潜在危险: File descriptors are inherited from the parent, unless the FD_CLOEXEC is set by the parent on the file descriptor. For security reasons, some programs, such as python, do this by default in certain cases. Be careful if you are creating and trying to pass in FDs in python.
launch program with empty env: env -i /challenge/embryoio_level7
process.cmdline()
如果process parent终止了但是子进程没有终止,parent process就会成为PID=1的那个进程 This process is the initialization process of your docker container (aka PID 1). When the parent of a process terminates, that process is 'reparented' to PID 1. So, the likely situation here is that your parent process terminated before waiting on the child. Go fix that