<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>a_dawn.log</title>
        <link>https://velog.io/</link>
        <description>https://adawn0106.tistory.com/ &lt;- 이쪽으로 옮겨요! / EN blog: https://adawn0106.github.io/</description>
        <lastBuildDate>Fri, 16 Aug 2024 09:26:15 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>a_dawn.log</title>
            <url>https://velog.velcdn.com/images/a_dawn/profile/87887412-46e7-4dd7-97d8-13770251df73/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. a_dawn.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/a_dawn" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[addition-quiz]]></title>
            <link>https://velog.io/@a_dawn/addition-quiz</link>
            <guid>https://velog.io/@a_dawn/addition-quiz</guid>
            <pubDate>Fri, 16 Aug 2024 09:26:15 GMT</pubDate>
            <description><![CDATA[<h1 id="addition-quiz">addition-quiz</h1>
<p><img src="https://velog.velcdn.com/images/a_dawn/post/654937d5-8459-4630-8377-f26add94cb21/image.png" alt=""></p>
<p>문제 주소: <a href="https://dreamhack.io/wargame/challenges/1114">https://dreamhack.io/wargame/challenges/1114</a></p>
<p>Dreamhack의 새싹 난이도의 misc 문제이다.
<br></p>
<h2 id="문제">문제</h2>
<br>


<p>문제는 다음과 같다.</p>
<blockquote>
<p>랜덤한 2개의 숫자를 더한 결과가 입력 값과 일치하는지 확인하는 과정을 50번 반복하는 프로그램입니다. 모두 일치하면 flag 파일에 있는 플래그를 출력합니다. 알맞은 값을 입력하여 플래그를 획득하세요.
플래그 형식은 DH{...} 입니다.</p>
</blockquote>
<br>

<h2 id="분석">분석</h2>
<br>

<p>먼저 프로그램을 원격 접속해보면 다음화면처럼 뜬다. 
<br></p>
<p><img src="https://velog.velcdn.com/images/a_dawn/post/1e271258-ca95-46a2-b738-f983ed11a8d9/image.png" alt=""></p>
<p>랜덤한 두개의 숫자를 합한 값을 구하고 빠른 시간 안에 답변하지 않으면 프로그램이 닫히는 걸 알 수 있다.
문제 파일을 다운로드 받아 열어보면 아래 소스코드를 확인할 수 있다. 
쉽게 이해 할 수 있도록 주석을 추가하였다.</p>
<pre><code>// Name: chall.c
// Compile Option: gcc chall.c -o chall -fno-stack-protector

#include &lt;stdio.h&gt;
#include &lt;signal.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;unistd.h&gt;
#include &lt;time.h&gt;

#define FLAG_SIZE 0x45

void alarm_handler() { //alarm(1)에 의해 signal을 거친후 alarm_handler가 호출되는데 화면에 TIME OUT을 출력하고 프로그램을 종료함.
    puts(&quot;TIME OUT&quot;);
    exit(1);
}

void initialize() {  //비버퍼링 모드로 전환하여 사용자와 상호작용을 더 빠르게 해줌
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    signal(SIGALRM, alarm_handler); // signal(SIGALRM, alarm_handler);은 특정신호에 대해 alarm_handler를 호출하는 역할을 함
}

int main(void) {
    int fd;
    char *flag;

    initialize();
    srand(time(NULL)); 

    flag = (char *)malloc(FLAG_SIZE); // flag라는 값을 FLAG_SIZE만큼 동적으로 할당하고 flag 파일을 읽기 전용으로 읽어와서 FLAG_SIZE만큼 flag 변수에 저장함.
    fd = open(&quot;./flag&quot;, O_RDONLY);
    read(fd, flag, FLAG_SIZE);
    close(fd);

    int num1 = 0;
    int num2 = 0;
    int inpt = 0; 

    for (int i = 0; i &lt; 50; i++){
        alarm(1); //1초후 alarm이 실행되며 SIGALRM으로 신호가 전달되어 alarm_handler의 내용을 실행함.

        num1 = rand() % 10000; //num1과 num2 랜덤한 값으로 생성
        num2 = rand() % 10000;
        printf(&quot;%d+%d=?\n&quot;, num1, num2);
        scanf(&quot;%d&quot;, &amp;inpt);

        if(inpt != num1 + num2){ //사용자에게 inpt값을 받아와서 num1+num2값과 비교하고 만약 틀리면 Wrong을 반환하고 틀릴 경우 종료 , 맞을 경우 for문을 탈출할 시 nice를 띄우며 flag를 출력해준다.
            printf(&quot;Wrong...\n&quot;);
            return 0;
        }
    } 

    puts(&quot;Nice!&quot;);
    puts(flag);

    return 0;
}</code></pre><p>문제와 프로그램 실행 결과,소스코드를 참고해봤을 떄 결론은 프로그램에서 띄워주는 랜덤한 2개의 값을 더해서 프로그램으로 반환하는 일을 50번하면 flag을 얻을 수 있다라는 것이다.
<br></p>
<p>홈페이지의 hint를 보면 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/a_dawn/post/81992d1f-e9ba-47a5-8c28-08d063ee7217/image.png" alt=""></p>
<p>pwntools를 사용하라는 걸 알 수 있는데 pwntools는 간단하게 시스템 해킹에 주로 사용하는 Python 모듈이다. </p>
<p>프로그램이 1초라는 시간 안에 답을 입력하지 않으면 닫히기 떄문에 pwntools를 이용하여 해결하고자 한다. </p>
<h2 id="exploit">Exploit</h2>
<BR>

<p>Full Exploit은 다음과 같다. </p>
<pre><code>from pwn import * //pwntools를 사용

p = remote(&#39; host3.dreamhack.games&#39;,14299) // 본인의 포트를 입력



for i in range(50): //아래 내용을 50번 반복
    number = p.recvuntil(b&#39;=&#39;)
    numbers = number.split(b&#39;+&#39;)
    number1 = int(numbers[0])
    number2 = int(numbers[1].split(b&#39;=&#39;)[0])

    p.recvline()
    p.sendline(str(number1 + number2))

p.interactive()</code></pre><h2 id="exploit-분석">Exploit 분석</h2>
<br>
해당 코드를 분석해보면 다음과 같다.
<br>

<p>p = remote(&#39; host3.dreamhack.games&#39;,14299)는(&#39;호스트&#39;,포트) 형태로 입력하면 되는데 해당 호스트에 해당 포트로 원격 접속한다는 의미이다.  이해를 돕기 위해 예를 들어 설명하겠다.
 <br>
 예를 들어 </p>
<blockquote>
<p> 1234 + 5678 = ? </p>
</blockquote>
<p> 가 출력되었다고 가정해보자 
 <br></p>
<p>  number = p.recvuntil(b&#39;=&#39;)는 =까지의 내용을 받아오는 코드인데  위의 예시를 들면 1234 + 5678 = 까지 가져온다.
  그럼 현재 number에 1234 + 5678 = 가 저장되어 있는 상태이다.
  <br></p>
<p>  numbers = number.split(b&#39;+&#39;) 같은 경우엔 number의 값이 split(b&#39;+&#39;)를 기준으로 나뉘어져 저장되는데 이는 리스트 형태로 저장되게 된다. </p>
<p>  numbers = [b&#39;1234&#39;, b&#39;5678=&#39;]</p>
<p>  number1 = int(numbers[0])는 numbers[0]인 b&#39;1234&#39;를 number1에 int형으로 저장하고 
  number2 = int(numbers[1].split(b&#39;=&#39;)[0])는 numbers[1]인 b&#39;5678=&#39;를 b&#39;=&#39;을 기준으로 나눠 그중 0번 인덱스 즉 b&#39;5678&#39;을 number2에 int형으로 저장한다는 의미이다. 
  <br>
  이렇게 되면 number1에는 int형 1234 , number2에는 int형 5678이 저장되게 되는데 
  revuntil()은 괄호안의 값까지 읽어오는 역할을 하는데 우리는 b&#39;=&#39;까지 읽어왔었기 떄문에 
  전체문장이 1234 + 5678 = ? \n 이지만 1234 + 5678 = 만 읽어온 것이다. 
  <br>
  그럼 그 뒷부분을 마저 실행해줘야 다음으로 넘어가기 떄문에 p.recvline() 를 사용하여 넘어가준다.
   이후 p.sendline(str(number1 + number2))을 이용하여 number1과 number2를 합한 값을 프로그램에 전달해준다. 
   <br>
   이 과정들을 for문을 통해 50번 실행하고 끝나게 되면 
   p.interactive()를 통해 결과값 확인 및 쉘을 얻을 수 있다. </p>
<p>   <img src="https://velog.velcdn.com/images/a_dawn/post/65efea88-04ea-4dd7-9776-3f8490e58228/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[rev-basic-5]]></title>
            <link>https://velog.io/@a_dawn/rev-basic-5</link>
            <guid>https://velog.io/@a_dawn/rev-basic-5</guid>
            <pubDate>Thu, 15 Aug 2024 13:05:24 GMT</pubDate>
            <description><![CDATA[<h1 id="reversing-basic-challenge-5">Reversing Basic Challenge #5</h1>
<p><img src="https://velog.velcdn.com/images/a_dawn/post/bdf775ba-04b6-4d51-8762-72ba2fbbbef7/image.png" alt=""></p>
<p>문제 주소:<a href="https://dreamhack.io/wargame/challenges/19">https://dreamhack.io/wargame/challenges/19</a></p>
<p>Dreamhack의 2단계 난이도의 리버싱 문제이다. </p>
<h2 id="문제">문제</h2>
<br>
문제는 다음과 같다.



<blockquote>
<p>이 문제는 사용자에게 문자열 입력을 받아 정해진 방법으로 입력값을 검증하여 correct 또는 wrong을 출력하는 프로그램이 주어집니다.
해당 바이너리를 분석하여 correct를 출력하는 입력값을 찾으세요!
획득한 입력값은 DH{} 포맷에 넣어서 인증해주세요.
예시) 입력 값이 Apple_Banana일 경우 flag는 DH{Apple_Banana}</p>
</blockquote>
<h2 id="분석">분석</h2>
<br>

<p>문제 파일을 다운 받아서 실행시켜 보면 다음 화면처럼 뜬다. </p>
<p><img src="https://velog.velcdn.com/images/a_dawn/post/9056ee2b-845c-409c-9670-e098ecf5cb52/image.png" alt=""></p>
<p>아무거나 입력하게 되면 wrong을 출력하게 된다.</p>
<p><img src="https://velog.velcdn.com/images/a_dawn/post/2e60f0c1-4749-4231-b198-8ccc905abcb1/image.png" alt=""></p>
<p>해당 프로그램이 어떤 구조로 되어있는지 알아보기 위해 ida로 실행시켜 봤다.</p>
<p><img src="https://velog.velcdn.com/images/a_dawn/post/f29d263b-c976-4344-94bd-014e90cf70fa/image.png" alt=""></p>
<p>문제 설명과 같이 입력값을 검증하여 wrong이나 correct를 출력해주는 것을 볼 수 있다.
해당 부분을 ida의 pseuedo code로 보게 되면 다음 화면처럼 뜨는 걸 확인 할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/a_dawn/post/d3f1ee3c-be23-4905-9903-9b2aeaec5003/image.png" alt=""></p>
<p>main 함수를 살펴보면 사용자로부터 Input을 받아 V4에 저장하고 if문의 결과에 따라 correct나 wrong을 출력하고 있다. </p>
<p>if문의 조건문은 다음과 같다.</p>
<p><img src="https://velog.velcdn.com/images/a_dawn/post/753422d8-4ee8-42b1-9810-e7d610ab1774/image.png" alt=""></p>
<p>해당 함수는 인자를 v4로 받아왔기 때문에 a1 = v4라는 것을 알 수 있고 
for문이 실행되는 동안 * (a1+i+1) + * (a1+i) = byte_140003000[i] 가 일치한다면 true를 그렇지 않다면 false를 반환하는 것을 알 수 있다.
<br>
예를 들어 사용자가 Input에 1234를 넣었다면 i가 0일때 </p>
<p>v4 = a1 = 123456</p>
<p>*(a1+ i) + *(a1 + i + 1) = byte_140003000[0]</p>
<p> 12 + 34 = byte_140003000[0] 을 구하면 된다는 이야기이다.</p>
<p> 왜냐하면 a1의 다음 +1 바이트 값은 34 , 다음 +2 바이트 값은 56이 되기 때문이다.</p>
<p>문제를 풀기 위해선 byte_140003000의 값을 알아야 한다. 
<br></p>
<p>byte_140003000의 값은 다음과 같다.
<br></p>
<p><img src="https://velog.velcdn.com/images/a_dawn/post/85e4d167-90ff-468c-acb6-425b9e5c8112/image.png" alt=""></p>
<p>제일 앞에 있는 값인 0ADh는 0xAD를 이야기 한다. 
2 dup(0CBh)는 0xCB가 2번 연속 있다는 것을 의미한다. </p>
<p>결국 우리가 찾아야 하는 값은 i 가 0이라고 가정하면 *(a1) + *(a1 + 1) = byte_140003000[0]   (0xAD)를 찾아야 한다.</p>
<p>위의 for문이 0x18 (24) 까지 반복되므로 24바이트 만큼 검사한다는 것을 알 수 있다.</p>
<p>주어진 byte_140003000을 24번쨰까지 계산해보면 22번쨰에 0x4c , 23번쨰에 0x00인걸 알 수 있다. 
이걸 식에 대입해보면
<br></p>
<p>i가 22일때 *(a1 + 22) + *(a1+22+1) = 0x4c </p>
<p>i가 23일때 *(a1 +23) + *(a1+23+1) = 0x00 </p>
<p>즉 </p>
<p>i가 22일때 *(a1+22) + *(a1+23) = 0x4c</p>
<p>i가 23일때 *(a1+23) + *(a1+24) = 0x00 
이므로 </p>
<p>x + y = 0x4c
y + z = 0x00
<br></p>
<p>다시 생각해보면 char v4[256]이므로 그렇다는 건 입력값이 문자형이라는 것이고 아스키코드에는 음수 값은 존재하지 않는다.
그러므로 y &gt;= 0 , z &gt;= 0 인데 만약 y나z가 0보다 크게 되버리면 y+z = 0x00 이 성립되지 않는다. 
결국 y = 0 , z = 0 이라는 소리이고 y가 0이 되었기 때문에 x = 0x4c가 된다. 
22번째 바이트는 0x4c , 23번째는 0x00 이런식으로 0번째까지 계산해 나가면 0번 인덱스부터 차례대로 
<br>
41 6c 6c 5f 6c 31 66 65 6c 33 6e 64 73 5f 77 31 74 68 5f 4e 55 4c 4c 00 
<br>
이 나오게 되는데 마찬가지로 문자형이였기 떄문에 cyberchef에서 From hex로 읽어들이면<img src="https://velog.velcdn.com/images/a_dawn/post/ec876f81-060f-4af7-acdb-ad3e022e91d5/image.png" alt=""></p>
<p>해당 문자열이 나오게 되는데 이 문자열을 프로그램에 입력하게 되면 <img src="https://velog.velcdn.com/images/a_dawn/post/c2241c19-9013-424b-b3b3-43bf5d429eb3/image.png" alt=""></p>
<p>Correct가 뜨는 걸 확인 할 수 있다.</p>
<p>원래는 생각나는대로 손으로 풀어서 exploit 작성을 안했었지만 공부 겸 exploit을 작성하여 추가하였다.</p>
<h2 id="exploit">Exploit</h2>
<br>

<p>Full exploit은 다음과 같다.
<br></p>
<pre><code>#include &lt;stdio.h&gt;

int main(void) {

    int arr[24] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,0 };  // 우리가 찾는 값
    int arr2[24] = { 173,216,203,203,157,151,203,196,146,161,
                     210,215,210,214,168,165,220,199,173,163,
                     161,152,76,0 }; //byte140003000의 decimal 

    for (int i = 0; i &lt;23; i++) {
        arr[22-i] = arr2[22-i] - arr[22 - i + 1];
    }

    for (int i = 0; i &lt; 23; i++) {
        printf(&quot;%c&quot;, arr[i]); //decimal을 문자형으로 출력
    }


    return 0;
}</code></pre>]]></description>
        </item>
    </channel>
</rss>