一、Ubuntu安装Telnet服务

在ubuntu上安装Telnet服务,网上有很多教程。不过大体分为两种方式,一种是telnetd+xinetd,另一种是telnetd+openbsd-inetd。这两种方式都能实现Telnet服务,我这里选择的第二种,原因在于第二种配置更简单,只需要配置一个文件,以下是配置过程。

1.安装telnetd和openbsd-inetd

sudo apt-get install openbsd-inetd telnetd

2.配置文件

sudo leafpad /etc/inetd.conf
#在文件最后一行添加ltenet stream tcp nowait telnetd /usr/sbin/tcpd /usr/sbin/in.telnetd
注意,这里有坑,因为按照网上的教程,安装完telnetd之后他会自动在该文件中写入我们添加的内容,所以很多教程也没提过这个,导致Telnet服务无法正常开启,花费了很多时间。同时如果对vim不熟悉的话,推荐使用leafpad或者gedit编辑器对文件进行编辑。在加入图中所示这一行即可配置成功。

Pro: 信息安全综合训练Lab3 - 图1

3. 重启openbsd-inetd

/etc/init.d/openbsd-inetd restart
一般来说,Telnet服务这时候已经开启了,此时我们通过命令netstat -a |grep telnet 来查看Telnet是否开启。如果有返回,则证明服务开启成功。
需要注意的是,netstat命令在ubuntu中并没有默认安装,需要通过指令sudo apt-get install net-tools 进行安装。Telnet服务开启后的状态如下。
Pro: 信息安全综合训练Lab3 - 图2
Pro: 信息安全综合训练Lab3 - 图3
此时Telnet服务在23端口进行监听,此时我们可以用其他主机对Telnet服务进行测试。

4.Telnet服务测试

要对Telnet服务进行测试,需要注意的是服务端主机和客户端主机需要在同一个网段,由于我们的服务端主机是虚拟机,我们可以将网络设置为桥接模式,此时他们将处于同一个网段,于是可以进行测试了。
Pro: 信息安全综合训练Lab3 - 图4

我们的客户端主机ip为: 172.27.185.156
Pro: 信息安全综合训练Lab3 - 图5
我们的服务端主机ip为:172.27.146.235
Pro: 信息安全综合训练Lab3 - 图6
接下来我们可以在客户端进行测试了,这里我推荐一个远程连接软件MobaXterm,这是一款集合了几乎所有主流远程连接功能的强大工具,界面简洁,功能强大。我们新建一个Telnet会话,如下图。
Pro: 信息安全综合训练Lab3 - 图7
我们点击ok,输入主机密码就可以惊喜的发现已经连接上Telnet服务了,如图。连接后点击X或者输入exit即可断开Telnet连接。

Pro: 信息安全综合训练Lab3 - 图8
这时候我们已经成功建立Telnet会话,从ubuntu主机上,输入命令netstat -pantu 我们可以发现我们的客户端的23端口已经和服务端的23187端口建立了Telnet连接。
Pro: 信息安全综合训练Lab3 - 图9
此时我们已经测试完成ubuntu作为Telnet服务端。我们还需要测试ubuntu作为客户端与其他主机建立Telnet连接。由于我所使用的主机为windows 10家庭版,默认禁止Telnet服务,所以直接尝试自己连自己。在终端输入指令> telnet 127.0.0.1 23
即可连接,需要注意,使用Telnet指令连接时与windows不同,需要在后面加上端口,不然会连接失败。如图。
Pro: 信息安全综合训练Lab3 - 图10


二、Ubuntu安装VNC服务

VNC服务也是一种远程连接服务,不过提供桌面化远程操作环境。在ubuntu上安装VNC服务的操作与Telnet差别不大,操作过程如下。

1.安装VNC服务器

sudo apt-get install vnc4server
这里我选择使用vnc4server提供vnc服务。

2.安装桌面环境

sudo apt-get install gnome-panel gnome-settings-daemon metacity nautilus gnome-terminal
如果不装桌面环境,VNC也是可以直接使用的,不过界面会很简陋,所以需要安装桌面环境。

3.配置桌面环境

vi /home/rainturtle/.vnc/xstartup
将文件内容替换为如下所示:
Pro: 信息安全综合训练Lab3 - 图11
需要注意的是,我们此时用leafpad和gedit都无法编辑该文件,即使加了sudo。不过可以在桌面环境下双击打开此文件,默认使用builder打开。此时就可以在图形化界面进行粘贴复制了。

4.开启服务

vnc4server
此时会要求你输入vnc服务的密码,其他主机通过该密码进行vnc连接,密码长度在6-8位,不能过长或过短。输入密码后,此时我们就已经开启VNC服务了。
Pro: 信息安全综合训练Lab3 - 图12
我们可以看到,VNC服务运行在5901端口,VNC服务端和客户端ip同Telnet实验。服务端ip为172.27.146.235
我们依旧使用MobaXterm作为客户端进行连接。配置如图。
Pro: 信息安全综合训练Lab3 - 图13
连接后就可以看到一个桌面化环境了,跟在ubuntu本地使用无太大差别。
Pro: 信息安全综合训练Lab3 - 图14
同样在vnc服务端可以查看到连接情况。
Pro: 信息安全综合训练Lab3 - 图15
Telnet和VNC都是远程连接服务,他们有一个共同点就是传输信息是不加密,直接明文传输。所以现在更主流的远程连接是SSH连接,安全加密。


三、搭建简易服务器提供文档下载功能

对于一个简单Web服务器的搭建,我选择使用的python进行编写,主要调用socket来编写服务器代码。通过socket可以很快速的实现服务器与客户端的通信。HTTP协议是建立在TCP协议之上的,在通过socket建立tcp连接之后,按照HTTP协议格式模拟web服务器。
这是代码主要逻辑,通过socket建立tcp连接,使用多进程连接处理并发连接,依靠单个进程模拟HTTP协议。
Pro: 信息安全综合训练Lab3 - 图16
然后在单个进程中,我们收到客户端的连接,客户端发送的信息按照HTTP协议格式,我们的发回的数据也应该依照HTTP协议的格式,符合HTTP响应包的格式。HTTP响应由三部分组成:状态行、响应头、响应正文;
状态行:包括协议版本Version、状态码Status Code、回应短语;
响应头:包括搭建服务器的软件,发送响应的时间,回应数据的格式等信息;
响应正文:就是响应的具体数据。
最重要的是响应头和状态行,这是浏览器处理我们的响应包的基础,所以以下代码是必须的。
Pro: 信息安全综合训练Lab3 - 图17
通过这两行代码,我们可以让浏览器识别我们的响应包为HTTP包。注意,每设置一个响应头,末尾都需要加\r\n,这符合HTTP协议。
在响应正文即body中,我们可以填写HTML代码,像设置响应头和状态行一样。不过由于HTML文档比较小还好,但是我们的HTML文档往往较大,直接写进代码一点也不优雅。所以我们通过将HTML代码保存在文件中,通过读取文件内容,返回不同的web界面。如图所示。
Pro: 信息安全综合训练Lab3 - 图18
然后通过以下代码对body部分进行替换。
Pro: 信息安全综合训练Lab3 - 图19
这样我们可以很方便的组织HTML页面,完成实验功能总共用了三个HTML页面,分别是登录页,错误页,主页。当然考察静态页面的制作不是重点,所以界面写得很简单,代码也用的txt保存,也不放进文档里了。
Pro: 信息安全综合训练Lab3 - 图20
以下是读取各HTML文件和文件下载所需要文件。
image.png
读取文档进body后,就可以构造响应包了,将包头、状态行、body部分连接返回构造好的响应包,然后关闭socket连接。
Pro: 信息安全综合训练Lab3 - 图22
需要注意的是,最先开始编写的时候,来自服务端的响应包出现了中文乱码现象。如图。
Pro: 信息安全综合训练Lab3 - 图23
具体原因忘了,不过依稀记得几个设置的重点。
首先是socket传输传输的是二进制流,所以需要将str类型的响应包转化为bytes类型的响应包。语句是response.encode(‘utf-8’),理论上还可以使用bytes(response,’utf-8’)实现,不过我在代码里用这种方式还是出现乱码现象。
除了设置这里,我还对HTML文件的编码格式进行了设置,用notepad++转换为utf-8格式。同时在HTML文档头部声明了他的编码方式,如图。
Pro: 信息安全综合训练Lab3 - 图24
如此成功解决了中文乱码问题,成熟的登录界面如下图所示。
Pro: 信息安全综合训练Lab3 - 图25

Pro: 信息安全综合训练Lab3 - 图26
然后怎么实现登录功能呢?这里我们又不能单靠js进行校验,因为我们的服务器处理不了,我们也不能像在后端框架里一样进行校验,也没有提取参数的函数。所以我选择用正则来对请求包进行分析,查看是否有用户名和密码并提取用户名和密码进行校验,然后根据校验结果返回登录失败页面或者登录成功页面。正则编写和使用如下。
Pro: 信息安全综合训练Lab3 - 图27
第一个pattern字段是分别匹配出用户名和密码字段,然后提取出用户名和密码,和我们设置的用户名和密码进行比较,如果正确返回后台主页,如下图代码。
Pro: 信息安全综合训练Lab3 - 图28
如果用户名和密码错误,则返回错误页面。其实错误页面只是多加了一个js的alert而已,然而实现这种一点的改变却需要重新读取个HTML文档, 很臃肿。
Pro: 信息安全综合训练Lab3 - 图29

我们登陆成功的页面如下图,登陆成功后弹出欢迎消息框,然后是下载界面。
Pro: 信息安全综合训练Lab3 - 图30
image.png

image.png
界面比较简陋,不过还是很优雅的。此时我们点击链接即可下载文档。
错误界面是如下,主要是弹框然后回到登陆界面。
Pro: 信息安全综合训练Lab3 - 图33

还有一个问题,怎么实现导航栏地址和页面匹配呢?不像django或者flask等框架可以直接设置路由。这里还是使用正则匹配响应头,根据响应头来返回不同的页面。当然,这只是个简易实现的服务器与后端处理框架杂合子,鲁棒性很差,有很多方法可以绕过正则。请求头的设置如下图。
Pro: 信息安全综合训练Lab3 - 图34
这里的请求头字段为: /index?user=admin&password=123456,通过form表单提交实现,也并未对get或者post方法进行区分。
image.png
这里的请求头字段为:/paper,通过
标签实现。
对于文件下载,并没有真正限制是否有登录,如果用户直接在导航栏搜索/paper,也可以直接下载,或者只要用户请求头中包含paper字样都可以进行文件下载,正则设置的很松。不过可以将请求头字段复杂化,可以很好的解决问题。
进行到这儿,我们已经完成搭建服务器大部分工作了,只剩下一两片乌云笼罩在大厦头顶了。最后还需要解决的问题是如何实现文件传输,首相想到的是通过socket进行文件传输,然而需要服务端和客户端的配合,而我们是B/S架构,没有客户端,所以不成立。再查阅资料,还有一种实现方式,调用现有的python库使用python -m SimpleHTTPServer 8000 来实现,但这很明显不符合我们的要求。所以只剩最后一种方案,通过HTTP协议将文件传输到浏览器供用户下载。
确定了实现方向,但是前路坎坷,踩了很多坑。
HTTP协议传送文件进行下载,响应包头需要包含如下字段。
Content-Type:application/octet-stream
Content-Disposition: attachment;filename = 信息安全综合训练Lab3_xxx.docx
这告诉浏览器这是一个文件,以文件方式来解析他。在进行响应头和响应体的拼接的时候,遇到另一个坑,socket通信是二进制的,我们的响应头最开始设置的是字符串格式,而在python3中,已经对str类型和bytes类型进行了严格区分,不能再混用,所以需要将响应头或响应体转换成同一种格式再进行拼接。但是,由于我们读取的docx文档是二进制形式的,所以进行decode()的时候,有些字符并不能转换成Unicode,导致出错。所以只能把响应头和响应体都设置成bytes类型再进行拼接。
除此之外,在实现这些之后,程序还是运行不起来,浏览器识别不了我们的文件,即使更改后缀之后仍然无法打开。
Pro: 信息安全综合训练Lab3 - 图36
最后终于在某篇文档中看到,http_header和http_body之间需要两个\r\n分隔而不是一个。加上一个\r\n后,问题解决,我们能下载我们的报告了,然而遗憾的是我们的响应头中报告名不能为中文,似乎可以先为字符串,再bytes()转换再拼接,就不试了。
image.png
image.png
image.png
全文排版比较散乱,还望见谅。虽然写出来的服务器只是个demo,模拟了服务器的一些功能。不过通过一整天的学习,收获还是蛮多的,挺充实的。


代码

server.py

  1. # coding:utf-8
  2. # server.py
  3. import socket
  4. from multiprocessing import Process
  5. import re
  6. # 读取登录界面
  7. response_login = ""
  8. with open('login.txt', 'r', encoding='utf-8') as f:
  9. response_login += f.read()
  10. #print(response_login)
  11. response_admin=""
  12. with open('admin.txt', 'r', encoding='utf-8') as f:
  13. response_admin += f.read()
  14. response_error=""
  15. with open('error.txt', 'r', encoding='utf-8') as f:
  16. response_error += f.read()
  17. data=b""
  18. with open("信息安全综合训练Lab3_xxx.docx","rb") as img:
  19. data+=img.read()
  20. def handle_client(client_socket):
  21. """
  22. 处理客户端请求
  23. """
  24. response_start_line = "HTTP/1.1 200 OK\r\n"
  25. response_headers = "Server: RainTurtle\r\n"
  26. #正则匹配用户名和密码
  27. pattern="user=(.*)&password=(\S*).*HTTP"
  28. download="paper"
  29. request_data = client_socket.recv(1024).decode()
  30. print("request data:", request_data)
  31. rec=re.search(pattern,request_data)
  32. down=re.search(download,request_data)
  33. if rec:
  34. user=rec.group(1)
  35. password=rec.group(2)
  36. print(user+" "+password)
  37. # 如果密码正确
  38. if user == "admin" and password == "123456":
  39. print("correct!")
  40. response_body=response_admin
  41. response = response_start_line + response_headers + "\r\n" + response_body
  42. # 向客户端返回响应数据
  43. client_socket.send((response).encode('utf-8'))
  44. # 关闭客户端连接
  45. client_socket.close()
  46. else:
  47. print("error!")
  48. response_body=response_error
  49. response = response_start_line + response_headers + "\r\n" + response_body
  50. # 向客户端返回响应数据
  51. client_socket.send((response).encode('utf-8'))
  52. # 关闭客户端连接
  53. client_socket.close()
  54. return
  55. if down:
  56. # application/octet-stream\r\nContent-Disposition: attachment;filename = lan.png
  57. headers=b'HTTP/1.1 200 OK\r\nServer: My server\r\nContent-Type:application/octet-stream\r\nContent-Disposition: attachment;filename = 17281278.docx\r\n\r\n'
  58. response=headers+data
  59. client_socket.send(response)
  60. client_socket.close()
  61. return
  62. # 构造响应数据
  63. response_body = response_login
  64. response = response_start_line + response_headers + "\r\n" + response_body
  65. # 向客户端返回响应数据
  66. client_socket.send((response).encode('utf-8'))
  67. # 关闭客户端连接
  68. client_socket.close()
  69. if __name__ == "__main__":
  70. # 建立TCP连接,绑定本机8000端口,最高允许同时连接数128个
  71. server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  72. #绑定端口
  73. server_socket.bind(("", 8000))
  74. #监听端口
  75. server_socket.listen(128)
  76. while True:
  77. #收到连接多进程处理
  78. client_socket, client_address = server_socket.accept()
  79. print("%s, %s用户连接" % client_address)
  80. handle_client_process = Process(target=handle_client, args=(client_socket,))
  81. handle_client_process.start()
  82. client_socket.close()

login.txt

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Login</title>
  6. <style type="text/css">
  7. body{
  8. background-color: #e3e3e3;
  9. margin-top: 50px;
  10. }
  11. h1{
  12. text-align: center;
  13. }
  14. div{
  15. width: 400px;
  16. height: 300px;
  17. background-color: white;
  18. border-radius: 10px;
  19. margin-top: 200px;
  20. margin-left: 35%;
  21. padding: 20px;
  22. text-align: center;
  23. }
  24. form{
  25. margin-top:50px;
  26. }
  27. button{
  28. width: 50px;
  29. height: 30px;
  30. margin-left: 35px;
  31. }
  32. </style>
  33. </head>
  34. <body>
  35. <div>
  36. <h1>登录</h1>
  37. <form action="/index">
  38. 用户名 <input type="text" name="user"><br><br>
  39. &nbsp;密码&nbsp;&nbsp;&nbsp;&nbsp;<input type="password" name="password">
  40. <br><br>
  41. <button type="submit">登录</button>
  42. </form>
  43. </div>
  44. </body>
  45. </html>

admin.txt

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>文件下载</title>
  6. </head>
  7. <script>
  8. alert("欢迎您,爱打篮球的CXK!");
  9. </script>
  10. <style type="text/css">
  11. div{
  12. margin-left: 100px;
  13. margin-top: 200px;
  14. text-align: center;
  15. }
  16. </style>
  17. <body>
  18. <div>
  19. <h2>文件下载</h2>
  20. <h3>实验报告!点击就送!</h3>
  21. <a href="/paper">信息安全综合训练Lab3_xxx</a>
  22. </div>
  23. </body>
  24. </html>

error.txt

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Login</title>
  6. <style type="text/css">
  7. body{
  8. background-color: #e3e3e3;
  9. margin-top: 50px;
  10. }
  11. h1{
  12. text-align: center;
  13. }
  14. div{
  15. width: 400px;
  16. height: 300px;
  17. background-color: white;
  18. border-radius: 10px;
  19. margin-top: 200px;
  20. margin-left: 35%;
  21. padding: 20px;
  22. text-align: center;
  23. }
  24. form{
  25. margin-top:50px;
  26. }
  27. button{
  28. width: 50px;
  29. height: 30px;
  30. margin-left: 35px;
  31. }
  32. </style>
  33. <script>
  34. alert("密码错误");
  35. </script>
  36. </head>
  37. <body>
  38. <div>
  39. <h1>登录</h1>
  40. <form action="/index">
  41. 用户名 <input type="text" name="user"><br><br>
  42. &nbsp;密码&nbsp;&nbsp;&nbsp;&nbsp;<input type="password" name="password">
  43. <br><br>
  44. <button type="submit">登录</button>
  45. </form>
  46. </div>
  47. </body>
  48. </html>