<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>pingu_9.log</title>
        <link>https://velog.io/</link>
        <description>안녕하세요</description>
        <lastBuildDate>Wed, 28 May 2025 00:33:18 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>pingu_9.log</title>
            <url>https://velog.velcdn.com/images/pingu_9/profile/3cabd6e6-2cae-4002-b6b7-38005a0101a4/image.webp</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. pingu_9.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/pingu_9" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[파이썬[9일차]]]></title>
            <link>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC9%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC9%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 28 May 2025 00:33:18 GMT</pubDate>
            <description><![CDATA[<details>
  <summary>참고</summary>
  <div><span style="color:blue">참고 자료는 점프 투 파이썬으로 선택했습니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</details>

<blockquote>
<h4 id="1-다음-코드의-결과값은-무엇일까">1. 다음 코드의 결과값은 무엇일까?</h4>
<p>a = &quot;Life is too short, you need python&quot;
<img src="https://velog.velcdn.com/images/pingu_9/post/180e925f-bfe5-4d7a-b5a2-93450cf75047/image.png" alt="">
<strong>답:</strong> shirt</p>
</blockquote>
<blockquote>
<h4 id="2-while문을-사용해-1부터-1000까지의-자연수-중-3의-배수의-합을-구해-보자">2. while문을 사용해 1부터 1000까지의 자연수 중 3의 배수의 합을 구해 보자.</h4>
<p><strong>답:</strong></p>
</blockquote>
<pre><code class="language-python">b = 1
result = 0
while b &lt;= 1000:
    if b % 3 == 0:
        result += b
    b += 1
print(&quot;1부터 1000까지 3의 배수의 합:&quot;, result)</code></pre>
<blockquote>
<h4 id="3-while문을-사용하여-다음과-같이-별을-표시하는-프로그램을-작성해-보자">3. while문을 사용하여 다음과 같이 별(*)을 표시하는 프로그램을 작성해 보자.</h4>
</blockquote>
<pre><code>*
**
***
****
*****</code></pre><p><strong>답:</strong></p>
<pre><code class="language-python">a = &quot;*&quot;
b = 0
while b &lt; 5:
    print(a)
    b += 1
    a += &quot;*&quot;</code></pre>
<pre><code class="language-python">a = 0
while a &lt;= 5:
    print(a * &quot;*&quot;)
    a += 1</code></pre>
<blockquote>
<h4 id="4-for문을-사용해-1부터-100까지의-숫자를-출력해-보자">4. for문을 사용해 1부터 100까지의 숫자를 출력해 보자.</h4>
<p><strong>답:</strong></p>
</blockquote>
<pre><code class="language-python">for a in range(0,101):
    print(a)</code></pre>
<blockquote>
<h4 id="5-a-학급에-총-10명의-학생이-있다-이-학생들의-중간고사-점수는-다음과-같다">5. A 학급에 총 10명의 학생이 있다. 이 학생들의 중간고사 점수는 다음과 같다.</h4>
<p>[70, 60, 55, 75, 95, 90, 80, 80, 85, 100]
for문을 사용하여 A 학급의 평균 점수를 구해 보자.
<strong>답:</strong></p>
</blockquote>
<pre><code class="language-python">a = [70, 60, 55, 75, 95, 90, 80, 80, 85, 100]
total = 0
for i in a:
    total += i
print(&quot;%0.0f&quot; %(total/10))</code></pre>
<blockquote>
<h4 id="6-리스트-중에서-홀수에만-2를-곱하여-저장하는-다음-코드가-있다">6. 리스트 중에서 홀수에만 2를 곱하여 저장하는 다음 코드가 있다.</h4>
</blockquote>
<pre><code class="language-python">numbers = [1, 2, 3, 4, 5]
result = []
for n in numbers:
    if n % 2 == 1:
        result.append(n*2)</code></pre>
<p>위 코드를 리스트 내포(list comprehension)를 사용하여 표현해 보자.
<strong>답:</strong></p>
<pre><code class="language-python">numbers = [1, 2, 3, 4, 5]
result = [n*2 for n in numbers if n % 2 == 1]
print(result)</code></pre>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고문헌">출처 및 참고문헌</h1>
<h1 id="httpswikidocsnet23"><a href="https://wikidocs.net/23">https://wikidocs.net/23</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬[8일차]]]></title>
            <link>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC8%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC8%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 19 Dec 2024 01:51:47 GMT</pubDate>
            <description><![CDATA[<details>
  <summary>참고</summary>
  <div><span style="color:blue">참고 자료는 점프 투 파이썬으로 선택했습니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</details>

<h2 id="for-문">for 문</h2>
<blockquote>
<p>파이썬의 직관적인 특징을 가장 잘 보여 주는 것이 바로 for 문이다.
while 문과 비슷한 반복문인 for 문은 문장 구조가 한눈에 들어온다는 장접이 있다.
for 문을 잘 사용하면 프로그래밍이 즐거워질 것이다.</p>
</blockquote>
<h3 id="ㅁ-for-문의-기본-구조">ㅁ for 문의 기본 구조</h3>
<blockquote>
<p>for 문의 기본 구조는 다음과 같다.</p>
</blockquote>
<pre><code class="language-python">for 변수 in 리스트(또는 튜플, 문자열):
    수행할_문장1
    수행할_문장2
    ...</code></pre>
<p>리스트나 튜플, 문자열의 첫 번째 요소부터 마지막 요소까지 차례로 변수에 대입되어 ‘수행할_문장1’, ‘수행할_문장2’ 등이 수행된다.</p>
<h3 id="ㅁ-예제를-통해-for-문-이해하기">ㅁ 예제를 통해 for 문 이해하기</h3>
<blockquote>
<p>for 문은 예쩨를 통해서 살펴보는 것이 가장 알기 쉽다.</p>
</blockquote>
<h4 id="1-전형적인-for-문">1. 전형적인 for 문</h4>
<pre><code class="language-python">&gt;&gt;&gt; test_list = [&#39;one&#39;, &#39;two&#39;, &#39;three&#39;] 
&gt;&gt;&gt; for i in test_list: 
...     print(i)
... 
one 
two 
three</code></pre>
<ul>
<li>[&#39;one&#39;, &#39;two&#39;, &#39;three&#39;] 리스트의 첫 번째 요소인 &#39;one&#39;이 먼저 i 변수에 대입된 후 print(i) 문장을 수행한다.</li>
<li>다음에 두 번째 요소 &#39;two&#39;가 i 변수에 대입된 후 print(i) 문장을 수행하고 리스트의 마지막 요소까지 이것을 반복한다.<blockquote>
</blockquote>
<h4 id="2-다양한-for-문의-사용">2. 다양한 for 문의 사용</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = [(1,2), (3,4), (5,6)]
&gt;&gt;&gt; for (first, last) in a:
...     print(first + last)
...
3
7
11</code></pre>
</li>
<li>위 예는 a 리스트의 요솟값이 튜플이기 때문에 각각의 요소가 자동으로(first, last) 변수에 대입된다.<blockquote>
</blockquote>
<h4 id="3-for-문의-응용">3. for 문의 응용</h4>
for 문의 쓰임새를 알기 위해 다음과 같은 문제를 생각해 보자.<pre><code>5명의 학생이 시험을 보았는데 시험 점수가 60점 이상이면 합격이고 그렇지 않으면 불합격이다. 합격인지, 불합격인지 결과를 보여 주시오.</code></pre></li>
<li>먼저 학생 5명의 시험 점수를 리스트로 표현해 보자.<pre><code class="language-python">marks = [90, 25, 67, 45, 80]</code></pre>
</li>
<li>1번 학생은 90점이고 5번 학생은 80점이다.</li>
<li>이런 점수를 차례로 검사해서 합격했는지, 불합격했는지 통보해 주는 프로그램을 만들어 보자.<pre><code class="language-python"># marks1.py
marks = [90, 25, 67, 45, 80]   # 학생들의 시험 점수 리스트
&gt;
number = 0   # 학생에게 붙여 줄 번호
for mark in marks:   # 90, 25, 67, 45, 80을 순서대로 mark에 대입
  number = number +1 
  if mark &gt;= 60: 
      print(&quot;%d번 학생은 합격입니다.&quot; % number)
  else: 
      print(&quot;%d번 학생은 불합격입니다.&quot; % number)</code></pre>
</li>
<li>각각의 학생에게 번호를 붙여 주기 위해 number 변수를 사용하였다.</li>
<li>점수 리스트 marks에서 차레로 점수를 꺼내어 mark라는 변수에 대입하고 for 문 안의 문장들을 수행한다.</li>
<li>먼저 for 문이 한 번씩 수행될 때마다 number는 1씩 증가한다.</li>
</ul>
<h3 id="ㅁ-for-문과-continue-문">ㅁ for 문과 continue 문</h3>
<blockquote>
<p>while 문에서 살펴본 continue 문을 for 문에서도 사용할 수 있다.
즉, for 문 안의 문장을 수행하는 도중 continue 문을 만나면 for 문의 처음으로 돌아가게 된다.
<br>
앞에서 for 문 응용 예제를 그대로 사용해서 60점 이상인 사람에게는 축하 메시지를 보내고 나머지 사람에게는 아무런 메시지도 전하지 않는 프로그램을 작성해보자.</p>
</blockquote>
<pre><code class="language-python"># marks2.py
marks = [90, 25, 67, 45, 80]
&gt;
number = 0 
for mark in marks: 
    number = number +1 
    if mark &lt; 60:
        continue 
    print(&quot;%d번 학생 축하합니다. 합격입니다. &quot; % number)</code></pre>
<ul>
<li>점수가 60점 이하인 학생인 경우에는 <strong>mark &lt; 60</strong>이 참이 되어 continue 문이 수행된다.</li>
<li>따라서 축하 메시지를 출력하는 부분인 print 문을 수행하지 않고 for 문의 처음으로 돌아가게 된다.<pre><code>C:\doit&gt;python marks2.py
1번 학생 축하합니다. 합격입니다.
3번 학생 축하합니다. 합격입니다.
5번 학생 축하합니다. 합격입니다.</code></pre></li>
</ul>
<h3 id="ㅁ-for-문과-함께-자주-사용하는-range-함수">ㅁ for 문과 함께 자주 사용하는 range 함수</h3>
<blockquote>
<p>for 문은 숫자 리스트를 자동으로 만들어 주는 range 함수와 함께 사용하는 경우가 많다.
다음은 range 함수의 간단한 사용법이다.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; a = range(10)
&gt;&gt;&gt; a
range(0, 10)</code></pre>
<ul>
<li>range(10)은 0 부터 10 미만의 숫자를 포함하는 range 객체를 만들어 준다.</li>
<li>시작 숫자와 끝 숫자를 지정하려면 rnage(시작_숫자, 끝_숫자) 형태를 사용하는데, 이때 끝 숫자는 포함되지 않는다.<pre><code class="language-python">&gt;&gt;&gt; a = range(1, 11)
&gt;&gt;&gt; a
range(1, 11)</code></pre>
</li>
</ul>
<h3 id="ㅁ-range-함수의-예시-살펴보기">ㅁ range 함수의 예시 살펴보기</h3>
<blockquote>
<p>for와 range 함수를 사용하면 1부터 10까지 더하는 것을 다음과 같이 쉽게 구현할 수 있다.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; add = 0 
&gt;&gt;&gt; for i in range(1, 11): 
...     add = add + i 
... 
&gt;&gt;&gt; print(add)
55</code></pre>
<ul>
<li>range(1, 11)은 숫자 1부터 10까지(1 이상 11 미만)의 숫자를 데이터로 가지는 객체이다.</li>
<li>따라서 위 예에서 i 변수에 숫자가 1부터 10까지 하나씩 차례로 대입되면서 <strong>add = add + i</strong> 문장을 반복적으로 수행하고 add는 최종적으로 55가 된다.</li>
</ul>
<blockquote>
<p>또한 우리가 앞에서 살펴본 합격 축하 문장을 출력하는 예제도 range 함수를 사용해서 다음과 같이 바꿀 수 있다.</p>
</blockquote>
<pre><code class="language-python"># marks3.py
marks = [90, 25, 67, 45, 80]
for number in range(len(marks)):
    if marks[number] &lt; 60: 
        continue
    print(&quot;%d번 학생 축하합니다. 합격입니다.&quot; % (number+1))</code></pre>
<ul>
<li>len는 리스트 안의 요소 개수를 리턴하는 함수이다.</li>
<li>따라서 len(marks)는 5, range(len(marks))는 range(5)가 될 것이다.</li>
<li>number 변수에는 차례로 0부터 4까지의 숫자가 대입되고 marks[number]는 차례대로 90, 25, 67, 45, 80 값을 가지게 된다. 결과는 marks2.py 예제와 동일하다.</li>
</ul>
<h3 id="ㅁ-for와-range를-이용한-구구단">ㅁ for와 range를 이용한 구구단</h3>
<blockquote>
<p>for와 range 함수를 사용하면 소스 코드 단 4줄만으로 구구단을 출력할 수 있다.
들여쓰기에 주의하면서 입력해보자.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; for i in range(2,10):        # 1번 for문
...     for j in range(1, 10):   # 2번 for문
...         print(i*j, end=&quot; &quot;) 
...     print(&#39;&#39;) 
... 
2 4 6 8 10 12 14 16 18 
3 6 9 12 15 18 21 24 27 
4 8 12 16 20 24 28 32 36
5 10 15 20 25 30 35 40 45
6 12 18 24 30 36 42 48 54 
7 14 21 28 35 42 49 56 63 
8 16 24 32 40 48 56 64 72 
9 18 27 36 45 54 63 72 81</code></pre>
<ul>
<li>위 예를 보면 for 문을 두 번 사용했다.</li>
<li>1번 for 문에서 2부터 9까지의 숫자(<strong>range(2, 10</strong>))가 차례대로 i에 대입된다.</li>
<li>i가 처음 2일 때 2번 for 문을 만나게 된다. 2번 for 문에서 1부터 9까지의 숫자(<strong>range(1, 10)</strong>)가 j에 대입되고 그다음 문장인 <strong>print(i*j, end=&quot; &quot;)</strong>를 수행한다.</li>
<li>따라서 i가 2일 때 <strong>2 * 1, 2 * 2, 2 * 3, … 2 * 9</strong>까지 차례대로 수행되며 그 값을 출력하게 된다.</li>
<li>그다음으로 i가 3일 때 역시 2일 때와 마찬가지로 수행될 것이고 i가 9일 때까지 계속 반복된다.<blockquote>
<br>
![](https://velog.velcdn.com/images/pingu_9/post/739f57bf-62e2-49ba-a8d9-98333a18c3e5/image.png)</blockquote>
</li>
<li><strong>print(i*j, end=&quot; &quot;)</strong>와 같이 print 함수에 end 파라미터를 설정한 이유는 해당 결괏값을 출력할 때 다음 줄로 넘기지 않고 그 줄에 계속 출력하기 위해서이다.</li>
<li>그다음에 이어지는 <strong>print(&#39;&#39;)</strong>는 2단, 3단 등을 구분하기 위해 사용했다.</li>
<li>두 번째 for 문이 끝나면 결괏값을 다음 줄부터 출력하게 하는 역할을 한다.<blockquote>
<blockquote>
<ul>
<li>print 문의 end 매개변수에는 줄바꿈 문자(<strong>\n</strong>)가 기본값으로 설정되어 있다.</li>
</ul>
</blockquote>
</blockquote>
</li>
</ul>
<h3 id="ㅁ-리스트-컴프리헨션-사용하기">ㅁ 리스트 컴프리헨션 사용하기</h3>
<blockquote>
<p>리스트 안에 for 문을 포함하는 리스트 컴프리헨션(list comprehension)을 사용하면 좀 더 편리하고 직관적인 프로그램을 만들 수 있다. 다음 예제를 살펴보자.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3,4]
&gt;&gt;&gt; result = []
&gt;&gt;&gt; for num in a:
...     result.append(num*3)
...
&gt;&gt;&gt; print(result)
[3, 6, 9, 12]</code></pre>
<ul>
<li>위 예제에서는 a 리스트의 각 항목에 3을 곱한 결과를 result 리스트에 담았다.</li>
<li>리스트 컴프리헨션을 사용하면 다음과 같이 좀 더 간단하게 작성할 수 있다.<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3,4]
&gt;&gt;&gt; result = [num * 3 for num in a]
&gt;&gt;&gt; print(result)
[3, 6, 9, 12]</code></pre>
</li>
<li>만약 [1,2,3,4] 중에서 짝수에만 3을 곱하여 담고 싶다면 리스트 컴프리헨션 안에 &#39;if 조건문&#39;을 사용하면 된다.<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3,4]
&gt;&gt;&gt; result = [num * 3 for num in a if num % 2 == 0]
&gt;&gt;&gt; print(result)
[6, 12]</code></pre>
</li>
<li>리스트 컴프리헨션의 문법은 다음과 같다. &#39;if 조건문&#39; 부분은 앞의 예제에서 볼 수 있듯이 생략할 수 있다.<pre><code class="language-python">[표현식 for 항목 in 반복_가능_객체 if 조건문]</code></pre>
</li>
<li>조금 복잡하지만, for 문을 2개 이상 사용하는 것도 가능하다.</li>
<li>for 문을 여러 개 사용할 때의 문법은 다음과 같다.<pre><code class="language-python">[표현식 for 항목1 in 반복_가능_객체1 if 조건문1
    for 항목2 in 반복_가능_객체2 if 조건문2
    ...
    for 항목n in 반복_가능_객체n if 조건문n]</code></pre>
</li>
<li>만약 구구단의 모든 결과를 리스트에 담고 싶다면 리스트 컴프리헨션을 사용하여 다음과 같이 간단하게 구현할 수도 있다.<pre><code class="language-python">&gt;&gt;&gt; result = [x*y for x in range(2,10)
...               for y in range(1,10)]
&gt;&gt;&gt; print(result)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 3, 6, 9, 12, 15, 18, 21, 24, 27, 4, 8, 12, 16,
20, 24, 28, 32, 36, 5, 10, 15, 20, 25, 30, 35, 40, 45, 6, 12, 18, 24, 30, 36, 42
, 48, 54, 7, 14, 21, 28, 35, 42, 49, 56, 63, 8, 16, 24, 32, 40, 48, 56, 64, 72,
9, 18, 27, 36, 45, 54, 63, 72, 81]</code></pre>
</li>
<li>지금까지 우리는 프로그램 흐름을 제어하는 if 문, while 문, for 문에 대해 알아보았다.</li>
<li>아마도 여러분은 while 문과 for 문을 보면서 2가지가 매우 비슷하다는 느낌을 받았을 것이다.</li>
<li>실제로 for 문으로 작성한 코드를 while 문으로 바꿀 수 있는 경우도 많고 while 문을 for 문으로 바꾸어서 사용할 수 있는 경우도 많다.</li>
</ul>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고문헌">출처 및 참고문헌</h1>
<h1 id="httpswikidocsnet22"><a href="https://wikidocs.net/22">https://wikidocs.net/22</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[CTF[9일차]]]></title>
            <link>https://velog.io/@pingu_9/CTF9%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/CTF9%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 19 Dec 2024 01:49:04 GMT</pubDate>
            <description><![CDATA[<blockquote>
<details>
  <summary>참고</summary>
  <div><span style="color:blue">
※참고 자료는 드림핵을 이용하였습니다.<br>
※드림핵의 로드맵대로 공부할 예정입니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</blockquote>
</details>

<h2 id="exercise-docker">Exercise: Docker</h2>
<h3 id="도커-설치">도커 설치</h3>
<blockquote>
<p>우분투 리눅스 22.04에 <a href="https://docs.docker.com/engine/install/ubuntu/">도커 엔진</a>을 설치하여 도커를 사용하겠습니다.
아래 명령을 순서대로 실행하여 도커 엔진을 설치합니다.</p>
</blockquote>
<pre><code>$ sudo apt-get update
$ sudo apt-get install \
    ca-certificates \
    curl \
    gnupg</code></pre><pre><code>$ sudo mkdir -m 0755 -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg</code></pre><pre><code>$ echo \
  &quot;deb [arch=&quot;$(dpkg --print-architecture)&quot; signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  &quot;$(. /etc/os-release &amp;&amp; echo &quot;$VERSION_CODENAME&quot;)&quot; stable&quot; | \
  sudo tee /etc/apt/sources.list.d/docker.list &gt; /dev/null</code></pre><pre><code>$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin</code></pre><pre><code>$ sudo docker run hello-world</code></pre><p>위 명령어를 입력했을 때 Hello from Docker!가 출력되면 도커 엔진이 잘 설치된 것입니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/27ee1a7e-bf7e-4bee-a162-c939b544e82f/image.png" alt=""></p>
<h2 id="exercisedocker---1">Exercise:Docker - 1</h2>
<p>이제 도커를 이용하여 드림핵 워게임 문제 환경에 접속해 보겠습니다.
Exercise:Docker는 플래그를 찾는 것이 목표가 아니라 Dockerfile로 직접 이미지를 빌드하고 컨테이너를 실행해 보기 위한 실습 문제입니다.</p>
<p>-&gt;이어서 후에 할 예정
<a href="https://learn.dreamhack.io/459#10">https://learn.dreamhack.io/459#10</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CTF[8일차]]]></title>
            <link>https://velog.io/@pingu_9/CTF8%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/CTF8%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 18 Dec 2024 23:54:17 GMT</pubDate>
            <description><![CDATA[<blockquote>
<details>
  <summary>참고</summary>
  <div><span style="color:blue">
※참고 자료는 드림핵을 이용하였습니다.<br>
※드림핵의 로드맵대로 공부할 예정입니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</blockquote>
</details>

<h1 id="ssh">SSH</h1>
<blockquote>
<p>원격 Linux 서버에 연결하는 가장 일반적인 방식은 SSH 명령어를 사용하는 것입니다.
<strong>SSH (Secure Shell, Secure Socket Shell)</strong>는 원격 서버(컴퓨터)에 연결할 수 있도록 해 주는 암호화된 네트워크 프로토콜입니다.
암호화를 통해 호스트와 클라이언트가 안전하게 통신할 수 있습니다.
클라이언트가 원격 서버의 터미널에 접속하여 명령어를 입력하면, 호스트가 명령 실행 결과를 클라이언트에게 전달합니다.</p>
</blockquote>
<blockquote>
<ul>
<li>워게임이나 CTF 문제 서버에 접속하기 위해 가끔 SSH 명령어를 사용합니다. 이번 강의에서는 SSH 명령어 사용법에 대해 알아보겠습니다.</li>
</ul>
</blockquote>
<h2 id="ssh-명령어-준비">SSH 명령어 준비</h2>
<blockquote>
<p>Linux와 macOS에서는 터미널에서 <strong>ssh</strong> 명령어를 기본적으로 사용할 수 있습니다.
앞서 Virtual Machine 강의에서 구축한 Ubuntu Linux 환경을 사용한다면 따로 설치할 것이 없으므로 다음 단계로 넘어가시면 됩니다.</p>
</blockquote>
<blockquote>
<p>Windows에서는 open SSH 클라이언트를 사용해야 합니다.
Windows 10 기준으로 open SSH 클라이언트는 다음과 같이 <a href="https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse?tabs=gui&amp;pivots=windows-server-2025">설치</a>합니다. </p>
</blockquote>
<ol>
<li><p>설정 - 앱 - 선택적 기능 클릭</p>
</li>
<li><p>선택적 기능 추가 (기능 보기) - OpenSSH 클라이언트 설치
<img src="https://velog.velcdn.com/images/pingu_9/post/ceb7ca77-af60-4e49-9656-0cbe595b2e58/image.png" alt=""></p>
</li>
<li><p>터미널에서 ssh 명령어를 입력하여 아래와 같이 뜨는지 확인</p>
<pre><code class="language-c">PS C:\Users\user&gt; ssh
usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]
        [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
        [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]
        [-i identity_file] [-J [user@]host[:port]] [-L address]
        [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
        [-Q query_option] [-R address] [-S ctl_path] [-W host:port]
        [-w local_tun[:remote_tun]] destination [command]</code></pre>
</li>
</ol>
<h2 id="ssh-사용법">SSH 사용법</h2>
<blockquote>
<p><strong>ssh</strong> 명령은 다음과 같이 작성합니다.</p>
</blockquote>
<pre><code class="language-c">ssh user@HOST -p PORT -i [개인 키 파일 경로]</code></pre>
<ul>
<li>ssh 접속할 때는 원격 서버에 존재하는 계정으로 접속합니다. <strong>user</strong>에 접속할 계정(사용자 이름)을 작성합니다. </li>
<li><strong>HOST</strong>에는 접속하려는 원격 서버의 ip 또는 도메인을 작성합니다.</li>
<li>특정 포트로 접속하고 싶은 경우 <strong>-p</strong> 옵션을 이용합니다.<br>
접속하는 클라이언트가 믿을만한 사용자인지 인증하는 방법은 두 가지가 있습니다.<br></li>
</ul>
<ol>
<li><p>첫 번째는 패스워드로 인증하는 방법입니다. <strong>ssh user@HOST</strong> 명령을 실행하면 패스워드를 입력한 뒤 원격 서버에 접속할 수 있습니다.
하지만 패스워드를 충분히 긴 길이로 설정하지 않으면 브루트 포스 공격을 통해 패스워드를 유추할 수 있다는 위험이 있어 권장되지 않습니다. </p>
</li>
<li><p>더 안전한 방법은 원격 서버에 공개 키를 저장하고, 클라이언트가 사용할 개인 키를 지정하여 알맞은 사용자인지 검증하는 것입니다.
공개 키-개인 키 쌍은 <strong>ssh-keygen</strong> 명령으로 생성할 수 있습니다.
이번 강의는 <strong>ssh</strong>로 원격 서버에 접속해 보는 것이 목적이므로, 암호화와 검증에 대한 자세한 내용은 다루지 않겠습니다.
개인 키 파일을 이용하여 원격 서버에 접속할 때 <strong>-i</strong> 옵션을 이용한다는 것만 알아두어도 충분합니다.</p>
</li>
</ol>
<h2 id="ssh-사용-예시">SSH 사용 예시</h2>
<h3 id="ㅁ-패스워드로-원격-서버에-접속하기">ㅁ 패스워드로 원격 서버에 접속하기</h3>
<pre><code class="language-c">Host: host3.dreamhack.games
Port: 11051/tcp → 31337/tcp</code></pre>
<pre><code class="language-c">ssh with 
id: bguser
pw: bgpw </code></pre>
<ul>
<li>접속 정보, 사용자, 패스워드가 위와 같이 주어진 예시입니다.</li>
</ul>
<p>터미널을 열고 <strong>ssh <a href="mailto:bguser@host3.dreamhack.games">bguser@host3.dreamhack.games</a> -p 11051</strong> 명령을 수행한 뒤, 패스워드로 <strong>bgpw</strong>를 입력하여 문제 서버에 접속합니다.</p>
<h3 id="ㅁ-개인-키로-원격-서버에-접속하기">ㅁ 개인 키로 원격 서버에 접속하기</h3>
<pre><code class="language-c">Host: host3.dreamhack.games
Port: 11051/tcp → 31337/tcp</code></pre>
<pre><code>ssh with id: bguser</code></pre><ul>
<li>같은 예시에서 패스워드 대신 개인 키 파일이 첨부된 경우입니다. </li>
</ul>
<p>터미널을 열고 ssh <a href="mailto:bguser@host3.dreamhack.games">bguser@host3.dreamhack.games</a> -p 11051 -i [다운받은 개인 키 파일 경로] 명령을 수행하면 문제 서버에 접속합니다.</p>
<h3 id="ㅁ-exercise-ssh">ㅁ Exercise: SSH</h3>
<blockquote>
<p>이제 ssh로 워게임 문제 서버에 직접 접속해 보겠습니다.
<a href="https://dreamhack.io/wargame/challenges/875/">Exercise: SSH</a>는 ssh로 원격 서버에 접속해서 플래그 파일을 읽는 것이 목표인 문제입니다.
접속을 위한 사용자와 패스워드 정보는 다음과 같습니다.
Host와 Port는 <strong>접속 정보 보기</strong>를 클릭하여 알 수 있습니다.</p>
</blockquote>
<pre><code>ssh with
id: chall
password: dhbgssh</code></pre><ul>
<li>문제 서버에 다음과 같이 접속하여 플래그를 출력합니다. 직접 명령어를 작성하고 접속해 본 뒤 정답을 확인하시기 바랍니다.<pre><code class="language-c">user@user-VirtualBox:~$ ssh chall@host2.dreamhack.games -p 20411
The authenticity of host &#39;[host2.dreamhack.games]:20411 ([158.247.221.81]:20411)&#39; can&#39;t be established.
ED25519 key fingerprint is SHA256:xhAn3bi+kzaaA1iGfdWEqxlXIHfGg8F0iJuyKHulTXw.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added &#39;[host2.dreamhack.games]:20411&#39; (ED25519) to the list of known hosts.
chall@host2.dreamhack.games&#39;s password: (dhbgssh 입력)
Welcome to Ubuntu 22.04.1 LTS (GNU/Linux 4.19.234 x86_64)
... (생략)
chall@localhost:~$ ls
bin  flag
chall@localhost:~$ cat flag
DH{h3110_6e9inn3rs!}
chall@localhost:~$ </code></pre>
</li>
</ul>
<h1 id="docker">Docker</h1>
<blockquote>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/4fe354b6-41e7-4f8e-9b4d-b62322a5fb15/image.gif" alt="">
CTF나 워게임을 풀어 보았다면 <strong>도커(Docker)</strong>를 본 적이 있을 것입니다.
도커가 무엇인지 몰랐다면, 열심히 검색하고 도커 문서를 읽다가 지쳐 <strong>그래서 도커가 대체 뭐지?</strong>라고 생각했을 수 있습니다.
도커를 이미 알고 있더라도 해킹과 도커는 무슨 관련이 있는지, 해킹 공부를 할 때 도커를 꼭 알아야 하는지 의문을 가질 수도 있습니다.</p>
</blockquote>
<p>이번 강의에서는 도커가 무엇이고, 앞으로의 해킹 공부에 왜 필요한지 알아보겠습니다.
그리고 도커 관련 명령어와 사용 방법을 배운 뒤, 도커를 사용하여 직접 워게임에 접속하는 실습을 진행합니다.</p>
<h2 id="도커docker">도커(Docker)</h2>
<blockquote>
<p><strong>도커(Docker)</strong>는 <u>컨테이너</u>를 만들고, 실행하고, 배포할 수 있는 가상화 프랫폼입니다.
도커의 컨테이너란, 가상의 환경이 구축되어 있는 하나의 박스를 말합니다.
VirtualBox 등의 가상 머신으로 하나의 운영체제 위에 다른 운영체제 환경을 구축하는 것과 유사하지만, 도커 컨테이너는 새로운 운영체제 환경을 구축할 필요 없이 하나의 분리된 프로세스처럼 작동하여 더 가볍습니다.
쉽게 말하면 특정한 환경을 구성하기 위해 만들어진 가상의 공간입니다.</p>
</blockquote>
<h3 id="도커-이미지docker-image">도커 이미지(Docker Image)</h3>
<blockquote>
<p><strong>도커 이미지</strong>는 도커 컨테이너의 전 단계로, 컨테이너를 생성하고 실행하기 위한 모든 것을 포함합니다.
예를 들어 컨테이너 생성에 필요한 파일, 환경, 변수, 명령어 등과 파일 시스템이 있습니다.
자신만의 이미지를 만들거나 다른 사람이 만든 이미지를 사용할 수도 있습니다.</p>
</blockquote>
<p>이미지를 생성항려면 <strong>Dockerfile</strong>을 작성하고 이미지를 빌드해야 합니다.
Dockerfile은 이미지를 빌드하는 데 단계적으로 필요한 명령어가 있는 파일입니다.</p>
<blockquote>
<p>도커 이미지에는 태그(Tag)를 붙일 수 있습니다.
태크를 붙이는 것은 하나의 이미지에 여러 개의 별명을 붙여 주는 것과 같습니다.
주로 이미지의 버전을 지정하기 위해 사용합니다.</p>
</blockquote>
<h3 id="도커-컨테이너docer-container">도커 컨테이너(Docer Container)</h3>
<blockquote>
<p><strong>도커 컨테이너</strong>는 도커 이미지로부터 만들어진 실행 가능한 인스턴스입니다.
다르게 말하면, 실행 중인 이미지를 컨테이너라고 합니다.
컨테이너는 도커 이미지와 사용자가 컨테이너를 시작할 때 작성하는 옵션에 의해 정의됩니다.
컨테이너를 실행하는 동안은 분리된 파일 시스템을 사용합니다.</p>
</blockquote>
<h3 id="도커-레지스트리docker-registry">도커 레지스트리(Docker Registry)</h3>
<blockquote>
<p><strong>도커 레지스트리</strong>는 도커 이미지를 저장하는 저장소입니다.
도커의 공식 레지스트리로 <a href="https://hub.docker.com/">Dokcer Hub</a>가 있습니다.
누구나 레지스트리에 도커 이미지를 올리고, 존재하는 도커 이미지를 가져올 수 있습니다.</p>
</blockquote>
<h3 id="도커를-쓰는-이유">도커를 쓰는 이유</h3>
<blockquote>
<p>CTF 혹은 워게임 문제에 종종 Dockerfile이 제공되는 경우가 있습니다.
이 경우, 제공되는 Dockerfile을 빌드하고 컨테이너를 실행하면 문제 환경을 똑같이 재현하여 풀 수 있습니다. </p>
</blockquote>
<p>문제에서 Dockerfile을 제공하여 도커를 사용할 수 있도록 하는 이유는 무엇일까요?</p>
<ul>
<li>도커가 없다면 VirtualBox와 같은 가상 머신을 설치하여 직접 문제 환경을 구축해야 합니다.</li>
<li>VM을 사용하면 설치하는 데 시간이 오래 걸리고 과정도 복잡합니다.</li>
<li>문제마다 환경을 구성해야 할 수도 있는데, 가상 머신은 용량이 매우 크고 무거워서 동시에 여러 개를 실행하기 어렵습니다.</li>
<li>뿐만 아니라, 풀이자가 직접 가상 환경을 구축하면 출제자가 의도한 환경에서 벗어날 수도 있습니다.</li>
<li>특히 시스템 해킹의 경우 정교한 공격을 위해 똑같은 환경에서 바이너리를 디버깅하고 익스플로잇하는 것이 중요합니다.<blockquote>
<br></blockquote>
</li>
<li>도커 컨테이너는 가상 환경 구축의 많은 부분을 생략하고 가볍게 실행되어, 매우 간편하게 문제 환경을 재현합니다.</li>
<li>또한, 문제 환경과 거의 동일한 환경을 제공하여 문제 풀이에 방해가 되는 요소를 줄입니다.<blockquote>
<br></blockquote>
</li>
<li>CTF의 경우 같은 서버에서 여러 문제를 제공하면 공격 과정에서 다른 문제에 영향을 미치거나, 출제자가 의도하지 않은 공격을 수행할 수도 있습니다.</li>
<li>도커는 문제가 각각 분리된 환경에 있는 것처럼 제공하여 이를 막습니다.</li>
</ul>
<h2 id="도커-명령어">도커 명령어</h2>
<ul>
<li>자주 사용하는 도커 명령어를 소개합니다.</li>
<li>더 많은 명령어와 옵션에 대한 자세한 설명은 <a href="https://docs.docker.com/reference/cli/docker/">도커 공식 문서</a>에서 확인할 수 있습니다.</li>
</ul>
<h3 id="ㅁdocker-build">ㅁdocker build</h3>
<blockquote>
<p>Dockerfile을 이용하여 이미지를 생성합니다.</p>
</blockquote>
<ul>
<li><strong>docker build [옵션] &lt;경로&gt;</strong></li>
<li><strong>docker build -t &lt;이미지명:태그&gt; &lt;경로&gt;</strong><blockquote>
</blockquote>
</li>
<li><em>-t*</em> 옵션으로 이미지의 이름과 태그를 지정할 수 있습니다.
태그를 작성하지 않을 경우 &#39;latest&#39;로 지정됩니다.<blockquote>
</blockquote>
➡️ <strong>docker build .</strong> : 현재 디렉토리에 있는 Dockerfile로 이미지 생성
➡️ <strong>docker build -t my-image .</strong> : 현재 디렉토리에 있는 Dockerfile로 ‘my-image:latest’ 이미지 생성</li>
</ul>
<h3 id="ㅁ-docker-images">ㅁ docker images</h3>
<blockquote>
<p>도커 이미지 목록을 출력합니다.
아래는 미리 준비된 Dockerfile을 이용해서 <strong>docker build</strong> 명령어로 이미지를 빌드 후, <strong>docker images</strong> 명령어로 출력하는 모습입니다.</p>
</blockquote>
<pre><code class="language-c">user@user-VirtualBox:~/Desktop/ex-docker$ docker build .
[+] Building 27.1s (17/17) FINISHED                                             
 =&gt; [internal] load build definition from Dockerfile                       0.0s                                         
 =&gt; ...생략...
 =&gt; exporting to image                                                     0.0s
 =&gt; =&gt; exporting layers                                                    0.0s
 =&gt; =&gt; writing image sha256:08a83756c396b9ca5d83735153cf0176056fb23c3eb3c  0.0s
user@user-VirtualBox:~/Desktop/ex-docker$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
&lt;none&gt;       &lt;none&gt;    9d201c4de2b6   2 minutes ago   122MB
user@user-VirtualBox:~/Desktop/ex-docker$ docker build -t my-image:1 .
[+] Building 0.8s (17/17) FINISHED                                              
 =&gt; ...생략...
 =&gt; exporting to image                                                     0.0s
 =&gt; =&gt; exporting layers                                                    0.0s
 =&gt; =&gt; writing image sha256:9d201c4de2b62519383058265e31669b167c422502643  0.0s
 =&gt; =&gt; naming to docker.io/library/my-image:1                              0.0s
user@user-VirtualBox:~/Desktop/ex-docker$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
my-image     1         9d201c4de2b6   4 minutes ago   122MB</code></pre>
<h3 id="ㅁ-docker-run">ㅁ docker run</h3>
<blockquote>
<p>도커 이미지로 컨테이너를 생성하고 실행합니다.</p>
</blockquote>
<ul>
<li><strong>docker run [옵션] &lt;이미지명|ID&gt; [명령어]</strong></li>
<li><strong>docker run -p &lt;호스트 PORT&gt;:&lt;컨테이너 PORT&gt;&lt;이미지명|ID&gt;</strong><blockquote>
</blockquote>
</li>
<li><em>-P*</em> 옵션은 도커 컨테이너의 포트와 호스트의 포트를 매핑합니다.
컨테이너에서 리슨하고 있는 포트를 호스트의 특정 포트로 접속할 수 있도록 합니다.</li>
<li><strong>docker run -it &lt;이미지명|ID&gt; &lt;명령어&gt;</strong><blockquote>
</blockquote>
</li>
<li><em>-it*</em> 옵션으로 컨테이너에서 bash 셸을 사용할 수 있습니다.</li>
<li><em>-i (--interactive)*</em>는 표준 입력을 활성화하여 사용자가 명령어를 입력할 수 있도록 하고, <strong>-t (--tty)</strong>는 가상 터미널(tty)을 사용할 수 있도록 합니다.<blockquote>
<br>
➡️ **docker run -it my-image:1 /bin/bash : my-image:1** 이미지로 컨테이너를 생성하고 실행하여 bash 셸 열기
</blockquote>
<pre><code class="language-c">user@user-VirtualBox:~/Desktop/ex-docker$ docker run -it my-image:1 /bin/bash
chall@852bb2be037c:~$ </code></pre>
</li>
</ul>
<h3 id="ㅁ-docker-ps">ㅁ docker ps</h3>
<blockquote>
<p>실행 중인 컨테이너 목록을 출력합니다.</p>
</blockquote>
<ul>
<li><strong>docker ps -a</strong><blockquote>
</blockquote>
</li>
<li><em>-a*</em> 옵션은 종료된 컨테이너까지 모두 출력합니다.<br></li>
<li>컨테이너를 실행한 상태로 다른 터미널 창을 열어 <strong>docker ps</strong>를 입력하면 아래와 같이 실행 중인 컨테이너 목록이 출력됩니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/2c86c132-174b-4f0e-a67a-24ddea70020c/image.png" alt=""></li>
<li>컨테이너 안에서 <strong>exit</strong> 명령어를 실행하여 컨테이너를 종료한 후 <strong>docker ps</strong>를 입력하면 컨테이너가 출력되지 않고, <strong>docker ps -a</strong>를 입력하면 종료된 컨테이너까지 출력됩니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/44c1dc7d-013d-47f3-a8c7-09731d640fa8/image.png" alt=""></li>
</ul>
<p><u>docker run 대신, 컨테이너 생성과 실행을 따로 명령할 수도 있습니다.</u></p>
<h3 id="ㅁ-docker-create">ㅁ docker create</h3>
<blockquote>
<p>도커 이미지로 컨테이너를 생성합니다.
-** docker create [옵션] &lt;이미지명|ID&gt; [명령어]**</p>
</blockquote>
<h3 id="ㅁ-docker-start">ㅁ docker start</h3>
<blockquote>
<p>중단된 컨테이너를 시작합니다.</p>
</blockquote>
<ul>
<li><strong>docker start [옵션] &lt;컨테이너명|ID&gt;</strong><pre><code class="language-c">user@user-VirtualBox:~$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
my-image     1         9d201c4de2b6   2 hours ago   122MB
user@user-VirtualBox:~$ docker create my-image:1
eb01688504dc201d9f3a03bf3a27d84cdeafca4b2110766d52fc7551a7d9d05a
user@user-VirtualBox:~$ docker ps -a
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS    PORTS     NAMES
eb01688504dc   my-image:1   &quot;/bin/sh -c &#39;socat -…&quot;   4 seconds ago   Created             priceless_meninsky
user@user-VirtualBox:~$ docker start eb01688504dc
eb01688504dc
user@user-VirtualBox:~$ docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS         PORTS      NAMES
eb01688504dc   my-image:1   &quot;/bin/sh -c &#39;socat -…&quot;   19 seconds ago   Up 4 seconds   2222/tcp   priceless_meninsky</code></pre>
</li>
</ul>
<h3 id="ㅁ-docker-exec">ㅁ docker exec</h3>
<blockquote>
<p>실행 중인 컨테이너에 접속하여 명령을 수행합니다. </p>
</blockquote>
<ul>
<li><strong>docker exec [옵션] &lt;컨테이너명|ID&gt; [명령어]</strong><blockquote>
</blockquote>
</li>
<li><em>docker run*</em>과 유사하게 <strong>-it</strong> 옵션으로 bash 셸을 실행할 수 있습니다. <br>
➡️ **docker exec -it <컨테이너명|ID> /bin/bash** : 실행 중인 컨테이너에서 bash 셸 열기
```c
1  user@user-VirtualBox:~$ docker exec -it eb01688504dc /bin/bash
2  chall@eb01688504dc:~$ 
```

</li>
</ul>
<h3 id="ㅁdocker-stop">ㅁdocker stop</h3>
<blockquote>
<p>실행 중인 컨테이너를 중단합니다.</p>
</blockquote>
<ul>
<li><strong>docker stop [옵션] &lt;컨테이너명|ID&gt;</strong></li>
</ul>
<h3 id="ㅁ-docker-pull">ㅁ docker pull</h3>
<blockquote>
<p>레지스트리(Docker Hub)에 존재하는 도커 이미지르 다운받습니다.</p>
</blockquote>
<ul>
<li>docker pull [옵션] &lt;이미지명&gt;<br>
➡️ **docker pull ubuntu:18.04** : Docker hub에서 ubuntu:18.04 이미지를 다운받습니다.
```c
user@user-VirtualBox:~$ docker pull ubuntu:18.04</li>
</ul>
<p>18.04: Pulling from library/ubuntu
0c5227665c11: Pull complete 
Digest: sha256:8aa9c2798215f99544d1ce7439ea9c3a6dfd82de607da1cec3a8a2fae005931b
Status: Downloaded newer image for ubuntu:18.04
docker.io/library/ubuntu:18.04</p>
<pre><code>
### ㅁ docker rm
&gt;도커 컨테이너를 삭제합니다.
- **docker rm [옵션] &lt;컨테이너명|ID&gt;**

### ㅁ docker rmi 
&gt;도커 이미지를 삭제합니다.
- **docker rmi [옵션] &lt;이미지명|ID&gt;**

### ㅁ docker inspect
&gt;도커 이미지 혹은 컨테이너의 자세한 정보를 출력합니다. 
- **docker inspect [옵션] &lt;이미지 혹은 컨테이너명|ID&gt;**
```c
user@user-VirtualBox:~$ docker inspect ubuntu:18.04
[
    {
        &quot;Id&quot;: &quot;sha256:3941d3b032a8168d53508410a67baad120a563df67a7959565a30a1cb2114731&quot;,
        &quot;RepoTags&quot;: [
            &quot;ubuntu:18.04&quot;
        ],
        &quot;RepoDigests&quot;: [
            &quot;ubuntu@sha256:8aa9c2798215f99544d1ce7439ea9c3a6dfd82de607da1cec3a8a2fae005931b&quot;
        ],
        &quot;Parent&quot;: &quot;&quot;,
        &quot;Comment&quot;: &quot;&quot;,
        &quot;Created&quot;: &quot;2023-03-08T03:22:44.73196058Z&quot;,
        &quot;Container&quot;: &quot;ee3fcc8c88d3f3129f1236850de28a7eba0da7c548a7b23a6495905ebcf255ea&quot;,
        &quot;ContainerConfig&quot;: {
            &quot;Hostname&quot;: &quot;ee3fcc8c88d3&quot;,
            &quot;Domainname&quot;: &quot;&quot;,
            &quot;User&quot;: &quot;&quot;,
            &quot;AttachStdin&quot;: false,
            &quot;AttachStdout&quot;: false,
            &quot;AttachStderr&quot;: false,
            &quot;Tty&quot;: false,
            &quot;OpenStdin&quot;: false,
            &quot;StdinOnce&quot;: false,
            &quot;Env&quot;: [
                &quot;PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin&quot;
            ],
            &quot;Cmd&quot;: [
                &quot;/bin/sh&quot;,
                &quot;-c&quot;,
                &quot;#(nop) &quot;,
                &quot;CMD [\&quot;/bin/bash\&quot;]&quot;
            ],
            &quot;Image&quot;: &quot;sha256:b64649bc9d1a48300ec5a929146aa3c5ca80046f74c33aa5de65a7046f5177a6&quot;,
            &quot;Volumes&quot;: null,
            &quot;WorkingDir&quot;: &quot;&quot;,
            &quot;Entrypoint&quot;: null,
            &quot;OnBuild&quot;: null,
            &quot;Labels&quot;: {
                &quot;org.opencontainers.image.ref.name&quot;: &quot;ubuntu&quot;,
                &quot;org.opencontainers.image.version&quot;: &quot;18.04&quot;
            }
        },
        &quot;DockerVersion&quot;: &quot;20.10.12&quot;,
        &quot;Author&quot;: &quot;&quot;,
        &quot;Config&quot;: {
            &quot;Hostname&quot;: &quot;&quot;,
            &quot;Domainname&quot;: &quot;&quot;,
            &quot;User&quot;: &quot;&quot;,
            &quot;AttachStdin&quot;: false,
            &quot;AttachStdout&quot;: false,
            &quot;AttachStderr&quot;: false,
            &quot;Tty&quot;: false,
            &quot;OpenStdin&quot;: false,
            &quot;StdinOnce&quot;: false,
            &quot;Env&quot;: [
                &quot;PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin&quot;
            ],
            &quot;Cmd&quot;: [
                &quot;/bin/bash&quot;
            ],
            &quot;Image&quot;: &quot;sha256:b64649bc9d1a48300ec5a929146aa3c5ca80046f74c33aa5de65a7046f5177a6&quot;,
            &quot;Volumes&quot;: null,
            &quot;WorkingDir&quot;: &quot;&quot;,
            &quot;Entrypoint&quot;: null,
            &quot;OnBuild&quot;: null,
            &quot;Labels&quot;: {
                &quot;org.opencontainers.image.ref.name&quot;: &quot;ubuntu&quot;,
                &quot;org.opencontainers.image.version&quot;: &quot;18.04&quot;
            }
        },
        &quot;Architecture&quot;: &quot;amd64&quot;,
        &quot;Os&quot;: &quot;linux&quot;,
        &quot;Size&quot;: 63146040,
        &quot;VirtualSize&quot;: 63146040,
        &quot;GraphDriver&quot;: {
            &quot;Data&quot;: {
                &quot;MergedDir&quot;: &quot;/var/lib/docker/overlay2/0fe24c66cfaad338ccd55946d7734702a3575513fb2e697b409d3194c95c7e62/merged&quot;,
                &quot;UpperDir&quot;: &quot;/var/lib/docker/overlay2/0fe24c66cfaad338ccd55946d7734702a3575513fb2e697b409d3194c95c7e62/diff&quot;,
                &quot;WorkDir&quot;: &quot;/var/lib/docker/overlay2/0fe24c66cfaad338ccd55946d7734702a3575513fb2e697b409d3194c95c7e62/work&quot;
            },
            &quot;Name&quot;: &quot;overlay2&quot;
        },
        &quot;RootFS&quot;: {
            &quot;Type&quot;: &quot;layers&quot;,
            &quot;Layers&quot;: [
                &quot;sha256:b7e0fa7bfe7f9796f1268cca2e65a8bfb1e010277652cee9a9c9d077a83db3c4&quot;
            ]
        },
        &quot;Metadata&quot;: {
            &quot;LastTagTime&quot;: &quot;0001-01-01T00:00:00Z&quot;
        }
    }
]</code></pre><hr>
<hr>
<hr>
<h1 id="출처-및-참고자료">출처 및 참고자료</h1>
<h1 id="httpslearndreamhackio4599"><a href="https://learn.dreamhack.io/459#9">https://learn.dreamhack.io/459#9</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬[7일차]]]></title>
            <link>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC7%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC7%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 17 Dec 2024 07:16:29 GMT</pubDate>
            <description><![CDATA[<details>
  <summary>참고</summary>
  <div><span style="color:blue">참고 자료는 점프 투 파이썬으로 선택했습니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</details>

<h2 id="while-문">while 문</h2>
<blockquote>
<p>문장을 반복해서 수행해야 할 경우 while 문을 사용한다. 그래서 while문을 &#39;반복문&#39;이라고도 부른다.</p>
</blockquote>
<h3 id="while-문의-기본구조">while 문의 기본구조</h3>
<blockquote>
<p>다음은 while 문의 기본 구조이다.</p>
</blockquote>
<pre><code class="language-python">while 조건문:
    수행할_문장1
    수행할_문장2
    수행할_문장3
    ...</code></pre>
<p>while 문은 조건문이 참인 동안 while 문에 속한 문장들이 반복해서 수행된다.</p>
<blockquote>
<p>‘열 번 찍어 안 넘어가는 나무 없다’라는 속담을 파이썬 프로그램으로 만들면 다음과 같다.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; treeHit = 0
&gt;&gt;&gt; while treeHit &lt; 10:
...     treeHit = treeHit +1
...     print(&quot;나무를 %d번 찍었습니다.&quot; % treeHit)
...     if treeHit == 10:
...         print(&quot;나무 넘어갑니다.&quot;)
...
나무를 1번 찍었습니다.
나무를 2번 찍었습니다.
나무를 3번 찍었습니다.
나무를 4번 찍었습니다.
나무를 5번 찍었습니다.
나무를 6번 찍었습니다.
나무를 7번 찍었습니다.
나무를 8번 찍었습니다.
나무를 9번 찍었습니다.
나무를 10번 찍었습니다.
나무 넘어갑니다.</code></pre>
<blockquote>
</blockquote>
<ul>
<li>위 예에서 while 문의 조건문은 <span style="background-color:grey;color:orange">$$treeHit&lt;10$$</span>이다.</li>
<li>즉, treeHit가 10보다 작은 동안 while 문에 포함된 문장들을 계속 수행한다.</li>
<li>while 문 안의 문장을 보면 가장 먼저 <span style="background-color:grey;color:orange">treeHit = treeHit + 1</span>로 treeHit 값이 계속 1씩 증가한다는 것을 알 수 있다.</li>
<li>그리고 나무를 treeHit번만큼 찍었다는 것을 알리는 문장을 출력하고 treeHit가 10이 되면 &quot;나무 넘어갑니다.&quot;라는 문장을 출력한다.</li>
<li>그러고 나면 <span style="background-color:grey;color:orange">$$treeHit &lt; 10$$</span> 조건문이 거짓이 되므로 while 문을 빠져나가게 된다.</li>
</ul>
<blockquote>
<p>treeHit = treeHit + 1은 프로그래밍을 할 때 매우 자주 사용하는 기법이다.
treeHit 값을 1만큼씩 증가시킬 목적으로 사용하며 treeHit += 1처럼 작성해도 된다.</p>
</blockquote>
<h3 id="while-문-만들기">while 문 만들기</h3>
<p>ㅇ 이번에는 여러 가지 선택지 중 하나를 선택해서 입력받는 예제를 만들어 보자</p>
<blockquote>
<ul>
<li>먼저 다음과 같이 여러 줄짜리 문자열을 만들자</li>
</ul>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; prompt = &quot;&quot;&quot;
... 1. Add
... 2. Del
... 3. List
... 4. Quit
...
... Enter number: &quot;&quot;&quot;
&gt;&gt;&gt;</code></pre>
<ul>
<li>이어서 number 변수에 0을 먼저 대입한다.</li>
<li>이렇게 변수를 먼저 설정해 놓지 않으면 다음에 나올 while 문의 조건문인 <span style="background-color:grey;color:orange">number != 4</span> 에서 변수가 존재하지 않는다는 오류가 발생한다.</li>
</ul>
<blockquote>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; number = 0
&gt;&gt;&gt; while number != 4:
...     print(prompt)
...     number = int(input())
...
&gt;
1. Add
2. Del
3. List
4. Quit
&gt;
Enter number:</code></pre>
<ul>
<li>while 문을 보면 number가 4가 아닌 동안 prompt를 출력하고 사용자로부터 번호를 입력받는다.</li>
<li>다음 결과 화면처럼 사용자가 값 4를 입력하지 않으면 계속해서 prompt를 출력한다.<blockquote>
<blockquote>
<p>여기에서 <strong>number = int(input())</strong>는 사용자의 숫자 입력을 받아들이는 것이라고만 알아 두자. int나 input 함수에 대한 내용은 뒤에 나오는 내장 함수 부분에서 자세하게 다룬다.</p>
</blockquote>
</blockquote>
</li>
</ul>
<h3 id="while-문-강제로-빠져나가기">while 문 강제로 빠져나가기</h3>
<p>ㅇ 다음 예는 커피 자판기 이야기를 파이썬 프로그램으로 표현해 본 것이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; coffee = 10
&gt;&gt;&gt; money = 300
&gt;&gt;&gt; while money:
...     print(&quot;돈을 받았으니 커피를 줍니다.&quot;)
...     coffee = coffee -1
...     print(&quot;남은 커피의 양은 %d개입니다.&quot; % coffee)
...     if coffee == 0:
...         print(&quot;커피가 다 떨어졌습니다. 판매를 중지합니다.&quot;)
...         break
...</code></pre>
<blockquote>
<p>money가 300으로 고정되어 있고 <strong>while money:</strong>에서 조건문인 money는 0이 아니기 때문에 항상 참이다.</p>
</blockquote>
<ul>
<li>따라서 무한히 반복되는 무한 루프를 돌게 된다.</li>
<li>그리고 while 문의 내용을 한 번 수행할 때마다 coffee = coffee - 1에 의해 coffee의 개수가 1개씩 줄어든다.</li>
<li>만약 coffee가 0이 되면 if coffee == 0: 문장에서 coffee == 0이 참이 되므로 if 문 다음 문장 &quot;커피가 다 떨어졌습니다. 판매를 중지합니다.&quot;가 출력되고 break 문이 호출되어 while 문을 빠져나가게 된다.<br></li>
<li>하지만 실제 자판기는 위 예처럼 작동하지는 않을 것이다.</li>
<li>다음은 자판기의 실제 작동 과정과 비슷하게 만들어 본 예이다.</li>
<li>다음 예는 조금 복잡하므로 대화형 인터프리터를 사용하지 말고 IDLE 에디터를 사용해서 작성해 보자.</li>
</ul>
<pre><code class="language-python"># coffee.py
coffee = 10
while True:
    money = int(input(&quot;돈을 넣어 주세요: &quot;))
    if money == 300:
        print(&quot;커피를 줍니다.&quot;)
        coffee = coffee -1
    elif money &gt; 300:
        print(&quot;거스름돈 %d를 주고 커피를 줍니다.&quot; % (money -300))
        coffee = coffee -1
    else:
        print(&quot;돈을 다시 돌려주고 커피를 주지 않습니다.&quot;)
        print(&quot;남은 커피의 양은 %d개 입니다.&quot; % coffee)
    if coffee == 0:
        print(&quot;커피가 다 떨어졌습니다. 판매를 중지 합니다.&quot;)
        break</code></pre>
<blockquote>
<p>이제 coffee.py 파일을 저장한 후 명령 프롬프트 창을 열어 프로그램을 직접 실행해 보자.
<br>
다음과 같은 입력란이 나타난다.</p>
</blockquote>
<pre><code class="language-cmd">C:\doit&gt;python coffee.py
돈을 넣어 주세요:</code></pre>
<ul>
<li>입력란에 여러 숫자를 입력해 보면서 결과를 확인하자.<pre><code class="language-cmd">돈을 넣어 주세요: 500
거스름돈 200를 주고 커피를 줍니다.
돈을 넣어 주세요: 300
커피를 줍니다.
돈을 넣어 주세요: 100
돈을 다시 돌려주고 커피를 주지 않습니다.
남은 커피의 양은 8개입니다.
돈을 넣어 주세요:</code></pre>
</li>
</ul>
<h3 id="while-문의-맨-처음으로-돌아가기">while 문의 맨 처음으로 돌아가기</h3>
<blockquote>
<ul>
<li>while 문 안의 문장을 수행할 때 입력 조건을 검사해서 조건에 맞지 않으면 while 문을 빠져나간다.</li>
</ul>
</blockquote>
<ul>
<li>그런데 프로그래밍을 하다 보면 while 문을 빠져나가지 않고 while 문의 맨 처음(조건문)으로 다시 돌아가게 만들고 싶은 경우가 생기게 된다.</li>
<li>이때 사용하는 것이 바로 continue 문이다.<br></li>
<li>1부터 10까지의 숫자 중에서 홀수만 출력하는 것을 while 문을 사용해서 작성한다고 생각해 보자. 어떤 방법이 좋을까?<pre><code class="language-python">&gt;&gt;&gt; a = 0
&gt;&gt;&gt; while a &lt; 10:
...        a = a + 1
...        if a % 2 == 0: continue
...     print(a)
...
1
3
5
7
9</code></pre>
</li>
<li>위는 1부터 10까지의 숫자 중 홀수만 출력하는 예이다.</li>
<li>a가 10보다 작은 동안 a는 1만큼씩 계속 증가한다.</li>
<li>a % 2 == 0(a를 2로 나누었을 때 나머지가 0인 경우)이 참이 되는 경우는 a가 짝수일 때이다.</li>
<li>즉, a가 짝수이면 continue 문을 수행한다.</li>
<li>이 continue 문은 while 문의 맨 처음인 조건문(a &lt; 10)으로 돌아가게 하는 명령어이다.</li>
<li>따라서 위 예에서 a가 짝수이면 print(a) 문장은 수행되지 않을 것이다.</li>
</ul>
<h3 id="무한-루프">무한 루프</h3>
<blockquote>
<p>이번에는 무한 루프(endless loop)에 대해 알아보자. 무한 루프란 무한히 반복한다는 의미이다. 우리가 사용하는 일반 프로그램 중에서 무한 루프 개념을 사용하지 않는 프로그램은 거의 없다. 그만큼 자주 사용한다는 뜻이다.</p>
</blockquote>
<ul>
<li><p>파이썬에서 무한 루프는 while 문으로 구현할 수 있다. 다음은 무한 루프의 기본 형태이다.</p>
<pre><code class="language-python">while True: 
  수행할_문장1 
  수행할_문장2
  ...</code></pre>
</li>
<li><p>while 문의 조건문이 True이므로 항상 참이 된다. 따라서 while 문 안에 있는 문장들은 무한히 수행될 것이다.</p>
</li>
<li><p>다음은 무한 루프의 예이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; while True:
...     print(&quot;Ctrl+C를 눌러야 while문을 빠져나갈 수 있습니다.&quot;)
...
Ctrl+C를 눌러야 while문을 빠져나갈 수 있습니다.
Ctrl+C를 눌러야 while문을 빠져나갈 수 있습니다.
Ctrl+C를 눌러야 while문을 빠져나갈 수 있습니다.
....</code></pre>
</li>
<li><p>위 문장은 영원히 출력된다. 하지만 이 예처럼 아무 의미 없이 무한 루프를 돌리는 경우는 거의 없을 것이다. <strong>[Ctrl+C]</strong>를 눌러 빠져나가자.</p>
</li>
</ul>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고문헌">출처 및 참고문헌</h1>
<h1 id="httpswikidocsnet21"><a href="https://wikidocs.net/21">https://wikidocs.net/21</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[CTF[7일차]]]></title>
            <link>https://velog.io/@pingu_9/CTF7%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/CTF7%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 17 Dec 2024 01:39:31 GMT</pubDate>
            <description><![CDATA[<blockquote>
<details>
  <summary>참고</summary>
  <div><span style="color:blue">
※참고 자료는 드림핵을 이용하였습니다.<br>
※드림핵의 로드맵대로 공부할 예정입니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</blockquote>
</details>

<h1 id="system-hacking101">System Hacking101</h1>
<h2 id="system-hacking">System Hacking</h2>
<blockquote>
<ul>
<li><strong>시스템 해킹(System Hacking)</strong>은 컴퓨터 프로그램의 행위를 조작하여 공격자가 원하는 행동을 실행하도록 하는 공격 전반을 일컫습니다.</li>
</ul>
</blockquote>
<ul>
<li>&#39;시스템 해킹&#39;은 컴퓨터에서 구동되는 모든 프로그램에 대한 해킹에 적용 가능한 말입니다.
<br><br></li>
<li>System Hacking 관련 강의에서 보게 되는 취약한 프로그램들은 대부분 C언어로 구현되었습니다.</li>
<li>C언어는 효율성과 유연함에 큰 강점이 있어 다양한 애플리케이션을 구현하는데 사용됩니다.</li>
<li>여기서는 운영체제, 게임 등 굉장히 복잡한 프로그램도 포함됩니다.<ul>
<li>그렇기에, 시스템 프로그래밍 및 시스템 해킹을 공부하고자 한다면 C언어를 먼저 배우는걸 권장합니다.
<br><br></li>
</ul>
</li>
<li>드림핵의 System Hacking 강의는 C 언어 기반 프로그램에서 발생할 수 있는 취약점에 대한 기본적인 지식과 이를 이해하기 위한 배경 지식을 설명하는 것을 목표로 합니다.</li>
<li>여기에는 프로그램이 <strong>시스템 상에서 작동하는 방식</strong>, 프로그램을 <strong>분석하는데 필요한 도구</strong>, <strong>취약점의 유형</strong> 및 이를 <strong>공략하는(익스플로잇하는) 방법론</strong>에 대한 설명이 포함되어 있습니다.
<br><br></li>
<li>시스템 해킹을 공부할 때는 시작하는 과정이 가장 어려운 단계 중 하나입니다. 요구하는 배경 지식의 범주가 상당히 넓은 편이기 때문입니다.
<br><br></li>
<li>예를 들어, 가장 기초적인 취약점인 스택 버퍼오버플로우(Stack Buffer Overflow)를 이해하려면 assembly 레벨에서의 메모리 사용과 같은 시스템 프로그래밍 관련 지식을 요구합니다.
<br><br></li>
<li>시스템 해킹의 목표는 통상적으로 <strong>공격 대상 프로그램이 구동되는 서버의 임의 유저와 같은 권한을 획득하는 것</strong>입니다. 원격 환경에 있는 공격자가 타겟 서버에서 운영체제의 명령어를 실행할 수 있는 공격을 원격코드실행(Remote Code Execution)이라고 부릅니다.</li>
</ul>
<h2 id="강의-수강에-필요한-사전-지식">강의 수강에 필요한 사전 지식</h2>
<blockquote>
<p>시스템 해킹을 잘하기 위해서 C 언어가 컴파일 된 이후에 어떤 방식으로 동작하는지 이해하고 있어야 합니다. 따라서, 시스템 해킹을 공부하기에 앞서 C 언어를 배워야 합니다. 하지만 <strong>얼마나 자세하게 C 언어를 공부하고 이해해야 하는지에 대한 척도</strong>는 가늠하기 어렵습니다.
<br>
드림핵의 시스템 해킹 강의는 가능한 적은 사전 지식을 요구하는 형태로 구성되었습니다. 그럼에도, 원활한 강의 수강과 실습을 위해 C 언어에 대한 기본 지식은 필요하기 때문에, 리버싱 엔지니어링 강의를 수강한 후 시스템 해킹 강의를 수강하기를 권장합니다.</p>
</blockquote>
<blockquote>
<ul>
<li><u>아래는 간단한 C 코드입니다.</u></li>
</ul>
</blockquote>
<pre><code class="language-c">#include &lt;stdio.h&gt;
&gt;
void fun (int x, int y)
{
    int z;    
    char buf[100];
&gt;    
    z = x;
    read (0, buf, y);
&gt;
    printf (&quot;x is %d\n&quot;, x);
    //printf (“z is %d\n”, z);
}
&gt;
int main (int argc, char* argv[])
{
    int a, b;
    a = 30;
    b = 300;
&gt;
    fun (a,b);
}</code></pre>
<blockquote>
</blockquote>
<p><u>코드를 이해한 후 아래 체크리스트를 확인해 보세요.</u></p>
<ol>
<li>위 코드가 실행 되었을 때, 프로그램이 어떻게 동작할지 예상할 수 있다</li>
<li>calling convention이 무엇인지 설명할 수 있다.</li>
<li>stack frame이 무엇인지 설명할 수 있다.</li>
<li>register가 무엇인지 설명할 수 있으며, C 코드가 진행됨에 따라 레지스터 값들이 어떻게 변할지 유추할 수 있다.</li>
<li>시작 시점부터 종료 시점까지 main 함수의 stack의 변화를 설명할 수 있다</li>
<li>32bit 프로그램일 때와 64bit 프로그램일 때 stack 값들의 차이점을 설명할 수 있다.</li>
<li>fun 함수의 취약한 부분이 무엇인지 찾을 수 있다.</li>
<li>fun 함수의 취약점으로 인해 32bit와 64bit환경에서 x의 출력값이 어떻게 달라지는지 설명할 수 있다.</li>
<li>x가 아닌 z를 출력하는 경우, 32bit와 64bit환경에서 z의 출력값이 어떻게 달라지는지 설명할 수 있다.</li>
<li>Figure 1을 컴파일한 바이너리가 주어졌을 때, 이를 익스플로잇하여 셸(shell)을 획득하는 공격 코드를 작성할 수 있다.</li>
<li>위 문항 중 체크할 수 있는 답변이 없다</li>
</ol>
<blockquote>
<ul>
<li>위 문항 중 11번만 체크할 수 있다면 리버싱 엔지니어링 강의를 우선적으로 수강해야 합니다.</li>
</ul>
</blockquote>
<ul>
<li>1번만 체크할 수 있다면, 시스템 해킹 강의를 수강하며 2~6번에 해당하는 키워드를 중심으로 공부를 진행하면 됩니다.</li>
<li>해당 키워드를 모두 이해했다면, 강의를 통해  7~10번 내용을 학습하며 본격적으로 시스템 해킹을 이해할 수 있습니다.</li>
</ul>
<h1 id="reverse-engineering">Reverse Engineering</h1>
<h2 id="reverse-engineering-1">Reverse Engineering</h2>
<blockquote>
<p><strong>리버스 엔지니어링(Reverse Engineering)</strong>은 줄여서 <strong>리버싱</strong>으로도 부릅니다.</p>
</blockquote>
<ul>
<li>이름에서 알 수 있듯이 리버스 엔지니어링은 무언가를 설계하고 제작하는 &#39;엔지니어링&#39; 과정을 정반대로 수행하는 것입니다.</li>
<li>컴퓨터 프로그래밍적 관점에서는 개발자가 소스 코드를 작성하고, 컴파일한 산출물에서부터 시작하는 것입니다.</li>
<li>프로그램의 동작을 직접 실행 시켜보면서 소스 코드의 내용을 <strong>추측</strong>하는 것도 가능한 방법이고, 컴파일된 결과물의 데이터를 분석하여 소스 코드의 내용을 <strong>유추, 복구</strong> 해볼 수도 있습니다.
<br><br></li>
<li>위에서 언급한 산출물을 흔히 &#39;프로그램&#39; 또는 &#39;이진 파일&#39; 이라고 부릅니다.</li>
<li>컴파일 되지 않은 코드 역시 &#39;프로그램&#39;이라고 부르는 경우가 있어 &#39;이진 파일&#39;이 조금 더 보편적으로 사용됩니다.</li>
<li>이진 파일은 사람이 눈으로 식별하기 어려운 데이터로 이루어져 있어, 단순히 이 데이터 값을 본다고 해서 어떤 동작을 하는지 알아내기가 어렵습니다.
<br><br></li>
<li>이를 도와주는 것이 &#39;디스어셈블러(disassembler)&#39;, &#39;디컴파일러(decompiler)&#39;와 같은 도구입니다.</li>
<li>사람이 식별하기 어려운 데이터를, 보다 알아보기 쉬운 형태로 변형 시켜주는 역할을 합니다.
<br><br></li>
<li>사람이 알아볼 수 있는 프로그래밍 언어로 이루어진 프로그램을 분석하는 것도 리버싱이라고 부를 수 있을까요? 물론 그렇습니다.</li>
<li>아무리 읽고 이해할 수 있는 텍스트로 이루어져 있다고 해도 단순히 살펴보는 것만으로는 프로그램의 전체 구조와 설계자의 의도를 이해할 수 없습니다.</li>
<li>그렇기 때문에 ‘분석하는 데이터의 형태가 식별 가능한지’가 리버싱인지 아닌지를 결정하지는 않습니다.
<br><br></li>
<li>리버스 엔지니어링 강의는 시스템 해킹, 웹 해킹 카테고리에 비해 강의 수가 적습니다.</li>
<li>그 이유는, 다른 강의에서 실습 문제를 분석하는 과정도 하나의 리버싱이기 때문입니다.</li>
<li>간단하게 정리하면 리버싱은 &#39;해킹&#39;이면서 동시에 &#39;분석&#39;을 하는 분야입니다.</li>
</ul>
<h2 id="강의-수강에-필요한-사전-지식-1">강의 수강에 필요한 사전 지식</h2>
<blockquote>
<p>첫째로, 리버스 엔지니어링을 통해 프로그램의 동작을 이해하기 위해서는 해당 프로그램을 구성하는 프로그래밍 언어를 이해할 수 있어야 합니다.</p>
</blockquote>
<ul>
<li>예를 들어, C 언어로 소스 코드를 작성하고 컴파일한 프로그램은 아무리 사람에게 편한 형태로 복구되어도 C 언어가 최대치입니다.</li>
<li>따라서 C 언어를 모른다면 이를 위한 디컴파일러의 동작은 효과를 보기 어렵습니다.
<br><br>
둘째로, x86 assembly를 읽고 이해할 수 있으면 좋습니다. 물론 x86 assembly에 대한 강의도 존재하기에 처음부터 숙지해야 할 필요는 없습니다.</li>
<li>어셈블리어가 한 종류만 있는 것은 아니지만 기본적으로 복잡하게 구성된 x86 assembly를 이해할 수 있다면 다른 아키텍쳐의 어셈블리어는 보다 손쉽게 습득하실 수 있습니다.</li>
<li>어셈블리어를 이해한다는 말은, 프로그램이 low-level에서 메모리를 어떤 방식으로 사용하는지 이해하고 있다는 말과 같습니다.</li>
<li>디컴파일러가 없는 환경에서 리버싱을 해야할 수도 있기 때문에 어셈블리어를 읽고 이해하는 능력은 앞으로 필수적입니다. </li>
</ul>
<blockquote>
</blockquote>
<pre><code class="language-c">예시 C코드
#include &lt;stdio.h&gt;
&gt;
int enc[17] = {75, 104, 111, 111, 114, 35, 71, 117, 104, 100, 112, 107, 100, 102, 110, 36, 3};
&gt;
int main(){
&gt;
    int key = 0;
    int dec[17];
&gt;
    for(int i=0; i&lt;17; i++){
        printf(&quot;%c&quot;, enc[i]);
    }
&gt;
    printf(&quot;\nYour input: &quot;);
    scanf(&quot;%d&quot;, &amp;key);
&gt;
    for(int i=0; i&lt;17; i++){
        dec[i] = enc[i] - key;
        printf(&quot;%c&quot;, dec[i]);
    }
    printf(&quot;\n&quot;);
&gt;
    return 0;
}</code></pre>
<ul>
<li>스스로 얼마나 준비가 되었는지 알아보기 위해 1) 위<strong>와 같이 C 언어로 작성된 간단한 소스코드</strong>와 2) <strong>아래와 같이 해당 소스코드의 실행파일을 disassemble한 어셈블리 코드</strong>를 준비했습니다. 두 코드를 보고 아래의 질문을 얼마나 답할 수 있는지 체크해보세요!<pre><code>예시 assembly 코드
Dump of assembler code for function main:
 0x00005555555551a9 &lt;+0&gt;:     endbr64 
 0x00005555555551ad &lt;+4&gt;:     push   rbp
 0x00005555555551ae &lt;+5&gt;:     mov    rbp,rsp
 0x00005555555551b1 &lt;+8&gt;:     sub    rsp,0x60
 0x00005555555551b5 &lt;+12&gt;:    mov    rax,QWORD PTR fs:0x28
 0x00005555555551be &lt;+21&gt;:    mov    QWORD PTR [rbp-0x8],rax
 0x00005555555551c2 &lt;+25&gt;:    xor    eax,eax
 0x00005555555551c4 &lt;+27&gt;:    mov    DWORD PTR [rbp-0x5c],0x0
 0x00005555555551cb &lt;+34&gt;:    mov    DWORD PTR [rbp-0x58],0x0
 0x00005555555551d2 &lt;+41&gt;:    jmp    0x5555555551f6 &lt;main+77&gt;
 0x00005555555551d4 &lt;+43&gt;:    mov    eax,DWORD PTR [rbp-0x58]
 0x00005555555551d7 &lt;+46&gt;:    cdqe   
 0x00005555555551d9 &lt;+48&gt;:    lea    rdx,[rax*4+0x0]
 0x00005555555551e1 &lt;+56&gt;:    lea    rax,[rip+0x2e38]        # 0x555555558020 &lt;enc&gt;
 0x00005555555551e8 &lt;+63&gt;:    mov    eax,DWORD PTR [rdx+rax*1]
 0x00005555555551eb &lt;+66&gt;:    mov    edi,eax
 0x00005555555551ed &lt;+68&gt;:    call   0x555555555080 &lt;putchar@plt&gt;
 0x00005555555551f2 &lt;+73&gt;:    add    DWORD PTR [rbp-0x58],0x1
 0x00005555555551f6 &lt;+77&gt;:    cmp    DWORD PTR [rbp-0x58],0x10
 0x00005555555551fa &lt;+81&gt;:    jle    0x5555555551d4 &lt;main+43&gt;
 0x00005555555551fc &lt;+83&gt;:    lea    rax,[rip+0xe01]        # 0x555555556004
 0x0000555555555203 &lt;+90&gt;:    mov    rdi,rax
 0x0000555555555206 &lt;+93&gt;:    mov    eax,0x0
 0x000055555555520b &lt;+98&gt;:    call   0x5555555550a0 &lt;printf@plt&gt;
 0x0000555555555210 &lt;+103&gt;:   lea    rax,[rbp-0x5c]
 0x0000555555555214 &lt;+107&gt;:   mov    rsi,rax
 0x0000555555555217 &lt;+110&gt;:   lea    rax,[rip+0xdf4]        # 0x555555556012
 0x000055555555521e &lt;+117&gt;:   mov    rdi,rax
 0x0000555555555221 &lt;+120&gt;:   mov    eax,0x0
 0x0000555555555226 &lt;+125&gt;:   call   0x5555555550b0 &lt;__isoc99_scanf@plt&gt;
 0x000055555555522b &lt;+130&gt;:   mov    DWORD PTR [rbp-0x54],0x0
 0x0000555555555232 &lt;+137&gt;:   jmp    0x55555555526f &lt;main+198&gt;
 0x0000555555555234 &lt;+139&gt;:   mov    eax,DWORD PTR [rbp-0x54]
 0x0000555555555237 &lt;+142&gt;:   cdqe   
 0x0000555555555239 &lt;+144&gt;:   lea    rdx,[rax*4+0x0]
 0x0000555555555241 &lt;+152&gt;:   lea    rax,[rip+0x2dd8]        # 0x555555558020 &lt;enc&gt;
 0x0000555555555248 &lt;+159&gt;:   mov    eax,DWORD PTR [rdx+rax*1]
 0x000055555555524b &lt;+162&gt;:   mov    ecx,DWORD PTR [rbp-0x5c]
 0x000055555555524e &lt;+165&gt;:   sub    eax,ecx
 0x0000555555555250 &lt;+167&gt;:   mov    edx,eax
 0x0000555555555252 &lt;+169&gt;:   mov    eax,DWORD PTR [rbp-0x54]
 0x0000555555555255 &lt;+172&gt;:   cdqe   
 0x0000555555555257 &lt;+174&gt;:   mov    DWORD PTR [rbp+rax*4-0x50],edx
 0x000055555555525b &lt;+178&gt;:   mov    eax,DWORD PTR [rbp-0x54]
 0x000055555555525e &lt;+181&gt;:   cdqe   
 0x0000555555555260 &lt;+183&gt;:   mov    eax,DWORD PTR [rbp+rax*4-0x50]
 0x0000555555555264 &lt;+187&gt;:   mov    edi,eax
 0x0000555555555266 &lt;+189&gt;:   call   0x555555555080 &lt;putchar@plt&gt;
 0x000055555555526b &lt;+194&gt;:   add    DWORD PTR [rbp-0x54],0x1
 0x000055555555526f &lt;+198&gt;:   cmp    DWORD PTR [rbp-0x54],0x10
 0x0000555555555273 &lt;+202&gt;:   jle    0x555555555234 &lt;main+139&gt;
 0x0000555555555275 &lt;+204&gt;:   mov    edi,0xa
 0x000055555555527a &lt;+209&gt;:   call   0x555555555080 &lt;putchar@plt&gt;
 0x000055555555527f &lt;+214&gt;:   mov    eax,0x0
 0x0000555555555284 &lt;+219&gt;:   mov    rdx,QWORD PTR [rbp-0x8]
 0x0000555555555288 &lt;+223&gt;:   sub    rdx,QWORD PTR fs:0x28
 0x0000555555555291 &lt;+232&gt;:   je     0x555555555298 &lt;main+239&gt;
 0x0000555555555293 &lt;+234&gt;:   call   0x555555555090 &lt;__stack_chk_fail@plt&gt;
 0x0000555555555298 &lt;+239&gt;:   leave  
 0x0000555555555299 &lt;+240&gt;:   ret    
End of assembler dump.</code></pre></li>
</ul>
<blockquote>
<ol>
<li>프로그램이 실행 되었을 때 프로그램이 어떠한 동작을 하는지 설명할 수 있다.</li>
<li>c 코드의 enc[17] 와 key 가 메모리에 배치될 때 각각 어떠한 메모리 세그먼트에 위치할지 대략적으로 설명할 수 있다.</li>
<li>메모리와 레지스터의 차이를 설명할 수 있다.</li>
<li>명령어 집합 구조(Instruction Set Architecture, ISA)가 무엇인지 설명할 수 있다.</li>
<li>c 코드가 어떠한 과정을 거쳐 컴파일 되는지, 그리고 컴파일 과정에서 코드가 어떻게 바뀌는지 설명할 수 있다.</li>
<li>c, 어셈블리, 바이너리 코드 각각의 특징과 그 차이점에 대해 설명할 수 있다.</li>
<li>어셈블리 코드를 보고 main 함수의 stack frame 구조를 파악할 수 있다.</li>
<li>어셈블리 코드를 보고 메모리와 레지스터를 구분할 수 있다.</li>
<li>어셈블리를 보고 동일한 기능을 하는 C 코드를 작성할 수 있다</li>
<li>c 코드에서 int형 배열이 문자로 출력될 수 있는 이유를 설명할 수 있다.</li>
<li>“Hello dreamhack!” 을 출력하도록 하는 key 값을 구할 수 있다.</li>
</ol>
</blockquote>
<blockquote>
<ul>
<li>만약 1번 질문부터 답을 할 수 없거나 질문이 이해가 안 된다면 강의를 수강하거나 실습 문제를 해결하는 데 어려움이 있을 수 있습니다.</li>
</ul>
</blockquote>
<ul>
<li>먼저 C 언어를 공부한 후 리버싱에 대해 공부해야 합니다.</li>
<li>최소 4번 질문까지 답변을 할 수 있는 상태에서 로드맵을 수강 하시길 추천합니다.</li>
<li>5~11번 질문 중 답을 할 수 없는 질문이거나 처음 들어보는 키워드가 있다면 강의를 수강하며 배워갈 수 있습니다.</li>
<li>혹은 스스로 질문에 대한 답을 찾아본 후 로드맵을 수강하며 답을 확인해보세요.</li>
</ul>
<h1 id="web-hacking-101">Web Hacking 101</h1>
<h2 id="web-hacking">Web Hacking</h2>
<p>본 강의는 웹 해킹이 무엇인지 소개하고, Web Hacking 로드맵과 강의 수강에 필요한 지식을 설명합니다.</p>
<blockquote>
<p><strong>웹 해킹(Web Hacking)</strong>은 웹 상에서 본래의 의도와 다른 동작을 일으키거나 데이터를 도용, 변조, 시스템을 손상시키는 등의 악의적인 행위를 수행하는 것을 말합니다.</p>
</blockquote>
<ul>
<li>웹으로 제공하는 서비스가 매우 다양해지고 복잡한 기능을 구현하면서, 의도치 않은 동작을 일으킬 수 있는 웹 해킹의 위협도 증가하였습니다.</li>
<li>따라서 웹에서 발생할 수 있는 취약점을 알고 방어 대책을 연구하는 것의 중요성이 커지고 있습니다.</li>
</ul>
<blockquote>
<p>드림핵에는 다음과 같이 총 세 가지 Web Hacking 로드맵이 기본적으로 존재합니다.</p>
</blockquote>
<ul>
<li>Web Hacking Fundamental</li>
<li>Web Hacking Advanced - Server Side</li>
<li>Web Hacking Advanced - Client Side<blockquote>
</blockquote>
Web Hacking Fundamental을 우선 수강 후, Web Hacking Advanced를 들으시는 것을 추천해 드립니다.</li>
</ul>
<h3 id="web-hacking-fundamental">Web Hacking Fundamental</h3>
<blockquote>
<p>Web Hacking Fundamental 카테고리의 강의는 안전한 웹 서비스의 구현을 위해 반드시 알아둬야 할 <strong>웹 해킹의 기초적인 지식과 기술을 전달하는 것을 목표</strong>로 합니다.
해킹에 대한 막연한 호기심으로 드림핵을 방문하신 분들이 최대한 쉽게 웹 해킹에 입문할 수 있도록 도울 것입니다.</p>
</blockquote>
<p>Web Hacking Fundamental 카테고리의 강의는 <strong>웹의 기반이 되는 프로토콜인 HTTP/HTTPS와, 웹 브라우저의 기본적인 원리</strong>부터 배웁니다. 이를 시작으로 <strong>클라이언트 사이드에서 일어날 수 있는 공격 기법과, 서버 사이드에서 일어날 수 있는 공격 기법</strong>을 배우고 실습해보며 웹 해킹의 기초적인 지식과 기술을 익힐 수 있습니다.</p>
<h3 id="web-hacking-advanced---server-side">Web Hacking Advanced - Server Side</h3>
<blockquote>
<p>Web Hacking Advanced - Server Side 로드맵은 <strong>Web Hacking Fundamental 로드맵의 배경 지식을 기반</strong>으로, 보다 심화된 내용을 다룹니다.
특히 <strong>서버 사이드에서 일어날 수 있는 공격 기법과 보안</strong>에 초점을 맞춥니다.</p>
</blockquote>
<blockquote>
<ul>
<li>Web Hacking Advanced - Server Side의 카테고리는 <strong>웹 서버 개발 시 사용되는 다양한 데이터베이스들</strong>을 알아보고 <strong>각 데이터베이스를 대상으로 수행할 수 있는 SQL Injection 공격 기법</strong>을 배우고 실습합니다.</li>
</ul>
</blockquote>
<ul>
<li>그리고 <strong>서버의 운영체제에서 악의적인 명령어를 실행하는 공격인 Command Injection</strong>을 배웁니다. 또한 웹 서버에 파일을 업로드하거나 웹 서버로부터 파일을 다운로드할 수 있을 때 수행할 수 있는 공격 기법도 익혀봅니다.</li>
</ul>
<h3 id="web-hacking-advanced---client-side">Web Hacking Advanced - Client Side</h3>
<blockquote>
<p>Web Hacking Advanced - Client Side 로드맵은 <strong>Web Hacking Fundamental 강의의 배경 지식을 기반</strong>으로, 보다 심화된 내용을 다룹니다. 특히 <strong>클라이언트 사이드에서 일어날 수 있는 공격 기법과 보안</strong>에 초점을 맞춥니다.</p>
</blockquote>
<blockquote>
<ul>
<li>Web Hacking Advanced - Client Side의 카테고리는 공격자가 웹 리소스에 악성 스크립트를 삽입하여 이용자의 웹 브라우저에서 이를 실행하는 공격 기법인 <strong>XSS</strong>를 배웁니다.</li>
</ul>
</blockquote>
<ul>
<li>그리고 이를 막는 <strong>여러 가지 필터링을 배우고 이를 우회하는 방법</strong>도 시도해봅니다.</li>
</ul>
<blockquote>
</blockquote>
<ul>
<li>브라우저는 악성 스크립트의 실행을 막고 브라우저가 가지고 있는 중요한 데이터가 외부로 유출되지 않도록 다양한 보호 기법이 적용되어 있습니다.</li>
<li>현대 브라우저에 적용된 보호 기법들과 이를 우회하는 방법들도 알아봅니다.</li>
<li>그 밖에 Template Injection, CSS Injection, Relative Path Overwrite, 그리고 DOM XSS 등 클라이언트 사이드를 대상으로한 다양한 공격 기법들도 배우고 실습해봅니다.</li>
</ul>
<h2 id="강의-수강에-필요한-사전-지식-2">강의 수강에 필요한 사전 지식</h2>
<blockquote>
<p>웹 해킹을 잘 하려면 웹 개발 지식이 필요하다는 말이 있습니다. 이는 맞는 말입니다.</p>
</blockquote>
<ul>
<li>웹 개발자가 작성한 코드를 이해하고 분석하여 취약점을 찾아내기 위해서는 웹 개발에 대한 기본적인 이해와 지식이 필요합니다.</li>
<li>따라서 웹 해킹을 잘하려는 사람들에게 웹 개발은 필수적인 덕목 중 하나입니다.
-웹 해킹을 위해서는 웹 프로토콜과 웹 서버, 웹 어플리케이션의 작동 방식을 이해하는 것이 중요합니다.</li>
<li>웹 개발에서 사용되는 언어와 프레임워크에 대한 이해도도 높여야 하며, 데이터베이스와 여러 보안 기술에 대한 이해 역시 필요합니다.</li>
</ul>
<blockquote>
<p>하지만, 웹 개발자와 웹 해커는 서로 다른 분야이기 때문에, 웹 해킹을 하려는 사람들이 반드시 웹 개발을 전문적인 수준으로 공부할 필요는 없습니다.</p>
</blockquote>
<ul>
<li>웹 개발자의 입장에서 생각하여 웹 서비스를 분석하고, 취약점을 찾는 것이 중요하지만, 웹 해킹에서 사용되는 다양한 도구와 기술들에 대한 이해와 활용 능력도 길러야하기 때문입니다.</li>
</ul>
<blockquote>
<p>드림핵의 웹 해킹 강의는 적어도 Flask, NodeJS, 그리고 Spring 중 한 가지 프레임워크로 작성된 웹 소스를 읽고 이해할 수 있는 수준임을 전제로 합니다.</p>
</blockquote>
<ul>
<li>만약 관련 지식이 없다면, 책 또는 온라인에 공개된 웹 개발 강의를 통해 기초적인 웹 서비스를 만들어보시고 난 후 수강하시기를 추천해 드립니다.</li>
</ul>
<blockquote>
<p>수월한 강의 수강을 위해 어느 정도로 웹 개발을 잘해야 하나요? 에 대한 답을 찾으실 수 있도록 아래의 웹 소스 코드와 몇 가지 질문을 준비해보았습니다.</p>
</blockquote>
<ul>
<li>아래의 소스 코드는 Flask와 MySQL을 활용하여 구현된 게시판 웹 서비스입니다. 전체 소스 코드는 <a href="https://drive.google.com/file/d/1Wjgpi-YmIc8h2UW26api-_Zwm5QPoFHy/view">본 링크</a>를 통해 다운로드할 수 있습니다.<pre><code class="language-sql">Flask와 MySQL을 활용하여 구현된 게시판 웹 서비스
#!/usr/bin/env python3
import os
import pymysql
from flask import Flask, abort, redirect, render_template, request
&gt;
PAGINATION_SIZE = 10
&gt;
app = Flask(__name__)
app.secret_key = os.urandom(32)
&gt;
def connect_mysql():
  conn = pymysql.connect(host=&#39;db&#39;,
                         port=3306,
                         user=os.environ[&#39;MYSQL_USER&#39;],
                         passwd=os.environ[&#39;MYSQL_PASSWORD&#39;],
                         db=&#39;board&#39;,
                         charset=&#39;utf8mb4&#39;)
  cursor = conn.cursor()
  return conn, cursor
&gt;
@app.route(&#39;/&#39;)
def index():
  return redirect(&#39;/board&#39;)
&gt;
@app.route(&#39;/board&#39;)
def board():
&gt;
  page = request.args.get(&#39;page&#39;)
  page = int(page) if page and page.isdigit() and int(page) &gt; 0 else 1
&gt;
  ret = []
&gt;
  conn, cursor = connect_mysql()
  try:
      query = &#39;SELECT _id, title FROM posts ORDER BY _id DESC LIMIT %s, %s&#39;
      cursor.execute(query, ((page - 1) * PAGINATION_SIZE, PAGINATION_SIZE))
      ret = cursor.fetchall()
  except Exception as e:
      print(e, flush=True)
      abort(400)
  finally:
      cursor.close()
      conn.close()
&gt;
  return render_template(&#39;board.html&#39;, page=page, ret=ret)
&gt;
@app.route(&#39;/board/&lt;post_id&gt;&#39;)
def board_post(post_id):
&gt;
  if not post_id or not post_id.isdigit() or int(post_id) &lt; 1:
      abort(400)
&gt;
  ret = None
&gt;
  conn, cursor = connect_mysql()
  try:
      query = &#39;SELECT title, content FROM posts WHERE _id = %s&#39;
      cursor.execute(query, (post_id))
      ret = cursor.fetchone()
  except Exception as e:
      print(e, flush=True)
      abort(400)
  finally:
      cursor.close()
      conn.close()
&gt;
  if not ret:
      abort(404)
&gt;
  return render_template(&#39;post.html&#39;, title=ret[0],
                         content=ret[1], post_id=post_id)
&gt;
@app.route(&#39;/write_post&#39;, methods=[&#39;POST&#39;])
def write_post():
  if &#39;title&#39; not in request.form or &#39;content&#39; not in request.form:
      return render_template(&#39;write_post.html&#39;)
&gt;
  title = request.form[&#39;title&#39;]
  content = request.form[&#39;content&#39;]
&gt;
  conn, cursor = connect_mysql()
  try:
      query = &#39;INSERT INTO posts (title, content) VALUES (%s, %s)&#39;
      cursor.execute(query, (title, content))
      conn.commit()
  except Exception as e:
      print(e, flush=True)
      abort(400)
  finally:
      cursor.close()
      conn.close()
&gt;
  return redirect(&#39;/board&#39;)
&gt;
@app.route(&#39;/modify_post&#39;, methods=[&#39;POST&#39;])
def modify_post():
  post_id = request.form[&#39;post_id&#39;]
&gt;
  if not post_id or not post_id.isdigit() or int(post_id) &lt; 1:
      abort(400)
&gt;
  if &#39;title&#39; not in request.form or &#39;content&#39; not in request.form:
      conn, cursor = connect_mysql()
      try:
          query = &#39;SELECT title, content FROM posts WHERE _id = %s&#39;
          cursor.execute(query, (post_id, ))
          ret = cursor.fetchone()
      except Exception as e:
          print(e, flush=True)
          abort(400)
      finally:
          cursor.close()
          conn.close()
&gt;
      if not ret:
          abort(404)
&gt;
      return render_template(&#39;modify_post.html&#39;, title=ret[0],
                             content=ret[1], post_id=post_id)
&gt;
  title = request.form[&#39;title&#39;]
  content = request.form[&#39;content&#39;]
&gt;
  conn, cursor = connect_mysql()
  try:
      query = &#39;UPDATE posts SET title=%s, content=%s WHERE _id = %s&#39;
      cursor.execute(query, (title, content, post_id, ))
      conn.commit()
  except Exception as e:
      print(e, flush=True)
  finally:
      cursor.close()
      conn.close()
&gt;
  return redirect(f&#39;/board/{post_id}&#39;)
&gt;
@app.route(&#39;/delete_post&#39;, methods=[&#39;POST&#39;])
def delete_post():
&gt;
  post_id = request.form[&#39;post_id&#39;]
  if not post_id or not post_id.isdigit() or int(post_id) &lt; 1:
      abort(400)
&gt;
  if &#39;answer&#39; not in request.form:
      return render_template(&#39;delete_post.html&#39;, post_id=post_id)
&gt;
  if request.form[&#39;answer&#39;] == &#39;y&#39;:
      conn, cursor = connect_mysql()
      try:
          query = &#39;DELETE FROM posts WHERE _id = %s&#39;
          cursor.execute(query, (post_id, ))
          conn.commit()
      except Exception as e:
          print(e, flush=True)
      finally:
          cursor.close()
          conn.close()
&gt;
      return redirect(&#39;/board&#39;)
&gt;
  return redirect(f&#39;/board/{post_id}&#39;)
&gt;
if __name__ == &#39;__main__&#39;:
  app.run(host=&#39;0.0.0.0&#39;, port=8000)</code></pre>
</li>
</ul>
<blockquote>
</blockquote>
<ol>
<li>웹 브라우저와 웹 서버가 통신하는 프로토콜의 약자를 설명할 수 있다.</li>
<li>웹 사이트 주소에 포함된 &quot;https&quot; 중 &quot;s&quot;가 어떤 의미를 나타내는지 설명할 수 있다.</li>
<li>웹 브라우저와 서버가 이용자의 로그인 상태를 어떤 방법으로 유지하는지 설명할 수 있다.</li>
<li>요청을 성공적으로 처리하였을 때, 웹 서버가 어떤 HTTP 상태 코드를 반환해야 하는지 설명할 수 있다.</li>
<li>클라이언트의 요청에 오류가 있어서 요청을 처리하지 못했을 때, 웹 서버가 어떤 HTTP 상태 코드를 반환해야 하는지 설명할 수 있다.</li>
<li>웹 서버 측에서 발생한 오류로 인해 요청을 처리하지 못했을 때, 웹 서버가 어떤 HTTP 상태 코드를 반환해야 하는지 설명할 수 있다.</li>
<li>클라이언트와 서버 간의 데이터 전송 시, 인코딩과 암호화 간의 주요한 차이점을 설명할 수 있다.</li>
<li>웹 애플리케이션에서 사용자의 입력을 검증하는 이유와 그 중요성을 설명할 수 있다.</li>
<li>HTTP 메소드에는 어떠한 종류가 있는지 나열할 수 있다.</li>
<li>GET 메소드와 POST 메소드의 차이가 무엇인지 설명할 수 있다.</li>
<li>위의 웹 서비스에 어떤 엔드포인트들이 존재하는지 설명할 수 있다.</li>
<li>각 엔드포인트가 수행하는 주요 기능에 대해 설명할 수 있다.</li>
<li>각 기능을 수행하기 위해 사용되는 SQL 쿼리를 이해하고 설명할 수 있다.</li>
<li>이용자가 POST /board/<post_id> 엔드포인트를 통해 게시글을 생성하는 경우, 브라우저, 웹 서비스, 그리고 데이터베이스 간의 상호작용 과정을 상세히 설명할 수 있다.</li>
</ol>
<blockquote>
<ul>
<li>1번부터 10번까지의 질문은 웹 기초 지식에 관련된 내용이고, 11번부터 14번까지는 위 소스 코드와 관련된 질문입니다.</li>
</ul>
</blockquote>
<ul>
<li>만약 질문에 답을 할 수 없거나 질문이 이해가 안 된다면 강의를 수강하거나 실습 문제를 해결하는 데 어려움이 있을 수 있으므로, 구글링을 통해 Flask 프레임워크와 MySQL 데이터베이스를 사용한 간단한 웹 개발 공부를 먼저 선행해 보시기를 권장합니다.</li>
</ul>
<h3 id="게시판-구동-방법">게시판 구동 방법</h3>
<blockquote>
<p>소스 코드를 눈으로만 보는 것 뿐만 아니라 직접 웹 서비스를 실행하여 결과값을 확인하면서 분석을 하면 더 빠르고 쉽게 이해하며 공부할 수 있습니다.</p>
</blockquote>
<ul>
<li>리눅스에서 도커를 사용하여 본 게시판 웹 서비스를 구동하는 방법을 설명하겠습니다.</li>
<li>Docker 사용법이 아직 익숙치 않은 경우, 이후의 <a href="https://dreamhack.io/lecture/courses/459">Docker</a> 강의를 수강하면서 사용 방법을 먼저 숙지한 후 실습해 보시기를 바랍니다.</li>
</ul>
<p><a href="https://drive.google.com/file/d/1Wjgpi-YmIc8h2UW26api-_Zwm5QPoFHy/view">링크</a>를 통해 게시판을 다운로드한 후 압축을 풀어보면 다음과 같은 구조를 지닙니다.</p>
<pre><code>$ tree .
.
`-- my_simple_board
    |-- deploy
    |   |-- app
    |   |   |-- app
    |   |   |   |-- app.py
    |   |   |   |-- run.sh
    |   |   |   `-- templates
    |   |   |       |-- board.html
    |   |   |       |-- delete_post.html
    |   |   |       |-- modify_post.html
    |   |   |       |-- post.html
    |   |   |       `-- write_post.html
    |   |   |-- Dockerfile
    |   |   `-- requirements.txt
    |   `-- db
    |       `-- 1_init.sql
    `-- docker-compose.yml

6 directories, 11 files
$</code></pre><ul>
<li>우선 my_simple_board 디렉토리로 이동합니다. <strong>ls</strong> 명령어를 치면 다음과 같은 결과가 나와야 합니다.<pre><code>$ ls
deploy  docker-compose.yml
$</code></pre></li>
<li>이후 다음과 같이 docker compose up 명령어를 실행하고 기다리면 게시판 웹 서비스가 실행됩니다.<pre><code>$ docker compose up
[+] Building 4.2s (14/14) FINISHED
</code></pre></li>
</ul>
<p>...</p>
<p>my_simple_board-db-1   | 2022-11-29  7:57:48 0 [Note] Server socket created on IP: &#39;::&#39;.
my_simple_board-db-1   | 2022-11-29  7:57:48 0 [Note] InnoDB: Buffer pool(s) load completed at 221129  7:57:48
my_simple_board-db-1   | 2022-11-29  7:57:48 0 [Note] mariadbd: ready for connections.
my_simple_board-db-1   | Version: &#39;10.9.3-MariaDB-1:10.9.3+maria~ubu2204&#39;  socket: &#39;/run/mysqld/mysqld.sock&#39;  port: 3306  mariadb.org binary distribution
my_simple_board-app-1  |  * Serving Flask app &#39;app&#39;
my_simple_board-app-1  |  * Debug mode: off
my_simple_board-app-1  | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
my_simple_board-app-1  |  * Running on all addresses (0.0.0.0)
my_simple_board-app-1  |  * Running on <a href="http://127.0.0.1:8000">http://127.0.0.1:8000</a>
my_simple_board-app-1  |  * Running on <a href="http://172.16.29.3:8000">http://172.16.29.3:8000</a>
my_simple_board-app-1  | Press CTRL+C to quit</p>
<pre><code>- 이후 웹 브라우저를 통해 해당 웹서버의 8000포트로 접속하면 아래와 같이 게시판에 접속할 수 있습니다.
![](https://velog.velcdn.com/images/pingu_9/post/35de9a38-94a6-49c9-894d-9e516ba1523e/image.png)

# Cryptography 101
## Cryptography
&gt;**암호학(Cryptography)**은 정보를 보호하거나 안전하게 통신하기 위한 방법론을 다루는 학문입니다.
- 더 자세히 말하면, 키(Key)를 이용하여 평문(Plaintext)을 암호문(Ciphertext)으로 변환하거나, 암호문을 평문으로 변환하는 전반적인 과정을 일컫습니다.
- 암호학은 개인정보 관리, 전자상거래, 클라우드 서비스 등 보안을 유지해야 하는 다양한 영역에서 사용됩니다. 

&gt;암호학은 깊게 파고들수록 수학 지식이 많이 필요하지만, 드림핵의 Cryptography 강의는 암호학을 공부해본 적 없는 분들에게 암호학을 넓고 얕게 전달하는 것을 목표로 하고 있습니다.

&gt;따라서 많은 사전 지식을 요구하지는 않으나 다음에 나오는 지식을 알고 있으면 강의를 수강하고 워게임을 해결해 나가는데 있어서 많은 도움이 됩니다.

## 강의 수강에 필요한 사전 지식
&gt;### 비트 연산(Bit Operation)
다양한 비트 연산자가 어떤 연산을 하는지 미리 알아야 강의를 수월하게 수강할 수 있습니다.
&gt;
- 비트 연산에는 AND, OR, XOR, NOT, SHIFT 등이 있습니다. 비트 연산은 많은 암호학적인 알고리즘의 기반이 되므로 필수로 알아야 합니다.
- 강의를 수강하거나 워게임 해결을 시도할 때 또한 많은 비트 연산을 마주치게 됩니다.
- 새로운 비트 연산을 만날 때마다 공부해도 되지만 미리 각 비트 연산이 어떤 연산을 하는지 미리 이해하고 시작하신다면 좀더 수월하게 암호학 강의를 수강할 수 있습니다.

&gt;### 모듈로 연산(Modulo Operation)
모듈로 연산이 기본적으로 어떤 연산을 하는지 알면 강의를 수월하게 수강할 수 있습니다.
&gt;
- 모듈로 연산(Modulo Operation)은 나머지 연산이라고도 불리며, 어떤 숫자를 다른 숫자로 나눈 나머지 값을 구하는 연산입니다.
- 많은 암호화 알고리즘에서 공개키와 개인키 및 소수를 나타내기 위해 큰 정수가 사용되며, 모듈로 연산은 큰 정수에 대한 산술을 효율적으로 연산하는 방법을 제공하므로 암호학을 공부하려면 반드시 알아야 하는 연산입니다.
&lt;br&gt;
- 모듈로 연산은 다양한 법칙과 특징을 가지고 있습니다. 
- 지만 드림핵의 암호학 강의는 모든 법칙과 특징을 설명하지 않습니다.
- 하나의 개념을 설명할 때 필요할 때 필요한 지식을 개괄적으로 설명하고 넘어가므로 미리 깊게 모듈로 연산을 미리 깊게 공부할 필요는 없습니다.
- 기본적으로 어떤 연산을 하는지만 알고가면 됩니다.

&gt;### Python
Python은 미리 필수적으로 알고 강의를 수강하여야 수월하게 내용을 이해할 수 있습니다.
&gt;
- 강의에서 암호화 알고리즘의 구현을 보여줄 때 Python으로 작성된 코드를 기준으로 설명합니다.
- 또한 드림핵의 암호학 워게임이 제공하는 파일은 Python으로 작성된 파일들이 많습니다.
- 따라서 기본적으로 Python을 읽고 사용할 수 있는 수준이 되어야 수월하게 강의를 수강하고 워게임을 해결해나갈 수 있습니다.
&gt;
스스로 얼마나 준비가 되었는지 알아보기 위해 아래의 Python 언어로 작성된 간단한 퀴즈들과, 이 퀴즈들을 풀기 위해 필요한 개념을 체크하는 질문을 준비했습니다.

```python
import random


def bit_quiz1():
    print(&quot;bit operation quiz1&quot;)
    a = random.randint(0, 255)
    b = random.randint(0, 255)
    print(f&quot;{a = }&quot;)
    print(f&quot;{b = }&quot;)

    if int(input(&quot;a ^ b = &quot;)) != a ^ b:
        exit(&quot;Wrong!&quot;)
    if int(input(&quot;a &amp; b = &quot;)) != a &amp; b:
        exit(&quot;Wrong!&quot;)
    if int(input(&quot;a | b = &quot;)) != a | b:
        exit(&quot;Wrong!&quot;)

    print(&quot;Good Job!&quot;)


def bit_quiz2():
    print(&quot;bit operation quiz2&quot;)
    a = random.randint(0, 255)
    b = random.randint(0, 255)
    target = a * 256 + b
    i = int(input())
    if (a &lt;&lt; i) ^ b != target:
        exit(&quot;Wrong!&quot;)

    print(&quot;Good Job!&quot;)


def modulo_quiz1():
    print(&quot;modulo quiz1&quot;)
    p = 0x10001
    a = random.randint(1, p)
    b = random.randint(1, p)
    print(f&quot;{a = }&quot;)
    print(f&quot;{b = }&quot;)

    if int(input(&quot;a + b = ? (mod p) &gt; &quot;)) != (a + b) % p:
        exit(&quot;Wrong!&quot;)
    if int(input(&quot;a - b = ? (mod p) &gt; &quot;)) != (a - b) % p:
        exit(&quot;Wrong!&quot;)
    if int(input(&quot;a * b = ? (mod p) &gt; &quot;)) != (a * b) % p:
        exit(&quot;Wrong!&quot;)

    print(&quot;Good Job!&quot;)


def modulo_quiz2():
    print(&quot;modulo quiz2&quot;)
    p = 15260339158265275051  # 64bit prime
    a = random.randint(1, p)
    b = random.randint(1, p)
    print(f&quot;{a = }&quot;)
    print(f&quot;{b = }&quot;)

    d = int(input(&quot;a / b = ? (mod p) &gt; &quot;))
    if (d * b - a) % p != 0:
        exit(&quot;Wrong!&quot;)

    print(&quot;Good Job!&quot;)


def modulo_quiz3():
    print(&quot;modulo quiz3&quot;)
    p = 15260339158265275051  # 64bit prime
    a = random.randint(1, p)
    b = random.randint(1, p)
    print(f&quot;{a = }&quot;)
    print(f&quot;{b = }&quot;)

    if int(input(&quot;a**b = ? (mod p) &gt; &quot;)) != pow(a, b, p):
        exit(&quot;Wrong!&quot;)

    print(&quot;Good Job!&quot;)


if __name__ == &quot;__main__&quot;:
    bit_quiz1()
    bit_quiz2()
    modulo_quiz1()
    modulo_quiz2()
    modulo_quiz3()

    flag = open(&quot;flag&quot;, &quot;rb&quot;).read()
    print(flag)</code></pre><blockquote>
<p><strong>아래의 질문을 얼마나 답할 수 있는지 체크해보세요!</strong></p>
</blockquote>
<ol>
<li>파이썬 코드를 보고, 프로그램이 어떤 흐름으로 실행될 지 예상할 수 있다.</li>
<li>비트 연산 중 AND, OR, XOR이 어떤 연산인지 설명할 수 있고, bit_quiz1을 풀 수 있다.</li>
<li>SHIFT 연산을 할 때 숫자의 비트들이 어떻게 바뀌는지 설명할 수 있고, bit_quiz2을 풀 수 있다.</li>
<li>모듈로 연산이 무엇인지 설명할 수 있다.</li>
<li>모듈로 연산에서 덧셈, 뺄셈, 곱셈이 어떻게 이뤄지는지 설명할 수 있고, modulo_quiz1을 풀 수 있다.</li>
<li>모듈로 연산에서 곱셈 역원이 무엇이고, 나눗셈이 어떻게 이뤄지는지 설명할 수 있다.</li>
<li>modulo_quiz2을 풀 수 있다.</li>
<li>모듈로 연산에서 거듭제곱이 어떻게 이뤄지는지 설명할 수 있다.</li>
<li>이때 지수가 매우 클 경우, 어떻게 거듭제곱을 빠르게 계산할 수 있는지 설명할 수 있고, modulo_quiz3을 풀 수 있다.</li>
<li>위 문항 중 체크할 수 있는 답변이 없다.</li>
</ol>
<blockquote>
<ul>
<li>위 문항들 중 10번만 체크할 수 있다면 우선 파이썬 언어를 먼저 익히셔야 합니다.</li>
</ul>
</blockquote>
<ul>
<li>1번을 체크할 수 있다면 위의 퀴즈들을 차근차근 하나씩 풀어보며 2~8번 질문의 키워드들을 공부하면 됩니다.</li>
</ul>
<p>모든 퀴즈들을 해결하고 이해하셨다면, 이제 로드맵의 강의를 들을 준비가 되었습니다.</p>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고자료">출처 및 참고자료</h1>
<h1 id="httpsdreamhackiolecturecourses450"><a href="https://dreamhack.io/lecture/courses/450">https://dreamhack.io/lecture/courses/450</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬[6일차]]]></title>
            <link>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC6%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC6%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 11 Dec 2024 04:56:45 GMT</pubDate>
            <description><![CDATA[<details>
  <summary>참고</summary>
  <div><span style="color:blue">참고 자료는 점프 투 파이썬으로 선택했습니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</details>

<h2 id="챗gpt로-배우는-점프-투-파이썬">챗GPT로 배우는 점프 투 파이썬</h2>
<h3 id="2장-연습문제-풀이">2장 연습문제 풀이</h3>
<h4 id="1-정수-7과-정수-3을-더한-결과를-구하는-파이썬-코드를-작성하세요">1. 정수 7과 정수 3을 더한 결과를 구하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python">a = 7
b = 3
c = a + b
print(c)</code></pre>
<h4 id="2-주어진-실수-31415를-소수점-두-번째-자리에서-반올림하는-파이썬-코드를-작성하세요">2. 주어진 실수 3.1415를 소수점 두 번째 자리에서 반올림하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python"># 풀이방법 1
a = round(3.1415, 2)
print(a)</code></pre>
<pre><code class="language-python"># 풀이방법 2
a = 3.1415
b = &quot;%0.2f&quot; % a
print(b)</code></pre>
<pre><code class="language-python"># 풀이방법 3
a = 3.1415
b = &quot;{:.2f}&quot;.format(a)
print(b)</code></pre>
<blockquote>
<pre><code class="language-python">round(숫자, 소수점_자리수)</code></pre>
</blockquote>
<pre><code>첫 번째 인자: 반올림할 숫자
두 번째 인자: 반올림할 소수점 자리수


#### 3. 주어진 문자열 &#39;Hello, World!&#39;에서 첫 번째 단어 &#39;Hello&#39;만 추출하는 파이썬 코드를 작성하세요.
```python
# 풀이방법 1
a = &quot;Hello, World!&quot;
b = a[0:5]
print(b)</code></pre><pre><code class="language-python"># 풀이방법 2
a = &quot;Hello, World!&quot;
b = a.split(&#39;,&#39;)[0]  # &#39;,&#39; 기준으로 나눈 후 첫 번째 부분 가져오기
# b = a.partition(&#39;,&#39;)[0]) 위와 같음
print(b)  # 출력: Hello</code></pre>
<h4 id="4-주어진-문자열-python의-모든-문자를-대문자로-변환하는-파이썬-코드를-작성하세요">4. 주어진 문자열 &#39;Python&#39;의 모든 문자를 대문자로 변환하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python">a = &quot;python&quot;
b = a.upper()
print(b)</code></pre>
<h4 id="5-주어진-리스트-1-2-3-4-5에서-첫-번째-원소와-마지막-원소를-교환하는-파이썬-코드를-작성하세요">5. 주어진 리스트 [1, 2, 3, 4, 5]에서 첫 번째 원소와 마지막 원소를 교환하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python">a = [1,2,3,4,5]
a[0], a[-1] = a[-1], a[0] # 첫 번째와 마지막 원소 교환
print(a)</code></pre>
<h4 id="6-주어진-리스트-5-2-7-1-9를-오름차순-정렬하는-파이썬-코드를-작성하세요">6. 주어진 리스트 [5, 2, 7, 1, 9]를 오름차순 정렬하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python">a = [5,2,7,1,9]
a.sort()
print(a)</code></pre>
<h4 id="7-주어진-튜플-apple-banana-cherry에서-첫-번째-원소-apple을-추출하는-파이썬-코드를-작성하세요">7. 주어진 튜플 (&#39;apple&#39;, &#39;banana&#39;, &#39;cherry&#39;)에서 첫 번째 원소 &#39;apple&#39;을 추출하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python">a = (&#39;apple&#39;,&#39;banana&#39;,&#39;cherry&#39;)
print(a[0])</code></pre>
<h4 id="8-두-개의-튜플-1-2-3과-4-5-6을-병합하여-새로운-튜플-1-2-3-4-5-6을-생성하는-파이썬-코드를-작성하세요">8. 두 개의 튜플 (1, 2, 3)과 (4, 5, 6)을 병합하여 새로운 튜플 (1, 2, 3, 4, 5, 6)을 생성하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python">a = 1,2,3
b = 4,5,6
print(a + b)</code></pre>
<h4 id="9-주어진-딕셔너리-apple-3-banana-5-cherry-2에서-banana의-값을-추출하는-파이썬-코드를-작성하세요">9. 주어진 딕셔너리 {&#39;apple&#39;: 3, &#39;banana&#39;: 5, &#39;cherry&#39;: 2}에서 &#39;banana&#39;의 값을 추출하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python"># 이거 &#39;banana&#39; key를 추출하는 건줄 알고 풀음..🐧
a = {&#39;apple&#39;: 3, &#39;banana&#39;: 5, &#39;cherry&#39;: 2}
keys = list(a.keys())
print(keys[1])</code></pre>
<pre><code class="language-python">#&#39;banana&#39; value 가져오는 풀이방법1
a = {&#39;apple&#39;: 3, &#39;banana&#39;: 5, &#39;cherry&#39;: 2}
print([&#39;banana&#39;])</code></pre>
<pre><code class="language-python"># 풀이방법 2
a = {&#39;apple&#39;: 3, &#39;banana&#39;: 5, &#39;cherry&#39;: 2}
print(a.get(&#39;banana&#39;))</code></pre>
<h4 id="10-주어진-딕셔너리-apple-3-banana-5-cherry-2에-orange-4를-추가하는-파이썬-코드를-작성하세요">10. 주어진 딕셔너리 {&#39;apple&#39;: 3, &#39;banana&#39;: 5, &#39;cherry&#39;: 2}에 &#39;orange&#39;: 4를 추가하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python">a = {&#39;apple&#39;: 3, &#39;banana&#39;: 5, &#39;cherry&#39;: 2}
a[&#39;orange&#39;] = 4
print(a)</code></pre>
<h4 id="11-주어진-두-집합-1-2-3과-2-3-4의-교집합을-구하는-파이썬-코드를-작성하세요">11. 주어진 두 집합 {1, 2, 3}과 {2, 3, 4}의 교집합을 구하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python"># 풀이방법 1
a = {1,2,3}
b = {2,3,4}
print(a &amp; b)</code></pre>
<pre><code class="language-python"># 풀이방법 2
a = {1,2,3}
b = {2,3,4}
print(a.intersection(b))</code></pre>
<h4 id="12-주어진-두-불-값-true와-false를-and-연산하는-파이썬-코드를-작성하세요">12. 주어진 두 불 값 True와 False를 AND 연산하는 파이썬 코드를 작성하세요.</h4>
<pre><code class="language-python">a = True
b = False
c = a and b
print(c)</code></pre>
<hr>
<hr>
<hr>
<h1 id="제어문">제어문</h1>
<blockquote>
<p>if,while,for 등의 제어문에 대해 알아보자.</p>
</blockquote>
<h2 id="ㅁ-if문">ㅁ if문</h2>
<pre><code class="language-python">&gt;&gt;&gt; money = True
&gt;&gt;&gt; if money:
...     print(&quot;택시를 타고 가라&quot;)
... else:
...     print(&quot;걸어 가라&quot;)
...
택시를 타고 가라</code></pre>
<ul>
<li>money에 True를 대입했으므로 money는 참이다. 따라서 if 문 다음 문장이 수행되어 &#39;택시를 타고 가라&#39;가 출력된다.</li>
<li>프로그램 실행 과정을 순서도로 그려 보면 훨씬 이해하기 쉽다.
<img src="https://velog.velcdn.com/images/pingu_9/post/b794ddbd-6031-4dda-9188-8ea0f117c96b/image.png" alt=""><h3 id="ㅇ-if문의-기본-구조">ㅇ if문의 기본 구조</h3>
<blockquote>
<p>다음은 if와 else를 사용한 조건문의 기본 구조이다.</p>
</blockquote>
<pre><code class="language-python">if 조건문:
  수행할_문장1
  수행할_문장2
  ...
else:
  수행할_문장A
  수행할_문장B
  ...</code></pre>
</li>
<li>조건문을 테스트해서 참이면 if문 바로 다음 문장(if 블록)들을 수행하고 조건문이 거짓이면 else문 다음 문장(else 블록)들을 수행하게 된다.</li>
<li>따라서 else 문은 if 문 없이 독립적으로 사용할 수 없다.</li>
</ul>
<h3 id="ㅇ-들여쓰기-방법-알아보기">ㅇ 들여쓰기 방법 알아보기</h3>
<blockquote>
<p>if 문을 만들 때는 if 조건문: 바로 다음 문장부터 if 문에 속하는 모든 문장에 들여쓰기(indentation)를 해야 한다.</p>
</blockquote>
<ul>
<li>다음 예를 보면 조건문이 참일 경우 ‘수행할_문장1’을 들여쓰기했고 ‘수행할_문장2’와 ‘수행할_문장3’도 들여쓰기했다.
※ 다른 프로그래밍 언어를 사용해 온 사람들은 파이썬에서 ‘수행할_문장’을 들여쓰기하는 것을 무시하는 경우가 많으므로 더 주의해야 한다.<pre><code class="language-python">if 조건문:
  수행할_문장1
  수행할_문장2
  수행할_문장3</code></pre>
↑↑↑ 들여쓰기한 문장</li>
<li>다음처럼 작성하면 오류가 발생한다. ‘수행할_문장2’를 들여쓰기하지 않았기 때문이다.<pre><code class="language-python">if 조건문:
  수행할_문장1
수행할_문장2
  수행할_문장3</code></pre>
</li>
<li>IDLE 에디터에서 다음과 같이 작성하여 실행해 보자.</li>
<li>여기서는 오류가 발생하는지 확인만 하면 되므로 IDLE 에디터 창에 코드를 작성하고 [F5]를 눌러 바로 실행하자.<pre><code class="language-python"># indent_error.py
money = True
if money:
  print(&quot;택시를&quot;)
print(&quot;타고&quot;)
  print(&quot;가라&quot;)</code></pre>
<img src="https://velog.velcdn.com/images/pingu_9/post/fd62aba6-2b65-4b91-8115-affe49e7b67b/image.png" alt=""><blockquote>
<blockquote>
<p>들여쓰기 오류가 발생하는 것을 확인할 수 있다.</p>
</blockquote>
</blockquote>
</li>
<li>다음과 같은 경우에도 오류가 발생한다.</li>
<li>&#39;수행할_문장3&#39;을 들여쓰기했지만, &#39;수행할_문장1&#39;이나 &#39;수행할_문장2&#39;와 들여쓰기의 깊이가 다르다.</li>
<li>즉, 들여쓰기는 언제나 같은 깊이로 해야한다.<pre><code class="language-python">if 조건문:
  수행할_문장1
  수행할_문장2
      수행할_문장3</code></pre>
<blockquote>
<blockquote>
<p>그렇다면 들여쓰기는 공백 문자<span style="background-color:lightgrey; color:orange">([Spacebar])</span>로 하는 것이 좋을까, 탭 문자<span style="background-color:lightgrey; color:orange">([Tab])</span>로 하는 것이 좋을까? 
이에 대한 논란은 파이썬을 사용하는 사람들 사이에서 아직도 계속되고 있다.
공백 문자로 하자는 쪽과 탭 문자로 하자는 쪽 모두가 동의하는 내용은 2가지를 혼용해서 쓰지 말자는 것이다.
공백 문자로 할 것이라면 공백으로 통일하고, 탭 문자로 할 것이라면 탭으로 통일하자는 말이다. 탭이나 공백은 프로그램 소스에서 눈으로 보이는 것이 아니기 때문에 혼용해서 쓰면 오류의 원인이 되므로 주의하자.</p>
<blockquote>
<p>요즘 파이썬 커뮤니티에서는 들여쓰기를 할 때 공백 문자 4개를 사용하는 것을 권장한다.
또한 파이썬 에디터는 대부분 탭 문자로 들여쓰기를 하더라도 탭 문자를 공백 문자 4개로 자동 변환하는 기능을 갖추고 있다.</p>
</blockquote>
</blockquote>
</blockquote>
</li>
</ul>
<h3 id="ㅇ-조건문-다음에-콜론을-잊지-말자">ㅇ 조건문 다음에 콜론(:)을 잊지 말자!</h3>
<blockquote>
<p>if 조건문 뒤에는 반드시 콜론(:)이 붙는다.
어떤 특별한 의미가 있다기보다는 파이썬 문법 구조이다.
왜 하필 콜론(:)인지 궁금하다면 파이썬을 만든 귀도에게 직접 물어봐야 할 것이다.
앞으로 배울 while이나 for,def,class도 역시 문장의 끝에 콜론(:)이 항상 들어간다.</p>
</blockquote>
<p>파이썬이 다른 언어보다 보기 쉽고 소스 코드가 간결한 이유는 바로 콜론(:)을 사용하여 들여쓰기를 하도록 만들었기 떄문이다.
하지만 이는 숙련된 프로그래머들이 파이썬을 처음 접할 때 제일 혼란스러워하는 부분이기도 하다.
다른 언어에서는 if문에 속한 문장들을 {}로 감싸지만, 파이썬에서는 들여쓰기로 해결한다는 점을 기억하자.</p>
<h3 id="ㅇ-조건문이란-무엇인가">ㅇ 조건문이란 무엇인가?</h3>
<blockquote>
<p>if 조건문에서 &#39;조건문&#39;이란 참과 거짓을 판단하는 문장을 말한다.</p>
</blockquote>
<p>앞에서 살펴본 택시 예제에서 조건문은 money가 된다.</p>
<pre><code class="language-python">&gt;&gt;&gt; money = True
&gt;&gt;&gt; if money:</code></pre>
<ul>
<li>money는 True이기 때문에 조건이 참이 되어 if 문 다음 문장을 수행한다.</li>
</ul>
<h3 id="ㅇ-비교-연산자">ㅇ 비교 연산자</h3>
<blockquote>
<p>이번에는 조건문에 비교 연산자(&lt;, &gt;, ==, !=, &gt;=, &lt;=)를 쓰는 방법에 대해 알아보자.</p>
</blockquote>
<p>다음 표는 비교 연산자를 잘 설명해 준다.</p>
<blockquote>
</blockquote>
<table>
<thead>
<tr>
<th>비교연산자</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>x &lt; y</td>
<td>x가 y보다 작다.</td>
</tr>
<tr>
<td>x &gt; y</td>
<td>x가 y보다 크다.</td>
</tr>
<tr>
<td>x == y</td>
<td>x와 y가 같다.</td>
</tr>
<tr>
<td>x != y</td>
<td>x와 y가 같지 않다.</td>
</tr>
<tr>
<td>x &gt;= y</td>
<td>x가 y보다 크거나 같다.</td>
</tr>
<tr>
<td>x &lt;= y</td>
<td>x가 y보다 작거나 같다.</td>
</tr>
<tr>
<td>- 이제 이 연산자를 어떻게 사용하는지 알아보자.</td>
<td></td>
</tr>
<tr>
<td>```python</td>
<td></td>
</tr>
</tbody></table>
<blockquote>
<blockquote>
<blockquote>
<p>x = 3
y = 2
x &gt; y
True</p>
</blockquote>
</blockquote>
</blockquote>
<pre><code>- x에 3, y에 2를 대입한 후 x &gt; y라는 조건문을 수행하면 True를 리턴한다.
- **x &gt; y** 조건문이 참이기 때문이다.
```python
&gt;&gt;&gt; x &lt; y
False</code></pre><ul>
<li>위 조건문은 거짓이기 때문에 False를 리턴한다.<pre><code class="language-python">&gt;&gt;&gt; x == y
False</code></pre>
</li>
<li>x와 y는 같지 않다. 따라서 위 조건문은 거짓이므로 False를 리턴한다.<pre><code class="language-python">&gt;&gt;&gt; x != y
True</code></pre>
</li>
<li>x와 y는 같지 않다. 따라서 위 조건문은 참이므로 True를 리턴한다.<blockquote>
<blockquote>
<p>사용법을 알아봤으므로 이제 응용해 보자. 앞에서 살펴본 택시 예제를 다음처럼 바꾸려면 어떻게 해야 할까?</p>
<blockquote>
<p>만약 3000원 이상의 돈을 가지고 있으면 택시를 타고 가고, 그렇지 않으면 걸어가라.</p>
</blockquote>
</blockquote>
</blockquote>
</li>
<li>이 상황은 다음처럼 프로그래밍할 수 있다.<pre><code class="language-python">&gt;&gt;&gt; money = 2000
&gt;&gt;&gt; if money &gt;= 3000:
...     print(&quot;택시를 타고 가라&quot;)
... else:
...     print(&quot;걸어가라&quot;)
...
걸어가라
&gt;&gt;&gt;</code></pre>
<span style="background-color:lightgrey; color:orange">money &gt;= 3000</span> 조건문이 거짓이 되기 때문에 else 문 다음 문장을 수행하게 된다.</li>
</ul>
<h3 id="ㅇ-andornot">ㅇ and,or,not</h3>
<blockquote>
<p>조건을 판단하기 위해 사용하는 다른 연산자로는 and,or,not이 있다.</p>
</blockquote>
<ul>
<li>각각의 연산자는 다음처럼 동작한다.<blockquote>
</blockquote>
<table>
<thead>
<tr>
<th>연산자</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>x or y</td>
<td>x와 y 둘 중 하나만 참이어도 참이다.</td>
</tr>
<tr>
<td>x and y</td>
<td>x와 y 모두 참이어야 참이다.</td>
</tr>
<tr>
<td>not x</td>
<td>x가 거짓이면 참이다.</td>
</tr>
</tbody></table>
</li>
<li>다음 예를 통해 or 연산자의 사용법을 알아보자!<blockquote>
<blockquote>
<p>돈이 3000원 이상 있거나 카드가 있다면 택시를 타고 가고, 그렇지 않으면 걸어가라.</p>
</blockquote>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; money = 2000
&gt;&gt;&gt; card = True
&gt;&gt;&gt; if money &gt;= 3000 or card:
...     print(&quot;택시를 타고 가라&quot;)
... else:
...     print(&quot;걸어가라&quot;)
...
택시를 타고 가라
&gt;&gt;&gt;</code></pre>
</li>
<li>money는 2000이지만, card가 True이기 때문에 <span style="background-color:lightgrey; color:orange">money &gt;= 3000 or card</span> 조건문이 참이 된다.</li>
<li>따라서 if 문에 속한 ‘택시를 타고 가라’ 문장이 출력된다.</li>
</ul>
<h3 id="ㅇ-innot-in">ㅇ in,not in</h3>
<blockquote>
<p>파이썬은 다른 프로그래밍 언어에서 쉽게 볼 수 없는 재미있는 조건문도 제공한다.</p>
</blockquote>
<ul>
<li>바로 다음과 같은 것들이다.<blockquote>
</blockquote>
<table>
<thead>
<tr>
<th>in</th>
<th>not in</th>
</tr>
</thead>
<tbody><tr>
<td>x in 리스트</td>
<td>x not in 리스트</td>
</tr>
<tr>
<td>x in 튜플</td>
<td>x not in 튜플</td>
</tr>
<tr>
<td>x in 문자열</td>
<td>x not in 문자열</td>
</tr>
</tbody></table>
</li>
<li>영어 단어 in의 뜻이 &#39;~안에&#39;라는 것을 생각해 보면 다음 예가 쉽게 이해될 것이다.<pre><code class="language-python">&gt;&gt;&gt; 1 in [1, 2, 3]
True
&gt;&gt;&gt; 1 not in [1, 2, 3]
False</code></pre>
</li>
<li>앞에서 첫 번째 예는 ‘[1, 2, 3]이라는 리스트 안에 1이 있는가?’라는 조건문이다.</li>
<li>1은 [1, 2, 3] 안에 있으므로 참이 되어 True를 리턴한다.<br></li>
<li>두 번째 예는 ‘[1, 2, 3] 리스트 안에 1이 없는가?’라는 조건문이다.</li>
<li>1은 [1, 2, 3] 안에 있으므로 거짓이 되어 False를 리턴한다.<br></li>
<li>다음은 튜플과 문자열에 in과 not in을 적용한 예이다.</li>
<li>각각의 결과가 나온 이유는 쉽게 유추할 수 있다.<pre><code class="language-python">&gt;&gt;&gt; &#39;a&#39; in (&#39;a&#39;, &#39;b&#39;, &#39;c&#39;)
True
&gt;&gt;&gt; &#39;j&#39; not in &#39;python&#39;
True</code></pre>
</li>
<li>이번에는 우리가 계속 사용해 온 택시 예제에 in을 적용해 보자.<blockquote>
<blockquote>
<p>만약 주머니에 돈이 있으면 택시를 타고 가고, 없으면 걸어가라.</p>
</blockquote>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; pocket = [&#39;paper&#39;, &#39;cellphone&#39;, &#39;money&#39;]
&gt;&gt;&gt; if &#39;money&#39; in pocket:
...     print(&quot;택시를 타고 가라&quot;)
... else:
...     print(&quot;걸어가라&quot;)
...
택시를 타고 가라
&gt;&gt;&gt;</code></pre>
</li>
<li><span style="background-color:lightgrey; color:orange">[&#39;paper&#39;, &#39;cellphone&#39;, &#39;money&#39;]</span> 리스트 안에 &#39;money&#39;가 있으므로 <span style="background-color:lightgrey; color:orange">&#39;money&#39; in pocket</span>은 참이 된다.</li>
<li>따라서 if 문에 속한 문장이 수행된다.</li>
</ul>
<h3 id="ㅇ-조건문에서-아무-일도-하지-않게-설정하고-싶다면">ㅇ 조건문에서 아무 일도 하지 않게 설정하고 싶다면?</h3>
<blockquote>
<p>가끔 조건문의 참, 거지에 따라 실행할 행동을 정의할 때나 아무런 일도 하지 않도록 설정하고 싶을 때가 있다.</p>
</blockquote>
<ul>
<li>다음 예를 살펴 보자.<blockquote>
<blockquote>
<p>주머니에 돈이 있으면 가만히 있고, 주머니에 돈이 없으면 카드를 꺼내라.</p>
</blockquote>
</blockquote>
</li>
<li>이럴 때 사용하는 것이 바로 pass이다.</li>
<li>위 예를 pass를 적용해서 구현해 보자.<pre><code class="language-python">&gt;&gt;&gt; pocket = [&#39;paper&#39;, &#39;money&#39;, &#39;cellphone&#39;]
&gt;&gt;&gt; if &#39;money&#39; in pocket:
...     pass 
... else:
...     print(&quot;카드를 꺼내라&quot;)
...</code></pre>
</li>
<li>pocket 리스트 안에 money 문자열이 있기 때문에 if 문 다음 문장인 pass가 수행되고 아무런 결괏값도 보여 주지 않는다.</li>
</ul>
<h3 id="ㅇ-다양한-조건을-판단하는-elif">ㅇ 다양한 조건을 판단하는 elif</h3>
<blockquote>
<p>if와 else만으로는 다양한 조건을 판단하기 어렵다.</p>
</blockquote>
<ul>
<li>다음 예를 보더라도 if와 else만으로는 조건을 판단하는 데 어려움을 겪게 된다는 것을 알 수 있다.<blockquote>
<blockquote>
<p>주머니에 돈이 있으면 택시를 타고 가고, 주머니에 돈은 없지만 카드가 있으면 택시를 타고, 돈도 없고 카드도 없으면 걸어가라.</p>
</blockquote>
</blockquote>
</li>
<li>위 문장을 보면 조건을 판단하느 부분이 두 군데 있다.</li>
<li>먼저 주머니에 돈이 있는지를 판단해야 하고 주머니에 돈이 없으면 다시 카드가 있는지 판단해야 한다.<br></li>
<li>if와 else만으로 위 문장을 표현하려면 다음과 같이 할 수 있다.<pre><code class="language-python">&gt;&gt;&gt; pocket = [&#39;paper&#39;, &#39;cellphone&#39;]
&gt;&gt;&gt; card = True
&gt;&gt;&gt; if &#39;money&#39; in pocket:
...     print(&quot;택시를 타고가라&quot;)
... else:
...     if card:
...         print(&quot;택시를 타고가라&quot;)
...     else:
...         print(&quot;걸어가라&quot;)
...
택시를 타고가라
&gt;&gt;&gt;</code></pre>
</li>
<li>언뜻 보기에도 이해하기 어렵고 산만한 느낌이 든다.</li>
<li>이런 복잡함을 해결하기 위해 파이썬에서는 다중 조건 판단을 가능하게 하는 elif를 사용한다.<br></li>
<li>위 예에 elif를 사용하면 다음과 같이 바꿀 수 있다.<pre><code class="language-python">&gt;&gt;&gt; pocket = [&#39;paper&#39;, &#39;cellphone&#39;]
&gt;&gt;&gt; card = True
&gt;&gt;&gt; if &#39;money&#39; in pocket:
...      print(&quot;택시를 타고가라&quot;)
... elif card: 
...      print(&quot;택시를 타고가라&quot;)
... else:
...      print(&quot;걸어가라&quot;)
...
택시를 타고가라</code></pre>
</li>
<li>즉, elif는 이전 조건문이 거짓일 때 수행된다.</li>
<li>if, elif, else를 모두 사용할 때 기본 구조는 다음과 같다.<pre><code class="language-python">if 조건문:
  수행할_문장1 
  수행할_문장2
  ...
elif 조건문:
  수행할_문장1
  수행할_문장2
  ...
elif 조건문:
  수행할_문장1
  수행할_문장2
  ...
...
else:
 수행할_문장1
 수행할_문장2
 ... </code></pre>
</li>
<li>위에서 볼 수 있듯이 elif는 개수에 제한 없이 사용할 수 있다.
<img src="https://velog.velcdn.com/images/pingu_9/post/f19b1e9f-be3e-4a2f-afc2-e0d01a60bc34/image.png" alt=""></li>
</ul>
<h3 id="ㅇ-if-문을-한-줄로-작성하기">ㅇ if 문을 한 줄로 작성하기</h3>
<blockquote>
<p>앞의 pass를 사용한 예를 들어 보면 if 문 다음에 수행할 문장이 한 줄이고 else 문 다음에 수행할 문장도 한 줄밖에 되지 않는다.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; if &#39;money&#39; in pocket:
...     pass 
... else:
...     print(&quot;카드를 꺼내라&quot;)
...</code></pre>
<ul>
<li>이렇게 수행할 문장이 한 줄일 때 좀 더 간략하게 코드를 작성하는 방법이 있다.<pre><code class="language-python">&gt;&gt;&gt; pocket = [&#39;paper&#39;, &#39;money&#39;, &#39;cellphone&#39;]
&gt;&gt;&gt; if &#39;money&#39; in pocket: pass
... else: print(&quot;카드를 꺼내라&quot;)
...</code></pre>
</li>
<li>if 문 다음에 수행할 문장을 콜론(:) 뒤에 바로 적었다.</li>
<li>else 문 역시 마찬가지이다.</li>
</ul>
<h3 id="ㅇ-조건부-표현식">ㅇ 조건부 표현식</h3>
<blockquote>
<p>다음 코드를 살펴보자.
score가 60 이상일 경우 message에 문자열 &quot;success&quot;, 아닐 경우에는 문자열 &quot;failure&quot;를 대입하는 코드이다.</p>
</blockquote>
<pre><code class="language-python">if score &gt;= 60:
    message = &quot;success&quot;
else:
    message = &quot;failure&quot;</code></pre>
<ul>
<li>파이썬의 조건부 표현식(conditional expression)을 사용하면 위 코드를 다음과 같이 간단히 표현할 수 있다.<pre><code class="language-python">message = &quot;success&quot; if score &gt;= 60 else &quot;failure&quot;</code></pre>
</li>
<li>조건부 표현식은 다음과 같이 정의한다.<blockquote>
<blockquote>
<p><code>변수 = 조건문이_참인_경우의_값 if 조건문 else 조건문이_거짓인_경우의_값</code></p>
</blockquote>
</blockquote>
</li>
<li>조건부 표현식은 가독성에 유리하고 한 줄로 작성할 수 있어 활용성이 좋다.</li>
</ul>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고문헌">출처 및 참고문헌</h1>
<h1 id="httpswikidocsnet20"><a href="https://wikidocs.net/20">https://wikidocs.net/20</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[CTF[6일차]]]></title>
            <link>https://velog.io/@pingu_9/CTF6%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/CTF6%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 11 Dec 2024 04:54:18 GMT</pubDate>
            <description><![CDATA[<blockquote>
<details>
  <summary>참고</summary>
  <div><span style="color:blue">
※참고 자료는 드림핵을 이용하였습니다.<br>
※드림핵의 로드맵대로 공부할 예정입니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</blockquote>
</details>

<h1 id="ㅁ-c코드-작성">ㅁ C코드 작성</h1>
<p>VS code로 기본적인 C 코드를 작성해 보겠습니다.</p>
<ul>
<li>다음 코드는 “Hello Beginners!”를 출력하고 종료하는 C 코드입니다.<pre><code class="language-C">#include &lt;stdio.h&gt;
</code></pre>
</li>
</ul>
<p>int main(){
    printf(&quot;Hello Beginners!\n&quot;);
    return 0;
}</p>
<pre><code>ㅇ VS code를 열고 리눅스에 원격 접속한 뒤, 아래와 같이 Desktop 디렉토리에 test.c 파일을 생성합니다.
![](https://velog.velcdn.com/images/pingu_9/post/87070491-1b17-4146-8ea4-96bb3a70df11/image.png)
ㅇ 아래와 같이 test.c 파일에 위에서 소개한 C 코드를 작성하고 저장합니다.
![](https://velog.velcdn.com/images/pingu_9/post/f173a4b9-e087-44b6-a7a2-70f19a99ff97/image.png)


### ㅇ C 코드 컴파일, 실행
&gt;소스 코드가 포함된 c 파일은 **컴파일** 과정을 거쳐야 실행 가능한 파일로 변환됩니다.
- 리눅스에서 C/C++ 언어로 작성된 소스 코드를 컴파일할 때는 주로 **gcc** 컴파일러를 사용합니다.
&lt;br&gt;
- 리눅스 터미널에 &lt;span style=&quot;background-color:lightgrey;color:orange&quot;&gt;gcc --version&lt;/span&gt;을 입력하여 다음과 같이 버전이 출력되는지 확인합니다.(버전 숫자는 달라도 괜찮습니다!)
```linux
user@LAPTOP-FM1BL380:~$ gcc --version
gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.</code></pre><ul>
<li>버전이 뜨지 않으면 아래 명령어를 통해 gcc를 설치합니다. <pre><code>sudo apt install gcc</code></pre></li>
<li>설치가 완료되면 test.c 파일이 있는 디렉토리로 이동하고 컴파일합니다.</li>
<li>아래는 test.c 파일을 실행 가능한 test 파일로 컴파일하는 명령어입니다.</li>
<li>컴파일 후에 ./test 명령으로 test 파일을 실행하면 “Hello Beginners!”가 출력됩니다.<pre><code>gcc -o test test.c</code></pre><img src="https://dreamhack-lecture.s3.amazonaws.com/media/81af5fb5fffbbed2b89bcddb2843d7c7401e09501047d8c1a9d014983f56b565.png" alt=""></li>
</ul>
<h3 id="vs-code로-c-코드-실행">VS code로 C 코드 실행</h3>
<blockquote>
<p>VS code의 C/C++ 확장 프로그램을 사용하면, gcc 명령어를 직접 사용해서 컴파일 하지 않아도 메뉴를 통해 컴파일하여 실행할 수 있습니다.</p>
</blockquote>
<ol>
<li>VS code를 열고 좌측 탭의 <strong>Extensions</strong>를 클릭하여 C/C++을 <strong>Install</strong> 합니다.
<img src="https://dreamhack-lecture.s3.amazonaws.com/media/3275eb7c8b5c3d0710acc48103a4c3bfad28344ccfe2e93248f38171b7233531.png" alt=""></li>
<li>다음으로 상단 메뉴에서 <strong>Run - Run Without Debugging</strong> 혹은 단축키 <strong>Ctrl+f5</strong>로 코드를 실행합니다. 그러면 VS code에서 자동으로 소스 코드를 컴파일하고 실행 파일을 생성하여 실행합니다.
<img src="https://dreamhack-lecture.s3.amazonaws.com/media/ac308367ecfed9a47b279a50b0357d54242dd0870a0549427b0c9cd2ce835f99.png" alt=""></li>
<li>**아래 스크린샷은 실행 결과입니다.
<img src="https://dreamhack-lecture.s3.amazonaws.com/media/d3d443f1ccbc27b808d66a20f8a0e2c7724ad4cc146e863efcc87318203c01d2.png" alt=""></li>
</ol>
<ul>
<li>VS code로 코드를 실행하면 더 편리하지만, 때에 따라 VS code를 사용할 수 없는 경우도 있으니 앞서 보았던 gcc 컴파일을 기본적으로 알아 두면 좋습니다.</li>
</ul>
<h2 id="디버깅">디버깅</h2>
<h3 id="에러-해결">에러 해결</h3>
<blockquote>
<p>소스 코드의 문법이 잘못되었거나 비정상적인 코드를 작성한 경우 컴파일 혹은 실행 과정에서 에러가 발생합니다.
아래의 그림은 에러가 발생하는 예시 코드입니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/543805d5-de2c-4b24-b016-7fa323f21204/image.png" alt=""></p>
</blockquote>
<ul>
<li>VS code에서 코드를 실행하면 터미널 창에 에러 메시지가 출력됩니다.</li>
<li>이처럼 코드에 에러가 발생한 경우, 출력된 에러 메시지를 활용해서 어느 부분이 잘못되었는지 알아내고 수정하여 에러를 해결할 수 있어야 합니다.<blockquote>
</blockquote>
터미널 창을 보면 에러가 발생한 이유는 <span style="background-color:white;color:#DF01D7">error: &#39;sum&#39; undeclared (first use in this function)</span>이고, 에러가 발생한 코드는 11번 라인의 <span style="background-color:white;color:#DF01D7">sum=a+b;</span>입니다. 에러 메시지를 통해 <span style="background-color:white;color:#DF01D7">sum</span> 변수가 선언되지 않아서 에러가 발생했다는 것을 알 수 있고, 이에 따라 11번 라인 이전에 <span style="background-color:white;color:#DF01D7">int sum=0;</span>을 추가하면 에러가 발생하지 않습니다. <blockquote>
</blockquote>
해당 에러는 수정하기 쉬운 예시이지만, 에러 메시지를 봐도 어떤 에러인지, 어떻게 해결하는지 알기 어려운 경우가 많습니다. 이런 경우 <strong>구글링</strong>을 통해 사람들이 비슷한 에러를 어떻게 처리했는지 참고하는 것도 좋은 방법입니다. <blockquote>
</blockquote>
</li>
<li><em>아래 그림*</em>의 에러 메시지 <span style="background-color:white;color:#DF01D7">undeclared (first use in this function)</span>를 구글에 검색해 보면 동일한 에러를 겪은 사람의 게시글이 가장 먼저 뜹니다. 해당 게시글에 달린 여러 사람들의 답변을 보고, 에러를 해결하려면 변수를 선언해야 한다는 사실을 알아낼 수 있습니다.</li>
</ul>
<h3 id="디버깅-1">디버깅</h3>
<blockquote>
<p>에러 해결에 도움이 되는 또 다른 방법으로 디버깅이 있습니다.</p>
</blockquote>
<ul>
<li>디버깅(Debugging)은 소스 코드의 오류(버그)를 찾고 수정하는 과정을 말합니다. 코드를 검사하여 잘못된 부분을 찾거나, 특정 코드를 수행한 결과를 확인하기 위해 사용합니다.</li>
<li>VS code에서 제공하는 디버깅 기능을 살펴 보겠습니다.</li>
<li>상단 메뉴의 Run - Start Bebugging 혹은 단축키 F5로 디버깅을 시작할 수 있습니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/79bfc4a7-2e29-42d6-8fe3-2d5d247fb4cf/image.png" alt="">
<span style="background-color:white;color:#01DFD7"><strong>Breakpoint</strong></span>
주로 확인하고 싶은 코드에 Breakpoint(중단점)를 설정한 뒤 디버깅을 시작합니다. 중단점을 설정하면 해당 코드를 실행하기 직전에 프로그램을 중단하여 그 시점의 변수 값이나 콜 스택 정보 등을 확인할 수 있습니다. 중단점은 코드 줄 번호 왼쪽을 클릭하거나 코드에 커서를 두고 단축키 f9를 클릭하여 설정합니다.<blockquote>
</blockquote>
<span style="background-color:white;color:#B404AE"><strong>Debug View</strong></span>
디버깅을 시작하면 좌측 Debug View에서 VARIABLES(변수), WATCH(변수 또는 표현식의 결과), CALL STACK(호출한 함수), BREAKPOINTS(사용자가 설정한 중단점 목록) 등의 정보를 확인할 수 있습니다.<blockquote>
</blockquote>
<span style="background-color:white;color:#DF7401"><strong>Debug Toolbar</strong></span>
디버깅 툴바의 각 버튼은 순서대로 다음과 같은 기능을 합니다. </li>
<li>⏯️ Continue/Pause : 다음 중단점을 만날 때까지 프로그램 실행 혹은 프로그램 중단 (<strong>f5</strong>)</li>
<li>➡️ Step Over : 코드 한 줄 실행 - 함수를 만나면 함수 실행 (<strong>f10</strong>)</li>
<li>⬇️ Step Into : 코드 한 줄 실행 - 함수를 만나면 함수 내부로 이동하여 한 줄 실행 (<strong>f11</strong>)</li>
<li>⬆️ Step Out : 함수의 나머지 부분을 모두 실행 (<strong>Shift+f11</strong>)</li>
<li>🔄️ Restart : 디버깅 재시작 (<strong>Ctrl+Shift+f5</strong>)</li>
<li>⏹️ Stop : 디버깅 종료 (<strong>Shift+f5</strong>)<blockquote>
</blockquote>
<span style="background-color:white;color:#01DF74"><strong>Debug Console</strong></span></li>
<li>디버깅 결과를 출력하는 콘솔 창입니다.</li>
</ul>
<h2 id="vim">Vim</h2>
<blockquote>
<ul>
<li>Vim(Vi IMproved)은 UNIX의 Vi 편집기(Visual editor)의 기능을 개선한 버전의 텍스트 편집기로, Linux, macOS, BSD 등 UNIX 기반의 모든 환경에서 사용할 수 있습니다.</li>
</ul>
</blockquote>
<ul>
<li>마우스 없이 키보드 입력만으로 모든 작업이 가능하기 때문에 Vim 사용에 익숙해지면 소스 코드를 매우 빠르고 효율적으로 편집할 수 있습니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/aad1da1a-e165-48da-a43b-096edafdee7f/image.png" alt=""></li>
<li>리눅스 환경에서는 Vim 편집기 사용법을 알아 두면 편리합니다. 물론 꼭 알아야 하는 것은 아니지만, 다른 편집기를 사용할 수 없는 경우를 대비하여 익혀두는 것도 좋습니다. </li>
<li>우분투 리눅스에는 Vim이 기본적으로 설치되어 있는 경우도 있으나 만약 없다면 터미널에서 <span style="background-color:white;color:#DF01D7">sudo apt install vim</span> 명령을 실행하여 설치합니다.</li>
</ul>
<h3 id="vim-사용법">Vim 사용법</h3>
<h4 id="vim-실행">Vim 실행</h4>
<p><span style="background-color:white;color:#DF01D7">vi</span> 명령을 입력하면 아래와 같이 Vim이 실행됩니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/6c87c599-9982-46ba-988e-2861728d1896/image.png" alt="">
<span style="background-color:white;color:#DF01D7">vi 파일명</span>은 기존 파일을 수정하거나 새 파일을 생성합니다. 아래는 <span style="background-color:white;color:#DF01D7">vi a.txt</span> 명령으로 a.txt 파일을 연 모습입니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/d609592a-2622-4a5e-b7be-7384d4c62634/image.png" alt=""></p>
<h4 id="vim-사용법---모드-1">Vim 사용법 - 모드 1</h4>
<p><strong>모드</strong></p>
<ul>
<li>Vim의 3가지 모드와 각 모드에서 자주 사용하는 명령을 소개하겠습니다. 
<img src="https://velog.velcdn.com/images/pingu_9/post/85389f49-7361-4be5-bb0c-1bb44d345d8e/image.jpg" alt=""><h4 id="normal-mode-일반-모드">Normal Mode (일반 모드)</h4>
</li>
<li>Vim을 처음 실행하면 일반 모드로 시작합니다.</li>
<li>다른 모드에서 <span style="background-color:white;color:#DF01D7">esc</span> 키를 클릭하면 일반 모드로 전환됩니다.</li>
<li>일반 모드에서는 방향 키와 Home, End 등의 키를 통해 커서를 이동할 수 있는데, 다른 키로도 동일한 동작을 수행할 수 있습니다.</li>
<li><table>
<thead>
<tr>
<th>커서이동</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>gg</td>
<td>첫 행으로 이동</td>
</tr>
<tr>
<td>k</td>
<td>위로 이동</td>
</tr>
<tr>
<td>0</td>
<td>행의 처음으로 이동</td>
</tr>
<tr>
<td>h</td>
<td>왼쪽으로 이동</td>
</tr>
<tr>
<td>l</td>
<td>오른쪽으로 이동</td>
</tr>
<tr>
<td>$</td>
<td>행의 끝으로 이동</td>
</tr>
<tr>
<td>G</td>
<td>마지막 행으로 이동</td>
</tr>
<tr>
<td>j</td>
<td>아래로 이동</td>
</tr>
</tbody></table>
</li>
<li><table>
<thead>
<tr>
<th>삭제,복사,붙여넣기</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>x</td>
<td>현재 커서가 위치한 글자 삭제(del)</td>
</tr>
<tr>
<td>X</td>
<td>현재 커서 앞 글자 삭제(backspace)</td>
</tr>
<tr>
<td>dd</td>
<td>현재 커서가 위치한 행 삭제</td>
</tr>
<tr>
<td>yy</td>
<td>현재 커서가 위치한 행 복사</td>
</tr>
<tr>
<td>p</td>
<td>복사한 내용을 현재 행 이후에 붙여넣기</td>
</tr>
<tr>
<td>P</td>
<td>복사한 내용을 현재 행 이전에 붙여넣기</td>
</tr>
</tbody></table>
</li>
<li><table>
<thead>
<tr>
<th>문자열 찾기</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>/문자열,enter</td>
<td>현재 커서 이후로 문자열 찾기</td>
</tr>
<tr>
<td>n</td>
<td>찾은 문자열 목록에서 다음 문자로 이동</td>
</tr>
</tbody></table>
</li>
<li><table>
<thead>
<tr>
<th>되돌리기</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>u</td>
<td>이전 수정 사항 되돌리기</td>
</tr>
</tbody></table>
</li>
</ul>
<h4 id="vim-사용법---모드-2">Vim 사용법 - 모드 2</h4>
<p><strong>Insert Mode (입력 모드)</strong></p>
<ul>
<li>입력 모드는 사용자가 실제로 텍스트를 입력하고 편집하는 작업을 수행합니다.</li>
<li>입력 모드에서도 방향키를 사용할 수 있으며, 일반 텍스트 편집기와 유사하게 동작합니다.</li>
<li>일반 모드에서 아래 명령 키들을 클릭하면 입력 모드로 전환됩니다.</li>
</ul>
<table>
<thead>
<tr>
<th>입력 모드 명령 키</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>o</td>
<td>현재 커서 다음 줄에 입력</td>
</tr>
<tr>
<td>O</td>
<td>현재 커서 이전 줄에 입력</td>
</tr>
<tr>
<td>i</td>
<td>현재 커서 위치에 입력</td>
</tr>
<tr>
<td>I</td>
<td>현재 커서가 위치한 행의 처음에 입력</td>
</tr>
<tr>
<td>s</td>
<td>현재 커서 한 글자 지우고 입력</td>
</tr>
<tr>
<td>S</td>
<td>현재 커서 한 줄 지우고 입력</td>
</tr>
<tr>
<td>a</td>
<td>현재 커서 다음 칸에 입력</td>
</tr>
<tr>
<td>A</td>
<td>현재 커서가 위치한 행의 마지막에 입력</td>
</tr>
</tbody></table>
<h4 id="vim-사용법---모드-3">Vim 사용법 - 모드 3</h4>
<p><strong>Command Mode (명령 모드)</strong></p>
<ul>
<li>명령 모드는 저장, 종료, 취소 등의 명령을 수행합니다. 일반 모드에서 <span style="background-color:white;color:#DF01D7">:</span>를 입력하면 명령 모드로 전환됩니다. 이후 원하는 명령을 입력하면 됩니다.</li>
</ul>
<table>
<thead>
<tr>
<th>명령 모드 명령어</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>:w</td>
<td>저장</td>
</tr>
<tr>
<td>:q</td>
<td>종료</td>
</tr>
<tr>
<td>:i</td>
<td>취소</td>
</tr>
<tr>
<td>:wq</td>
<td>저장하고 종료</td>
</tr>
<tr>
<td>:q!</td>
<td>저장하지 않고 종료</td>
</tr>
<tr>
<td>:%s/문자열1/문자열2/g</td>
<td>전체에서 문자열1을 모두 찾아 문자열2로 치환</td>
</tr>
<tr>
<td>***</td>
<td></td>
</tr>
<tr>
<td>***</td>
<td></td>
</tr>
<tr>
<td>***</td>
<td></td>
</tr>
<tr>
<td># 출처 및 참고문헌</td>
<td></td>
</tr>
<tr>
<td># <a href="https://learn.dreamhack.io/449#21">https://learn.dreamhack.io/449#21</a></td>
<td></td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬[5일차]]]></title>
            <link>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC5%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC5%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 10 Dec 2024 02:16:59 GMT</pubDate>
            <description><![CDATA[<details>
  <summary>참고</summary>
  <div><span style="color:blue">참고 자료는 점프 투 파이썬으로 선택했습니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</details>

<h1 id="자료형의-값을-저장하는-공간-변수">자료형의 값을 저장하는 공간, 변수</h1>
<h2 id="변수는-어떻게-만들까">변수는 어떻게 만들까?</h2>
<ul>
<li>우리는 앞에서 이미 변수를 사용해 왔다. 다음 예와 같은 a,b,c를 &#39;변수&#39;라고 한다.<pre><code class="language-python">&gt;&gt;&gt; a = 1
&gt;&gt;&gt; b = &quot;python&quot;
&gt;&gt;&gt; c = [1,2,3]</code></pre>
</li>
<li>변수를 만들 때는 위 예처럼 =(assignment) 기호를 사용한다.<pre><code class="language-python">변수_이름 = 변수에_저장할_값</code></pre>
다른 프로그래밍 언어인 C나 JAVA에서는 변수를 만들 때 자료형의 타입을 직접 지정해야 한다.
하지만 파이썬은 변수에 저장된 값은 스스로 판단하여 자료형의 타입을 지정하기 떄문에 더 편리하다.<h2 id="변수란">변수란?</h2>
파이썬에서 사용하는 변수는 객체를 가리키는 것이라고도 말할 수 있다.
객체란 우리가 지금까지 보아 온 자료형의 데이터(값)와 같은 것을 의미하는 말이다.<pre><code class="language-python">a = [1,2,3]</code></pre>
만약 위 코드처럼 <span style="background-color:grey; color:orange"> a = [1,2,3]</span> 이라고 하면 [1, 2, 3] 값을 가지는 리스트 데이터(객체)가 자동으로 메모리에 생성되고 변수 a는 [1, 2, 3] 리스트가 저장된 메모리의 주소를 가리키게 된다.<blockquote>
<p>메모리란 컴퓨터가 프로그램에서 사용하는 데이터를 기억하는 공간을 말한다.</p>
</blockquote>
</li>
</ul>
<p>a 변수가 가리키는 메모리의 주소는 다음과 같이 확인할 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; id(a)
4303029896</code></pre>
<p>id는 변수가 가리키고 있는 객체의 주소 값을 리턴하는 파이썬의 내장 함수이다.
즉, 여기에서 필자가 만든 변수 a가 가리키는 [1, 2, 3] 리스트의 주소 값은 4303029896이라는 것을 알 수 있다.</p>
<h2 id="리스트를-복사하고자-할-때">리스트를 복사하고자 할 때</h2>
<ul>
<li>다음 예를 통해 알아보자.<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; b = a</code></pre>
b 변수에 a 변수를 대입하면 어떻게 될까? b와 a는 같은 걸까?, 다른 걸까?
결론부터 말하면 b는 a와 완전히 동일하다고 할 수 있다.
다만 [1,2,3]이라는 리스트 객체를 참조하는 변수가 a 변수 1개에서 b 변수가 추가되어 2개로 늘어났다는 차이만 있을 뿐이다.</li>
</ul>
<p>id 함수를 사용하여 이러한 사실을 확인할 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; id(a)
4303029896
&gt;&gt;&gt; id(b)
4303029896</code></pre>
<p>id(a)의 값이 id(b)의 값과 동일하다는 것을 확인할 수 있다.
즉, a가 가리키는 대상과 b가 가리키는 대상이 동일하다는 것을 알 수 있다.
동일한 객체를 가리키고 있는지에 대해서 판단하는 파이썬 명령어 is를 다음과 같이 실행해도 역시 참을 리턴해 준다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a is b  # a와 b가 가리키는 객체가 같을까?
True</code></pre>
<p>이제 다음 예를 계속 수행해 보자!</p>
<pre><code class="language-python">&gt;&gt;&gt; a[1] = 4
&gt;&gt;&gt; a
[1, 4, 3]
&gt;&gt;&gt; b
[1, 4, 3]</code></pre>
<p>a 리스트의 두 번째 요소를 값 4로 바꾸었더니 a만 바뀌는 것이 아니라 b도 똑같이 바꾸었다.
그 이유는 앞에서 살펴본 것처럼 a,b 모두 동일한 리스트를 가리키고 있기 때문이다.</p>
<p>그렇다면 b 변수를 생성할 때 a 변수의 값을 가져오면서 a와는 다른 주소를 가리키도록 만들 수 는 없을까?
다음 2가지 방법이 있다.</p>
<h3 id="1이용하기">1.[:]이용하기</h3>
<p>첫 번째 방법은 다음과 같이 리스트 전체를 가리키는 [:]을 사용해서 복사하는 것이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3]
&gt;&gt;&gt; b = a[:]
&gt;&gt;&gt; a[1] = 4
&gt;&gt;&gt; a
[1, 4, 3]
&gt;&gt;&gt; b
[1, 2, 3]</code></pre>
<p>위 예에서 볼 수 있듯이 a 리스트 값을 바꾸더라도 b 리스트에는 아무런 영향이 없다.</p>
<h3 id="2copy-모듈-이용하기">2.copy 모듈 이용하기</h3>
<p>두 번째 방법은 copy 모듈을 사용하는 것이다.
다음 예를 보면 <span style="background-color:grey; color:orange">from copy import copy</span>라는 처음 보는 형태의 문장이 나온다.
여기서는 단순히 copy 함수를 쓰기 위해서 사용하는 것이라고만 알아 두자.</p>
<pre><code class="language-python">&gt;&gt;&gt; from copy import copy
&gt;&gt;&gt; a = [1, 2, 3]
&gt;&gt;&gt; b = copy(a)</code></pre>
<p>위 예에서 b = copy(a)는 b = a[:]과 동일하다.
두 변수의 값은 같지만, 서로 다른 객체를 가리키고 있는지 다음과 같이 확인해 보자.</p>
<pre><code class="language-python">&gt;&gt;&gt; b is a
False</code></pre>
<p>위 예에서 <span style="background-color:grey; color:orange"> b is a</span>가 False를 리턴하므로 b와 a가 가리키는 객체는 서로 다르다는 것을 알 수 있다.</p>
<h4 id="copy-함수-사용하기">copy 함수 사용하기</h4>
<p>다음처럼 리스트 자료형의 자체 함수인 copy 함수를 사용해도 copy 모듈을 사용하는 것과 동일한 결과를 얻을 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; b = a.copy()
&gt;&gt;&gt; b is a
False</code></pre>
<h2 id="변수를-만드는-여러-가지-방법">변수를 만드는 여러 가지 방법</h2>
<ul>
<li>다음과 같이 튜플로 a,b에 값을 대입할 수 있다.<pre><code class="language-python">&gt;&gt;&gt; a, b = (&#39;python&#39;, &#39;life&#39;)</code></pre>
</li>
<li>이 방법은 다음 예문과 완전히 동일하다.<pre><code class="language-python">&gt;&gt;&gt; (a,b) = &#39;python&#39;, &#39;life&#39;</code></pre>
</li>
<li>튜플 부분에서도 언급했지만, 튜플은 괄호를 생략해도 된다.</li>
</ul>
<br>

<ul>
<li>다음처럼 리스트로 변수를 만들 수도 있다.<pre><code class="language-python">&gt;&gt;&gt; [a, b] = [&#39;python&#39;, &#39;life&#39;]</code></pre>
</li>
<li>또한 여러 개의 변수에 같은 값을 대입할 수도 있다.<pre><code class="language-python">&gt;&gt;&gt; a = b = &#39;python&#39;
</code></pre>
</li>
</ul>
<pre><code>- 파이썬에서는 위 방법을 사용하여 두 변수의 값을 매우 간단하게 바꿀 수 있다.

```python
&gt;&gt;&gt; a = 3
&gt;&gt;&gt; b = 5
&gt;&gt;&gt; a, b = b, a
&gt;&gt;&gt; a
5
&gt;&gt;&gt; b
3</code></pre><p>처음에 a에 값 3,b에는 값 5가 대입되어 있지만 <span style="background-color:grey; color:orange">a, b = b, a</span> 문장을 수행한 후에는 그 값이 서로 바뀌었다는 것을 확인할 수 있다.</p>
<hr>
<hr>
<h2 id="되새김-문제">되새김 문제!</h2>
<h3 id="01-홍길동-씨의-과목별-점수는-다음과-같다-홍길동-씨의-평균-점수를-구해-보자">01. 홍길동 씨의 과목별 점수는 다음과 같다. 홍길동 씨의 평균 점수를 구해 보자.</h3>
<blockquote>
<p>국어 80  영어 75  수학 55</p>
</blockquote>
<pre><code class="language-python">a = 80
b = 75
c = 55
d = (a+b+c)/3
print(&quot;%0.0f&quot; % d) #소수점 없애기 위해 %0.0f 사용</code></pre>
<h3 id="02-자연수-13이-홀수인지-짝수인지-판별할-수-있는-방법에-대해-말해-보자">02. 자연수 13이 홀수인지 짝수인지 판별할 수 있는 방법에 대해 말해 보자.</h3>
<pre><code class="language-python">#2로 나누었을 때 나머지가 0이 되면 짝수 아니면 홀수!
a = 13%2
if a == 0:
    print(&quot;짝수&quot;)
else:
    print(&quot;홀수&quot;)</code></pre>
<h3 id="03-홍길동-씨의-주민등록번호는-881120-1068234이다-홍길동-씨의-주민등록번호를-연월일yyyymmdd-부분과-그-뒤의-숫자-부분으로-나누어-출력해-보자">03. 홍길동 씨의 주민등록번호는 881120-1068234이다. 홍길동 씨의 주민등록번호를 연월일(YYYYMMDD) 부분과 그 뒤의 숫자 부분으로 나누어 출력해 보자.</h3>
<pre><code class="language-python">a = &quot;881120-1068234&quot;
front = a[:6] #a[:-8]와 같음
back = a[7:] #a[-7:]와 같음
print(&quot;앞자리:&quot;, front)
print(&quot;뒷자리:&quot;, back)</code></pre>
<h3 id="04-주민등록번호-뒷자리의-맨-첫-번째-숫자는-성별을-나타낸다-주민등록번호에서-성별을-나타내는-숫자를-출력해-보자">04. 주민등록번호 뒷자리의 맨 첫 번째 숫자는 성별을 나타낸다. 주민등록번호에서 성별을 나타내는 숫자를 출력해 보자.</h3>
<pre><code class="language-python">a = &quot;881120-1068234&quot;
Gender = a[7] #a[7:8]
if Gender == &#39;1&#39;: #if int(Gender) == 1 과 같음
    print(&quot;남자&quot;)
else:
    print(&quot;여자&quot;)</code></pre>
<h3 id="05-다음과-같은-문자열-abcd가-있다-문자열의-replace-함수를-사용하여-abcd로-바꿔서-출력해-보자">05. 다음과 같은 문자열 a:b:c:d가 있다. 문자열의 replace 함수를 사용하여 a#b#c#d로 바꿔서 출력해 보자.</h3>
<pre><code class="language-python">a = &quot;a:b:c:d&quot;
a = a.replace(&quot;:&quot;, &quot;#&quot;)
print(a)</code></pre>
<h3 id="06-1-3-5-4-2-리스트를-5-4-3-2-1로-만들어-보자">06. [1, 3, 5, 4, 2] 리스트를 [5, 4, 3, 2, 1]로 만들어 보자.</h3>
<pre><code class="language-python">a = [1,3,5,4,2]
a.sort(reverse=True)
print(a)</code></pre>
<pre><code class="language-python">a = [1,3,5,4,2]
a.sort()
a.reverse()
print(a)</code></pre>
<pre><code class="language-python">a = [1, 3, 5, 4, 2]
a = sorted(a, reverse=True)  # 내림차순으로 정렬된 새로운 리스트 반환
print(a)</code></pre>
<pre><code class="language-python">a = [1, 3, 5, 4, 2]
a = sorted(a)  # 오름차순으로 정렬 [1, 2, 3, 4, 5]
a = a[::-1]  # 슬라이싱으로 뒤집기
print(a)  # [5, 4, 3, 2, 1]</code></pre>
<h3 id="07-life-is-too-short-리스트를-life-is-too-short-문자열로-만들어-출력해-보자">07. [&#39;Life&#39;, &#39;is&#39;, &#39;too&#39;, &#39;short&#39;] 리스트를 Life is too short 문자열로 만들어 출력해 보자.</h3>
<pre><code class="language-python">a = [&#39;Life&#39;, &#39;is&#39;, &#39;too&#39;, &#39;short&#39;]
result = &#39; &#39;.join(a)
print(result)</code></pre>
<pre><code class="language-python">a = [&#39;Life&#39;, &#39;is&#39;, &#39;too&#39;, &#39;short&#39;]
result = f&#39;{a[0]} {a[1]} {a[2]} {a[3]}&#39;
print(result)</code></pre>
<pre><code class="language-python">a = [&#39;Life&#39;, &#39;is&#39;, &#39;too&#39;, &#39;short&#39;]
print(*a) #unpacking 기법, (공백으로 자동 연결됨)</code></pre>
<h3 id="08-123-튜플에-값-4를-추가하여-1234를-만들어-출력해-보자">08. (1,2,3) 튜플에 값 4를 추가하여 (1,2,3,4)를 만들어 출력해 보자.</h3>
<pre><code class="language-python">t1 = 1,2,3
t2 = 4,
t3 = t1 + t2
print(t3)</code></pre>
<pre><code class="language-python">t = (1, 2, 3)
t = list(t)  # 튜플을 리스트로 변환
t.append(4)  # 리스트에 값 추가
t = tuple(t)  # 다시 튜플로 변환
print(t)  # (1, 2, 3, 4)</code></pre>
<h3 id="09-다음과-같은-딕셔너리-a가-있다br-a--dictbr-abr-br다음-중-오류가-발생하는-경우를-고르고-그-이유를-설명해-보자">09. 다음과 같은 딕셔너리 a가 있다.<br>&gt;&gt;&gt; a = dict()<br>&gt;&gt;&gt; a<br> {}<br>다음 중 오류가 발생하는 경우를 고르고, 그 이유를 설명해 보자.</h3>
<blockquote>
<ol>
<li>a[&#39;name&#39;] = &#39;python&#39;</li>
<li>a[(&#39;a&#39;,)] = &#39;python&#39;</li>
<li>a[[1]] = &#39;python&#39;</li>
<li>a[250] = &#39;python&#39;</li>
</ol>
</blockquote>
<p>답 : 3번
오류 원인: 리스트는 가변형 자료형으로, 딕셔너리의 키로 사용할 수 없습니다.
딕셔너리의 키는 반드시 <strong>불변형 자료형(immutable type)</strong>이어야 합니다.
(예: 문자열, 정수, 튜플 등)</p>
<h3 id="10-딕셔너리-a에서-b에-해당되는-값을-추출해-보자">10. 딕셔너리 a에서 &#39;B&#39;에 해당되는 값을 추출해 보자.</h3>
<blockquote>
<p>a = {&#39;A&#39;:90, &#39;B&#39;:80, &#39;C&#39;:70}</p>
</blockquote>
<pre><code class="language-python">a = {&#39;A&#39;:90, &#39;B&#39;:80, &#39;C&#39;:70}
print(a.get(&#39;B&#39;))</code></pre>
<pre><code class="language-python">a = {&#39;A&#39;:90, &#39;B&#39;:80, &#39;C&#39;:70}
result = a.pop(&#39;B&#39;)
print(result)</code></pre>
<h3 id="11-a-리스트에서-중복-숫자를-제거해-보자">11. a 리스트에서 중복 숫자를 제거해 보자.</h3>
<blockquote>
<p>a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5]</p>
</blockquote>
<pre><code class="language-python">a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5]  # 중복 요소가 있는 리스트
seta = set(a)  # 리스트를 집합(set)으로 변환하여 중복 제거
b = list(seta)  # 다시 리스트로 변환
print(b)</code></pre>
<ul>
<li>집합(set)은 순서를 보장하지 않으므로, 순서를 유지하면서 중복을 제거하려면 다음과 같이 처리할 수 있습니다.<pre><code class="language-python">a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5]
b = list(dict.fromkeys(a))  # 딕셔너리는 입력 순서를 유지하며 중복 제거
print(b)</code></pre>
</li>
</ul>
<h3 id="12-파이썬은-다음처럼-동일한-값에-여러-개의-변수를-선언할-수-있다-다음과-같이-a-b-변수를-선언한-후-a의-두-번째-요-솟값을-변경하면-b-값은-어떻게-될까-그리고-이런-결과가-오는-이유에-대해-설명해-보자">12. 파이썬은 다음처럼 동일한 값에 여러 개의 변수를 선언할 수 있다. 다음과 같이 a, b 변수를 선언한 후 a의 두 번째 요 솟값을 변경하면 b 값은 어떻게 될까? 그리고 이런 결과가 오는 이유에 대해 설명해 보자.</h3>
<pre><code class="language-python">&gt;&gt;&gt; a = b = [1, 2, 3]
&gt;&gt;&gt; a[1] = 4
&gt;&gt;&gt; print(b)</code></pre>
<ul>
<li>[1, 4, 3]이 출력된다. <ul>
<li>이유는 a와 b 변수는 모두 동일한 [1, 2, 3]이라는 리스트 객체를 가리키고 있기 때문이다.</li>
</ul>
</li>
</ul>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고문헌">출처 및 참고문헌</h1>
<h1 id="httpswikidocsnet180351"><a href="https://wikidocs.net/180351">https://wikidocs.net/180351</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[CTF[5일차]]]></title>
            <link>https://velog.io/@pingu_9/CTF5%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/CTF5%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Tue, 10 Dec 2024 02:13:02 GMT</pubDate>
            <description><![CDATA[<blockquote>
<details>
  <summary>참고</summary>
  <div><span style="color:blue">
※참고 자료는 드림핵을 이용하였습니다.<br>
※드림핵의 로드맵대로 공부할 예정입니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</blockquote>
</details>

<h1 id="문제-baby-linux">문제 baby-linux</h1>
<blockquote>
<p>Description
리눅스 명령어를 실행하는 웹 서비스가 작동하고 있습니다.
해당 웹 서비스의 코드가 첨부파일로 주어집니다.<br>
flag.txt 파일을 찾아 출력하여 플래그를 획득하세요!<br>
플래그 형식은 DH{...} 입니다.</p>
</blockquote>
<pre><code class="language-python">#코드 첨부파일 내용
#!/usr/bin/env python3
import subprocess
from flask import Flask, request, render_template

APP = Flask(__name__)

@APP.route(&#39;/&#39;, methods=[&#39;GET&#39;, &#39;POST&#39;])
def index():
    if request.method == &#39;POST&#39;:
        user_input = request.form.get(&#39;user_input&#39;)
        cmd = f&#39;echo $({user_input})&#39;
        if &#39;flag&#39; in cmd:
            return render_template(&#39;index.html&#39;, result=&#39;No!&#39;)

        try:
            output = subprocess.check_output([&#39;/bin/sh&#39;, &#39;-c&#39;, cmd], timeout=5)
            return render_template(&#39;index.html&#39;, result=output.decode(&#39;utf-8&#39;))
        except subprocess.TimeoutExpired:
            return render_template(&#39;index.html&#39;, result=&#39;Timeout&#39;)
        except subprocess.CalledProcessError:
            return render_template(&#39;index.html&#39;, result=&#39;Error&#39;)

    return render_template(&#39;index.html&#39;)

if __name__ == &#39;__main__&#39;:
    APP.run(host=&#39;0.0.0.0&#39;, port=8000)</code></pre>
<h3 id="1-문제-상황">1. 문제 상황</h3>
<ul>
<li>Flask 애플리케이션에서 사용자 입력을 쉘 명령어로 실행할 수 있는 기능이 구현되어 있음.</li>
<li>입력 창에 명령어를 입력하면 서버에서 실행되어 결과를 반환함.</li>
<li>예를 들어, ls나 cat 명령어를 입력하면 서버의 파일이나 디렉터리 내용을 확인 가능.</li>
</ul>
<h3 id="2-발견한-취약점">2. 발견한 취약점</h3>
<h5 id="21-명령어-인젝션-가능성">2.1. 명령어 인젝션 가능성</h5>
<ul>
<li>사용자 입력값이 필터링 없이 쉘 명령어로 실행되므로 공격자가 임의 명령어를 실행할 수 있음.
예를 들어:<ul>
<li>ls를 입력해 디렉터리 구조 탐색 가능.</li>
<li>cat 명령어로 파일 내용을 읽을 수 있음.</li>
</ul>
</li>
</ul>
<h5 id="22-특정-파일-차단-로직-존재">2.2. 특정 파일 차단 로직 존재</h5>
<ul>
<li>flag.txt라는 파일에 접근하려고 시도하면 &quot;No!!&quot;라는 메시지가 출력됨.</li>
<li>Flask 코드에서 특정 문자열(예: flag)을 포함한 명령어를 차단하는 로직이 있는 것으로 보임.</li>
</ul>
<h3 id="3-실험-과정">3. 실험 과정</h3>
<h5 id="31-디렉터리-탐색">3.1. 디렉터리 탐색</h5>
<ul>
<li>ls 명령어를 입력해 파일 및 디렉터리 구조를 탐색.</li>
<li>결과: dream/hack/hello 디렉터리 발견.</li>
</ul>
<h5 id="32-파일-확인">3.2. 파일 확인</h5>
<ul>
<li>ls를 통해 hint.txt 파일 존재 확인</li>
<li>cat hint.txt를 통해 ./dream/hack/hello 파일이 존재함을 확인.</li>
<li>ls -l ./dream/hack/hello경로에 flag.txt 파일이 존재함을 확인.</li>
<li>cat ./dream/hack/hello/flag.txt 실행 시 차단됨(&quot;No!!&quot; 출력).</li>
</ul>
<h5 id="33-차단-우회-시도">3.3. 차단 우회 시도</h5>
<ul>
<li>flag 문자열을 우회하거나 다른 방식으로 파일에 접근하려는 다양한 방법을 시도함:</li>
<li>파일 이름 생략(cat ./dream/hack/hello/fla*)을 하니 flag 값이 나옴.</li>
</ul>
<h3 id="4-보안적-취약점-정리">4. 보안적 취약점 정리</h3>
<h5 id="명령어-인젝션">명령어 인젝션</h5>
<ul>
<li>사용자의 입력값이 필터링 없이 실행되므로 공격자가 시스템 명령어를 통해 민감한 정보에 접근 가능.</li>
</ul>
<h5 id="불완전한-차단-로직">불완전한 차단 로직</h5>
<ul>
<li>특정 문자열(예: flag)만 차단하고 있으나, 파일 이름 변형이나 우회 방법으로 접근 가능.</li>
</ul>
<h5 id="시스템-정보-노출">시스템 정보 노출</h5>
<ul>
<li>명령어 결과가 그대로 반환되므로, 서버 파일 구조와 민감한 정보를 쉽게 탐색 가능.</li>
</ul>
<hr>
<p>이번 글에서는 코딩을 시작하는 발걸음이 되는 소스 코드 편집기 사용법을 알아보고, 기본적인 C 코드를 컴파일하여 실행하는 과정을 살펴 보겠습니다.</p>
<h1 id="visual-studio-code">Visual Studio Code</h1>
<blockquote>
<ul>
<li>비주얼 스튜디오 코드(Visual Studio Code, 이하 VS Code)는 Windows, macOS, Linux에서 사용 가능한 소스 코드 편집기입니다.</li>
</ul>
</blockquote>
<ul>
<li>기본적으로 JavaScript, TypeScript, Node.js를 지원하며 확장 프로그램(Extension)을 통해 C, Java, Python 등 100개 이상의 언어를 지원합니다.</li>
<li>가볍고 무료인데 다양한 기능을 제공하여 많은 사람들이 사용하고 있습니다. </li>
<li>개발을 할 때만 소스 코드 편집기를 사용한다고 생각하는 것은 큰 오해입니다.</li>
<li>해킹 공부를 할 때도 직접 익스플로잇 코드 혹은 스크립트를 작성해야 하는 경우가 많습니다.</li>
</ul>
<h2 id="visual-studio-code---tips">Visual Studio Code - Tips</h2>
<h3 id="ㅁ-커맨드-팔레트">ㅁ 커맨드 팔레트</h3>
<p><strong>커맨드 팔레트(Command Palette)</strong>는 VS Code에 존재하는 기능을 키보드 입력으로 검색하고 실행할 수 있는 간편한 명령 처리 기능입니다. 
<strong>View-Command Palette...</strong> 혹은 단축키 <strong>Ctrl+Shift+P</strong>로 열 수 있습니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/5a27c75b-98b9-48f6-8684-8df3b71a191e/image.png" alt=""></p>
<h3 id="ㅁ-터미널">ㅁ 터미널</h3>
<p>VS Code 내에서 빠르게 명령어를 실행할 수 있는 <strong>터미널(Terminal)</strong> 창이 존재합니다.
<strong>View-Terminal</strong> 혹은 단축키 <strong>Ctrl+`</strong>로 터미널 창을 엽니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/69460736-c66d-47a7-b287-ca9f483286a1/image.png" alt=""></p>
<h2 id="리눅스-vm-🐧-vs-code">리눅스 VM 🐧 VS Code</h2>
<blockquote>
<ul>
<li>대부분의 드림핵 강의가 리눅스 환경을 필요로 하기 때문에 앞서 리눅스 VM을 구축했습니다.</li>
</ul>
</blockquote>
<ul>
<li>그런데 VM에서 코딩을 하다 보면 속도가 느리거나 불편한 경우가 있습니다.</li>
<li>이번 강의에는 편리한 코딩을 위해 <strong>VS Code 편집기를 리눅스 VM에서 사용할 수 있도록 연결</strong>하겠습니다.</li>
</ul>
<h2 id="리눅스-vm-virtualbox-🐧-vs-code">리눅스 VM (VirtualBox) 🐧 VS Code</h2>
<p>VirtualBox로 리눅스 VM을 구축한 경우 다음과 같이 연결합니다. </p>
<h3 id="리눅스-vm에-ssh-서버-설치">리눅스 VM에 ssh 서버 설치</h3>
<p>리눅스 VM에서 VS Code 편집기를 사용한다는 것은 호스트 머신에서 리눅스에 원격으로 접속한 상태로 VS Code를 사용한다는 것과 같습니다.
원격 접속을 하기 위해서는 <strong>ssh</strong>를 이용합니다.</p>
<p>먼저 리눅스 VM의 터미널에 아래 명령어를 입력하여 업데이트를 진행하고, ssh 서버를 설치합니다.</p>
<pre><code class="language-linux">sudo apt update
sudo apt upgrade
sudo apt-get install openssh-server</code></pre>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/409a3b05-ebe5-4e1f-933a-583e9952d643/image.png" alt=""></p>
<h3 id="리눅스-vm-포트-포워딩">리눅스 VM 포트 포워딩</h3>
<p>※ VirtualBox로 우분투 22.04.5 lts 실행 시 해상도가 자꾸 깨져서
vmware로 다시 설치 후 진행 ※</p>
<h4 id="1-우분투-네트워크-세팅">1. 우분투 네트워크 세팅</h4>
<p>:우분투 22.04 마우스 우클릭 &gt; Setting 클릭 &gt; Network Adapter &gt; Custom에서 NAT 선택
<img src="https://velog.velcdn.com/images/pingu_9/post/9d27a855-00e7-48bb-8470-a62091ed2d0c/image.png" alt="">
<img src="https://velog.velcdn.com/images/pingu_9/post/37daedda-e842-4303-81c8-eb1f49d9a1e9/image.png" alt=""></p>
<h4 id="2-vmware-네트워크-설정">2. VMware 네트워크 설정</h4>
<p>: Edit 클릭 &gt; Virtual Network Editor 클릭 &gt; NAT 선택 후, Change Setting 클릭
<img src="https://velog.velcdn.com/images/pingu_9/post/7b7cb679-6ee9-46f2-b981-60106c02b400/image.png" alt="">
<img src="https://velog.velcdn.com/images/pingu_9/post/cade90f1-b32d-493c-b49d-f8e7cd41c692/image.png" alt="">
: NAT 선택 후, NAT Settings 클릭
<img src="https://velog.velcdn.com/images/pingu_9/post/39a9867a-395c-4e43-8335-d0386cb61c53/image.png" alt="">
 NAT Settings에서 Add 버튼 클릭 후, 두 번째 사진과 같이 설정하기 </p>
<ul>
<li>Host Port : 접근할 포트번호 (unknown 포트번호 사용하기)</li>
<li>Virtual Machine IP address : 본인 우분투 IP 주소(우분투 들어가서 터미널에 ipconfig 하면 나옴)</li>
<li>Virtual Machine Port : 본인 우분투 포트번호(web은 80, ssh는 22)
<img src="https://velog.velcdn.com/images/pingu_9/post/c2f382bf-516f-4bb1-a4f3-51bb889a1d60/image.png" alt="">
<img src="https://velog.velcdn.com/images/pingu_9/post/3b0e51cb-a4d8-4313-8b62-151c8ed743c6/image.png" alt=""><ul>
<li>포트는 ssh 이므로 22로 설정</li>
</ul>
</li>
</ul>
<h3 id="vs-code-설정-remote---ssh-설치">VS Code 설정: Remote - SSH 설치</h3>
<p>이제 VS Code에서 리눅스 ssh 서버로 접속하기 위한 설정을 진행하겠습니다.</p>
<p>VS Code 좌측 <strong>Extensions</strong> 탭을 열어 ssh를 검색합니다. <strong>Remote - SSH extension</strong>를 클릭하고 Install 버튼을 눌러 설치합니다. 아래와 같이 Uninstall 버튼이 뜨면 정상적으로 설치가 완료된 것입니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/1800015c-62ac-4aff-8aed-f0b546a7f174/image.png" alt=""></p>
<h3 id="vs-code-설정-ssh-config-파일-구성">VS Code 설정: SSH config 파일 구성</h3>
<p>이제 Remote - SSH의 기능을 실행할 수 있습니다. 리눅스 ssh 서버로의 연결을 등록하기 위해 Ctrl+Shift+P로 아래와 같이 커맨드 팔레트를 열고, ssh를 검색합니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/472d1bcf-bd42-4afa-89bb-a373d109436b/image.png" alt="">
<img src="https://velog.velcdn.com/images/pingu_9/post/2144df01-225e-461a-ad36-ec271f8b3826/image.png" alt="">
목록에서** Remote-SSH: Open SSH Configuration File…<strong>을 클릭한 뒤 기본 config 파일 경로인 **~/.ssh/config</strong>를 선택하여 ssh config 파일을 엽니다.</p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/9b5f9380-d323-484a-8a08-80a4a8cfe26e/image.png" alt="">
config 파일은 여러 ssh 서버에 간편하게 접속할 수 있도록 호스트, 포트, 키 파일 등의 옵션을 미리 지정해 두는 파일입니다. 기본 config 파일은 ~/.ssh/config 경로에 존재합니다. 만약 config 파일이 없다면 해당 경로에 생성하면 됩니다.
접속할 호스트를 등록하는 기본 구성은 다음과 같습니다.</p>
</blockquote>
<pre><code>Host [접속할 호스트 이름]
    HostName [호스트 IP 주소]
    Port [접속할 포트]
    User [호스트 사용자 이름]
    IdentityFile [접속시 사용할 개인 키 파일 경로]</code></pre><p>ssh 개인 키(private key) 파일은 ssh-keygen 등을 이용하여 생성할 수 있습니다. 현재 ~/.ssh 경로 아래 개인 키 파일이 존재한다고 가정하며, 키 파일 생성 과정은 자세히 다루지 않겠습니다. </p>
<h3 id="vs-code-설정-리눅스-ssh-서버-연결">VS Code 설정: 리눅스 ssh 서버 연결</h3>
<blockquote>
<p>이제 생성한 호스트에 접속하기 위해 커맨드 팔레트에서 <strong>Remote-SSH: Connect to Host…</strong>를 클릭하고 앞서 작성한 Host 이름을 클릭합니다.</p>
</blockquote>
<p>새 윈도우가 열리고 윈도우 상단에 사용자 암호를 입력하는 창이 뜨면 리눅스 사용자의 암호를 입력하고 엔터를 눌러 접속을 완료합니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/ed052570-8a81-4e80-8ff6-db1078c3e450/image.png" alt="">
<img src="https://velog.velcdn.com/images/pingu_9/post/448403a0-1f81-4b95-bdb0-989cf3e7a2a2/image.png" alt=""></p>
<ul>
<li>아까 config에 본인이 설정한 HostName이 뜰겁니다!
<img src="https://velog.velcdn.com/images/pingu_9/post/8fb19a0f-96a0-4260-8fd7-a484f1ea666e/image.png" alt=""></li>
</ul>
<h3 id="vs-code-사용">VS Code 사용</h3>
<p><strong>Open Folder</strong>를 클릭하고 원하는 디렉토리를 선택한 뒤 암호를 한 번 더 입력합니다. 이제 리눅스 환경에 존재하는 파일들을 VS Code에서 열고 수정할 수 있습니다. 테스트로 Desktop 디렉토리에 a.txt 파일을 생성하고 내용을 작성한 뒤 저장하겠습니다.<img src="https://velog.velcdn.com/images/pingu_9/post/95e56e02-5542-4eed-ad5f-72e42dbdfbc5/image.png" alt=""></p>
<ul>
<li>그럼 아래와 같이 리눅스 환경에 a.txt 파일이 생성되고, 작성한 내용도 잘 반영된 것을 볼 수 있습니다!</li>
</ul>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/141ff93e-769f-45cf-be62-846bef402247/image.png" alt=""></p>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고문헌">출처 및 참고문헌</h1>
<h1 id="httpsjihyeong-ji99hy99tistorycom161"><a href="https://jihyeong-ji99hy99.tistory.com/161">https://jihyeong-ji99hy99.tistory.com/161</a></h1>
<h1 id="httpshi-sojeongtistorycom101"><a href="https://hi-sojeong.tistory.com/101">https://hi-sojeong.tistory.com/101</a></h1>
<h1 id="httpslearndreamhackio44911"><a href="https://learn.dreamhack.io/449#11">https://learn.dreamhack.io/449#11</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[CTF[4일차]]]></title>
            <link>https://velog.io/@pingu_9/CTF4%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/CTF4%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Mon, 09 Dec 2024 06:37:29 GMT</pubDate>
            <description><![CDATA[<blockquote>
<details>
  <summary>참고</summary>
  <div><span style="color:blue">
※참고 자료는 드림핵을 이용하였습니다.<br>
※드림핵의 로드맵대로 공부할 예정입니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</blockquote>
</details>

<h1 id="권한">권한</h1>
<h2 id="유저user와-그룹group">유저(user)와 그룹(group)</h2>
<blockquote>
<p>리눅스에서 <strong>유저</strong>와 <strong>그룹</strong>은 <strong>리눅스의 권한 시스템</strong>을 설명하기 위해 빠뜨릴 수 없는 개념입니다.
리눅스의 각 <strong>유저</strong>는 이름과 <strong>고유한 사용자 ID(UID)</strong> 를 가지고 있습니다.
<strong>그룹</strong>은 말 그대로 여러 유저가 속할 수 있는 그룹으로, 이 역시 그룹 이름과 <strong>고유한 그룹 ID(GID)</strong> 를 가지고 있습니다.<br>
파일이나 디렉토리와 같은 시스템 자원에 유저가 접근하면 유저의 UID와 해당 유저가 속한 그룹의 GID를 확인하여 정당한 권한을 가지고 있는지를 판단해 접근을 제어합니다.</p>
</blockquote>
<blockquote>
<p><code style="background-color:grey; color:orange">/etc/passwd</code> 는 리눅스의 유저 정보를 담고 있는 텍스트 파일입니다.
각 사용자의 이름, 사용자 ID, 속해있는 그룹 ID 등의 정보를 포함하고 있습니다.</p>
<blockquote>
<ul>
<li>다음과 같이 <code style="background-color:grey; color:orange">cat</code> 명령어로 <code style="background-color:grey; color:orange">/etc/passwd</code> 파일의 내용을 확인할 수 있습니다.</li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
...(생략)
user:x:1000:1000:user,,,:/home/user:/bin/bash
fwupd-refresh:x:128:136:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
vboxadd:x:999:1::/var/run/vboxadd:/bin/false
user@user-VirtualBox:~/new_dir$</code></pre>
<blockquote>
<p><code style="background-color:grey; color:orange">/etc/group</code> 은 리눅스의 그룹 정보를 저장하는 텍스트 파일입니다.
각 그룹의 이름, 그룹 ID, 그룹에 속한 유저 목록 등의 정보를 포함하고 있습니다.</p>
<blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">cat</code> 명령어로 <code style="background-color:grey; color:orange">/etc/group</code> 파일의 내용을 확인한 결과입니다.</li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ cat /etc/group
root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:syslog,user
tty:x:5:
disk:x:6:
...(생략)
user:x:1000:
sambashare:x:135:user
fwupd-refresh:x:136:
vboxsf:x:999:
vboxdrmipc:x:998:
user@user-VirtualBox:~/new_dir$</code></pre>
<h2 id="파일-및-디렉토리-권한">파일 및 디렉토리 권한</h2>
<blockquote>
<ul>
<li>리눅스는 사용자가 파일과 디렉토리에 접근하는 행위에 대해 권한으로 제어합니다.</li>
</ul>
</blockquote>
<ul>
<li>각 파일과 디렉토리 <strong>소유자(owner)</strong>와 <strong>소유 그룹(group)</strong>을 가지고 있습니다.</li>
<li>소유자는 파일 또는 디렉토리의 권한을 수정할 수 있는 능력을 가지고 있습니다.</li>
<li>소유자는 이를 통해 소유자 또는 소유 그룹에 포함된 유저가 해당 파일 또는 디렉토리에 대해서 <strong>얼마만큼 접근 권한을 가질 것인지</strong> 설정할 수 있습니다.</li>
<li>다음과 같이 세 종류의 접근 권한이 있습니다.<ul>
<li><strong>읽기(Read)</strong>: 파일 또는 디렉토리의 내용을 볼 수 있게 허용합니다.</li>
<li><strong>쓰기(Write)</strong>: 파일 또는 디렉토리의 내용을 수정하거나 삭제하는 것을 허용합니다.</li>
<li><strong>실행(Execute)</strong>: 파일이 프로그램인 경우 실행할 수 있게 허용합니다. 디렉토리의 경우, 디렉토리의 내용에 접근할 수 있도록 허용합니다.<br>
파일이나 디렉토리의 권한을 보기 위해 <code style="background-color:grey; color:orange">ls -l</code>를 사용합니다.
해당 명령어는 디렉토리의 내용을 권한 정보와 함께 출력합니다.</li>
</ul>
</li>
<li>다음은 <code style="background-color:grey; color:orange">ls -l</code> 명령어 예시 결과입니다.
```linux
user@user-VirtualBox:~/new_dir$ ls -l
total 12
drwxrwxr-x 2 user user 4096 12월  2 13:38 dir</li>
<li>--------- 1 user user   13 12월  2 13:05 hello</li>
<li>rwxrw-r-- 1 user user   13 12월  2 13:08 world
user@user-VirtualBox:~/new_dir$
```</li>
<li>다음은 <code style="background-color:grey; color:orange">dir</code> 디렉토리의 예시입니다. <strong>첫 번째 열은 권한 플래그</strong>를 나타내고 <strong>세 번째 열은 소유자</strong>를 나타냅니다. <strong>네 번째 열은 소유 그룹</strong>을 나타냅니다. 결과의 첫 번째 행을 가져와 자세히 살펴보겠습니다.<pre><code class="language-linux">drwxrwxr-x 2 user user 4096 12월 2 13:38 dir</code></pre>
<code style="background-color:grey; color:orange">dir</code>의 권한 플래그는 <code style="background-color:grey; color:orange">drwxrwxr-x</code>이고, 소유자는 <code style="background-color:grey; color:orange">user</code>이며 소유 그룹은 <code style="background-color:grey; color:orange">user</code> 입니다. 각각에 대해 자세히 알아보겠습니다.<blockquote>
<blockquote>
<h3 id="첫-번째-열-code-stylebackground-colorgrey-colororangedrwxrwxr-xcode--권한-플래그">첫 번째 열 <code style="background-color:grey; color:orange">drwxrwxr-x</code> : 권한 플래그</h3>
</blockquote>
</blockquote>
<pre><code class="language-linux">drwxrwxr-x 2 user user 4096 12월 2 13:38 dir</code></pre>
</li>
<li>위 결과에서 <strong>첫 번째 열</strong>이 각 파일 또는 디렉토리의 권한 플래그를 나타냅니다.</li>
<li>권한 플래그는 다음과 같이 4개의 부분으로 나뉠 수 있습니다:  <strong>d  rwx  rwx  r-x</strong><br></li>
<li><strong>d</strong> rwx rwx r-x
먼저 위에서 bold 처리한 첫 번째 문자는 파일의 타입을 나타냅니다.
<code style="background-color:grey; color:orange">d</code>는 디렉토리, <code style="background-color:grey; color:orange">-</code>는 일반 파일, <code style="background-color:grey; color:orange">l</code>은 바로가기와 같은 링크 파일을 나타냅니다.<br></li>
<li>d <strong>rwx</strong> rwx r-x
그 다음 문자들은 권한 플래그입니다. 문자 3개씩 3개의 덩어리로 나뉩니다.
위에서 bold 처리한 3개의 문자는 파일 또는 디렉터리의 <strong>소유자의 권한</strong>을 나타냅니다.<br></li>
<li>d rwx <strong>rwx</strong> r-x
위에서 bold 처리한 3개의 문자는 파일 또는 디렉토리의 <strong>소유 그룹에 포함된 유저들의 권한</strong>을 나타냅니다.<br></li>
<li>d rwx rwx <strong>r-x</strong>
위에서 bold 처리한 3개의 문자는 파일 또는 디렉토리의 소유자 및 소유 그룹에 포함된 유저들을 제외한, <strong>나머지 유저들의 권한</strong>을 나타냅니다.<br>
권한을 나타내는 각 문자에 대한 설명은 다음과 같습니다.</li>
<li><code style="background-color:grey; color:orange">r</code>: 소유자(또는 소유 그룹에 포함된 유저들 또는 그외 유저)가 파일 또는 디렉토리에 <strong>읽기(Read)</strong> 권한을 가집니다.</li>
<li><code style="background-color:grey; color:orange">w</code>: 소유자(또는 소유 그룹에 포함된 유저들 또는 그외 유저)가 파일 또는 디렉토리에 <strong>쓰기(Write)</strong> 권한을 가집니다.</li>
<li><code style="background-color:grey; color:orange">x</code>: 소유자(또는 소유 그룹에 포함된 유저들 또는 그외 유저)가 파일 또는 디렉토리에 <strong>실행(Execute)</strong> 권한을 가집니다.<br>
권한을 나타내는 3개 문자는 2진수나 10진수로도 표현이 가능합니다.
예를 들어 <code style="background-color:grey; color:orange">rwx</code> 는 2진수로 <code style="background-color:grey; color:orange">111</code>이며, 10진수로는 7입니다.
<code style="background-color:grey; color:orange">r--</code> 은 2진수로 <code style="background-color:grey; color:orange">100</code>이며, 10진수로는 4입니다.<blockquote>
<blockquote>
<h3 id="세-번째-열-code-stylebackground-colorgrey-colororangeusercode--소유자">세 번째 열 <code style="background-color:grey; color:orange">user</code> : 소유자</h3>
</blockquote>
</blockquote>
<pre><code class="language-linux">drwxrwxr-x 2 user user 4096 12월 2 13:38 dir</code></pre>
위 결과에서 <strong>세 번째 열</strong>이 파일 또는 디렉토리의 소유자를 나타냅니다.<br></li>
<li><em>소유자*</em>는 파일 또는 디렉토리에 대한 제어권을 가지고 있습니다.
소유자는 파일 또는 디렉토리의 권한 플래그를 변경할 수 있고 파일의 소유자 또는 소유 그룹을 변경할 수도 있습니다.
위 <code style="background-color:grey; color:orange">dir</code> 디렉토리의 소유자가 <code style="background-color:grey; color:orange">user</code> 유저임을 알 수 있습니다.<blockquote>
<blockquote>
<h3 id="네-번째-열-code-stylebackground-colorgrey-colororangeusercode--소유-그룹">네 번째 열 <code style="background-color:grey; color:orange">user</code> : 소유 그룹</h3>
<p>리눅스에는 여러 사용자를 하나의 집합으로 관리할 수 있는 <strong>그룹</strong> 기능이 있습니다.</p>
</blockquote>
</blockquote>
</li>
<li><em>소유 그룹*</em>은 그룹 단위로 파일 또는 디렉토리에 권한을 부여할 때 사용합니다.
특정 파일 또는 디렉토리에 대한 접근 권한을 편리하게 그룹 단위로 부여하거나 제한할 수 있어 자주 활용되는 기능입니다.</li>
</ul>
<blockquote>
<blockquote>
<h3 id="결론">결론</h3>
<p>앞서 배운 것들을 종합하여 아래의 ls -l 결과를 해석해보겠씁니다.</p>
</blockquote>
</blockquote>
<pre><code class="language-linux">-rwxrw-r-- 1 user user 13 12월 2 13:08 world</code></pre>
<p>우선 <strong>소유자</strong>는 <code style="background-color:grey; color:orange">user</code>이며 <strong>소유 그룹</strong>은 <code style="background-color:grey; color:orange">user</code>입니다.<br>
권한 플래그는 다음과 같습니다.
<code>rwx rw- r--</code></p>
<ul>
<li><strong>파일 타입을 나타내는 첫 번째 문자</strong>가 <code style="background-color:grey; color:orange">-</code> 이므로 <code style="background-color:grey; color:orange">world</code> 는 <strong>일반 파일</strong>입니다.</li>
<li><strong>소유자 권한 플래그</strong>는 <code style="background-color:grey; color:orange">rwx</code> 이므로 <code style="background-color:grey; color:orange">user</code> 유저는 <code style="background-color:grey; color:orange">world</code> 파일을 <strong>읽고 쓰고 실행</strong>할 수 있습니다.</li>
<li><strong>소유 그룹 권한 플래그</strong>는 <code style="background-color:grey; color:orange">rw-</code> 이므로 <code style="background-color:grey; color:orange">user</code> 그룹에 속한 유저들은 <code style="background-color:grey; color:orange">world</code> 파일을 <strong>읽고 쓸 수는 있지만 실행할 수는 없습니다.</strong></li>
<li><code style="background-color:grey; color:orange">user</code> 유저가 아니면서 <code style="background-color:grey; color:orange">user</code> 그룹에 속하지 않은 유저들은 <code style="background-color:grey; color:orange">r--</code> 권한을 가지므로 <code style="background-color:grey; color:orange">world</code> 파일을 <strong>읽을 수만 있고 쓰거나 실행할 수는 없습니다.</strong></li>
</ul>
<h2 id="파일-및-디렉토리-권한-명령어">파일 및 디렉토리 권한 명령어</h2>
<h3 id="chmod">chmod</h3>
<blockquote>
<p><code style="background-color:grey; color:orange">chmod</code>는 파일 권한을 변경하는 명령어입니다. <code style="background-color:grey; color:orange">root</code> 유저 혹은 파일의 소유자만 실행할 수 있습니다.
<code style="background-color:grey; color:orange">chmod 권한 파일명</code> 형식으로 사용합니다.
권한을 표현할 때는 권한 플래그를 10진수로 표현하거나 기존의 권한에 문자를 더하거나 뺍니다.</p>
<blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">ls -l</code> 명령어 결과입니다. <code style="background-color:grey; color:orange">hello</code> 파일에 아무 권한도 부여되지 않은 상태입니다.</li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ ls -l
total 12
drwxrwxr-x 2 user user 4096 12월  2 13:38 dir
---------- 1 user user   13 12월  2 13:05 hello
-rwxrw-r-- 1 user user   13 12월  2 13:08 world
user@user-VirtualBox:~/new_dir$</code></pre>
<p><code style="background-color:grey; color:orange">world</code> 파일과 동일하게, 소유자는 읽고 쓰고 실행할 수 있고, 소유 그룹은 읽고 쓸 수 있고, 일반 유저는 읽을 수만 있도록 <code style="background-color:grey; color:orange">hello</code> 파일 권한을 수정하겠습니다.<br>
소유자 권한은 <strong>rwx</strong>이므로 <code style="background-color:grey; color:orange">111</code>=<strong>7</strong>, 소유 그룹 권한은 <strong>rw-</strong>이므로 <code style="background-color:grey; color:orange">110</code>=<strong>6</strong>, 일반 유저 권한은 <strong>r--</strong>이므로 <code style="background-color:grey; color:orange">100</code>=<strong>4</strong>입니다.</p>
<ul>
<li><code style="background-color:grey; color:orange">chmod 764 hello</code> 를 실행하면 권한이 아래와 같이 변경됩니다.
```linux
user@user-VirtualBox:<del>/new_dir$ chmod 764 hello
user@user-VirtualBox:</del>/new_dir$ ls -l
total 12
drwxrwxr-x 2 user user 4096 12월  2 13:38 dir</li>
<li>rwxrw-r-- 1 user user   13 12월  2 13:05 hello</li>
<li>rwxrw-r-- 1 user user   13 12월  2 13:08 world
user@user-VirtualBox:~/new_dir$
```<blockquote>
<blockquote>
</blockquote>
<p>이번에는 <code style="background-color:grey; color:orange">hello</code> 파일 소유 그룹에 실행 권한을 부여하겠습니다.
다음과 같이 <code style="background-color:grey; color:orange">chmod g+x hello</code> 명령어를 실행하면 권한이 변경됩니다.
권한을 제거하고 싶으면 <code style="background-color:grey; color:orange">chmod g-wx hello</code>와 같은 형식으로 입력합니다.</p>
</blockquote>
```linux
user@user-VirtualBox:<del>/new_dir$ chmod g+x hello
user@user-VirtualBox:</del>/new_dir$ ls -l
total 12
drwxrwxr-x 2 user user 4096 12월  2 13:38 dir</li>
<li>rwxrwxr-- 1 user user   13 12월  2 13:05 hello</li>
<li>rwxrw-r-- 1 user user   13 12월  2 13:08 world
user@user-VirtualBox:<del>/new_dir$ chmod g-wx hello
user@user-VirtualBox:</del>/new_dir$ ls -l
total 12
drwxrwxr-x 2 user user 4096 12월  2 13:38 dir</li>
<li>rwxr--r-- 1 user user   13 12월  2 13:05 hello</li>
<li>rwxrw-r-- 1 user user   13 12월  2 13:08 world<pre><code></code></pre></li>
</ul>
<h3 id="chown">chown</h3>
<blockquote>
<p><code style="background-color:grey; color:orange">chown</code>은 파일 소유자 혹은 소유 그룹을 변경하는 명령어입니다.
<code style="background-color:grey; color:orange">root</code> 유저만 실행할 수 있습니다.
<code style="background-color:grey; color:orange">chown 사용자명[.그룹명] 파일명</code> 형식으로 사용합니다.
소유 그룹만 변경하고 싶은 경우 <code style="background-color:grey; color:orange">chgrp</code> 명령어를 사용합니다.</p>
</blockquote>
<p><code style="background-color:grey; color:orange">hello</code> 파일의 소유자를 <code style="background-color:grey; color:orange">user</code>에서 <code style="background-color:grey; color:orange">root</code>로 변경하겠습니다. 명령어를 <code style="background-color:grey; color:orange">root</code> 권한으로 실행하려면 맨 앞에 <code style="background-color:grey; color:orange">sudo</code>를 붙여줍니다.</p>
<blockquote>
</blockquote>
<p><code style="background-color:grey; color:orange">sudo chown root hello</code> 명령어를 실행하면 소유자가 변경됩니다. 이제 <code style="background-color:grey; color:orange">user</code> 유저는 <code style="background-color:grey; color:orange">hello</code> 파일을 수정할 수 없습니다.</p>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ ls -l
total 12
drwxrwxr-x 2 user user 4096 12월  2 13:38 dir
-rwxr--r-- 1 user user   13 12월  2 13:05 hello
-rwxrw-r-- 1 user user   13 12월  2 13:08 world
user@user-VirtualBox:~/new_dir$ sudo chown root hello
[sudo] password for user: 
user@user-VirtualBox:~/new_dir$ ls -l
total 12
drwxrwxr-x 2 user user 4096 12월  2 13:38 dir
-rwxr--r-- 1 root user   13 12월  2 13:05 hello
-rwxrw-r-- 1 user user   13 12월  2 13:08 world
user@user-VirtualBox:~/new_dir$ echo &quot;hello&quot; &gt; hello
bash: hello: Permission denied
user@user-VirtualBox:~/new_dir$ </code></pre>
<h2 id="특수-권한">특수 권한</h2>
<blockquote>
<p>앞서 배운 r,w,x 권한 외에 특수한 권한 3가지를 소개하겠습니다.</p>
</blockquote>
<ul>
<li><h3 id="setuid-일반-사용자가-파일을-실행하면-파일-소유자-권한으로-실행됩니다">setuid: 일반 사용자가 파일을 실행하면 파일 소유자 권한으로 실행됩니다.</h3>
예를 들어, <code style="background-color:grey; color:orange">/bin/passwd</code> 파일은 소유자가 <code style="background-color:grey; color:orange">root</code>이지만 setuid가 설정되어 있어 일반 사용자가 <code style="background-color:grey; color:orange">root</code> 권한으로 실행하고 비밀번호도 변경할 수 있습니다.
setuid는 소유자의 실행 권한에 <code style="background-color:grey; color:orange">x</code> 대신 <code style="background-color:grey; color:orange">s</code> 문자로 나타냅니다.
대문자 <code style="background-color:grey; color:orange">S</code>로 표시되는 경우에는 setuid가 걸려 있으나, 실행 권한이 없는 경우입니다.<blockquote>
<br></blockquote>
</li>
<li><code style="background-color:grey; color:orange">/bin/passwd</code>의 권한 플래그는 다음과 같습니다.
```linux
user@user-VirtualBox:/bin$ ls -l passwd</li>
<li>rwsr-xr-x 1 root root 59976 11월 24 21:05 passwd
```</li>
<li>소유자의 실행 권한이 s로 설정된 것을 볼 수 있습니다.<blockquote>
<br></blockquote>
</li>
<li><h3 id="setgid-일반-사용자가-파일을-실행하면-파일-소유-그룹-권한으로-실행됩니다">setgid: 일반 사용자가 파일을 실행하면 파일 소유 그룹 권한으로 실행됩니다.</h3>
setgid는 소유 그룹의 실행 권한에 <code style="background-color:grey; color:orange">x</code> 대신 <code style="background-color:grey; color:orange">s</code> 문자로 나타냅니다.
마찬가지로 실행 권한이 없으나 setgid가 걸려 있는 경우 대문자 <code style="background-color:grey; color:orange">S</code>로 표시됩니다.<blockquote>
<br></blockquote>
</li>
<li><h3 id="sticky-bit-디렉토리에-sticky-bit를-설정하면-파일-및-디렉토리-소유자와-root-사용자-외에-일반-사용자가-파일을-삭제할-수-없습니다">sticky bit: 디렉토리에 sticky bit를 설정하면 파일 및 디렉토리 소유자와 root 사용자 외에 일반 사용자가 파일을 삭제할 수 없습니다.</h3>
주로 공용 디렉토리에 사용합니다. 일반 사용자의 실행 권한에 <code style="background-color:grey; color:orange">x</code> 대신 <code style="background-color:grey; color:orange">t</code> 문자로 나타냅니다.
이 역시 마찬가지로 실행 권한이 없는 경우에는 대문자 <code style="background-color:grey; color:orange">T</code>로 표시됩니다.<blockquote>
<blockquote>
<p>특수 권한을 지정할 때는 권한 플래그 맨 앞에 숫자를 붙여 나타냅니다.</p>
</blockquote>
</blockquote>
</li>
<li><em>setuid*</em>는 <strong>4</strong>, <strong>setgid</strong>는 <strong>2</strong>, <strong>sticky bit</strong>는 <strong>1</strong>입니다.<br></li>
<li><code style="background-color:grey; color:orange">다음은 chmod 4755 world</code> 명령어로 <code style="background-color:grey; color:orange">world</code> 파일에 실행 권한과 setuid를 설정하는 모습입니다. setuid만 설정하는 경우 <code style="background-color:grey; color:orange">chmod u+s world</code>도 가능합니다. <blockquote>
<blockquote>
</blockquote>
<p>setgid는 <code style="background-color:grey; color:orange">chmod g+s world</code>, sticky bit는 <code style="background-color:grey; color:orange">chmod o+t world</code>로 설정할 수 있습니다.</p>
</blockquote>
```linux
user@user-VirtualBox:~/new_dir$ ls -l
total 12
drwxrwxr-x 2 user user 4096 12월  2 13:38 dir</li>
<li>rwxr--r-- 1 root user   13 12월  2 13:05 hello</li>
<li>rwxrw-r-- 1 user user   13 12월  2 13:08 world
user@user-VirtualBox:<del>/new_dir$ chmod 4775 world
user@user-VirtualBox:</del>/new_dir$ ls -l
total 12
drwxrwxr-x 2 user user 4096 12월  2 13:38 dir</li>
<li>rwxr--r-- 1 root user   13 12월  2 13:05 hello</li>
<li>rwsrwxr-x 1 user user   13 12월  2 13:08 world<pre><code></code></pre></li>
</ul>
<h2 id="디렉토리-구조">디렉토리 구조</h2>
<h3 id="루트-디렉토리code-stylebackground-colorgrey-colororangecode">루트 디렉토리<code style="background-color:grey; color:orange">/</code></h3>
<p>루트 디렉토리는 리눅스의 최상위 디렉토리를 말하며, 절대 경로는 <code style="background-color:grey; color:orange">/</code>입니다.
<code style="background-color:grey; color:orange">cd /; ls -l</code> 또는 <code style="background-color:grey; color:orange">ls -l /</code>를 실행하면 루트 디렉토리에 존재하는 파일과 디렉토리들을 볼 수 있습니다.</p>
<ul>
<li>명령어 실행 결과는 다음과 같습니다.
```linux
user@user-VirtualBox:~$ ls -l /
total 3991632
lrwxrwxrwx   1 root root          7 11월 30 18:15 bin -&gt; usr/bin
drwxr-xr-x   4 root root       4096 12월  1 14:10 boot
drwxrwxr-x   2 root root       4096 11월 30 18:25 cdrom
drwxr-xr-x  19 root root       4180 12월  1 14:25 dev
drwxr-xr-x 130 root root      12288 12월  1 14:09 etc
drwxr-xr-x   3 root root       4096 11월 30 18:27 home
lrwxrwxrwx   1 root root          7 11월 30 18:15 lib -&gt; usr/lib
lrwxrwxrwx   1 root root          9 11월 30 18:15 lib32 -&gt; usr/lib32
lrwxrwxrwx   1 root root          9 11월 30 18:15 lib64 -&gt; usr/lib64
lrwxrwxrwx   1 root root         10 11월 30 18:15 libx32 -&gt; usr/libx32
drwx------   2 root root      16384 11월 30 18:14 lost+found
drwxr-xr-x   3 root root       4096 11월 30 19:49 media
drwxr-xr-x   2 root root       4096  8월  9 20:48 mnt
drwxr-xr-x   3 root root       4096 11월 30 19:55 opt
dr-xr-xr-x 257 root root          0 12월  1 14:11 proc
drwx------   4 root root       4096 12월  1 14:17 root
drwxr-xr-x  33 root root        900 12월  1 14:12 run
lrwxrwxrwx   1 root root          8 11월 30 18:15 sbin -&gt; usr/sbin
drwxr-xr-x  11 root root       4096  8월  9 20:55 snap
drwxr-xr-x   2 root root       4096  8월  9 20:48 srv</li>
<li>rw-------   1 root root 4087349248 11월 30 18:15 swapfile
dr-xr-xr-x  13 root root          0 12월  1 14:11 sys
drwxrwxrwt  20 root root       4096 12월  1 14:17 tmp
drwxr-xr-x  14 root root       4096  8월  9 20:48 usr
drwxr-xr-x  14 root root       4096  8월  9 20:54 var
user@user-VirtualBox:~$<pre><code>위 &lt;code style=&quot;background-color:grey; color:orange&quot;&gt;ls&lt;/code&gt; 명령어 실행 결과에서 볼 수 있듯이 루트 디렉토리 안에 많은 디렉토리가 존재합니다.
이중 몇 가지 중요한 디렉토리들을 알아보겠습니다.
&gt;#### &lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/bin&lt;/code&gt;
&gt;&gt;일반 유저가 사용할 수 있는 기본적인 명령어나 프로그램을 담고 있는 디렉토리입니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/boot&lt;/code&gt;
&gt;&gt;시스템 부팅에 필요한 파일들을 담고 있는 디렉토리입니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/dev&lt;/code&gt;
&gt;&gt;리눅스에서는 컴퓨터에 부착된 물리적인 장치들을 디바이스 드라이버를 거쳐 파일 형태로 접근 가능합니다.
그러한 장치들을 나타내는 파일들을 담고 있는 디렉토리입니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/etc&lt;/code&gt;
&gt;&gt;운영체제나 운영체제 위에서 동작하는 서비스의 설정 파일들을 담고 있는 디렉토리입니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/home&lt;/code&gt;
&gt;&gt;각 일반 유저의 홈 디렉토리를 담고 있는 디렉토리입니다. 일반 유저들은 각기 자신만의 홈 디렉토리를 가지고 있습니다. 예를 들어 &lt;code style=&quot;background-color:grey; color:orange&quot;&gt;dream&lt;/code&gt; 유저의 홈 디렉토리는 &lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/home/dream&lt;/code&gt; 입니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/lib&lt;/code&gt;
&gt;&gt;시스템에 필요한 라이브러리 파일들을 담고 있는 디렉토리입니다. &lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/bin&lt;/code&gt; 이나 &lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/sbin&lt;/code&gt; 에 존재하는 프로그램이 필요로 하는 동적 라이브러리 파일이 &lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/lib&lt;/code&gt; 디렉토리에 존재합니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/opt&lt;/code&gt;
&gt;&gt;소프트웨어 패키지들을 담는 디렉토리입니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/proc&lt;/code&gt;
&gt;&gt;리눅스 커널 자원에 접근할 수 있는 파일과 프로세스를 나타내는 파일을 담고 있습니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/root&lt;/code&gt;
&gt;&gt;&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;root&lt;/code&gt; 유저의 홈 디렉토리입니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/sbin&lt;/code&gt;
&gt;&gt;&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/bin&lt;/code&gt; 디렉토리와 마찬가지로 기본적인 유저 명령어나 프로그램을 가지고 있는 디렉토리입니다. &lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/sbin&lt;/code&gt;은 &lt;code style=&quot;background-color:grey; color:orange&quot;&gt;root&lt;/code&gt; 유저가 사용할 수 있는 명령어나 프로그램을 가지고 있습니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/tmp&lt;/code&gt;
&gt;&gt;유저나 프로그램이 임시로 파일을 생성해야할 때 사용할 수 있는 디렉토리입니다. 본 디렉토리에 오래 존재했던 파일들은 자동으로 삭제되므로 주의하여 사용해야 합니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/usr&lt;/code&gt;
&gt;&gt;사용자 바이너리, 문서, 라이브러리, 헤더 파일 등을 담고 있는 디렉토리입니다.
&gt;
&lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/var&lt;/code&gt;
&gt;&gt;프로그램이나 시스템이 실시간으로 가변적인 파일을 사용하고 저장해야 할 때 활용하는 디렉토리입니다.
예를 들어 &lt;code style=&quot;background-color:grey; color:orange&quot;&gt;/var/log&lt;/code&gt;에는 다양한 로그 파일이 저장됩니다.

</code></pre></li>
</ul>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고자료">출처 및 참고자료</h1>
<h1 id="httpslearndreamhackio44116"><a href="https://learn.dreamhack.io/441#16">https://learn.dreamhack.io/441#16</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬[4일차]]]></title>
            <link>https://velog.io/@pingu_9/python4%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/python4%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Sun, 08 Dec 2024 14:30:30 GMT</pubDate>
            <description><![CDATA[<details>
  <summary>참고</summary>
  <div><span style="color:blue">참고 자료는 점프 투 파이썬으로 선택했습니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</details>

<h1 id="집합-자료형">집합 자료형</h1>
<blockquote>
<p>집합(set)은 집합에 관련된 것을 쉽게 처리하기 위해 만든 자료형이다.</p>
</blockquote>
<h2 id="집합-자료형은-어떻게-만들까">집합 자료형은 어떻게 만들까?</h2>
<ul>
<li>집합 자료형은 다음과 같이 set 키워드를 사용해 만들 수 있다.<pre><code class="language-python">&gt;&gt;&gt; s1 = set([1,2,3])
&gt;&gt;&gt; s1
{1,2,3}</code></pre>
</li>
<li>위와 같이 set()의 괄호 안에 리스트를 입력하여 만들거나 다음과 같이 문자열을 입력하여 만들 수도 있다.<pre><code class="language-python">&gt;&gt;&gt; s2 = set(&quot;Hello&quot;)
&gt;&gt;&gt; s2
{&#39;e&#39;,&#39;H&#39;,&#39;l&#39;,&#39;o&#39;}</code></pre>
<blockquote>
<p>비어 있는 집합 자료형은 s = set()로 만들 수 있다.</p>
</blockquote>
</li>
</ul>
<h2 id="집합-자료형의-특징">집합 자료형의 특징</h2>
<p>그런데 위에서 살펴본 <code style="background-color:grey; color:orange">set("Hello")</code>의 결과가 좀 이상하지 않은가?
분명 &quot;Hello&quot; 문자열로 set 자료형을 만들었는데 생성된 자료형에는 l 문자가 하나 빠져 있고 순서도 뒤죽박죽이다.
그 이유는 set에 다음과 같은 2가지 특징이 있기 때문이다.</p>
<ul>
<li><p><strong>중복을 허용하지 않는다.</strong></p>
</li>
<li><p><strong>순서가 없다(Unordered).</strong></p>
<blockquote>
<p>set은 <u>중복을 허용하지 않는 특징</u> 때문에 데이터의 중복을 제거하기 위한 필터로 종종 사용된다.</p>
<blockquote>
<ul>
<li>리스트나 튜플은 순서가 있기(ordered) 때문에 인덱싱을 통해 요솟값을 얻을 수 있지만,</li>
<li>set 자료형은 순서가 없기(unordered) 때문에 인덱싱을 통해 요솟값을 얻을 수 없다.</li>
<li>이는 마치 딕셔너리와 비슷하다.</li>
<li>딕셔너리 역시 순서가 없는 자료형이므로 인덱싱을 지원하지 않는다.</li>
</ul>
</blockquote>
</blockquote>
</li>
<li><p>만약 set 자료형에 저장된 값을 인덱싱으로 접근하려면 다음과 같이 리스트나 튜플로 변환한 후에 해야 한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; s1 = set([1, 2, 3])
&gt;&gt;&gt; l1 = list(s1)
&gt;&gt;&gt; l1
[1, 2, 3]
&gt;&gt;&gt; l1[0]
1
&gt;&gt;&gt; t1 = tuple(s1)
&gt;&gt;&gt; t1
(1, 2, 3)
&gt;&gt;&gt; t1[0]
1</code></pre>
</li>
</ul>
<blockquote>
<h3 id="교집한-합집합-차집합-구하기">교집한, 합집합, 차집합 구하기</h3>
<blockquote>
<p>set 자료형을 정말 유용하게 사용하는 경우는 교집합, 합집합, 차집합을 구할 때이다.</p>
</blockquote>
</blockquote>
<ul>
<li>먼저 다음과 같이 2개의 set 자료형을 만든 후 따라 해 보자.
s1에는 1부터 6까지의 값, s2에는 4부터 9까지의 값을 주었다.<pre><code class="language-python">&gt;&gt;&gt; s1 = set([1, 2, 3, 4, 5, 6])
&gt;&gt;&gt; s2 = set([4, 5, 6, 7, 8, 9])</code></pre>
<h4 id="교집합-구하기">교집합 구하기</h4>
s1과 s2의 교집합을 구해 보자.</li>
<li>다음과 같이 &#39;&amp;&#39;를 이용하면 교집합을 간단히 구할 수 있다.<pre><code class="language-python">&gt;&gt;&gt; s1 &amp; s2
{4,5,6}</code></pre>
</li>
<li>또는 다음과 같이 intersection 함수를 사용해도 결과는 동일하다.<pre><code class="language-python">&gt;&gt;&gt; s1.intersection(s2)
{4,5,6}</code></pre>
</li>
<li>s2.intersection(s1)을 사용해도 결과는 동일하다.<h4 id="합집합-구하기">합집합 구하기</h4>
&#39;|&#39;를 사용하면 합집합을 구할 수 있다.
이때 4,5,6처럼 중복해서 포함된 값은 1개씩만 표현된다.<pre><code class="language-python">&gt;&gt;&gt; s1 | s2
{1, 2, 3, 4, 5, 6, 7, 8, 9}</code></pre>
</li>
<li>union 함수를 사용해도 된다.<pre><code class="language-python">&gt;&gt;&gt; s1.union(s2)
{1, 2, 3, 4, 5, 6, 7, 8, 9}</code></pre>
</li>
<li>s2.union(s1)을 사용해도 결과는 동일하다.<h4 id="차집합-구하기">차집합 구하기</h4>
</li>
<li>(빼기_를 사용하면 차집합을 구할 수 있다.<pre><code class="language-python">&gt;&gt;&gt; s1 - s2
{1, 2, 3}
&gt;&gt;&gt; s2 - s1
{8, 9, 7}</code></pre>
</li>
<li>difference 함수를 사용해도 차집합을 구할 수 있다.<pre><code class="language-python">&gt;&gt;&gt; s1.difference(s2)
{1, 2, 3}
&gt;&gt;&gt; s2.difference(s1)
{8, 9, 7}</code></pre>
</li>
</ul>
<h2 id="집합-자료형-관련-함수">집합 자료형 관련 함수</h2>
<h3 id="값-1개-추가하기---add">값 1개 추가하기 - add</h3>
<ul>
<li>이미 만들어진 set 자료형에 값을 추가할 수 있다.</li>
<li>1개의 값만 추가 add할 때는 다음과 같이 하면 된다.<pre><code class="language-python">&gt;&gt;&gt; s1 = set([1, 2, 3])
&gt;&gt;&gt; s1.add(4)
&gt;&gt;&gt; s1
{1, 2, 3, 4}</code></pre>
<h3 id="값-여러-개-추가하기---update">값 여러 개 추가하기 - update</h3>
</li>
<li>여러 개의 값을 한꺼번에 추가(update)할 때는 다음과 같이 하면 된다.<pre><code class="language-python">&gt;&gt;&gt; s1 = set([1, 2, 3])
&gt;&gt;&gt; s1.update([4, 5, 6])
&gt;&gt;&gt; s1
{1, 2, 3, 4, 5, 6}</code></pre>
<h3 id="특정-값-제거하기---remove">특정 값 제거하기 - remove</h3>
특정 값을 제거하고 싶을 때는 다음과 같이 하면 된다.<pre><code class="language-python">&gt;&gt;&gt; s1 = set([1, 2, 3])
&gt;&gt;&gt; s1.remove(2)
&gt;&gt;&gt; s1
{1, 3}</code></pre>
</li>
</ul>
<hr>
<h1 id="불-자료형">불 자료형</h1>
<p>불(bool) 자료형이란 참(True)과 거짓(False)을 나타내는 자료형이다.</p>
<ul>
<li>불 자료형은 다음 2가지 값만을 가질 수 있다.<ul>
<li>True: 참을 의미한다.</li>
<li>False: 거짓을 의미한다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>True나 False는 파이썬의 예약어로, true, false와 같이 작성하면 안 되고 첫 문자를 항상 대문자로 작성해야 한다.</p>
</blockquote>
<h2 id="불-자료형은-어떻게-사용할까">불 자료형은 어떻게 사용할까?</h2>
<p>다음과 같이 변수 a에는 True, 변수 b에는 False를 지정해 보자.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = True
&gt;&gt;&gt; b = False</code></pre>
<ul>
<li><p>따옴표로 감싸지 않은 문자열을 변수에 지정해서 오류가 발생할 것 같지만, 잘 실행된다.</p>
</li>
<li><p>type 함수를 변수 a와 b에 사용하면 두 변수의 자료형이 bool로 지정된 것을 확인할 수 있다</p>
<pre><code class="language-python">&gt;&gt;&gt; type(a)
&lt;class &#39;bool&#39;&gt;
&gt;&gt;&gt; type(b)
&lt;class &#39;bool&#39;&gt;</code></pre>
<blockquote>
<p>type(x)는 x의 자료형을 확인하는 파이썬의 내장 함수이다.</p>
</blockquote>
</li>
<li><p>불 자료형은 조건문의 리턴값으로도 사용된다.</p>
</li>
<li><p>조건문에 대해서는 if 문에서 자세히 배우겠지만 잠시 살펴보고 넘어가자.</p>
<pre><code class="language-python">ed!&gt;&gt;&gt; 1 == 1
True</code></pre>
</li>
<li><p><code style="background-color:grey; color:orange">1 == 1</code> 은 ‘1과 1이 같은가?’를 묻는 조건문이다.</p>
</li>
<li><p>이런 조건문은 결과로 True 또는 False에 해당하는 불 자료형을 리턴한다.</p>
<ul>
<li>1과 1은 같으므로 True를 리턴한다.<pre><code class="language-python">&gt;&gt;&gt; 2 &gt; 1
True</code></pre>
</li>
</ul>
</li>
<li><p>2는 1보다 크므로 <code style="background-color:grey; color:orange">2 > 1</code> 조건문은 참이다. 즉, True를 리턴한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; 2 &lt; 1
False</code></pre>
</li>
<li><p>2는 1보다 작지 않으므로 <code style="background-color:grey; color:orange">2 < 1</code> 조건문은 거짓이다. 즉, False를 리턴한다.</p>
</li>
</ul>
<h2 id="자료형의-참과-거짓">자료형의 참과 거짓</h2>
<blockquote>
<p>‘자료형에 참과 거짓이 있다?’라는 말이 조금 이상하게 들리겠지만, 참과 거짓은 분명히 있다. 이는 매우 중요한 특징이며 실제로도 자주 쓰인다.</p>
</blockquote>
<ul>
<li>자료형의 참과 거짓을 구분하는 기준은 다음과 같다.</li>
</ul>
<table>
<thead>
<tr>
<th>값</th>
<th>참 or 거짓</th>
</tr>
</thead>
<tbody><tr>
<td>&quot;python&quot;</td>
<td>참</td>
</tr>
<tr>
<td>&quot;&quot;</td>
<td>거짓</td>
</tr>
<tr>
<td>[1, 2, 3]</td>
<td>참</td>
</tr>
<tr>
<td>[]</td>
<td>거짓</td>
</tr>
<tr>
<td>(1, 2, 3)</td>
<td>참</td>
</tr>
<tr>
<td>()</td>
<td>거짓</td>
</tr>
<tr>
<td>{&#39;a&#39;: 1}</td>
<td>참</td>
</tr>
<tr>
<td>{}</td>
<td>거짓</td>
</tr>
<tr>
<td>1</td>
<td>참</td>
</tr>
<tr>
<td>0</td>
<td>거짓</td>
</tr>
<tr>
<td>None</td>
<td>거짓</td>
</tr>
</tbody></table>
<ul>
<li>문자열, 리스트, 튜플, 딕셔너리 등의 값이 비어 있으면(&quot;&quot;, [], (), {}) 거짓이 되고 비어 있지 않으면 참이 된다.</li>
<li>숫자에서는 그 값이 0일 때 거짓이 된다. 위 표를 보면 None이 있는데, 이것에 대해서는 뒷부분에서 배우므로 아직은 신경 쓰지 말자.<ul>
<li>그저 None은 거짓을 뜻한다는 것만 알아 두자.</li>
</ul>
</li>
</ul>
<p>다음 예를 보고 자료형의 참과 거짓이 프로그램에서 어떻게 쓰이는지 간단히 알아보자.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3, 4]
&gt;&gt;&gt; while a:
...     print(a.pop())
...
4
3
2
1</code></pre>
<ul>
<li>먼저 a = [1,2,3,4]라는 리스트를 만들었다.</li>
<li>while 문은 조건문이 참인 동안 조건문 안에 있는 문장을 반복해서 수행한다.<pre><code class="language-python">while 조건문:
  수행할_문장</code></pre>
즉, 위 예를 보면 a가 참인 경우, a.pop()를 계속 실행하여 출력하라는 의미이다.
a.pop() 함수는 리스트 a의 마지막 요소를 끄집어 내는 함수이므로 리스트 안에 요소가 존재하는 한(a가 참인 동안) 마지막 요소를 계속 끄집어 낼 것이다.
결국 더 이상 끄집어 낼 것이 없으면 a가 빈 리스트([])가 되어 거짓이 된다.
따라서 while 문에서 조건문이 거짓이 되므로 while 문을 빠져나가게 된다</li>
</ul>
<p>위 예제가 복잡하다면 아래 예를 보자</p>
<pre><code class="language-python">&gt;&gt;&gt; if []:
...     print(&quot;참&quot;)
... else:
...     print(&quot;거짓&quot;)
...
거짓</code></pre>
<ul>
<li>[]는 앞의 표에서 볼 수 있듯이 비어 있는 리스트이므로 거짓이다.</li>
<li>따라서 &quot;거짓&quot;이라는 문자열이 출력된다.</li>
</ul>
<p>다른 예도 하나만 더 살펴보자.</p>
<pre><code class="language-python">&gt;&gt;&gt; if [1, 2, 3]:
...     print(&quot;참&quot;)
... else:
...     print(&quot;거짓&quot;)
... 
참</code></pre>
<ul>
<li>만약 [1, 2, 3]이 참이면 &quot;참&quot;이라는 문자열을 출력하고, 그렇지 않으면 &quot;거짓&quot;이라는 문자열을 출력하라.</li>
<li>[1, 2, 3]은 요솟값이 있는 리스트이므로 참이다. 따라서 &quot;참&quot;을 출력한다.</li>
</ul>
<h2 id="불-연산">불 연산</h2>
<p>자료형에 참과 거짓이 있다는 것을 이제 알게 되었다.
bool 함수를 사용하면 자료형의 참과 거짓을 보다 정확하게 식별할 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; bool(&#39;python&#39;)
True</code></pre>
<ul>
<li>&#39;python&#39; 문자열은 비어 있지 않으므로 bool 연산의 결과로 불 자료형인 True를 리턴한다.<pre><code class="language-python">&gt;&gt;&gt; bool(&#39;&#39;)
False</code></pre>
</li>
<li>&#39;&#39;문자열은 비어 있으므로 bool 연산의 결과로 불 자료형인 False를 리턴한다.</li>
</ul>
<p>앞에서 알아본 몇 가지 예제를 더 수행해 보자.</p>
<pre><code class="language-python">&gt;&gt;&gt; bool([1, 2, 3])
True
&gt;&gt;&gt; bool([])
False
&gt;&gt;&gt; bool(0)
False
&gt;&gt;&gt; bool(3)
True</code></pre>
<ul>
<li>앞에서 알아본 것과 동일한 참과 거짓에 대한 결과를 리턴하는 것을 확인할 수 있다.</li>
</ul>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고-자료">출처 및 참고 자료</h1>
<h1 id="httpswikidocsnet18"><a href="https://wikidocs.net/18">https://wikidocs.net/18</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[CTF[3일차]]]></title>
            <link>https://velog.io/@pingu_9/CTF3%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/CTF3%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Fri, 06 Dec 2024 02:18:45 GMT</pubDate>
            <description><![CDATA[<blockquote>
<details>
  <summary>참고</summary>
  <div><span style="color:blue">
※참고 자료는 드림핵을 이용하였습니다.<br>
※드림핵의 로드맵대로 공부할 예정입니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</blockquote>
</details>

<h1 id="문제-64se64">문제 64se64</h1>
<blockquote>
<p>Description
&quot;Welcome! 👋&quot;을 출력하는 html 페이지입니다.
소스 코드를 확인하여 문제를 풀고 플래그를 획득하세요.
플래그 형식은 DH{...} 입니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/99665898-4ace-479f-801b-e0afc3cc56ce/image.png" alt=""></p>
</blockquote>
<blockquote>
<ul>
<li><strong>아래 문자는 HTML base64로 인코딩된 문자인 것 같음</strong>
IyEvdXNyL2Jpbi9lbnYgcHl0aG9uMwphc2M9WzY4LCA3MiwgMTIzLCA5OCwgMTAxLCA0OCwgNTIsIDU0LCA5OCwgNTUsIDUzLCA1MCwgNTAsIDk3LCA5NywgNTAsIDEwMSwgNTAsIDU2LCAxMDIsIDUwLCA1NSwgNTQsIDEwMSwgNDgsIDk5LCA1NywgNDksIDQ4LCA1MywgNTAsIDQ5LCAxMDIsIDUwLCA1MSwgOTcsIDQ4LCA1MywgNTYsIDU1LCA0OCwgNDgsIDUzLCA5NywgNTYsIDUxLCA1NSwgNTUsIDUxLCA1NSwgNDgsIDk3LCA0OSwgNDksIDEwMSwgNTMsIDEwMSwgNTIsIDEwMCwgOTksIDQ5LCA1MywgMTAyLCA5OCwgNTAsIDk3LCA5OCwgMTI1XQphcnI9WzAgZm9yIGkgaW4gcmFuZ2UoNjgpXQpmb3IgaSBpbiByYW5nZSgwLDY4KToKICAgIGFycltpXT1jaHIoYXNjW2ldKQpmbGFnPScnLmpvaW4oYXJyKQpwcmludChmbGFnKQ==</li>
</ul>
</blockquote>
<ul>
<li>아래 스크립트는 base64로 인코딩된 python 스크립트를 디코딩한 결과이다.
<img src="https://velog.velcdn.com/images/pingu_9/post/0ced491b-6037-4440-9e35-0ad6ccbd748a/image.png" alt=""><pre><code class="language-python">#!/usr/bin/env python3
asc=[68, 72, 123, 98, 101, 48, 52, 54, 98, 55, 53, 50, 50, 97, 97, 50, 101, 50, 56, 102, 50, 55, 54, 101, 48, 99, 57, 49, 48, 53, 50, 49, 102, 50, 51, 97, 48, 53, 56, 55, 48, 48, 53, 97, 56, 51, 55, 55, 51, 55, 48, 97, 49, 49, 101, 53, 101, 52, 100, 99, 49, 53, 102, 98, 50, 97, 98, 125]
arr=[0 for i in range(68)]
for i in range(0,68):
  arr[i]=chr(asc[i])
flag=&#39;&#39;.join(arr)
print(flag)</code></pre>
<blockquote>
<p><strong>python 코드 해석</strong></p>
</blockquote>
</li>
<li>asc 리스트 : ASCII 코드로 이루어진 숫자들의 배열</li>
<li>arr 리스트 : asc의 각 요소를 chr()로 문자로 변환하여 새 리스트에 저장</li>
<li>flag : 모든 문자를 하나의 문자열로 결합하여 flag에 저장</li>
<li>print : flag 값을 출력</li>
</ul>
<hr>
<h1 id="리눅스-사용법">리눅스 사용법</h1>
<h2 id="셸shell">셸(Shell)</h2>
<blockquote>
<p>셸은 유저가 리눅스 시스템을 이용할 수 있는 인터페이스입니다.
셸은 유저에게 입력을 받고 운영체제가 그것을 프로그램으로 처리하면 그 결과를 유저에게 출력한다.</p>
</blockquote>
<ul>
<li><p>터미널 실행 단축키</p>
<ul>
<li>crtl + alt + T(윈도우, 리눅스 기준)</li>
<li>control + option + T(맥 기준)</li>
</ul>
</li>
<li><p>단축키를 눌러 터미널을 실행하면 bash 셸이 자동으로 실행됩니다.</p>
<h3 id="셸-프롬프트shell-prompt">셸 프롬프트(Shell Prompt)</h3>
<blockquote>
<p>bash가 실행되면 아래와 같은 텍스트가 출력됩니다.</p>
</blockquote>
<pre><code class="language-Linux">user@user-VirtualBox:~$</code></pre>
</li>
<li><p>이것을 셸 프롬프트라고 부릅니다.</p>
</li>
<li><p>유저는 셸 프롬프트를 보고 셸이 명령어를 입력 받을 준비가 되었음을 알 수 있습니다.</p>
</li>
</ul>
<h2 id="기초적인-명령어">기초적인 명령어</h2>
<blockquote>
<p>셸을 사용하여 리눅스를 이용하기 위해 필요한 기초적인 명령어들을 알아보겠습니다.</p>
</blockquote>
<h3 id="1-sudo-apt-update">1. sudo apt update</h3>
<blockquote>
<p><code style="background-color:grey; color:orange">sudo apt update</code>는 apt 명령어로 설치 가능한 소프트웨어 패키지 목록을 업데이트합니다.</p>
<blockquote>
<p>그리고 각 소프트웨어 패키지 별로 어떤 버전을 설치할 수 있는지도 없데이트합니다.</p>
</blockquote>
</blockquote>
<ul>
<li><code style="background-color:grey; color:orange">sudo apt update</code>실행 결과는 다음과 같습니다.<pre><code class="language-linux">user@user-VirtualBox:~$ sudo apt update
[sudo] password for user:
Get:1 http://security.ubuntu.com/ubuntu jammy-security InRelease [110 kB]
Hit:2 http://kr.archive.ubuntu.com/ubuntu jammy InRelease
Hit:3 http://kr.archive.ubuntu.com/ubuntu jammy-updates InRelease
Hit:4 http://kr.archive.ubuntu.com/ubuntu jammy-backports InRelease
Fetched 110 kB in 2s (60.0 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
3 packages can be upgraded. Run &#39;apt list --upgradable&#39; to see them.
user@user-VirtualBox:~$</code></pre>
</li>
</ul>
<h3 id="2-sudo-apt-upgrade">2. sudo apt upgrade</h3>
<blockquote>
<p>리눅스에 설치된 소프트웨어 패키지의 버전을 업그레이드합니다.</p>
<blockquote>
<p>오래된 소프트웨어 패키지에 존재하는 취약점은 보안 문제를 일으킬 수 있습니다.
따라서 주기적으로 소프트웨어 패키지를 업그레이드하여 보안 문제를 예방하는 작업이 중요합니다.</p>
</blockquote>
</blockquote>
<ul>
<li><code style="background-color:grey; color:orange">sudo apt upgrade</code> 실행 결과는 다음과 같습니다.<pre><code class="language-linux">user@user-VirtualBox:~$ sudo apt upgrade
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Calculating upgrade... Done
The following packages were automatically installed and are no longer required:
libflashrom1 libftdi1-2 linux-headers-5.15.0-43
linux-headers-5.15.0-43-generic linux-image-5.15.0-43-generic
linux-modules-5.15.0-43-generic linux-modules-extra-5.15.0-43-generic
Use &#39;sudo apt autoremove&#39; to remove them.
#
# News about significant security updates, features and services will
# appear here to raise awareness and perhaps tease /r/Linux ;)
# Use &#39;pro config set apt_news=false&#39; to hide this and future APT news.
#
The following packages have been kept back:
libglib2.0-0 libglib2.0-bin libglib2.0-data
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
user@user-VirtualBox:~$</code></pre>
</li>
</ul>
<h3 id="3-id">3. id</h3>
<blockquote>
<p>현재 유저의 유저 ID와 해당 유저가 속해있는 그룹 ID를 출력합니다. </p>
<blockquote>
<p>리눅스는 권한을 기반으로 파일을 읽고 쓰고 실행할 수 있기 때문에 주로 자신이 해당하는 권한을 가지고 있는지 확인하기 위해 사용하는 명령어입니다.</p>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~$ id
uid=1000(user) gid=1000(user) groups=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),122(lpadmin),134(lxd),135(sambashare)
user@user-VirtualBox:~$</code></pre>
<h3 id="4-pwd">4. pwd</h3>
<blockquote>
<p><strong>Print Working Directory</strong>의 줄임말로 현재 작업 중인 디렉토리의 경로를 출력합니다.
아래 pwd 명령어 실행 결과에 따르면 현재 /home/user 디렉토리에 위치함을 알 수 있습니다.</p>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~$ pwd
/home/user
user@user-VirtualBox:~$</code></pre>
<h3 id="5-ls">5. ls</h3>
<blockquote>
<p><strong>List</strong>의 줄임말로 디렉토리의 내용을 출력하는 명령어입니다.</p>
<blockquote>
<ul>
<li><code style="background-color:grey; color:orange">ls</code> 명령어 실행 결과는 다음과 같습니다.</li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~$ ls
Desktop  Documents  Downloads  Music  Pictures  Public  snap  Templates  Videos
user@user-VirtualBox:~$</code></pre>
<ul>
<li><code style="background-color:grey; color:orange">-l</code> 플래그를 추가한 형태인 <code style="background-color:grey; color:orange">ls -l</code> 을 실행하면 다음과 같이 더 자세한 정보를 함께 출력합니다.<pre><code class="language-linux">user@user-VirtualBox:~$ ls -l
total 36
drwxr-xr-x 2 user user 4096 11월 30 18:46 Desktop
drwxr-xr-x 2 user user 4096 11월 30 18:46 Documents
drwxr-xr-x 2 user user 4096 11월 30 18:46 Downloads
drwxr-xr-x 2 user user 4096 11월 30 18:46 Music
drwxr-xr-x 2 user user 4096 11월 30 18:46 Pictures
drwxr-xr-x 2 user user 4096 11월 30 18:46 Public
drwx------ 3 user user 4096 11월 30 18:45 snap
drwxr-xr-x 2 user user 4096 11월 30 18:46 Templates
drwxr-xr-x 2 user user 4096 11월 30 18:46 Videos
user@user-VirtualBox:~$</code></pre>
</li>
<li>현재 디렉토리 뿐만 아니라 임의 디렉토리의 내용을 출력하는 것도 가능합니다.</li>
<li>루트 디렉토리인 <code style="background-color:grey; color:orange">/</code> 디렉토리의 내용을 출력하는 <code style="background-color:grey; color:orange">ls -l /</code> 을 실행하면 다음과 같습니다.
```linux
user@user-VirtualBox:~$ ls -l /
total 3991632
lrwxrwxrwx   1 root root          7 11월 30 18:15 bin -&gt; usr/bin
drwxr-xr-x   4 root root       4096 12월  1 14:10 boot
drwxrwxr-x   2 root root       4096 11월 30 18:25 cdrom
drwxr-xr-x  19 root root       4180 12월  1 14:25 dev
drwxr-xr-x 130 root root      12288 12월  1 14:09 etc
drwxr-xr-x   3 root root       4096 11월 30 18:27 home
lrwxrwxrwx   1 root root          7 11월 30 18:15 lib -&gt; usr/lib
lrwxrwxrwx   1 root root          9 11월 30 18:15 lib32 -&gt; usr/lib32
lrwxrwxrwx   1 root root          9 11월 30 18:15 lib64 -&gt; usr/lib64
lrwxrwxrwx   1 root root         10 11월 30 18:15 libx32 -&gt; usr/libx32
drwx------   2 root root      16384 11월 30 18:14 lost+found
drwxr-xr-x   3 root root       4096 11월 30 19:49 media
drwxr-xr-x   2 root root       4096  8월  9 20:48 mnt
drwxr-xr-x   3 root root       4096 11월 30 19:55 opt
dr-xr-xr-x 260 root root          0 12월  1 14:11 proc
drwx------   4 root root       4096 12월  1 14:17 root
drwxr-xr-x  34 root root        920 12월  1 18:01 run
lrwxrwxrwx   1 root root          8 11월 30 18:15 sbin -&gt; usr/sbin
drwxr-xr-x  11 root root       4096  8월  9 20:55 snap
drwxr-xr-x   2 root root       4096  8월  9 20:48 srv</li>
<li>rw-------   1 root root 4087349248 11월 30 18:15 swapfile
dr-xr-xr-x  13 root root          0 12월  1 14:11 sys
drwxrwxrwt  21 root root       4096 12월  1 18:01 tmp
drwxr-xr-x  14 root root       4096  8월  9 20:48 usr
drwxr-xr-x  14 root root       4096  8월  9 20:54 var
user@user-VirtualBox:~$<pre><code></code></pre></li>
</ul>
<h3 id="6-cd">6. cd</h3>
<blockquote>
<p><strong>Change Directory</strong>의 줄임말로 작업중인 디렉토리를 변경하는 명령어입니다.<br></p>
<blockquote>
<p>명령어 설명에 앞서 <strong>절대 경로(Absolute Path)</strong> 와 <strong>상대 경로(Relative Path)</strong> 에 대해 알아야 합니다.<br>
<strong>절대 경로</strong>는 루트 디렉토리 / 를 시작으로 모든 경로를 적어서 표현하는 경로입니다. <code style="background-color:grey; color:orange">/home/user</code> 도 절대 경로 입니다.<br>
<strong>상대 경로</strong>는 현재 디렉토리를 기준으로 상위 디렉토리 또는 하위 디렉토리로 뻗어 나가는 경로를 말합니다.
예를 들어 <code style="background-color:grey; color:orange">cd ..</code>는 현재 디렉토리에서 부모 디렉토리로 이동합니다.
가령 현재 디렉토리가 <code style="background-color:grey; color:orange">/home/user</code> 일 때 <code style="background-color:grey; color:orange">cd ..</code> 를 실행하면 /home 으로 이동합니다.<br>
몇 가지 특별히 정해진 고유한 경로도 있습니다.
예를 들어 <code style="background-color:grey; color:orange">~</code> 는 현재 유저의 홈 디렉토리이며, <code style="background-color:grey; color:orange">-</code> 는 이전에 위치했던 디렉토리를 나타냅니다.</p>
</blockquote>
</blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">cd</code> 명령어와 <code style="background-color:grey; color:orange">pwd</code> 명령어를 실행한 예시입니다.<pre><code class="language-linux">user@user-VirtualBox:~$ pwd
/home/user
user@user-VirtualBox:~$ cd /
user@user-VirtualBox:/$ pwd
/
user@user-VirtualBox:/$ cd /home/user
user@user-VirtualBox:~$ pwd
/home/user
user@user-VirtualBox:~$ cd ..
user@user-VirtualBox:/home$ pwd
/home
user@user-VirtualBox:/home$ cd ~
user@user-VirtualBox:~$ pwd
/home/user
user@user-VirtualBox:~$</code></pre>
</li>
</ul>
<h3 id="7-mkdir">7. mkdir</h3>
<blockquote>
<p><strong>Make Directory</strong>의 줄임말로 디렉토리를 생성하는 명령어입니다.</p>
<blockquote>
<ul>
<li><code style="background-color:grey; color:orange">/home/user</code> 디렉토리에 위치할 때 <code style="background-color:grey; color:orange">mkdir new_dir</code> 명령어로 <code style="background-color:grey; color:orange">new_dir</code> 디렉토리를 생성하면, 다음과 같이 <code style="background-color:grey; color:orange">new_dir</code> 가 새롭게 추가됩니다.</li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~$ mkdir new_dir
user@user-VirtualBox:~$ ls -l
total 40
drwxr-xr-x 2 user user 4096 11월 30 18:46 Desktop
drwxr-xr-x 2 user user 4096 11월 30 18:46 Documents
drwxr-xr-x 2 user user 4096 11월 30 18:46 Downloads
drwxr-xr-x 2 user user 4096 11월 30 18:46 Music
drwxrwxr-x 2 user user 4096 12월  1 20:58 new_dir &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt; 새롭게 추가된 디렉토리
drwxr-xr-x 2 user user 4096 11월 30 18:46 Pictures
drwxr-xr-x 2 user user 4096 11월 30 18:46 Public
drwx------ 3 user user 4096 11월 30 18:45 snap
drwxr-xr-x 2 user user 4096 11월 30 18:46 Templates
drwxr-xr-x 2 user user 4096 11월 30 18:46 Videos
user@user-VirtualBox:~$ </code></pre>
<h3 id="8-touch">8. touch</h3>
<blockquote>
<p><code style="background-color:grey; color:orange">touch</code> 명령어는 비어 있는 새로운 파일을 만드는 데 사용합니다.</p>
<blockquote>
<ul>
<li>앞서 생성한 <code style="background-color:grey; color:orange">new_dir</code> 디렉토리로 이동 후 <code style="background-color:grey; color:orange">ls -l</code> 명령어를 실행해보면 아무런 파일도 존재하지 않습니다.</li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~$ cd new_dir
user@user-VirtualBox:~/new_dir$ ls -l
total 0
user@user-VirtualBox:~/new_dir$</code></pre>
<ul>
<li>이때 <code style="background-color:grey; color:orange">touch new_file</code> 명령어를 실행한 후 <code style="background-color:grey; color:orange">ls -l</code> 을 실행하면, 다음과 같이 <code style="background-color:grey; color:orange">new_file</code> 파일이 생성되었습니다.
```linux
user@user-VirtualBox:<del>/new_dir$ touch new_file
user@user-VirtualBox:</del>/new_dir$ ls -l
total 0</li>
<li>rw-rw-r-- 1 user user 0 12월  1 20:59 new_file
user@user-VirtualBox:~/new_dir$<pre><code></code></pre></li>
</ul>
<h3 id="9-mv">9. mv</h3>
<blockquote>
<p><strong>Move</strong>의 줄임말로 파일이나 디렉토리의 위치를 옮길 때 사용하는 명령어입니다.</p>
<blockquote>
<p>파일이나 디렉토리의 이름을 변경할 때에도 사용할 수 있습니다.<br></p>
</blockquote>
</blockquote>
<ul>
<li>먼저 아래와 같이 <strong>파일 이름을 변경</strong>할 수 있습니다. <code style="background-color:grey; color:orange">new_file</code> 파일의 이름을 <code style="background-color:grey; color:orange">old_file</code>로 변경하는 모습입니다.
```linux
user@user-VirtualBox:~/new_dir$ ls -l
total 0</li>
<li>rw-rw-r-- 1 user user 0 12월  1 20:59 new_file
user@user-VirtualBox:<del>/new_dir$ mv new_file old_file
user@user-VirtualBox:</del>/new_dir$
```</li>
<li>아래와 같이 <strong>파일을 옮길 수도 있습니다.</strong> <code style="background-color:grey; color:orange">old_file</code> 을 상위 디렉토리로 옮기는 모습입니다.<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ ls
old_file
user@user-VirtualBox:~/new_dir$ ls ..
Desktop    Downloads  new_dir   Public  Templates
Documents  Music      Pictures  snap    Videos
user@user-VirtualBox:~/new_dir$ mv old_file ..
user@user-VirtualBox:~/new_dir$ ls
user@user-VirtualBox:~/new_dir$ ls ..
Desktop    Downloads  new_dir   Pictures  snap       Videos
Documents  Music      old_file  Public    Templates
user@user-VirtualBox:~/new_dir$</code></pre>
</li>
</ul>
<h3 id="10-rm">10. rm</h3>
<blockquote>
<p><strong>Remove</strong>의 줄임말로 파일이나 디렉토리를 삭제하는 명령어입니다.</p>
<blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">abcd</code> 파일을 생성한 후 삭제하는 모습입니다.</li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ touch abcd
user@user-VirtualBox:~/new_dir$ ls -l
total 0
-rw-rw-r-- 1 user user 0 12월  2 11:05 abcd
user@user-VirtualBox:~/new_dir$ rm abcd
user@user-VirtualBox:~/new_dir$ ls -l
total 0
user@user-VirtualBox:~/new_dir$</code></pre>
<p>디렉토리 삭제는 <code style="background-color:grey; color:orange">-r</code> 플래그를 추가한 <code style="background-color:grey; color:orange">rm -r</code>로 수행할 수 있습니다.</p>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">dir</code> 디렉토리를 생성한 후 삭제하는 모습입니다.<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ mkdir dir
user@user-VirtualBox:~/new_dir$ ls -l
total 4
drwxrwxr-x 2 user user 4096 12월  2 11:11 dir
user@user-VirtualBox:~/new_dir$ rm -r dir
user@user-VirtualBox:~/new_dir$ ls -l
total 0
user@user-VirtualBox:~/new_dir$</code></pre>
</li>
</ul>
<h3 id="11-cat">11. cat</h3>
<blockquote>
<p>파일의 내용을 출력하는 명령어입니다.</p>
<blockquote>
<p><code style="background-color:grey; color:orange">cat 파일경로</code> 형식으로 사용할 수 있습니다.
다음은 <code style="background-color:grey; color:orange">/etc/passwd</code> 파일의 내용을 출력하는 모습입니다.
<code style="background-color:grey; color:orange">/etc/passwd</code> 파일은 운영체제에 접근할 수 있는 유저 목록을 담고 있습니다.</p>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
... (생략)
user:x:1000:1000:user,,,:/home/user:/bin/bash
fwupd-refresh:x:128:136:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
vboxadd:x:999:1::/var/run/vboxadd:/bin/false
user@user-VirtualBox:~/new_dir$</code></pre>
<h3 id="12-file">12. file</h3>
<blockquote>
<p>파일의 유형을 출력하는 명령어입니다.</p>
<blockquote>
<p><code style="background-color:grey; color:orange">file 파일경로</code> 형식으로 사용할 수 있습니다. 다음은 <code style="background-color:grey; color:orange">/bin/ls</code> 파일의 유형을 출력하는 모습입니다.
<code style="background-color:grey; color:orange">/bin/ls</code> 파일은 <code style="background-color:grey; color:orange">ls</code> 명령어를 입력하면 실행되는 실행 파일입니다.</p>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~$ file /bin/ls
/bin/ls: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=897f49cafa98c11d63e619e7e40352f855249c13, for GNU/Linux 3.2.0, stripped
user@user-VirtualBox:~$</code></pre>
<h3 id="13-echo">13. echo</h3>
<blockquote>
<p>셸에 유저가 입력한 텍스트를 출력합니다.</p>
<blockquote>
<p>다음은 <code style="background-color:grey; color:orange">echo</code> 명령어로 <code style="background-color:grey; color:orange">Hello World!</code>를 출력하는 모습입니다.</p>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ echo &quot;Hello world!&quot;
Hello world!
user@user-VirtualBox:~/new_dir$</code></pre>
<p><code style="background-color:grey; color:orange">echo</code> 명령어를 사용해서 파일을 생성할 수도 있습니다.
다음과 같이 <code style="background-color:grey; color:orange">echo</code> 명령문 끝에 <code style="background-color:grey; color:orange">> 파일명</code> 을 이어 붙여 실행하면 <code style="background-color:grey; color:orange">파일명</code> 을 이름으로 가지는 파일을 생성하고 <code style="background-color:grey; color:orange">echo</code> 뒤에 입력한 내용을 파일 내용으로 저장합니다.</p>
<ul>
<li>다음은 파일명이 <code style="background-color:grey; color:orange">hello</code> 이고 내용이 <code style="background-color:grey; color:orange">Hello world!</code> 인 파일을 생성한 후 그 내용을 출력하는 모습입니다.
```linux
user@user-VirtualBox:<del>/new_dir$ ls -l
total 0
user@user-VirtualBox:</del>/new_dir$ echo &quot;Hello world!&quot; &gt; hello
user@user-VirtualBox:~/new_dir$ ls -l
total 4</li>
<li>rw-rw-r-- 1 user user 13 12월  2 13:05 hello
user@user-VirtualBox:<del>/new_dir$ cat hello
Hello world!
user@user-VirtualBox:</del>/new_dir$<pre><code></code></pre></li>
</ul>
<h3 id="14-cp">14. cp</h3>
<blockquote>
<p><strong>Copy</strong>의 줄임말로 파일이나 디렉토리를 복사하는 명령어입니다.</p>
<blockquote>
<p>다음은 위에서 생성한 <code style="background-color:grey; color:orange">hello</code> 파일을 <code style="background-color:grey; color:orange">world</code> 라는 이름으로 복사하는 모습입니다.
디렉토리를 복사할 때는 <code style="background-color:grey; color:orange">-r</code> 플래그를 붙인 형태인 <code style="background-color:grey; color:orange">cp -r</code> 을 사용합니다.</p>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ ls -l
total 4
-rw-rw-r-- 1 user user 13 12월  2 13:05 hello
user@user-VirtualBox:~/new_dir$ cp hello world
user@user-VirtualBox:~/new_dir$ ls -l
total 8
-rw-rw-r-- 1 user user 13 12월  2 13:05 hello
-rw-rw-r-- 1 user user 13 12월  2 13:08 world
user@user-VirtualBox:~/new_dir$ cat world
Hello world!
user@user-VirtualBox:~/new_dir$</code></pre>
<h3 id="15-grep">15. grep</h3>
<blockquote>
<p>전체에서 특정 문자열을 찾을 때 사용합니다.</p>
<blockquote>
<p><code style="background-color:grey; color:orange">grep 문자열 파일</code> 형식으로 사용할 수 있습니다.</p>
</blockquote>
</blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">grep root /etc/passwd</code>를 수행하여 <code style="background-color:grey; color:orange">/etc/passwd</code> 파일에서 <code style="background-color:grey; color:orange">root</code> 문자열이 포함된 행을 출력하는 모습입니다.<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
nm-openvpn:x:121:127:NetworkManager OpenVPN,,,:/var/lib/openvpn/chroot:/usr/sbin/nologin</code></pre>
</li>
</ul>
<h3 id="16-man">16. man</h3>
<blockquote>
<p><strong>Manual</strong>의 줄임말로 특정 명령어의 매뉴얼을 보여주는 명령어입니다.</p>
<blockquote>
<p>매뉴얼은 명령어 사용법, 옵션, 예제 등 유용한 정보를 담고 있습니다.</p>
</blockquote>
</blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">man cp</code> 명령어 실행 결과입니다.</li>
<li>명령어를 실행하면 아래와 같이 <code style="background-color:grey; color:orange">cp</code> 명령어의 매뉴얼을 보여줍니다.<pre><code class="language-linux">CP(1)                            User Commands                           CP(1)
​
NAME
      cp - copy files and directories
​
SYNOPSIS
      cp [OPTION]... [-T] SOURCE DEST
      cp [OPTION]... SOURCE... DIRECTORY
      cp [OPTION]... -t DIRECTORY SOURCE...
​
DESCRIPTION
      Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.
​
      Mandatory  arguments  to  long  options are mandatory for short options
      too.
​
      -a, --archive
             same as -dR --preserve=all
​
      --attributes-only
             don&#39;t copy the file data, just the attributes
​
      --backup[=CONTROL]
Manual page cp(1) line 1 (press h for help or q to quit)</code></pre>
</li>
</ul>
<h3 id="17-curl">17. curl</h3>
<blockquote>
<p><strong>client URL</strong>의 줄임말로 서버에 데이터를 보내거나 서버로부터 데이터를 받는 데이터 전송 명령어입니다.</p>
<blockquote>
<p><code style="background-color:grey; color:orange">curl [옵션] URL</code> 형식으로 사용할 수 있으며, HTTP, HTTPS, FTP 등 다양한 프로토콜을 지원합니다.</p>
</blockquote>
</blockquote>
<ul>
<li>다음은 ‘<a href="http://www.google.com">http://www.google.com</a> ’ 웹 서버의 콘텐츠를 반환하여 출력하는 모습입니다. <pre><code class="language-linux">user@user-VirtualBox:~$ curl https://www.google.com
&lt;!doctype html&gt;&lt;html itemscope=&quot;&quot; itemtype=&quot;http://schema.org/WebPage&quot; lang=&quot;ko&quot;&gt; 
... (생략)
user@user-VirtualBox:~$</code></pre>
</li>
<li><code style="background-color:grey; color:orange">curl</code> 명령어의 주요 옵션은 다음과 같습니다. 아래 옵션들을 지금 모두 이해할 필요는 없으며, 다양한 방식으로 사용할 수 있다는 점을 기억하시면 됩니다.<ul>
<li><code style="background-color:grey; color:orange">-o file</code> : 전송 받은 데이터를 파일에 저장합니다.   </li>
<li><code style="background-color:grey; color:orange">-i</code> : 결과 값에 HTTP 응답 헤더를 포함합니다.</li>
<li><code style="background-color:grey; color:orange">-X</code> &quot;method&quot; : HTTP 요청 메소드를 지정합니다.</li>
<li><code style="background-color:grey; color:orange">-d</code> &quot;key=value&quot; : HTTP POST 메소드로 데이터를 전송합니다.<br></li>
</ul>
</li>
<li><em>curl을 이용한 명령어 실행 결과 전송*</em></li>
<li><code style="background-color:grey; color:orange">curl</code> 은 워게임 문제를 풀 때도 유용하게 사용됩니다.
예를 들어 풀이자가 명령어 실행 결과를 볼 수 없는 경우, 결과를 <code style="background-color:grey; color:orange">curl</code> 명령어에 포함하여 풀이자의 웹 서버로 전송하면 확인이 가능합니다.
다음은 서버 내 <code style="background-color:grey; color:orange">/etc/passwd</code> 파일을 <code style="background-color:grey; color:orange"><a href="https://hmqtzgx.request.dreamhack.games">https://hmqtzgx.request.dreamhack.games</a></code>에 POST 데이터로 전송하는 예시입니다.<pre><code class="language-linux">$ curl &quot;https://hmqtzgx.request.dreamhack.games&quot; -d &quot;`cat /etc/passwd`&quot;</code></pre>
</li>
</ul>
<h3 id="와일드카드">와일드카드</h3>
<blockquote>
<p><strong>와일드카드(wildcards)</strong>는 리눅스에서 임의의 다른 문자를 나타낼 수 있는 특수 문자들을 의미합니다.
주로 명령어를 다른 문자열로 대체하기 위해 사용합니다.<br></p>
<blockquote>
<p><code>?</code>
a-z, 0-9 범위 내 임의의 1개 문자로 대체됩니다.</p>
</blockquote>
</blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">cat he?lo</code> 를 실행하여 <code style="background-color:grey; color:orange">hello</code> 파일을 출력하는 모습입니다.
```linux
user@user-VirtualBox:~/new_dir$ ls -l
total 8</li>
<li>rw-rw-r-- 1 user user 13 12월  2 13:05 hello</li>
<li>rw-rw-r-- 1 user user 13 12월  2 13:08 world
user@user-VirtualBox:<del>/new_dir$ cat he?lo
Hello world!
user@user-VirtualBox:</del>/new_dir$<pre><code></code></pre></li>
</ul>
<blockquote>
<blockquote>
<p><code>*</code>
a-z, 0-9 범위 내 임의의 0개 이상 문자로 대체됩니다.</p>
</blockquote>
</blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">cat h*</code> 명령어를 입력하여 <code style="background-color:grey; color:orange">hello</code>는 모습입니다.<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ cat h*
Hello world!
user@user-VirtualBox:~/new_dir$ </code></pre>
</li>
</ul>
<blockquote>
<blockquote>
<p><code>[]</code>
[문자1-문자2] 혹은 [문자1, 문자2, …] 형태로 범위를 지정합니다. 범위 내 모든 문자로 대체될 수 있습니다.</p>
</blockquote>
</blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">ls test[0-9]</code> 를 실행하여 파일명이 <code style="background-color:grey; color:orange">test</code> 로 시작하고 마지막이 숫자인 파일을 모두 출력하는 모습입니다.
```linux
user@user-VirtualBox:~/new_dir$ ls -l
total 8</li>
<li>rw-rw-r-- 1 user user 13 12월  2 13:05 hello</li>
<li>rw-rw-r-- 1 user user 13 12월  2 13:08 world
user@user-VirtualBox:<del>/new_dir$ touch test1 test2 test3
user@user-VirtualBox:</del>/new_dir$ ls -l
total 8</li>
<li>rw-rw-r-- 1 user user 13 12월  2 13:05 hello</li>
<li>rw-rw-r-- 1 user user  0 12월  2 13:10 test1</li>
<li>rw-rw-r-- 1 user user  0 12월  2 13:10 test2</li>
<li>rw-rw-r-- 1 user user  0 12월  2 13:10 test3</li>
<li>rw-rw-r-- 1 user user 13 12월  2 13:08 world
user@user-VirtualBox:<del>/new_dir$ ls test[0-9]
test1  test2  test3
user@user-VirtualBox:</del>/new_dir$ <pre><code></code></pre></li>
</ul>
<h3 id="리다이렉션">리다이렉션</h3>
<blockquote>
<p><strong>리다이렉션(redirection)</strong>은 모니터에 나타나는 표준 출력 혹은 키보드로 입력하는 표준 입력을 다른 곳으로 변경하는 작업입니다.
주로 어떤 명령어의 결과를 파일로 저장하거나, 다른 명령어의 입력으로 전달하는 형태로 리다이렉션합니다. </p>
</blockquote>
<blockquote>
<h4 id="명령어파일">명령어&gt;파일</h4>
<p>명령어 표준 출력을 파일로 변경합니다.
파일이 없으면 새로 만들고, 있으면 덮어씁니다.</p>
<blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">ls test[0-9]</code> 명령어 결과를 <code style="background-color:grey; color:orange">world</code> 파일에 쓰는 예시입니다.</li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ ls test[0-9]
test1  test2  test3
user@user-VirtualBox:~/new_dir$ ls test[0-9] &gt; world
user@user-VirtualBox:~/new_dir$ cat world
test1
test2
test3
user@user-VirtualBox:~/new_dir$</code></pre>
<blockquote>
<h4 id="명령어파일-1">명령어&gt;&gt;파일</h4>
<p>명령어 표준 출력을 파일로 변경합니다.
파일이 없으면 새로 만들고, 있으면 이어서 씁니다.</p>
<blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">cat hello</code> 명령어 결과를 <code style="background-color:grey; color:orange">world</code> 파일에 쓰는 예시입니다. </li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ cat hello
hello
user@user-VirtualBox:~/new_dir$ cat hello &gt;&gt; world
user@user-VirtualBox:~/new_dir$ cat world
test1
test2
test3
hello
user@user-VirtualBox:~/new_dir$</code></pre>
<blockquote>
<h4 id="명령어파일-2">명령어&lt;파일</h4>
<p>명령어 표준 입력을 파일로 변경합니다.
파일로부터 표준 입력을 받아 명령어를 수행합니다.</p>
<blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">world</code> 파일 내용을 표준 입력으로 받아 <code style="background-color:grey; color:orange">grep test</code> 명령어를 수행하는 예시입니다.</li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ cat world
test1
test2
test3
hello
user@user-VirtualBox:~/new_dir$ grep test &lt; world
test1
test2
test3
user@user-VirtualBox:~/new_dir$</code></pre>
<blockquote>
<h3 id="파이프">파이프</h3>
<p><strong>파이프(pipe)</strong>는 리다이렉션의 한 형태로, 명령어 결과 표준 출력을 다른 명령어의 표준 입력으로 보낼 때 사용합니다.
파이프는 <code style="background-color:grey; color:orange">|</code> 문자로 나타냅니다.</p>
<blockquote>
<ul>
<li>다음은 <code style="background-color:grey; color:orange">ls -l</code> 명령 결과에서 <code style="background-color:grey; color:orange">hello</code>가 포함된 행을 찾아 출력하는 예시입니다.</li>
</ul>
</blockquote>
</blockquote>
<pre><code class="language-linux">user@user-VirtualBox:~/new_dir$ ls -l
total 8
-rw-rw-r-- 1 user user 13 12월  2 13:05 hello
-rw-rw-r-- 1 user user  0 12월  2 13:10 test1
-rw-rw-r-- 1 user user  0 12월  2 13:10 test2
-rw-rw-r-- 1 user user  0 12월  2 13:10 test3
-rw-rw-r-- 1 user user 13 12월  2 13:08 world
user@user-VirtualBox:~/new_dir$ ls -l | grep hello
-rw-rw-r-- 1 user user 13 12월  2 13:05 hello
user@user-VirtualBox:~/new_dir$ </code></pre>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고자료">출처 및 참고자료</h1>
<h1 id="httpslearndreamhackio44110"><a href="https://learn.dreamhack.io/441#10">https://learn.dreamhack.io/441#10</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬[3일차]]]></title>
            <link>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC3%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC3%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 05 Dec 2024 08:07:58 GMT</pubDate>
            <description><![CDATA[<details>
  <summary>참고</summary>
  <div><span style="color:blue">참고 자료는 점프 투 파이썬으로 선택했습니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</details>

<h2 id="리스트-자료형">리스트 자료형</h2>
<blockquote>
<p>앞서 숫자와 문자열에 대해서 배웠는데, 숫자와 문자열만으로 프로그래밍을 하기에는 부족한 점이 많다.
예를 들어 1부터 10까지의 숫자 중 홀수의 모음인 1,3,5,7,9의 집합을 생각해보면,
숫자나 문자열로 표현하기에는 어렵다. 
파이썬은 이러한 불편함을 해소할 수 있는 자료형이 존재한다.(이것이 리스트[List]이다.)</p>
</blockquote>
<h2 id="리스트는-어떻게-만들고-사용할까">리스트는 어떻게 만들고 사용할까?</h2>
<blockquote>
<p>리스트를 사용하면1,3,5,7,9의 숫자 모음을 다음과 같이 간단하게 표현할 수 있다.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; odd = [1,3,5,7,9]</code></pre>
<ul>
<li>리스트를 만들 때는 위에서 보는 것과 같이 대괄호([])로 감싸 주고 각 요솟값은 쉼표(,)로 구분해 준다.<pre><code>리스트명 = [요소1, 요소2, 요소3, ...]</code></pre></li>
</ul>
<h2 id="리스트의-인덱싱과-슬라이싱">리스트의 인덱싱과 슬라이싱</h2>
<blockquote>
<p>리스튿 문자열 처럼 인덱싱과 슬라이싱이 가능하다.</p>
</blockquote>
<h3 id="리스트의-인덱싱">리스트의 인덱싱</h3>
<p>먼저 a변수에 [1,2,3]값을 설정한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; a
[1,2,3]</code></pre>
<p>a[0]은 리스트 a의 첫 번째 요솟값을 말한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a[0]
1</code></pre>
<p>다음 은 a[0]와 a[2]의 값을 더한 예이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a[0] + a[2]
4</code></pre>
<blockquote>
<p>문자열을 공부할 때 이미 살펴보았지만, 파이썬은 숫자를 0부터 세기 때문에 a[1]이 리스트 a의 첫번째 요소가 아니라 a[0]이 리스트 a의 첫 번째 요소라는 것을 명심하자!
a[-1]은 문자열에서와 마찬가지로 리스트 a의 마지막 요솟값을 말한다.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; a[-1]
3</code></pre>
<p>이번에는 리스트 a를 숫자 1,2,3과 또 다른 리스트인 [&#39;a&#39;,&#39;b&#39;,&#39;c&#39;]를 포함하도록 만들어 보자.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3, [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]]</code></pre>
<p>그리고 다음 예제를 따라해보자!</p>
<pre><code class="language-python">&gt;&gt;&gt; a[0]
1
&gt;&gt;&gt; a[-1]
[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]
&gt;&gt;&gt; a[3]
[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]</code></pre>
<ul>
<li>예상한 대로 a[-1]은 마지막 요솟값 [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]를 타나낸다.</li>
<li>a[3]은 리스트 a의 네 번째 요소를 나타내기 때문에 마지막 요소를 나타내는 a[-1]과 동일한 결괏값을 보여준다.</li>
</ul>
<p>그렇다면 리스트 a에 포함된 [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;] 리스트에서 &#39;a&#39; 값을 인덱싱을 사용해 끄집어 낼 수 있는 방법은 없을까? 다음 예제를 살펴 보자!</p>
<pre><code class="language-python">&gt;&gt;&gt; a[-1][0]
&#39;a&#39;</code></pre>
<p>&#39;b&#39;와 &#39;c&#39;도 마찬가지로 하면 된다!</p>
<pre><code class="language-python">&gt;&gt;&gt; a[-1][1]
&#39;b&#39;
&gt;&gt;&gt; a[-1][2]
&#39;c&#39;</code></pre>
<h4 id="삼중-리스트에서-인덱싱하기">삼중 리스트에서 인덱싱하기</h4>
<blockquote>
<p>조금 복잡하지만, 리스트를 다음과 같이 작성할 수도 있다.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,[&#39;a&#39;,&#39;b&#39;,[&#39;Life&#39;,&#39;is&#39;]]]</code></pre>
<p>리스트 a 안에 [&#39;a&#39;, &#39;b&#39;, [&#39;Life&#39;, &#39;is&#39;]] 리스트가 포함되어 있고 그 리스트 안에 다시 [&#39;Life&#39;, &#39;is&#39;] 리스트가 포함되어 있다.
즉, 삼중 구조의 리스트이다.
이 경우, &#39;Life&#39; 문자열만 끄집어 내려면 다음과 같이 해야 한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a[2][2][0]
&#39;Life&#39;</code></pre>
<h3 id="리스트의-슬라이싱">리스트의 슬라이싱</h3>
<p>문자열과 마찬가지로 리스트에서도 슬라이싱 기법을 적용할 수 있다. 슬라이싱은 &#39;잘라 낸다&#39;라는 뜻이라고 했다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3, 4, 5]
&gt;&gt;&gt; a[0:2]
[1,2]</code></pre>
<p>앞의 예를 문자열에서 슬라이싱했던 예와 비교해 보자.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;12345&quot;
&gt;&gt;&gt; a[0:2]
&#39;12&#39;</code></pre>
<p>몇 가지 예를 더 살펴보자.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3, 4, 5]
&gt;&gt;&gt; b = a[:2]
&gt;&gt;&gt; c = a[2:]
&gt;&gt;&gt; b
[1, 2]
&gt;&gt;&gt; c
[3, 4, 5]</code></pre>
<ul>
<li>b 변수는 리스트 a의 첫 번째 요소부터 두 번째 요소인 a[1]까지 나타내는 리스트이다.</li>
<li>물론 a[2] 값인 3은 포함되지 않는다. c라는 변수는 리스트 a의 세 번째 요소부터 끝까지 나타내는 리스트이다.</li>
</ul>
<h4 id="중첩된-리스트에서-슬라이싱하기">중첩된 리스트에서 슬라이싱하기</h4>
<blockquote>
<p>리스트가 포함된 중첩 리스트 역시 슬라이싱 방법은 똑같이 적용된다.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3, [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;], 4, 5]
&gt;&gt;&gt; a[2:5]
[3, [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;], 4]
&gt;&gt;&gt; a[3][:2]
[&#39;a&#39;, &#39;b&#39;]</code></pre>
<h2 id="리스트-연산하기">리스트 연산하기</h2>
<p>리스트 역시 <code style="background-color:#D8D8D8">+</code>를 사용해서 더할 수 있고 <code style="background-color:grey">*</code>를 사용해서 반복할 수 있다. 문자열과 마찬가지로 리스트에서도 되는지 직접 확인해 보자.</p>
<h3 id="리스트-더하기">리스트 더하기(+)</h3>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3]
&gt;&gt;&gt; b = [4, 5, 6]
&gt;&gt;&gt; a + b
[1, 2, 3, 4, 5, 6]</code></pre>
<ul>
<li>리스트 사이에서 +는 2개의 리스트를 합치는 기능을 한다.</li>
<li>문자열에서 &quot;abc&quot; + &quot;def&quot; = &quot;abcdef&quot;가 되는 것과 같은 이치이다.</li>
</ul>
<h3 id="리스트-반복하기code-stylebackground-colord8d8d8code">리스트 반복하기(<code style="background-color:#D8D8D8">*</code>)</h3>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3]
&gt;&gt;&gt; a * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]</code></pre>
<ul>
<li>위에서 볼 수 있듯이 [1,2,3] 리스트가 세 번 반복되어 새로운 리스트를 만들어 낸다.</li>
<li>문자열에서 &quot;abc&quot; * 3 = &quot;abcabcabc&quot; 가 되는 것과 같은 이치이다.</li>
</ul>
<h3 id="리스트-길이-구하기">리스트 길이 구하기</h3>
<p>리스트 길이를 구하기 위해서는 다음처럼 len 함수를 사용해야 한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; len(a)
3</code></pre>
<ul>
<li>len은 문자열, 리스트 외에 앞으로 배울 튜플과 딕셔너리에도 사용할 수 있는 함수이다.</li>
</ul>
<h4 id="초보자가-범하기-쉬운-리스트-연산-오류">초보자가 범하기 쉬운 리스트 연산 오류</h4>
<blockquote>
<p>다음 소스 코드를 입력했을 때 결괏값은 어떻게 나올까?</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; a[2[ + &quot;hi&quot;</code></pre>
<ul>
<li>a[2]의 값인 3과 문자열 hi가 더해져서 3hi가 출력될 것이라고 생각할 수 있다. 하지만 다음 결과를 살펴보니 오류가 발생했다. 오류의 원인은 무엇일까?<pre><code>Traceback (most recent call last):
File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
TypeError: unsupported operand type(s) for +: &#39;int&#39; and &#39;str&#39;</code></pre></li>
<li>a[2]에 저장된 값은 3이라는 정수인데 &quot;hi&quot;는 문자열이다. 정수와 문자열은 당연히 서로 더할 수 없기 때문에 오류가 발생한 것이다.</li>
<li>만약 숫자와 문자열을 더해서 &#39;3hi&#39;를 만들고 싶다면 다음처럼 숫자 3을 문자 &#39;3&#39;으로 바꾸어야 한다.<pre><code class="language-python">&gt;&gt;&gt; str(a[2]) + &quot;hi&quot;
3hi</code></pre>
</li>
<li>str은 정수나 실수를 문자열로 바꾸어 주는 파이썬 내장 함수이다.</li>
</ul>
<h3 id="리스트의-값-수정하기">리스트의 값 수정하기</h3>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; a[2] = 4
&gt;&gt;&gt; a
[1,2,3]</code></pre>
<ul>
<li>a[2]의 요솟값 3이 4로 바뀌었다.</li>
</ul>
<h3 id="del-함수를-사용해-리스트-요소-삭제하기">del 함수를 사용해 리스트 요소 삭제하기</h3>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; dek a[1]
&gt;&gt;&gt; a
[1,3]</code></pre>
<p>del a[x]는 x번째 요솟값을 삭제한다. 위에서는 a리스트에서 a[1]을 삭제했다.</p>
<ul>
<li>del 함순느 파이썬이 자체적으로 가지고 있는 삭제 함수이며 다음과 같이 사용한다.<pre><code class="language-python">del 객체</code></pre>
<blockquote>
<p>객체란 파이썬에서 사용되는 모든 자료형을 말한다.</p>
</blockquote>
</li>
</ul>
<p>다음처럼 슬라이싱 기법을 사용하여 리스트의 요소 여러 개를 한꺼번에 삭제할 수도 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3,4,5]
&gt;&gt;&gt; del a[2:]
&gt;&gt;&gt; a
[1,2]</code></pre>
<ul>
<li>a[2:]에 해당하는 리스트의 요소들이 삭제되었다.</li>
<li>리스트의 요소를 삭제하는 방법에는 2가지가 더 있다. 바로 리스트의 remove와 pop 함수를 사용하는 것인데, 이는 관련 함수에서 설명한다!</li>
</ul>
<h2 id="리스트-관련-함수">리스트 관련 함수</h2>
<p>문자열과 마찬가지로 리스트 변수 이름 뒤에&#39;.&#39;를 붙여 여러 가지 리스트 관련 함수를 사용할 수 있다.</p>
<h3 id="리스트에-요소-추가하기---append">리스트에 요소 추가하기 - append</h3>
<p>append의 사전적 의미는 &#39;덧붙이다, 첨부하다&#39;이다. 이 뜻을 안다면 다음 예가 바로 이해가 될 것이다.
append(x)는 리스트의 맨 마지막에 x를 추가하는 함수이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; a.append(4)
&gt;&gt;&gt; a
[1,2,3,4]</code></pre>
<p>리스트 안에는 어떤 자료형도 추가할 수 있다. 다음 예제는 리스트에 다시 리스트를 추가한 결과이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; a.append([5,6])
&gt;&gt;&gt; a
[1,2,3,4,[5,6]]</code></pre>
<h3 id="리스트-정렬---sort">리스트 정렬 - sort</h3>
<p>sort 함수는 리스트의 요소를 순서대로 정렬해 준다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,4,3,2]
&gt;&gt;&gt; a.sort()
&gt;&gt;&gt; a
[1,2,3,4]</code></pre>
<p>문자 역시 알파벳 순서로 정렬할 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [&#39;a&#39;, &#39;c&#39;, &#39;b&#39;]
&gt;&gt;&gt; a.sort()
&gt;&gt;&gt; a
[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]</code></pre>
<h3 id="리스트-뒤집기---reverse">리스트 뒤집기 - reverse</h3>
<p>reverse 함수는 리스트를 역순으로 뒤집어 준다. 이때 리스트 요소들을 순서대로 정렬한 다음 다시 역순으로 정렬하는 것이 아니라 현재의 리스트를 그대로 거꾸로 뒤집는다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [&#39;a&#39;, &#39;c&#39;, &#39;b&#39;]
&gt;&gt;&gt; a.reverse()
&gt;&gt;&gt; a
[&#39;b&#39;, &#39;c&#39;, &#39;a&#39;]</code></pre>
<h3 id="인덱스-반환---index">인덱스 반환 - index</h3>
<p>index(x) 함수는 리스트에 x 값이 있으면 x의 인덱스 값(위칫값)을 리턴한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; a.index(3)
2
&gt;&gt;&gt; a.index(2)
1</code></pre>
<ul>
<li>a.index(0) 에서 값 0은 a리스트에 존재하지 않기 때문에 오류가 발생한다.</li>
</ul>
<h3 id="리스트에-요소-삽입---insert">리스트에 요소 삽입 - insert</h3>
<p>insert(a,b)는 리스트의 a번째 위치에 b를 삽입하는 함수이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3]
&gt;&gt;&gt; a.insert(0,4)
&gt;&gt;&gt; a
[4,1,2,3]</code></pre>
<ul>
<li>위 예는 0번째 자리, 즉 첫 번째 요소인 a[0] 위치에 값 4를 삽입하라는 뜻이다.<pre><code class="language-python">&gt;&gt;&gt; a.insert(3, 5)
&gt;&gt;&gt; a
[4, 1, 2, 5, 3]</code></pre>
</li>
<li>위 예는 리스트 a의 a[3], 즉 네 번째 요소 위치에 값 5를 삽입하라는 뜻이다.</li>
</ul>
<h3 id="리스트-요소-제거---remove">리스트 요소 제거 - remove</h3>
<p>remove(x)는 리스트에서 첫 번째로 나오는 x를 삭제하는 함수이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3,1,2,3]
&gt;&gt;&gt; a.remove(3)
&gt;&gt;&gt; a
[1,2,1,2,3]</code></pre>
<ul>
<li>a가 3이라는 값을 2개 가지고 있을 경우, 첫 번째 3만 제거되는 것을 알 수 있다.<pre><code class="language-python">&gt;&gt;&gt; a.remove(3)
&gt;&gt;&gt; a
[1, 2, 1, 2]</code></pre>
</li>
<li>remove(3)을 한 번 더 실행하면 다시 3이 삭제된다.</li>
</ul>
<h3 id="리스트-요소-끄집어-내기---pop">리스트 요소 끄집어 내기 - pop</h3>
<p>pop()은 리스트의 맨 마지막 요소를 리턴하고 그 요소는 삭제한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3]
&gt;&gt;&gt; a.pop()
3
&gt;&gt;&gt; a
[1, 2]</code></pre>
<ul>
<li><p>a 리스트를 다시 보면 [1, 2, 3]에서 3을 끄집어 내고 최종적으로 [1, 2]만 남는 것을 확인할 수 있다.</p>
</li>
<li><p>pop(x)는 리스트의 x번째 요소를 리턴하고 그 요소는 삭제한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3]
&gt;&gt;&gt; a.pop(1)
2
&gt;&gt;&gt; a
[1, 3]</code></pre>
</li>
<li><p>a.pop(1)은 a[1]의 값을 끄집어 내어 리턴한다. 다시 a를 출력해 보면 끄집어 낸 값이 삭제된 것을 확인할 수 있다.</p>
</li>
</ul>
<h3 id="리스트에-포함된-요소-x의-개수-세기---count">리스트에 포함된 요소 x의 개수 세기 - count</h3>
<p>count(x)는 리스트 안에 x가 몇 개 있는지 조사하여 그 개수를 리턴하는 함수이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1,2,3,1]
&gt;&gt;&gt; a.count(1)
2</code></pre>
<ul>
<li>1이라는 값이 리스트 a에 2개 들어 있으므로 2를 리턴한다.</li>
</ul>
<h3 id="리스트-확장---extend">리스트 확장 - extend</h3>
<p>extend(x)에서 x에는 리스트만 올 수 있으며 원래의 a 리스트에 x 리스트를 더하게 된다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = [1, 2, 3]
&gt;&gt;&gt; a.extend([4, 5])
&gt;&gt;&gt; a
[1, 2, 3, 4, 5]
&gt;&gt;&gt; b = [6, 7]
&gt;&gt;&gt; a.extend(b)
&gt;&gt;&gt; a
[1, 2, 3, 4, 5, 6, 7]</code></pre>
<ul>
<li>a.extend([4, 5])는 <code style="background-color:#D8D8D8">a += [4, 5]</code>와 동일하다.</li>
</ul>
<h1 id="튜플-자료형">튜플 자료형</h1>
<blockquote>
<p>튜플(tuple)은 몇 가지 점을 제외하곤 리스트와 거의 비슷하며 리스트와 다른 점은 다음과 같다.</p>
</blockquote>
<ul>
<li>리스트는 [], 튜플은()으로 둘러싼다.</li>
<li>리스트는 요솟값의 생성, 삭제, 수정이 가능하지만, 튜플은 요솟값을 바꿀 수 없다.</li>
</ul>
<h2 id="튜플은-어떻게-만들까">튜플은 어떻게 만들까?</h2>
<p>튜플은 다음과 같이 여러 가지 모습으로 생성할 수 있다.</p>
<pre><code class="language-python">t1 = ()
t2 = (1,)
t3 = (1,2,3)
t4 = 1, 2, 3
t5 = (&#39;a&#39;, &#39;b&#39;, (&#39;ab&#39;, &#39;cd&#39;))</code></pre>
<ul>
<li><p>모습은 리스트와 거의 비슷하지만, 튜플에서는 리스트와 다른 2가지 차이점을 찾아볼 수 있다.</p>
</li>
<li><p><code style="background-color:#D8D8D8; color:#FA58F4">t2 = (1,)</code>처럼 단지 1개의 요소만을 가질 때는 요소 뒤에 쉼표(,)를 반드시 붙여야 하고</p>
</li>
<li><p><code style="background-color:#D8D8D8; color:#FA58F4">t4 = 1, 2, 3</code>처럼 소괄호(())를 생략해도 된다는 점이다.</p>
</li>
<li><p>얼핏 보면 튜플과 리스트는 비슷한 역할을 하지만, 프로그래밍을 할 때 튜플과 리스트는 구별해서 사용하는 것이 유리하다.</p>
</li>
<li><p>튜플과 리스트의 가장 큰 차이는 요솟값을 변화시킬 수 있는지의 여부이다.</p>
</li>
<li><p>즉, 리스트의 요솟값은 변화가 가능하고 튜플의 요솟값은 변화가 불가능하다.</p>
</li>
<li><p>따라서 프로그램이 실행되는 동안 요솟값이 항상 변하지 않기를 바란다거나 값이 바뀔까 걱정하고 싶지 않다면 주저하지 말고 튜플을 사용해야 한다.</p>
</li>
<li><p>이와 반대로 수시로 그 값을 변화시켜야할 경우라면 리스트를 사용해야 한다.</p>
</li>
<li><p>실제 프로그램에서는 값이 변경되는 형태의 변수가 훨씬 많기 때문에 평균적으로 튜플보다 리스트르 더 많이 사용한다.</p>
</li>
</ul>
<h2 id="튜플의-요솟값을-지우거나-변경하려고-하면-어떻게-될까">튜플의 요솟값을 지우거나 변경하려고 하면 어떻게 될까?</h2>
<p>앞에서 설명했듯이 튜플의 요솟값은 한 번 정하면 지우거나 변경할 수 없다.
다음에 소개하는 두 예를  살펴보면 무슨 말인지 알 수 있을 것이다!</p>
<h3 id="1튜플-요솟값을-삭제하려-할-때">1.튜플 요솟값을 삭제하려 할 때</h3>
<pre><code class="language-python">&gt;&gt;&gt; t1 = (1, 2, &#39;a&#39;, &#39;b&#39;)
&gt;&gt;&gt; del t1[0]
Traceback (most recent call last):
File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
TypeError: &#39;tuple&#39; object doesn&#39;t support item deletion</code></pre>
<ul>
<li>튜플의 요소를 리스트처럼 del 함수로 지우려고 한 예이다.</li>
<li>튜플은 요솟값을 지울 수 없다는 오류 메시지를 확인할 수 있다.</li>
</ul>
<h3 id="2튜플-요솟값을-변경하려-할-때">2.튜플 요솟값을 변경하려 할 때</h3>
<pre><code class="language-python">&gt;&gt;&gt; t1 = (1, 2, &#39;a&#39;, &#39;b&#39;)
&gt;&gt;&gt; t1[0] = &#39;c&#39;
Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
TypeError: &#39;tuple&#39; object does not support item assignment</code></pre>
<ul>
<li>튜플의 요솟값을 변경하려고 해도 오류가 발생하는 것을 확인할 수 있다.</li>
</ul>
<h2 id="튜플-다루기">튜플 다루기</h2>
<p>튜플은 요솟값을 변화시킬 수 없다는 점만 제외하면 리스트와 완전히 동일하므로 간단하게만 살펴보자.
다음 예제는 서로 연관되어 있으므로 차례대로 수행 해보자!</p>
<h3 id="인덱싱하기">인덱싱하기</h3>
<pre><code class="language-python">&gt;&gt;&gt; t1 = (1,2,&#39;a&#39;,&#39;b&#39;)
&gt;&gt;&gt;t1[0]
1
&gt;&gt;&gt;t1[3]
&#39;b&#39;</code></pre>
<ul>
<li>문자열, 리스트와 마찬가지로 t1[0],t1[3] 처럼 인덱싱이 가능하다.</li>
</ul>
<h3 id="슬라이싱하기">슬라이싱하기</h3>
<pre><code class="language-python">&gt;&gt;&gt; t1 = (1,2,&#39;a&#39;,&#39;b&#39;)
&gt;&gt;&gt; t1[1:]
(2,&#39;a&#39;,&#39;b&#39;)</code></pre>
<ul>
<li>t1[1]부터 튜플의 마지막 요소까지 슬라이싱하는 예이다.</li>
</ul>
<h3 id="튜플-더하기">튜플 더하기</h3>
<pre><code class="language-python">&gt;&gt;&gt; t1 = (1, 2, &#39;a&#39;, &#39;b&#39;)
&gt;&gt;&gt; t2 = (3, 4)
&gt;&gt;&gt; t3 = t1 + t2
&gt;&gt;&gt; t3
(1, 2, &#39;a&#39;, &#39;b&#39;, 3, 4)</code></pre>
<ul>
<li>튜플을 더하는 방법을 보여 주는 예이다. 이때도 t1, t2 튜플의 요솟값이 바뀌는 것은 아니다.</li>
<li>다만, t1, t2 튜플을 더하여 새로운 튜플 t3을 생성한 것이다.</li>
</ul>
<h3 id="튜플-곱하기">튜플 곱하기</h3>
<pre><code class="language-python">&gt;&gt;&gt; t2 = (3, 4)
&gt;&gt;&gt; t3 = t2 * 3
&gt;&gt;&gt; t3
(3, 4, 3, 4, 3, 4)</code></pre>
<ul>
<li>튜플의 곱하기(반복)의 예를 보여준다.</li>
</ul>
<h3 id="튜플-길이-구하기">튜플 길이 구하기</h3>
<pre><code class="language-python">&gt;&gt;&gt; t1 = (1, 2, &#39;a&#39;, &#39;b&#39;)
&gt;&gt;&gt; len(t1)
4</code></pre>
<ul>
<li>튜플의 길이를 구하는 예이다.</li>
</ul>
<blockquote>
<p>튜플은 요솟값을 변경할수 없기 때문에 sort, insert, remove, pop과 같은 내장 함수가 없다.</p>
</blockquote>
<hr>
<h2 id="딕셔너리-자료형">딕셔너리 자료형</h2>
<blockquote>
<p>딕셔너리는 &#39;연관 배열(associative array)’또는 ‘해시(hash)’라고 한다.
딕셔너리는 리스트나 튜플처럼 순차적으로(sequential) 해당 요솟값을 구하지 않고 Key를 통해 Value를 얻는다. </p>
</blockquote>
<h3 id="딕셔너리는-어떻게-만들까">딕셔너리는 어떻게 만들까?</h3>
<ul>
<li><p>다음은 딕셔너리의 기본 모습이다.</p>
<pre><code class="language-python">{Key1: Value1, Key2: Value2, Key3: Value3, ...}</code></pre>
</li>
<li><p>Key와 Value의 쌍 여러 개가 {}로 둘러싸여 있다.</p>
</li>
<li><p>각각의 요소는 Key:Value 형태로 이루어져 있고 쉼표(,)로 구분되어 있다.</p>
</li>
<li><p>다음 딕셔너리의 예를 살펴보자.</p>
<pre><code class="language-python">&gt;&gt;&gt; dic = {&#39;name&#39;: &#39;pey&#39;, &#39;phone&#39;: &#39;010-9999-1234&#39;, &#39;birth&#39;: &#39;1118&#39;}</code></pre>
</li>
<li><p>위에서 Key는 각각 &#39;name&#39;, &#39;phone&#39;, &#39;birth&#39;</p>
</li>
<li><p>각각의 Key에 해당하는 Value는 &#39;pey&#39;, &#39;010-9999-1234&#39;, &#39;1118&#39;이 된다.</p>
<h5 id="딕셔너리-dic의-정보">딕셔너리 dic의 정보</h5>
<table>
<thead>
<tr>
<th>key</th>
<th>value</th>
</tr>
</thead>
<tbody><tr>
<td>name</td>
<td>pey</td>
</tr>
<tr>
<td>phone</td>
<td>010-9999-1234</td>
</tr>
<tr>
<td>birth</td>
<td>1118</td>
</tr>
</tbody></table>
</li>
<li><p>다음은 Key로 정숫값 1, Value로 문자열 &#39;hi&#39;를 사용한 예이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = {1:&#39;hi&#39;}</code></pre>
</li>
<li><p>또한 다음 예처럼 Value에 리스트도 넣을 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = {&#39;a&#39;:[1,2,3]}</code></pre>
<h3 id="딕셔너리-쌍-추가하기">딕셔너리 쌍 추가하기</h3>
<pre><code class="language-python">&gt;&gt;&gt; a = {1: &#39;a&#39;}
&gt;&gt;&gt; a[2] = &#39;b&#39;
&gt;&gt;&gt; a
{1: &#39;a&#39;, 2: &#39;b&#39;}</code></pre>
</li>
<li><p>{1: &#39;a&#39;} 딕셔너리에 a[2] = &#39;b&#39;와 같이 입력하면 딕셔너리 a에 Key와 Value가 각각 2와 &#39;b&#39;인 {2: &#39;b&#39;} 딕셔너리 쌍이 추가된다.</p>
</li>
</ul>
<pre><code class="language-python">&gt;&gt;&gt; a[&#39;name&#39;] = &#39;pey&#39;
&gt;&gt;&gt; a
{1: &#39;a&#39;, 2: &#39;b&#39;, &#39;name&#39;: &#39;pey&#39;}</code></pre>
<ul>
<li>딕셔너리 a에 {&#39;name&#39;:&#39;pey&#39;} 쌍이 추가되었다.<pre><code class="language-python">&gt;&gt;&gt; a[3] = [1, 2, 3]
&gt;&gt;&gt; a
{1: &#39;a&#39;, 2: &#39;b&#39;, &#39;name&#39;: &#39;pey&#39;, 3: [1, 2, 3]}</code></pre>
</li>
<li>Key는 3, Value는 [1, 2, 3]을 가지는 한 쌍이 또 추가되었다.</li>
</ul>
<h3 id="딕셔너리-요소-삭제하기">딕셔너리 요소 삭제하기</h3>
<pre><code class="language-python">&gt;&gt;&gt; del a[1]
&gt;&gt;&gt; a
{2: &#39;b&#39;, &#39;name&#39;: &#39;pey&#39;, 3: [1, 2, 3]}</code></pre>
<ul>
<li>del 함수를 사용해서 <code sytle="background-color:grey">del a[key]</code>를 입력하면 지정한 Key에 해당하는 {Key: Value} 쌍이 삭제된다.</li>
</ul>
<h3 id="딕셔너리에-key를-사용해-value-얻기">딕셔너리에 Key를 사용해 Value 얻기</h3>
<pre><code class="language-python">&gt;&gt;&gt; grade = {&#39;pey&#39;: 10, &#39;julliet&#39;: 99}
&gt;&gt;&gt; grade[&#39;pey&#39;]
10
&gt;&gt;&gt; grade[&#39;julliet&#39;]
99</code></pre>
<ul>
<li>리스트나 튜플, 문자열은 요솟값을 얻고자 할 때 인덱싱이나 슬라이싱 기법 중 하나를 사용했다. 하지만 딕셔너리는 단 1가지 방법뿐이다. 그것은 바로 Key를 사용해서 Value를 구하는 방법이다. 위 예에서 &#39;pey&#39;라는 Key의 Value를 얻기 위해 <code sytle="background-color:grey">grade['pey']</code>를 사용한 것처럼 어떤 Key의 Value를 얻기 위해서는 &#39;딕셔너리_변수_이름[Key]&#39;를 사용해야 한다.</li>
</ul>
<h3 id="딕셔너리-만들-때-주의할-사항">딕셔너리 만들 때 주의할 사항</h3>
<pre><code class="language-python">&gt;&gt;&gt; a = {1:&#39;a&#39;, 1:&#39;b&#39;}
&gt;&gt;&gt; a
{1: &#39;b&#39;}</code></pre>
<ul>
<li>딕셔너리에서 Key는 고유한 값이므로 중복되는 Key 값을 설정해 놓으면 하나를 제외한 나머지 것들이 모두 무시된다는 점에 주의해야 한다.</li>
<li>위의 예에서 볼 수 있듯이 동일한 Key가 2개 존재할 경우, 1: &#39;a&#39; 쌍이 무시된다.</li>
<li>이렇게 Key가 중복되었을 때 1개를 제외한 나머지 Key: Value 값이 모두 무시되는 이유는 Key를 통해서 Value를 얻는 딕셔너리의 특징 때문이다.</li>
<li>즉, 딕셔너리에는 동일한 Key가 중복으로 존재할 수 없다.</li>
</ul>
<ul>
<li>또 1가지 주의해야 할 점은 Key에 리스트는 쓸 수 없다는 것이다.</li>
<li>하지만 튜플은 Key로 쓸 수 있다.</li>
<li>딕셔너리의 Key로 쓸 수 있느냐, 없느냐는 Key가 변하는(mutable) 값인지, 변하지 않는(immutable) 값인지에 달려 있다.</li>
<li>리스트는 그 값이 변할 수 있기 때문에 Key로 쓸 수 없다. </li>
<li>리스트를 Key로 설정하면 리스트를 키 값으로 사용할 수 없다는 오류가 발생한다.</li>
</ul>
<h2 id="딕셔너리-관련-함수">딕셔너리 관련 함수</h2>
<h3 id="key-리스트-만들기---keys">Key 리스트 만들기 - keys</h3>
<pre><code class="language-python">&gt;&gt;&gt; a = {&#39;name&#39;: &#39;pey&#39;, &#39;phone&#39;: &#39;010-9999-1234&#39;, &#39;birth&#39;: &#39;1118&#39;}
&gt;&gt;&gt; a.keys()
dict_keys([&#39;name&#39;, &#39;phone&#39;, &#39;birth&#39;])</code></pre>
<ul>
<li>a.keys()는 딕셔너리 a의 Key만을 모아 dict_keys 객체를 리턴한다.</li>
</ul>
<ul>
<li><p>dict_keys 객체는 다음과 같이 사용할 수 있다. 리스트를 사용하는 것과 별 차이는 없지만, 리스트 고유의 append, insert, pop, remove, sort 함수는 수행할 수 없다.</p>
<pre><code class="language-python">&gt;&gt;&gt; for k in a.keys():
...    print(k)
...
name
phone
birth</code></pre>
<blockquote>
<ul>
<li>print(k)를 입력할 때 들여쓰기를 하지 않으면 오류가 발생하므로 주의하자.</li>
</ul>
</blockquote>
</li>
<li><p>dict_keys 객체를 리스트로 변환하려면 다음과 같이 하면 된다.</p>
<pre><code class="language-python">&gt;&gt;&gt; list(a.keys())
[&#39;name&#39;, &#39;phone&#39;, &#39;birth&#39;]</code></pre>
</li>
</ul>
<h3 id="value-리스트-만들기---values">Value 리스트 만들기 - values</h3>
<pre><code class="language-python">&gt;&gt;&gt; a.values()
dict_values([&#39;pey&#39;, &#39;010-9999-1234&#39;, &#39;1118&#39;])</code></pre>
<ul>
<li>key를 얻는 것과 마찬가지 방법으로 Value만 얻고 싶다면 values 함수를 사용하면 된다.</li>
<li>values 함수를 호출하면 dict_values 객체를 리턴한다.</li>
</ul>
<h3 id="key-value-쌍-얻기---items">Key, Value 쌍 얻기 - items</h3>
<pre><code class="language-python">&gt;&gt;&gt; a.items()
dict_items([(&#39;name&#39;, &#39;pey&#39;), (&#39;phone&#39;, &#39;010-9999-1234&#39;), (&#39;birth&#39;, &#39;1118&#39;)])</code></pre>
<ul>
<li>items 함수는 Key와 Value의 쌍을 튜플로 묶은 값을 dict_items 객체로 리턴한다.<h3 id="key-value-쌍-모두-지우기---clear">Key: Value 쌍 모두 지우기 - clear</h3>
<pre><code class="language-python">&gt;&gt;&gt; a.clear()
&gt;&gt;&gt; a
{}</code></pre>
</li>
<li>clear 함수는 딕셔너리 안의 모든 요소를 삭제한다.<blockquote>
<p>빈 리스트를 [], 빈 튜플을 ()로 표현하는 것과 마찬가지로 빈 딕셔너리도 {}로 표현한다.</p>
</blockquote>
</li>
</ul>
<h3 id="key로-value-얻기---get">Key로 Value 얻기 - get</h3>
<pre><code class="language-python">&gt;&gt;&gt; a = {&#39;name&#39;: &#39;pey&#39;, &#39;phone&#39;: &#39;010-9999-1234&#39;, &#39;birth&#39;: &#39;1118&#39;}
&gt;&gt;&gt; a.get(&#39;name&#39;)
&#39;pey&#39;
&gt;&gt;&gt; a.get(&#39;phone&#39;)
&#39;010-9999-1234&#39;</code></pre>
<ul>
<li>get(x) 함수는 x라는 Key에 대응되는 Value를 리턴한다. 앞에서 살펴보았듯이 a.get(&#39;name&#39;)은 a[&#39;name&#39;]을 사용했을 때와 동일한 결괏값을 리턴한다.</li>
</ul>
<ul>
<li><p>다만, 다음 예제에서 볼 수 있듯이 a[&#39;nokey&#39;]처럼 딕셔너리에 존재하지 않는 키로 값을 가져오려고 할 경우, a[&#39;nokey&#39;] 방식은 오류를 발생시키고 a.get(&#39;nokey&#39;) 방식은 None을 리턴한다는 차이가 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = {&#39;name&#39;:&#39;pey&#39;, &#39;phone&#39;:&#39;010-9999-1234&#39;, &#39;birth&#39;: &#39;1118&#39;}
&gt;&gt;&gt; print(a.get(&#39;nokey&#39;))
None
&gt;&gt;&gt; print(a[&#39;nokey’])
Traceback (most recent call last):
File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
KeyError: &#39;nokey&#39;</code></pre>
</li>
<li><p>딕셔너리 안에 찾으려는 Key가 없을 경우, 미리 정해 둔 디폴트 값을 대신 가져오게 하고 싶을 때는 get(x, &#39;디폴트 값&#39;)을 사용하면 편리하다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a.get(&#39;nokey&#39;, &#39;foo&#39;)
&#39;foo&#39;</code></pre>
</li>
<li><p>딕셔너리 a에는 &#39;nokey&#39;에 해당하는 Key가 없다. 따라서 디폴트 값인 &#39;foo&#39;를 리턴한다.</p>
</li>
</ul>
<h3 id="해당-key가-딕셔너리-안에-있는지-조사하기---in">해당 Key가 딕셔너리 안에 있는지 조사하기 - in</h3>
<pre><code class="language-python">&gt;&gt;&gt; a = {&#39;name&#39;:&#39;pey&#39;, &#39;phone&#39;:&#39;010-9999-1234&#39;, &#39;birth&#39;: &#39;1118&#39;}
&gt;&gt;&gt; &#39;name&#39; in a
True
&gt;&gt;&gt; &#39;email&#39; in a
False</code></pre>
<ul>
<li>&#39;name&#39; 문자열은 a 딕셔너리의 Key 중 하나이다. 따라서 &#39;name&#39; in a를 호출하면 참(True)을 리턴한다.</li>
<li>이와 반대로 &#39;email&#39;은 a 딕셔너리 안에 존재하지 않는 Key이므로 거짓(False)을 리턴한다.</li>
</ul>
<hr>
<hr>
<hr>
<h1 id="출처-및-참고자료">출처 및 참고자료</h1>
<h1 id="httpswikidocsnet14"><a href="https://wikidocs.net/14">https://wikidocs.net/14</a></h1>
<h1 id="httpswikidocsnet14-1"><a href="https://wikidocs.net/14">https://wikidocs.net/14</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[CTF[2일차]]]></title>
            <link>https://velog.io/@pingu_9/CTF2%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/CTF2%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Thu, 05 Dec 2024 02:52:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
<details>
  <summary>참고</summary>
  <div><span style="color:blue">
※참고 자료는 드림핵을 이용하였습니다.<br>
※드림핵의 로드맵대로 공부할 예정입니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</blockquote>
</details>

<h1 id="컴퓨터-과학-기초">컴퓨터 과학 기초</h1>
<blockquote>
<p>컴퓨터 과학(Computer Science)은 컴퓨터를 이용한 모든 작업과 그 기반 이론을 연구하는 학문입니다.
이는 코딩뿐만 아니라 계산 이론, 알고리즘, 소프트웨어 설계, 네트워크 등 광범위한 영역을 포함합니다.</p>
</blockquote>
<blockquote>
<p><strong>해킹</strong>은 이러한 컴퓨터 과학 지식을 응용하여 프로그램이나 시스템의 취약점을 발견하고 공격하는 행위를 가리킵니다. 따라서 컴퓨터 시스템, 네트워크, 프로그래밍 언어, 운영 체제 등의 컴퓨터 과학 지식이 요구됩니다.</p>
</blockquote>
<hr>
<h2 id="진법">진법</h2>
<blockquote>
<p>진법은 임의의 숫자 혹은 문자를 사용하여 수를 표현하는 체계를 말합니다.</p>
</blockquote>
<ul>
<li>n진법은 한 자릿수를 n가지(0~n-1)의 숫자 혹은 문자로 나타낼 수 있습니다.</li>
<li>n진법으로 나타낸 수는 각각 <strong>10진수(decimal)</strong>, <strong>2진수(binary)</strong>, <strong>16진수(hexadecimal)</strong>라고 합니다.</li>
</ul>
<h2 id="비트와-바이트">비트와 바이트</h2>
<blockquote>
<p>비트와 바이트는 컴퓨터의 데이터를 다루는데 가장 기본이 되는 개념이다.</p>
</blockquote>
<ul>
<li>컴퓨터는 0과 1만으로 데이터를 표현하고 처리한다.</li>
<li>컴퓨터에서 사용하는 데이터의 최소 단위를 <strong>1비트(bit, binary digit)</strong>라고 한다.</li>
<li>8개의 비트로 구성된 더 큰 단위는 <strong>1바이트(byte)</strong>라고 하고, 이는 메모리에 저장되는 최소단위다.</li>
<li>1바이트는 $$
2^8=256$$가지의 수를 표현할 수 있습니다.<ul>
<li>10진수로 0<del>255, 2진수로 00000000</del>11111111, 16진수로 00~FF 까지 나타냅니다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>10진수 60을 2진수와 16진수로 나타낸 예시
<img src="https://velog.velcdn.com/images/pingu_9/post/dea9303a-9f2f-4078-bbd2-b71fe127aaf7/image.png" alt=""></p>
</blockquote>
<ul>
<li>16진수 한 자리는 2진수 네 자리로 변환된다.</li>
<li>따라서 16진수 0x3C는 각 자리를 2진수로 나타내면 0011과 1100이 됩니다. 이를 이어 붙이면 00111100이 되며, 이는 10진수 60을 2진수로 표현한 것과 같다.</li>
</ul>
<h3 id="최상위-비트msb-최하위-비트lsb">최상위 비트(MSB), 최하위 비트(LSB)</h3>
<blockquote>
<p>여러 개의 비트로 구성된 이진 데이터에서 가장 왼쪽에 있는 비트를 <strong>Most Significant Bit (MSB, 최상위 비트)</strong>라고 하고, 가장 오른쪽에 있는 비트를 <strong>Least Significant Bit (LSB, 최하위 비트)</strong>라고 부른다.</p>
</blockquote>
<ul>
<li><p><strong>“중요하다(Significant)”</strong>는 표현을 붙이는 이유는 가장 왼쪽에 있는 비트가 숫자의 크기에 가장 큰 영향을 미치기 때문이고, 가장 오른쪽에 있는 비트는 숫자의 크기에 가장 작은 영향을 미치기 때문에 그러한 명명이 붙은 것으로 알려져 있다.</p>
</li>
<li><p>예를 들어, 2진수 0b10010100의 MSB와 LSB를 표시하면 아래와 같습니다. 이때 우리는 “0b10010100의 MSB는 1이고, LSB는 0이다”라고 말할 수 있습니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/5dd53f13-d39c-4281-b37a-806df5d6decd/image.png" alt=""></p>
</li>
</ul>
<h3 id="부호-비트">부호 비트</h3>
<blockquote>
<p>부호가 있는 데이터의 경우, MSB는 부호의 의미를 가지게 됩니다.</p>
</blockquote>
<ul>
<li>MSB가 0이면 양수, 1이면 음수를 나타냅니다.</li>
<li>프로그래밍 언어에서 부호(+,-)를 가지는 데이터는 Signed 데이터 또는 부호가 있는 데이터라 부르고, 부호없이 양수(+)만 나타내는 데이터는 unsigned데이터 또는 부호가 없는 데이터라 부릅니다.</li>
<li>예를 들어 앞서 살펴본 0b10010100가 부호가 있는 데이터라면, MSB가 1이기 때문에 10진수로 표현하면 음수인 -108이 됩니다.</li>
<li>반면에 부호가 없는 데이터라면, MSB인 1은 부호를 의미하지 않고, 값을 의미하므로 양수인 148이 됩니다.</li>
</ul>
<h3 id="바이트-오더링byte-ordering">바이트 오더링(Byte Ordering)</h3>
<blockquote>
<p>2바이트 이상의 데이터는 메모리에 연속적으로 저장됩니다.</p>
</blockquote>
<ul>
<li>이때 각 바이트가 메모리에 정렬되는 방식을 바이트 오더링이라고 부릅니다.</li>
<li>바이트 오더링의 두 가지 방식으로 ** 빅 엔디안(Big Endian)<strong>과 **리틀 엔디안(Little Endian)</strong>이 있습니다. </li>
<li>어떤 바이트부터 낮은 주소에 저장되는지에 따라 두 방식을 구분합니다.</li>
<li>빅 엔디안은 큰 바이트부터 낮은 주소에 저장되고, 반대로 리틀 엔디안은 작은 바이트부터 낮은 주소에 저장됩니다.</li>
</ul>
<blockquote>
<p>💡 <strong>바이트 오더링과 MSB,LSB</strong></p>
</blockquote>
<ul>
<li>MSB,LSB를 이용하여 빅 엔디안, 리틀 엔디안을 설명하는 것을 종종 볼 수 있습니다.</li>
<li>이떄의 MSB,LSB는 앞서 배운 Bit를 의미하는 것이 아니라, Byte를 의미합니다.</li>
<li><u>바이트 오더링은 비트의 순서가 아니라 바이트의 순서를 고려하는 것으로, 바이트 내 비트의 순서는 동일하고 바이트의 순서만 달라집니다.</u></li>
</ul>
<h3 id="빅-엔디안big-endian">빅 엔디안(Big-endian)</h3>
<blockquote>
<p><strong>가장 왼쪽에 있는(큰) 바이트부터 메모리의 낮은 주소에 저장됩니다.</strong></p>
</blockquote>
<ul>
<li>네트워크 상에서 데이터를 전송할 때는 빅 엔디안 방식을 따릅니다.</li>
<li>대표적으로 SPARC CPU에서 빅 엔디안을 사용합니다
<img src="https://velog.velcdn.com/images/pingu_9/post/1e7b0924-dfc8-4d1d-9bb8-4283c729169a/image.png" alt=""></li>
</ul>
<h3 id="리틀-엔디안little-endian">리틀 엔디안(Little-endian)</h3>
<blockquote>
<p><strong>가장 오른쪽에 있는(작은) 바이트부터 메모리의 낮은 주소에 저장됩니다.</strong></p>
</blockquote>
<ul>
<li>대표적으로 Intel의 x86, x86-64 CPU에서 리틀 엔디안을 사용합니다. 대다수의 개인용 컴퓨터 및 서버 환경에서 x86-64 CPU 아키텍처를 사용하고 있는 만큼, 리틀 엔디안 방식을 잘 알고 있어야 합니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/2bbbb72c-c1dc-41ad-b3e4-8e7d5b322b52/image.png" alt=""></li>
</ul>
<h3 id="바이트-오더링-예시">바이트 오더링 예시</h3>
<blockquote>
<p>정교함과 정확함이 필수인 해킹 분야에서 데이터가 어떤 바이트 오더링으로 메모리에 저장되었는지 고려하는 것은 기본 중에 기본입니다.</p>
</blockquote>
<blockquote>
<ul>
<li>예를 들어, 리버스 엔지니어링 분야에서 메모리에 저장된 값을 이용해 역연산을 수행하여 어떤 정답이 되는 값을 찾아내는 작업은 매우 흔합니다. </li>
</ul>
</blockquote>
<ul>
<li>이때 메모리에 저장된 값이 어떤 엔디안으로 저장되어 있는지를 고려하지 않으면, 전혀 다른 데이터로 혼동하여 올바른 역연산 결과를 얻을 수 없게 됩니다. 앞서 살펴본 예시와 같이 리틀 엔디안 방식으로 저장된 0x01234567을 빅 엔디안으로 생각하고 0x67452301이라는 숫자로 다뤄버리면, 결국 전혀 다른 데이터를 가지고 역연산을 수행하는 꼴이 되므로 올바른 결과를 얻을 수 없게 됩니다.</li>
</ul>
<blockquote>
<ul>
<li>시스템 해킹을 예로 들어 보겠습니다. 공격을 위해 특정 메모리 주소에 원하는 값을 덮어씌워야 한다고 가정합니다. 메모리의 낮은 주소부터 값을 쓰는 경우라면, 리틀 엔디안을 고려하여 저장하려는 값의 가장 오른쪽 바이트부터 써야 원하는 값이 제대로 저장됩니다.</li>
</ul>
</blockquote>
<ul>
<li>또한 어떤 변수의 출력값을 알아내려고 한다면, 메모리의 변수 주소 영역에서 높은 주소부터 값을 읽어온다는 것을 고려해야 합니다.</li>
</ul>
<blockquote>
<ul>
<li>현실에서 많은 개인용 컴퓨터와 서버 환경이 x86 아키텍처를 사용하고 있고, 이에 따라 드림핵 로드맵 역시 대부분 x86 아키텍처 환경을 기준으로 설명하고 있습니다.</li>
</ul>
</blockquote>
<ul>
<li>그만큼 리틀 엔디안에 친숙해지는 편이 좋으므로 예시를 통해 자세히 살펴보겠습니다.</li>
<li>하단의 코드는 문자열과 16진수 정수를 메모리에 저장하는 C 프로그램의 소스 코드입니다. </li>
<li>각각 메모리에 저장된 값과 출력값을 직접 확인하여 리틀 엔디안 방식이 어떻게 적용되었는지 알아보겠습니다.</li>
</ul>
<pre><code class="language-C">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

int main(void) {
    char * str = &quot;ABCD&quot;; // 16진수: 41424344
    puts(str);    // 문자열 출력 결과: ABCD

    unsigned int num = 0;
    num = 0x41424344;
    printf(&quot;%x\n&quot;, num);  // 16진수 출력 결과: 41424344

    return 0;
}</code></pre>
<h4 id="ㅁ-문자열">ㅁ 문자열</h4>
<ul>
<li><code style="background-color:#D8D8D8">str</code> 변수 주소의 메모리를 1 바이트씩 4 바이트 출력한 결과입니다. </li>
<li><u>문자열을 메모리에 저장할 때는 바이트 오더링을 고려하지 않습니다.</u></li>
<li>따라서 문자열 &quot;ABCD&quot;는 리틀 엔디안 방식을 따르지 않고, 문자 순서 그대로 메모리에 저장됩니다.<pre><code>1  0x555555556004: 0x41    0x42    0x43    0x44</code></pre><h4 id="ㅁ-문자열이-아닌-데이터---16진수-정수">ㅁ 문자열이 아닌 데이터 - 16진수 정수</h4>
</li>
<li><code style="background-color:#D8D8D8">num</code> 변수 주소의 메모리를 1 바이트씩 4 바이트 출력한 결과입니다.</li>
<li>문자열이 아닌 데이터는 리틀 엔디안 방식으로 저장됩니다.</li>
<li>따라서 16진수 0x41424344는 가장 오른쪽의 바이트부터 메모리의 낮은 주소에 저장된 것을 볼 수 있습니다.</li>
<li><code style="background-color:#D8D8D8">num</code> 변수 값을 출력하면 메모리에 저장된 4 바이트에서 높은 주소부터 읽어 와서 원래 값 그대로 출력됩니다.<pre><code>1  0x7fffffffe314: 0x44    0x43    0x42    0x41</code></pre><h2 id="비트-연산">비트 연산</h2>
<blockquote>
<p>피연산자를 2진수로 표현하여 비트(bit) 단위로 연산하는 것을 비트 연산이라고 합니다.</p>
</blockquote>
</li>
<li>비트 단위로 논리 연산을 수행하거나, 비트를 특정 값만큼 이동하는 시프트(shift) 연산을 수행합니다.</li>
</ul>
<h4 id="ㅁ-논리-연산">ㅁ 논리 연산</h4>
<blockquote>
<p>참 또는 거짓 값으로 연산을 수행하고 결과로 참(1,true) 또는 거짓(0,false)을 반환합니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/01a35347-7826-4a6d-bf27-fc1ffc8d0f54/image.png" alt=""></p>
</blockquote>
<h4 id="ㅁ-비트-연산자">ㅁ 비트 연산자</h4>
<blockquote>
<p>비트 단위로 논리 연산을 수행합니다. 1은 참, 0은 거짓을 나타냅니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/3c8dd70f-e482-40f9-98a3-db35a1885221/image.png" alt=""></p>
</blockquote>
<h4 id="ㅁ-시프트-연산자">ㅁ 시프트 연산자</h4>
<blockquote>
<p>비트를 특정 값만큼 왼쪽 혹은 오른쪽으로 이동합니다. n만큼 시프트한 결과는 $$
2^n$$으로 곱하거나 나눈 값과 같습니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/6369126e-a8de-4f41-9977-0b5e95da8127/image.png" alt=""></p>
</blockquote>
<hr>
<hr>
<h2 id="인코딩-디코딩">인코딩, 디코딩</h2>
<blockquote>
<p><strong>인코딩(Encoding)</strong>은 데이터를 특정한 형식으로 변환하는 것을 말합니다.</p>
</blockquote>
<ul>
<li>데이터의 크기를 줄이거나, 컴퓨터가 이해하기 쉽게 변환할 때 사용합니다.</li>
<li>인코딩된 데이터는 <strong>디코딩(Decoding)</strong>하여 원래의 값을 구할 수 있습니다.</li>
<li>인코딩은 암호화와 유사하지만, 암호화는 데이터의 기밀성을 목적으로 남이 데이터를 알아보지 못하도록 변환하기 때문에 비밀키가 있어야 원문을 복구할 수 있지만, 인코딩은 누구나 표준화된 방식을 사용해서 디코딩하여 원문을 구할 수 있다는 점이 다릅니다.</li>
<li>인코딩은 컴퓨터가 데이터를 효율적으로 다루도록 중요한 역할을 수행합니다.</li>
<li>그만큼 해킹을 공부하다 보면 웹, 시스템, 네트워크 등 모든 분야에서 인코딩이 중요하다는 것을 알 수 있습니다.</li>
<li>어떤 인코딩된 데이터의 생김새를 보고 인코딩 방식을 유추하여 직접 디코딩해서 원문으로부터 단서를 얻어야 하는 경우도 있습니다. </li>
</ul>
<h2 id="아스키-코드">아스키 코드</h2>
<blockquote>
<p>컴퓨터는 0과 1만을 이용하여 정보를 처리하고 표현합니다.
우리가 입력하는 모든 글자가 0과 1로 변환되려면 숫자로 표현되어야 합니다.(이를 위한 것이 아스키 코드)</p>
</blockquote>
<blockquote>
<p><strong>아스키 코드(American Standard Code for Information Interchange, ASCII)</strong>는 정보 교환을 위한 미국 표준 코드로, 문자를 숫자로 변환하는 문자 인코딩(character encoding)의 표준입니다.</p>
</blockquote>
<ul>
<li>아스키 코드를 사용하여 문자를 숫자로 인코딩하면 서로 다른 장치 간 데이터 전송을 더 쉽게 수행할 수 있습니다.</li>
</ul>
<blockquote>
<ul>
<li>아스키 문자 1개는 1 바이트 크기로, 7 비트로 문자를 표현하고 1 비트는 오류 체크를 위해 사용합니다.</li>
</ul>
</blockquote>
<ul>
<li>따라서 27=128가지의 문자 표현이 가능하며, 각 문자는 0~127까지의 10진수 값을 가집니다.</li>
<li>이 값을 문자의 아스키 값(ASCII value)이라고 합니다.
<img src="https://velog.velcdn.com/images/pingu_9/post/c0743bf9-9986-47ea-932b-6f2dc40e713a/image.gif" alt=""><h6 id="아스키테이블">아스키테이블</h6>
</li>
</ul>
<h4 id="아스키-테이블-실습">아스키 테이블 실습</h4>
<p>🐧 아스키 테이블을 참조하여 다음 일련의 비트를 해석해보자!
<code style="background-color:#D8D8D8; color:salmon">01001000 01100101 01101100 01101100 01101111 00101100 00100000 01000100 01110010 01100101 01100001 01101101 01101000 01100001 01100011 01101011 00100001</code></p>
<blockquote>
<p>정답: Hello, Dreamhack!
풀이 : 8비트씩 분리 -&gt; 8비트 이진수를 십진수로 변환 -&gt; 십진수에 대응하는 아스키 문자 찾기</p>
</blockquote>
<h2 id="유니코드">유니코드</h2>
<blockquote>
<p><strong>유니코드(Unicode)</strong>는 영어 뿐만 아니라, 전세계 모든 언어의 문자에 고유한 번호를 부여하는 국제 표준 코드입니다.</p>
</blockquote>
<ul>
<li>서로 다른 언어를 사용할 때 문자가 호환되지 않는 문제를 해결하기 위해 만들어졌습니다.</li>
<li>아스키 코드보다 용량을 크게 확장하여 최대 32 비트로 문자 1개를 표현하여, 현재 143000개 이상의 문자를 표현할 수 있습니다.</li>
<li>유니코드의 처음 128개 문자는 아스키 코드의 문자와 정확히 일치합니다.</li>
<li>즉, 유니코드 안에 아스키 코드가 포함된다고 볼 수 있습니다.</li>
<li>유니코드 값은 U+ 뒤에 16진수를 붙여 나타냅니다. </li>
</ul>
<blockquote>
<ul>
<li>UTF-8, UTF-16, UTF-32 등 유니코드를 사용하는 다양한 인코딩 형식이 존재합니다.</li>
</ul>
</blockquote>
<ul>
<li>이는 컴퓨터가 어떤 문자를 어떻게 읽어야 하는지 미리 정해줍니다.</li>
<li>UTF 뒤의 숫자는 비트를 의미합니다.</li>
<li>가장 일반적으로 사용되는 UTF-8은 1~4 바이트의 가변적인 크기로 문자 1개를 표현하는 방식으로, 아스키 코드와 유사합니다.</li>
<li>현재 컴퓨터로 볼 수 있는 글자는 대부분 UTF-8로 인코딩된 값입니다.</li>
</ul>
<h2 id="url-인코딩퍼센트-인코딩">URL 인코딩(퍼센트 인코딩)</h2>
<blockquote>
<p>웹에서 사용되는 URL은 특정한 형식의 문자열만 허용합니다.</p>
</blockquote>
<ul>
<li>알파벳 대소문자, 숫자, 그리고 일부 특수 문자만을 포함할 수 있습니다.</li>
<li>웹 브라우저로부터 받은 URL 문자열을 유효한 형식으로 변환하는 것을 <u>URL 인코딩</u>이라고 합니다. </li>
</ul>
<blockquote>
<p>URL 인코딩을 통해 문자열을 인터넷으로 전송 가능한 형식으로 변환합니다.</p>
</blockquote>
<ul>
<li>이를 통해 전송 중에 문자가 수정되거나 의도와 다르게 해석되는 것을 막을 수 있습니다.</li>
<li>허용되지 않는 문자, 즉 인코딩이 필요한 특수문자는 <code style="background-color:#D8D8D8; color:salmon">:/?#[]@!$&'()*+,;=%공백</code>입니다.</li>
</ul>
<blockquote>
<p>URL 인코딩은 % 기호 뒤에 해 문자의 아스키 코드 16진수 값을 붙여 나타냅니다.</p>
</blockquote>
<ul>
<li>공백 문자를 예로 들어 보겠습니다. </li>
<li>URL에 공백이 포함되는 경우 + 기호 혹은 %20으로 변환됩니다.</li>
<li>여기서 %20이 URL 인코딩 결과입니다.<ul>
<li>예를 들어, 문자열 <code style="background-color:#D8D8D8; color:salmon">Welcome, Dreamhack Beginners! :)</code>를 URL 인코딩한 결과는 <code style="background-color:#D8D8D8; color:salmon">Welcome%2C%20Dreamhack%20Beginners%21%20%3A%29</code>입니다.</li>
</ul>
</li>
</ul>
<h2 id="base64-인코딩">Base64 인코딩</h2>
<blockquote>
<p>Base64 인코딩은 이진 데이터를 아스키 문자로 구성된 텍스트로 변환하는 인코딩 방식입니다.</p>
</blockquote>
<ul>
<li>총 64개의 아스키 문자가 인코딩에 사용되기 때문에 64진법(Base 64)라는 의미에서 이러한 이름이 붙여졌습니다.</li>
<li>64개의 아스키 문자는 알파벳 대소문자(52자), 숫자(10자), +, / 입니다. <ul>
<li><code style="background-color:#D8D8D8; color:salmon">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/</code></li>
</ul>
</li>
<li>Base64 인코딩은 이진 데이터를 그대로 포함할 수 없이 텍스트만 허용되는 환경에서 이진 데이터를 텍스트 형식으로 나타내기 위해 사용합니다.</li>
<li>예를 들어, 이진 데이터인 이미지를 HTML 파일에 넣는 경우 base64로 인코딩해 넣을 수 있습니다.</li>
</ul>
<blockquote>
<h5 id="base64-인코딩-방식은-다음과-같습니다">Base64 인코딩 방식은 다음과 같습니다.</h5>
</blockquote>
<ol>
<li>원본 이진 데이터를 비트 나열로 표현하고, 이를 6 비트씩 끊어서 묶습니다. 만약 비트의 개수가 6의 배수가 아닐 경우, 0을 뒤에 추가하여 6의 배수로 만듭니다.</li>
<li>각 6 비트 묶음을 수로 변환한 뒤, <a href="https://www.garykessler.net/library/base64.html">base64 테이블</a>에서 해당하는 문자를 찾아 이로 치환합니다.</li>
<li>이렇게 치환 과정을 거친 뒤, 글자 수가 4의 배수가 되도록 문자 &#39;=&#39;를 반복해 뒤에 추가합니다. 이를 <strong>패딩(Padding)</strong>이라고 합니다.</li>
</ol>
<blockquote>
<p><strong>패딩을 왜 넣어야 하나요?</strong></p>
<blockquote>
<p>예를 들어 여러분이 ZA 라는 두 글자를 디코딩하게 되면, 011001 000000 이라는 12개의 비트 나열로 바뀌게 되고, 이를 앞에서 8개씩 끊어 읽으면 아스키 문자 ‘d&#39; (01100100) 이후 0000 이 남게 됩니다.
이 경우 디코딩을 하는 입장에서 뒤에 추가적인 내용이 있는데 오지 않은 것인지, 아니면 여기서 디코딩을 끝내는 것이 맞는지 알 수 없게 됩니다.
그러므로 총 비트의 개수가 8의 배수가 되게끔 패딩 문자 &#39;=&#39;를 뒤에 붙여 이를 명확하게 하는 것입니다.</p>
</blockquote>
</blockquote>
<h5 id="아래-그림은--문자열-code-stylebackground-colord8d8d8-colorsalmondreamcode을-base64-인코딩한-예시입니다-인코딩-결과는-code-stylebackground-colord8d8d8-colorsalmonzhjlyw0code입니다">아래 그림은  문자열 <code style="background-color:#D8D8D8; color:salmon">dream</code>을 <a href="https://tools.dreamhack.games/cyberchef">base64 인코딩</a>한 예시입니다. 인코딩 결과는 <code style="background-color:#D8D8D8; color:salmon">ZHJlYW0=</code>입니다.</h5>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/f2640886-98f2-4c33-942b-bad90a16b3c3/image.png" alt=""></p>
<h4 id="base64-디코딩-실습">Base64 디코딩 실습</h4>
<p>🐧 온라인 base64 디코더를 사용해서 다음의 데이터를 직접 디코딩해보자!
<code style="background-color:#D8D8D8; color:salmon">SGFwcHkgRHJlYW1oYWNrLCBIYXBweSBIYWNraW5nIQ==</code></p>
<blockquote>
<ul>
<li>정답 : Happy Dreamhack, Happy Hacking!
풀이 : <a href="https://tools.dreamhack.games/cyberchef">Dreamhack Tools</a></li>
</ul>
</blockquote>
<h2 id="인코딩-도구">인코딩 도구</h2>
<ul>
<li><p><a href="https://tools.dreamhack.games/cyberchef">https://tools.dreamhack.games/cyberchef</a>  </p>
</li>
<li><p><a href="https://emn178.github.io/online-tools/base64_encode.html">https://emn178.github.io/online-tools/base64_encode.html</a>  </p>
</li>
<li><p><a href="https://encoding.tools/">https://encoding.tools/</a>  </p>
</li>
</ul>
<hr>
<hr>
<h2 id="운영체제os">운영체제(OS)</h2>
<blockquote>
<p>사용자는 웹 브라우저, 엑셀, 메모장 등의 프로그램으로 원하는 작업을 수행하곤 합니다. 
사용자를 위해 특정한 기능을 수행하는 이러한 프로그램을 응용 프로그램이라고 합니다. 
이때 응용 프로그램의 동작을 수행하고, 응용 프로그램에게 시스템 자원을 할당하는 등의 복잡한 관리 작업은 사용자가 아니라 <strong>운영체제(Operating System, OS)</strong>라는 소프트웨어에 의해 이루어집니다.</p>
</blockquote>
<blockquote>
<p>사용자 및 응용 프로그램은 컴퓨터 하드웨어(CPU, 메모리, 입출력 장치 등)에 직접 접근하지 않습니다.
대신 운영체제가 하드웨어와 사용자/응용 프로그램 사이에서 중재자 역할을 합니다.</p>
</blockquote>
<h4 id="운영체제가-하는-일">운영체제가 하는 일</h4>
<blockquote>
<p>운영체제는 CPU, 메모리, 입출력 장치(키보드, 마우스, 디스크) 등의 하드웨어 자원을 효율적으로 사용할 수 있도록 분배, 할당하여 성능을 높입니다.
만약 운영체제가 없다면 사용자가 하드웨어를 직접 관리해야 합니다.
운영체제 덕분에 사용자는 컴퓨터를 보다 편리하게 사용할 수 있습니다.
운영체제는 하드웨어 자원들을 적절히 분배하고 각 기능을 수행합니다. 수행하는 대표적인 기능들은 다음과 같습니다.</p>
</blockquote>
<ul>
<li>실행중인 프로그램, 즉 프로세스에 CPU를 번갈아 할당해야 하는데, 이때 어떤 프로세스에 CPU를 할당할지 결정합니다. (CPU 스케줄링)</li>
<li>메모리 공간을 각 프로세스에 분배하고 사용하는 과정을 관리합니다.</li>
<li>컴퓨터가 입출력 장치와 정보를 주고 받는 과정을 관리합니다.</li>
</ul>
<p>운영체제는 사용자와 컴퓨터 사이 인터페이스 역할도 합니다. 사용자가 컴퓨터에 명령을 내릴 수 있도록 하는데, 이는 다음으로 소개할 <strong>셸</strong>의 기능입니다.</p>
<h4 id="커널과-셸">커널과 셸</h4>
<blockquote>
<p>운영체제는 크게 <strong>커널</strong>과 <strong>셸</strong>로 나눌 수 있습니다.
먼저 <strong>커널(Kernel, 알맹이)</strong>은 운영체제의 핵심 기능인 하드웨어 관리를 실제로 수행하는 프로그램입니다.
커널은 소프트웨어와 하드웨어 간의 커뮤니케이션을 관리하며, 시스템이 부팅될 때 메모리에 올라가서 꺼질 때까지 실행됩니다.</p>
</blockquote>
<blockquote>
<p><strong>셸(Shell, 껍질)</strong>은 사용자와 운영체제의 커널 사이에서 사용자가 운영체제에 명령을 내릴 수 있도록 인터페이스 역할을 합니다.
사용자가 셸에 명령을 입력하면, 셸이 명령어를 해석하여 커널에 요청합니다.
커널은 명령을 수행하며 하드웨어를 조작하고, 수행 결과를 셸에 전송합니다.
셸은 이 결과를 해석하여 사용자에게 출력해 줍니다. 즉, 셸은 명령어를 해석하는 역할을 하여 사용자와 운영체제가 소통할 수 있도록 합니다.
셸을 획득하면 명령어를 통해 원하는 작업을 수행하고 시스템을 제어할 수 있게 됩니다.
따라서 일반적으로 셸을 획득하는 것을 시스템 해킹의 성공으로 여깁니다.</p>
</blockquote>
<hr>
<hr>
<hr>
<h2 id="마치며">마치며</h2>
<blockquote>
<p>이번 강의에서는 컴퓨터 과학이 무엇이며 왜 공부해야 하는지 알아보고, 강의 수강을 위해 필요한 기초 지식을 공부했습니다. 이번 강의를 통해 컴퓨터에서 값을 표현하고 메모리에 저장하는 방법, 비트 연산을 수행하는 방법, 인코딩 방식, 그리고 리눅스(Linux) 운영체제가 무엇인지 충분히 숙지하셨다면 앞으로 강의를 수강할 때 더 깊은 이해가 가능할 것입니다.</p>
</blockquote>
<blockquote>
<p>해킹은 컴퓨터에 대한 이해와 기술적 지식이 필요한 분야인 만큼 깊게 파고들면 파고들수록 컴퓨터 과학에 대해 더 깊게 이해해야 합니다. 하지만 이번 강의에서 다룬 내용은 컴퓨터 과학에서 극히 기초적인 지식에 불과합니다. 따라서 드림핵 강의를 수강하시면서 컴퓨터 과학 공부도 함께 차근차근 병행해 나가시기를 추천해 드립니다. 드림핵이든 컴퓨터 과학이든 뒤로 갈수록 지식이 결합되면서 시너지 효과가 발생할 것은 분명합니다. 🚩
<strong>출처 : <a href="https://learn.dreamhack.io/440#16">https://learn.dreamhack.io/440#16</a></strong></p>
</blockquote>
<h2 id="키워드">키워드</h2>
<ul>
<li><strong>진법</strong>: 임의의 숫자 혹은 문자를 사용하여 수를 표현하는 체계. 10진법, 2진법, 16진법, 8진법 등이 있고 컴퓨터에서는 주로 2진법과 16진법을 사용한다.</li>
</ul>
<ul>
<li><p><strong>바이트 오더링</strong>: 바이트가 메모리에 저장되는 방식. 빅 엔디안은 가장 왼쪽에 있는 바이트부터 낮은 주소에 저장되고, 리틀 엔디안은 가장 오른쪽에 있는 바이트부터 낮은 주소에 저장한다.</p>
</li>
<li><p><strong>비트 연산</strong>: 비트 단위로 수행하는 연산. |(or), &amp;(and), ^(xor), ~(not), &gt;&gt;(right shift), &lt;&lt;(left shift) 연산자가 있다.</p>
</li>
<li><p><strong>인코딩</strong>: 데이터를 특정한 형식으로 변환하는 것. 인코딩 방식으로는 아스키 코드와 유니 코드, url 인코딩과 base64 인코딩 등이 있다.</p>
</li>
<li><p><strong>운영 체제</strong>: 사용자 및 응용 프로그램과 하드웨어 사이에서 중재자 역할을 하는 소프트웨어. 하드웨어를 관리하고 사용자에게 편리함을 제공한다.</p>
</li>
</ul>
<h1 id="출처-및-참고자료">출처 및 참고자료</h1>
<h1 id="httpslearndreamhackio44016"><a href="https://learn.dreamhack.io/440#16">https://learn.dreamhack.io/440#16</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬[2일차]]]></title>
            <link>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC2%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@pingu_9/%ED%8C%8C%EC%9D%B4%EC%8D%AC2%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 04 Dec 2024 04:24:15 GMT</pubDate>
            <description><![CDATA[<details>
  <summary>참고</summary>
  <div><span style="color:blue">참고 자료는 점프 투 파이썬으로 선택했습니다.<br>
※스스로를 위해 정리한 참고 자료입니다.</span></div>
</details>


<h2 id="파이썬-프로그래밍의-기초-자료형">파이썬 프로그래밍의 기초, 자료형</h2>
<blockquote>
<ul>
<li>어떤 프로그래밍 언어이든 그 언어의 <strong>자료형</strong>을 알고 이해할 수 있다면 이미 그 언어의 절반을 터득한 것이나 다름없다.</li>
</ul>
</blockquote>
<ul>
<li>자료형이란 프로그래밍을 할 때 쓰이는 숫자, 문자열 등과 같이 자료 형태로 사용하는 모든 것을 뜻한다.</li>
</ul>
<hr>
<h2 id="숫자형">숫자형</h2>
<blockquote>
<p><span style="color:blue">숫자형(Number)</span>이란 숫자 형태로 이루어진 자료형으로, 우리가 이미 잘 알고 있는 것이다.</p>
</blockquote>
<ul>
<li>123과 같은 정수, 12.34 같은 실수, 8진수나 16진수도 있다.</li>
</ul>
<p>다음 표는 파이썬에서 숫자를 어떻게 사용하는지 간략하게 보여준다.</p>
<table>
<thead>
<tr>
<th align="center">항목</th>
<th align="center">파이썬 사용 예</th>
</tr>
</thead>
<tbody><tr>
<td align="center">정수</td>
<td align="center">123,-345,0</td>
</tr>
<tr>
<td align="center">실수</td>
<td align="center">123.45, -123.45, 3.4e10</td>
</tr>
<tr>
<td align="center">8진수</td>
<td align="center">0o34, 0o25</td>
</tr>
<tr>
<td align="center">16진수</td>
<td align="center">0x2A, 0xFF</td>
</tr>
</tbody></table>
<h3 id="숫자형은-어떻게-만들고-사용할까">숫자형은 어떻게 만들고 사용할까?</h3>
<h4 id="ㅁ-정수형">ㅁ 정수형</h4>
<ul>
<li><p>정수형(integer)이란 말 그대로 정수를 뜻하는 자료형을 말한다.</p>
</li>
<li><p>다음은 양의 정수와 음의 정수, 숫자 0을 변수 a에 대입하는 예이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = 123
&gt;&gt;&gt; a = -178
&gt;&gt;&gt; a = 0</code></pre>
<h4 id="ㅁ-실수형">ㅁ 실수형</h4>
</li>
<li><p>파이썬에서 실수형(floating-point)은 소수점이 포함된 숫자를 말한다.</p>
</li>
<li><p>다음은 실수를 변수 a에 대입하는 예이다. 일반적으로 볼 수 있는 실수형의 소수점 표현 방식이다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = 1.2
&gt;&gt;&gt; a = -3.45</code></pre>
</li>
<li><p>다음은 &#39;컴퓨터식 지수 표현 방식&#39;으로, 파이썬에서는 4.24e10 또는 4.24E10 처럼 표현한다.(e와 E 둘 중 어느 것을 사용해도 가능!)</p>
<pre><code class="language-python">&gt;&gt;&gt; a = 4.24E10
&gt;&gt;&gt; a = 4.24e-10</code></pre>
</li>
<li><p>여기서 4.24E10은 $$
4.24 * 10^{10}$$ , 4.24e-10은 $$
4.24 * 10^{-10}$$을 의미한다.</p>
<h4 id="ㅁ-8진수와-16진수">ㅁ 8진수와 16진수</h4>
</li>
<li><p>8진수(octal)를 만들기 위해서는 숫자가 0o 또는 0O(숫자0 + 알파벳 소문자o 또는 ㄷ문자 O)으로 시작하면 된다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = 0o177
&gt;&gt;&gt; print(a)
127</code></pre>
<blockquote>
<p>$$
1×8^2+7×8^1+7=127$$</p>
</blockquote>
</li>
<li><p>16진수(hexadecimal)를 만들기 위해서는 0x로 시작하면 된다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = 0x8ff
&gt;&gt;&gt; b = 0xABC
&gt;&gt;&gt; print(b)
2748</code></pre>
<blockquote>
<p>$$
10×16^2+11×16^1+12=2748$$</p>
</blockquote>
</li>
</ul>
<h3 id="숫자형을-활용하기-위한-연산자">숫자형을 활용하기 위한 연산자</h3>
<h4 id="ㅁ-사칙-연산">ㅁ 사칙 연산</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = 3
&gt;&gt;&gt; b = 4
&gt;&gt;&gt; a + b
7
&gt;&gt;&gt; a - b
-1
&gt;&gt;&gt; a * b
12
&gt;&gt;&gt; a / b
0.75</code></pre>
<h4 id="ㅁ-x의-y-제곱을-나타내는-연산자">ㅁ x의 y 제곱을 나타내는 **연산자</h4>
<ul>
<li>사칙연산 다음으로는 <code style="background-color:#D8D8D8">**</code> 연산자가 있다.</li>
<li>이 연산자는 <code style="background-color:#D8D8D8">x ** y</code> 처럼 사용했을 때 $$
x^y$ 값을 나타낸다.<pre><code class="language-python">&gt;&gt;&gt; a = 3
&gt;&gt;&gt; b = 4
&gt;&gt;&gt; a ** b
81</code></pre>
<h4 id="ㅁ-나눗셈-후-나머지를-리턴하는-code-stylebackground-colord8d8d8code연산자">ㅁ 나눗셈 후 나머지를 리턴하는 <code style="background-color:#D8D8D8">%</code>연산자</h4>
<pre><code class="language-python">&gt;&gt;&gt; 7 % 3
1
&gt;&gt;&gt; 3 % 7
3</code></pre>
<h4 id="ㅁ-나눗셈-후-몫을-리턴하는-연산자">ㅁ 나눗셈 후 몫을 리턴하는 //연산자</h4>
```python<blockquote>
<blockquote>
<blockquote>
<p>7 / 4  # 그냥 나누기</p>
</blockquote>
</blockquote>
</blockquote>
</li>
</ul>
<p>1.75</p>
<pre><code>```python
7 // 4
1</code></pre><h4 id="ㅁ-복합-연산자">ㅁ 복합 연산자</h4>
<ul>
<li>복합 연산자는 앞서 살펴본 +,- 와 같은 산술 연산자와 대입 연산자(=)를 합쳐 놓은 것이다.<pre><code class="language-python">&gt;&gt;&gt; a = 1
&gt;&gt;&gt; a = a + 1 # a + 1로 계산된 값을 다시 a에 대입한다.
&gt;&gt;&gt; print(a)
2</code></pre>
<pre><code class="language-python">&gt;&gt;&gt; a += 1 #a = a + 1 과 같은 표현이다.</code></pre>
</li>
</ul>
<blockquote>
<p>복합 연산자에는 다음과 같은 것들이 있다.</p>
</blockquote>
<ul>
<li>+=</li>
<li>-=</li>
<li>*=</li>
<li>/=</li>
<li>//=</li>
<li>%=</li>
<li>**=</li>
</ul>
<hr>
<h2 id="문자열-자료형">문자열 자료형</h2>
<blockquote>
<p>문자열(string)이란 연속된 문자들의 나열을 말한다.</p>
</blockquote>
<ul>
<li>&quot;123&quot;  &quot;a&quot;  &lt;- 큰따옴표로 둘러싸여 있으면 모두 문자열이라고 보면 된다.</li>
</ul>
<h3 id="문자열-만드는-방법-4가지">문자열 만드는 방법 4가지</h3>
<h4 id="ㅁ-큰따옴표로-양쪽-둘러싸기">ㅁ 큰따옴표로 양쪽 둘러싸기</h4>
<ul>
<li>&quot;Hello World&quot;<h4 id="ㅁ-작은따옴표로-양쪽-둘러싸기">ㅁ 작은따옴표로 양쪽 둘러싸기</h4>
</li>
<li>&#39;Hello World&#39;<h4 id="ㅁ-큰따옴표-3개를-연속으로-써서-양쪽-둘러싸기">ㅁ 큰따옴표 3개를 연속으로 써서 양쪽 둘러싸기</h4>
</li>
<li>&quot;&quot;&quot;Hello World&quot;&quot;&quot;<h4 id="ㅁ-작은따옴표-3개를-연속으로-써서-양쪽-둘러싸기">ㅁ 작은따옴표 3개를 연속으로 써서 양쪽 둘러싸기</h4>
</li>
<li>&#39;&#39;&#39;Hello World&#39;&#39;&#39;</li>
</ul>
<h4 id="ㅁ-문자열에-작은따옴표-포함하기">ㅁ 문자열에 작은따옴표 포함하기</h4>
<ul>
<li>큰따옴표 안에 들어 있는 작은따옴표는 문자열을 나타내기 위한 기호로 인식되지 않는다.<pre><code class="language-python">&gt;&gt;&gt; A = &quot;Hello&#39; World&quot;
&gt;&gt;&gt; A
Hello&#39; World</code></pre>
</li>
<li>프롬프트에 A를 입력해 결과를 확인해 보면 변수에 저장된 문자열이 그대로 출력된다.</li>
<li>반대로 큰따옴표를 문자열에 포함하고 싶으면 작은따옴표로 둘러싸면 된다.<h4 id="ㅁ-역슬래시를-사용해서-작은따옴표와-큰따옴표를-문자열에-포함하기">ㅁ 역슬래시를 사용해서 작은따옴표와 큰따옴표를 문자열에 포함하기</h4>
<pre><code class="language-python">&gt;&gt;&gt; A = &#39;Hel\&#39;lo World&#39;
&gt;&gt;&gt; B = &quot;Hel\&quot;lo World&quot;
&gt;&gt;&gt; A
&gt;&gt;&gt; B
Hel\&#39;lo World
Hel\&quot;lo World
</code></pre>
</li>
</ul>
<pre><code>- 역슬래시(&lt;code style=&quot;background-color:#D8D8D8&quot;&gt;/&lt;/code&gt;)를 작은따옴표나 큰따옴표 앞에 삽입하면 역슬래시 뒤의 작은따옴표나 큰따옴표는 문자열을 둘러싸는 기호의 의미가 아니라 &#39;나 &quot; 자체를 뜻하게 된다.
#### ㅁ 여러 줄인 문자열을 변수에 대입하고 싶을 때
1. **줄을 바꾸기 위한 이스케이프 코드 &lt;code style=&quot;background-color:#D8D8D8&quot;&gt;\n&lt;/code&gt; 삽입하기**
&gt;Hello
world

```python
&gt;&gt;&gt; A = &quot;Hello\n World&quot;</code></pre><ul>
<li>위 예제처럼 줄바꿈 문자인 <code style="background-color:#D8D8D8">\n</code>을 삽입하는 방법이 있지만, 읽기가 불편하고 줄이 길어지는 단점이 있다.</li>
</ul>
<ol start="2">
<li><strong>연속된 작은따옴표 3개 또는 큰따옴표 3개 사용하기</strong>
1번의 방법의 단점을 극복하기 위해 파이썬에서는 다음과 같이 작은따옴표 3개(&#39;&#39;&#39;) 또는 큰따옴표 3개(&quot;&quot;&quot;)를 사용한다.<pre><code class="language-python">&gt;&gt;&gt; A = &#39;&#39;&#39;
... Hello
... World
... &#39;&#39;&#39;</code></pre>
</li>
</ol>
<ul>
<li>작은따옴표 3개를 사용한 경우<pre><code class="language-python">&gt;&gt;&gt; A = &quot;&quot;&quot;
... Hello
... World
... &quot;&quot;&quot;</code></pre>
</li>
<li>큰따옴표 3개를 사용한 경우<pre><code class="language-python">&gt;&gt;&gt; print(A)
Hello
World</code></pre>
</li>
<li>위 코드는 출력 결과를 나타낸다.</li>
</ul>
<hr>
<blockquote>
<h5 id="이스케이프-코드란">이스케이프 코드란?</h5>
<p>문자열 예제에서 여러 줄의 문장을 처리할 때 역슬래시 문자와 소문자 n을 조합한 <code style="background-color:#D8D8D8">\n</code> 이스케이프 코드를 사용했다.
이스케이프(escape)코드란 프로그래밍할 때 사용할 수 있도록 미리 정의해 둔 &#39;문자 조합&#39;을 말한다.
주로 출력물을 보기 좋게 정렬하는 용도로 사용한다.
몇 가지 이스케이프 코드를 정리하면 다음과  같다.</p>
</blockquote>
<table>
<thead>
<tr>
<th>코드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code style="background-color:#D8D8D8">\n</code></td>
<td>문자열 안에서 줄을 바꿀 때 사용</td>
</tr>
<tr>
<td><code style="background-color:#D8D8D8">\t</code></td>
<td>문자열 사이에 탭 간격을 줄 때 사용</td>
</tr>
<tr>
<td><code style="background-color:#D8D8D8">\ &lt;/code></td>
<td><code>&lt;/code>를 그대로 표현할 때 사용</td>
</tr>
<tr>
<td><code style="background-color:#D8D8D8">&#39;</code></td>
<td>작은따옴표(&#39;)를 그대로 표현할 때 사용</td>
</tr>
<tr>
<td><code style="background-color:#D8D8D8">&quot;</code></td>
<td>큰따옴표(&quot;)를 그대로 표현할 때 사용</td>
</tr>
<tr>
<td><code style="background-color:#D8D8D8">\r</code></td>
<td>캐리지 리턴(줄 바꿈 문자, 커서를 현재 줄의 가장 앞으로 이동)</td>
</tr>
<tr>
<td><code style="background-color:#D8D8D8">\f</code></td>
<td>폼 피드(줄 바꿈 문자, 커서를 줄의 다음 줄로 이동</td>
</tr>
<tr>
<td><code style="background-color:#D8D8D8">\a</code></td>
<td>벨 소리(출력할 때 PC 스피커에 &#39;삑&#39; 소리가 난다</td>
</tr>
<tr>
<td><code style="background-color:#D8D8D8">\b</code></td>
<td>백 스페이스</td>
</tr>
<tr>
<td><code style="background-color:#D8D8D8">\000</code></td>
<td>널 문자</td>
</tr>
<tr>
<td>- 이 중에서 활용 빈도가 높은 것은 <code style="background-color:#D8D8D8">\n,\t,\ ,&#39;,&quot;</code>이다. 나머지는 잘 사용하지 않는다.</td>
<td></td>
</tr>
<tr>
<td>***</td>
<td></td>
</tr>
<tr>
<td>#### ㅁ 문자열 연산하기</td>
<td></td>
</tr>
<tr>
<td>- 파이썬에서는 문자열을 더하거나 곱할 수 있다.</td>
<td></td>
</tr>
<tr>
<td>#### ㅁ 문자열 더해서 연결하기</td>
<td></td>
</tr>
<tr>
<td>```python</td>
<td></td>
</tr>
</tbody></table>
<blockquote>
<blockquote>
<blockquote>
<p>head = &quot;python&quot;
tail = &quot;is fun!&quot;
head + tail
python is fun!</p>
</blockquote>
</blockquote>
</blockquote>
<pre><code>#### ㅁ 문자열 곱하기
```python
&gt;&gt;&gt; a = &quot;python&quot;
&gt;&gt;&gt; a * 2
pythonpython</code></pre><ul>
<li><code style="background-color:#D8D8D8">a * 2</code>라는 문장은 a를 2번 반복하라는 뜻이다.</li>
<li><code style="background-color:#D8D8D8">*</code>은 문자열의 반복을 뜻하는 의미로 사용되었다.<h4 id="ㅁ-문자열-곱하기를-응용하기">ㅁ 문자열 곱하기를 응용하기</h4>
<pre><code class="language-python">&gt;&gt;&gt; print(&quot;=&quot; * 50)
&gt;&gt;&gt; print(&quot;My Program&quot;)
&gt;&gt;&gt; print(&quot;=&quot; * 50)
==================================================
My Program
==================================================</code></pre>
</li>
<li>프로그램을 만들어 실행시켰을 때 출력되는 화면의 제일 위쪽에 프로그램 제목을 이와 같이 표현하면 표시하기 좋은 것 같다!<h4 id="ㅁ-문자열-길이-구하기">ㅁ 문자열 길이 구하기</h4>
</li>
<li>문자열의 길이는 다음과 같이 len 함수를 사용하면 구할 수 있다.</li>
<li>len 함수는 print 함수처럼 파이썬의 기본 내장 함수로, 별다른 설정 없이 바로 사용할 수 있다.</li>
</ul>
<blockquote>
<p>문자열의 길이에는 공백 문자도 포함된다.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Hello World&quot;
&gt;&gt;&gt; len(a)
11</code></pre>
<h4 id="ㅁ-문자열-인덱싱과-슬라이싱">ㅁ 문자열 인덱싱과 슬라이싱</h4>
<ul>
<li>인덱싱(indexing)이란 무엇인가를 &#39;가리킨다&#39;, 슬라이싱(sclicing)은 무엇인가를 &#39;잘라 낸다&#39;라는 의미이다.<h4 id="ㅁ-문자열-인덱싱">ㅁ 문자열 인덱싱</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Life is too short, You need Python&quot;</code></pre>
</li>
<li>위 코드에서 변수 a에 저장한 문자열의 각 문자마다 번호르 매겨 보자!
<img src="https://velog.velcdn.com/images/pingu_9/post/f5f68023-5811-4908-b28e-cfc16594bf76/image.png" alt=""></li>
<li>그 다음 예제를 살펴보자<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Life is too short, You need Python&quot;
&gt;&gt;&gt; a[3]
e</code></pre>
</li>
<li>a[3]이 뜻하는 것은 a라는 문자열의 네 번째 문자 e를 말한다.<ul>
<li>파이썬은 0부터 숫자를 센다!</li>
<li>위 예에서 볼 수 있듯이 a[번호]는 문자열 안의 특정한 값을 뽑아내는 역할을 한다.<ul>
<li>이러한 작업을 <strong>인덱싱</strong> 이라고 한다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="ㅁ-문자열-인덱싱-활용하기">ㅁ 문자열 인덱싱 활용하기</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Life is too short, You need Python&quot;
&gt;&gt;&gt; a[0]
&gt;&gt;&gt; a[12]
&gt;&gt;&gt; a[-1]
L
s
n</code></pre>
<ul>
<li>앞의 a[0]과 a[12]는 쉽게 이해할 수 있는데, 마지막의 a[-1]이 뜻하는 것은 뭘까?</li>
<li>문자열을 뒤에서 부터 읽기 위해 -(빼기) 기호를 붙인 것이다.</li>
<li>즉 a[-1]은 뒤에서부터 세어 첫 번째가 되는 문자를 말한다.<h4 id="ㅁ-문자열-슬라이싱">ㅁ 문자열 슬라이싱</h4>
</li>
<li>그렇다면 문자열에서 단순히 한 문자만 뽑아 내는 것이 아니라 &#39;Life&#39;, &#39;You&#39; 같은 단어를 뽑아 내는 방법은 없을까? 알아보자!<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Life is too short, You need Python&quot;
&gt;&gt;&gt; b = a[0] + a[1] + a[2] + a[3]
&gt;&gt;&gt; b
Life</code></pre>
</li>
<li>위와 같이 단순하게 접근할 수도 있지만 파이썬에서는 더 좋은 방법을 제공한다. 바로 슬라이싱(slicing) 기법이다.</li>
</ul>
<blockquote>
<p>인덱싱 기법과 슬라이싱 기법은 뒤에서 배울 자료형인 리스트나 튜플에서도 사용할 수 있다.</p>
</blockquote>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Life is too short, You need Python&quot;
&gt;&gt;&gt; a[0:4]
Life</code></pre>
<ul>
<li>a[0:4]는 a 문자열, 즉 &quot;Life is too short, You need Python&quot; 문자열에서 자리 번호 0부터 4까지의 문자를 뽑아 낸다는 뜻이다.</li>
<li>a[0:3]으로도 뽑아 낼 수 있지 않을까? 하는 의문이 생긴다.</li>
<li>하지만 슬라이싱 기법은 a[시작_번호:끝_번호]를 지정할 때 끝 번호에 해당하는 문자는 포함하지 않는다.</li>
<li>수식으로 표현해보면 0 &lt;= a &lt; 3 으로 표현할 수 있다.</li>
</ul>
<h4 id="ㅁ-슬라이싱-기법의-원리">ㅁ 슬라이싱 기법의 원리</h4>
<pre><code class="language-python">a[start:end:step]</code></pre>
<ul>
<li>start: 슬라이스 시작 인덱스 (기본값 = 0)</li>
<li>end: 슬라이스 끝 인덱스 (기본값 = 리스트의 끝)</li>
<li>step: 몇 칸씩 이동할지 정함 (기본값 = 1)<ul>
<li>특히, step에 -1을 주면 리스트를 거꾸로 뒤집을 수 있습니다.</li>
</ul>
</li>
</ul>
<h4 id="ㅁ-문자열을-슬라이싱하는-방법">ㅁ 문자열을 슬라이싱하는 방법</h4>
<ul>
<li><p>슬라이싱 할 때 항상 시작 번호가 0일 필요는 없다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a[5:7]
&gt;&gt;&gt; a[12:17]
is
short</code></pre>
</li>
<li><p>a[시작_번호:끝_번호]에서 끝 번호 부분을 생략하면 시작 번호부터 그 문자열의 끝까지 뽑아 낸다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a[19:]
You need python</code></pre>
</li>
<li><p>a[시작_번호:끝_번호]에서 시작 번호를 생략하면 문자열의 처음부터 끝 번호까지 뽑아 낸다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a[:17]
Life is too short</code></pre>
</li>
<li><p>a[시작_번호:끝_번호]에서 시작 번호와 끝 번호를 생략하면 문자열의 처음부터 끝까지 뽑아 낸다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a[:]
Life is too short, You need python</code></pre>
</li>
<li><p>슬라이싱에서도 인덱싱과 마찬가지로 -(빼기) 기호를 사용할 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a[19:-7]
You need</code></pre>
<h4 id="ㅁ-슬라이싱으로-문자열-바꾸기">ㅁ 슬라이싱으로 문자열 바꾸기</h4>
</li>
<li><p>Pithon 문자열을 Python으로 바꾸려면 어떻게 해야 할까?</p>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Pithon&quot;
&gt;&gt;&gt; a[1] = &#39;y&#39;</code></pre>
</li>
<li><p>즉, a 변수에 &quot;Pithon&quot; 문자열을 대입하고 a[1]의 값이 i이므로 a[1]을 y로 바꾸어 준다는 생각이다.</p>
</li>
<li><p>하지만 결과는 오류가 발생한다. -&gt; 문자열의 요솟값은 바꿀 수 있는 값이 아니기 때문이다.</p>
<ul>
<li>그래서 문자열을 &#39;변경 불가능한(immutable)자료형&#39;이라고도 부른다.</li>
</ul>
</li>
<li><p>하지만 앞에서 배운 슬라이싱 기법을 사용하면 Pithon 문자열을 사용해 Python 문자열을 만들 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Pithon&quot;
&gt;&gt;&gt;a[:1] + &#39;y&#39; + a[2:]
python</code></pre>
</li>
<li><p>슬라이싱을 사용하면 &quot;Pithon&quot; 문자열을 &#39;P&#39; 부분과 &#39;thon&#39; 부분으로 나눌 수 있고, 그 사이에 &#39;y&#39; 문자를 추가하면 &#39;Python&#39;이라는 새로운 문자열을 만들 수 있다.</p>
<h4 id="ㅁ-문자열-포매팅이란">ㅁ 문자열 포매팅이란?</h4>
</li>
<li><p>문자열에서 또 하나 알아야 할 것으로 문자열 포매팅(string formatting)이 있다.</p>
</li>
<li><p>문자열 포매팅을 공부하기 전에 다음과 같은 문자열을 출력하는 프로그램을 작성했다고 가정해 보자.</p>
</li>
</ul>
<blockquote>
<p>&quot;현재 온도는 18도 입니다.&quot;</p>
</blockquote>
<p>시간이 지나서 20도가 되면 다음 문장을 출력해보자</p>
<blockquote>
<p>&quot;현재 온도는 20도 입니다.&quot;</p>
</blockquote>
<ul>
<li>두 문자열은 모두 같은데 20이라는 숫자와 18이라는 숫자만 다르다.</li>
<li>이렇게 문자열 안에 특정한 값을 바꿔야 할 경우가 있을 때 이것을 가능하게 해 주는 것이 바로 문자열 포매팅이다.</li>
<li>쉽게 말해 문자열 포매팅이란 문자열 안에 어떤 값을 삽입하는 방법이다.<h4 id="ㅁ-문자열-포매팅-따라-하기">ㅁ 문자열 포매팅 따라 하기</h4>
</li>
<li><em>1. 숫자 바로 대입*</em><pre><code class="language-python">&gt;&gt;&gt; &quot;I eat %d apples.&quot; % 3
I eat 3 apples.</code></pre>
</li>
<li>결괏값을 보면 알겠지만, 위 예제는 문자열 안에 정수 3을 삽입하는 방법을 보여 준다.</li>
<li>문자열 안의 숫자를 넣고 싶은 자리에 %d 문자를 넣어 주고</li>
<li>삽입할 숫자 3은 가장 뒤에 있는 % 문자 다음에 써 넣었다.<ul>
<li>여기서 %d 는 &#39;문자열 포맷 코드&#39; 라고 부른다.</li>
</ul>
</li>
</ul>
<p><strong>2. 문자열 바로 대입</strong></p>
<pre><code class="language-python">&gt;&gt;&gt; &quot;I eat %s apples.&quot; %&quot;five&quot;
I eat five apples.</code></pre>
<ul>
<li>문자열 안에 또 다른 문자열을 삽입하기 위해 앞에서 사용한 문자열 포맷 코드 %d가 아닌 %s를 썻다.</li>
</ul>
<blockquote>
<p>앞에서 배운 것 처럼 문자열을 대입할 때는 반드시 큰따옴표나 작은따옴표를 써야 한다.</p>
</blockquote>
<p><strong>3. 숫자 값을 나타내는 변수로 대입</strong></p>
<pre><code class="language-python">&gt;&gt;&gt; number = 3
&gt;&gt;&gt; &quot;I eat %d apples.&quot; % number
I eat 3 apples.</code></pre>
<ul>
<li>1번처럼 숫자를 바로 대입하든, 위 예제처럼 숫자 값을 나타내는 변수를 대입하든 결과는 같다.</li>
</ul>
<p><strong>4.2개 이상의 값 넣기</strong></p>
<ul>
<li>문자열 안에 1개가 아닌 여러 개의 값을 넣고 싶을 때는 어떻게 해야 할까?<pre><code class="language-python">&gt;&gt;&gt; number = 10
&gt;&gt;&gt; day = &quot;three&quot;
&gt;&gt;&gt; I ate %d apples. so I was sick for %s days.: %(number, day)
I ate 10 apples. so I was sick for three days.</code></pre>
</li>
<li>두개 이상의 값을 넣으려면 마지막 % 다음 괄호 안에 쉼표(,)로 구분하여 각각 값을 넣어 주면 된다.<h4 id="ㅁ-문자열-포맷-코드">ㅁ 문자열 포맷 코드</h4>
<table>
<thead>
<tr>
<th>코드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>%s</td>
<td>문자열(String)</td>
</tr>
<tr>
<td>%c</td>
<td>문자 1개(character)</td>
</tr>
<tr>
<td>%d</td>
<td>정수(integer)</td>
</tr>
<tr>
<td>%f</td>
<td>부동소수(floating-point)</td>
</tr>
<tr>
<td>%o</td>
<td>8진수</td>
</tr>
<tr>
<td>%x</td>
<td>16진수</td>
</tr>
<tr>
<td>%%</td>
<td>Literal %(문자 % 자체)</td>
</tr>
</tbody></table>
</li>
</ul>
<h4 id="ㅁ-여기서-s-포맷-코드를-예제를-통해-살펴보자">ㅁ 여기서 %s 포맷 코드를 예제를 통해 살펴보자.</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;I have %s apples&quot; %3
I have 3 apples
&gt;&gt;&gt; &quot;rate is %s&quot; %3.234
rate is 3.234</code></pre>
<ul>
<li>3을 문자열 안에 삽입하려면 %d를 사용해야 하고 3.234를 삽입하려면 %f를 사용해야 한다.</li>
<li>하지만 %s를 사용하면 %s는 자동으로 % 뒤에 있는 3이나 3.234와 같은 값을 문자열로 바꾸어 대입하기 때문에 이런 것을 생각하지 않아도 된다.</li>
</ul>
<h4 id="ㅁ-포매팅-연산자-d와-를-같이-쓸-때는-를-쓴다">ㅁ 포매팅 연산자 %d와 %를 같이 쓸 때는 %%를 쓴다.</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;Error is %d%.&quot; %98</code></pre>
<ul>
<li>여기서 결과 값이 당연히 &#39;Error is 98%&#39; 라고 생각하겠지만, 파이썬은 &#39;형식이 불안전하다&#39;라는 오류 메시지를 보여 준다.</li>
<li>그 이유는 &#39;문자열 포맷 코드인 %d 와 %가 같은 문자열 안에 존재하는 경우, %를 나타내려면 반드시 %%를 써야 한다.</li>
<li>하지만, 문자열 안에 %d와 같은 포매팅 연산자가 없으면 %는 홀로 쓰여도 상관없다.</li>
<li>위 예제를 제대로 실행하려면 다음과 같이 작성해야 한다.<pre><code class="language-python">&gt;&gt;&gt; &quot;Error is %d%%.&quot; % 98
Error is 98%</code></pre>
<h3 id="ㅁ-포맷-코드와-숫자-함께-사용하기">ㅁ 포맷 코드와 숫자 함께 사용하기</h3>
<blockquote>
<p>앞에서 살펴보았듯이 %d,%s등과 같은 포맷 코드는 문자열 안에 어떤 값을 삽입할 때 사용한다.
하지만 포맷 코드를 숫자와 함께 사용하면 더 유용하다.</p>
</blockquote>
</li>
</ul>
<h4 id="1정렬과-공백">1.정렬과 공백</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;%10s&quot; % &quot;hi&quot;
        hi</code></pre>
<ul>
<li>%10s는 전체 길이가 10개인 문자열 공간에서 대입되는 값을 오른쪽으로 정렬하고 그 앞의 나머지는 공백으로 남겨 두라는 의미
<img src="https://velog.velcdn.com/images/pingu_9/post/adb82124-7742-4a75-bb45-dd9ddf60feaf/image.png" alt=""></li>
<li>그렇다면 반대쪽인 왼쪽 정렬은 %-10s 가 될 것이다.<pre><code class="language-python">&gt;&gt;&gt; &quot;%-10sjane.&quot; % &#39;hi&#39;
hi        jane.</code></pre>
<h4 id="2소수점-표현하기">2.소수점 표현하기</h4>
```python<blockquote>
<blockquote>
<blockquote>
<p>&quot;%0.4f&quot; % 3.42134234</p>
</blockquote>
</blockquote>
</blockquote>
</li>
</ul>
<p>3.4213</p>
<pre><code>- 3.42134234를 소수점 네번째 자리까지만 나타내고 싶은 경우에는 위와 같이 작성한다.
- %0.4f에서 &#39;.&#39;는 소수점 포인트, 그 뒤의 숫자 4는 소수점 뒤에 나올 숫자의 개수를 말함
- 소수점 포인트 앞의 숫자는 문자열 전체 길이를 의미하는데, 숫자 0은 길이에 상관하지 않겠다는 의미
- %0.4f는 0을 생략하여 %.4f 처럼 사용하기도 함
```python
&gt;&gt;&gt; &quot;%10.4f&quot; % 3.42134234
    3.4213</code></pre><p><img src="https://velog.velcdn.com/images/pingu_9/post/f331402c-dd27-46f4-919a-9db5ceaa5903/image.png" alt=""></p>
<h3 id="ㅁ-format-함수를-사용한-포매팅">ㅁ format 함수를 사용한 포매팅</h3>
<h4 id="ㅁ-숫자-바로-대입하기">ㅁ 숫자 바로 대입하기</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;I eat {0} apples&quot;.format(3)
I eat 3 apples</code></pre>
<ul>
<li>문자열 중 {0} 부분이 숫자 3으로 바뀌었다.<h4 id="ㅁ-문자열-바로-대입하기">ㅁ 문자열 바로 대입하기</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;I eat {0} apples&quot;.format(&quot;five&quot;)
I eat five apples</code></pre>
</li>
<li>문자열의 {0} 항목이 &quot;five&quot;라는 문자열로 바뀌었다.<h4 id="ㅁ숫자-값을-가진-변수로-대입하기">ㅁ숫자 값을 가진 변수로 대입하기</h4>
<pre><code class="language-python">&gt;&gt;&gt; number = 3
&gt;&gt;&gt; &quot;I eat {0} apples&quot;.format(number)
I eat 3 apples</code></pre>
</li>
<li>문자열의 {0} 항목이 number 변수의 값인 3으로 바뀌었다.<h4 id="ㅁ-2개-이상의-값-넣기">ㅁ 2개 이상의 값 넣기</h4>
<pre><code class="language-python">&gt;&gt;&gt; number = 10
&gt;&gt;&gt; day = &quot;three&quot;
&gt;&gt;&gt; &quot;I ate {0} apples. so I was sick for {1} days.&quot;.format(number, day)
I ate 10 apples. so I was sick for three days.</code></pre>
</li>
<li>2개 이상의 값을 넣을 경우, 문자열의 {0},{1}과 같은 인덱스 항목이 format 함수의 입력값으로 순서에 맞게 바뀐다.</li>
<li>위 예에서 {0}은 format 함수의 첫 번째 입력값인 number, {1}은 format 함수의 두 번째 입력값인 day로 바뀐다.<h4 id="ㅁ-이름으로-넣기">ㅁ 이름으로 넣기</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;I ate {number} apples. so I was sick for {day} days.&quot;.format(number=10, day=3)
I ate 10 apples. so I was sick for 3 days.</code></pre>
</li>
<li>{name} 형태를 사용할 경우, format 함수에는 반드시 name=value와 같은 형태의 입력값이 있어야 한다.<h4 id="ㅁ-인덱스와-이름을-혼용해서-넣기">ㅁ 인덱스와 이름을 혼용해서 넣기</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;I ate {0} apples. so I was sick for {day} days.&quot;.format(10, day=3)
I ate 10 apples. so I was sick for 3 days.</code></pre>
</li>
<li>인덱스 항목과 name=value 형태를 혼용하는 것도 가능하다.<h4 id="ㅁ-왼쪽-정렬">ㅁ 왼쪽 정렬</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;{0:&lt;10}&quot;.format(&quot;hi&quot;)
hi</code></pre>
</li>
<li>:&lt;10 표현식을 사용하면 치환되는 문자열을 왼쪽으로 정렬하고 문자열의 총 자릿수를 10으로 맞출 수 있다.<h4 id="ㅁ-오른쪽-정렬">ㅁ 오른쪽 정렬</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;{0:&gt;10}&quot;.format(&quot;hi&quot;)
      hi</code></pre>
</li>
<li>오른쪽 정렬은 :&lt; 대신 :&gt;을 사용하면 된다. (화살표의 방향을 생각면 됨!)<h4 id="ㅁ-가운데-정렬">ㅁ 가운데 정렬</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;{0:^10}&quot;.format(&quot;hi&quot;)
&#39;    hi    &#39;</code></pre>
</li>
<li>:^를 사용하면 가운데 정렬도 가능하다.<h4 id="ㅁ-공백-채우기">ㅁ 공백 채우기</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;{0:=^10}&quot;.format(&quot;hi&quot;)
&#39;====hi====&#39;
&gt;&gt;&gt; &quot;{0:!&lt;10}&quot;.format(&quot;hi&quot;)
&#39;hi!!!!!!!!&#39;</code></pre>
</li>
<li>정렬할 때 공백 문자 대신 지정한 문자 값으로 채워 넣을 수도 있다.</li>
<li>채워 넣을 문자 값은 정렬 문자 &lt;,&gt;,^ 바로 앞에 넣어야 한다.<h4 id="ㅁ-소수점-표현하기">ㅁ 소수점 표현하기</h4>
```python<blockquote>
<blockquote>
<blockquote>
<p>y = 3.42134234
&quot;{0:0.4f}&quot;.format(y)</p>
</blockquote>
</blockquote>
</blockquote>
</li>
</ul>
<p>3.4213</p>
<pre><code>- 위는 format 함수를 사용해 소수점을 4자리까지만 표현하는 방법을 보여 준다.
- 앞서 보았던 표현식 0.4f를 그대로 사용한 것을 알 수 있다.
```python
&gt;&gt;&gt; &quot;{0:10.4f}&quot;.format(y)
&#39;    3.4213&#39;</code></pre><ul>
<li><p>위와 같이 자릿수를 10으로 맞출 수도 있다.</p>
<h4 id="ㅁ-또는문자-표현하기">ㅁ {또는}문자 표현하기</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;{{ and }}&quot;.format()
{ and }</code></pre>
</li>
<li><p>format 함수를 사용해 문자열을 포매팅할 경우, {}와 같은 중괄호 문자를 포매팅 문자가 아닌 문자 그대로 사용하고 싶은 경우에 위 예의 {{}}처럼 2개를 연속해서 사용하면 된다.</p>
<h4 id="ㅁ-f-문자열-포매팅">ㅁ f 문자열 포매팅</h4>
<blockquote>
<p>파이썬 3.6버전부터는 f문자열 포매팅 기능을 사용할 수 있다. 파이썬 3.6 미만 버전에서는 사용할 수 없다.</p>
</blockquote>
</li>
<li><p>다음과 같이 문자열 앞에 f 접두사를 붙이면 f문자열 포매팅 기능을 사용할 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; name = &#39;홍길동&#39;
&gt;&gt;&gt; age = 30
&gt;&gt;&gt; f&#39;나의 이름은 {name}입니다. 나이는 {age}입니다.&#39;
나의 이름은 홍길동입니다. 나이는 30입니다.</code></pre>
</li>
<li><p>f 문자열 포매팅은 위와 같이 name, age와 같은 변숫값을 생성한 후에 그 값을 참조할 수 있다.</p>
</li>
<li><p>또 f 문자열 포매팅은 표현식을 지원하기 때문에 다음과 같은 것도 가능하다.</p>
<ul>
<li>표현식이란 중괄호 안의 변수를 계산식과 함께 사용하는 것을 말한다.<pre><code class="language-python">&gt;&gt;&gt; age = 30
&gt;&gt;&gt; f&#39;나는 내년이면 {age + 1}살이 된다.&#39;
나는 내년이면 31살이 된다.</code></pre>
</li>
</ul>
</li>
<li><p>딕셔너리는 f 문자열 포매팅에서 다음과 같이 사용할 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; d = {&#39;name&#39;:&#39;홍길동&#39;,&#39;age&#39;:30}
&gt;&gt;&gt; f&#39;나의 이름은 {d[&quot;name&quot;]}입니다. 나이는 {d[&quot;age&quot;]}입니다.&#39;
나의 이름은 홍길동입니다. 나이는 30입니다.</code></pre>
<blockquote>
<p>딕셔너리는 Key와 Value라는 것을 한 쌍으로 가지는 자료형이다.</p>
</blockquote>
</li>
<li><p>정렬은 다음과 같이 할 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; f&#39;{&quot;hi&quot;:&lt;10}&#39;  # 왼쪽 정렬
&#39;hi        &#39;
&gt;&gt;&gt; f&#39;{&quot;hi&quot;:&gt;10}&#39;  # 오른쪽 정렬
&#39;        hi&#39;
&gt;&gt;&gt; f&#39;{&quot;hi&quot;:^10}&#39;  # 가운데 정렬
&#39;    hi  </code></pre>
</li>
<li><p>공백 채우기는 다음과 같이 할 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; f&#39;{&quot;hi&quot;:=^10}&#39;  # 가운데 정렬하고 &#39;=&#39; 문자로 공백 채우기
&#39;====hi====&#39;
&gt;&gt;&gt; f&#39;{&quot;hi&quot;:!&lt;10}&#39;  # 왼쪽 정렬하고 &#39;!&#39; 문자로 공백 채우기
&#39;hi!!!!!!!!&#39;</code></pre>
</li>
<li><p>소수점은 다음과 같이 표현할 수 있다.</p>
<pre><code class="language-python">&gt;&gt;&gt; y = 3.42134234
&gt;&gt;&gt; f&#39;{y:0.4f}&#39;  # 소수점 4자리까지만 표현
&#39;3.4213&#39;
&gt;&gt;&gt; f&#39;{y:10.4f}&#39;  # 소수점 4자리까지 표현하고 총 자리수를 10으로 맞춤
&#39;    3.4213&#39;</code></pre>
</li>
<li><p>f 문자열에서 {}를 문자 그대로 표시하려면 다음과 같이 2개를 동시에 사용해야 한다.</p>
<pre><code class="language-python">&gt;&gt;&gt; f&#39;{{and}}&#39;
{and}</code></pre>
<h3 id="ㅁ-문자열-관련-함수들">ㅁ 문자열 관련 함수들</h3>
<blockquote>
<p>문자열 자료형은 자체적으로 함수를 가지고 있다.</p>
</blockquote>
</li>
<li><p>이들 함수를 다른 말로 &#39;문자열 내장 함수&#39;라고 한다.</p>
</li>
<li><p>이 내장 함수를 사용하려면 문자열 변수 이름 뒤에&#39;.&#39;를 붙인 후 함수 이름을 써 주면 된다.</p>
</li>
<li><p>이제 문자열 내장 함수에 대해 알아보자!</p>
</li>
</ul>
<h4 id="ㅁ-문자-개수-세기---count">ㅁ 문자 개수 세기 - count</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;hobby&quot;
&gt;&gt;&gt; a.count(&#39;b&#39;)
2</code></pre>
<ul>
<li>count 함수로 문자열 중 문자 b의 개수를 리턴했다.</li>
</ul>
<h4 id="ㅁ-위치-알려주기-1---find">ㅁ 위치 알려주기 1 - find</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Python is the best choice&quot;
&gt;&gt;&gt; a.find(&#39;b&#39;)
14
&gt;&gt;&gt; a.find(&#39;k&#39;)
-1</code></pre>
<ul>
<li>find 함수로 문자열 중 문자 b가 처음으로 나온 위치를 반환했다.</li>
<li>만약 찾는 문자나 문자열이 존재하지 않는다면 -1을 반환한다.<blockquote>
<p>파이썬은 숫자를 0부터 세기 때문에 b의 위치는 15가 아닌 14가 된다.</p>
</blockquote>
</li>
</ul>
<h4 id="ㅁ-위치-알려-주기-2---index">ㅁ 위치 알려 주기 2 - index</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Life is too short&quot;
&gt;&gt;&gt; a.index(&#39;t&#39;)
8
&gt;&gt;&gt; a.index(&#39;k&#39;)
Traceback (most recent call last):
File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
ValueError: substring not found</code></pre>
<ul>
<li>index 함수로 문자열 중 문자 t가 맨 처음으로 나온 위치를 반환했다.</li>
<li>만약 찾는 문자나 문자열이 존재하지 않는다면 오류가 발생한다.</li>
<li>앞서 find 함수와는 다른 점이 오류가 발생한다는 것이다.</li>
</ul>
<h4 id="ㅁ-문자열-삽입---join">ㅁ 문자열 삽입 - join</h4>
<pre><code class="language-python">&gt;&gt;&gt; &quot;,&quot;.join(&#39;abcd&#39;)
&#39;a,b,c,d&#39;</code></pre>
<ul>
<li>join 함수로 abcd 문자열의 각각의 문자 사이에 &#39;,&#39;를 삽입했다.</li>
<li>join 함수는 문자열뿐만 아니라 앞으로 배울 리스트나 튜플도 입력으로 사용할 수 있다.</li>
<li>join 함수의 입력으로 리스트를 사용하는 예는 다음과 같다.<pre><code class="language-python">&gt;&gt;&gt; &quot;,&quot;.join([&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;])
a,b,c,d</code></pre>
<h4 id="ㅁ-소문자를-대문자로-바꾸기--upper">ㅁ 소문자를 대문자로 바꾸기 -upper</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;hi&quot;
&gt;&gt;&gt; a.upper()
HI</code></pre>
</li>
<li>upper 함수는 소문자를 대문자로 바꾸어 준다. 만약 문자열이 이미 대문자라면 아무런 변화 X<h4 id="ㅁ-대문자를-소문자로-바꾸기---lower">ㅁ 대문자를 소문자로 바꾸기 - lower</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;HI&quot;
&gt;&gt;&gt; a.lower()
hi</code></pre>
</li>
<li>lower 함수는 대문자를 소문자로 바꾸어 준다.<h4 id="ㅁ-왼쪽-공백-지우기---lstrip">ㅁ 왼쪽 공백 지우기 - lstrip</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot; hi &quot;
&gt;&gt;&gt; a.lstrip()
&#39;hi &#39;</code></pre>
</li>
<li>lstrip 함수는 문자열 중 가장 왼쪽에 있는 한 칸 이상의 연속된 공백들을 모두 지운다.<h4 id="ㅁ-오른쪽-공백-지우기---rstrip">ㅁ 오른쪽 공백 지우기 - rstrip</h4>
<pre><code class="language-python">&gt;&gt;&gt; a= &quot; hi &quot;
&gt;&gt;&gt; a.rstrip()
&#39; hi&#39;</code></pre>
</li>
<li>rstrip 함수는 문자열 중 가장 오른쪽에 있는 한 칸 이상의 연속된 공백을 모두 지운다.<h4 id="ㅁ-양쪽-공백-지우기---strip">ㅁ 양쪽 공백 지우기 - strip</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot; hi &quot;
&gt;&gt;&gt; a.strip()
&#39;hi&#39;</code></pre>
</li>
<li>strip 함수는 문자열 양쪽에 있는 한 칸 이상의 공백을 모두 지운다.<h4 id="ㅁ-문자열-바꾸기---replace">ㅁ 문자열 바꾸기 - replace</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Life is too short&quot;
&gt;&gt;&gt; a.replace(&quot;Life&quot;, &quot;Your leg&quot;)
&#39;Your leg is too short&#39;</code></pre>
</li>
<li>replace 함수는 replace(바뀔_문자열, 바꿀_문자열)처럼 사용해서 문자열 안의 특정한 값을 다른 값으로 치환해 준다.<h4 id="ㅁ-문자열-나누기---split">ㅁ 문자열 나누기 - split</h4>
<pre><code class="language-python">&gt;&gt;&gt; a = &quot;Life is too short&quot;
&gt;&gt;&gt; a.split()
[&#39;Life&#39;, &#39;is&#39;, &#39;too&#39;, &#39;short&#39;]
&gt;&gt;&gt; b = &quot;a:b:c:d&quot;
&gt;&gt;&gt; b.split(&#39;:&#39;)
[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;]</code></pre>
</li>
<li>split 함수는 a.split() 처럼 괄호 안에 아무 값도 넣어 주지 않으면 공백([Space],[Tab],[Enter])을 기준으로 문자열을 나누어 준다.</li>
<li>b.split(&#39;:&#39;)처럼 괄호 안에 특정 값이 있을 경우에는 괄호 안의 값을 구분자로 해서 문자열을 나누어 준다.</li>
<li>이렇게 나눈 값은 리스트에 하나씩 들어간다.<ul>
<li>[&#39;Life&#39;, &#39;is&#39;, &#39;too&#39;, &#39;short&#39;]나 [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;]가 리스트이다.</li>
</ul>
</li>
</ul>
<h3 id="ㅁ-착각하기-쉬운-문자열-함수">ㅁ 착각하기 쉬운 문자열 함수</h3>
<ul>
<li>소문자를 대문자로 바꾸어 주는 다음의 예를 보자!<pre><code class="language-python">&gt;&gt;&gt; a = &#39;hi&#39;
&gt;&gt;&gt; a.upper()
&#39;HI&#39;</code></pre>
</li>
<li>이와 같이 실행한 후에 a 변수의 값은 &#39;HI&#39;로 변했을까? 아니면 &#39;hi&#39; 값을 유지할까?</li>
<li>확인해 보면 &#39;hi&#39;값을 유지한다.</li>
<li>upper()를 실행하면 upper 함수는 a변수의 값 자체를 변경하는 것이 아니라 대문자로 바꾼 값을 리턴하기 때문이다.</li>
<li>문자열은 위에서도 언급했지만 자체의 값을 변경할 수 없는 immutable 자료형이다.</li>
<li>따라서 a 값을 &#39;HI&#39;로 바꾸고 싶다면 다음과 같이 대입문을 사용해야 한다.<pre><code class="language-python">&gt;&gt;&gt; a = a.upper()
&gt;&gt;&gt; a
&#39;HI&#39;</code></pre>
<blockquote>
<p>upper 뿐만 아니라 lower, join, lstrip, rstrip, replace, split 함수는 모두 이와 같은 규칙이 적용되어  문자열 자체의 값이 변경되는 것이 아니라 변경된 값을 리턴한다는 사실에 주의하자</p>
</blockquote>
</li>
</ul>
<hr>
<hr>
<hr>
<h1 id="참고자료-및-출처">참고자료 및 출처</h1>
<h1 id="httpswikidocsnet13"><a href="https://wikidocs.net/13">https://wikidocs.net/13</a></h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[GitHub Repository Delete]]></title>
            <link>https://velog.io/@pingu_9/GitHub-Repository-Delete-cnngs4sa</link>
            <guid>https://velog.io/@pingu_9/GitHub-Repository-Delete-cnngs4sa</guid>
            <pubDate>Thu, 07 Nov 2024 13:31:09 GMT</pubDate>
            <description><![CDATA[<p>1.GitHub Home 화면에서 Repository 목록을 확인해 삭제하고 싶은 <code>Repository 를 선택</code>한다.
<img src="https://velog.velcdn.com/images/pingu_9/post/7c2e34ae-268e-4cce-9a01-9363b3ccc5d6/image.png" alt=""></p>
<hr>
<p>2.<code>Setting</code> Click!
<img src="https://velog.velcdn.com/images/pingu_9/post/a816bcd7-f0da-4a6f-8f35-0bcdf74fd0ac/image.png" alt=""></p>
<hr>
<p>3.Setting 화면 맨 아래 Danger Zone에서 <code>Delete this repository</code> 클릭 
<img src="https://velog.velcdn.com/images/pingu_9/post/af68a91d-9e49-45ac-b41b-662fef2998a2/image.png" alt=""></p>
<hr>
<p>4.<code>I want to delete this repository</code> Click!
<img src="https://velog.velcdn.com/images/pingu_9/post/631bc5df-418d-4125-8472-cd2e183e2629/image.png" alt=""></p>
<hr>
<p>5.<code>I have read and understand these effects</code> Click!
<img src="https://velog.velcdn.com/images/pingu_9/post/930db56d-6a39-48d2-b336-1824660ac6b4/image.png" alt=""></p>
<hr>
<p>6.아래 칸에 double quotation marks 안에 text 그대로 입력 후 <code>Delete this repository</code> Click
<img src="https://velog.velcdn.com/images/pingu_9/post/7a934c0b-4a92-4535-9a88-63a80f683142/image.png" alt=""></p>
<hr>
<p>7.Password 입력후 <code>Confirm</code> Click!
<img src="https://velog.velcdn.com/images/pingu_9/post/a77ce117-2350-4e01-a016-87ce70de9ee7/image.png" alt=""></p>
<hr>
<p>8.Home에서 보면 3개중 하나가 삭제된 것을 볼 수 있음
<img src="https://velog.velcdn.com/images/pingu_9/post/cbc434ea-06bf-4b7d-b6f6-7f3f857b3ee2/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Getting started with GitHub]]></title>
            <link>https://velog.io/@pingu_9/Getting-started-with-GitHub</link>
            <guid>https://velog.io/@pingu_9/Getting-started-with-GitHub</guid>
            <pubDate>Tue, 05 Nov 2024 10:40:59 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>Let&#39;s go over some <U>things to know</U> before starting with GitHub.
First, let&#39;s learn about SCM(Software Configuration Management).</strong></p>
</blockquote>
<h3 id="scmsoftware-configuration-management">SCM(Software Configuration Management)</h3>
<ul>
<li>Software Configuration Management (SCM) involves defining, controlling, and verifying changes to abstract management targets, such as functionality, performance, and constraints, and reporting these changes to relevant stakeholders.</li>
</ul>
<h3 id="the-purpose-of-scm">The purpose of SCM</h3>
<ul>
<li>The goal of SCM is to improve productivity and stability during project development, ensuring high-quality software production and easy maintenance.</li>
<li>SCM aims to reduce the overall cost of software development and to ensure that various obstacles in the development process are minimized. </li>
<li>Additionally, it provides answers to questions such as who made changes, what was changed, when it was changed, and why the changes were made.</li>
</ul>
<hr>
<h4 id="references">References</h4>
<p><a href="https://devyihyun.tistory.com/20">https://devyihyun.tistory.com/20</a>
<a href="https://sujinnaljin.medium.com/software-engineering-%ED%98%95%EC%83%81-%EA%B4%80%EB%A6%AC%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC-932d14f6f341">https://sujinnaljin.medium.com/software-engineering-%ED%98%95%EC%83%81-%EA%B4%80%EB%A6%AC%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC-932d14f6f341</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[침해대응 & CERT(Googling)-2주차]]></title>
            <link>https://velog.io/@pingu_9/%EC%B9%A8%ED%95%B4%EB%8C%80%EC%9D%91-CERTGoogling</link>
            <guid>https://velog.io/@pingu_9/%EC%B9%A8%ED%95%B4%EB%8C%80%EC%9D%91-CERTGoogling</guid>
            <pubDate>Sat, 28 Sep 2024 06:19:57 GMT</pubDate>
            <description><![CDATA[<h2 id="google-hacking">Google hacking</h2>
<ul>
<li><strong>구글 해킹(Google hacking)은</strong> 웹 사이트가 사용하는 구성과 컴퓨터 코드에 보안 구멍을 찾기 위해 Google 검색 및 기타 Google 응용 프로그램을 사용하는 컴퓨터 해킹 기술이다.<ul>
<li>공격자는 개인정보 등 손쉽게 취약점을 찾을 수 있다.</li>
<li><strong>구글해킹의 구글봇(웹 크롤러)이</strong> 수집하는 데이터를 서버에 캐시상태로 저장하기 때문에, 해당 사이트가 삭제되거나 한 후에도 오랜 시간이 지나기 전엔 검색결과에 노출되기 때문에 이전 페이지가 그대로 노출 될 수 있으며, 이 데이터를 모으면 손쉽게 취약점을 찾을 수 있다.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="키워드">키워드</h2>
<h3 id="1-검색어--→-ex-보안관제">1. “검색어“  → ex) “보안관제”</h3>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/01f79c87-3663-4e0d-941d-42920383d87d/image.png" alt=""></p>
<ul>
<li>큰따옴표 안에 검색어를 반드시 포함한 결과만 찾는다.</li>
</ul>
<hr>
<h3 id="2-intitle검색어--→-ex-intitle보안관제">2. intitle:검색어  → ex) intitle:보안관제</h3>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/f91b3f8d-6b26-4f05-b395-194d3ba88027/image.png" alt=""></p>
<ul>
<li>페이지 제목(title tag)에 특정 검색어가 포함된 페이즈를 찾는다.</li>
</ul>
<hr>
<h3 id="3-inurl검색어--→-ex-inurl보안관제">3. Inurl:검색어  → ex) inurl:보안관제</h3>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/c5d98610-bb2f-48e2-ae75-01c6ad47f69f/image.png" alt=""></p>
<ul>
<li>페이지 URL에 검색어가 포함된 페이지를 검색하는 연산자</li>
</ul>
<hr>
<h3 id="4-intext검색어--→-ex-intext보안관제">4. Intext:검색어  → ex) intext:보안관제</h3>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/de36ac55-01ae-4916-b764-03dc4688d931/image.png" alt=""></p>
<ul>
<li>본문에 검색어가 포함되는 페이지를 찾는다.</li>
</ul>
<hr>
<h3 id="5-site검색어--→-ex-sitevelogiopingu_9">5. site:검색어  → ex) site:velog.io/@pingu_9</h3>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/7af6762d-63f5-48a4-8025-b2121913c718/image.png" alt=""></p>
<ul>
<li>해당 웹사이트에 대한 결과만 보여준다.</li>
</ul>
<hr>
<h3 id="6-filetype확장자-→-ex-filetypepdf--extpdf">6. filetype:확장자 → ex) filetype:pdf = ext:pdf</h3>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/48e2e110-8a35-4d89-8cfc-9c5dbbface6f/image.png" alt=""></p>
<ul>
<li>해당 파일 확장자가 있는 것을 찾는 명령어이다.(.ext:로 대체가능)</li>
</ul>
<hr>
<h2 id="구글-검색의-취약점">구글 검색의 취약점</h2>
<h3 id="디렉토리-리스팅directory-listing">디렉토리 리스팅(Directory listing)</h3>
<h4 id="ex-intitleindexof-password">Ex) intitle:index.of “password”</h4>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/e26f2575-982c-41d7-99fd-e8d757950993/image.png" alt=""></p>
<ul>
<li><p>index.of 는 디렉토리 리스팅 취약점이 있는 웹사이트를 방문하면 볼 수 있는 문자열로, 웹 서버의 특정 경로에 있는 파일들을 웹 서비스를 통해 디렉토리 형식으로 볼 수 있는 취약점이다.</p>
</li>
<li><p>이 취약점이 노출될 경우 웹 서버의 디렉토리 안에 들어있는 여러 파일들의 소스 코드가 고스란히 노출되고  ,웹 서버에 저장되어 있는 데이터들을 아무 제한 없이 다운로드 받을 수도 있고 버전 확인도 가능하다.</p>
</li>
<li><p>소스 코드를 분석하여 웹 서버의 구조를 파악하고 웹 서버의 민감한 데이터 등을 탈취하는 작업이 가능해지기 때문에 현재 대부분의 웹 서버에서는 보안 설정 상 디렉토리 목록 검색을 허용하고 있지 않다.</p>
</li>
</ul>
<hr>
<h3 id="2-관리자-페이지-노출-ex-inurladmin-intitlelogin">2. 관리자 페이지 노출 Ex) inurl:admin intitle:login</h3>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/803158d6-0863-48a2-8a13-f1261d462bcc/image.png" alt=""></p>
<ul>
<li>이 페이지들을 통해서 서버의 버전 등을 포함한 정보 등을 확인할 수 있다.</li>
<li>관리자 페이지의 경우 sql injection이나 XSS를 통해서 서버의 계정 정보를 취득하거나 서버의 로컬 권한을 획득하는 데 사용될 위험이 있다.</li>
</ul>
<hr>
<h4 id="대응-방안">대응 방안</h4>
<ul>
<li>Robots.txt 설정: 크롤러가 민감한 경로에 접근하지 못하도록 제한.</li>
<li>서버 보안 강화: 디렉터리 리스팅 비활성화, 관리자 페이지 접근 제한.</li>
<li>웹 애플리케이션 방화벽(WAF) 적용: SQL injection 및 XSS와 같은 공격을 방어.</li>
<li>정기적 보안 점검: 취약점 스캐닝 및 보안 업데이트.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[침해사고대응팀-CERT]]></title>
            <link>https://velog.io/@pingu_9/CERT</link>
            <guid>https://velog.io/@pingu_9/CERT</guid>
            <pubDate>Fri, 30 Aug 2024 14:12:49 GMT</pubDate>
            <description><![CDATA[<h2 id="침해사고대응팀cert란">침해사고대응팀(CERT)란?</h2>
<blockquote>
<p>CERT : Computer Emergency Response Team</p>
</blockquote>
<ul>
<li>주로 사이버 보안 사고를 예방하는 업무를 진행 </li>
<li>보안 사고가 발생하였을 때 해당 사고에 대한 원인과 피해 규모를 신속하게 파악하여 대책을 수립</li>
<li>최종적으로는 피해를 최소화 시키는 업무를 수행하는 직무</li>
</ul>
<hr>
<h2 id="cert의-업무-및-특징">CERT의 업무 및 특징</h2>
<h3 id="cert의-업무">CERT의 업무</h3>
<ul>
<li>보안 사고 예방을 위한 활동을 한다.</li>
<li>사고 발생 시 해당 사고에 대한 원인과 피해 규모 분석을 실시한다.</li>
<li>해당 사고에 대한 대책을 수립한다.</li>
<li>피해를 최소화 시키기 위한 다양한 활동을 한다.</li>
<li>유사 공격 등 사고를 방지하기 위한 활동을 한다.
CERT의 특징<h3 id="cert의-특징">CERT의 특징</h3>
</li>
<li>대부분의 대기업이나 정부 기관은 자체적으로 CERT 팀을 구성하여 내부 보안 사고에 대응한다.  </li>
<li>전문 보안 업체가 여러 기관이나 기업을 대상으로 보안 서비스를 제공해 줄 수 있다.</li>
<li>보안 위협과 취약점에 대한 정보를 조직이나 대중과 공유한다.</li>
</ul>
<hr>
<h2 id="cert의-업무-절차-및-특징">CERT의 업무 절차 및 특징</h2>
<p><img src="https://velog.velcdn.com/images/pingu_9/post/d2ddbdef-7a31-4410-b218-dd9a0b79856c/image.png" alt=""></p>
<h4 id="출저--kisa--침해사고-분석절차-안내서">출저 : KISA : 침해사고 분석절차 안내서</h4>
<ul>
<li>사고 전 준비(예방) 부터 복구,해결까지 7단계의 절차로 분석 절차가 진행된다.</li>
<li>1~7까지의 절차 완료 후 다시 1번의 예방부터 시작하는 반복 사이클이다.</li>
<li>해당 절차는 보안관제 업무 절차와 비슷하다.</li>
</ul>
<hr>
<h3 id="1사고-전-준비">1.사고 전 준비</h3>
<ul>
<li>침해사고 발생 전 침해사고 대응팀과 조직적인 대응을 준비하는 단계이다.</li>
<li>사고를 어떻게 대응할 것인지에 대한 체제와 대응 팀에 대해 준비한다.</li>
<li>효율적인 사고 대응을 위한 전략과 대처 방안을 개발하며</li>
<li>전문가 조직을 구성하고 시스템/네트워크 관리자와 긴밀한 협조 관계를 구성한다. <h3 id="2-사고-탐지">2. 사고 탐지</h3>
<img src="https://velog.velcdn.com/images/pingu_9/post/fb898c2d-282e-4a15-85d0-1d5ee41ea10a/image.png" alt=""></li>
<li>정보보호 시스템(IPS/IDS등) 및 네트워크 장비에 의한 이상징후를 탐지하는 단계이다.</li>
<li>사고를 탐지하는 부분은 IDS, 관리자, 보안관제, 인사부 등이 존재한다</li>
<li>관리자에 의해 침해사고를 식별하기도 한다<h3 id="3-초기-대응">3. 초기 대응</h3>
</li>
<li>초기 조사를 수행하는 단계</li>
<li>사고 정황에 대한 세부사항을 기록한다.</li>
<li>침해사고 대응팀을 소집 / 네트워크와 시스템 정보를 수집한다</li>
<li>침해사고 관련 부서(기관)에 침해사고 발생 여부를 통지한다.<h3 id="4-대응-전략-체계화">4. 대응 전략 체계화</h3>
</li>
<li>대응 전략 수립 단계</li>
<li>초기대응 단계에서 확인한 정보를 이용해 대응한다.</li>
<li>공격 환경, 대응 능력 등을 고려해 대응 전략을 수립한다.</li>
<li>대응 방법에 따라 조직의 업무의 영향이 미칠수 있으므로 해당부분을 고려해야 하며, 상위 관리자가 승인해야 한다.
<img src="https://velog.velcdn.com/images/pingu_9/post/71052cd6-938e-4ee6-87b4-4edfa4f1bfcc/image.png" alt=""><blockquote>
<p>다음 표와 같은 사고 예시와 그에 맞는 대응 전략이 존재</p>
</blockquote>
</li>
</ul>
<h3 id="5-사고-조사">5. 사고 조사</h3>
<ul>
<li>호스트 기반/ 네트워크 기반 /기타 기반 증거로 나누어 조사를 실시한다.</li>
<li>데이터 수집의 단계로 공격 시작부터 종료까지 어떤 공격이 이루어 졌는지를 조사한다.</li>
<li>피해 확산 및 사고 재발의 방안을 결정한다.
<img src="https://velog.velcdn.com/images/pingu_9/post/d815bb7a-bd5a-4e9b-bc65-5898ea3746ff/image.png" alt=""><blockquote>
<p>데이터 수집 단계에서 수집한 정보는 호스트 기반 정보 / 네트워크 기반 정보 / 일반 정보 3가지로 분리되어 집니다.
데이터 분석 단계에서는 포렌식 이미징 작업부터 모든 수집된 정보를 기반으로 데이터 준비 과정을 거쳐 데이터 분석으로 전체적인 조사과정을 수행합니다.</p>
</blockquote>
<h3 id="6-보고서-작성">6. 보고서 작성</h3>
</li>
<li>2~5단계 까지의 데이터를 추합해 보고서를 작성하는 단계</li>
<li>수집한 데이터의 분석을 하여 육하원칙(왜, 언제, 어디서, 누가, 무엇을, 어떻게)에 따라 보고서를 작성한다.<h3 id="7-복구-및-해결-과정">7. 복구 및 해결 과정</h3>
</li>
<li>공격 이후 유사 공격을 예방하기 위한 보안 정책의 수립, 절차 변경을 진행한다.</li>
<li>침해사고 재발 방지를 위한 조치를 하며 대책을 수립한다.</li>
</ul>
<hr>
<h4 id="참고">참고</h4>
<blockquote>
<p><a href="https://blog.naver.com/PostView.nhn?blogId=hanajava&amp;logNo=222114434472">https://blog.naver.com/PostView.nhn?blogId=hanajava&amp;logNo=222114434472</a>
<a href="https://maker5587.tistory.com/26">https://maker5587.tistory.com/26</a>
<a href="https://velog.io">https://velog.io</a>
KISA : 침해사고 분석절차 안내서</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>