JIT spraying

Last updated

JIT spraying is a class of computer security exploit that circumvents the protection of address space layout randomization and data execution prevention by exploiting the behavior of just-in-time compilation. [1] It has been used to exploit the PDF format [2] and Adobe Flash. [3]

A just-in-time compiler (JIT) by definition produces code as its data. Since the purpose is to produce executable data, a JIT compiler is one of the few types of programs that cannot be run in a no-executable-data environment. Because of this, JIT compilers are normally exempt from data execution prevention. A JIT spray attack does heap spraying with the generated code.

To produce exploit code from JIT, an idea from Dion Blazakis [4] is used. The input program, usually JavaScript or ActionScript, typically contains numerous constant values that can be erroneously executed as code. For example, the XOR operation could be used: [5]

vara=(0x11223344^0x44332211^0x44332211^...);

JIT then will transform bytecode to native x86 code like:

0:  b8 44 33 22 11      mov$0x11223344,%eaxmoveax,0x11223344 5:  35 11 22 33 44      xor$0x44332211,%eaxxoreax,0x44332211 a:  35 11 22 33 44      xor$0x44332211,%eaxxoreax,0x44332211

The attacker then uses a suitable bug to redirect code execution into the newly generated code. For example, a buffer overflow or use after free bug could allow the attack to modify a function pointer or return address.

This causes the CPU to execute instructions in a way that was unintended by the JIT authors. The attacker is usually not even limited to the expected instruction boundaries; it is possible to jump into the middle of an intended instruction to have the CPU interpret it as something else. As with non-JIT ROP attacks, this may be enough operations to usefully take control of the computer. Continuing the above example, jumping to the second byte of the "mov" instruction results in an "inc" instruction:

1:  44                  inc%espincesp 2:  33 22               xor(%edx),%espxoresp,DWORDPTR[edx] 4:  11 35 11 22 33 44   adc%esi,0x44332211adcDWORDPTRds:0x44332211,esi a:  35 11 22 33 44      xor$0x44332211,%eaxxoreax,0x44332211

x86 and x86-64 allow jumping into the middle of an instruction, but not fixed-length architectures like ARM.

To protect against JIT spraying, the JIT code can be disabled or made less predictable for the attacker. [4]

Related Research Articles

<span class="mw-page-title-main">Assembly language</span> Low-level programming language

In computer programming, assembly language, often referred to simply as assembly and commonly abbreviated as ASM or asm, is any low-level programming language with a very strong correspondence between the instructions in the language and the architecture's machine code instructions. Assembly language usually has one statement per machine instruction (1:1), but constants, comments, assembler directives, symbolic labels of, e.g., memory locations, registers, and macros are generally also supported.

x86 Family of instruction set architectures

x86 is a family of complex instruction set computer (CISC) instruction set architectures initially developed by Intel based on the Intel 8086 microprocessor and its 8088 variant. The 8086 was introduced in 1978 as a fully 16-bit extension of Intel's 8-bit 8080 microprocessor, with memory segmentation as a solution for addressing more memory than can be covered by a plain 16-bit address. The term "x86" came into being because the names of several successors to Intel's 8086 processor end in "86", including the 80186, 80286, 80386 and 80486 processors. Colloquially, their names were "186", "286", "386" and "486".

Common Intermediate Language (CIL), formerly called Microsoft Intermediate Language (MSIL) or Intermediate Language (IL), is the intermediate language binary instruction set defined within the Common Language Infrastructure (CLI) specification. CIL instructions are executed by a CLI-compatible runtime environment such as the Common Language Runtime. Languages which target the CLI compile to CIL. CIL is object-oriented, stack-based bytecode. Runtimes typically just-in-time compile CIL instructions into native code.

<span class="mw-page-title-main">Netwide Assembler</span> Assembler for the Intel x86 architecture

The Netwide Assembler (NASM) is an assembler and disassembler for the Intel x86 architecture. It can be used to write 16-bit, 32-bit (IA-32) and 64-bit (x86-64) programs. It is considered one of the most popular assemblers for Linux and x86 chips.

Bytecode is a form of instruction set designed for efficient execution by a software interpreter. Unlike human-readable source code, bytecodes are compact numeric codes, constants, and references that encode the result of compiler parsing and performing semantic analysis of things like type, scope, and nesting depths of program objects.

Transmeta Corporation was an American fabless semiconductor company based in Santa Clara, California. It developed low power x86 compatible microprocessors based on a VLIW core and a software layer called Code Morphing Software.

x86 assembly language is the name for the family of assembly languages which provide some level of backward compatibility with CPUs back to the Intel 8008 microprocessor, which was launched in April 1972. It is used to produce object code for the x86 class of processors.

<span class="mw-page-title-main">Shellcode</span> Small piece of code used as a payload to exploit a software vulnerability

In hacking, a shellcode is a small piece of code used as the payload in the exploitation of a software vulnerability. It is called "shellcode" because it typically starts a command shell from which the attacker can control the compromised machine, but any piece of code that performs a similar task can be called shellcode. Because the function of a payload is not limited to merely spawning a shell, some have suggested that the name shellcode is insufficient. However, attempts at replacing the term have not gained wide acceptance. Shellcode is commonly written in machine code.

In software engineering, a spinlock is a lock that causes a thread trying to acquire it to simply wait in a loop ("spin") while repeatedly checking whether the lock is available. Since the thread remains active but is not performing a useful task, the use of such a lock is a kind of busy waiting. Once acquired, spinlocks will usually be held until they are explicitly released, although in some implementations they may be automatically released if the thread being waited on blocks or "goes to sleep".

In computing, a bus error is a fault raised by hardware, notifying an operating system (OS) that a process is trying to access memory that the CPU cannot physically address: an invalid address for the address bus, hence the name. In modern use on most architectures these are much rarer than segmentation faults, which occur primarily due to memory access violations: problems in the logical address or permissions.

Fetching the instruction opcodes from program memory well in advance is known as prefetching and it is served by using a prefetch input queue (PIQ). The pre-fetched instructions are stored in a queue. The fetching of opcodes well in advance, prior to their need for execution, increases the overall efficiency of the processor boosting its speed. The processor no longer has to wait for the memory access operations for the subsequent instruction opcode to complete. This architecture was prominently used in the Intel 8086 microprocessor.

The x86 instruction set refers to the set of instructions that x86-compatible microprocessors support. The instructions are usually part of an executable program, often stored as a computer file and executed on the processor.

W^X is a security feature in operating systems and virtual machines. It is a memory protection policy whereby every page in a process's or kernel's address space may be either writable or executable, but not both. Without such protection, a program can write CPU instructions in an area of memory intended for data and then run those instructions. This can be dangerous if the writer of the memory is malicious. W^X is the Unix-like terminology for a strict use of the general concept of executable space protection, controlled via the mprotect system call.

In the x86 architecture, the CPUID instruction is a processor supplementary instruction allowing software to discover details of the processor. It was introduced by Intel in 1993 with the launch of the Pentium and SL-enhanced 486 processors.

crt0 is a set of execution startup routines linked into a C program that performs any initialization work required before calling the program's main function.

This article describes the calling conventions used when programming x86 architecture microprocessors.

<span class="mw-page-title-main">Cosmos (operating system)</span> Toolkit for building GUI and command-line based operating systems

C# Open Source Managed Operating System (Cosmos) is a toolkit for building GUI and command-line based operating systems, written mostly in the programming language C# and small amounts of a high level assembly language named X#. Cosmos is a backronym, in that the acronym was chosen before the meaning. It is open-source software released under a BSD license.

A decompiler is a computer program that translates an executable file to high-level source code. It does therefore the opposite of a typical compiler, which translates a high-level language to a low-level language. While disassemblers translate an executable into assembly language, decompilers go a step further and translate the code into a higher level language such as C or Java, requiring more sophisticated techniques. Decompilers are usually unable to perfectly reconstruct the original source code, thus will frequently produce obfuscated code. Nonetheless, they remain an important tool in the reverse engineering of computer software.

<span class="mw-page-title-main">LuaJIT</span> Just-in-time compiler for the Lua programming language

LuaJIT is a tracing just in time compiler for the Lua programming language. Mike Pall, a primary maintainer of the project had resigned in 2015, resorting only to occasional patching to the future 2.1 version.

Sigreturn-oriented programming (SROP) is a computer security exploit technique that allows an attacker to execute code in presence of security measures such as non-executable memory and code signing. It was presented for the first time at the 35th IEEE Symposium on Security and Privacy in 2014 where it won the best student paper award. This technique employs the same basic assumptions behind the return-oriented programming (ROP) technique: an attacker controlling the call stack, for example through a stack buffer overflow, is able to influence the control flow of the program through simple instruction sequences called gadgets. The attack works by pushing a forged sigcontext structure on the call stack, overwriting the original return address with the location of a gadget that allows the attacker to call the sigreturn system call. Often just a single gadget is needed to successfully put this attack into effect. This gadget may reside at a fixed location, making this attack simple and effective, with a setup generally simpler and more portable than the one needed by the plain return-oriented programming technique.

References

  1. Jürgen Schmidt (20 January 2011). "Return of the sprayer -- JIT Spraying: Exploits to beat DEP and ASLR". The H. Retrieved 22 January 2011.
  2. Haifei Li (10 February 2010). "JIT Spraying in PDF". Fortinet blog. Archived from the original on 18 April 2010. Retrieved 22 January 2011.
  3. Larry Seltzer (4 February 2010). "New "JIT Spray" Penetrates Best Windows Defenses". PCMag . Retrieved 22 January 2011.
  4. 1 2 Dion Blazakis. "Interpreter Exploitation. Pointer Inference and JIT Spraying" (PDF). Black Hat & Defcon 2010.; "Slides" (PDF).
  5. Alexey Sintsov (5 March 2010). "Writing JIT-Spray Shellcode For Fun And Profit". Packet Storm Security . Retrieved 30 January 2012.