精华内容
下载资源
问答
  • 这是作者的系列网络安全...本文将分析Python攻防之构建Web目录扫描器,实现IP代理池。本文参考了爱春秋ADO老师的课程内容,这里也推荐大家观看他Bilibili和ichunqiu的课程,同时也结合了作者之前的编程经验进行讲解。

    这是作者的系列网络安全自学教程,主要是关于网安工具和实践操作的在线笔记,特分享出来与博友共勉,希望您们喜欢,一起进步。前文分享了Python弱口令攻击、自定义字典生成,调用Python的exrex库实现,并结合Selenium和BurpSuite实现网站暴库案例;本文将分析Python攻防之构建Web目录扫描器,实现IP代理池。本文参考了爱春秋ADO老师的课程内容,这里也推荐大家观看他Bilibili和ichunqiu的课程,同时也结合了作者之前的编程经验进行讲解。

    作者作为网络安全的小白,分享一些自学基础教程给大家,希望你们喜欢。同时,更希望你能与我一起操作深入进步,后续也将深入学习网络安全和系统安全知识并分享相关实验。总之,希望该系列文章对博友有所帮助,写文不容易,大神请飘过,不喜勿喷,谢谢!

    下载地址:https://github.com/eastmountyxz/NetworkSecuritySelf-study
    百度网盘:https://pan.baidu.com/s/1dsunH8EmOB_tlHYXXguOeA 提取码:izeb

    展开全文
  • Python安全小工具之Web目录扫描

    千次阅读 2017-11-04 15:14:42
    本次的程序实质是Web目录的暴力破解,即基本过程为取出字典内容、和目标网站进行组合、然后进行请求识别,能否扫描出相应的Web目录主要看字典的强大与否。至于字典,网上也很多资源,收集一下即可。 这里为了方便,...

    本次的程序实质是Web目录的暴力破解,即基本过程为取出字典内容、和目标网站进行组合、然后进行请求识别,能否扫描出相应的Web目录主要看字典的强大与否。至于字典,网上也很多资源,收集一下即可。

    这里为了方便,将收集的UA自己保存成一个文件方便其他脚本直接调用。

    user_agent_list.py:

    #!/usr/bin/python
    #coding=utf-8
    import random
    
    def get_user_agent():
    	user_agent_list = [
    		{'User-Agent':'Mozilla/4.0 (Mozilla/4.0; MSIE 7.0; Windows NT 5.1; FDM; SV1; .NET CLR 3.0.04506.30)'},
    		{'User-Agent':'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; en) Opera 11.00'},
    		{'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.2) Gecko/2008092313 Ubuntu/8.04 (hardy) Firefox/3.0.2'},
    		{'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.1.15) Gecko/20101027 Fedora/3.5.15-1.fc12 Firefox/3.5.15'},
    		{'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.551.0 Safari/534.10'},
    		{'User-Agent':'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.2) Gecko/2008092809 Gentoo Firefox/3.0.2'},
    		{'User-Agent':'Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/7.0.544.0'},
    		{'User-Agent':'Opera/9.10 (Windows NT 5.2; U; en)'},
    		{'User-Agent':'Mozilla/5.0 (iPhone; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko)'},
    		{'User-Agent':'Opera/9.80 (X11; U; Linux i686; en-US; rv:1.9.2.3) Presto/2.2.15 Version/10.10'},
    		{'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru-RU) AppleWebKit/533.18.1 (KHTML, like Gecko) Version/5.0.2 Safari/533.18.5'},
    		{'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9b3) Gecko/2008020514 Firefox/3.0b3'},
    		{'User-Agent':'Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; fr) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16'},
    		{'User-Agent':'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.20 (KHTML, like Gecko) Chrome/11.0.672.2 Safari/534.20'},
    		{'User-Agent':'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; InfoPath.2)'},
    		{'User-Agent':'Mozilla/4.0 (compatible; MSIE 6.0; X11; Linux x86_64; en) Opera 9.60'},
    		{'User-Agent':'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.366.0 Safari/533.4'},
    		{'User-Agent':'Mozilla/5.0 (Windows NT 6.0; U; en; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.51'}
    	]
    
    	return random.choice(user_agent_list)


    然后将该脚本放在名为agent_proxy目录中。

    接着是主程序,使用多线程以及读取文件的形式来实现Web目录的暴破扫描,最后将扫描出来的结果以HTML文件的超链接的形式展现:

    #!/usr/bin/python
    #coding=utf-8
    import requests
    import sys
    from Queue import Queue
    import threading
    from agent_proxy import user_agent_list
    from optparse import OptionParser
    
    class DirScanMain:
    	"""docstring for DirScanMain"""
    	def __init__(self, options):
    		self.url = options.url
    		self.filename = options.filename
    		self.count = options.count
    		
    	class DirScan(threading.Thread):
    		"""docstring for DirScan"""
    		def __init__(self, queue,total):
    			threading.Thread.__init__(self)
    			self._queue = queue
    			self._total = total
    				
    		def run(self):
    			while not self._queue.empty():
    				url = self._queue.get()
    
    				#
    				threading.Thread(target=self.msg).start()
    
    				try:
    					r = requests.get(url=url, headers=user_agent_list.get_user_agent(), timeout=8,)
    					if r.status_code == 200:
    						sys.stdout.write('\r' + '[+]%s\t\t\n' % (url))
    						result = open('result.html','a+')
    						result.write('<a href="' + url + '" target="_blank">' + url + '</a>')
    						result.write('\r\n</br>')
    						result.close()
    				except Exception as e:
    					pass
    
    		def msg(self):
    			# print self._total,self._queue.qsize()
    			per = 100 - float(self._queue.qsize())/float(self._total) * 100
    			percentage = "%s Finished| %s All| Scan in %1.f %s"%((self._total - self._queue.qsize()),self._total,per,'%')
    			sys.stdout.write('\r'+'[*]'+percentage)
    
    	def start(self):
    		result = open('result.html','w')
    		result.close()
    
    		queue = Queue()
    
    		f = open('./dics/%s'%self.filename,'r')
    		for i in f:
    			queue.put(self.url+i.rstrip('\n'))
    
    		#
    		total = queue.qsize()
    
    		threads = []
    		thread_count = int(self.count)
    
    		for i in range(thread_count):
    			threads.append(self.DirScan(queue,total))
    		for i in threads:
    			i.start()
    		for i in threads:
    			i.join()
    
    if __name__ == '__main__':
    
    	print '''
    	 ____  _      ____                  
    	|  _ \(_)_ __/ ___|  ___ __ _ _ __  
    	| | | | | '__\___ \ / __/ _` | '_ \ 
    	| |_| | | |   ___) | (_| (_| | | | |
    	|____/|_|_|  |____/ \___\__,_|_| |_|
    
    	'''
    
    	parser = OptionParser('./web_dir_scan.py -u <Target URL> -f <Dictionary file name> [-t <Thread_count>]')
    	parser.add_option('-u','--url',dest='url',type='string',help='target url for scan')
    	parser.add_option('-f','--file',dest='filename',type='string',help='dictionary filename')
    	parser.add_option('-t','--thread',dest='count',type='int',default=10,help='scan thread_count')
    	(options,args)=parser.parse_args()
    
    	if options.url and options.filename:
    		# start(options.url,options.filename,options.count)
    		dirscan = DirScanMain(options)
    		dirscan.start()
    		sys.exit(1)
    	else:
    		parser.print_help()
    		sys.exit(1)


    运行结果:




    后期会使用Django框架编写一个Web目录扫描系统,当然是使用简单的暴破的原理,想着是有一个界面平台来方便操作。

    展开全文
  • 效果展示 项目目录目录底下那么多文件,怎么就扫描到两个呢?emmm,这就是扫描器的缺点所在,等下说。

    效果展示

    在这里插入图片描述
    项目目录:
    在这里插入图片描述

    引言

    不知是否有小伙伴在学习Web安全相关的知识,如果有的话,那应该对XSS,SQL注入,文件上传,一句话脚本等等基本功应该是再熟悉不过了。最初学习的时候是它,实战最先测试的也是它,就跟饭前先洗手一样,成了固定习惯。

    但是呢,这些基本功的使用是需要环境的,人家的网站不会“明目张胆”的把一个漏洞挂在首页上,并在旁边打上标注“这系个漏洞,一个你没油见过的船新漏洞,漏洞不用冲,金币全靠打,只需三翻钟,你奏会拥有介个网站的管理权限,快来锌动吧!”

    为什么漏洞需要去“挖”呢?为什么安全从业者的工作叫“渗透”呢?就是因为没人知到漏洞在哪里,需要根据自己以往的经验以及平常的练习,猜测网站的设计在哪里可能存在疏忽,然后再去验证。用“大胆假设,谨慎验证”来描述其过程再合适不过了。

    我们知道啊,如果想使用XSS,SQL注入之类的技巧,需要找到一个网站与用户进行数据交互的功能点,比如搜索框,评论区,文件上传功能点等等。在这些地方,服务器需要接受用户的输入数据进行一些处理,如果没有全面的过滤用户输入,就可能留下隐患。这些地方就大概率可以使用到我们平常练习的小技巧。

    上面也说到了,没人会傻到让主页存在漏洞,或者说即使有漏洞,也早被人发现并修复了。这种现实情况会“劝退”一部分像我一样的“新手玩家”,找了个网站,主页看了半天,除了熟悉网站小字的内容外,好像和其他用户没什么区别,果断放弃此网站,下一个。然,下一个是同样的情况,果断放弃安全,说再见。

    理想很丰满哈,现实比理想还丰满,一屁股坐下去能把理想坐出“奥利给”来。对于有经验的Web安全人员来说,他们在简单的分析了网站的whois域名、管理者信息,网站的基本设计情况后,就会开始寻找适合用“武力”的地方,比如,后台管理系统的登录入口界面:
    在这里插入图片描述
    (这是我从搜索引擎里随便找的,别去测试人家,你是需要负责的哦~)

    我们可以看到,这种网页最适合我们使用技巧了,什么XSS,SQL啊都给它试一遍。(成功的概率会很低,因为随着大家安全意识的提高,以及各种CMS的出现,这种简单的漏洞越来越少,如今更多的隐患是网站设计时的逻辑疏忽。)

    现在开发网站的框架越来越多,如果管理者很懒,很可能随便找了一个开始“填空”。这些框架,大部分都会提供后台管理功能,以方便管理者管理网站,但是为了避免随便什么人都能进入,就会提供上面的登录验证功能。

    现在我们来看,上面功能点的目录:
    在这里插入图片描述
    asp…,呵,获得一个信息点(再说一遍,别去测试人家~)。

    综上,在对一个Web站点进行安全测试的前期,会需要寻找网站的一些“易碎”网页,比如上面的登录点。那怎么知道网站的一些隐藏功能点的网址目录呢?就是这篇文章说的——对网站进行目录扫描。

    简介

    对网站目录进行扫描,原理很简单,事先准备子目录字典,如:
    在这里插入图片描述
    (这种资源很多,可以去github上找找哦)

    然后将其逐个拼接到网站主目录后,形成新的网址,并对其发送HTTP请求,如果返回成功,则判断该页面存在。

    其实跟端口扫描如出一辙,就是字典爆破。不过因为使用的协议不同了,建立链接的方式相应改变而已。

    在学习过程中的小伙伴,可能会经常在一些靶场网站上练习,来强化自己的技能。如果刷题刷多了,我们会发现一个规律,题目需要的网页就那么几个,比如main.html,main.php,flag.php,flag.php3,robots.txt,index.html等等等等。这时,你就可以准备一个自己的刷题字典,每做一道题时,就先扫一遍。因为是特制的字典,不但针对性强,字典还很小,效率极其高,简直不要太爽。

    下面说说缺点,可能有的小伙伴已经看到了。最开的动图里面扫出了两个页面index和robots,但是项目目录下有很多文件并没有扫到。为什么呢?对,就是因为事先准备的字典里没有。那第一个缺点就有了,它的扫描效果依赖字典的全面度。但是,当字典太大了,扫描时间又会变长,这也算是我们需要权衡的地方吧。

    和端口扫描器一样啊,它也有特殊情况。在端口扫描里,有时建立连接失败恰恰说明端口开放,而网站目录扫描,在返回正常时,有时恰恰说明页面不存在。哈?理解不了。

    其实这是开发者的一种安全手法,背后的逻辑就是,当用户访问不存在页面时,我给他统一返回一个指定的页面,比如跳转“主页”之类的。如此,每个请求都会成功,但是所请求页面却不一定存在。这会让许多扫描器丧失效果,那我们怎么处理这个问题呢?先记住这个问题,我们在实现的时候一点点想。

    目前较为成熟的,或者比较出名的目录扫描器可能是“御剑”吧,听名字还挺修仙的,它应该属于早期的一款工具,感兴趣的小伙伴可以去了解下。

    设计实现

    类的设计

    简单分析一下,需要的参数有什么呢?网站的主目录(host),这个是必须的。其次,还需要待拼接的子目录序列(paths),我们暂时将其设计成list。再有呢,就是多线程的数量(thread_num),毕竟扫描的太慢,我们也不太能接受。

    属性完了,说行为。与端口扫描器差不多,需要一个开场动画animation,和启动扫描器的接口run。

    能初步想到的就是这些,于是有:

    + host
    + thread_num
    + paths
    + animation()
    + run()

    直接开始吧,依旧从init函数开始写起,因为它最明确,好设计。

    class WebScanner(object):
        
        def __init__(self, host, thread_num, paths):
            """initialization object"""
            
            self.host = host if host[-1] != '/' else host[:-1]
            self.thread_num = thread_num
            self.paths = paths
    

    这里在初始化host的时候啊,我们做个判断看看最后是否有/,如果有的话就去掉。因为我们的子目录字典里的数据,默认格式都是开头有/的,为了避免重复,在这里多处理一下。

    两个行为,最简单的当然是animation了。于是:

        def animation(self):
            """opening animation"""
            
            return r'''
     __      __      ___.     _________                                         
    /  \    /  \ ____\_ |__  /   _____/ ____ _____    ____   ____   ___________ 
    \   \/\/   // __ \| __ \ \_____  \_/ ___\\__  \  /    \ /    \_/ __ \_  __ \
     \        /\  ___/| \_\ \/        \  \___ / __ \|   |  \   |  \  ___/|  | \/
      \__/\  /  \___  >___  /_______  /\___  >____  /___|  /___|  /\___  >__|   
           \/       \/    \/        \/     \/     \/     \/     \/     \/       
            '''
    

    字符画的设计,在端口扫描器里做了分享,这里再提供下。如果自己有其它好用的也是可以的哈。(传送门

    接下来设计重头戏吧,启动函数run。对于run呢,我们采用相同的处理方式,让它建立相应数量的子线程,子线程的工作再分一个函数写,这样的结构更加明确些(虽然这里没什么必要)。

        def run(self):
            """start scanner"""
    
            for i in range(self.thread_num):
                threading.Thread(target=self._subthread).start()
    

    那子线程函数的设计呢?其实并不复杂,简单分析下,线程要做的就是从paths中拿出来一个子目录(可以用list的pop实现此行为),与主目录host进行拼接,并对其发送HTTP请求,根据请求结果输出相应内容就好了。

        def _subthread(self):
            "get url from dictionary and try to connect"
    
            while self.paths:
                sub_url = self.paths.pop()
                headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
                            'Chrome/51.0.2704.63 Safari/537.36'}
                url = self.host + sub_url
                req = urllib.request.Request(url=url, headers=headers)
                try:
                    ##Discard requests longer than two seconds
                    request = urllib.request.urlopen(req, timeout=1)
                    result = request.geturl(), request.getcode(), len(request.read())
                    print(result)
                except:
                    pass
    

    对于HTTP链接的建立,我选择了标准库urllib,并没有什么特殊的原因,只是因为它是标准库,不用另外安装。而且因为它是标准库,在速度层面上也是比较快的,如果你习惯用requests等第三方库,完全由你决定,reqeusts其实也是封装了urllib,做的工作比urllib多了很多,相应的会慢些。

    对于请求成功与否的处理,我没有找到像socket中的connect_ex一样,可以替代connect不抛出异常的方法,所以这里用异常来处理的,如果你有更好的方式处理它,就放弃异常(因为它一点都不优雅)。

    第二个注意点是header的设计,这里根据网站的反爬机制相应设计就好,你也可以把它设计成接口,让用户来自定义这个值。

    还有一点,还记的在简介里,我们留下的那个问题吗?回去看一眼,再看看我们print的时候,是怎么知道哪些页面是不存在,但不抛出异常的。

    ok,任务完成。但是我仍旧希望有计时功能,毕竟能看到运行时间,会显得工具很秀(sao)。

    那运行时间应当从什么时候开始,什么时候结束呢?其实如果你看了端口扫描器,这个结论很好得出。在run建立线程的时候开始计时,最后一个线程完成任务后结束计时。如:

        _running_time = 0
        _number_of_threads_completed = 0
    
        def run(self):
            """start scanner"""
    
            WebScanner._running_time = time.time()
            for i in range(self.thread_num):
                threading.Thread(target=self._subthread).start()
    
        def _subthread(self):
            "get url from dictionary and try to connect"
    
            while self.paths:
                sub_url = self.paths.pop()
                headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
                            'Chrome/51.0.2704.63 Safari/537.36'}
                url = self.host + sub_url
                req = urllib.request.Request(url=url, headers=headers)
                try:
                    ##Discard requests longer than two seconds
                    request = urllib.request.urlopen(req, timeout=1)
                    result = request.geturl(), request.getcode(), len(request.read())
                    print(result)
                except:
                    pass
            WebScanner._number_of_threads_completed += 1
            if WebScanner._number_of_threads_completed == self.thread_num:
                print("Cost time {} seconds.".format(time.time() - WebScanner._running_time))
    

    至此,整个类的设计完毕。

    测试脚本

    接下来就可以测试一下啦。首先啊,创建对象我们需要host,thread_num,和paths。host和thread_num都好说,这个paths列表怎么得到呢?因为我们的字典都是一些文件,需要我们读取文件内容生成列表,那接受的用户参数就来指定读取哪些文件就好了。

    def create_parser():
        parser = argparse.ArgumentParser(description="The scanner of web catalog")
        parser.add_argument("host", help="The url of web which will be scaned")
        parser.add_argument("--asp", help="Add 'asp' dict into search list", \
                            action="store_true")
        parser.add_argument("--aspx", help="Add 'aspx' dict into search list", \
                            action="store_true")
        parser.add_argument("--dir", help="Add 'dir' dict into search list", \
                            action="store_true")
        parser.add_argument("--jsp", help="Add 'jsp' dict into search list", \
                            action="store_true")
        parser.add_argument("--mdb", help="Add 'mdb' dict into search list", \
                            action="store_true")
        parser.add_argument("--php", help="Add 'php' dict into search list", \
                            action="store_true")
        parser.add_argument("-t", "--thread", help="The numbers of threads", type=int, choices= \
                            [1, 3, 5], default=1)
        args = parser.parse_args()
        return args
    

    可以看到,除了host和thread之外,添加了6个参数,他们的action值为“store_true”,它的作用是,当命令行有相应的参数时,此参数的值为True,单说不明白,举个例子。

    如果命令行命令为:python 123.py http:xxxxx --dir --php
    这里的parser.dir 和 parser.php的值就是True,换而言之,“store_true”的行为作用是,判断此参数是否存在。argparse module的使用:传送门

    如此,读取文件生成列表就简单多了。

    def read_dict(parser):
        ''' load the dict '''
        combin = list()
        if parser.asp:
            with open('ASP.txt') as f:
                combin.extend(f.read().split())
        if parser.aspx:
            with open('ASPX.txt') as f:
                combin.extend(f.read().split())
        if parser.dir:
            with open('DIR.txt') as f:
                combin.extend(f.read().split())
        if parser.jsp:
            with open('JSP.txt') as f:
                combin.extend(f.read().split())
        if parser.mdb:
            with open('MDB.txt') as f:
                combin.extend(f.read().split())
        if parser.php:
            with open('PHP.txt') as f:
                combin.extend(f.read().split())
        return combin
    

    我必须得承认,这里看着一点也不优雅,甚至有些丑陋,但是我忍了…(里面的文件,也都是和文章开头展示的文件一样,分别存着不同类型的子目录。通过分析网站的后台开发语言,有针对性的选择子目录范围,会有不错的效果~)

    这样我们就生成了类需要的paths。那就写个测试脚本调用下吧。

    完整节目单

    import threading
    import urllib.request
    import argparse
    import time
    
    class WebScanner(object):
    
        _running_time = 0
        _number_of_threads_completed = 0
        
        def __init__(self, host, thread_num, paths):
            """initialization object"""
            
            self.host = host if host[-1] != '/' else host[:-1]
            self.thread_num = thread_num
            self.paths = paths
    
        def animation(self):
            """opening animation"""
            
            return r'''
     __      __      ___.     _________                                         
    /  \    /  \ ____\_ |__  /   _____/ ____ _____    ____   ____   ___________ 
    \   \/\/   // __ \| __ \ \_____  \_/ ___\\__  \  /    \ /    \_/ __ \_  __ \
     \        /\  ___/| \_\ \/        \  \___ / __ \|   |  \   |  \  ___/|  | \/
      \__/\  /  \___  >___  /_______  /\___  >____  /___|  /___|  /\___  >__|   
           \/       \/    \/        \/     \/     \/     \/     \/     \/       
            '''
    
        def run(self):
            """start scanner"""
    
            WebScanner._running_time = time.time()
            for i in range(self.thread_num):
                threading.Thread(target=self._subthread).start()
    
        def _subthread(self):
            "get url from dictionary and try to connect"
    
            while self.paths:
                sub_url = self.paths.pop()
                headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
                            'Chrome/51.0.2704.63 Safari/537.36'}
                url = self.host + sub_url
                req = urllib.request.Request(url=url, headers=headers)
                try:
                    ##Discard requests longer than two seconds
                    request = urllib.request.urlopen(req, timeout=1)
                    result = request.geturl(), request.getcode(), len(request.read())
                    print(result)
                except:
                    pass
            WebScanner._number_of_threads_completed += 1
            if WebScanner._number_of_threads_completed == self.thread_num:
                print("Cost time {} seconds.".format(time.time() - WebScanner._running_time))
    
    def create_parser():
        parser = argparse.ArgumentParser(description="The scanner of web catalog")
        parser.add_argument("host", help="The url of web which will be scaned")
        parser.add_argument("--asp", help="Add 'asp' dict into search list", \
                            action="store_true")
        parser.add_argument("--aspx", help="Add 'aspx' dict into search list", \
                            action="store_true")
        parser.add_argument("--dir", help="Add 'dir' dict into search list", \
                            action="store_true")
        parser.add_argument("--jsp", help="Add 'jsp' dict into search list", \
                            action="store_true")
        parser.add_argument("--mdb", help="Add 'mdb' dict into search list", \
                            action="store_true")
        parser.add_argument("--php", help="Add 'php' dict into search list", \
                            action="store_true")
        parser.add_argument("-t", "--thread", help="The numbers of threads", type=int, choices= \
                            [1, 3, 5], default=1)
        args = parser.parse_args()
        return args
    
    def read_dict(parser):
        ''' load the dict '''
        combin = list()
        if parser.asp:
            with open('ASP.txt') as f:
                combin.extend(f.read().split())
        if parser.aspx:
            with open('ASPX.txt') as f:
                combin.extend(f.read().split())
        if parser.dir:
            with open('DIR.txt') as f:
                combin.extend(f.read().split())
        if parser.jsp:
            with open('JSP.txt') as f:
                combin.extend(f.read().split())
        if parser.mdb:
            with open('MDB.txt') as f:
                combin.extend(f.read().split())
        if parser.php:
            with open('PHP.txt') as f:
                combin.extend(f.read().split())
        return combin
    
    if __name__ == "__main__":
        parser = create_parser()
        scanner = WebScanner(parser.host, parser.thread, read_dict(parser))
        print(scanner.animation())
        scanner.run()
    
    

    关于main函数

    前不久看到一篇微信服务号里的推文,作者很反感Python代码里面写“main函数”,我看了一下文章内容,作者反感它的原因是因为很多人根本不知道它的作用是什么,只是在“照猫画虎”的无脑模仿,并且认为这样比较规范。

    这里也借助这个例子,我们来聊一聊Python的main函数。

    “害,main函数有什么可聊的?不就是程序的入口嘛,我知道。”

    这…,还真不是。Python里面所谓的main函数,和C&Java等语言里的main不同。它不是必须的,你在最开始写Python代码的时候,没有因为不写main导致程序运行不了的情况吧。

    Python语言的设计和实现上,任何一个py文件(module)都可以作为程序入口,且为顺序执行。比如本文中的代码,当我们开始运行web.py(文件的保存名称)时,他会先执行import,将依赖module一个个导入,然后加载类,加载函数,最后执行到所谓的main函数,执行调用类和函数的脚本。而并不是我们以为然的程序从main函数开始执行。

    那既然main没有用,它存在的意义是什么呢?这要从__name__这个变量说起。

    每个module都维护着一个自己的name变量,相互之间没有影响。它主要用来标识当前module是自己在执行还是被调用了。

    比如,我们直接运行web.py,此时name的值就是main,也因此代码中的if函数条件满足,所以之后的代码被执行了。当我们在另一个module通过import导入web这个module的时候,web.py整个内容会被执行,该加载的加载,该执行的执行。走到if条件语句的时候,这时候web的name值为“web”,即module本身的名字。简单讲,当自己执行时,name值为main;当被别人调用时,它的值为文件名(module名),如果调用它的module是直接执行的文件,那调用它的module里面的name为main;依次类推,如果调用它的module是被另个一module调用的,那调用它的module的name是它自己的文件名。(太绕,别迷糊了)

    回到最初的问题上,它被设计出来的目的是什么呢?有一个比较简单能理解的作用,就是对当前写的单元做测试。比如文章里设计出来的scanner类,理应是被其他文件使用的,那当前代码有没有什么错误呢?写个脚本调用测试一下,就是那个所谓的main函数了。如果没有这个判断,当其他文件import web时,这里的脚本就会被执行,我们只是导入了module,结果模块里的测试脚本自己运行了,不就乱了套了吗。但是如果测试脚本是在main里面的,其他文件导入的时候,他就会因为判断条件不满足而不执行,这就是main函数的一种用处。

    所以,我们的这种写法其实是为了偷懒。正确的设计方式应该是web里只有类的设计,对它的测试另外写一个py文件。如
    web.py:

    import threading
    import urllib.request
    import time
    
    class WebScanner(object):
    
        _running_time = 0
        _number_of_threads_completed = 0
        
        def __init__(self, host, thread_num, paths):
            """initialization object"""
            
            self.host = host if host[-1] != '/' else host[:-1]
            self.thread_num = thread_num
            self.paths = paths
    
        def animation(self):
            """opening animation"""
            
            return r'''
     __      __      ___.     _________                                         
    /  \    /  \ ____\_ |__  /   _____/ ____ _____    ____   ____   ___________ 
    \   \/\/   // __ \| __ \ \_____  \_/ ___\\__  \  /    \ /    \_/ __ \_  __ \
     \        /\  ___/| \_\ \/        \  \___ / __ \|   |  \   |  \  ___/|  | \/
      \__/\  /  \___  >___  /_______  /\___  >____  /___|  /___|  /\___  >__|   
           \/       \/    \/        \/     \/     \/     \/     \/     \/       
            '''
    
        def run(self):
            """start scanner"""
    
            WebScanner._running_time = time.time()
            for i in range(self.thread_num):
                threading.Thread(target=self._subthread).start()
    
        def _subthread(self):
            "get url from dictionary and try to connect"
    
            while self.paths:
                sub_url = self.paths.pop()
                headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
                            'Chrome/51.0.2704.63 Safari/537.36'}
                url = self.host + sub_url
                req = urllib.request.Request(url=url, headers=headers)
                try:
                    ##Discard requests longer than two seconds
                    request = urllib.request.urlopen(req, timeout=1)
                    result = request.geturl(), request.getcode(), len(request.read())
                    print(result)
                except:
                    pass
            WebScanner._number_of_threads_completed += 1
            if WebScanner._number_of_threads_completed == self.thread_num:
                print("Cost time {} seconds.".format(time.time() - WebScanner._running_time))
    
    

    test.py:

    import web
    import argparse
    
    def create_parser():
        parser = argparse.ArgumentParser(description="The scanner of web catalog")
        parser.add_argument("host", help="The url of web which will be scaned")
        parser.add_argument("--asp", help="Add 'asp' dict into search list", \
                            action="store_true")
        parser.add_argument("--aspx", help="Add 'aspx' dict into search list", \
                            action="store_true")
        parser.add_argument("--dir", help="Add 'dir' dict into search list", \
                            action="store_true")
        parser.add_argument("--jsp", help="Add 'jsp' dict into search list", \
                            action="store_true")
        parser.add_argument("--mdb", help="Add 'mdb' dict into search list", \
                            action="store_true")
        parser.add_argument("--php", help="Add 'php' dict into search list", \
                            action="store_true")
        parser.add_argument("-t", "--thread", help="The numbers of threads", type=int, choices= \
                            [1, 3, 5], default=1)
        args = parser.parse_args()
        return args
    
    def read_dict(parser):
        ''' load the dict '''
        combin = list()
        if parser.asp:
            with open('ASP.txt') as f:
                combin.extend(f.read().split())
        if parser.aspx:
            with open('ASPX.txt') as f:
                combin.extend(f.read().split())
        if parser.dir:
            with open('DIR.txt') as f:
                combin.extend(f.read().split())
        if parser.jsp:
            with open('JSP.txt') as f:
                combin.extend(f.read().split())
        if parser.mdb:
            with open('MDB.txt') as f:
                combin.extend(f.read().split())
        if parser.php:
            with open('PHP.txt') as f:
                combin.extend(f.read().split())
        return combin
    
    
    parser = create_parser()
    scanner = WebScanner(parser.host, parser.thread, read_dict(parser))
    print(scanner.animation())
    scanner.run()
    

    总结,main的存在可以简单理解,是为了测试代码不影响到未来可能import它的文件的运行结果。而我们这里写main,纯粹了为了偷懒,懒得再创建一个引用它的文件。

    那这里可以去掉main吗?当然可以啊~,我们只用一个文件运行,有没有main没有任何的区别。我想这大概就是那个作者反感main的原因吧,本没有必要写,但在不明所以的情况下,当做语言规范写了。

    如果大家是从C或Java语言转到的Python,把写main当成了一种习惯,也无可厚非,只是我们要知道,此main非彼main,他们的作用完全不可类比。

    下篇尝试将这个工具做成桌面窗口版的,不知何时能写完(我是说文章哈,不是代码),暂定下周。

    完。

    展开全文
  • 二维码扫描web实现登录

    千次阅读 2016-03-01 11:13:23
    下面介绍二维码扫描登录原理, 首先需要web服务端,和app客户端。 web服务端主要工作是生成二维码,检测客户端提交信息正确性,更新网页界面。 app客户端主要工作是扫描二维码,提交账户信息(此不是指...

    最近项目开发中需要用到所以做个总结:

    下面介绍二维码扫描登录原理,

    首先需要web服务端,和app客户端。

    web服务端主要工作是生成二维码,检测客户端提交信息正确性,更新网页界面。

    app客户端主要工作是扫描二维码,提交账户信息(此不是指提交用户名和密码),与服务端通信。

    那么二维码扫描登录有什么优势呢?

    1 简单快捷

       只需要app客户端扫描二维码,点击确认登录就完成登录了。

    2 安全

       在与客户端通信过程中不提供用户名和密码信息,断绝了以往直接在PC端登录木马窃取用户账户密码的行为。

    那么二维码扫描登录是怎么工作的呢?

    1 web服务端需要生成了一个唯一KEY,代表此次用户的登录事件ID,跟你在京东买东西下单的单号差不多。

    2 根据唯一KEY生成二维码信息,显示在网页上。

    3 用户app扫描二维码,后通知服务端我已经扫描了二维码。

    4 服务端接收消息后,更新网页提示说已经扫描,把唯一KEY加入将要登录列表,如果超时将会移除(相当于把单号状态改为待支付状态,超过24小时就会说下单失败)。

    5 用户app端主动获取当前状态,如果唯一KEY没有超时或者没有异常,将会跳转到app端的确认登录页面。

    6 用户点击确认登录后,与服务端通信,提交用户名和密码验证值(可以考虑其他方案)。

    7 web服务端接收后,判断验证值是否与数据库的验证值匹配,如果匹配确认用户登录。

    9 用户app端检测服务端返回值,处理当前返回状态,登录成功,失败。


    展开全文
  • 作者:程序员自由之路https://www.cnblogs.com/54chensongxia/p/12530268.html随着微信的普及,我们可以通过微信扫描设备二维码来实现IoT物...
  • Oriented Architecture,ROA)、REST式设计的优点、REST式Web服务的真实案例分析、如何用各种流行的编程语言编写Web服务客户端、如何用三种流行的框架(Ruby on Rails、Restlet和Django)实现REST式服务等。...
  • 文章目录目录扫描简介目录遍历漏洞敏感信息泄露目录爆破工具御剑扫描Dirbuster安装使用 ...使得攻击者通过利用一些特殊字符就可以绕过服务器的安全限制,访问任意的文件(可以是web目录以外的文件),甚至执行系统
  • 信息搜集-目录扫描

    千次阅读 2020-10-19 10:36:00
    目录扫描目录原理爆破工具1.御剑后台扫描工具2.burp3.dirbuster4.dirb5. 常见fuzz工具爬虫工具长亭rad浏览器爬虫总结 目录 网站目录本质上就是我们的文件夹,不同的文件夹放着不同的文件。 进行目录扫描是为了扩大...
  • 10大Web漏洞扫描工具

    万次阅读 多人点赞 2018-09-20 18:19:19
    这是一个开源的Web服务器扫描程序,它可以对Web服务器的多种项目(包括3500个潜在的危险文件/CGI,以及超过900个服务器版本,还有250多个服务器上的版本特定问题)进行全面的测试。其扫描项目和插件经常更新并且可以...
  • 第七章 Web 应用扫描(一) 作者:Justin Hutchens 译者:飞龙 协议:CC BY-NC-SA 4.0 7.1 使用 Nikto 扫描 Web 应用Nikto 是 Kali 中的命令行工具,用于评估 Web 应用的已知安全问题。Nikto 爬取目标站点并...
  • 第七章 Web 应用扫描(三) 作者:Justin Hutchens 译者:飞龙 协议:CC BY-NC-SA 4.0 7.13 使用 BurpSuite Sequencer(序列器)Web 应用会话通常由会话 ID 标识来维护,它由随机或伪随机值组成。出于这个...
  • Servlet3无web.xml的原理

    千次阅读 2021-04-01 10:12:46
    在最新的SpringMVC中,一个web项目中无需传统的web.xml文件,这是怎么实现的呢?其实这并不是SpringMVC的功劳,而是servlet3规范以及web容器对这个规范的支持。 简单使用 配置 引入依赖: ... .... <!-- 指定...
  • 实现原理这里简单说明描述: 就是当Web服务器接收到http请求后,当请求进入对应的Filter进行过滤,将原本需要由web服务器创建会话的过程转交给Spring-Session进行创建,本来创建的会话保存在Web服务器内存中,...
  • 现在计划搞个web应用,需要用到身份证扫描仪。身份证扫描有内置的运行程序在电脑上安装就可以识别身份证。现在想把身份证扫描仪功能嵌入web应用中,扫描身份证的时候,数据直接在web应用...请教高手指点几招实现原理
  • SpringMVC实现原理

    千次阅读 2017-09-27 20:23:27
    今天我们来实现一个简单的springMVC框架,可以理解为 springMVC1.0这个版本,只是功能比较简单而已;废话不多说,进入正题;先看看springMVC的简单流程;我们请求的地址会被dispatchservlet这个springMVC的核心拦截...
  • 基于浏览器实现二维码扫描技术
  • LinkChecker 其原理是利用机器人爬虫框架实现,通过多线程进行死链扫描,并进行结果反馈。 1. 版本要求 系统版本:Ubuntu 16.04 Python版本: 2.7.12 2. pip 安装  tar xf pip.tar.gz ./configure && make &&...
  • 扫描器需要实现功能的思维导图: 1.1 实验内容 编写一个简单的多线程爬虫,用于对网站地址进行爬取,编写一个简单的sql注入工具,用于对网站地址进行sql注入的检测。 1.2 实验知识点 多线程的使用 网站爬虫...
  • vue实现原理

    千次阅读 多人点赞 2018-06-29 12:10:31
    二 探讨vue的双向绑定原理实现   成果图 下面介绍两个内容  1.vue双向绑定的原理  2.实现简易版vue的过程,包括声明式数据渲染及一些简单的指令 vue双向绑定原理 vue的双向绑定是由数据劫持结合发布者-...
  • 1. 微信移动端扫描二维码登录(C-S-C模式)  CSC模式为:web客户端 --> 服务端(腾讯)  认证步骤:  1)打开微信网页版,在浏览器生成一个web客户端,此客户端并未任务授权,但服务端给它生成了一个...
  • JAVA实现WEB实现app扫码登录

    万次阅读 2020-05-19 19:57:46
    接下来就是对于这个服务的详细实现。首先,大概说一下原理:用户打开网站的登录页面的时候,向浏览器的服务器发送获取登录二维码的请求。服务器收到请求后,随机生成一个uuid,将这个id作为key值存入redis服务器,...
  • 本节会基于上节开发的插件框架,讲解xss漏洞形成的原理,据此编写一个简单的XSS检测插件,先上效果图。 1.2 实验知识点 XSS基础知识 XSS检测原理 1.3 实验环境 Python 2.7 win10 PyCharm 二、开发...
  • 目录 一、Spring Cloud Feign概述与工作原理解读 (一)服务间调用的几种方式 (二)Feign 概述 二、FeignClent注解剖析+Spring Cloud Feign基本功能配置解读 (一)@FeignClient 注解剖析 (二)Spring Cloud...
  • SpringMVC无web.xml原理

    千次阅读 2021-04-01 10:57:21
    从Servlet3.0开始就可以不需要web.xml了,而Spring MVC中也很好的支持了这一个特性。 简单使用 gradle配置 description = "Spring MVC Demo" apply plugin: "groovy" apply plugin: "kotlin" dependencies { ...
  • 深入理解java注解的实现原理

    千次阅读 2019-11-13 16:58:08
    在Spring 2.0及早期时代,Web项目开发是通过配置文件 xml来实现 Bean 的依赖注入,有多少个Bean,就在xml配置问价中加多少个,这样一来在 Bean 的数量越来越多的时候,xml的配置也就会越来越复杂,显得格外的冗余,...
  • 什么是Web?及web服务器原理

    千次阅读 2016-12-10 23:53:06
    什么是WebWeb就是一种超文本信息系统,Web的一个主要的概念就是超文本连接,它使得文本不再象一本书一样是固定的线性的。而是可以从一个位置跳到另外的位置。你可以从中获取更多的信息。可以转到别的主题上。...
  • A:为实现“按名存取”,必须建立文件名与辅存空间中物理地址的对应关系,体现这种对应关系的数据结构称为文件目录 Q:目录扫描的作用是什么? A:可以让我们发现这个网站存在多少个目录,多少个页面,探索出网站的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 57,043
精华内容 22,817
关键字:

web目录扫描实现原理