1. 유닉스(리눅스) 패스워드 크래킹

유닉스나 리눅스는 기본적으로 사용자의 패스워드를 MD5 해시값으로 변경하여 관리하고 있습니다. 예를 들어, abcd 아이디의 패스워드가 1234라고 하면 1234에 대한 MD5 해시값인 81 dc 9d db 52 d0 4d c2 00 36 db d8 31 3e d0 55를 사용합니다. 그런데 test 아이디를 가진 사람의 패스워드도 1234라고 하면 문제가 발생할 수도 있습니다. abcd 아이디를 가진 사람이 우연히 test의 비밀번호 MD5값이 동일하다는 것을 안다면 비밀번호가 1234라는 것을 알 수 있기 때문입니다. 그래서 이런 문제를 해결하기 위해 salt라 부르는 2개의 문자를 원래 패스워드에 추가한 후 MD5 해시를 구성하는 매커니즘을 사용하고 있습니다. 

다시 예를 들어 abcd 아이디의 패스워드가 1234면 salt값로 fa를 앞에 추가하여 fa1234의 MD5 해시값을 07 9b 71 85 33 d9 9a fe 18 9a fb e2 bc 4a a3 58과 같이 만듭니다. 이 값에 salt인 fa를 추가합니다 . 문자 fa는 16진수 ASCII 값으로 66 61이므로 abcd의 1234는 66 01 07 9b 71 85 33 d9 9a fe 18 9a fb e2 bc 4a a3 58로 관리하게 됩니다. 동일한 원리로 test의 패스워드 1234에 salt로 f3을 추가했다고 하면 abcd와 test의 MD5 해시값은 다른 값이 생성됩니다.


리눅스는 사용자 인증에 필요한 정보를  /etc/passwd에 저장하고 관리합니다. 

root : x : 0 : 0 : root : /root : /bin/bash
#로그인 이름:패스워드:사용자아이디:그룹아이디:코멘트:홈디렉토리:기본쉘

두 번째 필드가 패스워드이지만 모두 x로 표시되어 있으며, 실제 패스워드는 /etc/shadow 파일에 저장되어 있습니다. 

root:$1$agjnf2382F32o9h#T2:14923:0:99999:7:	:	:
abcd:$1$fnafnQO'I2R28y:14945:0:99999:7:	:	: 

첫 번쨰 필드는 사용자계정이고 두 번째 필드는 salt가 포함된 사용자 패스워드 해시값입니다.

두 번째 필드 분류

$1$: MD5

$5$: SHA256

$6$: SHA512 

위에서 예로 든 /etc/shadow 파일의 내용에 접근하여 root와 abcd의 패스워드 해시값을 얻었다면 오프라인 공격 유형으로 패스워드 크래킹을 수행할 수 있습니다. 인터넷에는 패스워드 크래킹을 위한 사전을 텍스트 파일로 유통하는 사이트가 많이 있습니다. 보통 용량이 크기 때문에 아래와 같이 사전파일을 예로 만들고 패스워드 크래킹의 원리를 설명합니다.

apple
python
password
12345
secret
welcome
admin
pineapple
other
login
pokemon
iloveyou


/etc/shadow에서 패스워드 크래킹을 위해 획득했다고 가정하고 passwords.txt로 저장합니다.

root:$1$a3gSE1RAj6522:14923:0:99999:7:::
test:$1$zfti6chVSQLlQ:14945:0:99999:7:::


 아래 코드를 작성한 후 실행하면 다음의 결과가 생성됩니다.

import crypt


def find_pass(pass_hash, dictfile):
    salt = pass_hash[3:5]
    with open(dictfile, 'r') as dfile:
        for word in dfile.readlines():
            word = word.strip('\n')
            cryptwd = crypt.crypt(word, salt)
            if cryptwd == pass_hash[3:]:
                return word


dictfile = 'dictionary.txt'
with open('passwords.txt', 'r') as pass_file:
    for line in pass_file.readlines():
        data = line.split(':')
        user = data[0].strip()
        passwd = data[1].strip()
        word = find_pass(passwd, dictfile)

        if word:
            print('id: {0} password: {1}'.format(user, word))

        else:
            print('not found')
 
# 결과
# id: root password: iloveyou
# id: test password: python

2. zip 파일 패스워드 크래킹

zip 파일은 사전공격이나 무차별 대입 공격으로 ZIP 파일을 풀 수 있습니다. 아래는 사전공격으로 zip 파일을 푸는 파이썬 예시입니다.

import zipfile
from threading import Thread


def crackzip(zfile, passwd):
    try:
        zfile.extractall(pwd=passwd)
        print('zip file pass {0}'.format(passwd.decode()))
        return True

    except:
        pass
    return False


dictfile = 'dictionary.txt'
zipfilename = 'locked.zip'
zfile = zipfile.ZipFile(zipfilename, 'r')
pfile = open(dictfile, 'r')

for line in pfile.readlines():
    passwd = line.strip('\n')
    t = Thread(target=crackzip, args=(zfile, passwd.encode('utf-8')))
    t.start()

해당 파일의 같은 경로에 zip파일과 비밀번호가 있는 dictionary.txt 파일이 존재하면 압축파일이 해제되는 것을 확인할 수 있습니다.

3. 시스템 패스워드 크래킹 

수동적 온라인 공격

공격자가 대상 시스템에 직접 연결하거나 통신하지 않고 패스워드 크래킹을 수행하는 방법입니다. 유선 스니핑, 중간자 공격 등이 있습니다.

능동적 온라인 공격

공격자가 대상 시스템에 직접 접속하여 패스워드를 추측하여 입력함으로써 공격하는 방법입니다. 패스워드를 일일이 입력하지 않고 자동화된 도구를 활용하여 공격합니다. 자동화 도구로는 트로이 목마, 스파이웨어, 키로거 등이 있습니다.

오프라인 공격

오프라인 패스워드 공격은 공격자가 시스템이 관리하는 패스워드 파일에 접근할 수 있을 경우 가능한 공격 방법입니다. 오프라인 공격에 보편적으로 활용되는 해킹 기법은 무차별 대입 공격, 사전공격, 음절 공격, 레인보우 테이블 공격 등과 같은 암호 공격입니다.

'보안 & 보안' 카테고리의 다른 글

TLS (Transport Layer Security)  (0) 2018.12.18
스니핑  (0) 2017.04.12
패스워드 크래킹  (0) 2017.03.28
알려진 평문 공격 (기지 평문 공격) - Known-plaintext attack  (0) 2017.03.27
무차별 대입 공격 (Brute Force Attack)  (0) 2017.03.27
SSL (Secure Socket Layer)  (0) 2017.03.27

+ Random Posts