OpenBSD Remote Exploit

”Only two remote holes in the default install” Alfredo A. Ortega

July 26, 2007

How the bug was found

Events: 1. January 16,2007: OpenBSD Team releases a patch for the IPv6 Stack titled “OpenBSD 008: RELIABILITY FIX”. (Infinite loop on kernel mode)

How the bug was found

Events: 1. January 16,2007: OpenBSD Team releases a patch for the IPv6 Stack titled “OpenBSD 008: RELIABILITY FIX”. (Infinite loop on kernel mode) 2. A research project was started to reproduce this vulnerability.

How the bug was found

Events: 1. January 16,2007: OpenBSD Team releases a patch for the IPv6 Stack titled “OpenBSD 008: RELIABILITY FIX”. (Infinite loop on kernel mode) 2. A research project was started to reproduce this vulnerability. 3. Because of the lack of information regarding the bug, a IPv6 fuzzer system was implemented. 4. The system Manually send fragmented IPv6 Packets containing differents headers. 5. A couple of lucky packet broke all versions of OpenBSD.

Mbuf buffer overflow

Buffer overflow Researching the “OpenBSD 008: RELIABILITY FIX” a new vulnerability was found: The m dup1() function causes an overflow on the mbuf structure, used by the kernel to store network packets.

Copy direction

mbuf1

mbuf2

mbuf3

mbuf4

End of overflow

Figure:

The function m freem() crashed...

mbuf chain overflow direction

Searching for a way to gain code execution

Searching for a way to gain code execution

C code equivalent

/ s y s / mbuf . h MEXTREMOVE(m) do { \ i f (MCLISREFERENCED(m) ) { \ MCLDEREFERENCE(m) ; \ } e l s e i f ( (m)−>m f l a g s & M CLUSTER) { \ p o o l p u t (& m c l p o o l , (m)−>m e x t . e x t b u f ) ; \ } e l s e i f ( (m)−>m e x t . e x t f r e e ) { \ ( ∗ ( (m)−>m e x t . e x t f r e e ) ) ( (m)−>m e x t . e x t b u f , \ (m)−>m e x t . e x t s i z e , (m)−>m e x t . e x t a r g ) ; \ } else { \ f r e e ( (m)−>m e x t . e x t b u f , (m)−>m e x t . e x t t y p e ) ; \ } \ (m)−>m f l a g s &= ˜ (M CLUSTER |M EXT ) ; \ (m)−>m e x t . e x t s i z e = 0 ; /∗ why ? ? ? ∗/ \ } w h i l e ( /∗ CONSTCOND ∗/ 0 )

#d e f i n e

IcmpV6 packets Attack vector We use two IcmpV6 packets as the attack vector

Mbuf chain Fragment 1

Fragment 2

IPv6 Header

IPv6 Header

Hop−by−Hop Header

Fragmentation Header

Fragmentation Header

Header

mbuf 1

Icmpv6 Icmpv6 Header Trampoline

ShellCode

Header

mbuf 2

SyscallHook Payload

Header

mbuf 3

Figure:

Detail of IcmpV6 fragments

Where are we?

Code execution We really don’t know where in kernel-land we are. But ESI is pointing to our code.

Final situation

Initial situation

User process

Kernel ?

? Ring 0

?

Ring 3

Hooked syscall

?

?

?

ESI

ShellCode

ShellCode ?

iret Int 0x80

? ?

?

?

Ring 0

Kernel

Where we are?

Figure:

Initial and final situations

Now what? Hook (remember DOS TSRs?) We hook the system call (Int 0x80)

Normal System Call

Hooked System Call

User process Ring 3 INT 0x80

User process Normal syscall

INT 0x80

return

Hooked syscall

return Kernel

Kernel Ring 0

Hook

Figure:

System call hook

Note: If the OS uses SYSENTER for system calls, the operation is slightly different.

New syscall pseudo-code

1. Get curproc variable (current process)

New syscall pseudo-code

1. Get curproc variable (current process) 2. Get user Id (curproc− >userID)

New syscall pseudo-code

1. Get curproc variable (current process) 2. Get user Id (curproc− >userID) 3. If userID == 0, the process is root : 3.1 3.2 3.3 3.4 3.5

Get LDT position Extend DS and CS on the LDT (This disables WˆX!) Copy the user-mode code to the the stack of the process Modify return address for the syscall to point to our code Restore the original Int 0x80 vector (remove the hook)

New syscall pseudo-code

1. Get curproc variable (current process) 2. Get user Id (curproc− >userID) 3. If userID == 0, the process is root : 3.1 3.2 3.3 3.4 3.5

Get LDT position Extend DS and CS on the LDT (This disables WˆX!) Copy the user-mode code to the the stack of the process Modify return address for the syscall to point to our code Restore the original Int 0x80 vector (remove the hook)

New syscall pseudo-code

1. Get curproc variable (current process) 2. Get user Id (curproc− >userID) 3. If userID == 0, the process is root : 3.1 3.2 3.3 3.4 3.5

Get LDT position Extend DS and CS on the LDT (This disables WˆX!) Copy the user-mode code to the the stack of the process Modify return address for the syscall to point to our code Restore the original Int 0x80 vector (remove the hook)

4. Continue with the original syscall

OpenBSD WˆX internals

WˆX: Writable memory is never executable i386: uses CS selector to limit the execution. To disable WˆX, we extend CS from ring0.

0x00000000

0xffffffff

4 GB

.text

.so

.so

heap

stack

512 MB User Code Segment (CS) User Data Segment (DS)

Figure:

Extension stack

OpenBSD selector scheme and extension

Extension

Defeating WˆX from ring0

Our algorithm, independent of the Kernel: sldt ax ; S t o r e LDT i n d e x on EAX sub esp , b y t e 0 x 7 f ; Store global d e s c r i p t o r table sgdt [ e s p +4] mov ebx , [ e s p +6] add esp , b y t e 0 x 7 f push eax ; Save l o c a l d e s c r i p t o r t a b l e i n d e x mov edx , [ ebx+eax ] mov ecx , [ ebx+eax+0x4 ] shr edx , 1 6 ; b a s e l o w−−>e dx mov eax , e c x shl eax , 2 4 ; b a s e m i d d l e −−> e dx shr eax , 8 or edx , eax mov eax , e c x ; b a s e h i g h −−> e dx and eax , 0 x f f 0 0 0 0 0 0 or edx , eax mov ebx , edx ; l d t −−> e bx ; E x t e n d CS s e l e c t o r or dword [ ebx+0x 1 c ] , 0 x 0 0 0 f 0 0 0 0 ; E x t e n d DS s e l e c t o r or dword [ ebx+0x24 ] , 0 x 0 0 0 f 0 0 0 0

Injected code WˆX will be restored on the next context switch, so we have two choices to do safe execution from user-mode: Creating a W+X section

Turning off W^X (from usermode)

From kernel...

From kernel...

User Stack

Ring 3

1. mprotect() 2.fork() 3.Standard user−mode code

mprotect() extends CS permanently

Figure:

Ring 3

Payload injection options

User Stack

1. fork() 2.mmap() 3.copy 4.jmp to mmap 5. Standard user−mode code

Questions before going on?

Now we are executing standard user-mode code, and the system has been compromised.

Proposed protection

Limit the Kernel CS selector The same strategy than on user-space. Used on PaX (http://pax.grsecurity.net) for Linux.

0x00000000

0xffffffff

4 GB 0xD1000000 kernel

0xD0000000

CS shrink

Kernel Code Segment (CS) Kernel Data Segment (DS)

Figure:

mbuf chains, etc

OpenBSD Kernel CS selector shrink

A third remote vulnerability?

IPv6 Routing Headers Uninitialized variable on the processing of IPv6 headers. 1. DoS or Code Execution (depending who you ask!) 2. Present on CVS from January to March of 2007 (very few systems affected) RCS f i l e : / u s r /OpenBSD/ c v s / s r c / s y s / n e t i n e t 6 / r o u t e 6 . c , v r e t r i e v i n g r e v i s i o n 1.13 r e t r i e v i n g r e v i s i o n 1.14 s w i t c h ( rh−>i p 6 r t y p e ) { c a s e IPV6 RTHDR TYPE 0 : + r h l e n = ( rh−>i p 6 r l e n + 1 ) << 3 ; i f ( rh−>i p 6 r s e g l e f t == 0 ) b r e a k ; /∗ F i n a l d s t . J u s t i g n o r e t h e h e a d e r . ∗/ − r h l e n = ( rh−>i p 6 r l e n + 1 ) << 3 ;

Conclusions

In this article we presented: 1. Generic kernel execution code and strategy 2. Possible security improvement of the kernel

Conclusions

In this article we presented: 1. Generic kernel execution code and strategy 2. Possible security improvement of the kernel 3. A third bug - No software is perfect

Final Questions?

Thanks to: Gerardo Richarte: Exploit Architecture Mario Vilas and Nico Economou: Coding support

Only two remote holes in the default install

Jul 26, 2007 - ... to point to our code. 3.5 Restore the original Int 0x80 vector (remove the hook) ... User Data Segment (DS). 0xffffffff. 4 GB heap. 512 MB.

297KB Sizes 1 Downloads 146 Views

Recommend Documents

No documents