collision

Twenty input bytes are read as five ints and summed; any five values adding to 0x21DD09EC pass the check.

2026.08.18 Pwn original post

col.c 의 C 언어 코드를 둘러보자. 코드를 보면 가장 중요한 4개를 알 수 있다.

  • 입력 길이는 정확히 20 bytes
  • 입력 문자열을 int* 로 캐스팅
  • 4바이트씩 5개로 나눠서 더함
  • 합이 0x21DD09EC 이면 성공

즉, 입력은 20바이트 → 4바이트 × 5개.

ip[0] + ip[1] + ip[2] + ip[3] + ip[4] = 0x21DD09EC

그럼 목표값을 계산해보자. 일단 16진수를 10진수로 바꿔준다. 0x21DD09EC = 568134124 (decimal). 그리고 코드대로 5로 나눠준다.

part = target // 5
568134124 // 5 = 113626824
113626824 × 4 = 454507296
남은 값       = 113626828

따라서 다섯 값은 113626824, 113626824, 113626824, 113626824, 113626828 이다.

Figure 1

여기서 중요한 사실은 리눅스 우분투는 리틀 엔디안을 사용한다는 것이다. 즉, 4바이트 정수는 거꾸로 저장된다. 그 사실을 기억하고 코드를 짜자. 참고로 파이썬 코드 파일이 따로 안 만들어져서, 한 줄로 바로 실행시킬 수 있도록 했다.

./col "$(python3 - <<'PY'
import struct, sys

target = 0x21DD09EC
part = target // 5          # target 값을 5개 int로 균등 분배

# 5개 중 4개는 동일한 값으로 설정
# part 값을 4바이트 Little Endian unsigned int로 변환해 4번 반복 (16바이트)
payload = struct.pack("<I", part) * 4

# 앞에서 만든 4개의 합을 제외한 나머지 값을 마지막 4바이트로 추가 (총 20바이트)
payload += struct.pack("<I", target - part * 4)

sys.stdout.buffer.write(payload)
PY
)"

그리고 실행시켜보면.

Figure 2