Security Protection Mechanism
TyeYeah Lv4

Binary vulnerabilities are executable files (PE, ELF files, etc.) that are not properly considered when encoding, causing softwares to perform unexpected functions.
Binary vulnerabilities include:

  • buffer(stack, bss or heap) overflow
  • integer overflow
  • format string vulnerability
  • use after free
  • race condition
  • sandbox escape
  • IO flie related

Security Protection Mechanism is needed for software security.

Linux Security Protection Mechanism

To pwn, the initial step to check file’s format is:

1
2
3
4
$ file xxxxx
xxxxx: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=294d1f19a085a730da19a6c55788ec08c2187039, stripped
#or
xxxxx: PE32+ executable (GUI) x86-64, for MS Windows

The next and important step is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$  checksec xxxxx
[*] '/root/xxxxx'
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE
FORTIFY: Enabled

or

$ gdb xxxxx
gdb-peda$ checksec
CANARY : disabled
FORTIFY : ENABLED
NX : ENABLED
PIE : disabled
RELRO : disabled

Now the question is, what are those above means?

Canary (GS)

Attacks caused by stack overflows are very common and very old. A mitigation technique called canary has long appeared in glibc and has been the first line of defense for system security.

Canary is simple and efficient in both implementation and design. It is to insert a value. At the end of the high-risk area where stack overflow occurs, when the function returns, check if the value of canary has been changed to determine whether stack/buffer overflow is occur.

Canary and GS protection under Windows are effective means to prevent stack overflow. Its appearance largely prevents stack overflow, and since it hardly consumes system resources, it has become the standard of protection mechanism under Linux.

Canary can be set in GCC using the following parameters:

1
2
3
4
5
6
7
8
9
10
11
12
13
-fstack-protector (default)
# enables protection, but inserts protection only for functions that contain arrays in local variables

-fstack-protector-all
# enable protection, insert protection for all functions

-fstack-protector-strong

-fstack-protector-explicit
# enables protection only for functions with explicit stack_protect attribute

-fno-stack-protector
# Disable protection.

Fortify

This has something to do with a macro: _FORTIFY_SOURCE

Defining this macro causes some lightweight checks to be performed to detect some buffer overflow errors when employing various string and memory manipulation functions (for example, memcpy, memset, stpcpy, strcpy, strncpy, strcat, strncat, sprintf, snprintf, vsprintf, vsnprintf, gets, and wide character variants thereof).

For some functions, argument consistency is checked; for example, a check is made that open has been supplied with a mode argument when the specified flags include O_CREAT. For printf the %n is forbidden and %num$s can only exist when %num-1$s, %num-2$s, … %2$s and %1$s(%s) all exist. Not all problems are detected, just some common cases.

Some of the checks can be performed at compile time (via macros logic implemented in header files), and result in compiler warnings; other checks take place at run time, and result in a run-time error if the check fails.

Use of this macro requires compiler support, available with gcc since version 4.0.

Fortify can be set in GCC using the following parameters:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-U_FORTIFY_SOURCE 
# Disable protection (default)

-D_FORTIFY_SOURCE=1
# level 1
# If _FORTIFY_SOURCE is set to 1, with compiler optimization level 1 (gcc -O1) and above, checks that shouldn't change the behavior of conforming programs are performed.

# As for 'compiler optimization', it's for producing better machine codes.
# to be brief, this level only protect codes without optimization.

-D_FORTIFY_SOURCE=2
# level 2
# With _FORTIFY_SOURCE set to 2, some more checking is added, but some conforming programs might fail.
# This level protects codes anyway.

NX (DEP)

The basic principle of NX (No-eXecute) is to identify the memory page where the data is located as non-executable.

When the program overflows and transfers to shellcode successfully, the program will try to execute instructions on the data page, and the CPU will throw an exception instead of executing malicious instructions.

The principle is the same as DEP under windows.

NX can be set in GCC using the following parameters:

1
2
3
4
5
-z execstack 
# Disable protection

-z noexecstack
# Enable protection (default)

PIE (ASLR)

In general, NX (called DEP on Windows platforms) and Address Space Distribution Randomization (ASLR) will work simultaneously.

Memory address randomization mechanism (address space layout randomization) has three levels

  • 0: off ASLR. no randomization, same base address for stack & heap, and same address for libc.so
  • 1: normal ASLR. random base address for mmap, stack and libc.so , but not randomize for heap
  • 2: advanced/enhanced ASLR, random heap address added

Check ASLR condition

1
2
3
4
5
$ sysctl -n kernel.randomize_va_space
1
# or
$ cat /proc/sys/kernel/randomize_va_space
1

Off ASLR (same way as changing level)

1
2
3
$ sysctl -w kernel.randomize_va_space=0
# or
$ echo 0 > /proc/sys/kernel/randomize_va_space

As for PIE : Position-Independent-Executable
It’s the name for ASLR on Linux.

Difference:

  • PIE (on executable) is a power giver. It enables program to randomize address or not.
  • ASLR (on process) is the power user. It tells operating system to do program address randomization.

PIE can be set in GCC using the following parameters:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-no-pie # Disable PIE (default)
-fpie -pie # Enable PIE, level 1
-fPIE -pie # Enable PIE, level 2

# '-fpie' and '-fPIE' used for compilation, and '-pie' used for linking
# '-pie' is necessary for '-fpie' and '-fPIE'

-fpic # Enable PIC, level 1, but disable PIE
-fPIC # Enable PIC, level 2, but disable PIE

# '-fpic'
# If the GOT size for the linked executable exceeds a machine-specific maximum size, you get an error message from the linker indicating that -fpic does not work; in that case, recompile with -fPIC instead. (These maximums are 8k on the SPARC and 32k on the m68k and RS/6000. The 386 has no such limit.)

# '-fPIC'
# If supported for the target machine, emit position-independent code, suitable for dynamic linking and avoiding any limit on the size of the global offset table. This option makes a difference on the m68k, PowerPC and SPARC. Position-independent code requires special support, and therefore works only on certain machines.

As for PIC : Position-Independent Code
The difference between PIE and PIC:
PIE parameter is for executable files
PIC parameter is for shared library

RELRO

In the area of Linux system security, the data storage area that can be written will be the target of the attack, especially the area where function pointers are stored. So from the perspective of security protection, minimizing the writable storage area will be of great benefit to security.

GCC, GNU linker, and Glibc-dynamic linker work together to implement a technology called RELRO: read only relocation. The approximate implementation is setting the area of the binary specified by the linker after the dynamic linker has processed the relocation as read-only.

1
2
3
-z norelro # No RELRO
-z lazy # Partial RELRO (default)
-z now # Full RELRO

Sum-Up

NX:-z execstack / -z noexecstack (Off / On)
Canary:-fno-stack-protector /-fstack-protector / -fstack-protector-all (Off / On / All Func On)
PIE:-no-pie / -pie (Off / On)
RELRO:-z norelro / -z lazy / -z now (Off / Partial / Full)

Windows Security Protection Mechanism

There’re always many compiling options in Visual Studio when coding.
They can be set in Visual Studio before compilation.
Some parameters explained as below.

GS

Similar to Canary.
After the GS option is enabled, a piece of data is saved on the stack at the beginning of the function execution, and the data is checked when the function returns. If it is inconsistent, it is overwritten, so it jumps into the corresponding processing process and no longer returns, so the shellcode cannot be executed, this value is called “Security cookie”. Software calls Check_Security_Cookie () to check whether the stack is covered.

SafeSEH

Canary is useful for stack overflow.
However, they ignored that the SEH chain of exception handling is also on the stack, so they can overwrite the address of the SEH chain as jmp esp, and then trigger an exception to jump to the esp to execute the shellcode.

SafeSEH registers all exception handling functions when the program is compiled to a registered list. After an exception is triggered during execution, a check function is performed to check whether the address pointed to by the SEH chain is in the registered list.

DEP

Similar to NX.
However, in the logic of the check function, the execution is prevented only when the SEH chain points/links to the module (exe, dll) address. If the address pointed/linked to by the SEH chain is not in these modules, then it can be executed. Therefore, the program is not a module Find the jmp esp in the data space, such as the resource file with the nls suffix, etc., or in software that supports JS scripts (browser, etc.) bypass by writing shellcode through the script to allocated heap.

Data execution protection (DEP) refers to the heap and stack with only read and write permissions and no execute permissions. Therefore no shellcodes can be executed.

ASLR

Similar to PIE.
Load code to random space to prevent ROP.

CFG

CFI stands for Control-Flow Integrity.
It mainly adds dynamic security to the binary executable file by dynamically rewriting it.

e.g.
Insert a check ID agreed in the rewrite before the destination address of jmp, and check if the data in front of the destination address is the agreed check ID in jmp. If not, enter the error processing flow.
example1
Insert the check ID before the destination address of the call and the return address of ret, and then the check of the check ID is added to the rewritten call and ret. If it does not meet the expectations, enter the error processing flow.
example2

The implementation of CFI requires that when jmp, or call to a register (or use register indirect addressing), the destination address must sometimes be obtained dynamically, and the overhead of rewriting is very large, which has caused certain difficulties in the practical application of CFI.

CFG is the abbreviation of Control Flow Guard, which is a control flow protection. It is a combination of compiler and operating system protection, the purpose is to prevent untrusted indirect calls.

In the course of the vulnerability attack, a common exploitation method is to overwrite or directly tamper with the value of a register, tamper with the address of the indirect call, and then control the program execution flow. CFG records all indirect call information during compilation and linking, and records them in the final executable file, and inserts additional checks before all indirect calls. When the address of the indirect call is tampered, An exception is triggered and the operating system intervenes.

Powered by Hexo & Theme Keep
Total words 135.7k