메뉴 닫기

반디집 디자인 에러(?)

요약 : 반디집에서 zip로 압축하면서 비번걸때 ZipCrypto로 걸었으면, 비밀번호 없이 해당 zip 파일 압축 푸는 것이 가능함.

첨부파일에 테스트용 압축파일과 소스코드 있습니다.

패치 됬답니다..ㅜ
 
zip plaintext attack 관련해서 이해가 가지 않는 부분이 있어서 파이썬으로 코드 짜면서 이것저것 하다가 우연히 발견했습니다.

 

잘 아시겠지만 ZIP 압축 같은경우 압축파일에 암호를 걸 수 있습니다. 그 암호 알고리즘으로 ZipCrypto,AES256 등을 사용할 수 있고요.

오늘 전 ZipCrypto에 대해 이야기 해보려 합니다.

(일일히 설명하는건 귀찮으니 C-Style 의사코드를 봅시다.)

 

(Decrypt 함수에 인자로 zip파일의 비밀번호를 넣는다고 합시다..)

ZipCrypto는 스트림 암호처럼 동작을 하는데, 압축할때 앞 12 바이트(편의상 이 글에선 WeakHeader 라고 하겠습니다.) 에 랜덤한 데이터를 끼우는것이 중요합니다.  그리고, 그 랜덤한 데이터는 코드[26번째 줄]에서 보는 보는것 처럼 압축 풀때 무시합니다. 대부분의 압축프로그램에선 WeakHeader의 11번째, 12번째 바이트에 파일의 마지막 수정시각을 넣습니다. 특히 반디집도 그렇습니다.

쨋든 랜덤한 바이트를 넣음으로서 공격을 어렵게 하기 떄문에, WeakHeader에 들어가는 데이터는 안전한 RNG에 의해 생성되어야 합니다.  만약, PRNG의 품질이 낮아, WeakHeader 의 내용을 알 수 있을 경우에 가능한 몇몇 공격이 있습니다. "ZIP Attacks with Reduced Known Plaintext"(Michael Stay)를 보면, InfoZip의 RNG를 공격하여 압축된 파일의 시작 2바이트만 알아도 공격이 가능하다고 나와있습니다.

그런데 말입니다, 반디집은 이 WeakHeader 부분에 고정된 값을 사용합니다. 개발자는 난수랍시고(?) 사용했겠지만 srand 를 하지 않아 사실상 고정된 값이 사용됩니다. 반디집에서 파일을 압축할때 ZipCrypto 로 비밀번호를 건다면 WeakHeader 은 아래 코드같은 느낌(?) 으로 채워지고 나머지 2바이트는 파일의 마지막 수정시간이 됩니다.

 

 

WeakHeader를 전부 알고 있으니, WeakHeader를 바탕으로 비밀번호로 key0,key1,key2가 초기화된 상태 까지 계산을 해준다면, 비밀번호 없이 zip 파일 압축풀기가 가능합니다.  하지만 <각주1>에서 언급했다 싶이 전 아직 plaintext attack 과정중 여전히 이해가지 않는 부분이 있습니다. 오늘 하루 동안 관련논문을 열심히 읽어봤지만, 이해가 가지 않았습니다. 포기할까 하다가 구글링을 통해 좋은 내용을 찾았습니다.

http://sanya.sweetduet.info/understandzip/

 

책인듯 하고 1000엔 밖에 안하지만, 카드가 없는 관계로, 샘플.pdf 와 github에 있는 관련 코드들을 보면서 열심히 따라 해봤습니다.

그 결과, 상당한 복잡도를 가지지만, 압축된 파일의 내용을 전혀 몰라도, WeakHeader를 전부 알면, 압축파일을 푸는 것이 가능한 것 같았습니다. 예제 코드를 조금 수정하여 확인하여 보니 제 생각은 맞는 것 같습니다.

 

 

 

전체 가능한 key2를 검토하는 과정중, 단 0.1% 의 시도로 올바른 key2 를 알아냈습니다.

0.1%에 500여초가 걸렸으니 최악의 경우 500000초(5일 18시간)쯤 걸리네요. 실질적으로 써먹으려면 OpenMP나 OpenCL등을 이용해서 병렬화가 필수 일것 같습니다.

(라이젠 스레드리퍼… 꿈의 CPU 스레드 32개……….. 500000초 / 32스레드 —-> 약 4시간…)

 

 

** 보충 설명1

 이 툴로 key0,key1,key2 를 알아냈다면 pkcrack의 zipdecrypt 를 이용하여 복호화된 파일을 쉽게 생성 할 수 있습니다만, 해당 툴이 ZIPDIRENTRY 구조체 파싱을 잘 못하는 것 같습니다.

 

(이렇게 에러가 나도 test2.zip 파일에 ZIPFILERECORD 구조체 내용은 잘 작성되어 있으니, 7-zip 같은걸로 열면 아무 말 없이 잘 열립니다.)

 

 

** 보충 설명2 (추가 작성 완료)

 

https://twitter.com/teslamint/status/958844979543097344

(이분이 이 글을 잘못 이해하셔서(글을 대충 작성한 저한테 책임이 있습니다.ㅜ), 지적을 하셨는데, 지금은 대부분 사라졌네요..)

이 분 이야기에 대해 반박겸 보충설명을 해보겠습니다. ZipCrypto의 암호화 방식이 AES256 암호화 방식보다 취약하다는건 이미 알려진 사실이 맞습니다. 하지만 아직도 많은 압축 프로그램에서 Zip에 암호를 걸때 ZipCrypto 를 사용합니다. 중요한건 2가지.

1. 알집과 7-zip을 확인해본 결과 압축시에 ZipCrypto 와 AES256 을 선택하는 부분이 있지만 반디집의 경우 환경설정에서 바꿔야 하고, 기본값은 ZipCrypto 입니다
 

 

 
2. 반디집에선만 WeakHeader 부분에 고정된 값을 사용한다는 점.

 

 

 

 

srand는 없네요..

_tiddata13는 스레드 마다 존재하는데, 개발자분이 여기서 실수 하신것 같습니다.

 

**추가

 반디집 개발자분의 답변을 그대로 캡쳐해서 올립니다.

 (제가 올린 토픽은 아님)

https://groups.google.com/forum/#!category-topic/bandisoft/bandizip-kr/_shMDCH7EmA

 

 

제가 게시한 코드/사진을 보면 무차별 대입은 맞습니다만, 무식하게 2^96의 경우의수를 모두 맞추는 일은 아닙니다.

"A Known Plaintext Attack on the PKZIP Stream Cipher"의 3.1 절을 보면…

 

 

 

 

반디집에서 WeakHeader 을 제대로 처리하지 않았기 때문에 우리는 key3를 모두 알고 있습니다. 즉 이 정보를 이용하여 key2 의 14비트를 결정할 수 있습니다. 각 key2 리스트로 부터 여러개의 key1 리스트가 생성되고 각 key1 리스트로 부터 하나의 key0가 생성됩니다. key0,key1,key2를 검증하여 올바르다면 그것들로 decrypt를 해주면 압축이 풀립니다.

보충 설명2 요약:

 이 문제는 반디집만의 문제.

 key0,key1,key2 가 가질수 있는 2^96의 경우의수를 모두 대입하는 것이 아님.

** 번외

 먼말인지 잘 모르겠으면, 반디집으로 ZIP 압축할때 비밀번호 똑같이 해서 다른 파일 2개 따로따로 압축 해보십시오.

 

데이터 부분 시작의 첫 10바이트는 같습니다. 반디집만 그렇습니다. 

이게 뭘 의미하는지는 굳이 언급하지 않아도 눈치 채셨겠죠?

 
[POC]
 
## 이 글은 제가 네이버 블로그를 하던 시절에 작성한 글을 옮긴것입니다. 옮기는 과정에서 각주가 생략됬습니다.
 
아래는 원래 붙어있던 각주입니다. ( 이 글에서는 각주 번호가 생략되어 있으니 적당히 알아서(…) 보시면 됩니다.)
  1. 적어도 이 글을 쓰는 시점에서의 최신버전(6.10)은 영향을 받습니다. (아마 구버전도 마찬가지일 거로 생각합니다만, 확인해보지 않았습니다.)
  2. 아직도 해결되지 않았다고 합니다.;
  3. 그래서 코드[32번째 줄] 처럼 일부 PW 크랙 프로그램에선 확인용으로 그 사실을 이용합니다.
  4. 7-zip 의 구현도 그렇게 되어 있습니다.
  5. 난수가 사용되어야 하는 다른 곳에서도 그럴지 모릅니다.
  6. 코드[24번째줄]
  7. Plaintext Attack과 상당히 비슷한 느낌으로요..
  8. pkcrack 라고, 해당 논문의 내용을 코드로 구현해둔게 있지만 복잡해요..ㅜㅜㅜㅜㅜ
  9. https://github.com/kusano/understandzip_web
  10. 사실 plaintext attack 에서 가능한 key2를 줄이는걸 이해 못하고 있었는데, 반디집의 암호를 공격할때는 이 부분이 필요 없습니다.
  11. 사실 병렬화 한다고 이렇게 딱 성능이 32배 뛰지는 않습니다만… 적어도 20배이상 향상은 될꺼라 생각합니다.
  12. 13년도에 나온 제 노트북 CPU보다 성능이 훨신 좋을테니, 실제론 그보다 적게 걸릴겁니다.
  13. 이 구조체의 _holdrand 가 시드로 사용됩니다. 초기값은 1
  14. 2^96을 모두 대입하려면 개인용 컴퓨터로는 어림도 없죠.
  15. 이 글에서 언급한 WeakHeader가 아닌, 그 다음 13바이트를 알면 크랙이 가능하다는 이야기를 담은 논문입니다.
  16. 앞 13바이트를 알아야 하는데, OLE 포맷 같은걸 제외하면 고정된 값을 사용해 헤더를 길게 쓰는건 없을뿐만 아니라, 저장(압축안함)옵션이 아닌 이상에야 DEFLATE 로 압축 한번 하고 암호화 하기 때문에 제약조건이 조금 있습니다.
  17. 이 논문을 바탕으로 만들어진 ZIP Plaintext attack은 archpr, passware 같은 툴로 가능합니다.
  18. 비록 64개의 경우의수를 가지지만
  19. 2바이트는 파일 시간이니까 앵간하면(?) 다를 겁니다.

 

 

댓글 남기기

이메일은 공개되지 않습니다.