신한카드 이용대금 명세서 개인 비밀번호 분석 및 크랙

오랫만에 메일함을 들어갔더니 “[신한카드] 임준오님의 01월10일 체크카드 이용대금 명세서입니다.” 이런 제목의 메일이 와있었다. 예전에도 몇번 받아봤는데 첨부파일에 html파일이 있고 생년월일을 입력하면 명세서를 보여주는 형식이었다.

메일 화면

보안 이메일 명세서라고 나와있는데 얼마나 안전한가 한번 시험해보고 싶었다.

생년월일을 받는다.
내 생년월일을 입력하면 정상적으로 열리게 된다.

이제 소스를 열어보자.

뭔가 난독화가 많이 되어 있다. 일단 beautify 를 해보자.

이제 좀 보인다. 분석을 시작하자!

1. 생년월일을 비교하는 부분을 찾는다.

2. 연산하는 곳을 찾는다.

3. 복호화 코드를 짠다.

이 순으로 분석을 하면 될것 같다.

1. 생년월일을 비교하는 부분을 찾는다.

어떻게 찾을까 생각해봤는데 생년월일이 일치하지 않으면 아래와 같은 alert 창을 띄운다.

저 문자열을 찾아가면 될것 같다.

근데 난독화가 되어있어 alert 함수나 띄우는 문자열을 찾을 수 없었다.

약간의 감을 통해 최상단에 있는 문자열 배열이 함수명이나 메시지들을 담고 있을것 같았다.

엇.. alert가 있다…?

기억을 더듬어 보니 alert가 무려 17개나 있어 문자열로 찾았던 기억이 난다.

그럼 이제 저 지점에 브레이크포인트를 걸고 동적 디버깅을 해보자!

1234를 넣고 상황을 지켜보았다.

1345번째 줄을 보면 _0x9319xd9(함수의 인자) 변수에 내 비밀번호가 들어왔고 1348번째 줄에서 _0x9319xdf함수의 인자로 넘어갔다. 그럼 _0x9319xdf 함수가 복호화하는 함수다 !

2. 연산하는 곳을 찾는다.

1354번째 줄에서 _0x9319xde에 복호화한 값이 들어갔다.

복호화하는 로직을 보니 고정된 키를 사용하는것이 아닌 인풋을 키로 하여 복호화를 진행한다. 복호화 하는 함수를 조금더 분석해보자.

flow: _0x9319xdf -> _0x9319xe2 -> _0x9319xe2

불러오는 함수를 계속 따라가 보면 _0x9319xe4에 “SEED-CBC”란 값을 넣는걸 볼 수 있다.

SEED-CBC를 사용한다고 알려준다. SEED-CBC의 상세한 로직은 이미 쓰고 있는 곳들이 많아 안전할거라 생각하고 따로 분석하지 않았다.

3. 복호화 코드를 짠다.

내가 준 인풋(사용자의 생년월일)을 키로 사용하고 SEED-CBC 블록암호를 사용하기 때문에 복호화 코드를 짜도 의미가 없다. 아니 이미 복호화 해주는 코드는 내장되어 있다. 단지 키를 정의할 수 없을 뿐이다.

키를 구해야 되기 때문에 브루트포싱밖에 답이 없다. 하지만 복호화 하려는 데이터가 너무 크기때문에 1초정도 걸린다.

대충 계산 해보면..

1년을 365로 가정하고 카드 사용자층을 10대 ~ 60대로 선정하면 총 60년을 상대로 브루트포싱해야됨.

그러면 최종적으로 1s * 365 * 60 = 21900s = ~6시간

한개를 복호화 하는데 6시간이나 필요하다. 물론 쓰레딩으로 처리하면 줄일 수 있겠지만 현저히 많은 시간이다.

그러면 과연 더 나은 방법이 없을까?

생각 하던중 정상적으로 복호화 되었는지의 여부를 판별하는 곳을 보았다.

xxx(0, 10) == aaaaa

어.. 복호화된 앞 부분에서 비교를 한다라 .. ?

수 많은 블록을 한 블록으로 줄일 수 있게 되었다.

UNISAFESMAIL_DATA = btoa(atob(UNISAFESMAIL_DATA).substr(0, 16));

한 블록으로 줄인 후 브루트포스 코드를 구현했다.

완성된 브루트포스 코드는 아래와 같다.

function brutePassword() {
    for (var year=50; year<100; year++) {
        for (var month=1; month<=12; month++) {
            var tmp = month+"";
            if (tmp.length == 1)
                tmp = "0"+tmp;
            month = tmp;
            for (var day=1; day<=31; day++) {
                var tmp = day+"";
                if (tmp.length == 1)
                    tmp = "0"+tmp;
                day = tmp;
                isSuccess = new UniSafeMail().unisafe_smail_process(year+month+day);
                if (isSuccess) {
                    console.log(year+month+day);
                    return year+month+day;
                }
            }
        }
    }
}