본문으로 건너뛰기

07. AES-CBC 비트플립 공격 빠른 감

AES 자체가 깨지는 것과 CBC를 잘못 사용한 프로토콜이 변조되는 것은 다른 문제다. CBC 복호화에서 P_i = D_K(C_i) XOR C_{i-1}이므로, 이전 ciphertext 블록의 비트를 바꾸면 다음 plaintext 블록의 같은 위치가 예측 가능한 XOR 차이만큼 바뀐다. 다만 현재 블록의 복호화 결과도 함께 망가지므로, “원하는 문장으로 바꾼다”는 설명은 블록 경계와 패딩을 포함할 때만 정확하다.

실습에서 확인할 것

허가된 CTF나 직접 만든 로컬 토큰만 사용한다. 먼저 평문에서 조작할 바이트가 어느 블록에 놓이는지 계산하고, 원래 바이트 o를 목표 바이트 t로 바꾸려면 이전 블록에 o XOR t를 적용한다. 여러 바이트도 같은 방식으로 차분을 만들 수 있지만, ASCII 길이와 패딩 유효성까지 함께 검증해야 한다. 블록 크기는 AES에서 16바이트다.

from operator import xor

original = b"user"
target = b"admin"
delta = bytes(xor(a, b) for a, b in zip(original, target))
# delta는 이전 ciphertext 블록의 해당 위치에 XOR한다.

관찰 포인트는 성공 여부보다 서버의 검증 순서다. 암호문을 먼저 복호화하고 권한 필드를 파싱하는지, 패딩 오류와 인증 오류를 구별해 응답하는지, 재생 방지와 만료를 적용하는지를 기록한다. 오류가 구별되면 별도의 패딩 오라클이 생길 수 있지만, 승인된 테스트 범위를 벗어나 반복 요청을 보내서는 안 된다.

설계 판단

CBC 암호문을 신뢰 가능한 데이터처럼 다루면 기밀성만 제공하고 무결성은 제공하지 않는다는 사실을 놓치게 된다. 가장 단순한 교정은 검증된 Encrypt-then-MAC이며, 새 설계라면 AES-GCM이나 ChaCha20-Poly1305 같은 AEAD를 사용한다. 태그를 평문 파싱보다 먼저 일정한 방식으로 검증하고, nonce 재사용을 피하며, 실패 응답은 필요 이상으로 구별하지 않는다.

레거시 토큰을 점검할 때는 “공격 문자열이 만들어졌는가”보다 권한 결정이 인증된 데이터에만 의존하는지를 증거로 남긴다. 발견한 변조 가능성은 토큰 형식, 영향 범위, 재현에 사용한 로컬 fixture와 함께 보고하고, 운영 시스템에는 실제 조작 대신 테스트 계정과 격리된 엔드포인트를 사용한다.