0x00 Introduction
In Getting started with the C language, we all know a common sense: the memory that is dynamically requested via malloc () is released via Free (), and what happens if the heap memory is freed after the program is improperly designed. This seems like a stupid operation, but double free is a very common binary vulnerability in modern software.
I will use an example to illustrate the possible hazards of double free. This example was once a 0CTF game. CTF competition It is one of the better ways to get started safely by simply demonstrating common computer vulnerabilities and popularizing security technology to participants.
Program Address: Https://github.com/ctfs/write-ups-2015/tree/master/0ctf-2015/exploit/freenote
Environment: Ubuntu 16.04 x86_64
Tools: Ida, Pwntools, pwndbg
After the reverse, the restored code is as follows, if you do not want to see all can first notice the dotted line bug (reversed by @ Love stunned Sakura):
#include <stdio.h> #include <stdlib.h> #include <unistd.h> typedef struct NOTE {Long int flag;//
Existence note long int length;//The length of the note contents Char *content;//note contents}
typedef struct NOTES {long int max;
long int length;
Note NOTES256[256];
} notes;
Notes *base;
void Allocate_space () {base = (Notes *) malloc (sizeof (notes));
for (int i = 0; i < 256 i++) {base->notes256[i].flag = 0;
base->notes256[i].length = 0;
Base->notes256[i].content = NULL;
an int read_choice () {int choice;
Puts ("= = 0ops Free = ="); Puts ("1").
List note "); Puts ("2").
New note "); Puts ("3").
Edit note "); Puts ("4").
Delete note "); Puts ("5").
Exit ");
Puts ("====================");
printf ("Your choice:");
scanf ("%d", &choice);
return choice;
void list () {for (int i = 0;; i++) {if (I >= 256) {break;
} if (Base->notes256[i].flag = = 1) { printf ("%d.%s\n", I, base->notes256[i].content);
}} void Read_content (char *temp, int str_len) {int i;
int read_num;
for (i = 0; i < str_len i + = read_num) {read_num = Read (0, (void *) (temp + i), str_len-i);
if (read_num <= 0) {break;
}} void New_note () {int str_len;//string length char *temp;
void *str;
if (Base->length < Base->max) {for (int i = 0;; i++) {if (I >= Base->max) {
Break
} if (!base->notes256[i].flag) {printf ("Length of New Note:");
scanf ("%d", &str_len);
if (Str_len > 0) {if (Str_len > 4096) {str_len = 4096;
printf ("Enter Your Note:");
temp = (char *) malloc ((128-str_len% 128)% 128 + Str_len); Read_content (temp, str_len);
Base->notes256[i].flag = 1;
Base->notes256[i].length = Str_len;
Base->notes256[i].content = temp;
base->length++;
Puts ("done.");
Break
}} void Edit_note () {printf ("Note number:");
int num;
scanf ("%d", &num);
int length;
scanf ("%d", &length); if (length!=base->notes256[num].length) {Base->notes256[num].content=realloc (Base->notes256[num].
Content, (128-length% 128)% 128 + length);
base->notes256[num].length=length;
printf ("Enter Your Note:");
Read_content (base->notes256[num].content,length);
Puts ("done.");
} void Delete_note () {int index;
printf ("Note number:");
scanf ("%d", &index);
base->length--;
Base->notes256[index].flag = 0; base->notes256[index].length = 0;
* *------------------------------------------------------------------/*--------------------------bug is here---
------------------------*/Free (base->notes256[index].content); /*-------------------------------------------------------------------*/
/*--------------------------------------
-----------------------------* * * puts ("done.");
int main () {allocate_space ();
Base->max = 256;
while (1) {switch (Read_choice ()) {case 1:list ();
Break
Case 2:new_note ();
Break
Case 3:edit_note ();
Break
Case 4:delete_note ();
Break
Case 5:puts ("Bye");
return 0;
Default:puts ("invalid!");
Break
}
}
}
Can see in
Free (base->notes256[index].content);
After that, the pointer is not empty and a double free vulnerability can be created again in the subsequent execution flow. This problem does not occur if the assignment is null, and freeing the null pointer is a safe behavior.
and noted that in
Base->notes256[i].content
The address of the NOTE0 string is fixed, and, of course, it needs to know its address when using the pointer. Then, by triggering double free, change the place where the NOTE0 string address is stored, overwrite the got table and change the program execution flow.
The following is a detailed implementation process.
0x01 Info Leak
According to the source code you can see that there is an omission in the list function that can cause data to be leaked from the uninitialized heap if
The leak address requires two chunk to prevent merging of two, so add 4 note first.