SOME/IP中间人攻击模拟

文章讲述了作者在使用Python进行广播通信时遇到的错误,包括Windows和Linux环境下关于广播地址和权限的问题,通过设置socket属性和理解错误信息解决了这些问题。
摘要由CSDN通过智能技术生成
一些坎坷

        过程中遇到了一个奇怪的问题:广播地址为“255.255.255.255”时会出现“[WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试”的错误。将广播地址换成“192.168.1.255”就能运行。能运行之后,便将这个问题搁置了。

        在将代码移植到Linux系统时,又出现了错误,其中最大的PermissionError: [Errno 13] Permission denied(还有一个不太大的是:OSError: [Errno 22] Invalid argument,这个好像与上一个有点关系,最后一起都解决了)。老一会儿也没解决,最后从网上找了一个简单的广播代码测试,并进行比较,发现少了一行:

       

 udpServer.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

        这一行的是设置socket属性,第二个参数是广播服务。这一行的作用之一是开启广播属性,问题解决。后来回想到,搜索Permission denied的错误产生原因,其中有一个是没有访问权限,即使sudo也不行,得加上开启广播属性的代码才可以。之后完成了两台主机之间正常的广播服务,请求服务和提供服务的目标。(但是广播地址从“255.255.255.255”改到“192.168.1.255”这个现象,在Windows的pycharm上可以,在Linux上不行,也许是一个小漏洞?)

        一开始在Windows上测试的时候,socket(IP, port)中的IP可以使用socket.gethostname()来获取。当服务器和客户端在一台主机上时没有问题,在两台主机上的时候,发现客户端不能接收的广播报文。输出这个地址之后,发现socket中的IP事主机的名称,而不是IP地址。将套接字中的IP改为“0.0.0.0”(表示本网段上的本主机),或者ipconfig查到的的IP地址(192.168.1.161),两台主机即可通信。

payLoad.py
import someip.sd
from scapy.contrib.automotive.someip import *
import binascii
from scapy.layers.inet import IP
from scapy.all import ls
import struct

class load:

    def __init__(self):
        self.opt = 0  # 0: offer , 1: request, 2: response
        self.svce = []  # 存储服务ID

    def encod(self):
        msg: str = ""
        msg += str(self.len_format(self.opt, 4))
        for i in self.svce:
            msg += str(self.len_format(i, 4))

        return msg

    def len_format(self, num, len):
        """对数据做格式化, 去掉16进制数前面的0x"""
        length_hex = hex(num)
        if length_hex.startswith('0x'):
            str_length = length_hex[2:]  # 去掉16进制数前面的0x
        total_length = str_length.zfill(len)
        return total_length

    def decod(self, str: str):
        self.opt = int(str[0: 4], 16)
        i = 4
        while i < str.__len__():
            self.svce.append(int(str[i: i + 4], 16))
            i += 4

    def show_payload(self):
        print("opt = ", self.opt)
        for i in self.svce:
            print("service : ", i)

'''
pkt = SOMEIP(b"\x07\xff\x80\x01\x00\x00\x00S\x00\x00\x00\x06\x01\x01\x02\x00\x0c\\xf1\xdds\x84\x00\x00\x00>[\x19\xa2\xd1aV\xce'\xc1)\xa9x02Eg\x00\x00\x00D")
# ls(pkt)

# 编报头
data = SOMEIP()
data.srv_id = 0xffff
data.method_id = 0x8100

data.len = 8

data.client_id = 0
data.session_id = 0

data.proto_ver = 1
data.iface_ver = 1
data.msg_type = 2
data.retcode = 0

# 编辑有效载荷
msg = load()
msg.opt = 0
msg.svce.append(1234)
msg.svce.append(5678)
msg.svce.append(2345)
msg.svce.append(6789)

# 组合报文
data.add_payload(binascii.a2b_hex(msg.encod().encode()))
print("data: ", data.build())

# 接收报文,并解码
data1 = data
msg1 = binascii.b2a_hex(data1.payload.build())
msg1 = msg1.decode()  # 从 bytes 到 str

rcv = load()
rcv.decod(msg1)
rcv.show_payload()
'''





 服务器端
import time

from scapy.contrib.automotive.someip import *
import socket
from payLoad import load
import binascii

from threading import Thread

def recveData(soc):
    while True:
        clientData, clientAddr = soc.recvfrom(1024)  # 接收来自客户端的数据

        # print(clientData)  # 打印普通格式报文
        someipData = SOMEIP(_pkt=clientData)
        # someipData.show()  # 打印someip格式报文

        # 输出payload字段
        pay_load = load()
        # 16进制 -> 2进制的表现形式 -> str
        rmsg = binascii.b2a_hex(someipData.payload.build()).decode()
        pay_load.decod(rmsg)

        if pay_load.opt == 1:
            print("request service from client ", clientAddr)
            print("opt = ", pay_load.opt)
            for i in pay_load.svce:
                print("service : ", i)
            pay_load.opt = 2

        serviceData = someipData
        serviceData.remove_payload()
        serviceData.add_payload(binascii.a2b_hex(pay_load.encod().encode()))

        soc.sendto(serviceData.build(), clientAddr)  # 发送数据给客户端,提供服务


def broadCast(soc):
    data = SOMEIP()
    data.srv_id = 0xffff
    data.method_id = 0x8100

    # data.len = 8

    data.client_id = 0
    data.session_id = 0

    data.proto_ver = 1
    data.iface_ver = 1
    data.msg_type = 0x80
    data.retcode = 0

    # 编辑有效载荷
    msg = load()
    msg.opt = 0
    msg.svce.append(1234)
    msg.svce.append(5678)
    msg.svce.append(6789)
    msg.svce.append(7891)

    data.len = 8 + 2 + 2 * msg.svce.__len__()

    # 组合报文
    data.add_payload(binascii.a2b_hex(msg.encod().encode()))

    while True:
        soc.sendto(data.build(), ("255.255.255.255", 8080))
        print("broadcast")
        time.sleep(1)


udpServer = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 创建socket对象,走udp通道
# 开启socket的广播属性,否则进行广播时会报错!
udpServer.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
host = "0.0.0.0"  # 获取本地主机名
port = 1000
serverAddr = (host, port)
udpServer.bind(serverAddr)  # 绑定服务端地址

broadcastAddr = ("255.255.255.255", port)  # 广播地址

t1 = Thread(target=recveData, args=(udpServer,))
t2 = Thread(target=broadCast, args=(udpServer,))

t1.start()
t2.start()

t1.join()
t2.join()

udpServer.close()
客户端
import binascii
import socket
import time
import random
from payLoad import load

from scapy.contrib.automotive.someip import *
from threading import Thread

udpClient = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 创建socket对象,走udp通道
tcpClient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建socket对象,走tcp通道
# 开启socket的广播属性socket.SO_BROADCAST,否则进行广播时会报错!
udpClient.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
host = "0.0.0.0"  # 获取本地主机名
port = 8080
serverAddr = (host, port)
clientAddr = (host, port)
print(serverAddr)
udpClient.bind(clientAddr)
serviceList = []

find_server = 0

def recveData(soc):
    global find_server, serverAddr
    while True:
        rcvData, rcvAddr = soc.recvfrom(1024)  # 接收来自服务端的数据

        # print(rcvData)  # 打印普通格式报文
        someipData = SOMEIP(_pkt=rcvData)
        # someipData.show()  # 打印someip格式报文

        # 输出payload字段
        pay_load = load()
        # 16进制 -> 2进制的表现形式 -> str
        rmsg = binascii.b2a_hex(someipData.payload.build()).decode()
        pay_load.decod(rmsg)

        if pay_load.opt == 0 and find_server == 0:
            # 存储下服务器的地址和端口,以及提供的服务
            serverAddr = rcvAddr
            for i in pay_load.svce:
                serviceList.append(i)
            find_server = 1
            print("add service")
        else:
            if pay_load.opt == 2 and rcvAddr == serverAddr:
                print("response from server ", serverAddr)
                print("opt = ", pay_load.opt)
                for i in pay_load.svce:
                    print("service : ", i)



def sendData(udpClient):
    global serverAddr
    while True:
        if serviceList.__len__() == 0:
            continue
        # someip报文
        data = SOMEIP()
        data.srv_id = 0x2568
        data.method_id = 0x8001

        # data.len = 27

        data.client_id = 0
        data.session_id = 0

        data.proto_ver = 1
        data.iface_ver = 1
        data.msg_type = 0
        data.retcode = 0

        # 编辑有效载荷
        msg = load()
        msg.opt = 1
        req_svce = serviceList[random.randint(0, serviceList.__len__() - 1)]
        msg.svce.append(req_svce)

        data.len = 8 + 2 + 2 * msg.svce.__len__()

        # 组合报文
        data.add_payload(binascii.a2b_hex(msg.encod().encode()))

        i = 0
        while i < 1:
            udpClient.sendto(data.build(), serverAddr)  # 发送报文给服务端
            serverData, serverAddr = udpClient.recvfrom(1024)  # 接收来自服务端的数据
            # print(serverData)  # 打印普通格式报文
            someipData = SOMEIP(_pkt=serverData)
            # someipData.show()  # 打印someip格式报文

            # 输出payload字段
            pay_load = load()
            # 16进制 -> 2进制的表现形式 -> str
            rmsg = binascii.b2a_hex(someipData.payload.build()).decode()
            pay_load.decod(rmsg)
            # pay_load.show_payload()
            time.sleep(1)
            i += 1


t1 = Thread(target=recveData, args=(udpClient,))
t2 = Thread(target=sendData, args=(udpClient,))

t1.start()
t2.start()

t1.join()
t2.join()

udpClient.close()

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>