<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>RoughBoy.log</title>
        <link>https://velog.io/</link>
        <description>The day⋯ is doomed⋯. Thanks to⋯ the Rowdyruff Boys⋯.</description>
        <lastBuildDate>Tue, 14 Jan 2025 11:00:15 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>RoughBoy.log</title>
            <url>https://velog.velcdn.com/images/ohwy0723-/profile/1c4a0754-e37c-4c42-9231-dba6872b7ed4/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. RoughBoy.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ohwy0723-" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[DES]]></title>
            <link>https://velog.io/@ohwy0723-/DES</link>
            <guid>https://velog.io/@ohwy0723-/DES</guid>
            <pubDate>Tue, 14 Jan 2025 11:00:15 GMT</pubDate>
            <description><![CDATA[<h4 id="오랜만에-블로그를-써본다">오랜만에 블로그를 써본다.</h4>
<p>지난해 화이트햇을 마치고 BoB의 보안제품개발 트랙에 붙어서 프로젝트가 끝난뒤 정보보안 스타트업에 취직하게되어서 직무를 준비하는 과정에 대해서 써볼 예정이다. 많은 양은 쓰지 못하겠지만 직무를 준비하면서 써보겠다.</p>
<p>먼저 내 직무는 암호 모듈 개발자로 C를 이용한 암호 라이브러리나 하드웨어 모듈을 만들게 될 예정이다. 그에 따라 준비하기위해서 기초적인 암호 알고리즘을 작성해볼것이고 더 나아가 KCMVP에 대해 분석해보며 정리할 예정이다. </p>
<p>이번 글에서는 DES에 대해 작성해 보겠다. 개발에 앞서 면접을 볼때 paper만 보고도 암호 알고리즘을 작성할 줄 알아야한다고 해서 최대한 인터넷에 있는 코드들은 보지 않고 paper만 보고 작성해보고자 했다. 보통의 유명한 암호화 알고리즘인 DES, AES, RSA, ECC등은 NIST의 표준이기에 구글에 검색해보면 <a href="https://www.nist.gov/">NIST사이트</a>에 표준이 있기에 <a href="https://csrc.nist.gov/files/pubs/fips/46-3/final/docs/fips46-3.pdf">DES 표준</a>을 보면서 개발해 보았다.</p>
<p><img src="https://velog.velcdn.com/images/ohwy0723-/post/3119a7a1-42e2-4151-b163-61ad3599d6ed/image.png" alt=""></p>
<p>DES는 1977년 만들어진 블록 암호화 알고리즘으로 64bit의 키와 64bit의 블록을 가지고 암-복호화를 한다. </p>
<hr>
<h3 id="key-생성-및-스케줄링">KEY 생성 및 스케줄링</h3>
<h4 id="64bit-key-생성">64bit KEY 생성</h4>
<p>키값은 윈도우나 리눅스의 난수 생성 함수를 통해 64bit는 생성하면 된다.</p>
<h4 id="key-스케줄링">KEY 스케줄링</h4>
<p>64bit 키를 스케줄링을 통해 16개의 48bit sub key를 생성하는 과정이다.
순서는 아래와 같다.</p>
<ol>
<li>정해진 테이블을 이용한 PC-1함수를 통해 64bit를 56bit로 치환한다. </li>
<li>바뀐 56bit를 왼쪽, 오른쪽 28bit로 나눈다. (shift 혹은 &amp; 연산)</li>
</ol>
<p><strong>3. 각 R과 L을 정해진 테이블대로 Left로 shift 해준다.</strong>
<strong>4. 1번과 같이 L, R을 합친뒤(56bit) PC2를 통해 48bit로 치환하여 서브키를 생성한다.</strong>
5. 3~4번을 16번 반복하면서 48bit round key를 16개 생성한다.</p>
<p><img src="https://velog.velcdn.com/images/ohwy0723-/post/0c6ea577-e4de-42ce-ad14-aee56d508a3d/image.png" alt="키 스케줄링"></p>
<hr>
<h3 id="enc-dec">ENC, DEC</h3>
<p>암복호화는 대칭키 암호화 알고리즘으로 혼돈, 확산을 응용해 알기 어렵게 하는것이다.</p>
<p>암호화 순서는 아래 글과 사진으로 설명한다.</p>
<ol>
<li>input을 64bit 블록 단위로 나눈다.</li>
<li>블록을 IP를 통해 테이블 치환을 한다.</li>
<li>L, R 32bit씩 나눈다.</li>
</ol>
<p><strong>4. R을 f(R)을 통해 혼돈과 확산시킨다.</strong>
<strong>5. 4번의 결과로 나온 R을 L과 xor한다.</strong>
<strong>6. 5번 결과값을 R에 넣는다.</strong>
<strong>7. 초기 R값을 L에 넣어 R과 L값을 swap한다.</strong>
<strong>8. 위 4~7번을 16번의 라운드를 거친다.</strong>
9. 마지막 라운드의 결과는 R과 L을 swap하지 않고 64bit(output)로 합친다. 
10. output을 IIP를 통해 역치환을 한다. </p>
<p><img src="https://velog.velcdn.com/images/ohwy0723-/post/1490204b-1840-4f1d-b0b1-aa63a59ab46f/image.png" alt="암-복호화">
위 암호화 라운드를 표현한 그림</p>
<p>아래는 암호화 라운드 내부의 f()함수가 어떤 작동을 하는지에 대한 그림이다.
순서대로 설명하겠다.</p>
<ol>
<li>R(Half Block)을 Expansion 테이블을 사용하여 48bit로 확장한다.  </li>
<li>key 스케줄링을 통해 만들었던 서브키(round key)를 확장한 R과 xor한다.</li>
<li>2번의 결과 값을 6bit 8개로 나누어서 S-box를 이용해 32bit로 축소 시킨다.</li>
<li>3번의 결과 값을 주어진 P 테이블을 이용해 치환한다.  </li>
</ol>
<p><img src="https://velog.velcdn.com/images/ohwy0723-/post/97b55776-98e6-4a4a-b43f-924ae2bdd543/image.png" alt="f 함수">
암호화 내부 f함수의 동작도</p>
<p>위와 같은 동작을 구현하면 64bit블록을 암호화 구현할 수 있다.</p>
<p>코드는 아래와 같다.</p>
<pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdint.h&gt;
#include &lt;windows.h&gt;
#include &lt;bcrypt.h&gt;

#pragma comment(lib, &quot;bcrypt.lib&quot;)

/*
 * DES는 미국에서 1977년 발표된 대칭키를 사용하는 블록 암호화 알고리즘이다.
 * DES는 키 길이가 64bit이며, 블록의 크기도 64bit이다.
 * 암호화 과정은 다음과 같다.
 * RNG를 통해 64bit 키를 생성한뒤 키 스케줄링을 통해 16개의 서브키를 생성한다.
 * 만든 16개의 서브키를 사용하여 64bit의 평문을 16라운드에 걸쳐 암호화한다.
 * 혼돈과 확산 개념을 사용하여 암호화를 거치며 최종적으로 64bit 암호문을 생성한다.
 */

const int message_initial_permutation[64] = {
    58, 50, 42, 34, 26, 18, 10, 02,
    60, 52, 44, 36, 28, 20, 12, 04,
    62, 54, 46, 38, 30, 22, 14, 06,
    64, 56, 48, 40, 32, 24, 16, 8,
    57, 49, 41, 33, 25, 17, 9, 01,
    59, 51, 43, 35, 27, 19, 11, 03,
    61, 53, 45, 37, 29, 21, 13, 05,
    63, 55, 47, 39, 31, 23, 15, 07
};

const int inverse_message_final_permutation[64] = {
    40, 8, 48, 16, 56, 24, 64, 32,
    39, 07, 47, 15, 55, 23, 63, 31,
    38, 06, 46, 14, 54, 22, 62, 30,
    37, 05, 45, 13, 53, 21, 61, 29,
    36, 04, 44, 12, 52, 20, 60, 28,
    35, 03, 43, 11, 51, 19, 59, 27,
    34, 02, 42, 10, 50, 18, 58, 26,
    33, 01, 41, 9, 49, 17, 57, 25
};

const int expansion_p_box[48] = {
    32, 01, 02, 03, 04, 05,
    04, 05, 06, 07, 8, 9,
    8, 9, 10, 11, 12, 13,
    12, 13, 14, 15, 16, 17,
    16, 17, 18, 19, 20, 21,
    20, 21, 22, 23, 24, 25,
    24, 25, 26, 27, 28, 29,
    28, 29, 30, 31, 32, 01
};

const int straight_p_box[32] = {
    16, 07, 20, 21,
    29, 12, 28, 17,
    01, 15, 23, 26,
    05, 18, 31, 10,
    02, 8, 24, 14,
    32, 27, 03, 9,
    19, 13, 30, 06,
    22, 11, 04, 25
};

const int left_shift[16] = {
    1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};

const int S1[4][16] = { 14,  4, 13,  1,  2, 15, 11,  8,  3, 10,  6, 12,  5,  9,  0,  7,
             0, 15,  7,  4, 14,  2, 13,  1, 10,  6, 12, 11,  9,  5,  3,  8,
             4,  1, 14,  8, 13,  6,  2, 11, 15, 12,  9,  7,  3, 10,  5,  0,
            15, 12,  8,  2,  4,  9,  1,  7,  5, 11,  3, 14, 10,  0,  6, 13
};

const int S2[4][16] = { 15,  1,  8, 14,  6, 11,  3,  4,  9,  7,  2, 13, 12,  0,  5, 10,
             3, 13,  4,  7, 15,  2,  8, 14, 12,  0,  1, 10,  6,  9, 11,  5,
             0, 14,  7, 11, 10,  4, 13,  1,  5,  8, 12,  6,  9,  3,  2, 15,
            13,  8, 10,  1,  3, 15,  4,  2, 11,  6,  7, 12,  0,  5, 14,  9
};

const int S3[4][16] = { 10,  0,  9, 14,  6,  3, 15,  5,  1, 13, 12,  7, 11,  4,  2,  8,
            13,  7,  0,  9,  3,  4,  6, 10,  2,  8,  5, 14, 12, 11, 15,  1,
            13,  6,  4,  9,  8, 15,  3,  0, 11,  1,  2, 12,  5, 10, 14,  7,
             1, 10, 13,  0,  6,  9,  8,  7,  4, 15, 14,  3, 11,  5,  2, 12
};

const int S4[4][16] = { 7, 13, 14,  3,  0,  6,  9, 10,  1,  2,  8,  5, 11, 12,  4, 15,
            13,  8, 11,  5,  6, 15,  0,  3,  4,  7,  2, 12,  1, 10, 14,  9,
            10,  6,  9,  0, 12, 11,  7, 13, 15,  1,  3, 14,  5,  2,  8,  4,
             3, 15,  0,  6, 10,  1, 13,  8,  9,  4,  5, 11, 12,  7,  2, 14
};

const int S5[4][16] = { 2, 12,  4,  1,  7, 10, 11,  6,  8,  5,  3, 15, 13,  0, 14,  9,
            14, 11,  2, 12,  4,  7, 13,  1,  5,  0, 15, 10,  3,  9,  8,  6,
             4,  2,  1, 11, 10, 13,  7,  8, 15,  9, 12,  5,  6,  3,  0, 14,
            11,  8, 12,  7,  1, 14,  2, 13,  6, 15,  0,  9, 10,  4,  5,  3
};

const int S6[4][16] = { 12,  1, 10, 15,  9,  2,  6,  8,  0, 13,  3,  4, 14,  7,  5, 11,
            10, 15,  4,  2,  7, 12,  9,  5,  6,  1, 13, 14,  0, 11,  3,  8,
             9, 14, 15,  5,  2,  8, 12,  3,  7,  0,  4, 10,  1, 13, 11,  6,
             4,  3,  2, 12,  9,  5, 15, 10, 11, 14,  1,  7,  6,  0,  8, 13
};

const int S7[4][16] = { 4, 11,  2, 14, 15,  0,  8, 13,  3, 12,  9,  7,  5, 10,  6,  1,
            13,  0, 11,  7,  4,  9,  1, 10, 14,  3,  5, 12,  2, 15,  8,  6,
             1,  4, 11, 13, 12,  3,  7, 14, 10, 15,  6,  8,  0,  5,  9,  2,
             6, 11, 13,  8,  1,  4, 10,  7,  9,  5,  0, 15, 14,  2,  3, 12
};

const int S8[4][16] = { 13,  2,  8,  4,  6, 15, 11,  1, 10,  9,  3, 14,  5,  0, 12,  7,
             1, 15, 13,  8, 10,  3,  7,  4, 12,  5,  6, 11,  0, 14,  9,  2,
             7, 11,  4,  1,  9, 12, 14,  2,  0,  6, 10, 13, 15,  3,  5,  8,
             2,  1, 14,  7,  4, 10,  8, 13, 15, 12,  9,  0,  3,  5,  6, 11
};

const int permuted_choice1[56] = {
    57, 49, 41, 33, 25, 17, 9,
    01, 58, 50, 42, 34, 26, 18,
    10, 02, 59, 51, 43, 35, 27,
    19, 11, 03, 60, 52, 44, 36,
    63, 55, 47, 39, 31, 23, 15,
    07, 62, 54, 46, 38, 30, 22,
    14, 06, 61, 53, 45, 37, 29,
    21, 13, 05, 28, 20, 12, 04
};

const int permuted_choice2[48] = {
    14, 17, 11, 24, 01, 05,
    03, 28, 15, 06, 21, 10,
    23, 19, 12, 04, 26, 8,
    16, 07, 27, 20, 13, 02,
    41, 52, 31 ,37, 47, 55,
    30, 40, 51, 45, 33, 48,
    44, 49, 39, 56, 34, 53,
    46, 42, 50, 36, 29, 32
};

// char 2byte, int 4byte 
// 16bit * 4 , 32bit * 2
// DES는 64bit 블록 암호화 구현


// key 생성 함수 windows.h에 있는 BCryptGenRandom 함수 사용
uint64_t Key_Generation() {
    uint64_t key = 0;

    // BCryptGenRandom 함수 호출로 암호학적으로 안전한 난수 생성
    if (BCryptGenRandom(NULL, (PUCHAR)&amp;key, sizeof(key), BCRYPT_USE_SYSTEM_PREFERRED_RNG) != 0) {
        fprintf(stderr, &quot;Error generating random bytes\n&quot;);
        exit(EXIT_FAILURE);
    }

    return key;
}

// 치환 함수(분석 필요)
uint64_t Permuter_Choice(uint64_t var, const int pc[], int number) {
    int a;
    uint64_t numb = 0x00;
    uint64_t aft_ch = 0x00;

    for (a = 0; a &lt; number; a++) { 
        numb = var &gt;&gt; ((number + 8) - pc[a]);
        if (number == 56) // 64-&gt;56(pc1)
        {
            numb = numb &lt;&lt; (number + 7); 
            numb = numb &gt;&gt; (a + 8);  56비트를 만들기 위해서는 8을 더해줌
            aft_ch = (aft_ch | numb);
        }
        else // number = 48 // 56-&gt;48(pc2)
        {
            numb = var &gt;&gt; ((number + 8) - pc[a]);
            numb = numb &lt;&lt; (number + 15);
            numb = numb &gt;&gt; (a + 16);
            aft_ch = (aft_ch | numb);
        }
    }
    return aft_ch;
}

// 32비트를 p_box를 가지고 48비트로 확장 (분석 필요)
uint64_t Expansion_Bit(uint32_t R) {
    uint64_t res = 0;
    for (int i = 0; i &lt; 48; i++) {
        res |= (uint64_t)((R &gt;&gt; (32 - expansion_p_box[i])) &amp; 1) &lt;&lt; (47 - i);
    }
    return res;
}

// 32비트를 n만큼 왼쪽으로 회전
uint32_t Rotation(uint32_t num, unsigned int n) {
    return (((num &lt;&lt; n) &amp; 0xffffffff) | (num &gt;&gt; (28 - n)));
}

// key를 가지고 16개의 subkey를 생성
void Key_Schedule(uint64_t key, uint64_t* sub_key) {
    uint64_t tmp = 0;

    uint32_t C = 0, D = 0;
    tmp = Permuter_Choice(key, permuted_choice1, 56);

    C = tmp &gt;&gt; 28;
    D = (tmp &lt;&lt; 28) &gt;&gt; 28;

    for (int i = 0; i &lt; 16; i++) {
        C = Rotation(C, left_shift[i]);
        D = Rotation(D, left_shift[i]);

        tmp = (uint64_t)C &lt;&lt; 28;
        tmp |= (uint64_t)D;

        *(sub_key + i) = Permuter_Choice(tmp, permuted_choice2, 48);
    }

}

// 16round를 거치면서 48bit을 32bit으로 축소하는 S-Box
uint32_t S_Box(uint64_t num) {

    //num 은 48 bit니까 S_box 들어가기전 6비트 8개로 쪼개줘야함

    uint8_t rows[8], cols[8];

    uint32_t res = 0x00;

    for (int i = 7; i &gt;= 0; i--) {
        rows[i] = num &amp; 0b00100001;
        rows[i] = (rows[i] &amp; 0b00000001) | (rows[i] &gt;&gt; 4);

        cols[i] = (num &amp; 0b00011110) &gt;&gt; 1;

        num = num &gt;&gt; 6;
    }

    //S-Box를 3차원으로 만들고 이것도 for문으로 변경
    res |= S8[rows[7]][cols[7]];
    res |= (uint32_t)S7[rows[6]][cols[6]] &lt;&lt; 4;
    res |= (uint32_t)S6[rows[5]][cols[5]] &lt;&lt; 8;
    res |= (uint32_t)S5[rows[4]][cols[4]] &lt;&lt; 12;
    res |= (uint32_t)S4[rows[3]][cols[3]] &lt;&lt; 16;
    res |= (uint32_t)S3[rows[2]][cols[2]] &lt;&lt; 20;
    res |= (uint32_t)S2[rows[1]][cols[1]] &lt;&lt; 24;
    res |= (uint32_t)S1[rows[0]][cols[0]] &lt;&lt; 28;

    return res;
}

// 
// Enc에서 input을 message_initial_permutation를 사용하여 테이블로 치환
uint64_t Initial_Permuter(uint64_t plain_text) {
    uint64_t aftpt = 0;
    for (int i = 0; i &lt; 64; i++) {
        aftpt &lt;&lt;= 1;
        aftpt |= (plain_text &gt;&gt; (64 - message_initial_permutation[i])) &amp; 0x0000000000000001;
    }
    return aftpt;
}

// Enc에서 16-round를 끝내고 최종 치환 
uint64_t Inverse_Initial_Permuter(uint64_t cipher_text) {
    uint64_t aftct = 0;
    for (int i = 0; i &lt; 64; i++) {
        aftct |= ((cipher_text &gt;&gt; (64 - inverse_message_final_permutation[i])) &amp; 0x01) &lt;&lt; (63 - i);
    }
    return aftct;
}

// Enc 라운드내 함수의 치환함수
uint32_t Primitive(uint32_t num) {
    uint32_t res = 0;
    for (int i = 0; i &lt; 32; i++) {
        res = res | ((num &gt;&gt; (32 - straight_p_box[i])) &amp; 0x01) &lt;&lt; (31 - i);
    }
    return res;
}

void Enc(uint64_t* plain_text, uint64_t* cipher_text, uint64_t key) {
    uint64_t tmp = 0x00;
    uint64_t sub_key[16];
    uint64_t output = 0;
    uint32_t R_tmp = 0, swap_tmp = 0;

    // key값을 가지고 subkey 생성
    Key_Schedule(key, sub_key);

    for (int i = 0; i &lt; 16; i++) {
        printf(&quot;subkey[%d] : %llx\n&quot;, i, sub_key[i]);
    }

    // plain_text를 Initial Permutation(message_initial_permutation을 테이블로 치환)
    tmp = Initial_Permuter(*plain_text);

    printf(&quot;Initial Permutation : %llx\n&quot;, tmp);

    // 치환한 값을 32bit R, L로 나누기
    uint32_t L = 0, R = 0;

    // 치환한 값을 32bit R, L로 나누기
    L = tmp &gt;&gt; 32;
    R = tmp &amp; 0x00000000FFFFFFFF;

    printf(&quot;L : %x\n&quot;, L);
    printf(&quot;R : %x\n&quot;, R);

    //16라운드 반복
    for (int i = 0; i &lt; 16; i++) {
        R_tmp = R;

        /***         f() 시작        ***/
        //32bit R을 48bit으로 확장
        output = Expansion_Bit(R);

        // 48bit로 확장된 R과 subkey[i]를 xor연산
        output ^= sub_key[i];

        // S-Box로 32bit으로 축소
        R = S_Box(output);

        // 단순 치환 P-Box
        R = Primitive(R);
        /****         f() 끝         ***/

        // L과 xor연산
        R ^= L;

        // L, R swap
        L = R_tmp;
    }

    // 마지막 16라운드에는 swap을 복원
    swap_tmp = R;
    R = L;
    L = swap_tmp;

    // R과 L을 합치고 최종 치환
    tmp = ((uint64_t)L &lt;&lt; 32) | (uint64_t)R;
    *cipher_text = Inverse_Initial_Permuter(tmp);
}


void Dec(uint64_t* cipher_text, uint64_t* plain_text, uint64_t key) {
    uint64_t tmp = 0x00;
    uint64_t sub_key[16];
    uint64_t output = 0;
    uint32_t R_tmp = 0, swap_tmp = 0;


    // key값을 가지고 subkey 생성
    Key_Schedule(key, sub_key);

    // plain_text를 Initial Permutation(message_initial_permutation을 테이블로 치환)
    tmp = Initial_Permuter(*cipher_text);

    // 치환한 값을 32bit R, L로 나누기
    uint32_t L = 0, R = 0;

    // 치환한 값을 32bit R, L로 나누기
    L = tmp &gt;&gt; 32;
    R = tmp &amp; 0x00000000FFFFFFFF;

    //16라운드 반복 (Enc와는 Reverse 라운드)
    for (int i = 15; i &gt;= 0; i--) {
        R_tmp = R;

        /***         f() 시작        ***/
        //32bit R을 48bit으로 확장
        output = Expansion_Bit(R);

        // 48bit로 확장된 R과 subkey[i]를 xor연산
        output ^= sub_key[i];

        // S-Box로 32bit으로 축소
        R = S_Box(output);

        // 단순 치환 P-Box
        R = Primitive(R);
        /****         f() 끝         ***/

        // L과 xor연산
        R ^= L;

        // L, R swap
        L = R_tmp;
    }

    // 마지막 16라운드에는 swap을 복원
    swap_tmp = R;
    R = L;
    L = swap_tmp;

    // R과 L을 합치고 최종 치환
    tmp = ((uint64_t)L &lt;&lt; 32) | (uint64_t)R;
    *plain_text = Inverse_Initial_Permuter(tmp);
}


int main()
{
    // Key 생성
    //uint64_t key = 0x02468ace13579bdf;
    uint64_t key = Key_Generation();

    // 평문
    uint64_t plain_text = 0x0123456789abcdef;

    // 암호문
    uint64_t cipher_text = 0;

    // 복호문
    uint64_t decrypt_text = 0;

    printf(&quot;Plain Text : %llx\n&quot;, plain_text);
    printf(&quot;Key : %llx\n&quot;, key);

    //    암호화
    Enc(&amp;plain_text, &amp;cipher_text, key);

    printf(&quot;Cipher Text : %llx\n&quot;, cipher_text);

    //복호화
    Dec(&amp;cipher_text, &amp;decrypt_text, key);

    printf(&quot;Decrypt Text : %llx\n&quot;, decrypt_text);
}</code></pre>
<p>지금은 블록 암호화 개념을 이해하고 구현만하느라 코드에서 최적화 및 가독성이 좋지 않다.
이 코드는 그냥 재미삼아 보면 좋을것이다. 조금더 최적화를 진행해보고 다음은 LEA를 구현해볼 예정이다. 그후에는 KCMVP에 대해 서술해 보겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리눅스 커널 빌드하는법!]]></title>
            <link>https://velog.io/@ohwy0723-/%EB%A6%AC%EB%88%85%EC%8A%A4-%EC%BB%A4%EB%84%90-%EB%B9%8C%EB%93%9C%ED%95%98%EB%8A%94%EB%B2%95</link>
            <guid>https://velog.io/@ohwy0723-/%EB%A6%AC%EB%88%85%EC%8A%A4-%EC%BB%A4%EB%84%90-%EB%B9%8C%EB%93%9C%ED%95%98%EB%8A%94%EB%B2%95</guid>
            <pubDate>Tue, 16 Apr 2024 12:22:43 GMT</pubDate>
            <description><![CDATA[<h2 id="지역-도서관에서-흥미있는-책을-발견해서-시작하는-프로젝트">지역 도서관에서 흥미있는 책을 발견해서 시작하는 프로젝트</h2>
<p><img src="https://velog.velcdn.com/images/ohwy0723-/post/9e70b12c-9233-41f0-aba9-51ce479f29a0/image.png" alt=""></p>
<p>지난주부터 최근 일주일간 카페와 집을 드나들면서 하루에 몇시간씩 이 책을 읽으면서 공부를 시작했는데!
개발 모델 설정부터 UML까지 개발에 관해 상세하게 알려주면서 실제 개발을 위한 환경 설정을 위해 가상머신 설정과 커널 빌드하는 방법을 알려주는데, 2017년에 집필된 책이다 보니까 지금의 개발환경과는 다른면도 꽤나 있습니다.</p>
<p>그래서 혹시나 다른 분들이 이 책을 읽으면서 커널 빌드에 어려움을 겪으신다면 이 페이지를 통해 도움이 되셨으면 하는바람에 작성해봅니다.</p>
<p>먼저 책에서는 우분투 14.04.6v에서 리눅스 커널 4.2.0v를 사용하는데 이는 24년에서는 과거 버전이고 제가 했던 시행착오를 여러가지 소개해드리면서 제가 성공한 방법에 대해서 말해드리겠습니다.</p>
<ol>
<li><p>우분투 22.04.3 리눅스 커널 6.5.0-27-generic 설치시도 커널 6.5</p>
</li>
<li><p>우분투 14.04.6 리눅스 커널 4.4.0 설치시도 커널 4.2.0</p>
</li>
<li><p>우분투 22.04.4  리눅스 커널 6.5.0 설치시도 커널 6.8.6</p>
</li>
</ol>
<p>우와 같이 여러방법을 시도했으나 결국 3번 최신 우분투에서 최신 커널을 설치하는데 성공하였습니다.</p>
<h3 id="책에서의-빌드-순서-디렉토리-생성-및-이동은-생략">책에서의 빌드 순서 (디렉토리 생성 및 이동은 생략)</h3>
<ol>
<li><code>sudo apt-get install build-essential libssl-dev</code> : 의존성 패키지 설치</li>
<li><code>apt-get source linux-image-$(uname -r)</code> : 해당 리눅스 커널 이미지 설치</li>
<li><code>cp /boot/config-$(uname -r) .config</code> : 설정 파일 복사</li>
<li><code>make -j5 bzImage</code> : 이미지 파일 생성</li>
<li><code>make modules</code> : 모듈 생성</li>
<li><code>sudo make modules_install</code> : 모듈 설치</li>
<li><code>sudo make install</code> : 커널 설치</li>
<li><code>reboot</code> : 재부팅으로 커널 설치 확인</li>
</ol>
<p>저도 처음에는 위와 같은 방법으로 시도 했으나 커널 <code>2. 이미지 설치</code>에서 커널은 없고 패키지 설정만 있었고 <a href="kernel.org">kernel.org</a> 에 들어가서 커널 파일을 다운로드 받아야 커널을 구하였고 설정 파일 복사후 <code>4. 이미지 파일 생성</code>부터 며칠간은 뜨는 error들과 맞서 싸우느라 헤맸었습니다.</p>
<h3 id="에러들-해결한-빌드-순서">에러들 해결한 빌드 순서</h3>
<ol>
<li><p><code>sudo apt-get install build-essential libssl-dev libncurses-dev libelf-dev flex bison</code> : 의존성 패키지 설치 &lt;- 몇가지가 추가되었습니다.</p>
</li>
<li><p><code>wget https://mirrors.edge.kernel.org/pub/linux/kernel/v6.x/linux-6.8.6.tar.xz</code> : 해당 리눅스 커널 다운로드</p>
</li>
<li><p><code>tar -xvf linux-6.8.6.tar.xz</code> : 해당 리눅스 커널 압축해제</p>
</li>
<li><p><code>cd linux-6.8.6</code> : 해당 디렉토리로 이동</p>
</li>
<li><p><code>cp /boot/config-$(uname -r) ./.config</code> : 설정 파일 복사</p>
</li>
<li><p><code>make menuconfig</code> : 복사한 설정 파일을 적용할 커널에 맞게 설정</p>
<blockquote>
</blockquote>
<img src="https://velog.velcdn.com/images/ohwy0723-/post/9fd5f6a5-c03a-42f5-a825-5ead905762bf/image.png" width="500px">
위와 같이 화면에 뜨는데 load, save, exit를 통해 현재 커널에 적용해줍니다.
</li>
<li><p>.config 파일 수정
<code>CONFIG_SYSTEM_TRUSTED_KEYS=&quot;debian/canonical-certs.pem&quot; -&gt; CONFIG_SYSTEM_TRUSTED_KEYS = &quot;&quot; 
CONFIG_SYSTEM_REVOCATION_KEYS=&quot;debian/canonical-certs.pem&quot; -&gt; CONFIG_SYSTEM_REVOCATION_KEYS=&quot;&quot;</code>
두줄을 인파일검색을 통해 찾아준뒤 공백란으로 바꿔줍니다.</p>
</li>
<li><p><code>make bzImage</code> : 이미지 파일 생성</p>
</li>
<li><p><code>make modules</code> : 모듈 생성</p>
</li>
<li><p><code>sudo make modules_install</code> : 모듈 설치</p>
</li>
<li><p><code>sudo make install</code> : 커널 설치</p>
</li>
<li><p><code>reboot</code> : 재부팅으로 커널 설치 확인</p>
</li>
</ol>
<p>이렇게 하면 커널은 무사히 컴파일 됩니다.
<img src="https://velog.velcdn.com/images/ohwy0723-/post/e3ebbc87-566e-40d8-bce0-789f20e1bd4b/image.png" alt="">
지금 생각해보면 여러가지 안됐던 이유들이 지금 제가 적으면서 생각해보니까 다 해결되었네요.</p>
<p>앞으로 모듈을 만들어서 추가하는게 목표인데 화이팅!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[OWASP IOT TOP10 2018(번역)]]></title>
            <link>https://velog.io/@ohwy0723-/OWASP-IOT-TOP10-2018%EB%B2%88%EC%97%AD</link>
            <guid>https://velog.io/@ohwy0723-/OWASP-IOT-TOP10-2018%EB%B2%88%EC%97%AD</guid>
            <pubDate>Wed, 22 Nov 2023 06:31:52 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ohwy0723-/post/e0854ba4-944d-4355-8a8b-57d252aa31e5/image.jpg" alt=""></p>
<h3 id="2018년도에-작성된-owasp-internet-of-thingsiot-top-10">2018년도에 작성된 OWASP Internet of Things(IOT) TOP 10</h3>
<h4 id="1-쉽게-추측할수있거나-하드코딩되어있는-비밀번호weak-guessable-or-default-passwords">1. 쉽게 추측할수있거나 하드코딩되어있는 비밀번호(Weak, Guessable, or Default Passwords)</h4>
<p>&quot;배포된 시스템에 대한 무단 액세스를 허용하는 펌웨어 또는 클라이언트 소프트웨어의 백도어를 포함하여 쉽게 무차별 방식(Brute force)으로 공개적으로 사용 가능하거나 변경할 수 없는 자격 증명을 사용합니다.&quot;</p>
<p>오늘날 IoT 시스템의 일반적이고 만연한 취약점은 취약하거나 바뀌지않은 기본 비밀번호에서 비롯됩니다. 장치 자격 증명을 잘 못 관리하면 IoT장치가 무차별 대입 공격의 대상이 될 위험이 커집니다.</p>
<p>2018년 캘리포나이에선 SB-327 IoT 법률이 통과되어 기본 인증서 사용을 금지했습니다. 이 법은 최종적으로 취약한 비밀번호의 사용을 방지하는것을 목표로 만들어졌습니다.</p>
<p>이러한 시스템을 보호하기 위한 즉각적인 단계는 IT 관리자가 사용자와 관리자가 기본 장치 비밀번호를 변경하도록 요구하는 새로운 로그인 정책을 설정하는 것입니다.</p>
<h4 id="2-안전하지-않은-네트워크-서비스insecure-network-services">2. 안전하지 않은 네트워크 서비스(Insecure Network Services)</h4>
<p>“장치에서 실행되는 불필요하거나 안전하지 않은 네트워크 서비스, 특히 인터넷에 노출되는 네트워크 서비스는 정보의 기밀성, 무결성/진실성을 위태롭게 하고 IoT 장치의 무단 원격 제어 위험을 초래합니다.”</p>
<p>IoT 디바이스들은 네트워크 인프라에 통합되어 있으며 연기 경보, 근접 센서 또는 광학 장치와 같은 연결된 스마트 디바이스들로부터 데이터를 전송, 검색 및 해석할 수 있습니다. 시스템의 통신 메커니즘은 다양하지만 BLE 및 ZigBee부터 WiFi, 셀룰러 데이터 및 이더넷에 이르는 네트워크 프로토콜을 포함할 수 있습니다.</p>
<p>스마트 기술은 인간의 간섭 없이 선택을 할 수 있는 능력을 가지고 있어 독특합니다. 이러한 수준의 디바이스 자율성은 IoT 디바이스의 안전성을 손상시키지 않으면서 소비자 수준의 이동성과 상호 운용성을 보장해야 하는 어려움을 초래합니다.</p>
<p>인터넷에 연결된 모든 서비스가 올바르게 작동하려면 특정 포트를 열어야 합니다. 장치나 다른 기계에 대한 액세스를 제공하는 열린 포트와 서비스를 그대로 두는 것은 전형적인 보안 오류입니다. 비트사이트와 어드바이든의 공동 연구는 위반된 조직의 60%가 10개 이상의 취약한 열린 포트를 가지고 있다는 것을 보여주었습니다.</p>
<p>IoT 장치의 서비스 취약성을 이용하면 바이러스, 스파이웨어, 랜섬웨어 및 트로이 목마와 같은 은밀한 악성 소프트웨어 서비스가 발생할 수 있습니다. 사이버 범죄자는 이러한 오픈 포트 서비스를 사용하여 중요한 데이터에 액세스하거나 개인 통신을 듣거나 서비스 거부(DoS) 및 MITM(Man-in-the-middle) 공격을 실행할 수 있습니다.</p>
<p>그러나 심각한 보안 위협에도 불구하고 이러한 네트워크 계층 취약성을 해결할 수 있는 자동화된 보안 옵션이 부족합니다. 65,000개가 넘는 TCP 포트와 그에 상응하는 수의 UDP 포트를 사용하여 포트를 열고 닫을 수 있는 간단한 방법이 없습니다.</p>
<p>포트 유지 관리를 위해서는 네트워크에 필수 서비스를 연결하기 위해 어떤 포트가 열려 있어야 하는지 아는 관리자가 필요합니다. 포트가 열려 있고 중요한 네트워크 서비스에 연결되어 있지 않다면 포트는 즉시 닫아야 합니다.</p>
<p>상대적으로 IP 주소가 적은 소규모 네트워크는 취약한 포트를 폐쇄하는 데 오랜 시간이 걸리지 않아야 합니다. 그러나 새로운 장치를 지속적으로 추가하는 기업 네트워크에서는 개방된 포트를 모니터링하고 관리하는 데 시간이 많이 소요될 수 있습니다.</p>
<p>시스템 관리자는 네트워크에서 정보를 교환하는 불필요한 열린 포트 및 서비스를 검색하고 닫아야 합니다.</p>
<h4 id="3-안전하지-않은-생태계-인터페이스insecure-ecosystem-interfaces">3. 안전하지 않은 생태계 인터페이스(Insecure Ecosystem Interfaces)</h4>
<p>&quot;기기나 관련 구성 요소를 손상시킬 수 있는 기기 외부의 생태계에서 안전하지 않은 웹, 백엔드 API, 클라우드 또는 모바일 인터페이스. 일반적인 문제로는 인증/인가 부족, 암호화 부족 또는 취약, 입출력 필터링 부족 등이 있습니다.&quot;</p>
<p>많은 기업들이 백엔드 API에 연결할 때 IoT 시스템 보안 정책과 절차를 간과하는 경우가 많습니다. 생태계의 모든 장치와 센서, 그리고 이를 인터페이스하는 모든 장치를 이해하는 것이 중요합니다.</p>
<p>IoT 시스템은 대용량의 정보를 송수신하고 REST 기반의 API를 통해 디바이스/센서, 게이트웨이 디바이스, 백엔드 데이터베이스 간의 데이터 전송을 안전하게 보호합니다.</p>
<p>API가 강력한 확장성을 제공하지만, 이러한 동일한 API는 공격자가 여러분의 IoT 장치에 데이터를 연결하고 액세스할 수 있는 새로운 입구를 제공합니다. 해커는 올바르게 보안되지 않으면 라우터나 장치의 웹 인터페이스를 침해할 수 있습니다. 인증, 암호화 및 공개 키 인프라스트럭처(PKI)는 API가 미리 검증된 다른 장치 및 응용 프로그램과만 통신하도록 보장합니다.</p>
<p>또 다른 흔한 문제는 원격 관리 또는 원격 관리로 알려진 기능인 원격 웹 인터페이스에 연결된 라우터입니다. 관리자는 열린 포트 80(HTTP)과 443(HTTPS)을 확인함으로써 원격 관리를 위한 라우터의 가용성을 테스트할 수 있습니다. 이것은 관리자들이 이 기능을 안전하게 비활성화할 수 있게 해줍니다.</p>
<p>IoT 기기를 백엔드 시스템에 연결하는 네트워크도 안전해야 합니다.</p>
<p>IoT 애플리케이션은 표준, 장치, 통신 프로토콜이 다양하기 때문에 네트워크 보안이 더욱 어렵습니다. 설계 및 구현 시 IoT 네트워크 보안에 세심한 주의가 필요합니다.</p>
<p>개발자들은 기기 자체가 보호된다고 가정하지 않고 더 안전한 IoT 어플리케이션을 설계할 필요가 있습니다. 방화벽, 안티바이러스, 침입 탐지 및 방지 시스템은 안전한 IoT 네트워크를 제공해야 합니다.</p>
<p>IoT 기기들은 연결하고자 하는 기기의 신원을 확인하기 위해 서로 인증해야 합니다. 기기가 여러 기기에서 신원 확인을 수행하면 중앙 인증 기관이 도움이 될 수 있습니다.</p>
<p>또한 잘 훈련된 관리자가 정기적으로 패키지를 업데이트하고 오래된 서비스 및 패키지를 탐지 및 삭제하는 것이 필수적입니다.</p>
<h4 id="4-취약한-업데이트-메카니즘lack-of-a-secure-update-mechanism">4. 취약한 업데이트 메카니즘(Lack of a Secure Update Mechanism)</h4>
<p>&quot;IoT장치를 안전하게 업데이트하는 기능이 부족합니다. 부족한 점으로는 장치의 펌웨어 검증 부족, 안전한 전송 부족(전송 중 암호화 X), 롤백 방지 메카니즘 부족, 업데이트로 인한 보안 변경 알림 부족 등이 포함됩니다.&quot;</p>
<p>업데이트를 진행할때는 어떻게 수행되는지, 그리고 더욱 안전하게 만드는 방법을 고려해야합니다. 예를 들어 스마트 워치나 IOT센서와 같은 장치를 설계할 때 적절한 시기의 업데이트를 위한 업데이트 메카니즘 구축을 고려해야합니다.</p>
<p><em>**정기적인 업데이트는 운영체제, 펌웨어 및 애플리케이션의 공격 벡터 수를 최소화합니다.</em>
**
업데이트가 있는 경우 일부 장치에서는 사용자에게 업데이트가 있음을 알리지 않을 수 있습니다. 반대로, 다른 장치에서는 자동으로 업데이트를 설치할 수 있지만 업데이트가 적용되기 전에 하드웨어를 재부팅해야 할 수도 있습니다. 재부팅하면 업데이트를 적용하는 동안 시스템이 취약해지고 사용할 수 없게 됩니다.</p>
<p><strong><em>각 업데이트의 원본과 무결성을 확인하고 적법한 공급업체의 적법한 애플리케이션만 사용하는것이 중요합니다.</em></strong>
일부 사용 가능한 업데이트 메커니즘에는 무결성 보장이 부족하여 MITM 공격 및 수정 공격에 추약합니다. 기계 대 기꼐 인증 방법을 사용하여 새 펌웨어의 이미지를 다운로드하기 전에 업그레이드 서버를 인증하여 보호 계층을 추가 할 수 있습니다.</p>
<h4 id="5-취약하거나-업데이트-되지않은-구성-요소-사용use-of-insecure-or-outdated-components">5. 취약하거나 업데이트 되지않은 구성 요소 사용(Use of Insecure or Outdated Components)</h4>
<p>&quot;장치가 손상될 수 있는 사용 가치가 떨어지거나 안전하지 않은 소프트웨어 구성요소/라이브러리를 사용합니다. 여기에는 운영 체제 플랫폼의 안전하지 않은 사용자 지정, 손상된 공급망의 타사 소프트웨어 또는 하드웨어 구성요소 사용이 포함됩니다.&quot;</p>
<p>소프트웨어 종속성 또는 레거시 시스템의 취약성으로 인해 잠재적인 문제가 발생할 수 있습니다.</p>
<p>수백만 개의 IoT 스마트 기기에 영향을 미치는 중요한 취약점은 제조업체가 IoT 기기를 구축하기 위해 사용하는 타사 컴포넌트, 라이브러리, 프레임워크 등 오래되거나 보안이 되지 않은 소프트웨어를 사용하는 것입니다. 이 소프트웨어는 추적하기가 어렵고 제대로 알려지지 않거나 관리되지 않으면 사이버 공격에 취약합니다.</p>
<p>기존의 IoT 기기용 소프트웨어 업데이트 프로토콜을 사용하는 레거시 시스템은 사용자가 보안의 구멍을 찾고 패치하는 데 부담을 줍니다. 이러한 프로토콜은 다른 시스템이나 기기와 상호 작용하지 않고 방화벽 기기에서 실행됩니다. 결과적으로 사이버 보안 시스템은 IoT 기기를 알려지지 않은 엔드포인트로 간주하고, 따라서 IoT 기기의 특정 기기 유형, 위험 프로파일 및 예상 동작을 알지 못합니다.</p>
<p>이는 네트워크에 연결된 모든 엔드포인트에 걸쳐 가시성을 갖지만 IoT 기업 환경을 식별, 추적 및 보안할 수 있을 정도로 잘 확장할 수 없는 기존의 네트워크 기반 사이버 보안 시스템과 다릅니다.</p>
<p>IoT 자산은 이러한 고유한 위협의 실행을 방지하기 위해 보다 강력한 리스크 관리 관행이 필요합니다. PKI와 디지털 인증서는 기업 방화벽 내부와 외부의 연결을 보호하기 위해 그 어느 때보다 중요합니다. 각 개인, 기계 및 애플리케이션은 검증되고 신뢰할 수 있는 ID를 가져야 합니다.</p>
<p>최신 클라우드 기반 보안 인프라가 기존 네트워크 경계를 대체하기 때문에 기존 보안 시스템의 펌웨어나 소프트웨어에 대한 인식을 유지하는 것이 중요합니다.</p>
<h4 id="6-충분하지-않은-개인-정보-보호insufficient-privacy-protection">6. 충분하지 않은 개인 정보 보호(Insufficient Privacy Protection)</h4>
<p>&quot;장치나 생태계에 저장된 사용자의 개인정보가 안전하지 않거나 부적절하게 사용되거나 무단으로 사용되는 경우&quot;</p>
<p>개인이 개인 데이터 삭제를 요청할 때 제공자는 모든 제3자가 데이터를 삭제하도록 보장해야 합니다.</p>
<p>웹사이트와 달리 많은 IoT 기기들은 개인 정보 보호 정책을 보기 위한 쉬운 접근을 제공하지 않습니다. 이들은 종종 기기 설명서와 별도로 포함됩니다. 때로는 시스템을 열고 설치한 후에만 사용할 수 있거나 설명서 어딘가에 사용자가 제조업체의 웹사이트를 방문하도록 지시하는 안내문이 있을 수 있습니다.</p>
<p>운전자의 주의를 산만하게 하는 것과 같은 피해를 야기하는 것에 대한 합법적인 우려 때문에, IoT 기기는 사람들에게 그들이 데이터를 수집하고 있다는 것을 경고하는 훌륭한 방법을 가지고 있지 않습니다. 게다가, 일부 IoT 서비스 제공자들의 개인 정보 보호 정책 진술은 시스템 기능을 식별하기 어렵고 데이터 수집에 대해 불분명합니다.</p>
<p>사물인터넷 어플리케이션은 데이터 유출 취약성에도 취약합니다. 연구원들이 230개의 스마트싱스 어플리케이션을 분석했을 때, 그들은 138개의 어플리케이션이 인터넷이나 메시징 서비스를 통해 적어도 하나의 민감한 데이터를 노출하는 것을 발견했습니다. 저자들은 또한 분석된 어플리케이션의 절반이 디바이스 정보, 디바이스 상태, 사용자 입력, 인터넷 또는 메시징 서비스와 같은 적어도 세 가지의 다른 민감한 데이터 소스를 유출한다는 것을 보여주었습니다.</p>
<h4 id="7-안전하지-않은-데이터-전송-및-저장insecure-data-transfer-and-storage">7. 안전하지 않은 데이터 전송 및 저장(Insecure Data Transfer and Storage)</h4>
<p>&quot;휴게소, 운송 중 또는 처리 중 등 생태계 내 어디서나 중요한 데이터를 암호화하거나 액세스 제어할 수 없습니다.&quot;</p>
<p>네트워크 및 통신 계층은 모든 IoT 애플리케이션 및 구현에서 중심 역할을 수행하여 서로 다른 계층 간의 정보 공유를 용이하게 하고 IoT 디바이스 간의 실시간 상호 작용을 통해 가치를 창출합니다.</p>
<p>IoT 애플리케이션의 주요 특징 중 하나는 IoT 디바이스, 네트워크, 네트워크 및 네트워크, 그리고 고수준의 정보 처리 인프라(예를 들어, 클라우드, 데이터 센터 등) 간에 정보를 전송하는 것입니다.</p>
<p>그러나 네트워크를 통해 이동하는 스마트 기기가 수집한 데이터를 손상시키거나 새로운 위치에 저장할 가능성이 증가하고 있습니다. 예를 들어, MITM 공격은 잘못된 키 교환 관행을 악용하고 악성 기기가 생태계를 통과하는 모든 정보를 가로챌 수 있도록 합니다.</p>
<p>대부분의 IT 팀은 네트워크 액세스 제어 프로토콜을 사용하여 동적으로 온보드 IT 장치를 설계하지만 이 기능을 IoT 자산으로 확장하지는 않습니다.</p>
<p>클라우드 기반의 통신과 데이터 스토리지가 계속해서 성장함에 따라, 더 많은 데이터가 클라우드와 IoT 컴퓨터로 흘러갑니다. 고객들은 그들의 데이터가 전송되는 동안 안전하기를 기대합니다.</p>
<p>오늘날 사물인터넷 데이터 전송 및 저장 모범 사례에서는 암호화된 사물인터넷 기기 통신을 위해 DTLS 프로토콜을 통해 안전한 공개 키 암호화를 요구합니다. 공개 키 암호화는 하드 코드화된 비밀이 아닌 개인 및 공개 암호화 키에 의존하는 강력한 암호화 방법입니다.</p>
<p>여러 IoT 보안 솔루션은 DTLS, PKI 및 차세대 하드웨어 보안과의 통합을 제공하여 장치 ID, 권한 및 위험 프로파일을 관리합니다.</p>
<p>이동 중 데이터 통신 보안은 일반적인 PKI에서 사용되는 신뢰 체인 모델에 의해 달성됩니다. PKI 인증서는 가장 일반적인 암호화 및 인증을 가지며 HTTPS 인터넷 프로토콜에서 가장 일반적으로 사용됩니다.</p>
<p>인증된 당사자의 신원에 대한 완전한 유효성을 인증하는 인증기관은 각 디지털 인증서를 발급해야 합니다. 데이터 토큰화는 공인된 장치만이 해독할 수 있는 민감한 암호화된 데이터를 보호할 수 있습니다.</p>
<h4 id="8-기기-관리의-부족함lack-of-device-management">8. 기기 관리의 부족함(Lack of Device Management)</h4>
<p>&quot;자산 관리, 업데이트 관리, 안전한 삭제, 시스템 모니터링, 대응 기능 등 프로덕션에 배포된 장치에 대한 보안 지원이 부족합니다.&quot;</p>
<p>IoT의 가장 중요한 안전 위험 및 과제 중 하나는 모든 장치를 관리하고 경계를 폐쇠하는 것입니다.</p>
<p>그러나 악성 장치나 위조된 악성 IoT 장치는 인증업이 안전한 네트워크에 접근 합니다. 악성 장치는 원래 장치를 그룹 구성원으로 대체하거나 통합하여 민감한 정보를 수집하거나 변경합니다. 이러한 장치는 네트워크 경계를 무너뜨립니다.</p>
<p>장치 관리는 다른 IT 자산광리의 </p>
<h4 id="9-안전하지-않은-기본-설정insecure-settings-by-default">9. 안전하지 않은 기본 설정(Insecure Settings by Default)</h4>
<p>&quot;안전하지 않은 기본 설정으로 제공되는 장치나 시스템은 운영자가 구성을 수정하는 것을 제한함으로써 시스템을 보다 안전하게 만들 수 있는 기능이 부족합니다.&quot;</p>
<p>장치 온보드는 제한된 IoT 생태계에 새로운 장치가 추가될 때 발생합니다. 새로운 장치의 온보드 단계에서 도청이 발생할 수 있으며, 여기서 해커는 제한된 네트워크 내에서 통신을 설정하는 데 사용되는 비밀 키를 가로챌 수 있습니다.</p>
<p>해커들은 IoT 기기의 가장 깊은 계층인 물리적 마더보드에서 시작할 수 있습니다. JTAG UART, I2C, SPI와 같은 하드웨어 디버그 포트 또는 통신 포트는 거기에서 찾을 수 있습니다. 거기에서, 그들은 하드 코드화된 비밀번호, 숨겨진 뒷문, 그리고 그들의 버림받은 펌웨어의 취약점들을 검색할 수 있습니다.</p>
<p>장치에 응용 프로그램을 설정하려면 필요한 권한을 검토하고 이 응용 프로그램에 대한 액세스를 제한합니다. 설정, 자격 증명, 펌웨어 버전 및 최근 패치를 기록해야 합니다. 이 단계는 사용자가 어떤 보안 조치를 취해야 하는지 평가하고 어떤 장치를 교체하거나 업데이트해야 하는지 식별하는 데 도움이 될 수 있습니다.</p>
<p>방화벽 라우터 활성화, WPS 비활성화, WPA2 보안 프로토콜 활성화, 강력한 Wi-Fi 암호 사용 등이 바로 이러한 방식들 중 일부입니다. 또한 라우터에 VPN(Virtual Private Networking)을 설치하여 ISP를 통한 모든 트래픽을 암호화할 수 있습니다.</p>
<h4 id="10-물리적-보안의-부족lack-of-physical-hardening">10. 물리적 보안의 부족(Lack of Physical Hardening)</h4>
<p>&quot;물리적 보안 조치가 부족하여 잠재적인 공격자가 향후 원격 공격에 도움이 될 수 있는 민감한 정보를 얻거나 장치를 로컬로 제어할 수 있습니다.&quot;</p>
<p>IoT 컴퓨팅은 어디에나 있기 때문에 장치는 일반적으로 안전한 위치에 유지되지 않고 작업을 수행하기 위해 현장에 노출되어야 합니다. 감시가 없으면 악의적인 행위자가 장치를 조작하거나 액세스할 수 있습니다.</p>
<p>특히, IoT 기기들은 위협에 대응하기 위한 필수적인 내장 보안이 부족하기 때문에 취약합니다. 우리의 전화, 노트북, 개인용 컴퓨터와 달리, 많은 IoT 기기들은 무인으로 작동하기 때문에, 범죄자들이 기기를 조작하고 탐지되지 않는 것을 더 쉽게 만듭니다.</p>
<p>보안 프로토콜은 네트워크를 통해 전송되는 동안에는 데이터를 보호하지만 장치에 저장되는 동안에는 데이터를 보호하지 않습니다. 도난당하거나 폐기된 장비에서 복구된 데이터로 인해 대규모 데이터 침해가 발생했습니다.</p>
<p>암호화가 부족하면 해커는 각 장치의 파일 시스템을 변경할 수 있습니다. 엔지니어는 장치에 중요한 데이터가 저장되어 있어야 합니다.</p>
<p>UART(Universal Asynchronous Receiver Transmitter)에 무제한으로 액세스할 수 있는 소비자 및 산업용 제어 시스템 모두에 상당한 하드웨어 취약성이 있으며 이를 통해 장치 부팅 시퀀스를 변경할 수 있습니다. 해커는 부팅 시퀀스를 수정하여 장치에 대한 낮은 수준의 액세스를 얻고 로그인 정보를 추출할 수 있습니다.</p>
<p>단일 공격자가 시스템의 IT 요소와 OT 요소가 서로 상호 작용하는 것을 막을 수 있습니다. 물리 계층의 방해 및 변조는 센서가 화재, 홍수 및 예기치 않은 움직임과 같은 위험을 감지하지 못하게 할 수 있습니다.</p>
<p>하드웨어가 조작, 물리적 액세스, 조작 및 방해로부터 안전한지 확인합니다.</p>
<p>강력한 IoT 하드웨어 보안을 달성하는 한 가지 방법은 신뢰할 수 있는 플랫폼 모듈(TPM)과 신뢰할 수 있는 실행 환경(TEE)에 키를 저장하는 것입니다. TPM은 본질적으로 CPU 근처의 IoT 장치에 설치된 칩입니다. 보안 키를 생성하고 저장하고 데이터를 저장하는 암호화 작업 및 기타 관련 작업에 주로 사용됩니다. 디스크 암호화 및 암호 보호 플랫폼의 무결성을 보장할 수 있습니다.</p>
<p>2018년 이후 업데이트 되지 않는거같습니다. ㅠㅜ</p>
<hr>
<h3 id="참조-사이트">참조 사이트</h3>
<ul>
<li><a href="https://wiki.owasp.org/index.php/OWASP_Internet_of_Things_Project#tab=Main">OWASP IOT TOP10 2018</a></li>
<li><a href="https://www.keyfactor.com/blog/top-10-iot-vulnerabilities-in-your-devices/">Keyfactor에서 OWASP IOT TOP10 설명</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ARM 어셈블리어]]></title>
            <link>https://velog.io/@ohwy0723-/8l12tmed</link>
            <guid>https://velog.io/@ohwy0723-/8l12tmed</guid>
            <pubDate>Fri, 10 Nov 2023 07:11:45 GMT</pubDate>
            <description><![CDATA[<h1 id="arm">ARM</h1>
<ul>
<li>임베디드 기기에 주로 사용되는 RISC 프로세서</li>
<li>저전력을 사용하도록 설계됨 → 모바일 기기 또는 IoT 디바이스에 사용됨</li>
</ul>
<h2 id="모드">모드</h2>
<ul>
<li><p>Thumb 모드</p>
<p>  레지스터 : R0 ~ R7 (8개)</p>
<p>  기계어 코드 길이 : 16bit(2byte)</p>
</li>
<li><p>ARM 모드</p>
<p>  레지스터 : R0 ~ R15 (16개)</p>
<p>  기계어 코드 길이 : 32bit(4byte)</p>
</li>
</ul>
<p>Thumb ↔ ARM 전환 : BLX/BX등 X로 끝나는 분기문 명령으로 모드를 전환한다.</p>
<h2 id="레지스터">레지스터</h2>
<ul>
<li>R0 ~ R12 : 범용 레지스터, 인자값 및 임시 계산 저장소 등<ul>
<li>R0 : 함수 리턴값 저장</li>
<li>R0 ~ R3 : 함수 호출 인자 전달</li>
<li>R4 ~ R11 : 지역변수 저장</li>
</ul>
</li>
<li>R13 ~ R15 : 특수 레지스터<ul>
<li>R13(SP) : Stack Pointer 스택의 맨 위</li>
<li>R14(LR) : Link Register, 함수 호출 전 LR에 리턴 주소 저장</li>
<li>R15(PC) : 다음 실행할 코드의 주소 저장, x86의 EIP 레지스터와 동일한 역할</li>
</ul>
</li>
<li>CPSR : 현재 프로그램 상태 레지스터</li>
<li>SPSR : CPSR값을 저장해두는 레지스터(CPSR 백업용)</li>
</ul>
<p>ARM 아키텍처의 버전에 따라 레지스터의 개수는 다를 수 있다.  ARMv8의 레지스터는 범용레지스터가 16개이고 총 레지스터 갯수는 30개가 넘는다.</p>
<h2 id="함수-호출-규약">함수 호출 규약</h2>
<p>R0 ~ R3 : 인자 및 반환 값을 저장하기 위한 Register로 사용된다.</p>
<p>그러나 인자의 수가 4개 이상인 경우 stack을 통해 인자를 전달한다.</p>
<h2 id="명령어">명령어</h2>
<h3 id="op-codecond-rd-rs-rm"><strong>OP Code<cond> Rd, Rs, Rm</strong></h3>
<ul>
<li>OP Code : push, add, sub, mov 등 어셈블리 명령어</li>
<li>Rd : Register Direction, 반드시 R0~R15인 Register만 가능하며 연산작업의 결과값을 저장하는 레지스터</li>
<li>Rs : Register Source, 연산을 위해 사용되는 첫 번째 레지스터, 반드시 R0~R15인 Register만 가능</li>
<li>Rm : Op2, 레지스터뿐만 아니라 상수(#), 주소([]), 쉬프트 연산식 등 다양한 값이 사용가능.</li>
</ul>
<h3 id="1-1-산술연산"><strong>1-1) 산술연산</strong></h3>
<ul>
<li><strong>ADD(Addition)</strong><ul>
<li>ADD Rd Rs Rm → Rd = Rs + Rm</li>
</ul>
</li>
<li><strong>ADC(Addition with Carry)</strong><ul>
<li>ADC Rd Rs Rm → Rd = Rs + Rm + carry</li>
</ul>
</li>
<li><strong>SUB(Subtraction)</strong><ul>
<li>SUB Rd Rs Rm → Rd = Rs - Rm</li>
</ul>
</li>
<li><strong>SBC(Subtraction with Carry)</strong><ul>
<li>SBC Rd Rs Rm → Rd = Rs - Rm - !carry</li>
</ul>
</li>
<li><strong>RSB(Reverse Subtraction)</strong><ul>
<li>RSB Rd Rs Rm → Rd = Rs- Rs</li>
</ul>
</li>
<li><strong>RSC(Reverse Subtraction with Carry)</strong><ul>
<li>RSC Rd Rs Rm → Rd = Rm - Rs - !carry</li>
</ul>
</li>
</ul>
<h3 id="1-2-논리-연산"><strong>1-2) 논리 연산</strong></h3>
<ul>
<li><strong>AND(Logical AND)</strong><ul>
<li>AND Rd Rs Rm → Rd = Rs AND Rm</li>
</ul>
</li>
<li><strong>ORR(Logical OR)</strong><ul>
<li>ORR Rd Rs Rm → Rd  = Rs OR Rm</li>
</ul>
</li>
<li><strong>EOR(Logical XOR)</strong><ul>
<li>EOR Rd Rs Rm → Rd = Rs XOR Rm</li>
</ul>
</li>
<li><strong>BIC(Bit Clear)</strong><ul>
<li>BIC Rd Rs Rm → Rd = Rs AND (!Rm)</li>
</ul>
</li>
</ul>
<h3 id="1-4-시프트-연산"><strong>1-4) 시프트 연산</strong></h3>
<ul>
<li><strong>LSL(Logical Shift Left)</strong><ul>
<li>LSL #n : 최후에 밀려난 비트가 CPSR의 C-flag에 저장<ul>
<li><code>LSL</code> : <code>signed/unsigned</code> 곱하기 2</li>
</ul>
</li>
</ul>
</li>
<li><strong>LSR(Logical Shift Right)</strong><ul>
<li>LSR #n : 최후에 밀려 비트가 CPSR의 C-flag에 저장<ul>
<li><code>LSR</code> : <code>unsigned</code> 나누기 2</li>
</ul>
</li>
</ul>
</li>
<li><strong>ASR</strong><ul>
<li>ASR #n : MSB를 유지하고, 밀려난 비트가 CPSR의 C-flag에 저장<ul>
<li><code>ASR</code>은 <code>signed int</code>의 나누기 2 동작을 수행합니다.</li>
</ul>
</li>
<li>레지스터를 우측으로 지정한 비트 수 만큼 <strong>부호를 유지하며</strong> Shift합니다.</li>
</ul>
</li>
</ul>
<h3 id="1-4-register-값-저장"><strong>1-4) Register 값 저장</strong></h3>
<ul>
<li><strong>MOV(Move)</strong><ul>
<li>MOV Rd Rs → Rd = Rs</li>
</ul>
</li>
<li><strong>MVN(Move Negative)</strong><ul>
<li>MVN Rd Rs → Rd = !Rs</li>
</ul>
</li>
</ul>
<h3 id="1-5-비교-연산"><strong>1-5) 비교 연산</strong></h3>
<ul>
<li><strong>CMP(Compare)</strong><ul>
<li>CMP Rs Rm → status = Rs - Rm<ul>
<li>&quot;Rs - Rm&quot;의 결과를 Status flag에 반영</li>
</ul>
</li>
</ul>
</li>
<li><strong>CMN(Compare Negative)</strong><ul>
<li>CMN Rs Rm → status = Rs - ( -Rm) = Rs + Rm<ul>
<li>&quot;Rs + Rm&quot;의 결과를 Status flag에 반영</li>
</ul>
</li>
</ul>
</li>
<li><strong>TST(Test bits)</strong><ul>
<li>TST Rs Rm → Status = Rs AND Rm<ul>
<li>&quot;Rs AND Rm&quot;의 결과를 Status flag에 반영</li>
</ul>
</li>
</ul>
</li>
<li><strong>TEQ(Test Equivalence)</strong><ul>
<li>TEQ Rs Rm → Status = Rs XOR Rm<ul>
<li>&quot;Rs XOR Rm&quot;의 결과를 Status flag에 반영</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="1-6-분기-명령어">1-6) 분기 명령어</h3>
<ul>
<li><strong>B(Branch)</strong><ul>
<li>B Rd<ul>
<li>B add : Global Label</li>
<li>B 1f : Local Lable</li>
<li>B . : 무한루프(‘ . ’ = 제자리)</li>
</ul>
</li>
<li>뒤에 지정된 주소값으로 분기</li>
</ul>
</li>
<li><strong>BL(Branch with Link)</strong><ul>
<li>BL Rd</li>
<li>뒤에 지정된 주소값으로 분기하면서 현재 R15(PC) + 0x2 번지의 주소값을 R14에 저장</li>
</ul>
</li>
</ul>
<p>B와 BL은 분기 주소로 레지스터를 사용할 수 없다.</p>
<ul>
<li><strong>BX(Branch indirect)</strong><ul>
<li>BX R</li>
<li>뒤에 지정된 레지스터 값으로 분기</li>
</ul>
</li>
<li><strong>BLX(Branch indirect with Link)</strong><ul>
<li>BLX R</li>
<li>뒤에 지정된 레지스터 값으로 분기하면서 현재 R15(PC) + 0x2 번지의 주소 값을 R14에 저장</li>
</ul>
</li>
</ul>
<h3 id="1-7-메모리-접근-명령어">1-7) <strong>메모리 접근 명령어</strong></h3>
<ul>
<li><strong>LDR(Load) : 메모리 → 레지스터(Load to Register)</strong><ul>
<li>ldr Rd, [Rs] : Rs의 값을 주소로 참조하여 Rd에 저장</li>
<li>ldr Rd, [Rs], #4 : Rs의 값을 주소로 참조하여 Rd에 저장하고 Rs에 4를 더함</li>
<li>ldr Rs , =Value : Rs레지스터에 상수값(최대 4byte) 저장</li>
</ul>
</li>
<li><strong>STR(Store) : 레지스터 → 메모리(Store to Memory)</strong><ul>
<li>ex)<ul>
<li>str Rd, [Rs] : Rd의 값을 Rs의 값을 주소로 참조하여 저장</li>
<li>str Rd, [Rs], #4 : Rd의 값을 Rs의 값을 주소로 참조하여 저장하고 Rs에 4를 더함</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="상태-플래그"><strong>상태 플래그</strong></h2>
<ul>
<li>N : 연산 결과가 음의 값을 가질 경우 → Set 1</li>
<li>Z : 연산 결과가 Zero인 경우 → Set 1</li>
<li>C : 연산 결과가 Carry를 가질 경우 → Set 1</li>
<li>V : 연산 결과 Overflow가 발생한 경우 → Set 1
<img src="https://velog.velcdn.com/images/ohwy0723-/post/9b2b83e1-d66a-4cbf-aeed-358da66d03af/image.png" alt=""></li>
</ul>
<hr>
<h3 id="링크">링크</h3>
<ul>
<li><a href="https://heyrick.eu/assembler/qfinder.html">ARM 명령어 모음</a></li>
<li><a href="https://0xsaika.tistory.com/5">ARM assembly 문법정리</a> - <a href="https://0xsaika.tistory.com/">Saika Dev</a></li>
<li><a href="https://kyuhyuk.kr/article/simple-arm-operating-system/2019/03/04/Simple-ARM-Operating-System-Chapter-2">ARM Assembly 기초</a> - <a href="https://kyuhyuk.kr/">kyuhyuk blog</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[임베디드는 컴퓨터랑 뭐가 달라요?]]></title>
            <link>https://velog.io/@ohwy0723-/%EC%9E%84%EB%B2%A0%EB%94%94%EB%93%9C%EB%8A%94-%EC%BB%B4%ED%93%A8%ED%84%B0%EB%9E%91-%EB%AD%90%EA%B0%80-%EB%8B%AC%EB%9D%BC%EC%9A%94</link>
            <guid>https://velog.io/@ohwy0723-/%EC%9E%84%EB%B2%A0%EB%94%94%EB%93%9C%EB%8A%94-%EC%BB%B4%ED%93%A8%ED%84%B0%EB%9E%91-%EB%AD%90%EA%B0%80-%EB%8B%AC%EB%9D%BC%EC%9A%94</guid>
            <pubDate>Tue, 07 Nov 2023 08:53:10 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<p>임베디드는 영어로 &quot;장착하다.&quot;, &quot;끼워넣다.&quot;라는 뜻을 가집니다. 기기 내부에 장착되어있는 소규모의 시스템이라고 생각하면 됩니다. </p>
<p>임베디드 시스템은 사람의 간섭없이 독자적으로 기능을 수행하는 시스템으로 하드웨어랑 소프트웨어를 통틀어서 부릅니다. 보통 특정 기능만을 수행합니다. 그에 반대로 개인용 컴퓨터처럼 특정되지 않은 일반적인 목적을 수행하는 시스템을 &quot;범용 시스템&quot;이라고 합니다. 특정한 목적을 가지고 있느냐 아니냐에 따라 구분됩니다. </p>
<p>임베디드 시스템에는 보통 운영 체제(윈도우 , 리눅스 커널)가 포함되며 이 운영체제 위에 특수한 기능만을 수행하도록 응용프로그램이 장착되어 동작하도록 합니다. </p>
<p>제일 널리 쓰이고 많이 쓰이는 임베디드 기기는 스마트폰, USB, 게임기, 라우터 등이 있습니다.
실제로 내가 사용하는 닌텐도 스위치나 구글 홈 미니, 로지텍 g pro, wh-1000xm5등을 임베디드 기기라고 부를수 있다.</p>
<h2 id="특징">특징</h2>
<p>임베디드는 보통 저가의 제품으로 선택된 기능만을 수행하도록 설계되어 있습니다. 몇몇 기능은 매우 빨리 처리해야하며, 다른 기능들은 대부분 속도를 중요하게 여기지 않는 경우가 많다.
그래서 개인 컴퓨터등, 범용 컴퓨터 시스템의 하드웨어에 비해 의도적으로 단순화되어 있어 성능이 낮다. </p>
<p>하드웨어 장치의 롬이나 플래시 메모리에 내장하는 소프트웨어를 <code>펌웨어</code>라고 한다. </p>
<p>임베디드 시스템은 여러해에 이르는 오랜기간동안 오류없이 안정적으로 돌아가도록 설계됩니다. 따라서 펌웨어는 오랜기간동안 신중한 개발과 테스트 과정을 거친다. 또한 물리적으로 손상을 입을수 있는 드라이브나, 버튼, 스위치등 기계적인 동작으로 손상을 입을수 있는 부품의 사용을 피하고 플래시 메모리와 , 롬 같은 비교적 자유로운 칩 자재를 사용합니다.</p>
<h2 id="펌웨어firmware">펌웨어(Firmware)</h2>
<p>Firmware의 기원으로 옛날에는 펌웨어가 ROM에 저장되어 데이터의 수정이 불가능하여, 초기에 데이터를 저장하면 데이터가 변경이되는일이 없었습니다. 그래서 단단한, 고정된 뜻의 firm과 제품, 상품이란 뜻의 ware를 합쳐서 변경되지않는 제품이란 뜻의 Firmware가 되었습니다. </p>
<p>하지만 이제는 전원이 꺼진후에도 저장데이터의 내용이 지워지지 않는 EPRROM이나 플래시 메모리같이 비휘발성 메모리가 개발되면서 펌웨어의 수정(업데이트)가 가능해졌습니다.</p>
<p>또한 펌웨어는 특정 하드웨어 장치에 포함된 소프트 웨어로, 기능적으로 소프트웨어와 가깝지만 사용자가 쉽게 내용을 바꿀수 없는 하드웨어적 특성도 가지고 있다. </p>
<h3 id="펌웨어-획득">펌웨어 획득</h3>
<p>펌웨어는 비휘발성 메모리에 저장된 데이터이다. 임베디드 기기에서 사용되는 비 휘발성 메모리는 플래시 메모리라 플래시 메모리의 데이터를 구하면 펌웨어를 얻을수 있다. 펌웨어는 주로 바이너리 형식으로 이루어져있습니다.</p>
<p>방법은 두가지가 존재하는데 직접 임베디드 기기의 플래시 메모리에서 추출하는 방식이 있고, 제품  홈페이지의 자료실에 펌웨어가 올라와있는경우다. 국내 iptime 회사는 자사 모든기기의 펌웨어를 온라인 홈페이지에서 구할수 있다. 또한 tp-link라고 중국의 iot기기 회사도 공유기등 여러 제품의 펌웨어를 온라인으로 구할수 있다.</p>
<h3 id="펌웨어-구조">펌웨어 구조</h3>
<h2 id="arm">ARM</h2>
<p>CPU아키텍처로 거의 대부분 ARM 코어를 사용한다.
ARM은 고성능을 많이 사용하며 리눅스 커널을 포팅하여 많이 사용합니다. OS를 탑재하기위해 ARM 칩 외부에 RAM이나 FLASH를 PCB에 장착한다.</p>
<p>참고 자료</p>
<ol>
<li><a href="https://ko.wikipedia.org/wiki/%EC%9E%84%EB%B2%A0%EB%94%94%EB%93%9C_%EC%8B%9C%EC%8A%A4%ED%85%9C">위키</a></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[whs]간단한 화이트 햇 스쿨 1기 합격 이야기]]></title>
            <link>https://velog.io/@ohwy0723-/%EA%B0%84%EB%8B%A8%ED%95%9C-%ED%99%94%EC%9D%B4%ED%8A%B8-%ED%96%87-%EC%8A%A4%EC%BF%A8-1%EA%B8%B0-%ED%95%A9%EA%B2%A9-%EC%9D%B4%EC%95%BC%EA%B8%B0</link>
            <guid>https://velog.io/@ohwy0723-/%EA%B0%84%EB%8B%A8%ED%95%9C-%ED%99%94%EC%9D%B4%ED%8A%B8-%ED%96%87-%EC%8A%A4%EC%BF%A8-1%EA%B8%B0-%ED%95%A9%EA%B2%A9-%EC%9D%B4%EC%95%BC%EA%B8%B0</guid>
            <pubDate>Sat, 09 Sep 2023 14:33:02 GMT</pubDate>
            <description><![CDATA[<h2 id="신청하게된-계기">신청하게된 계기</h2>
<p>현재 4학년인 난 졸업을 기다리며 취업을 준비해야하는 시기이다. 올해 정보처리기사 자격증을 땃지만 회사에서 원할정도로 준비가 되었다고 생각하지는 않았기 때문에 따로 공부를 하거나 부트캠프같은곳을 준비할려했었다. 기존에 BOB를 생각하고있었으나 여건상 학교 막학기를 다녔어야했기 때문에 온라인 과정이 필요했었고 pre-BOB 라는 명목의 화이트 햇 스쿨을 기술정보원에서 하는것을 보고 신청하게되었다. 
온라인과정이라 무조건 붙어야한다고 생각했었다. BOB 가산점도 있다고 했고 ㅎㅎ</p>
<h3 id="준비한것">준비한것</h3>
<p>따로 준비한건 없었던거 같다.
포스터 내용을 보면 알듯이 과정을 아래와 같이 이루어졌다.</p>
<h4 id="1-서류-제출">1. 서류 제출</h4>
<p>서류제출은 나 같은 경우엔 절실하게 썻다. 
나이대로 내가 상한선이고 처음이자 마지막 기회였기에 공부 계획과 자기 소개서를 BOB를 가기전에 열심히 공부하고 싶다. 라고 썻던거 같다.
이 외에도 취약점 분석 경험, 프로젝트 경험, 공모전 수상 이력, 보유 자격증, CTF 경험 등 적을게 많은데 난 적을게 학교에서 진행했던 프로젝트, 보유 자격증, 공모전 정도만 적었었고 서류는 합격했다. </p>
<h4 id="2-서류-합격-발표">2. 서류 합격 발표</h4>
<p>서류 합격 발표를 BOB 사이트에서 확인을 하면 필기 시험과 AI 면접을 봐야된다.</p>
<h4 id="3-인적성-검사">3. 인적성 검사</h4>
<p>인적성 검사는 해봤던 경험을 기반으로 그냥 했다. 
애초에 난 이런거 재밌어해가지고 재밌게 했다ㅋㅋ</p>
<h4 id="4-필기-시험">4. 필기 시험</h4>
<p>50문제를 30분안에 풀어야된다. 4지 선다형인데 기억나는게 AWS와 어셈블리어, 암호학, 신기술 등 IT분야와 보안분야 전체적으로 다양하게 나왔는데 수준은 좀 있었다. 1기는 온라인으로 보았는데 원래는 오프라인이었는데 계획이 변경되었던거같다.</p>
<p>처음이었다 보니 일이 많았다. 사람이 몰려서 그런지 렉걸려서 문제 선택도 안됬었고 몇명은 시험 자체를 못봤던거 같다. 그래서 일주일 후 재시험이 열렸었다 ㅋㅋ</p>
<h4 id="5-ai-면접">5. AI 면접</h4>
<p>이거 또한 온라인이었다.
몬스터 AI면접이라고 카메라 보고 면접 질문 주어지고 카메라 보고 대답을 하는거였는데 인터넷에 정보가 많이 없다보니 좀 쫄았었는데 막상 해보니 질문이 막 어렵진 않았고 화이트 햇 스쿨을 어떤 마음가짐으로 하고싶은지를 잘 생각하고 보면 될거같다.</p>
<h4 id="6-최종-합격-발표">6. 최종 합격 발표</h4>
<p>무사히 최종합격 발표가 났고 다행히 합격을 했다.</p>
<p>아쉽게도 오티는 참석 못 했지만 온라인으로 참석을 했고 여러 유명인사가 온것을 볼 수 도 있었다.</p>
<h3 id="공부-일정">공부 일정</h3>
<blockquote>
<p>2달(9<del>10월)     온라인 기초 교육
2달(11</del>12월)    팀 프로젝트
2달(1~2월)     심화 교육</p>
</blockquote>
<p>이렇게 커리큘럼이 짜여있다. </p>
<p>현재 1주차가 지났고 공부하는 내용을 보면 정보처리기사 수준의 강의이다. 화이트 햇 스쿨은 어린 친구들 부터 지금의 대학교 4학년 까지 많은 나이대가 있다고 봤다.</p>
<p>어린 친구는 중2까지 있다고 봤다. (나랑 10살차이....🤣)</p>
<p>보통 대학교 2~3학년이 많은거같으니까 여러 친구들이 지원해서 해봤으면 좋을거같다. </p>
<p>내가 제일 추천하는 방식은 3학년때 화이트 햇 스쿨 교육을 듣고 4학년때에 BOB를 듣는게 좋을거같다.</p>
<p>궁금하신점은 댓글 남겨주시면 성심성의것 대답하겠습니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스택 버퍼 오버플로우(Stack Buffer Overflow)]]></title>
            <link>https://velog.io/@ohwy0723-/%EC%8A%A4%ED%83%9D-%EB%B2%84%ED%8D%BC-%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C%EC%9A%B0Stack-Buffer-Overflow</link>
            <guid>https://velog.io/@ohwy0723-/%EC%8A%A4%ED%83%9D-%EB%B2%84%ED%8D%BC-%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C%EC%9A%B0Stack-Buffer-Overflow</guid>
            <pubDate>Sat, 09 Sep 2023 13:49:34 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>스택 버퍼 오버플로우는 보안을 공부하지 않은 개발자들도 알만큼 유명하고 역사가 오래된 취약점이다. </p>
<blockquote>
<p>스택 오버플로우와 스택 버퍼 오버플로우의 차이점</p>
</blockquote>
<pre><code>스택영역은 실행중에 크기가 동적으로 확장될수 있다. 
그러나 한정된 크기의 메모리 안에서 스택이 무한히 확장될 수는 없다. 
스택 오버 플로우는 스택영역이 너무 많이 확장돼서 발생하는 버그를 뜻한다.
반면,
스택 버퍼 오버플로우는 스택에 위치한 버퍼에 버퍼의 크기보다 많은 데이터가 입력되어 발생하는 버그를 뜻한다.</code></pre><h3 id="스택-버퍼-오버플로우">스택 버퍼 오버플로우</h3>
<p>스택의 버퍼에서 발생하는 오버 플로우를 뜻한다. 이를 이해하기 위해서는 먼저 버퍼와 오버플로우의 개념을 알아야한다.</p>
<h4 id="버퍼">버퍼</h4>
<p>버퍼는 일상에서 완충장치라는 뜻으로 사용되며, 컴퓨터 과학에서는 &#39;데이터가 목적지로 이동되기 전에 보관되는 임시 저장소&#39;의 의미로 쓰인다.</p>
<p>데이터의 처리속도가 다른 두 장치가 있을 때, 이 둘 사이에 오가는 데이터를 임시로 저장해 두는 것은 일종의 완충 작용을 한다. 수신과 송신측에 사이에 버퍼라는 임시 저장소를 두고, 이를 통해 간접적으로 데이터를 전달하게 한다. 송신 측은 버퍼로 데이터를 전송하고, 수신 측은 버퍼에서 데이터를 꺼내 사용한다. 이렇게하면 버퍼가 가득 찰 때까지는 유실되는 데이터 없이 통신할 수 없다. 빠른 속도로 이동하던 데이터가 안정적으로 목적지에 도달할 수 있도록 완축 작용을 하는 것이 버퍼의 역할이라 할 수 있다.</p>
<p>현대에서는 이런 완충의 의미가 많이 희석되어 데이터가 저장될 수 있는 모든 단위를 버퍼라고 부르기도 한다. 스택에 있는 지역변수는&#39;스택 버퍼&#39;, 힙에 할당된 메모리 영역은 &#39;힙 버퍼&#39; 라고 불린다.</p>
<blockquote>
<p>버퍼링</p>
</blockquote>
<pre><code>버퍼에서 유래된 단어로, 송신 측의 전송 속도가 느려서  수신 측의 버퍼가 채워질 떄까지 대기하는 것을 의미한다.</code></pre><h4 id="버퍼-오버플로우">버퍼 오버플로우</h4>
<p>버퍼 오버플로우는 문자 그대로 버퍼가 넘치는 것을 의미한다. 버펀는 제각기 크기를 가지고 있는데, int로 선언한 지역변수는 4바이트의 크기를 갖고. 10개의 원소를 갖는 char 배열은 10바이트의 크기를 갖는다. 만약 10바이트 크기의 버퍼에 20바이트 크기의 데이터가 들어가려 하면 오버플로우가 발생한다. </p>
<p>일반적으로 버퍼는 메모리상에 연속해서 할당되어 있으므로, 어떤 버퍼에서 오버플로우가 발행하면, 뒤에 있는 버퍼등릐 값이 조작될 위험이 있다.</p>
<p>버퍼오버플로우는 일반적으로 어떤 메모리 영역에서 발생해도 큰 보안 위협으로 이어진다. </p>
<h4 id="중요-데이터-변조">중요 데이터 변조</h4>
<p>버퍼 오버 플로우가 발행하는 버퍼 뒤에 중요한 데이터가 있다면, 해당 데이터가 변조됨으로써 문제가 발생할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[RELRO]]></title>
            <link>https://velog.io/@ohwy0723-/RELRO</link>
            <guid>https://velog.io/@ohwy0723-/RELRO</guid>
            <pubDate>Sat, 09 Sep 2023 13:48:51 GMT</pubDate>
            <description><![CDATA[<h3 id="relro">RELRO</h3>
<p>이번 회차에서는 RELRO 보호기법을 공부해볼 것이다. </p>
<p>이전에 배웠던 background:Library에서 ELF는 GOT를 활용하여 반복되는 라이브러리 함수의 호출 비용을 줄인다 배웠다. GOT를 채우는 방식은 다양한데, 전에 배운 방법은 처음 호출될때 함수의 주소를 구하고, 이를 GOT에 적는 Lazy Binding기법을 배웠다. </p>
<p>Lazy binding을 하는 바이너리는 실행 중에 GOT 테이블을 업데이트할 수 있어야 하므로 GOT에 쓰기 권한이 부여된다. 그런데 이는 쓰기권한이 있기 때문에 바이너리를 취약하게 만드는 원인이 된다. </p>
<p>리눅스 개발자들은 이러한 문제를 해결하기 위해 프로세스의 데이터 세그먼트를 보호하는 RELocation Read-Only(RELRO)을 개발했다. RELRO는 쓰기 권한이 불 필요한 데이터 세그먼트에 쓰기권한을 제거한다.</p>
<p>RELRO는 적용하는 범위에 따라 두가지로 구분 된다. 하나는 부분적으로 적용하는 Partial RELRO이고, 나머지는 가장 넓은 영역에 RELRO를 적용하는 Full RELRO이다.</p>
<h4 id="relro-확인-및-검사">RELRO 확인 및 검사</h4>
<p>내 환경에서는 gcc는 Full RELRO를 기본 적용하고 PIE를 해제하면 Partial RELRO가 적용된다. checksec로 검사하면 RELRO 여부를 확인할 수 있다.</p>
<h4 id="relro-우회-방법">RELRO 우회 방법</h4>
<p>Partial RELRO는 .int_array와 .fini_array에 대한 쓰기권한이 제거되어 두 영역을 덮어쓰는 공격을 수행하기 어려워진다. 하지만, .got.plt 영역에 대한 쓰기권한이 존재하므로 GOT overwrite 공격을 활용할 수 있다.</p>
<p>Full RELRO의 경우 .init_array, .fini_array 뿐만 아니라 .got 영역에도 쓰기 권한이 제거되어있다. 그래서 공격자들은 덮어쓸 수 있는 다른 함수 포인터를 찾다가 라이브러리에 위치한 hook을 찾아쌘다. 라이브러리 함수의 대표적인 hook이 malloc hook과 free hook이다. 원래 이 함수 포인터는 동적 메모리의 할당과 해제 과정에서 발생하는 버그를 디버깅하기 쉽게 하려고 만들어졌다.</p>
<p><code>malloc</code> 함수의 코드를 살펴보면, 함수의 시작 부분에서 <code>__malloc_hook</code> 이 존재하는지 검사하고, 존재하면 이를 호출한다. <code>__malloc_hook</code>  은 <code>libc.so</code>에서 쓰기 가능한 영역에 위치한다. 따라서 공격자는 libc가 매핑된 주소를 알 때, 이 변수를 조작하고, <code>malloc</code>을 호출하여 실행 흐름을 조작할수있다. 이러한 기법을 hook overwrite라고 부른다.</p>
<blockquote>
</blockquote>
<pre><code class="language-C++">void *
__libc_malloc (size_t bytes)
{
  mstate ar_ptr;
  void *victim;
  void *(*hook) (size_t, const void *)
    = atomic_forced_read (__malloc_hook); // read hook
  if (__builtin_expect (hook != NULL, 0))
    return (*hook)(bytes, RETURN_ADDRESS (0)); // call hook
#if USE_TCACHE
  /* int_free also calls request2size, be careful to not pad twice.  */
  size_t tbytes;
  checked_request2size (bytes, tbytes);
  size_t tc_idx = csize2tidx (tbytes);
  // ...</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[방학 총 정리(22년 여름방학)]]></title>
            <link>https://velog.io/@ohwy0723-/%EB%B0%A9%ED%95%99-%EC%B4%9D-%EC%A0%95%EB%A6%AC22%EB%85%84-%EC%97%AC%EB%A6%84%EB%B0%A9%ED%95%99</link>
            <guid>https://velog.io/@ohwy0723-/%EB%B0%A9%ED%95%99-%EC%B4%9D-%EC%A0%95%EB%A6%AC22%EB%85%84-%EC%97%AC%EB%A6%84%EB%B0%A9%ED%95%99</guid>
            <pubDate>Sat, 09 Sep 2023 13:48:07 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>방학이란 긴 시간동안 교수님이 내신 코드 문제를 풀고 남은 한달을 드림핵에서 시스템 해킹을 나름 열심히 이해하고 내껄로 만들려고 노력했다. </p>
<p>지금부터 정리하는건 이번 한달동안 내머리속에 습득했던것들을 안보고 기억나는대로 설명해볼것이다. </p>
<h3 id="shellcode">shellcode</h3>
<p>리눅스에서 쉘을 통해 명령어를 입력하고 컴퓨터가 프로그램을 실행할수 있게해주는 사용자와 컴퓨터를 연결해주는 인터페이스다.</p>
<p>쉘코드는 우리가 공격하려는 대상의 쉘을 실행시키게 만들어주는 코드이다. 드림핵에서 파이썬을 통해 작성했으며 언어를 조금이라도 해본적있으면 쉽고 빠르게 습득할수있다.</p>
<h3 id="stack-buffer-overflow">Stack Buffer OverFlow</h3>
<p>bof를 이해할려면 스택을 이해해야한다. 내가 이해한것은
<img src="https://velog.velcdn.com/images/ohwy0723/post/11e2e1b4-9ca9-4956-8179-499c5472982d/image.jpg" alt=""></p>
<p>x86기준으로 변수들이 늘어날수록 ebp기준으로 아래로 스택이 확장된다. 여기서 스택 버퍼 오버플로우는 버퍼와 sfp를 임의의 값으로 채우고 ret를 자신이 원하는 흐름으로 바꿔서 공격하는 기법이다. scanf, read, gets, strcpy등 입력받는 크기를 버퍼의 크기보다 크게하거나 제한이 없으면 이 공격을 할수가있다.</p>
<p>이 공격을 막기위해서 scanf_s(버퍼보다 입력받는 크기가 크면 저장을 안함), read(입력받는 크기를 버퍼보다 작게설정), fgets(입력받는 크기를 제한) strncpy 등의 함수들이 개선되어 나왔고, 스택 카나리라는 보호기법이 생겼다.</p>
<h3 id="stack-canary">Stack Canary</h3>
<p>위에서 본 스택은 버퍼와 sfp만 채우면 ret를 원하는 값으로 뒤집어 쓸수있어서 공격하기 쉽다. 하지만 <code>Canary 보호기법</code>을 적용하면 버퍼와 sfp 사이에 함수가 시작될때마다 임의의 값을 삽입하여 함수가 종료될때 Canary에 부여된 임의의 값이 오염됬다고 판단되면 프로그램을 강제종료시키는 보호기법이다. </p>
<blockquote>
<h4 id="디버그로-본">디버그로 본</h4>
<p><img src="https://velog.velcdn.com/images/ohwy0723/post/bda5ae4a-e55d-4e36-8a3a-813ed4ea562f/image.png" alt="">
main 함수 초기에 gs(x86 레지스터)에 생성된 임의의 값을 ebp-8에 넣어주고 eax값을 초기화 시켜주는 부분이다. 카나리를 생성하고 대입한 부분이다.
<img src="https://velog.velcdn.com/images/ohwy0723/post/e3211de3-8736-40b0-abbb-3b62a18a3815/image.png" alt="">
main 함수 끝자락에 ebp-0x8에 넣어줬던 카나리 값을 edx로 꺼내  gs:0x14에 있는 맨처음에 생성된 카나리값을 비교해서 ebp-0x8에 있던 값이 오염됬다고 판단하면 함수의 끝으로가 프로그램을 종료시킨다.</p>
</blockquote>
<p>카나리 보호기법을 우회하기 위해서 우리는 Canary leak라는 방법을 사용하는데 내가 배운 리눅스(아키텍처마다 다를수있다.)에서 Canary는 \x00으로 시작하기 때문에 버퍼보다 한바이트 크게 오버라이트하면 카나리를 알아낼수가있다. 그래서 우리는 한바이트 크게 오버라이트하고 카나리를 알아내서 main으로 리턴해서 알아낸 카나리로 우회해 ret를 덮던가 다음 입력으로 ret를 덮어씌워 공격한다.</p>
<h4 id="bypass-nx-aslr">Bypass NX, ASLR</h4>
<p>먼저 ASLR은 Address Space Layout Randomization의 약자로 main함수를 제외한 라이브러리 함수 주소, 코드 함수 주소, 라이브러리 매핑주소, 스택 주소, 힙 주소등을 파일이 실행할때 마다 랜덤한 주소를 주는 보호기법이다. </p>
<p>NX는 메모리의 쓰기영역과 실행영역을 분리하는 보호기법이다.
공격자가 임의 버퍼에 주입한 코드를 실행하기 어렵게 만든다..NX를 적용하기 전에는 ret를 쉘코드 주소로 덮어서 공격하면 실행이되지만 NX를 설정하면 실행권한이 제한되어서 쉘코드를 이용한 bof 공격은 불가하다.</p>
<p>그래서 생긴게 NX를 우회하는 RTL (Return to Library)이다. 쉘을 획득하는 코드는 system(&quot;/bin/sh&quot;)이다. </p>
<p>&quot;임시저장&quot; (추가 작성 필요)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Return Orinted Programming]]></title>
            <link>https://velog.io/@ohwy0723-/Return-Orinted-Programming</link>
            <guid>https://velog.io/@ohwy0723-/Return-Orinted-Programming</guid>
            <pubDate>Sat, 09 Sep 2023 13:47:04 GMT</pubDate>
            <description><![CDATA[<h3 id="서론">서론</h3>
<p>스택의 반환 주소를 덮는 공격은 스택 카나리, NX, ASLR이 도입되며 점점 어려워졌다. 공격 기법은 셸 코드의 실행에서 라이브러리 함수의 실행으로, 그리고 다수의 리턴 가젯을 연결해서 사용하는 Return Orinted Programming(ROP)로 발전했다.</p>
<p>NX의 도입으로 셸 코드를 사용할 수 없게 된것은 공격자에게 큰 제약이 되었다. 프로그래서가 작성한 코드만 실행해서 셸이 획득될 가능성은 거의 없는데, 임의의 코드를 주입해서 사용할 수도 없어졌으므로 공격자는 새로운 방법을 찾아야했다.</p>
<p>그래서 지난코스 RTL에서 살펴본 것과 같이 <code>pop rdi; ret</code>같은 코드 가젯과 라이브러리의 <code>system</code>함수를 사용하는 공격 기법이 새롭게 등장했다.</p>
<p>지난 코스에서 관련된 실습을 진행했는데, 사실 해당 실습에선 편의를 위해 바이너리의PLT에 <code>system</code>함수를 포함시켰다. 그러나 이제는 많은 개발자가 해당 함수가 공격벡터로 사용될 수 있음을 알고 있으며, 여러 개발 도구들에서도 해당함수의 사용을 지양하도록 경고하고 있다. 그러므로 실제 바이너리에서 <code>system</code>함수가 PLT에 포함될 가능성은 거의 없다.</p>
<p>따라서, 현실적으로 ASLR이 걸린 환경에서 <code>system</code>함수를 사용하려면 프로세스에서 libc가 매핑된 주소를 찾고, 그 주소로부터 <code>system</code>함수의 오프셋을 이용하여 함수의 주소를 계산해야 한다. ROP는 이런 복잡한 제약사항을 유연하게 해결할 수 있는 수단을 제공한다. </p>
<h3 id="rop">ROP</h3>
<p>ROP는 리턴 가젯을 사용하여 복잡한 실행 흐름을 구현하는 기법이다. 공격자는 이를 이용해서 문제 상황에 맞춰 return to library, return to dl-resolve, GOT overwrite 등의 페이로드를 구성할 수 있다. 지난 코스에서 <code>pop rdi; ret</code>를 사용하여 <code>system(&quot;/bin/sh&quot;)</code>을 호출한 것도 ROP를 이용하여 return to library를 구현한 예다.</p>
<p>ROP 페이로드는 리턴 가젯으로 구성되는데, ret단위로 여러 코드가 연쇄적으로 실행되는 모습에서 ROP chain이라고 불린다.</p>
<h3 id="익스플로잇-설계">익스플로잇 설계</h3>
<ol>
<li><p>카나리 우회
이 전과 같다.</p>
</li>
<li><p>system 함수의 주소 계산
<code>system</code>함수는 libc.so.6에 정의 되어 있으며, 해당 라이브러리에는 이 바이너리가 호출하는<code>read</code>,<code>puts</code>,<code>printf</code>도 정의 되어 있다. 라이브러리 파일은 메모리에 매핑될 때 전체가 매핑되므로, 다른 함수들과 함께 <strong><code>system</code>함수도 프로세스 메모리에 같이 적재된다.</strong></p>
</li>
</ol>
<p>바이너리가 system 함수를 직접 호출하지 않아서 <code>system</code> 함수가 GOT에는 등록되지 않는다. 그러나 <code>read</code>, <code>puts</code>, <code>printf</code>는 GOT에 등록되어 있다. <code>main</code>g함수에서 반환 될 때는 이 함수들을 모두 호출한 이후이므로, 이들의 GOT를 읽을수 있다면 libc.so.6가 매핑된 영역으리 주소를 구할수 있다.</p>
<p>libc에는 여러 버전이 있는데 같은 libc안에서 두 데이터 사이의 거리(Offset)는 항상 같다. 그러므로 사용하는 libc의 버전을 알 때, libc가 매핑된 영역의 임의 주소를 구할 수 있으면 다른데이터의 주소를 모두 계산할 수 있다.</p>
<p>예를 들어, Ubuntu GLIBC 2.27-3ubuntu1.2에서 <code>read</code> 함수와 <code>system</code> 함수 사이의 거리는 항상 <code>0xc0ca0</code>입니다. 따라서 <code>read</code>함수의 주소를 알 때, <code>system=read-0xc0ca0</code>으로 <code>system</code> 함수의 주소를 구할 수 있습니다.</p>
<p>rop.c에서는 <code>read</code>, <code>puts</code>, <code>printf</code>가 GOT에 등록되어 있으므로, 하나의 함수를 수정해서 그 함수의 GOT 값을 읽고, 그 함수의 주소와<code>system</code> 함수 사이의 거리를 이용해서 <code>system</code> 함수의 주소를 구할 수 있다.</p>
<ol start="3">
<li><p>&quot;/bin/sh&quot;
이 바이너리는 데이터 영역에&quot;/bin/sh&quot; 문자열이 없다. 따라서 이 문자열을 임의 버퍼에 직접 주입하여 참조하거나, 다른 파일에 포함된 것을 사용해야 한다. 후자의 방법을 선택할 때 많이 사용되는 것이 libc.so.6에 포한된 &quot;/bin/sh&quot; 문자열이다. 이 문자열의 주소도 <code>system</code>함수의 주소를 계산할 때처럼 libc 영역의 임의 주소를 구하고, 그 주소로부터 거리를 더하거나 빼서 계산할 수 있다. 이방법은 주소를 알고 있는 버퍼에 &quot;/bin/sh&quot;를 입력하기 어려울때 차선책으로 사용될 수 있다.</p>
</li>
<li><p>GOT Overwrite
<code>system</code>함수와 &quot;/bin/sh&quot; 문자열의 주소를 알고있으므로, 지난 코스에서 처럼 <code>pop rdi; ret</code> 가젯을 활용하여 system(&quot;/bin/sh&quot;)를 호출할 수 있다. 그러나 <code>system</code>함수의 주소를 알았을 때는 ROP 페이로드가 전송된 이후이므로, 알아낸 <code>system</code>함수의 주소를 페이로드에 사용하려면 main함수로 돌아가서 다시 버퍼 오버플로우를 일으켜야한다. 이러한 공격패턴을 ret2main이라고 부르는데, 이번엔 GOT overwrite 기법을 통해 한번에 획득해본다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Return to Library(RTL)]]></title>
            <link>https://velog.io/@ohwy0723-/Return-to-LibraryRTL</link>
            <guid>https://velog.io/@ohwy0723-/Return-to-LibraryRTL</guid>
            <pubDate>Sat, 09 Sep 2023 13:46:26 GMT</pubDate>
            <description><![CDATA[<h3 id="서론">서론</h3>
<p>여태 공부했던 공격기법과 보호기법을 순서대로 정리해보면 다음과 같다.</p>
<ul>
<li><p>Return Address Overwrite : 반환 주소를 악성함수의 주소로 덮어서 셸 획득</p>
</li>
<li><p>Stack Canary : 스택 프레임의 반환 주소 전에 랜덤한 카나리를 주입하여 반환 주소를 덮기 어렵게 함</p>
</li>
<li><p>Return to Shellcode : 카나리를 우회하고, 셸 코드를 주입한 버퍼의 주소로 반환 주소를 덮어서 셸 획득</p>
</li>
<li><p>ASLR : 임의 버퍼의 주소를 알기 어렵게 함</p>
</li>
<li><p>NX : 각 세그먼트에 불필요한 실행권한을 제거함으로써 공격자가 임의 버퍼에 주입한 코드를 실행하기 어렵게함</p>
</li>
</ul>
<p>흐름을 살펴보면 공격 기법과 보호 기법이 서로 어떤 영향을 주고받으며 발전해왔을지 알 수 있다. 또한, 한편으론 NX의 등장으로 인해 이를 우회하는 공격 기법이 다시금 등장 했을 것이라 예상할 수 있다. 실제로 NX가 리눅스에 도입된 2004년 전후로 이를 우회하는 공격 기법이 여러 컨퍼런스에 발표됐다.</p>
<p>이번 강의에선 NX를 우회하는 RTL에 대해 공부한다.</p>
<h3 id="return-to-library">Return to Library</h3>
<p>NX로 인해 공격자가 버퍼에 주입한 셸 코드를 실행하기는 어렵지만, 스택 버퍼 오버플로우 취약점으로 반환 주소를 덮는 것은 여전히 가능했다.그래서 공격자들은 실행권한이 남아있는 코드 영역으로 반환 주소를 덮는 공격기법을 고안했다.</p>
<p>프로세스에 실행 권한이 있는 메모리 영역은 일반적으로 <strong>바이너리의 코드 영역</strong>과 <strong>바이너리가 참조하는 라이브러리의 코드 영역</strong>이다.</p>
<p>이 중, 공격ㄱ자들이 주목한 것은 다양한 함수가 구현된 라이브러리였다. 몇몇 라이브러리에는 공격에 유용한 함수들이 구현되어있다. 예를들어, 리눅스에서 C언어로 작성된 프로그램이 참조하는 libc에는 <code>system</code>, <code>execve</code>등 프로세스의 실행과 관련된 함수들이 구현되어 있다.</p>
<p>공격자들은 libc의 함수들로 NX를 우회하고 셸을 획득하는 공격 기법을 개발하였고, 이를 <code>Return to Libc</code>라고 이름 지었다. 다른 라이브러리도 공격에 활용될 수 있으므로 이 공격 기법은 <code>Return to Library</code>라고도 불린다. 유사한 공격 기법으로 Return To PLT가 있는데 이 공격 기법도 라이브러리의 코드를 사용하는것이 핵심이므로, 이 코스는 RTL의 하위 분류로 본다.</p>
<h3 id="코드분석">코드분석</h3>
<h4 id="binsh를-코드-섹션에-추가">&quot;/bin/sh&quot;를 코드 섹션에 추가</h4>
<p>rtl.c의 7번째 줄은 &quot;/bin/sh&quot;를 코드 섹션에 추가하기 위해 작성된 코드이다. ASLR이 적용되도 PIE가 적용되지 않으면 코드 세그먼트와 데이터 세그먼트의 주소는 고정되므로, &quot;/bin/sh&quot;의 주소는 고정되어 있습니다. </p>
<h4 id="system-함수를-plt에-추가">system 함수를 PLT에 추가</h4>
<p>rtl.c의 9번째 줄은 PLT에 <code>system</code>을 추가하기 위해 작성된 코드이다. 지난 코스에서 배웠듯 PLT와 GOT는 라이브러리 함수의 참조를 위해 사용하는 테이블이다. 그 중 PLT에는 함수의 주소가 resolve되지 않았을때, 함수의 주소를 구하고 실행하는코드가 적혀있다. </p>
<p>따라서 PLT에 어떤 라이브러리 함수가 등록되어 있다면, 그 함수의 PLT 엔트리를 실행함으로써 함수를 실행할 수 이싿. ASLR이 걸려 있어도  PIE가 적용되어 있지 않다면 PLT의 주소는 고정되므로, 무작위의 주소에 매핑되는 라이브러리의 베이스 주소를 몰라도 이 방법으로 라이브러리 함수를 실행할 수 있다. 이 공격기법을 <code>Return to PLT</code>라고 부른다.</p>
<p>라이브러리의 베이스 주소를 구하여 ASLR을 우회하는 기법은 다음 코스에서 다루고, 이 코스에서는 PLT를 이용하여 NX를 우회하도록 한다.</p>
<p>ELF의 PLT에는 ELF가 실행되는 라이브러리 함수만 포함된다. 따라서 다음 코드를 작성하면 PLT에 <code>system</code>함수를 추가할 수 있다.</p>
<h3 id="버퍼-오버플로우">버퍼 오버플로우</h3>
<p>rtl.c의 Leak canary부터 Overwrite return address주석까지가 두번의 오버플로우를 통해 스택카나리를 우회하고, 반환 주소를 덮을 수 있도록 작성된 코드이다.</p>
<blockquote>
<p>RTL 실습 코드</p>
</blockquote>
<pre><code class="language-c">//rtl.c
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
const char* binsh = &quot;/bin/sh&quot;;
int main() {
  char buf[0x30];
  setvbuf(stdin, 0, _IONBF, 0);
  setvbuf(stdout, 0, _IONBF, 0);
  // Add system function to plt&#39;s entry
  system(&quot;echo &#39;system@plt&#39;&quot;); //9번째 줄
  // Leak canary
  printf(&quot;[1] Leak Canary\n&quot;);
  printf(&quot;Buf: &quot;);
  read(0, buf, 0x100);
  printf(&quot;Buf: %s\n&quot;, buf);
  // Overwrite return address
  printf(&quot;[2] Overwrite return address\n&quot;);
  printf(&quot;Buf: &quot;);
  read(0, buf, 0x100);
  return 0;
}</code></pre>
<h3 id="익스플로잇-설계">익스플로잇 설계</h3>
<ol>
<li><p>카나리 우회
첫번째 입력에서 적절한 길이의 데이터를 입력하면 카나리를 구할수 있다.</p>
</li>
<li><p>rdi값을 &quot;/bin/sh&quot;의 주소로 설정 및 셸 획득
카나리를 구했으면 이제 두 번째 입력으로 반환 주소를 덮을 수 있다. 그러나NX로 인해 지난코스에서와 같이 buf에 셸코드를 주입하고 이를 실행할 수는 없다.</p>
</li>
</ol>
<p>알고있는정보</p>
<ul>
<li>&quot;/bin/sh&quot;의 주소를 안다.</li>
<li><code>sytstem</code>함수의 PLT 주소를 안다. ==&gt; <code>system</code>함수를 호출할 수 있다.</li>
</ul>
<p>RAO에서<code>system(&quot;/bin/sh&quot;)</code>을 호출하면 셸을 획득할수 있음을 배웠다. x86-64의 호출 규약에 따르면 이는 rdi&quot;/bin/sh&quot;주소인 상태에서 <code>system</code> 함수를 호출한 것과 같다.</p>
<p>이 예제에서는 &quot;/bin/sh&quot;의 주소를 알고, <code>system</code> 함수를 호출할 수 있으므로 &quot;/bin/sh&quot;의 주소를 rdi값으로 설정한다면 <code>system(&quot;/bin/sh&quot;)</code>을 실행할수 있다. 이를 위해선 <code>리턴 가젯</code>을 활용해야한다.</p>
<h3 id="리턴-가젯">리턴 가젯</h3>
<p>리턴 가젯은 다음과 같이 ret로 끝나는 어셈블리 코드 조각을 의미한다.</p>
<blockquote>
<p>0x0000000000400853 : pop rdi ; ret</p>
</blockquote>
<p>이제까지의 코스에서는 어떤 함수의 주소 또는 셸 코드의 주소로 반환 주소를 덮어서 한 번에 셸을 획득했다. 그러나 NX로 인해 셸 코드를 실행할 수 없는 상황에서, 단 한 번의 함수 실행으로 셸을 획득하는 것은 일반적으로 불가능하다</p>
<p>리턴 가젯은 반환 주소를 덮는 공격의 유연성을 높여서 익스플로잇에 필요한 조건을 만족할 수 있도록 돕는다. 예를들어 이 예제에서 rdi의 값을 &quot;/bin/sh&quot;의 주소로 설정하고, system함수를 호출해야한다. 리턴 가젯을 사용하여 반환 주소와 이후의 버퍼를 다음과 같이 덮으면, <code>pop rdi</code>로 <code>rdi</code>를  &quot;/bin/sh&quot;의 주소로 설정하고, 이어지는 <code>ret</code>로 <code>system</code> 함수를 호출 할 수있다. </p>
<blockquote>
</blockquote>
<p>addr of (&quot;pop rdi; ret&quot;)   &lt;= return address
addr of string &quot;/bin/sh&quot;   &lt;= ret + 0x8
addr of &quot;system&quot; plt       &lt;= ret + 0x10</p>
<p>대부분의 함수는 ret로 종료 되므로,함수들도 리턴 가젯으로 사용될 수 있다. </p>
<h4 id="리턴가젯">리턴가젯</h4>
<p>리턴 가젯을 찾는 방법은 다양하지만, 일반적으로 ROPgadget을 사용한다.</p>
<p>명령어<code>sudo apt install python3-ropgadget</code>를 이용해 설치를 완료했고 <code>ROPgadget -v</code>를 이용해 설치가 정상적으로 이뤄졌는지 확인 할수 있다.</p>
<p>다음 명령어로 필요한 가젯을 찾을 수 있다. <code>--re</code>옵션을 사용하면 정규표현식으로 가젯을 필터링할 수 있다. 일반적으로 바이너리에 포함된 가젯의 수가 매우 많으므로 필터링하여 가젯을 찾는걸 추첫한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Library & Link]]></title>
            <link>https://velog.io/@ohwy0723-/Library-Link</link>
            <guid>https://velog.io/@ohwy0723-/Library-Link</guid>
            <pubDate>Sat, 09 Sep 2023 13:45:31 GMT</pubDate>
            <description><![CDATA[<h3 id="라이브러리">라이브러리</h3>
<p>라이브러리는 컴퓨터 시스템에서, 프로그램들이 함수나, 변수를 공유해서 사용할 수 있게 한다. 대개의 프로그램은 서로 공통으로 사용하는 함수들이 많다. 예를 들어, <code>printf</code>, <code>scanf</code>, <code>strlen</code>, <code>memcpy</code>, <code>malloc</code>등은 많은 C프로그래머들이 코드를 작성하면서 사용하는 함수이다.</p>
<p>C언어를 비롯하여 많은 컴파일 언어들은 자주 사용되는 함수들의 정의를 묶어서 하나의 라이브러리 파일로 만들고, 이를 여러 프로그램이 공유해서 사용할 수 있도록 지원하고 있다. 라이브러리를 사용하면 같은 함수를 반복적으로 정의해야 하는 수고를 덜 수 있어 코드 개발의 효율이 높아진다는 장점이 있다.</p>
<p>또한, 각 언어에서 범용적으로 많이 사용되는 함수들은 표준 라이브러리가 제작되어 있어서 개발자들은 쉽게 해당 함수들을 사용할 수 있다. 대표적으로, C의 표준 라이브러리인 <code>libc</code>는 우분투에 기본적으로 탑재된 라이브러리이며, 실습환경에서는 <code>/lib/x86_64-lonux-gnu/libc-2.27.so</code>에 있다.
(왠지 모르겠지만 내 lib에는 python3.10밖에 안보인다.)
처음 코딩을 공부할 때, <code>printf</code>를 정의한 적이 없지만<code>printf(&quot;Hello world!&quot;)</code>라는 예제를 컴파일해서, 실행할 수있는 것은 <code>libc</code>에 이 함수가 이미 정의되어 있기 때문이다.</p>
<h3 id="링크">링크</h3>
<p>링크(Link)는 많은 프로그램 언어에서 컴파일의 마지막 단계로 알려져 있다. 프로그램에서 어떤 라이브러리의 함수를 사용한다면, 호출된 함수와 실제 라이브러리의 함수가 링크 과정에서 연결된다. 
리눅스에서 c소스 코드는 전처리, 컴파일, 어셈블 과정을 거쳐 ELF형식을 갖춘 <code>오브젝트 파일</code>로 번역된다.</p>
<p>오브젝트 파일은 실행 가능한 형식을 갖추고 있지만, 라이브러리 함수들의 정의가 어디 있는지 알지 못하므로 실행은 불가능합니다. 다음 명령어를 실행해보면, puts의 선언이 stdio.h에 있어서 심볼로는 기록되어 있지만, 심볼에 대한 자세한 내용은 하나도 기록되어 있지 않다. 심볼과 관련된 정보들을 찾아서 최종 실행 파일에 기록하는 것이 링크 과정에서 하는 일 중 하나다.</p>
<h3 id="라이브러리와-링크의-종류">라이브러리와 링크의 종류</h3>
<p>라이브러리는 크게 동적 라이브러리와 정적라이브러리로 구분되며, 동적 라이브러리를 링크하는것을 동적링크, 정적 라이브러리를 링크하는 것을 정적 링크라고 부른다.</p>
<h4 id="동적-링크">동적 링크</h4>
<p>프로그램을 사람으로, 라이브러리를 도서관으로 비유했을 때, 동적 링크는 가장 자연스러운 도서관 사용 방법이다. 동적 링크된 바이너리를 실행하면 동적 라이브러리가 프로세스 메모리에 매핑된다. 그리고 실행 중에 라이브러리의 함수를 호출하면 매핑된 라이브러리에서 호출할 함수의 주소를 찾고, 그 함수를 실행한다. 이 과정은 사람이 도서관에 방문해서 원하는 책의 위치를 찾고, 그 책에서 정보를 습득하는 과정과 유사하다.</p>
<h4 id="정적링크">정적링크</h4>
<p>마찬가지의 비유를 했을 때, 정적 링크는 도서관의 모든 책을 암기하는 것과 같다. 정적 링크를 하면 바이너리에 정적 라이브러리의 모든 함수가 포한된다. 따라서 해당 함수를 호출할 때, 라이브러리를 참조하는 것이 아니라, 자신의 함수를 호출하는 것처럼 호출할 수 있다. 라이브러리에서 원하는 함수를 찾지 않아도 되니 탐색의 비용이 절감되는 듯 하지만, 여러 바이너리에서 라이브러리를 사용하면 그 라이브러리의 복제가 여러번 이루어 지게 되므로 용량을 낭비하게 된다.</p>
<h4 id="동적-링크dynamic-link-vs-정적-링크static-link">동적 링크(dynamic link) vs 정적 링크(static link)</h4>
<ol>
<li><p>동적링크가 정적링크보다 더많은 용량을 차지한다.</p>
</li>
<li><p>static에서는 코드를 직접 호출한다.
dynamic에서는 코드의 plt 주소를 호출한다.
이런 차이가 발생하는이유는, 동적 링크된 바이너리는 함수의 주소를 라이브러리에서 &quot;찾아야&quot;하기 때문이다.
(plt는 이과정에서 사용되는 테이블이다)</p>
</li>
</ol>
<h3 id="plt--got">PLT &amp; GOT</h3>
<p>PLT와 GOT는 라이브러리에서 동적 링크된 심볼의 주소를 찾을때 사용하는 테이블이다.</p>
<p>바이너리를 실행되면 ASLR에의해 라이브러리가 임의의 주소에 매핑된다. 이 상태에서 라이브러리 함수를 호출하면, 함수의 이름을 바탕으로 하이브러리에서 심볼들을 탐색하고, 해당 함수의 정의를 발견하면 그 주소로 실행 흐름을 옮기게 된다. 이 전 과정을 통틀어 runtime resolve라고 한다.</p>
<p>그런데 만약 반복적으로 호출되는 함수의 정의를 매번 탐색해야 한다면 비효율적일 것이다. 그래서 ELF는 GOT라는 테이블을 두고, resolve된 함수의 주소를 해당 테이블에 저장한다. 그리고 나중에 다시 해당 함수를 호출하면 저장된 주소를 꺼내서 사용한다.</p>
<h4 id="시스템-해킹의-관점에서-본-plt와-got">시스템 해킹의 관점에서 본 PLT와 GOT</h4>
<p>PLT와 GOT는 동적 링크된바이너리에서 라이브러리 함수의 주소를 찾고, 기록할때 사용되는 중요한 테이블이다. 그런데, 시스템 해커의 관점에서 보면 PLT에서 GOT를 참조하여 실행 흐름을 옮길 때, GOT의 값을 검증하지 않는다는 보안상의 약점이 있다.</p>
<p>따라서 GOT에 저장된 <code>코드@@</code>의 주소를 공격자가 임의로 변경할 수 있으면, 두 번째로 <code>코드@@</code>가 호출될때 공격자가 원하는 코드가 실행되게할 수 있다.</p>
<p>이런 공격기법을 GOT Overwrite라고 부르며, 임의 주소값을 쓸 수 있을때, RCE를 하기 위한 방법으로 사용될 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[NX & ASLR]]></title>
            <link>https://velog.io/@ohwy0723-/NX-ASLR</link>
            <guid>https://velog.io/@ohwy0723-/NX-ASLR</guid>
            <pubDate>Sat, 09 Sep 2023 13:44:50 GMT</pubDate>
            <description><![CDATA[<h3 id="aslr이란">ASLR이란?</h3>
<p><code>Address Space Layout Randomization(ASLR)</code>은 바이너리가 실행될때마다 스택, 힙, 공유 라이브러리등을 임의의 주소에 할당하는 보호 기법이다.</p>
<h4 id="aslr의-특징">ASLR의 특징</h4>
<p>스택, 힙, 라이브러리 함수, 코드영역 함수, 라이브러리 매핑주소들을 보면 특징을 알수있다.</p>
<ul>
<li><p>코드영역의 함수 main을 제외한 다른 영역의 주소들은 실행될때마다 변경된다. 
실행할 때 마다 주소가 변경되기 때문에 바이너리를 실행하기 전에 해당 영역의 주소를 예측할 수 없다.</p>
</li>
<li><p>바이너리를 반복해서 실행해도 라이브러리 함수 주소의 하위 12비트 값은 변경되지 않는다. 
리눅스는 ASLR이 적용됐을 때, 파일을 페이지 단위로 임의 주소에 매핑한다. 따라서 페이지의 크기인 12비트 이하로는 주소가 변경되지 않는다.</p>
</li>
<li><p>라이브러리 매핑주소와 라이브러리 함수 주소의 차이는 항상 같다. ASLR이 적용되면, 라이브러리는 임의 주소에 매핑된다. 그러나 라이브러리 파일을 그대로 매핑하는 것이므로 매핑된 주소로부터 라이브러리의 다른 심볼들 까지의 거리(offset)는 항상 같다</p>
</li>
</ul>
<h3 id="nx란">NX란?</h3>
<p>NO-eXecute(NX)는 실행이되는 메모리 영역과 쓰기에 사용되는 메모리 영역을 분리하는 보호 기법이다. 어떤 메모리 영역에 대해 쓰기 권한과 실행 권한이 함께 있으면 시스템이 취약해지기 쉽다. 예를 들어, 코드 영역에 쓰기 권한이 있으면 공격자는 코드를 수정하여 원하는 코드가 실행되게 할 수 있고, 반대로 스택이나 데이터 영역에 실행권한이 있으면 RTS와 같은 공격을 시도할 수 있다.</p>
<p>CPU가 NX를 지원하면 컴파일러 옵션을 통해 바이너리에 NX를 적용할 수 있으며, NX가 적용된 바이너리는 실행 될 때 각 메모리 영역에 필요한 권한만을 부여받는다. gdb의 vmmap로 NX적용 전후의 메모리 맵을 비교하면, 다음과 같이 NX가 적용된 바이너리에는 코드 영역 외에 실행 권한이 없는것을 확인할 수 있다. 반면, NX가 적용되지 않은 바이너리에는 스택, 힙, 데이터 영역에 실행 권한이 존재하는것을 확인할수 있다.</p>
<h4 id="checksec을-이용한-nx-확인">Checksec을 이용한 NX 확인</h4>
<p>checksec를 이용하면 다음과 같이 바이너리에 NX가 적용됐는지 확인할 수 있다.</p>
<blockquote>
<p>NX의 다양환 명칭</p>
</blockquote>
<pre><code>NX는 인텔에선XD, AMD는 NX, 윈도우는 DEP, ARM에선 XN이라고 칭한다. 
다들 명칭만 다를 뿐 모두 비슷한 보호기법이다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Stack Canary]]></title>
            <link>https://velog.io/@ohwy0723-/Stack-Canary</link>
            <guid>https://velog.io/@ohwy0723-/Stack-Canary</guid>
            <pubDate>Sat, 09 Sep 2023 13:43:38 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>RAO에서 스택의 반환 주소를 조작하여 실행 흐름을 획득하는 공격 기법을 배웠다.  스택 버퍼 오버플로우를 이용한 공격은 매우 강력하면서, 역사가 오래되었기 때문에 관련된 보호 기법도 등장했다. Canary는 스택 버퍼 오버플로우로부터 반환주소를 보호하는 기법이다.</p>
<p>스택 카나리는 함수의 프롤로그에서 스탯 버퍼와 반환주소사이에 임의의 값을 삽입하고, 함수의 에필로그에서 해당값의 변조를 확인하는 보호기법이다. 카나리값의 변조가 확인되면 프로세스가 강제로 종료된다.</p>
<p>스택 버퍼 오버플로우로 반환수로를 덮으려면 반드시 카나리를 먼저 덮어야하므로 카나리값을 모르는 공격자는 반환 주소를 덮을때 카나리 값을 변조하게 된다. 이경우 에필로그에서 변조가 확인되어 공격자는 실행 흐름을 획득하지 못한다.</p>
<h3 id="카나리의-작동-원리">카나리의 작동 원리</h3>
<p>우분투 리눅스에서 gcc는 기본적으로 스택 카나리를 적용하여 컴파일 한다. 컴파일 옵션으로 -fno-stack-protector 옵션을 추가하면 카나리 없이 컴파일할 수 있다. 카나리를 적용해서 컴파일 한것과 안한것을 비교해보면 카나리를 적용해서 컴파일한것에 추가된 코드가 있는데 코드를 보자</p>
<blockquote>
<p>추가된 코드</p>
</blockquote>
<pre><code>mov rax, QWORD PTR fs:0x28
mov QWORD PTR [rbp-0x8], rax
xor eax, eax</code></pre><pre><code>mov rcx, QWORD PTR[rbp-0x8]
xor rcx, QWORD PTR fs:0x28
je  0x6f0 &lt;특정 주소&gt;
call 0x570 &lt;__stack_chk_fail@plt&gt;</code></pre><p>맨처음 rax에 fs:0x28의 데이터를 읽어서 저장한다. 
리눅스는 프로세스가 시작되 때 fs:0x28에 랜덤값을 저장한다. 따라서 rax에 리눅스가 생성한 랜던값이 저장된다. 
rbp-0x8에도 랜덤값이 저장된다.
이 랜덤값이 카나리다. 두번째 문단에서 rbp-8에 저장된 카나리를 rcx에 옮긴다. 그 뒤, rcx를 fs:0x28에 저장된 카나리와 xor을 한다. 두값이 동일하면 연산결과가 0이 되므로 je의 조건을 만족하게되고 main함수가 정상적으로 반환된다. 그러나 두 값이 동일 하지 않다면 __stack_chk_fail이 호출 되면서 강제로 종료 된다.</p>
<blockquote>
<h4 id="fs-세그먼트">fs 세그먼트</h4>
</blockquote>
<pre><code>fs는 세그먼트 레지스터의 일종으로 목적이 정해있지않아 운영체제가 임의로 사용할수있는 레지스터이다. 
리눅스는 fs를 TLS(Thread Local Storages)를 가리키는 포인터로 사용한다. 
간단히 말하면 TLS에 카나리를 비롯하여 프로세스 실행에 필요한 여러 데이터가 저장된다.</code></pre><h3 id="카나리-생성과정">카나리 생성과정</h3>
<p>카나리 값은 프로세스가 시작될 때, TLS에 전역 변수로 저장된거, 각 함수마다 프롤로그와 에필로그에서 이 값을 참조한다.</p>
<h4 id="tls의-주소파악">TLS의 주소파악</h4>
<p>fs는 TLS를 가리키므로 fs의 값을 알면 TLS의 주소를 알수있다. 그러나 fs는 특정 시스템 콜을 사용해야만 조회하거나 설정할 수 있다. gdb에서 다른 레지스터의 값을 출력하듯 info regester fs나 print $fs와 같은 방식으로는 값을 알 수 없다.</p>
<p>그래서 여기서는 fs의 값을 설정할 때 호출되는 arch_prctl(int code, unsigned long addr)시스템 콜에 중단점을 설정하여 fs가 어떤 값으로 설정되는지 조사하겠습니다. 이 시스템 콜을 arch_prctl(ARCH_SET_FS, addr)의 형태로 호출하면 fs의 값은 addr로 설정된다.</p>
<p>gdb에는 특정 이벤트가 발생했을 때, 프로세스를 중지시키는 catch라는 명령어가 있다. 이 명령어로 arch_prctl에 catch point를 설정하고 보면 catchpoint에 도달 했을때 rdi의 값은 arch_set_fs의 상수값이고  rsi의 값은 TLS를 저장할것이고, fs는 이값을 가리키게 될것이다.</p>
<h4 id="카나리-값-설정">카나리 값 설정</h4>
<p>TLS의 주소를 알게 됬으므로 gdb의 watch 명령어로 TLS+0ㅌ28에 값을 쓸때 프로세스를 중단 시켜 TLS+0x28에 카나리가 설정된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[함수 호출 규약(Calling Convention)]]></title>
            <link>https://velog.io/@ohwy0723-/%ED%95%A8%EC%88%98-%ED%98%B8%EC%B6%9C-%EA%B7%9C%EC%95%BDCalling-Convention</link>
            <guid>https://velog.io/@ohwy0723-/%ED%95%A8%EC%88%98-%ED%98%B8%EC%B6%9C-%EA%B7%9C%EC%95%BDCalling-Convention</guid>
            <pubDate>Sat, 09 Sep 2023 13:40:56 GMT</pubDate>
            <description><![CDATA[<h2 id="개요">개요</h2>
<h3 id="함수-호출-규약">함수 호출 규약</h3>
<p>함수 호출 규약은 함수의 호출 및 반환에 대한 약속이다. 한 함수에서 다른 함수를 호출할 떄, 프로그램의 실행 흐름은 다른 함수로 이동한다. 그리고 호출한 함수가 반환하면, 다시 원래 함수로 돌아와서 기존의 실행 흐름을 이어나간다. 그러믈호 함수를 호출할 때는 반환된 이후를 위해 호출자의 상태 및 반환 주소를 저장해야한다. 또한 호출자는 피호출자가 요구하는 인자를 전달해야하며 피호출자의 실행이 종료될 때는 반환값을 전달 받아야 한다.</p>
<p>함수 호출 규약을 적용하는 것은 일반적으로 컴파일러 몫이다. 프로그래머가 고수준 언어로 코드를 작성하면 컴파일러가 호출 규약에 맞게 코드를 컴파일한다. 호출 규약은 여러 가지가 있는데 프로그래서가 코드에 명시하지 않는다면, 컴파일러는 지원하는 호출 규약 중에 CPU의 아키텍처에 적합한 것을 선택합니다.</p>
<p>만약 컴파일러의 도움 없이 어셈블리 코드를 작성하려 하거나, 또는 어셈블리로 작성한 코드를 읽고자 한다면 함수 호출 규약을 알아야 할 필요가 있다.</p>
<h3 id="함수-호출-규약의-종류">함수 호출 규약의 종류</h3>
<p>컴파일러가 지원하는 호출 규약 중, CPU 아키텍처에 적합한 것을 선택한다. 예를 들어 x86(32bit) 아키텍처는 레지스터를 통해 피호출자의 인자를 전달하기에는 레지스터의 수가 적으므로, 스택으로 인자를 전달하는 규약을 사용한다. 반대로 x86-64 아키텍처에서는 레지스터가 많으므로 적은수의 인자는 레지스터만 사용해서 인자를 전달하고 인자가 너무 많을 때만 스택을 사용한다. CPU의 아키텍처가 같아도 컴파일러가 다르면 호출 규약이 다를 수 있다. C언어를 컴파일 할때, 윈도우에서는 MSVC를, 리눅스에서는 GCC를 많이 사용한다. </p>
<p>우리는 리눅스 gcc에서 x86바이너리를 컴파일 할 때 사용하는 cdecl 그리고, x86-64 바이너리를 컴파일할 때 사용하는 SYSTEM V호출 규약에 대해 공부할것이다.</p>
<h2 id="x86-호출-규약--cdecl">x86 호출 규약 : cdecl</h2>
<h3 id="cdecl">cdecl</h3>
<p>x86라키텍처는 레지스터 수가 적으므로, 스택을 통해 인자를 전달한다. 또한, 인자를 전달하기 위해 사용한 스택을 호출자가 정리하는 특징이 있다. 스택을 통해 인자를 전달할 때는, 마지막 인자부터 첫 번째 인자까지 거꾸로 스택에 push한다.</p>
<h2 id="x86-64-호출규약--sysv">X86-64 호출규약 : SYSV</h2>
<h3 id="sysv">sysv</h3>
<p>리눅스 SYSTEM V(SYSV) Application Binary Interface(ABI)를 기반으로 만들어졌습니다. SYSV ABI는 ELF 포맷, 링킹 방법, 함수 호출 규약등의 내용을 담고있습니다.</p>
<blockquote>
<p>SYSV에서 정의한 함수 호출 규약의 특직</p>
</blockquote>
<ol>
<li>6개의 인자를 RDI, RSI, RDX, RCX, R8, R9에 순서대로 저장하여 전달한다. 더많은 인자를 사용해야 할 때는 스택을 추가로 이용한다.</li>
<li>Caller에서 인자 전달에 사용된 스택을 정리한다.</li>
<li>함수의 반환값은 RAX로 전달한다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[쉘코드]]></title>
            <link>https://velog.io/@ohwy0723-/%EC%89%98%EC%BD%94%EB%93%9C</link>
            <guid>https://velog.io/@ohwy0723-/%EC%89%98%EC%BD%94%EB%93%9C</guid>
            <pubDate>Sat, 09 Sep 2023 13:37:31 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>해킹분야에선 상대 시스템을 공격하는것을 익스플로잇(Exploit)이라고 부른다. </p>
<p>이 커리큘럼에서는 9가지 공격기법을 배우는데 이 코스에서는 셸코드를 소개한다.</p>
<h4 id="셸코드">셸코드</h4>
<p>익스플로잇을 위해 제작된 어셈블리 코드 조각을 일컫습니다.
일반적으로 셸을 획득하기 위한 목적으로 셸코드를 사용한다. <strong>셸</strong>을 휙득하는 것은 시스템 해킹의 관점에서 매우 중요하다. 그 이유를 execve 셸 코드에서 살펴보겠다.</p>
<p>만약 해커가 rip(현재 실행되고 있는 명령의 실행 주소)를 자신이 작성한 셸코드로 옮길 수 있으면 해커가 원하는 어셈블리 코드가 실행 되게 할 수 잇다.</p>
<p>셸코드는 어셈블리어로 구성되므로 공격을 수행할 대상 아키텍처와 운영체제에 따라, 그리고 셸코드의 목적에 따라 다르게 작성됩니다. 일반적인 인터넷에 공유되는 셸코드는 범용적으로 작성된 것이기 때문에, 실행될 때의 메모리 상태 같은 시스템 환경을 완전히 반영하지 못하기 때문에, 실행될 때의 메모리 상태 같은 시스템 환경을 완전히 반영하지는 못한다.
따라서 최적의 셸코드는 일반적으로 직접 작성해야 하며, 상황에 따라 반드시 그래야만 할 수도 있다. </p>
<h4 id="orw-셸코드-작성-open-read-write">orw 셸코드 작성 (open, read, write)</h4>
<ol>
<li>int fd = open(&quot;/tmp/falg&quot;,O_RDONLY,NULL)</li>
</ol>
<p>첫 번째로 해야 할 일은 &quot;/tmp/flag&quot;라는 문자열을 메모리에 위치시키는 것이다. 이를 위해 /tmp/flag를 16진수 0x616c662f706d742f67로 바꿔주고 push한다. 그리고 rdi가 이를 가리키도록 rsp를 rdi로 옮긴다. O_RDONLY는 0이므로 rsi는 0으로 설정한다.</p>
<p>파일을 읽을떄 mode는 의미를 가지지 않으므로 rdx는 0으로 설정한다.
마지막으로 rax를 open의 syscall 값인 2로 설정한다.</p>
<blockquote>
<p>구현</p>
</blockquote>
<pre><code>push 0x67
mov rax, 0x616c662f706d742f 
push rax
mov rdi, rsp    ; rdi = &quot;/tmp/flag&quot;
xor rsi, rsi    ; rsi = 0 ; RD_ONLY
xor rdx, rdx    ; rdx = 0
mov rax, 2      ; rax = 2 ; syscall_open
syscall         ; open(&quot;/tmp/flag&quot;, RD_ONLY, NULL)</code></pre><ol start="2">
<li>read(fd, buf, 0x30)</li>
</ol>
<p>syscall의 반환 값은 rax로 저장된다. 따라서 open으로 획득한 /tmp/flag의 fd는 rax에 저장된다. read의 첫번째 인자를 이 값으로 설정해야 하므로 rax를 rdi에 대입한다. rsi는 파일에서 읽은 데이터를 저장할 주소를 가리킨다. 0x30만큼 읽을 것이므로 rsi에 rsp-0x30을 대입한다.</p>
<p>rdx는 파일로부터 읽어낼 데이터의 길이인 0x30으로 설정합니다.</p>
<p>read 시스템 콜을 호출하기 위해서는 rax를 0으로 설정한다.</p>
<blockquote>
<p>구현</p>
</blockquote>
<pre><code>mov rdi, rax      ; rdi = fd
mov rsi, rsp
sub rsi, 0x30     ; rsi = rsp-0x30 ; buf
mov rdx, 0x30     ; rdx = 0x30     ; len
mov rax, 0x0      ; rax = 0        ; syscall_read
syscall           ; read(fd, buf, 0x30)



3. write(1, buf, 0x30)

출력은 stdout으로 할 것이므로 rdi를 0x1로 설정한다.

rsi와 rdx는 read에서 사용한 값을 그대로 사용한다.

write 시스템 콜을 호출하기 위해서 rax를 1로 설정한다.


&gt;구현</code></pre><p>mov rdi, 10; rdi = 1 ; fd = stdout
mov rax, 0x1      ; rax = 1 ; syscall_write
syscall           ; write(fd, buf, 0x30)</p>
<pre><code></code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[어셈블리어 (2)]]></title>
            <link>https://velog.io/@ohwy0723-/%EC%96%B4%EC%85%88%EB%B8%94%EB%A6%AC%EC%96%B4-2</link>
            <guid>https://velog.io/@ohwy0723-/%EC%96%B4%EC%85%88%EB%B8%94%EB%A6%AC%EC%96%B4-2</guid>
            <pubDate>Sat, 09 Sep 2023 13:36:20 GMT</pubDate>
            <description><![CDATA[<h3 id="스택">스택</h3>
<p>x64 아키텍쳐에서 다음의 명령어로 스택을 조작한다.</p>
<blockquote>
<p>push val : val을 스택 최상단에 쌓음</p>
</blockquote>
<pre><code>연산
rsp -= 8
[rsp] = val</code></pre><pre><code>예제
[register]
rsp = 0x7fffffffc400
[stack]
0x7fffffffc400 | 0x0 &lt;=rsp
0x7fffffffc408 | 0x0
[code]
push 0x31337</code></pre><pre><code>결과
[register]
rsp = 0x7fffffffc3f8
[stack]
0x7fffffffc3f8 | 0x31337 &lt;=rsp
0x7fffffffc400 | 0x0
0x7fffffffc408 | 0x0</code></pre><p>밸류 0x31337을 0x7fffffffc400에서 연산인 8을 뺀 0x7fffffffc3f8(주소)에 넣는다.</p>
<blockquote>
<p>push reg : 스택 최상단의 값을 꺼내서 reg에 대입</p>
</blockquote>
<pre><code>연산
rsp += 8
reg = [rsp-8]</code></pre><pre><code>예제
[register]
rax = 0
rsp = 0x7fffffffc3f8
[stack]
0x7fffffffc3f8 | 0x31337 &lt;=rsp
0x7fffffffc400 | 0x0
0x7fffffffc408 | 0x0
[code]
pop rax</code></pre><pre><code>결과
[register]
rax = 0x31337
rsp = 0x7fffffffc400
[stack]
0x7fffffffc3f8 | 0x0 &lt;=rsp
0x7fffffffc400 | 0x0</code></pre><p>주소 0x7fffffffc3f8에 있는 0x31337(밸류)를 rax에 대입한다. 자연스럽게 그 아래 스택인 0x7fffffffc400이 rsp가 된다.</p>
<h3 id="프로시저">프로시저</h3>
<p>프로시저는 특정 기능을 수행하는 코드 조각을 말한다. 프로시저를 사용하면 반복되는 연산을 프로시저 호출로 대체할 수 있어서 코드의 크기를 줄일수있고 코드조각에 이름을 붙일수 있어 코드의 가독성을 높일 수 있다.</p>
<p>프로시저를 부르는 행위를 호출(call)이라 부르며 프로시저에서 돌아오는 것을 반환(Return)이라고 부른다. </p>
<blockquote>
<p>call addr : addr에 위치한 프로시져 호출</p>
</blockquote>
<pre><code>연산
push return_address
jmp addr</code></pre><pre><code>예제
[register]
rip = 0x400000
rsp = 0x7fffffffc400
[stack]
0x7fffffffc3f8 | 0x0
0x7fffffffc400 | 0x0 &lt;= rsp
[code]
0x400000 | call 0x401000 &lt;= rip
0x400005 | mov esi, eax
...
0x401000 | push rbp</code></pre><pre><code>결과
[register]
rip = 0x401000
rsp = 0x7fffffffc3f8
[stack]
0x7fffffffc3f8 | 0x400005 &lt;= rsp
0x7fffffffc400 | 0x0
[code]
0x400000 | call 0x401000
0x400005 | mov esi, eax
...
0x401000 | push rbp &lt;= rip</code></pre><blockquote>
<p>leave : 스택 프레임 정리</p>
</blockquote>
<pre><code>연산
mov rsp, rbp
pop rbp #pop은 스택을 빼는 함수</code></pre><pre><code>예제
[register]
rsp = 0x7fffffffc400
rbp = 0x7fffffffc480
[stack]
0x7fffffffc400 | 0x0 &lt;= rsp
...
0x7fffffffc480 | 0x7fffff500 &lt;= rbp
0x7fffffffc488 | 0x31337
[code]
leave</code></pre><pre><code>결과
[register]
rsp = 0x7fffffffc488
rbp = 0x7fffffffc500
[stack]
0x7fffffffc400 | 0x0
...
0x7fffffffc480 | 0x7fffffffc500
0x7fffffffc488 | 0x31337 &lt;= rsp
0x7fffffffc500 | 0x7fffffffc550 &lt;= rbp</code></pre><blockquote>
<p>ret : return address로 반환</p>
</blockquote>
<pre><code>연산
pop rip</code></pre><pre><code>예제
[register]
rip = 0x401000
rsp = 0x7fffffffc3f8
[stack]
0x7fffffffc3f8 | 0x400005 &lt;= rsp
[code]
0x400000 | call 0x401000
0x400005 | mov esi, eax
...
0x401000 | mov rbp, rsp
..
0x401007 | leave
0x401008 | ret &lt;= rip</code></pre><pre><code>결과
[register]
rip = 0x401005
rsp = 0x7fffffffc400
[stack]
0x7fffffffc3f8 | 0x400005
0x8fffffffc400 | 0x0 &lt;= rsp
[code]
0x400000 | call 0x401000
0x400005 | mov esi, eax &lt;= rip
...
0x401000 | mov rbp, rsp
..
0x401007 | leave
0x401008 | ret</code></pre><blockquote>
<h3 id="용어">용어</h3>
</blockquote>
<pre><code>데이터 레지스터
RAX(Extended Accmulator Register) : 산술, 논리 연산을 수행하며 함수의 반환값이 이 레지스터에 저장된다. 누산기 레지스터
RBX(Extended Base Pointer) : 메모리의 주소를 저장하는 용도로 사용된다. 베이스 레지스터
RCX(Extended Counter Register) : 반복문에 루프카운터로 사용된다. 카운터 레지스터
RDX(Extended Data Register) : RAX와 같이 사용된다. 데이터 레지스터</code></pre><pre><code>포인터 레지스터
RSP(Extended Stack Pointer) : 현재 스택 주소, 스택의 맨윗쪽 주소, 스택은 쌓아가는 구조. 스택 포인터 레지스터
RBP(Extended Base Pointer) : 스택복귀 주소, 고급언어에서 스택에 있는 함수 매개 변수와 지역변수를 참조 하기 위해서 사용된다. 베이스 포인터 레지스터
RSI(Extended Source Index)/RDI(Extended Destination Index) : 각각 메모리 출발지와 목적지를 나타낸다. 근원지 인덱스 레지스터목적지 인덱스 레지스터</code></pre><pre><code>RIP : 현재 실행되고 있는 명령의 실행 주소이다. 명령 포인터 레지스터
r8~r15 : 함수의 매개변수로 많이 사용된다.일반 적인 범용 레지스터</code></pre><h3 id="시스템-콜">시스템 콜</h3>
<p>운영 체제는 컴퓨터 자원의 효율적인 사용과 사용자의 편리한 경험을 제공하기 위해, 내부적으로 매우 복잡한 동작을 한다. 운영체제는 연결된 모든 하드웨어와 소프트 웨어에 접근 할 수 있으며, 이들을 제어 할 수도 있다. 그리고 보안을 위해 <strong><em>커널모드</em></strong>와 _<strong>유저모드</strong>_로 권한을 나눈다. </p>
<p>커널 모드는 운영체제가 전체 시스템을 제어하기 위해 시스템 소프트웨어에 부여하는 권한이다. 파일 시스템, 입력/출력, 네트워크 통신,. 메모리 관리등 모든 저수준의 작업은 사용자 모르게 커널모드에서 진행된다.</p>
<p>유저모드는 운영체제가 사용자에게 부여하는 권한이다. 브라우저를 이용하거나, 영상을 시청하는것, 게임과 프로그래밍을 하는 것 등이 모두 유저 모드에서 이루어진다.</p>
<p>시스템 콜(system call, syscall)은 유저 모드에서 커널 모드의 시스템 소프트웨어에게 어떤 동작을 요청하기 위해 사용된다. 소프트웨어 대부분은 커널의 도움이 필요합니다.
x64아키텍쳐에서는 시스템 콜을 위해 syscall 명령어가 있다.</p>
<h4 id="시스템-콜syscall">시스템 콜(syscall)</h4>
<p>시스템 콜은 함수다. 필요한 기능과 인자에 대한 정보를 레지스터로 전달하면, 커널이 이를 읽어서 요청을 처리한다. 리눅스에서는 x64아키텍쳐에서 rax로 무슨요청인지를 나타내고, 아래의 순서대로 필요한 인자를 전달한다.</p>
<blockquote>
<p>syscall</p>
</blockquote>
<pre><code>요청 : rax
인자순서 : rdi -&gt; rsi -&gt; rdx -&gt; rcx -&gt; r8 -&gt; r9 -&gt; stack
(64bit 함수 호출 규약 / fastcall 방식으로 리눅스 기준 정수의 파라민터 순서에 대한 레지스터가 위와 같다.)</code></pre><pre><code>예제
[register]
rax = 0x1
rdi = 0x1
rsi = 0x401000
rdx = 0xb
[memory]
0x401000 | &quot;Hello Wo&quot;
0x401008 | &quot;rld&quot;
[code]</code></pre><pre><code>결과
Hello World</code></pre><p>해석
syscall table을 보면 rax가 0x01일때 write 시스템 콜을 요청한다. 이때 rdi, rsi, rdx가 0x1, 0x401000, 0xb이므로 커널은 write(0x1, 0x401000, 0xb)를 수행한다. 
write함수의 형식은 write(출력 스트림/rdi, 출력 버퍼/rsi, 출력 길이/rdx)인데 여기서 0x01은 stdout이며 이는 일반적으로 화면을 으미한다. 0x401000에는 Hello World가 저장되어 있고, 길이는 0xb로 지정되어 있으니까 화면에 Hello World가 출력된다.</p>
<h4 id="x64-syscall--테이블">x64 syscall  테이블</h4>
<p>syscall 테이블은 총갯수가 300에 달하지만, 검색하면 쉽게 찾을 수 있으므로 외울 필요는 없다.
<img src="https://velog.velcdn.com/images/ohwy0723/post/fb22aa12-8e87-4939-82e9-b4239fa122cc/image.png" alt=""></p>
<p>드림핵에서 모든 내용을 확인 할수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[어셈블리어(1)]]></title>
            <link>https://velog.io/@ohwy0723-/%EC%96%B4%EC%85%88%EB%B8%94%EB%A6%AC%EC%96%B41</link>
            <guid>https://velog.io/@ohwy0723-/%EC%96%B4%EC%85%88%EB%B8%94%EB%A6%AC%EC%96%B41</guid>
            <pubDate>Sat, 09 Sep 2023 13:35:24 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>기계어는 0과 1로 구성된다. 단어위주로 문장을 구사하는 우리한테는 이해하기 매우 어렵다. 그래서 과학자 중 한 명인 David Wheeler은 EDSAC를 개발 하면서 어셈블리어와 어셈블러를 고안해냈다.</p>
<p>어셈블러는 개발자들이 어셈블리어(C언어 같은 프로그래밍 언어)로 코드를 작성하면 컴퓨터가 이해할 수 있는 기꼐어로 치환해준다.</p>
<p>소프트웨어를 역분석하는 사람들은 여기에 역발상을 더해 기계어를 어셈블리언어로 번역하는 역어셈블러를 개발해 소프트웨어를 분석할려고 기계어를 읽는 필요를 덜어줬다.</p>
<h3 id="어셈블리-언어">어셈블리 언어</h3>
<p>어셈블리어는 CPU에 사용되는 명령어 집합구조가 많은만큼 어셈블리어의 종류도 다양하다 x64, ARM등 많은 어셈블리어가 존재하는데 x64의 어셈블리어를 공부할거다.</p>
<h4 id="기본구조">기본구조</h4>
<p>x64 어셈블리언어는 단순한 문법구조를 가진다.
동사에 해당하는 명령어(Opcode)와 목적어(Operand)에 해당하는 피연산자로 구성된다.</p>
<blockquote>
<p>mov eax, 3
opcode  oprerand1  operand2
대입해라 eax에 3을</p>
</blockquote>
<h4 id="명령어">명령어</h4>
<p>x64에는 많은 명령어가 존재
주요한 21개의 명령어를 자세히 학습</p>
<blockquote>
<p>명령코드</p>
</blockquote>
<pre><code>데이터 이동 : mov, lea
산술 연산 : inc, dec, add, sub
논리 연산 : and, or, xor, not
비교 : cmp, test
분기 : jmp, je, jg
스택 : push, pop
프로시져 : call, ret, leave
시스템 콜 : syscall

#### 피연산자

피연산자(operand)에는 상수, 레지스터, 메모리 총 3가지 종류가 올수있다. 메모리 피연산자는 []으로 둘러싸인것으로 표현되며, 앞에 크기 지정자 TYPE PTR이 추가될수 있다. 여기서 타입 BYTE, WORD, DWORD, QWORD가 올 수 있으며, 각각 1바이트, 2바이트, 4바이트, 8바이트의 크기를 지정한다.

&gt;메모리 피연산자</code></pre><p>QWORD PTRT[0x8048000] : 0x08048000의 데이터를 8바이트만큼 참조
DWORD PTR[0x8048000] : 0x08048000의 데이터를 4바이트만큼 참조
WORD PTR[rax] : rax가 가르키는 주소에서 데이터를 2바이트 만큼 참조</p>
<h3 id="명령어-1">명령어</h3>
<h4 id="데이터-이동">데이터 이동</h4>
<p>데이터 이동 명령어는 어떤값을 레지스터나 메모리에 옮기도록 지시한다.</p>
<blockquote>
<p>mov dst, src : src에 들어있는 값을 dst에 대입</p>
</blockquote>
<pre><code>mov rdi, rsi : rsi의 값을 rdi에 대입
mov QWORD PTR[rdi], rsi : rsi의 값을 rdi가 가리키는 주소에 대입
mov QWORD PTR[rdi+8*rcx],rsi : rst의 값을 rdi+8*rcx가 가리키는 주소에 대입

&gt;lea dst,src : src의 유효주소를 dst에 저장한다</code></pre><p>lea rsi,[rbx+8<em>rcx] : rbx+8</em>rcx를 rsi에 대입</p>
<p>mov는 저장되어 있는 값을 이동시키고 lea는 값의 주소를 이동시킨다.</p>
<h4 id="산술연산">산술연산</h4>
<p>산술연산은 덧셈 뺄셈 곱셈 나눗셈 연산을 지시한다.</p>
<blockquote>
<p>add dst,src : dst에 src값을 더한다.</p>
</blockquote>
<pre><code>add eax,3 : eax += 3 
add ax,WORD PTR[rdi] : ax += *(WORD *)rdi

&gt;suv dst,src : dst에서 src의 값을 뺀다.</code></pre><p>sub eax,3 : eax -= 3
sub ax, WORD PTR[rdi] : ax-= *(WORD *)rdi</p>
<blockquote>
<p>inc op : op의 값을 1 증가시킴</p>
</blockquote>
<pre><code> inc eax : eax += 1

&gt;dec op : op의 값을 1 감소시킴</code></pre><p>dec eax : eax -= 1</p>
<h4 id="논리연산">논리연산</h4>
<p>논리 연산 명령어는 and, or, xor, neg등의 비트연산을 한다. (비트 단위)</p>
<blockquote>
<p>and dst, src : dst와 src의 비트가 모두 1이면 1, 아니면 0</p>
</blockquote>
<pre><code>[레지스터]
eax = 0xffff0000
ebx = 0xcafebabe
[Code]
and eax, ebx
[Result]
eax = 0xcafe0000(eax와 ebx를 비교해 1인 부분만 eax에 대입)

&gt;or dst, src : dst와 src의 비트 중 하나라도 1이면 1, 아니면 0</code></pre><p>[레지스터]
eax = 0xffff0000
ebx = 0xcafebabe
[Code]
or eax, ebx
[Result]
eax = 0xffffbabe(eax와 ebx를 비교해 1이 존재하는곳은 그대로 대입)</p>
<blockquote>
<p>xor dst, src : dst와 src의 비트가 서로 다르면 1, 같
으면 0</p>
</blockquote>
<pre><code>[레지스터]
eax = 0xffffffff
ebx = 0xcafebabe
[Code]
xor eax, ebx
[Result]
eax = 0x35014541 (eax와 비교를 하고 같으면 0 다르면 ebx의 비트를 반전시킨값을 eax에 대입)

&gt;not op : op의 비트 전부 반전</code></pre><p>[레지스터]
eax = 0xffff0000
[Code]
not eax
[Result]
eax = 0x0000ffff(그냥 비트를 전부 반전)</p>
<h4 id="비교">비교</h4>
<p>비교 명령어는 두 피연산자의 값을 비교하고 플래그를 설정한다.</p>
<blockquote>
<p><strong>cmp op1, op2 : op1과 op2를 비교</strong>
(cmp는 두 피연산자의 결과를 대입하지않고 플래그를 설정하는데 예시처럼 서로 같은 두수를 빼면 결과값이 0이되어 ZF플래그가 설정된다. 이 플래그를 보고 CPU가 두값이 같았는지를 알수있다.)</p>
</blockquote>
<pre><code>[code]
mov rax, 0xA
mov rbx, 0xA
cmp rax, rbx ; ZF = 1

&gt; **test op, op2 : op1과 op2를 비교**
cmp가 빼서 결과값으로 비교를 했다면 test는 두 피연산자에 AND 비트연산을 취해 결과값으로 플래그를 설정한다. 이후 CPU는 플래그를 보고 비교 결과를 판단할수있다.</code></pre><p>[code]
xor rax, rax
test rax, rax ; ZF = 1</p>
<h4 id="분기">분기</h4>
<p>분기 명령어는 rip를 이동시켜 실행 흐름을 바꾼다.</p>
<blockquote>
<p>jmp addr : addr로 rip를 이동시킵니다</p>
</blockquote>
<pre><code>[code]
xor rax, rax
jmp 1 ; jump to 1

&gt;je addr : 직전에 비교한 두 피연산자가 같으면 점프</code></pre><p>[code]
mov rax , 0xcafebabe
mov rbx , 0xcafebabe
cmp rax, rbx ; rax == rbx
je 1 ; jump to 1</p>
<blockquote>
<p>jg addr : 직전에 비교한 두연산자중 전자가 더 크면 점프(jump if greater)</p>
</blockquote>
<pre><code>mov rax , 0x31337
mov rbx , 0x13337
cmp rax, rbx ; rax ? rbx
je 1 ; jump to 1

### 정리
&gt;데이터 이동 연산자</code></pre><p>mov dst, src: src의 값을 dst에 대입
lea dst, src: src의 유효 주소를 dst에 대입</p>
<pre><code>산술 연산</code></pre><p>add dst, src: src의 값을 dst에 더함
sub dst, src: src의 값을 dst에서 뺌
inc op: op의 값을 1 더함
dec op: op의 값을 1 뺌</p>
<pre><code>논리 연산</code></pre><p>and dst, src: dst와 src가 모두 1이면 1, 아니면 0
or dst, src: dst와 src중 한 쪽이라도 1이면 1, 아니면 0
xor dst, src: dst와 src가 다르면 1, 같으면 0
not op: op의 비트를 모두 반전</p>
<pre><code>비교</code></pre><p>cmp op1, op2: op1에서 op2를 빼고 플래그를 설정
test op1, op2: op1과 op2에 AND 연산을 하고, 플래그를 설정</p>
<pre><code>분기</code></pre><p>jmp addr: addr로 rip 이동
je addr: 직전 비교에서 두 피연산자의 값이 같을 경우 addr로 rip 이동
jg addr: 직전 비교에서 두 피연산자 중 전자의 값이 더 클 경우 addr로 rip 이동</p>
<pre><code>



레지스터의 이름 및 크기
x86에서 x64로 넘어가면서 더 큰사이즈들의 레지스터들이 등장했다. 자연스레 이전 x86의 EAX(4byte)가 RAX(8byte)로 더 커졌지만 EAX는 RAX의 하위 4바이트를 의미하며 사용된다. 
EAX는 RAX의 하위 4바이트, AX는 EAX의 하위 2바이트를 의미한다.

</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[리눅스 메모리 구조]]></title>
            <link>https://velog.io/@ohwy0723-/%EB%A6%AC%EB%88%85%EC%8A%A4-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@ohwy0723-/%EB%A6%AC%EB%88%85%EC%8A%A4-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Sat, 09 Sep 2023 13:34:31 GMT</pubDate>
            <description><![CDATA[<h3 id="개요">개요</h3>
<p>CPU역할 : 실행할 명령어와 명령어 처리에 필요한 데이터를 메모리에서 읽고 ISA(Instruction Set Architecture, 명령어 집합 구조)에 따라 이를 처리합니다.
그리고 연산의 결과를 다시 메모리에 적재한다.</p>
<p>CPU의 동작과 메모리는 밀접한 관계를 가지는것을 알수있다.</p>
<p>리눅스에서는 프로세스의 메모리르 크게 5가지로 나눈다.
(코드세그먼트, 데이터 세그먼트, BSS 세그먼트, 힙 세그먼트, 스택 세그먼트)</p>
<p>운영체제가 메모리를 용도 별로 나누면 각 용도에 맞게 적절한 권한을 부여할수있다는 장점이 있다. 권한은 읽기, 쓰기, 실행이 존재 CPU는 메모리에 대해 권한이 부여된 행위만 할 수 있다.</p>
<h3 id="코드-세그먼트">코드 세그먼트</h3>
<p>코드세그먼트(텍스트세그먼트)는 실행 가능한 기계코드가 위치하는 영역이라고도 불립니다.</p>
<p>프로그램을 동작하려면 코드를 실행할수있어야 하므로 코드 세그먼트에는 <strong>읽기권한과 실행권한</strong>이 주어진다. 쓰기 권한이 있을경우 공격자가 악의적인 코드를 삽입하기 쉬워지므로 대부분의 현대 운영체제에서는 쓰기권한을 제거한다.</p>
<p>함수가 컴파일 되면 기계 코드로 변환되는데 기계 코드가 코드 세드먼트에 위치하게된다.</p>
<blockquote>
<p>함수 : int main() { return 31337; } -&gt; 기계코드 554889e5b8697a00005dc3</p>
</blockquote>
<h3 id="데이터-세그먼트">데이터 세그먼트</h3>
<p>데이터 세그먼트에는 컴파일 시점에 값이 정해진 전역변수 및 전역 상수들이 위치합니다. CPU가 이 세그먼트의 데이터를 읽을 수 있어야 하기 때문에 <strong>읽기 권한</strong>이 부여된다.</p>
<p>데이터 세그먼트
전역변수와 같이 프로그램이 실행되면서 값이 변할수있는 데이터들이 위치하는 세그먼트</p>
<p>로데이터(read-only data) 세그먼트
프로그램이 실행되면서 값이 변하면 안되는 데이터들이 위치하는 세그먼트</p>
<blockquote>
<p>int data_num = 31337; // data
char data_rwstr[] = &quot;writable_data&quot;;        // data
const char data_rostr[] = &quot;readonly_data&quot;;  // rodata
char *str_ptr = &quot;readonly&quot;;  // str_ptr은 data, 문자열은 rodata</p>
</blockquote>
<h3 id="bss-세그먼트">BSS 세그먼트</h3>
<p>BSS세그먼트는 컴파일 시점에 값이 정해지지않은 전역변수들이 위치하는 메모리 영역
개발자가 선언만 하고 초기화하지 않은 전역변수 등이 포함.
이세그먼트의 메모리 영역은 프로그램이 시작될 때 모두 0으로 값이 초기화 된다.</p>
<p><strong>읽기, 쓰기 권한</strong>이 부여된다.</p>
<blockquote>
<p>int bss_data; -&gt; 초기화 되지 않은 변수 BSS세그먼트에 위치한다.
int main() {
  printf(&quot;%d\n&quot;, bss_data);  // 0
  return 0;
}</p>
</blockquote>
<h3 id="스택-세그먼트">스택 세그먼트</h3>
<p>스택 세그먼트는 프로세스의 스택이 위치하는 영역
함수의 인자나 지역변수와 같은 임시 변수들이 실행중에 여기에 저장된다.</p>
<p>스택 세그먼트는 <strong>스택 프레임</strong>이라는 단위로 사용된다.
스택 프레임은 함수가 호출될때 생성되고 반환될때 해제된다.</p>
<p>여기서 우리는 얼마만큼의 스택 프레임이 사용될지 미리 계산하는건 일반적으로 불가능하다. 그래서 운영체제는 프로세스를 시작할때 작은 크기의 스택 세그먼트를 먼저 할당해주고 부족해질때마다 이를 확장해준다. 스택에 대헤서 &#39;아래로 자란다&#39;라는 표현을 종종 사용하는데, 이는 스택이 확장될때, 기존 주소보다 낮은 주소로 확장되기 때문이다.</p>
<p><strong>읽기, 쓰기 권한</strong>이 부여된다.</p>
<blockquote>
<p>void func() {
  int choice = 0;
  scanf(&quot;%d&quot;, &amp;choice);
  if (choice) 
    call_true();
  else
    call_false();
  return 0;
}-&gt; 이 코드에서 지역변수 choice가 스택에 저장된다.</p>
</blockquote>
<h3 id="힙-세그먼트">힙 세그먼트</h3>
<p>힙 세그먼트는 힙 데이터가 위치하는 세그먼트다</p>
<p>스택과 마찬가지로 실행중에 동적으로 할당될수 있으며, 리눅스에서는 스택 세그먼트와 반대 방향으로 자랍니다.</p>
<p>C언어에서 malloc(), calloc() 등을 호출해서 할당받는 메모리가 이 세그먼트에 위치하게 되며, 일반적으로 <strong>읽기와 쓰기권한</strong>이 부여된다.</p>
<blockquote>
<p>int main() {
  int <em>heap_data_ptr =
      malloc(sizeof(</em>heap_data_ptr));  // 동적 할당한 힙 영역의 주소를 가리킴
  *heap_data_ptr = 31337;              // 힙 영역에 값을 씀
  printf(&quot;%d\n&quot;, *heap_data_ptr);  // 힙 영역의 값을 사용함
  return 0;
}</p>
</blockquote>
<p>요약
<img src="https://velog.velcdn.com/images/ohwy0723/post/84d8cda4-1ffe-48ff-9f1f-f82ffcab209b/image.png" alt=""></p>
<p>ISA : 소프트웨어에서 하드웨어를 중재해주는 역할, 최하위 레벨의 프로그래밍 인터페이스로, 프로세스가 실행할 수 있는 모든 명령어들을 포함한다.(CPU에 존재)</p>
<p>본문의 대부분의 내용은 dreamhack.io에서 공부하실 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[velog 재시작!]]></title>
            <link>https://velog.io/@ohwy0723-/%EC%9D%B4%EC%A0%84%EC%97%90-%ED%96%88%EB%8D%98-velog-%EA%B3%84%EC%A0%95-%EC%98%AE%EA%B2%A8%EC%84%9C-%EB%8B%A4%EC%8B%9C-%EC%8B%9C%EC%9E%91%ED%95%B4%EB%B3%B4%EA%B2%A0%EC%8A%B5%EB%8B%88%EB%8B%A4</link>
            <guid>https://velog.io/@ohwy0723-/%EC%9D%B4%EC%A0%84%EC%97%90-%ED%96%88%EB%8D%98-velog-%EA%B3%84%EC%A0%95-%EC%98%AE%EA%B2%A8%EC%84%9C-%EB%8B%A4%EC%8B%9C-%EC%8B%9C%EC%9E%91%ED%95%B4%EB%B3%B4%EA%B2%A0%EC%8A%B5%EB%8B%88%EB%8B%A4</guid>
            <pubDate>Sat, 09 Sep 2023 13:29:55 GMT</pubDate>
            <description><![CDATA[<p>2023.09.09 화이트햇 스쿨을 시작하면서 이전에 공부했던 내용 복습 및 정리겸 새로 시작하겠습니다.</p>
<p><img src="https://velog.velcdn.com/images/ohwy0723-/post/eb8697aa-ce67-410e-a9ea-bc51ba09d9d1/image.gif" alt=""></p>
<p>열심히 해보겠습니다!</p>
]]></description>
        </item>
    </channel>
</rss>