【SEED Labs 2.0】Virtual Private Network (V*N) Lab

这篇具有很好参考价值的文章主要介绍了【SEED Labs 2.0】Virtual Private Network (V*N) Lab。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文为 SEED Labs 2.0 - Virtual Private Network (V*N) Lab 的实验记录。

0. 实验目标

本实验要求完成 V*N 的实现。其应当支持 TUN 建立、隧道加密、服务器认证、客户端登录、多用户等功能。

本实验的实验手册使用多虚拟机与 C 语言完成,而我们希望直接使用 docker 和 Python。我们一步到位完成了所有程序的编写,下面描述我们的具体步骤。

1. 生成证书

创建 CA

$ mkdir demoCA
$ cd demoCA
$ mkdir certs crl newcerts
$ touch index.txt serial
$ echo 1000 > serial
$ cd ..
$ cp /usr/lib/ssl/openssl.cnf myCA_openssl.cnf
$ openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -keyout ca.key -out ca.crt -subj "/CN=www.modelCA.com/O=Model CA LTD./C=US/ST=New York/L=Syracuse" -passout pass:dees

创建并签发服务器使用的证书。

$ openssl req -newkey rsa:2048 -sha256 -keyout vpn.key -out vpn.csr -subj "/CN=vpnlabserver.com/O=Model CA LTD./C=US/ST=New York/L=Syracuse" -passout pass:dees
$ openssl ca -config myCA_openssl.cnf -policy policy_anything -md sha256 -days 3650 -in vpn.csr -out vpn.crt -batch -cert ca.crt -keyfile ca.key

v*n.crtv*n.key,放入 server-certs 文件夹中。

ca.crt 放入 client-certs 文件夹中,并建立软链接:

$ openssl x509 -in ca.crt -noout -subject_hash
eaa14a05
$ ln -s ca.crt eaa14a05.0

2. 设置 Docker

编写 docker-compose.yml

version: "3"

services:
    VPN_Client1:
        image: handsonsecurity/seed-ubuntu:large
        container_name: client-10.0.2.5
        tty: true
        cap_add:
                - ALL
        extra_hosts:
                - "vpnlabserver.com:10.0.2.8"
        devices:
                - "/dev/net/tun:/dev/net/tun"
        volumes:
                - ./volumes:/volumes
        networks:
            net-10.0.2.0:
                ipv4_address: 10.0.2.5
        command: bash -c "tail -f /dev/null"
        
    VPN_Client2:
        image: handsonsecurity/seed-ubuntu:large
        container_name: client-10.0.2.6
        tty: true
        cap_add:
                - ALL
        extra_hosts:
                - "vpnlabserver.com:10.0.2.8"
        devices:
                - "/dev/net/tun:/dev/net/tun"
        volumes:
                - ./volumes:/volumes
        networks:
            net-10.0.2.0:
                ipv4_address: 10.0.2.6
        command: bash -c "tail -f /dev/null"
    
    VPN_Client3:
        image: handsonsecurity/seed-ubuntu:large
        container_name: client-10.0.2.7
        tty: true
        cap_add:
                - ALL
        extra_hosts:
                - "vpnlabserver.com:10.0.2.8"
        devices:
                - "/dev/net/tun:/dev/net/tun"
        volumes:
                - ./volumes:/volumes
        networks:
            net-10.0.2.0:
                ipv4_address: 10.0.2.7
        command: bash -c "tail -f /dev/null"

    Host_V:
        image: handsonsecurity/seed-ubuntu:large
        container_name: host-192.168.60.101
        tty: true
        cap_add:
                - ALL
        volumes:
                - ./volumes:/volumes
        networks:
            net-192.168.60.0:
                ipv4_address: 192.168.60.101
        command: bash -c "ip route del default  &&
                          ip route add default via 192.168.60.1  &&
                          /etc/init.d/openbsd-inetd start &&
                          tail -f /dev/null"
                
    Router:
        image: handsonsecurity/seed-ubuntu:large
        container_name: server-10.0.2.8-192.168.60.1
        tty: true
        cap_add:
                - ALL
        devices:
                - "/dev/net/tun:/dev/net/tun"
        sysctls:
                - net.ipv4.ip_forward=1
        volumes:
                - ./volumes:/volumes
        networks:
            net-10.0.2.0:
                ipv4_address: 10.0.2.8
            net-192.168.60.0:
                ipv4_address: 192.168.60.1
        command: bash -c "ip route del default  &&
                          ip route add default via 10.0.2.1 &&
                          tail -f /dev/null"
    
    MITM:
        image: handsonsecurity/seed-ubuntu:large
        container_name: mitm-10.0.2.9-192.168.60.2
        tty: true
        cap_add:
                - ALL
        devices:
                - "/dev/net/tun:/dev/net/tun"
        sysctls:
                - net.ipv4.ip_forward=1
        volumes:
                - ./volumes:/volumes
        networks:
            net-10.0.2.0:
                ipv4_address: 10.0.2.9
            net-192.168.60.0:
                ipv4_address: 192.168.60.2
        command: bash -c "ip route del default  &&
                          ip route add default via 10.0.2.1 &&
                          tail -f /dev/null"

networks:
    net-192.168.60.0:
        name: net-192.168.60.0
        ipam:
            config:
                - subnet: 192.168.60.0/24
                  gateway: 192.168.60.100

    net-10.0.2.0:
        name: net-10.0.2.0
        ipam:
            config:
                - subnet: 10.0.2.0/24
                  gateway: 10.0.2.1

其中:

  • V*N_Client1V*N_Client2V*N_Client3 为 3 个客户端
  • Host_V 为一台主机
  • Router 为 V*N 服务器
  • MITM 为中间人攻击使用的服务器

它们的 IP 和连接关系如下图所示

seedlab vpn实验,SEED Labs,docker,网络安全,网络

设置完成后,我们启动 docker

$ dcbuild
$ dcup

3. 编写程序

编写 V*N 服务器和中间人攻击服务器使用的 v*nserver.py

#!/usr/bin/env python3
import fcntl
import struct
import os
import ssl
import spwd
import crypt
from scapy.all import *

TUNSETIFF = 0x400454ca  # ioctl request code
IFF_TUN = 0x0001  # create a tunnel
IFF_TAP = 0x0002  # create a tap device
IFF_NO_PI = 0x1000  # don't pass on packet info

'''
Create the tun interface
'''
tun = os.open("/dev/net/tun", os.O_RDWR)  # open the tun device
# create the control block
ifr = struct.pack('16sH', b'tun%d', IFF_TUN | IFF_NO_PI)
ifname_bytes = fcntl.ioctl(tun, TUNSETIFF, ifr)  # create the interface

'''
Get the interface name
'''
ifname = ifname_bytes.decode(
    'UTF-8')[:16].strip("\x00")  # get the interface name
print("Interface Name: {}".format(ifname))  # print the interface name

'''
Set route
'''
os.system("ip addr add 192.168.53.1/24 dev {}".format(ifname))  # set the route
os.system("ip link set dev {} up".format(ifname))  # set the interface up

'''
Get certs
'''
SERVER_CERT = "/volumes/crt/server-certs/vpn.crt"  # server certificate
SERVER_PRIVATE = "/volumes/crt/server-certs/vpn.key"  # server private key

'''
Set SSL
'''
context_srv = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)  # create the SSL context
context_srv.num_tickets = 0  # disable session tickets
# load the server certificate
context_srv.load_cert_chain(SERVER_CERT, SERVER_PRIVATE)

'''
Set sock
'''
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM,
                     0)  # create the socket
sock.bind(("0.0.0.0", 443))  # bind the socket to the port
sock.listen(5)  # listen for connections
print(">>> Preparation done.")

'''
Initialization
'''
inputs = [sock, tun]  # create the input list
con_dict = {}  # create the connection dictionary
ip_dict = {}  # create the IP dictionary

'''
Main loop
'''
while True:
    ready, _, _ = select.select(inputs, [], [])  # select the ready inputs

    for fd in ready:  # for each ready input
        if fd is sock:  # if the input is the socket
            '''
            Acceppt a new connection and set up the connection
            '''
            con, addr = sock.accept()  # accept the connection
            IPa, _ = addr  # get the IP address
            # wrap the connection with SSL
            con = context_srv.wrap_socket(con, server_side=True)
            con.setblocking(0)  # set the socket to non-blocking

            print(">>> {} new connection".format(IPa))

            '''
            Receive the username and password.
            If they are all correct, add the connection to the listening list.
            '''
            usrname = b''  # create the username
            passwd = b''  # create the password

            re_client_auth = IP()  # create the packet to reply the client authentication
            re_client_auth.src = '192.168.53.1'  # set the source IP address

            while (usrname == b'') or (passwd == b''):  # while some data is not received
                # select the connection inputs
                ready, _, _ = select.select([con], [], [])
                for fd in ready:  # for each ready input
                    data = fd.recv(2048)  # receive the data
                    pkt = IP(data)  # create the packet
                    re_client_auth.dst = pkt.src  # set the destination IP address
                    if usrname == b'':  # if the username is not received
                        usrname = pkt[Raw].load  # get the username
                    else:  # if the username is received but the password is not received
                        passwd = pkt[Raw].load  # get the password

            try:
                # get the password
                pw1 = spwd.getspnam(usrname.decode()).sp_pwd
                # get the encrypted password
                pw2 = crypt.crypt(passwd.decode(), pw1)
            except KeyError:  # if the username is not found
                # message to the client
                con.sendall(bytes(re_client_auth/b'0'))
                con.close()  # close the connection
                print(">>> {} login failed - WRONG USERNAME".format(IPa))
            else:  # if the username is found
                if pw1 != pw2:  # if the password is not correct
                    # message to the client
                    con.sendall(bytes(re_client_auth/b'0'))
                    con.close()  # close the connection
                    print(">>> {} login failed - WRONG PASSWORD".format(IPa))
                else:  # if the password is correct
                    # message to the client
                    con.sendall(bytes(re_client_auth/b'1'))
                    inputs.append(con)  # add the connection to the input list
                    print(">>> {} login succeed".format(IPa))

        elif fd is tun:  # if the input is the tun interface
            packet = os.read(tun, 2048)  # read the packet
            pkt = IP(packet)  # create the packet
            print("=== TUN:\t{}\t-->\t{}\t===".format(pkt.src, pkt.dst))
            # send the packet to the destination
            con_dict[pkt.dst].sendall(packet)
        else:  # if the input is the connection
            data = fd.recv(2048)  # receive the data
            if data != b'':  # if the data is not empty
                pkt = IP(data)  # create the packet
                print("=== SOCKET:\t{}\t-->\t{}\t===".format(pkt.src, pkt.dst))
                if pkt.src not in con_dict:  # if the source IP is not in the dictionary
                    # add the connection to the dictionary
                    con_dict[pkt.src] = fd
                    # add the IP address to the IP dictionary
                    ip_dict[fd] = pkt.src
                # write the packet to the tun interface
                os.write(tun, bytes(pkt))
            else:  # if the data is empty
                print(">>> {} connection closed.".format(ip_dict[fd]))
                inputs.remove(fd)  # remove the connection from the input list
                # remove the IP from the connection dictionary
                del con_dict[ip_dict[fd]]
                del ip_dict[fd]  # remove the connection from the IP dictionary
                fd.close()  # close the connection

对于该程序,需要注意的是,我们使用了 TCP 而不是 UDP,所以最一开始建立的 sock 只会被用来和新客户端建立连接,而通信使用的是新建立的连接。

我们通过类似 ip route 的方式实现了文件描述符的选择,但由于在本案中连接数较少,我们没有使用多进程与管道——也就是说,在一条消息杯转发前,系统是阻塞的。经过测试,在 3 个客户端时,所有客户端都能正常通信,几乎不会有延迟。如果后期需要更多的客户端,我们再考虑增加多进程。

编写 V*N_Client1 使用的 v*nclient1.py

#!/usr/bin/env python3

import fcntl
import struct
import os
import socket
import ssl
import getpass
from scapy.all import *

TUNSETIFF = 0x400454ca # ioctl request code
IFF_TUN = 0x0001 # create a tunnel
IFF_TAP = 0x0002 # create a tap device
IFF_NO_PI = 0x1000 # don't pass on packet info

hostname = 'vpnlabserver.com' # hostname of the server
port = 443 # port of the server
cadir = '/volumes/crt/client-certs' # directory of the client certificates

'''
Set up the TLS context
'''
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) # create the SSL context

context.load_verify_locations(capath=cadir) # load the client certificates
context.verify_mode = ssl.CERT_REQUIRED # verify the client certificates
context.check_hostname = True # check the hostname of the server

'''
Create TCP connection
'''
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # create the socket
sock.connect((hostname, port)) # connect to the server

'''
Add the TLS
'''
try:
    ssock = context.wrap_socket( # wrap the socket with TLS
        sock, server_hostname=hostname, do_handshake_on_connect=False)
    ssock.do_handshake() # do the TLS handshake
except: # if the TLS handshake fails
    print(">>> Certificate failed") # print error message
    ssock.shutdown(socket.SHUT_RDWR) # shutdown the socket
    ssock.close() # close the socket
    exit() # exit the program
print("Server hostname: {}".format(ssock.server_hostname)) # print the server hostname

'''
Create the tun interface
'''
tun = os.open("/dev/net/tun", os.O_RDWR) # open the tun device
ifr = struct.pack('16sH', b'tun%d', IFF_TUN | IFF_NO_PI) # create the control block
ifname_bytes = fcntl.ioctl(tun, TUNSETIFF, ifr) # create the interface

'''
Get the interface name
'''
ifname = ifname_bytes.decode('UTF-8')[:16].strip("\x00") # get the interface name
print("Interface Name: {}".format(ifname)) # print the interface name

os.system("ip addr add 192.168.53.3/24 dev {}".format(ifname)) # set the route
os.system("ip link set dev {} up".format(ifname)) # set the interface up
os.system("ip route add 192.168.60.0/24 dev {} via 192.168.53.3".format(ifname)) # set the route

print(">>> Preparation done.")

'''
Login
'''
usrname = input("Input username: ") # input the username
passwd = getpass.getpass("Input password: ") # input the password
client_auth = IP()
client_auth.src = '192.168.53.3' # set the source IP address
client_auth.dst = '192.168.53.1' # set the destination IP address
ssock.send(bytes(client_auth/bytes(usrname.encode()))) # send the username
ssock.send(bytes(client_auth/bytes(passwd.encode()))) # send the password

ready, _, _ = select.select([ssock, tun], [], []) # wait for the server to send
for fd in ready:
    data = ssock.recv(2048) # receive the data
    pkt = IP(data) # create the packet
    client_auth_result = pkt[Raw].load # get the result
    if client_auth_result == b'0': # if the result is 0
        print(">>> Login failed") # print error message
        print(">>> Server closed") 
        ssock.shutdown(socket.SHUT_RDWR) # shutdown the socket
        ssock.close() # close the socket
        exit() # exit the program
print(">>> Login succeed")

'''
Main loop
'''
while True:
    ready, _, _ = select.select([ssock, tun], [], []) # wait for the server to send

    for fd in ready: # for each file descriptor
        if fd is tun: # if the file descriptor is the tun device
            packet = os.read(tun, 2048) # read the packet
            pkt = IP(packet) # create the packet
            print("=== TUN:\t{}\t-->\t{}\t===".format(pkt.src, pkt.dst)) 
            ssock.send(packet) # send the packet
        if fd is ssock: # if the file descriptor is the socket
            data = ssock.recv(2048) # receive the data
            if data != b'': # if the data is not empty
                # print (">>> Receive {} from {}".format(data, fd.getpeername()))
                pkt = IP(data) # create the packet
                print("=== SOCKET:\t{}\t-->\t{}\t===".format(pkt.src, pkt.dst))
                os.write(tun, bytes(pkt)) # send the packet to the tun device
            else: # if the data is empty
                print(">>> Server closed") 
                ssock.shutdown(socket.SHUT_RDWR) # shutdown the socket
                ssock.close() # close the socket
                exit() # exit the program

v*nserver2.pyv*nserver3.py 同理,只需要修改对应的 IP 地址即可。

以上程序实现了 **TUN 建立、隧道加密、服务器认证、客户端登录、多用户(无多进程)**的功能。程序的每一行都有详细的注释,在此不再赘述各个功能是如何实现的。

到目前为止,所有准备工作均已经完成,文件夹内结构如下所示:

.
├── docker-compose.yml
└── volumes
    ├── crt
    │   ├── ca.key
    │   ├── client-certs
    │   │   ├── eaa14a05.0
    │   │   └── ca.crt
    │   ├── demoCA
    │   ├── myCA_openssl.cnf
    │   ├── server-certs
    │   │   ├── vpn.crt
    │   │   └── vpn.key
    │   └── vpn.csr
    ├── vpnclient1.py
    ├── vpnclient2.py
    ├── vpnclient3.py
    └── vpnserver.py

4. 测试

相关命令几乎全是简单的 pingtelnet,此处不再赘述。

5. 总结

本实验较为简单。文章来源地址https://www.toymoban.com/news/detail-726124.html

到了这里,关于【SEED Labs 2.0】Virtual Private Network (V*N) Lab的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【SEED Labs 2.0】Public-Key Infrastructure (PKI) Lab

    本文为 SEED Labs 2.0 - Public-Key Infrastructure (PKI) Lab 的实验记录。 如今,公钥密码学已经成为了安全通信的基础。但是当通信的一方将其公钥发送给另一方时,它会受到中间人攻击。问题在于无法验证公钥的所有权——即给定公钥及其声称的所有者信息。我们如何确保公钥确实由

    2024年02月07日
    浏览(55)
  • 网络安全:堡垒机、跳板机、Virtual Private Network知识介绍

    目录 堡垒机、跳板机和VPN的概念、用途和区别 1、堡垒机(Bastion Host) 1.1 定义 1.2 作用 2、跳板机(Jump Server) 2.1 定义 2.2 作用 3、Virtual Private Network 3.1 定义 3.2 作用 4、三者之间的关系 对于企业来说,网络安全是IT信息建设最重要的,比如企业的隐私数据(客户数据、技术

    2023年04月10日
    浏览(39)
  • 初-SEED 2.0实验环境搭建

    SEED LABS是一系列的网络安全实验,其基本囊括了信息安全本科生所涉及到的几乎每个方面,例如软件安全,Web安全,密码学安全等。而每一个方面的实验又由好几个单独的实验组成。 不需要物理的实验空间。 不需要专门的机器,所有的实验任务都可以在学生的电脑上完成。

    2024年02月09日
    浏览(31)
  • 【信息安全】seed-labs实验-TCP/IP Attack Lab

    Install SEED VM on VirtualBox 上面完成了一台虚拟机的基本配置,然后clone两台虚拟机,和原来的虚拟机一起,分别是attacker、victim和observer。 attacker是发起攻击的机器、victim是遭受攻击的机器和observer是观察用的机器,同时后面也将victim作为客户端、observer作为服务器。 Oracle Virtua

    2024年02月02日
    浏览(41)
  • 网络攻防技术-Lab5-shellcode编写实验(SEED Labs – Shellcode Development Lab)

    网络攻防技术实验,实验环境、实验说明、实验代码见 Shellcode Development Lab 1) 编译mysh.s得到二进制文件 2) 执行 1)中的二进制文件 ,结果如下图, 我们 看到运行mysh之前的PID与运行mysh之后的PID是不同的,证明我们通过mysh启动了一个新的shell。 3) 获取机器码,以便进一步

    2023年04月13日
    浏览(43)
  • Virtual P****** Network (V*N) Lab

    我的(old)代码应要求放出来了,结果如本篇 一修 ,现在2022年8月30日02:28:53应该已经过审了。 (new)代码思路见 二修 ,希望各位自力更生,C源码放GitHub了,有缘公开/doge 可以使用docker容器。配置文件如下,如要模拟多客户端需要增加公网设备,直接复制修改以下client部分

    2024年02月09日
    浏览(36)
  • Packet Sniffing and Spoofing Lab(报文嗅探&欺骗SEED 实验)

    本次实验的目的有两点:学习使用报文嗅探欺骗的工具、理解其背后的原理。 本次实验使用处在同一局域网下的三台机器,使用docker运行,其文件在官网上可以下载,具体使用方法可以参考我的PKI实验报告。网络拓扑如图: 1.1 嗅探报文 最简单的一个嗅探代码,利用 ifconfi

    2024年02月07日
    浏览(41)
  • Vulnhub之 BoredHackerBlog: Social Network 2.0靶机详细测试过程

    作者:jason huawen 名称:BoredHackerBlog: Social Network 2.0 地址: 利用Kali Linux的netdiscover工具识别目标主机的IP地址为192.168.56.169 NMAP扫描结果表明目标主机有3个开放端口:22(ssh)、80(http)、8000(http) /databases/目录中有2个sql文件,将其下载到本地 Insert语句中,并没有密码值,有点奇怪

    2023年04月23日
    浏览(33)
  • IPSEC VPN安全介绍以及相关实验

    目录 一、IPSEC相关的安全服务          二、IPSEC的安全协议 三、实验 IPSEC一组协议集合,用于确保在IP网络上进行通信时的安全性和保密性。它提供了一种标准化的方法,用于对IP数据包进行加密、身份验证和完整性保护。IPSEC通常用于建立虚拟私人网络VPN连接,但也可用

    2024年03月10日
    浏览(36)
  • 【华为】IPsec VPN 实验配置(地址固定)

    因为本篇文章,就是IPsec的实验配置的话,它们 两端的IP地址是固定 的 那么就用第一阶段的主模式(Main Mode) 和第二阶段的快速模式(Quick Mode)就好啦 后面会有一个地址不固定的情况下,这个就需要用到野蛮模式的,也就是第一阶段会更改模式啦 R1为企业总部网关,R3为企

    2024年01月23日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包