App vulnerability scanning with address space randomization
Preface
In the previous article, "app vulnerability scanner local denial of service detection," learned that the Ali-Poly security vulnerability Scanner has a static analysis plus dynamic fuzzy testing method to detect the function, and detailed description of it in the local denial of service detection method.
At the same time, the Ali-Poly Vulnerability Scanner has a detection term called the unused address space randomization technique, which analyzes the elf files contained in the app to determine if they are using the technology . If the vulnerability exists in the app, the threshold for buffer overflow attacks is lowered.
This paper mainly introduces the principle of this technology and the detection method of the scanner. Because the implementation details of PIE are more complex, this article only introduces the approximate principle. Students who want to learn more about the details can refer to Pan's book "Programmer self-accomplishment".
What is pie?
PIE (position-independent executable) is a technique for generating address-independent executable programs . If the compiler uses pie in the process of generating an executable program, its load address is unpredictable when the executable program is loaded into memory.
Pie also has a twin brother pic (position-independent code). The function is the same as pie, which allows the compiled program to randomly load to a memory address. The difference is that pic is used when generating a dynamic link library (so in Linux), and pie is used when generating executables.
the role of PIE
Security
Pie can raise the threshold for buffer overflow attacks. It is part of the ASLR (Address space layout randomization). ASLR requires that an executing program be loaded into memory, and any part of it is random. include
Stack, Heap, Libs and Mmap, executable, Linker, Vdso. with PIE We can achieve executable memory randomization
save space for memory usage
In addition to security, the address-independent code has an important role to play in improving memory usage efficiency.
A shared library can be loaded by multiple processes at the same time, and if it is not an address-independent code (an absolute address reference exists in the code snippet), each process must call the dynamic-link library in conjunction with its native memory address. Causes the shared library to be copied to the process as a whole. If there are 100 processes in the system that call this library, there will be 100 copies of the library in memory, which can be a huge waste of space.
Conversely, if the shared library being loaded is an address-independent code and 100 processes call the library, the library needs to be loaded only once in memory. This is because pie separates the content in the shared library from the pieces that need to be transformed into data segments. Causes the code snippet to load into memory to be address independent. When multiple processes call a shared library, only the data segments of the shared library are loaded in their own process, and the code snippets can be shared.
Introduction to how PIE works
We start with practical examples to observe the difference between pie and No-pie in the performance of executable programs. Glimpse explores the implementation principle of address-independent code.
Example One
Define the following C code:
#include <stdio.h>int global;void main(){ printf("global address = %x\n", &global);}
A global variable is defined in the program and its address is printed. We first compile the program in a normal way.
gcc -o sample1 sample1.c
The running program can observe that the address that global loads into memory is the same every time.
$./sample1global6008a8$./sample1global6008a8$./sample1global6008a8
Then we compile sample1.c in pie mode.
-o sample1_pie sample1.-fpie-pie
Run the program to observe the results of global output:
./sample1_pieglobal1ce72b38./sample1_pieglobal4c0b38./sample1_pieglobal766dcb38
A transformation occurs every time the address is run, indicating that PIE makes the address of the executing program loaded into memory random every time.
Example Two
Declare an external variable, global in your code. However, the definition of this variable is not included in the compiled file.
#include <stdio.h>externint global;void main(){ printf("extern global address = %x\n", &global);}
First compile the extern_var.c using the normal way. The source file containing the global definition is intentionally not wrapped in the compilation options.
gcc -o extern_var extern_var.c
Discovery cannot be compiled by, GCC hint:
`main‘:extern_var.c:(.text+0xa): undefined reference to `global‘collect2: ld returned 1 exit status
The compiler has an important action called symbolic parsing and relocation during the link phase. The linker merges the data, code, and symbols of all intermediate files together, and calculates the virtual base address of the link. For example, the ". Text" segment starts with 0x1000, and the ". Data" segment starts with 0x2000. The linker then calculates the relative virtual address of each symbol (global) based on the base address.
When the compiler finds that the address of global is not found in the symbol table, it is reported that during undefined reference to `global`.
static linking the compiler must complete a link to all symbols during the compile link phase.
What happens if you use pie to compile extern_var.c into a share library?
-o extern_var.so extern_var.-shared-fPIC
The program can be compiled smoothly by generating extern_var.so. However, the runtime will error because the global symbol destination address cannot be found when loading. This indicates that the-FPIC option generates an address-independent code. Link work to a global symbol that is not found when statically linked is deferred to the load stage.
So at the compile link stage, how does the linker address the missing destination address in the code snippet?
The linker cleverly uses an intermediate table got (Global Offset table) to solve the problem of missing destination addresses for the referenced symbols. If you find a symbol in the link stage (Jing Tai) that cannot determine the destination address. The linker adds the symbol to the got table and replaces all references to that symbol with the address of the symbol in the Got table. To the load stage the dynamic linker fills in the actual destination address for each symbol in the Got table.
When the program executes the code corresponding to the symbol, the program first checks the location of the corresponding symbol in the Got table, and then locates the actual destination address of the symbol based on the location.
how address-independent code is generated
The so-called address-independent code requires that the program be loaded into memory for any address to execute properly. So a reference to a variable or function in a program must be relative and cannot contain an absolute address.
For example, the following pseudo-assembly code:
Pie mode: code can run at address 100 or 1000
100: COMPARE REG1, REG2101: JUMP_IF_EQUAL CURRENT+10...111: NOP
Non-pie: code can only run at address 100
100: COMPARE REG1, REG2101111...111: NOP
Because the code snippet for an executable program has no write properties for only the Read and execute properties, the data segment has read-write properties. To implement the address-independent code, separate the absolute values that need to be changed in the code snippet into the data segment. The code snippet can be persisted when the program is loaded, and the address-independent code is implemented by changing the contents of the data segment.
how pie and Non-pie programs are mapped in memory
Each time the program is loaded into memory at Non-pie, the same location is the same.
The execution program starts loading at a fixed address. The system's dynamic Linker library ld.so will load first, and then Ld.so will find other shared libraries that need to be loaded by using fields of type dt_need in the. Dynamic segment. And then load them into memory in turn. Note: Because of the non-pie mode, these dynamic link libraries are loaded in the same order and position each time.
For executing programs that are generated by pie, the addresses are loaded differently each time because there is no absolute address reference.
Not only the load address of the dynamic link library is not fixed, but even the address of the executing program loading is not the same. This requires that ld.so be loaded first, it is not only responsible for relocating the other shared libraries, but also to relocate the executable files.
Pie and Compiler options
The parameters used by the GCC compiler to generate address-independent code are mainly-fpic,-fpie,-pie.
Where-fpic,-fpie is a compile-time option for generating shared libraries and executables, respectively. They enable the intermediate code generated during the compilation phase to have the attribute of address-independent code. However, this does not mean that the last generated executable file is pie. You also need to tell the linker to generate an executable program of address-independent code at link time through the-pie option.
A standard PIE program compiles the following settings:
-o sample_pie sample.-fPIE-pie
The corresponding relationship between using the compile option in GCC and whether to generate a pie executable file is as follows:
The type for Dyn program supports PIE,EXEC types not supported. DYN, the corresponding relationship between exec and Pie is described later in this article.
The application of ASLR in Android
Pie is part of the ASLR, as mentioned in the previous section, ASLR includes randomization of the stack, Heap, Libs and Mmap, executable, Linker, Vdso.
The support for pie only means that ASLR is implemented for executable. With the development of Android, the support for ASLR is growing.
ASLR in Android 2.x
Android support for ASLR starts with Android 2.x. 2.x only supports randomization of the stack.
ASLR in Android 4.0
In 4.0, the so-called ASLR support version, the ASLR has only increased the randomization of some shared libraries such as libc, and for the heap, executable and linker are still static.
For the randomization of the heap, you can
2/proc/sys/kernel/randomize_va_space
To open.
For executable randomization, because most binary does not have GCC's-pie-fpie option, it compiles exec instead of dyn this shared object file, so it is not pie (Position Independent executable), so there is no way of randomization;
The same linker did not do ASLR.
ASLR in Android 4.1
Finally, in the 4.1 Jelly Bean, Android supports all of the memory ASLR. In Android 4.1, basically all binary is compiled and concatenated into the pie pattern (you can view its type by readelf). Therefore, the heap,executable and linker are provided with ASLR support compared to 4.0,4.1.
ASLR in Android 5.0
Android 5.0 has abandoned its support for Non-pie, and all processes are ASLR. If the program does not open pie, it will be error-free at run time and forced to quit.
The pie program runs on Android versions
The executable program that supports PIE can only run on 4.1+ versions. Crash will appear before the 4.1 release. And the Non-pie program, before the 5.0 version can run normally, but in 5.0 will crash.
how to detect if pie is turned on
The Execute program that does not open pie uses readelf to see that its file type should show the exec (executable file), and the executable program that opens the pie has the file type dyn (shared destination file). In addition, the virtual address of the code snippet always starts at 0.
Why test dyn to determine if pie is supported?
Dyn refers to the type of the file, which is the shared target file. So all the shared target files must be pie-enabled? We can find the answer from the source code. View the code in the GLIBC/GLIBC-2.16.0/ELF/DL-LOAD.C.
It is known from the source that the map_fixed flag is passed in when the mmap load file is called when the loading type is not Et_dyn. Maps a program to a fixed address.
recommendations in the security development of Ali Poly
- Systems prior to Android 2.x-4.1 do not use the option to generate pie at compile time.
- Later versions of Android 4.1 must use PIE to generate the native program, increasing the cost of attack in the attacker.
- Use the security vulnerability scanning system for secure scanning prior to release, blocking security breaches before release.
Reference
- Https://en.wikipedia.org/wiki/Position-independent_code
- http://www.openbsd.org/papers/nycbsdcon08-pie/
- Https://source.android.com/security/enhancements/enhancements50.html
- Http://ytliu.info/blog/2012/12/09/aslr-in-android/
- https://codywu2010.wordpress.com/2014/11/29/about-elf-pie-pic-and-else/
- Http://www.cnblogs.com/huxiao-tee/p/4660352.html
- Http://stackoverflow.com/questions/5311515/gcc-fpic-option
Hang Fox @ Ali Poly Security, more Android, iOS technical articles, please visit the security blog Ali Poly
The unused address space randomization of the app vulnerability scanner