如何检测局域网内哪些机器安装了SQL Server2000?(34分)

  • 主题发起人 主题发起人 Beyond2002
  • 开始时间 开始时间
不明白,能说具体一点吗?
 
关注当中,需要改问题的解答
 
MSDN for VS2003中文版 搜索 1434 第一项
太长了,不过在SQL Server的服务器网络实用工具中是找不到1434这个冬冬的
看下边的话好像1434是固定的
总而言之只有三种可能
1.不可能完成
2.SQL Server自身有固定的端口
3.Windows系统提供固定的名称服务的动态Port解析(请参考上面的发言)

Connections to SQL Server Over the Internet

Have the network administrator configure the firewall to forward the IP address and TCP port the instance of SQL Server is listening on (using either 1433 for a default instance, or the TCP port you configured a named instance to listen on). Also configure the firewall to forward requests for UDP port 1434 on the same IP address. SQL Server 2000 uses UDP port 1434 to establish communications links from applications.
 
好像那个API: NetServerEnum可以检测
指定其level参数为:101 那么从其bufptr参数返回的 SERVER_INFO_101 结构会给你指明某个机器是否安装Microsoft SQL Server

好像只安装Sybase的机器也会被检测到安装了Microsoft SQL Server,当然就更不能区分是7.0还是2000了
 
好像通过SQL Server本身的一个函数来查询的
 
很简单,你的分也太少了点吧
如何获取局域网中的所有 SQL Server 服务器

我一直想在我的应用程序中获得关于 SQL Server 更详细的信息。直到最近利用 SQLDMO(SQL Distributed Management Objects) 才得以实现这个想法。SQLDMO 提供了非常强大的功能,我们几乎可以利用程序实现任何 SQL Server 拥有的功能。在这篇文章中我将向您展示如何得到局域网中所有 SQL Servers 服务器、如何连接、如何获得服务器中的所有数据库。

SQLDMO 对像来自 SQL Server 2000 提供的动态连接库 SQLDMO.dll。 这个 dll 本身是一个 COM 对像,首先你必须从类型库中引用Microsoft SQLDMO Object Library (Version 8.0). Delphi 会自动为你生成SQLDMO_TLB.PAS文件,文件中包括了所有 COM 对象的接口。

在这里我们需要注意,由于引入的SQLDMO “TDatabase”和 “TApplication”和其它几个缺省类名与 Delphi 自带的类名冲突,所以自己可以修改成 _TypeName 的形式。或者其它的名字,我在这里改成 T_Application 、T_Database 等。

我们下一步要做的是在我们的程序中引入单元文件 SQLDMO_TLB.PAS 。 应用程序单元名称是 SqlServers

程序源代码如下:

unit SqlServers;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

StdCtrls, Buttons, ComCtrls , SQLDMO_TLB;//注意别忘了引入此文件

type

TdmoObject = record

SQL_DMO : _SQLServer;

lConnected : boolean;

end;



type

TFormServersList = class(TForm)

Label1: TLabel;

Label2: TLabel;

CB_ServerNames: TComboBox;

CB_DataNames: TComboBox;

Label3: TLabel;

Label4: TLabel;

Ed_Login: TEdit;

Ed_Pwd: TEdit;

BitBtn1: TBitBtn;

BitBtn2: TBitBtn;

procedure FormCreate(Sender: TObject);

procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);

procedure FormClose(Sender: TObject; var Action: TCloseAction);

procedure FormShow(Sender: TObject);

procedure BitBtn2Click(Sender: TObject);

procedure CB_DataNamesDropDown(Sender: TObject);

private

server_Names : TStringList;

//对象集合

PdmoObject : array of TdmoObject;

//获取所有的远程服务器

Function GetAllServers(ServerList : TStringList) : Boolean;

{ Private declarations }

public

{ Public declarations }

end;



var

FormServersList: TFormServersList;

implementation



{$R *.DFM}



{ TForm1 }



Function TFormServersList.GetAllServers(ServerList : TStringList) : Boolean;

var

sApp : _Application ;

sName : NameList;

iPos : integer;

begin

Result := True ;

try

sApp := CoApplication_.Create ; //创建的对象不用释放,delphi 自己会释放

sName := sApp.ListAvailableSQLServers;

except

Result := False;

Exit;

end;

if sName.Count > 0 then // 之所以 iPos 从1开始,是因为0 位置为空值即 ' '

for iPos := 1 to sName.Count - 1 do

begin

CB_ServerNames.Items.Add(sName.Item(iPos));

ServerList.Add(sName.Item(iPos));

end;

end;



procedure TFormServersList.FormCreate(Sender: TObject);

var

lcv : integer;

begin

server_Names := TStringList.Create;

if not GetAllServers(server_Names) then

begin

Application.MessageBox('无法获取服务器列表,可能缺少客户端DLL库函数','错误提示',MB_OK);

exit;

end;

for lcv := 0 to server_Names.Count - 1 do

begin

SetLength(PdmoObject,lcv + 1);

with PdmoObject[lcv] do

begin

SQL_DMO := CoSQLServer.Create;

SQL_DMO.Name := Trim(server_Names[lcv]);

//登陆安全属性,NT 身份验证

SQL_DMO.LoginSecure := false;

// 设置一个连接超时

SQL_DMO.LoginTimeout := 3;

//自动重新登陆,如果第一次失败后

SQL_DMO.AutoReconnect := true;

SQL_DMO.ApplicationName := server_Names[lcv];

lConnected := false;

end;

end;

end;



procedure TFormServersList.FormCloseQuery(Sender: TObject; var CanClose: Boolean);

begin

server_Names.Free;

end;



procedure TFormServersList.FormClose(Sender: TObject; var Action: TCloseAction);

begin

Action := CaFree;

end;



procedure TFormServersList.FormShow(Sender: TObject);

begin

if CB_ServerNames.Items.Count > 0 then //列举所有服务器名字

CB_ServerNames.Text := CB_ServerNames.Items.Strings[0];

end;



procedure TFormServersList.BitBtn2Click(Sender: TObject);

begin

Close ;

end;



procedure TFormServersList.CB_DataNamesDropDown(Sender: TObject);

var

icount ,Server_B : integer;

begin

CB_DataNames.Clear;

Screen.Cursor := CrHourGlass;

Server_B := CB_ServerNames.Items.IndexOf(CB_ServerNames.Text) ;

with PdmoObject[Server_B].SQL_DMO do

begin

if not PdmoObject[Server_B].lConnected then

try

Connect(Name,Trim(Ed_Login.Text),Trim(Ed_Pwd.Text));

except

Screen.Cursor := CrDefault ;

Application.MessageBox('请检查用户名或密码是否正确','连接失败',MB_OK);

Exit ;

end;

if not VerifyConnection(SQLDMOConn_ReconnectIfDead) then

begin

ShowMessage('在试图连接到SQL SERVER 2000 时出现错误' + #10#13 +

'确信是否加在了动态连接库SQLDMO.DLL');

exit;

end else

PdmoObject[Server_B].lConnected := True ;

Databases.Refresh(true);

for icount := 1 to Databases.Count do

CB_DataNames.Items.Add(Databases.Item(icount,null).name);

end;

Screen.Cursor := CrDefault ;

end

end.

 
SV_TYPE_SERVER 0x00000002 All LAN Manager servers
SV_TYPE_SQLSERVER 0x00000004 Any server running with


NET_API_STATUS NetServerEnum(

LPTSTR servername,
DWORD level,
LPBYTE *bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
DWORD servertype,
LPTSTR domain,
LPDWORD resume_handle
);


 
NetServerEnum
 
he NetServerEnum function lists all servers of the specified type that are visible in the specified domain. For example, an application can call NetServerEnum to list all domain controllers only or all SQL servers only.

You can combine bit masks to list several types. For example, a value of 0x00000003 combines the bit masks for SV_TYPE_WORKSTATION (0x00000001) and SV_TYPE_SERVER (0x00000002).



Note If you require more information on the type, name, and comment for a specific server, use the WNetEnumResource function.



Security Requirements

No special group membership is required to successfully execute NetServerEnum.

NET_API_STATUS NetServerEnum(

LPTSTR servername,
DWORD level,
LPBYTE *bufptr,
DWORD prefmaxlen,
LPDWORD entriesread,
LPDWORD totalentries,
DWORD servertype,
LPTSTR domain,
LPDWORD resume_handle
);


Parameters

servername

Pointer to a Unicode string containing the name of the remote server on which the function is to execute. A NULL pointer or string specifies the local computer.

level

Specifies one of the following values to return the level of information provided.

Value Meaning
100 The bufptr parameter points to an array of SERVER_INFO_100 structures.
101 The bufptr parameter points to an array of SERVER_INFO_101 structures.


bufptr

Pointer to the buffer in which the data set with the level parameter is stored.

prefmaxlen

Preferred maximum length, in 8-bit bytes of returned data.

entriesread

On return, the actual enumerated element count is located in the doubleword pointed to by entriesread.

totalentries

Returns the total number of visible servers and workstations on the network.

servertype

A DWORD mask that filters server entries to return from the enumeration. The defined mask bits specify:

Symbolic constant Value Meaning
SV_TYPE_WORKSTATION 0x00000001 All LAN Manager workstations
SV_TYPE_SERVER 0x00000002 All LAN Manager servers
SV_TYPE_SQLSERVER 0x00000004 Any server running with Microsoft SQL Server
SV_TYPE_DOMAIN_CTRL 0x00000008 Primary domain controller
SV_TYPE_DOMAIN_BAKCTRL 0x00000010 Backup domain controller
SV_TYPE_TIMESOURCE 0x00000020 Server running the Timesource service
SV_TYPE_AFP 0x00000040 Apple File Protocol servers
SV_TYPE_NOVELL 0x00000080 Novell servers
SV_TYPE_DOMAIN_MEMBER 0x00000100 LAN Manager 2.x Domain Member
SV_TYPE_LOCAL_LIST_ONLY 0x40000000 Servers maintained by the browser. See the following Remarks section.
SV_TYPE_PRINT 0x00000200 Server sharing print queue
SV_TYPE_DIALIN 0x00000400 Server running dial-in service
SV_TYPE_XENIX_SERVER 0x00000800 Xenix server
SV_TYPE_MFPN 0x00004000 Microsoft File and Print for Netware
SV_TYPE_NT 0x00001000 Windows NT (either Workstation or Server)
SV_TYPE_WFW 0x00002000 Server running Windows for Workgroups
SV_TYPE_SERVER_NT 0x00008000 Windows NT Non-DC server
SV_TYPE_POTENTIAL_BROWSER 0x00010000 Server that can run the Browser service
SV_TYPE_BACKUP_BROWSER 0x00020000 Server running a Browser service as backup
SV_TYPE_MASTER_BROWSER 0x00040000 Server running the master Browser service
SV_TYPE_DOMAIN_MASTER 0x00080000 Server running the domain master Browser
SV_TYPE_DOMAIN_ENUM 0x80000000 Primary Domain
SV_TYPE_WINDOWS 0x00400000 Windows 95 or later
SV_TYPE_ALL 0xFFFFFFFF All servers


domain

A pointer to a Unicode string containing the name of the domain for which a list of servers is to returned. If NULL is specified, the primary domain is implied.

resume_handle

Reserved. Must be set to zero. Use the Wnet functions.



Return Values

If the function returns account information, the return value is NERR_Success.
If the function fails, the return value is one of the following error codes:

Value Meaning
ERROR_ACCESS_DENIED The user does not have access to the requested information.
NERR_InvalidComputer The computer name is invalid.
ERROR_NO_BROWSER_SERVERS_FOUND No browser servers found.
ERROR_MORE_DATA More entries are available with subsequent calls.


Remarks

The SV_TYPE_LOCAL_LIST_ONLY flag returns the list of servers maintained by the browser internally. This has meaning only on the master browser (or on a computer that has been the master browser in the past). The master browser is the machine that currently has rights to determine which machines can be servers or workstations on the net.

See Also

NetServerDiskEnum, NetQueryDisplayInformation, SERVER_INFO_100, SERVER_INFO_101
 
经典呀。收藏
 
如果能读取其他机器的注册表我倒有简单办法,没几挑语句。
 
寫一段掃描端口的代碼﹐掃描局域網里所有端口1433打開的機器不就行了么??
 
1433端口可以改,1434不可以

转贴一篇文章:
深入探索MS SQL Server 2000网络连接的安全问题

创建时间:2001-11-13
文章属性:原创
文章来源:refdom
文章提交:refdom (refdom_at_263.net)

作者:refdom (refdom@263.net)

下面我们要说的,并不是SQL Server存在的漏洞,而只是一些安全缺陷,存在一些问题,当然这些问题是SQL Server一产生的时候就存在的。

1、MS SQL Server的密码明文传输缺陷

很倒霉,我没有在微软发布SQL Server的时候做下面的分析。当我吃惊地发现SQL Server竟然是使用明文进行密码传输的时候,我就马上去查阅是否有这些资料。可惜已经早早有人提出能够用sniffer获取SQL Server的密码了。不过,既然微软这么大胆,我们还是去看看,分析分析这个缺陷。

当然,SQL Server的连接过程还是先进行TCP连接的三次握手,同服务器建立连接过后,然后进行TDS(tabular data stream)协议的数据交流,可惜的是我一直没有找到TDS协议的具体描述,只有一些片段,所以,都只能一点点地对着数据报分析。谁有TDS协议(SQL Sevrer)的具体描述一定送我一份哦。

直接到login包吧,你会发现,你的用户名完全是明文的,而密码还不是。当你改变密码的时候,你可以看出,相同字符的编码是一样的,密码字符之间用一个相同的字符作为分隔“a5”。呵呵。所以,最傻的办法就是我做的这样,一个字符一个字符地改变密码,然后得到所有字符的对应编码(我不会解密)。
我使用的是SQL Server 2000 。我这里列举一部分得到的对应编码。大家可以很容易得到完整的字符编码。
“a”——b3 “A”——b1
“b”——83 “B”——81
“c”——93 “C”——91
“d”——e3 “D”——e1
“e”——f3 “E”——f1
等等。

对了,在SQL Server中不支持用 '、" 等等符号作为密码,如果你在用这些字符作为密码的话,那就糟糕了,你永远也登陆不上了,除非更改密码。
在TDS数据报的头中规定了一个字节来表示数据报类型,我探测到的是0x10,而我得到的资料说是用0x02来表示Login的数据报,可能是MS SQL Server在协议上有一些改动,因为Sybase也是使用的TDS协议的,那么Sybase可能也是使用的明文传输吧,我手里没有Sybase。可惜没有TDS协议的完整描述,所以,我也偷懒没有写出专门获得SQL Server帐号和密码的sniffer程序,谁能给我TDS协议的详细描述,请email: refdom@263.net。

不过MS对SQL Server的传输还是提供加密办法的,你可以使用SSL来加密。于是我也试了试,可以在实例属性的网络配置里面选择强制协议加密,然后要求你重新启动SQL Server,呵呵,然后呢,你启动起来了么?哈哈,我可是吃了亏的。因为没有SSL证书,所以,你一启动就错误,事件日志中说明是没有提供有效的证书。重新安装吧。该死的MS也不在我选择的时候提醒一下。

嗅探得到数据库帐号意味着什么?如果能够得到SA帐号呢?哈哈,有兴趣可以看看我前些天写的《从IIS转到SQL数据库安全》。


2、明文的数据传输缺陷
如果没有使用加密的协议的话,那么整个数据库的网络数据都是没有加密的,而且是明文传输。无论是从客户端发送命令还是从服务器端得到结果,都是明文传输的。看来,如果你用加密的协议,微软是不会为你做任何安全防护的。我想,目前国内使用的SQL Server数据库差不多都是没有使用SSL来加密,看来在网络上能得到不少东西。


3、神秘的1434端口和服务器信息明文传输缺陷

对于SQL Server2000来说,打开SQL Server客户端准备连接,当拉开服务器列表的时候,整个局域网所有的SQL Server服务器都被列出来了。于是我发现,从我自己的机器(192.168.0.1)上从1434端口广播(192.168.0.255)了这个UDP包,然后,整个局域网中的SQL Server服务器都开始响应这个UDP数据包,这时,我的客户端能够得到所有服务器信息。

这就是客户端进行连接的过程:当客户端连接到服务器时,应用程序请求连接远端计算机,Dbnetlib.dll 将打开到连接中所指定的计算机网络名上的 UDP 端口 1434 的连接。所有运行 SQL Server 2000 的计算机都监听此端口。当一个客户端 Dbnetlib.dll 连接到该端口时,服务器将返回一个监听服务器上运行的所有实例的数据包。对于每个实例,该数据包报告该实例正在监听的服务器 Net-Library 和网络地址。应用程序计算机上的 Dbnetlib.dll 收到该数据包后,选择在应用程序计算机和 SQL Server 实例上都启用的 Net-Library,然后连接为此数据包中的 Net-Library 列出的地址。

通过1434端口传输特定的UDP数据包,然后服务器开始回应,所有这些都是明文传输的,我们可以很容易探测一个IP地址的1434端口,获得该IP地址上运行的SQL Server的相关信息。这些信息包括:主机名称、实例名称、版本、管道名称以及使用的端口等。这个端口是微软自己使用,而且不象默认的1433端口那样可以改变,1434是不能改变的,呵呵,那么我们为了安全,去改变这个1433端口能起什么作用呢?

我们可以来捕获这些数据报,可以发现,通过1434端口的数据非常简单,客户端仅仅简单地发送了02一个字节出去。不过多次捕获,发现有时候发送的是 03。于是我就用下面程序一个一个测试,发送其他数据。不过最后只有02、03、04有回应。看来这三种字节用来做SQL Server探测的。而且你可以发送 02 00 00,也可以发送 02 00 00 00 00等等都能够得到SQL Server的回应,但是发送 02 03就不可以了。

下面是一个利用1434进行探测的程序,可以探测单个IP,也可以用来探测整个局域网的数据库服务器。
////////////////////////////////////////////////////////////
//             
// SQLPing by refdom
//
// Author: refdom. From Chip Andrews
// Email: refdom@263.net
//
////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <string.h>
#include <stdio.h>
#include <winsock2.h>

void decode_recv (char *buf, int size)
{
int index;
int counter = 0;

for (index = 3; index < size; index++)
{
if ((buf[index] == ';') &amp;&amp; (buf[index+1] != ';'))
{
//Look for a semi-colon and check for end of record (;;)
if ((counter % 2) == 0)
{
printf(":");
counter++;
}
else
{
printf("/n");
counter++;
}
}
else
{
if (buf[index] != ';')
{
// If an end of record (;;), then double-space for next instance
printf("%c",buf[index]);
}
else
{
printf("/n");
}
}
}

printf("/n");
}

void listen (void* v)
{
static const unsigned int buffersize = 64000;
static char buffer [buffersize];

SOCKET s = (SOCKET)v;

for (;;)
{
struct sockaddr_in udpfrom;
int udpfromlen = sizeof(udpfrom);
int n = recvfrom(s, buffer, sizeof(buffer), 0, (struct sockaddr *)&amp;udpfrom, &amp;udpfromlen);
int e = WSAGetLastError();

if (n > 0 &amp;&amp; e == 0)
decode_recv(buffer, n);

}
}

void useage()
{
printf("******************************************/n");
printf("SQLPing/n");
printf("/t Written by Refdom/n");
printf("/t Email: refdom@263.net/n");
printf("Useage: sqlping.exe target_ip /n");
printf("*******************************************/n");
}

int main(int argc, char* argv[])
{
WSADATA WSAData;
SOCKET sock;
SOCKADDR_IN addr_in;
char buf[5]={'/x02'};
HANDLE listener;

useage();

if (argc<2)
{
return false;
}

if (WSAStartup(MAKEWORD(2,0),&amp;WSAData)!=0)
{
printf("WSAStartup error.Error:%d/n",WSAGetLastError());
return false;
}

if ((sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==INVALID_SOCKET)
{
printf("Socket failed.Error:%d/n",WSAGetLastError());
return false;
}

addr_in.sin_family=AF_INET;
addr_in.sin_port=htons(1434);
addr_in.sin_addr.S_un.S_addr=inet_addr(argv[1]);

const int SNDBUF = 0;
const int TCPNODELAY = true;
const int BROADCAST = true;

if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (const char*)&amp;SNDBUF, sizeof(SNDBUF))==SOCKET_ERROR)
{
printf("Set SO_SNDBUF failed.Error:%d",WSAGetLastError());
return false;
}
if (setsockopt(sock, SOL_SOCKET, TCP_NODELAY, (const char*)&amp;TCPNODELAY, sizeof(TCPNODELAY))==SOCKET_ERROR)
{
printf("Set TCP_NODELAY failed.Error:%d",WSAGetLastError());
return false;
}
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char*)&amp;BROADCAST, sizeof(BROADCAST))==SOCKET_ERROR)
{
printf("Set SO_BROADCAST failed.Error:%d",WSAGetLastError());
return false;
}

listener = (HANDLE) _beginthread(listen, 0, (void*)sock);

// e = sendto(s, "/08", 1, 0,(sockaddr*) &amp;hostaddr, sizeof(hostaddr));
if (sendto(sock, buf, sizeof(buf), 0,(sockaddr*) &amp;addr_in, sizeof(addr_in))==SOCKET_ERROR)
{
printf("Send failed.Error:%d/n",WSAGetLastError());
return false;
}

printf("Listening..../n/n");

// wait a little while for listener thread
WaitForSingleObject(listener, 5000);

WSACleanup();

printf("SQLPing Complete./n");
return 0;
}

上面的程序只有探测作用,没有破坏性。呵呵

感谢Hectic给我提供的帮助。限于本人的水平,难免有错误之处,还请大家多多指正。如果谁有TDS协议(应用在SQL Server上的)的具体描述手册,请EMAIL给我,谢过了。EMAIL: refdom@263.net
 
这个在CSDN上的C版本上已经有转成DELPHI了,http://expert.csdn.net/Expert/topic/2424/2424337.xml?temp=.9322321
 
按照yubing8 的方法去做,但是SQLDMO.dll引入不了?我用的是d7、sql 2K。
 
多人接受答案了。
 
后退
顶部