
문제 설명

fgets, strcspn, memcmp, puts, __printf_chk → 전형적인 “입력받아 개행 제거 → 비교 → 성공/실패 출력” 흐름..rodata 내부에 다음 상수 존재:
성공 포맷: GoN{%s}\\n
실패 메시지: Nah...
짧은 평문 후보: mgUa
16-니블 치환 테이블(0x03 0x0c 0x0b … 0x02) + 0x100 바이트 S-box(ARIA S-box #2) + 16-바이트 키(바이너리 끝부분)
→ 입력을 난독화하지만 키/테이블이 바이너리 안에 그대로 들어있음.
fgets(buf, …, stdin)buf[strcspn(buf, "\\n")] = 0; // 개행 제거 → 길이 len = strlen(buf)memcmp(buf, <정답>, len) 으로 비교printf("GoN{%s}\\n", <무언가>); 아니면 puts("Nah...")read_file()가 unconventional에서 그대로 꺼냄:
0x2060: 암호화에 쓰인 box(S-box). 코드가 역함수 box⁻¹를 직접 구성.0x2020: 48바이트 암호문(ciphertext), 즉 GoN{...} 안에 들어갈 평문의 암호화 결과.base_key[16]도 코드에 하드코딩.decrypt_process()가 하는 일:
(옵션) AddRoundKey(XOR)
위치 기반 ROR(순환 쉬프트), 상호 Sub(뺄셈 믹스), 상수 XOR, 열 단위 쉬프트, 마지막에 S-box 역함수 적용
→ 각 단계가 바이트 모듈러 연산과 치환/순열로 이루어진 전부 전단사(가역).
즉, 암호 로직 전체가 공개된 상태에서 완전 역연산을 그대로 코딩해 둔 것.
for (i=0; i<0xC0FF33; i++) { decrypt(key); decrypt(block,key); }
큰 반복수는 보안강도가 아니라 연산량만 증가(off-by-obscurity).
C로 돌리면 충분히 실용 시간 내 복호됨. (게다가 키 스케줄 역시 같은 가역함수 재사용)