mistake

Operator precedence: the result of the comparison lands in fd instead of the file descriptor from open().

2026.08.18 Pwn original post

Figure 1

패스워드를 알아내야지 플래그를 볼 수 있는 듯함. 당연히 소스 코드 먼저 봐주겠음.

Figure 2

에바로다가김. 대충 훑어보면 패스워드 비교 코드임을 알 수 있음. 취약점은 무엇일까… if 문을 잘 살펴보자 보자 보자꾸나. open 조건문이다!

if (fd = open("/home/mistake/password", O_RDONLY, 0400) < 0) {

의도한 코드는 이거였을 것이다.

if ((fd = open(...)) < 0)     // fd에 저장 후 음수인지 확인

그런데 실제 동작은 이렇다.

if (fd = (open(...) < 0))     // 비교 먼저! 결과(0 또는 1)가 fd에 저장됨

< 연산자가 = 보다 우선순위가 높아서, 비교 결과(0 또는 1)가 fd 에 들어가요.

두 개이기 때문에 read() 조건문도 잘 펴봐주겠다 (집중해 ㄱㅇㅇ).

if (!(len = read(fd, pw_buf, PW_LEN) > 0)) {

같은 이유로 실제로는 이렇게 동작한다.

if (!(len = (read(fd, pw_buf, PW_LEN) > 0)))
// len에는 실제 읽은 바이트 수가 아닌 0 또는 1이 저장됨

결과적으로 fd 는 open() 반환값이 아닌 0 또는 1이다. fd = 0 이면 표준입력(stdin) 을 읽게 됨! 즉 read(0, pw_buf, PW_LEN) 이 되어 키보드 입력을 읽는다.

pw_buf 와 pw_buf2 가 둘 다 내 입력이니까, 내가 원하는 값을 넣을 수 있다.

strncmp(pw_buf, pw_buf2, 10) == 0

이 조건을 통과하려면 pw_buf == XOR1(pw_buf2) 이어야 한다. 즉

  1. pw_buf 에 들어갈 값을 먼저 입력
  2. 그 값을 XOR 1 한 결과를 pw_buf2 로 입력
  3. strncmp 통과!

예를 들어 0000000000 을 입력하면, XOR 1 결과는 1111111111 이니까:

첫 번째 입력: 0000000000
두 번째 입력: 1111111111

하면 Password OK 가 뜸.

Figure 3