一、Telnet介绍
Telnet命令通常用来远程登录。Telnet程序是基于TELNET协议的远程登录客户端程序。提供了在本地计算机上完成远程主机工作的 能力,在终端使用者的电脑上使用telnet程序,用它连接到服务器,终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个 telnet会话,必须输入用户名和密码来登录服务器。
Telnet因为采用明文传送报文,安全性不好。但仍然有很多别的系统可能采用了telnet方式来提供远程登录,因此弄清楚telnet客户端的使用方式仍是很有必要的。telnet命令还可做别的用途:
- 实例1:判断远程服务器是否可以访问
telnet 192.168.120.206
- 实例2:判断域名是否无法解析
telnet www.baidu.com
- 实例3:判断某个端口是否对本机放通
telnet 192.168.2.42 8080
1.1 Telnet协议介绍
Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议。Telnet协议的目的是提供一个相对通用的,双向的,面向八位字节的通信方法,允许界面终端设备和面向终端的过程能通过一个标准过程进行互相交互。
-
基本概念
- NVT
网络虚拟终端(Network Virtual Terminal)。是一种双向的虚拟设备,连接的双方都必需把它们各自的物理终端同NVT之间进行转换。Telnet协议可以工作在任何主机(例如,任何操作系统)或任何终端之间正是由于使用了统一的NVT。
NVT
对于发送的数据:客户机软件把来自用户终端的按键和命令序列转换为NVT格式,并发送到服务器,服务器软件将收到的数据和命令,从NVT格式转换为远地系统需要的格式;
对于返回的数据:远地服务器将数据从远地机器的格式转换为NVT格式,而本地客户机将将接收到的NVT格式数据再转换为本地的格式。 - NVT ASCII
即7比特的ASCII字符集。发送时,每个7比特的字符的最高比特位加0后,以8比特的格式发送。网间网协议族使用的字符集是NVT ASCII。例如FTP、SMTP等。 - IAC
Telnet通信的两个方向都是采用带内信令的方式,字节0xFF叫做IAC(Interpret As Command),意即作为命令来解释。该字节后面的一个字节代表命令。
- NVT
-
工作过程
Telnet 协议工作有规范的流程,大致包括连接、执行命令和断开连接 3 个部分。具体工作流程如图所示
Telnet Workflow
工作流程分为 6 个步骤,每个步骤含义如下:
1.Telnet 客户端通过 TCP 协议的三次握手与 Telnet 服务器建立连接,服务端口默认为23.
2.建立连接后,需要通过用户名和密码才能远程登录到服务器。因此,服务器要求客户端提供用户名和密码。
3.Telnet 客户端输入用户名和密码,尝试登录服务器。
4.成功登录后客户端向服务器发送要执行的命令。
5.服务器收到客户端发来的执行命令,开始执行命令,并将结果返回给客户端。
6.客户端不再需要远程执行命令,将向服务器发送 TCP 断开数据包,用于撤销连接。
二、实验环境
为理解Telnet工作过程与使用Python来分析流量,搭建如下环境:
在R2上启用Telnet作为服务端,在linux主机上安装Telnet程序作为客户端,同时通Wirshark远程捕获Linux 主机在接口流量,在Linux主机上运行Python脚本来分析Telnet流量。
实验环境
三、使用Scapy分析Telnet流量
使用如下Python脚本来捕获Telnet流量,并对Telnet交互命令进行解码。
#!/usr/bin/python3
# -*- coding=utf-8 -*-
from kamene.all import *
import hexdump
my_str = b""
def myhexdump(src,length=16):#每16字节提取一次,进行16进制decode
for i in range(0,len(src),length):
s = src[i : i+length]
hexdump.hexdump(s)
def telnet_monitor_back(pkt):
global my_str
try:
my_str = my_str + pkt.getlayer(Raw).fields["load"] #提取telnet中的数据,比进行拼接
except Exception:
pass
def telnet_monitor(src_ip, dst_ip, dst_port,ifname):
match = " net " + src_ip + " or net "+ dst_ip +" and port " + dst_port
print("开始捕获流量:"+ match )
ptks=sniff(prn=telnet_monitor_back,filter=match,store=1,iface=ifname)
wrpcap("telnet.cap",ptks) #将捕获的数据包到文件
myhexdump(my_str) #解码展示
if __name__=="__main__":
src_ip = "192.168.10.112"
dst_ip = "172.16.10.2"
dst_port = "23"
ifname = "ens37"
telnet_monitor(src_ip, dst_ip, dst_port, ifname)
-
首先在linux主机上运行Python脚本,之后再运行Telnet程序。
Telnet -
结束Python脚本后可以看到整个交互过程执行的命令。
运行结果 -
在同wirsharke查看交互过程:
交互过程
同时发现在命令交互过程中客户端输入一个字符就发送一个Telnet报文,然后远程返回一个应答,之后主机发送一个TCP报文。因此在Python解析中会出现重复字符。
image.png
image.png
四、对Telnet流量进行阻断
使用如下Python脚本对Telnet流量进行嗅探,发现Telnet流量之后发送TCP Reset对Telnet会话进行阻断。
#!/usr/bin/python3
# -*- coding=utf-8 -*-
from kamene.all import *
def tcp_monitor(pkt):
"对传入的数据包,发送TCP Rest进行会话重置"
source_mac = pkt[Ether].fields["src"]
destination_mac = pkt[Ether].fields["dst"]
source_ip = pkt[IP].fields['src']
destination_ip = pkt[IP].fields['dst']
source_port = pkt[TCP].fields['sport']
destination_port = pkt[TCP].fields['dport']
seq_sn = pkt[TCP].fields["seq"]
ack_sn = pkt[TCP].fields["ack"]
print(pkt.summary())
a = Ether(src=source_mac,dst=destination_mac)\
/IP(src=source_ip,dst=destination_ip)\
/TCP(dport=destination_port,sport=source_port,flags=4,seq=seq_sn)
b = Ether(src=destination_mac,dst=source_mac)\
/IP(src=destination_ip,dst=source_ip)\
/TCP(dport=source_port,sport=destination_port,flags=4,seq=seq_sn)
sendp(a,iface=ifname,verbose=False)
sendp(b, iface=ifname,verbose=False)
print("已发送 TCP reset")
print(a.summary())
print(b.summary(),"\n")
def tcp_reset(src_ip,dst_ip,dst_port,ifname,src_port=None):
'''用于捕获过滤数据包'''
if src_port is None:
match = " src host " + src_ip + " and dst host " + dst_ip + " and dst port " + dst_port + " and not tcp[13]=0x004 "#不捕获TCP reset包,否则会一直发送TCP reset
else:
match = " src host " + src_ip + " and dst host " + dst_ip + " and src port " + src_port + " and dst port " + dst_port + " and not tcp[13]=0x004 "
print("开始匹配异常流量:"+match)
sniff(prn=tcp_monitor,filter=match,iface=ifname,store=0)
if __name__ == "__main__":
src_ip = "192.168.10.112"
dst_ip = "172.16.10.2"
dst_port = "23"
ifname = "ens37"
tcp_reset(src_ip, dst_ip, dst_port, ifname)
在Linux 主机上先运行Python脚本,在运行Telnet程序。
发现此时无法连接到主机。
image.png
查看脚本运行脚本,可见一铺货到Telnet流量就会给双方发送TCP Reset。
image.png
在Wirshark上查看数据包交换如下
image.png
网友评论