LoginSignup
16
15

More than 5 years have passed since last update.

辞書攻撃を試してみた。

Last updated at Posted at 2016-01-31

概要

普段仕事で使っているパスワードがかなり辞書攻撃に弱そうなんだけど、そのパスワードってどれくらい効力があるんだろ?と疑問に思ったので、辞書攻撃するスクリプトを作ってみた。

辞書攻撃用コード

analyse_term()はuser_idやメールアドレスを解析して、辞書を作成する関数。例えば、cof@qiita.comからは、'cof@qiita', 'qiita', 'com', 'qiita.com', 'cof'というような辞書を作成する。
read_dictionaly()は所定の辞書を読見込む関数。ネットで調べたところざっと50万語くらいの辞書はあるようであったが、今回は後述する7語の辞書を使用した。
create_direct_word()は、作成した辞書に含まれるワードそのものを順次生成する関数。
create_indirect_word()は、辞書に含まれるワードに指定された文字数を足した文字列を生成する関数(例えば、辞書にboyが含まれ、2文字が指定されていた場合に、boy01とか、boyaaとかを生成する関数)
なお、パスワードが正しいかどうかを==で判定しているが、これは例えばzip等のファイル回答の解析結果に置き換えても構わない。

import itertools
def analyse_term(term):
    ans = []
    if not term:
        return ans
    for symbol in '!"@#$%&\'()=~-^\\|`{}[]:*;+<>,./?\_':
        if symbol in term:
            for t in term.split(symbol):
                ans.append(t)
                ans += analyse_term(t)
    return ans

def read_dictionaly(dictionaly_file):
    f = open(dictionaly_file)
    words = set(map(lambda x: x.replace('\n','').replace('\r',''), f.readlines()))
    f.close()
    return words

def create_direct_word(dictionaly):
    for term in dictionaly:
        yield term

def create_indirect_word(dictionaly,string,additional_num):
    for term in dictionaly:
        for s in itertools.combinations_with_replacement(string,additional_num):
            s = ''.join(s)
            yield s+term
            yield term+s

def dictionaly_attack(user_id, string, dictionaly_file, max_additional_num, answer):
    dictionaly = set(analyse_term(user_id))
    print dictionaly
    dictionaly |= set(read_dictionaly(dictionaly_file))
    print dictionaly
    for term in create_direct_word(dictionaly):
        #print term
        if term == answer:
            return term
    for i in range(1,max_additional_num+1):
        for term in create_indirect_word(dictionaly,string,i):
            #print term
            if term == answer:
                return term
    return False

辞書ファイル

とりあえず思いついたまま作成してみた。

boy
girl
guy
man
woman
gentleman
lady

メインスクリプト

使用文字を小文字、スペース、数字に絞り、user_idをcof@qiita.com、パスワードをgirl012としてアタックしてみたところ、およそ0.03秒で発見できた。

# coding: utf-8
# Here your code !
from attack import dictionaly_attack
import time

user_id = 'cof@qiita.com'
dictionaly_file = "dictionaly.txt"
password = 'gir012'
string = 'abcdefghijklmnopqrstuvwxyz 0123456789'
start = time.time()
ans = dictionaly_attack(user_id,  string, dictionaly_file, 3, password)
elapsed_time = time.time() - start
print ans,password
print ("elapsed_time:{0}".format(elapsed_time)) + "[sec]"

実行結果

辞書が小さいからなのかもしれないが、意外にあっさりとパスワードを発見することができた。普段仕事で使っているパスワードも、いいとこ1分もつかどうかくらいじゃなかろうか。

set(['cof@qiita.com', 'cof@qiita', 'qiita', 'cof', 'com', 'qiita.com'])
set(['boy', 'woman', 'cof@qiita.com', 'cof@qiita', 'lady', 'qiita', 'gentleman', 'cof', 'girl', 'com', 'guy', 'qiita.com', 'man'])
girl012 girl012
elapsed_time:0.0296669006348[sec]
16
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
15