{"id":40,"date":"2024-05-13T21:05:00","date_gmt":"2024-05-13T11:05:00","guid":{"rendered":"https:\/\/davidshoon.com\/?p=40"},"modified":"2026-10-20T09:50:59","modified_gmt":"2026-10-19T22:50:59","slug":"hacking-101-stack-buffer-overflows-on-x86_64","status":"publish","type":"post","link":"https:\/\/davidshoon.com\/?p=40","title":{"rendered":"Hacking 101 &#8211; stack buffer overflows on x86_64"},"content":{"rendered":"<h1 style=\"text-align: left\">Hacking 101 &#8211; stack buffer overflows on x86_64<\/h1>\n<p>I won&#8217;t explain in too much detail, but the following code creates a buffer overflow that controls the return instruction pointer on the stack, changing the flow of the code into calling func2().<br \/><span style=\"font-family: courier\"><br \/>\/*<\/p>\n<p>&nbsp;&nbsp; &nbsp;compile: gcc test.c -fno-stack-protector<br \/>&nbsp;&nbsp; &nbsp;run: .\/a.out 4 (or .\/a.out 2&#8230; greater than .\/a.out 1)<\/p>\n<p>*\/<\/p>\n<p>#include &lt;stdio.h&gt;<br \/>#include &lt;stdlib.h&gt;<br \/>#include &lt;string.h&gt;<\/p>\n<p>\/\/#define USE_CANARY<\/p>\n<p>void func2()<br \/>{<br \/>&nbsp;&nbsp; &nbsp;printf(&#8220;I did it!n&#8221;);<br \/>}<\/p>\n<p>void func(const char *input)<br \/>{<br \/>#ifdef USE_CANARY<br \/>&nbsp;&nbsp; &nbsp;long int canary = 0xdeadbeefc001d00d;<br \/>#endif<br \/>&nbsp;&nbsp; &nbsp;char buf[256];<\/p>\n<p>\/\/&nbsp;&nbsp;&nbsp; strcpy(buf, input);<br \/>\/\/ cause there&#8217;s a null in the address&#8230;<\/p>\n<p>&nbsp;&nbsp; &nbsp;memcpy(buf, input, 256+8*8);<br \/>&nbsp;&nbsp; &nbsp;\/\/ buffer overfl0wwwwwwwwwww<\/p>\n<p>&nbsp;&nbsp; &nbsp;printf(&#8220;buf: %sn&#8221;, buf);<br \/>&nbsp;&nbsp; &nbsp;fflush(stdout);<\/p>\n<p>#ifdef USE_CANARY<br \/>&nbsp;&nbsp; &nbsp;if (canary != 0xdeadbeefc001d00d) {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; printf(&#8220;Buffer overflow detected! Aborting!n&#8221;);<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; abort();<br \/>&nbsp;&nbsp; &nbsp;}<br \/>#endif<br \/>}<\/p>\n<p>int main(int argc, char **argv)<br \/>{<br \/>&nbsp;&nbsp; &nbsp;<br \/>&nbsp;&nbsp; &nbsp;char input[1024];<br \/>&nbsp;&nbsp; &nbsp;int loop;<\/p>\n<p>&nbsp;&nbsp; &nbsp;\/\/ fill up input with &#8216;A&#8217; x 256 (leaving 1024-256 bytes left)<br \/>&nbsp;&nbsp; &nbsp;memset(input, &#8216;A&#8217;, 256);<\/p>\n<p>&nbsp;&nbsp; &nbsp;printf(&#8220;size of func2&#8217;s pointer (in bytes): %ldn&#8221;, sizeof(&amp;func2));<br \/>&nbsp;&nbsp; &nbsp;printf(&#8220;func2&#8217;s address: %lxn&#8221;, (unsigned long) func2);<\/p>\n<p>&nbsp;&nbsp; &nbsp;if (argc &lt; 2) {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; loop = 4;<br \/>&nbsp;&nbsp; &nbsp;}<\/p>\n<p>&nbsp;&nbsp; &nbsp;else {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; loop = atoi(argv[1]);<br \/>&nbsp;&nbsp; &nbsp;}<\/p>\n<p>&nbsp;&nbsp; &nbsp;\/\/ fill past the &#8216;A&#8217;s with a pointer to func2(), up to &#8220;loop&#8221;.<br \/>&nbsp;&nbsp; &nbsp;for (int i = 0; i &lt; loop; i++) {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; unsigned long *p = (unsigned long *) (input + 256 + i * sizeof(&amp;func2));<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; *p = (unsigned long) func2;<br \/>&nbsp;&nbsp; &nbsp;}<\/p>\n<p>&nbsp;&nbsp; &nbsp;printf(&#8220;input: %sn&#8221;, input);<\/p>\n<p>&nbsp;&nbsp; &nbsp;\/\/ verify the func2&#8217;s addresses are actually inside the input buffer.<\/p>\n<p>&nbsp;&nbsp; &nbsp;for (int i = 0; i &lt; loop; i++) {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; char *p = input + 256 + i * sizeof(&amp;func2);<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; unsigned long *q = (unsigned long *) p;<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; printf(&#8220;address: %lxn&#8221;, *q);<br \/>&nbsp;&nbsp; &nbsp;}<\/p>\n<p>&nbsp;&nbsp; &nbsp;\/\/ call func with input buffer.<\/p>\n<p>&nbsp;&nbsp; &nbsp;func(input);<br \/>}<br \/><\/span><\/p>\n<p>Output:<\/p>\n<p><span style=\"font-family: courier\"><br \/>gcc test.c -fno-stack-protector<\/p>\n<p>$ .\/a.out<\/p>\n<p>size of func2&#8217;s pointer (in bytes): 8<br \/>func2&#8217;s address: 561e883a51e9<br \/>input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ufffdQ:\ufffdV<br \/>address: 561e883a51e9<br \/>address: 561e883a51e9<br \/>address: 561e883a51e9<br \/>address: 561e883a51e9<br \/>buf: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\ufffdQ:\ufffdV<br \/>I did it!<br \/>I did it!<br \/>I did it!<br \/>Segmentation fault (core dumped)<\/span><\/p>\n<h2 style=\"text-align: left\">Creating our own Canary<\/h2>\n<p>Notice if you compiled with -DUSE_CANARY, it uses our artificial canary, and will abort before the overflow exploits the return instruction pointer.<\/p>\n<p><span style=\"font-family: courier\">gcc test.c -fno-stack-protector -DUSE_CANARY<br \/>$ .\/a.out<\/p>\n<p>size of func2&#8217;s pointer (in bytes): 8<br \/>func2&#8217;s address: 562a98ea0209<br \/>input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&nbsp;&nbsp;&nbsp; \ufffd*V<br \/>address: 562a98ea0209<br \/>address: 562a98ea0209<br \/>address: 562a98ea0209<br \/>address: 562a98ea0209<br \/>buf: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&nbsp;&nbsp;&nbsp; \ufffd*V<br \/>Buffer overflow detected! Aborting!<br \/>Aborted (core dumped)<br \/><\/span><\/p>\n<h2 style=\"text-align: left\">Comparing with gcc&#8217;s canary<br \/><\/h2>\n<p>Now if you look at a normal compilation, and check out the assembly using `objdump -D .\/a.out`<br \/><span style=\"font-family: courier\"><br \/>0000000000001223 &lt;func&gt;:<br \/>&nbsp;&nbsp;&nbsp; 1223:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f3 0f 1e fa&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; endbr64 <br \/>&nbsp;&nbsp;&nbsp; 1227:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp; %rbp<br \/>&nbsp;&nbsp;&nbsp; 1228:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48 89 e5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; %rsp,%rbp<br \/>&nbsp;&nbsp;&nbsp; 122b:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48 81 ec 20 01 00 00&nbsp;&nbsp;&nbsp; sub&nbsp;&nbsp;&nbsp; $0x120,%rsp<br \/>&nbsp;&nbsp;&nbsp; 1232:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48 89 bd e8 fe ff ff&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; %rdi,-0x118(%rbp)<br \/>&nbsp;&nbsp;&nbsp; 1239:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 64 48 8b 04 25 28 00&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; %fs:0x28,%rax<br \/>&nbsp;&nbsp;&nbsp; 1240:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00 00 <br \/>&nbsp;&nbsp;&nbsp; 1242:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48 89 45 f8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; %rax,-0x8(%rbp)<br \/>&nbsp;&nbsp;&nbsp; 1246:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 31 c0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xor&nbsp;&nbsp;&nbsp; %eax,%eax<\/p>\n<p>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &#8230;. more opcodes &#8230;.<\/p>\n<p>&nbsp;&nbsp; &nbsp;&#8230; followed at the end by &#8230;<\/p>\n<p>&nbsp;&nbsp;&nbsp; 12a4:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e8 17 fe ff ff&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; call&nbsp;&nbsp; 10c0 &lt;__stack_chk_fail@plt&gt;<br \/>&nbsp;&nbsp;&nbsp; 12a9:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; leave &nbsp;<br \/>&nbsp;&nbsp;&nbsp; 12aa:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret&nbsp;&nbsp; &nbsp;<\/p>\n<p><\/span><br class=\"Apple-interchange-newline\" \/><br \/>This is the setting of the canary and the checking of the canary at the end of the function, done by the compiler.<\/p>\n<p>The objdump without stack protector for func is:<\/p>\n<p><span style=\"font-family: courier\">&lt;func&gt;:<br \/>&nbsp;&nbsp;&nbsp; 1203:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; f3 0f 1e fa&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; endbr64 <br \/>&nbsp;&nbsp;&nbsp; 1207:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp; %rbp<br \/>&nbsp;&nbsp;&nbsp; 1208:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48 89 e5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; %rsp,%rbp<br \/>&nbsp;&nbsp;&nbsp; 120b:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48 81 ec 10 01 00 00&nbsp;&nbsp;&nbsp; sub&nbsp;&nbsp;&nbsp; $0x110,%rsp<br \/>&nbsp;&nbsp;&nbsp; 1212:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 48 89 bd f8 fe ff ff&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp; %rdi,-0x108(%rbp)<br \/><\/span><\/p>\n<p>You can see the canary&#8217;s secret value is stored in %fs:0x28, and gets moved to register %rax, which then gets copied onto the frame pointer %rbp &#8211; 8 bytes, which is just before the saved frame pointer, and two pointers from the return instruction pointer on the stack.<\/p>\n<p>If you can leak the %fs:0x28 value, you can overwrite the canary with the same value during the overflow, and thus bypass the canary check.<\/p>\n<p>This is the reason why %rax is cleared (xor %rax, %rax), to avoid leaking the value in the %rax register.<\/p>\n<h2 style=\"text-align: left\">Getting the canary secret value from gcc via some means, and then using it<\/h2>\n<p>Source code follows:<\/p>\n<p><span style=\"font-family: courier\"><\/p>\n<p>\/*<\/p>\n<p>&nbsp;&nbsp; &nbsp;compile: gcc test.c -fno-stack-protector<br \/>&nbsp;&nbsp; &nbsp;run: .\/a.out 4 (or .\/a.out 2&#8230; greater than .\/a.out 1)<\/p>\n<p>*\/<\/p>\n<p>#include &lt;stdio.h&gt;<br \/>#include &lt;stdlib.h&gt;<br \/>#include &lt;string.h&gt;<\/p>\n<p>\/\/#define USE_CANARY<\/p>\n<p>unsigned long get_canary()<br \/>{<br \/>&nbsp;&nbsp; &nbsp;asm(&#8220;mov %fs:0x28, %rax&#8221;);<br \/>}<\/p>\n<p>void func2()<br \/>{<br \/>&nbsp;&nbsp; &nbsp;printf(&#8220;I did it!n&#8221;);<br \/>}<\/p>\n<p>void func(const char *input)<br \/>{<br \/>#ifdef USE_CANARY<br \/>&nbsp;&nbsp; &nbsp;long int canary = 0xdeadbeefc001d00d;<br \/>#endif<br \/>&nbsp;&nbsp; &nbsp;char buf[256];<\/p>\n<p>\/\/&nbsp;&nbsp;&nbsp; strcpy(buf, input);<br \/>\/\/ cause there&#8217;s a null in the address&#8230;<\/p>\n<p>&nbsp;&nbsp; &nbsp;memcpy(buf, input, 256+8*8);<br \/>&nbsp;&nbsp; &nbsp;\/\/ buffer overfl0wwwwwwwwwww<\/p>\n<p>&nbsp;&nbsp; &nbsp;printf(&#8220;buf: %sn&#8221;, buf);<br \/>&nbsp;&nbsp; &nbsp;fflush(stdout);<\/p>\n<p>#ifdef USE_CANARY<br \/>&nbsp;&nbsp; &nbsp;if (canary != 0xdeadbeefc001d00d) {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; printf(&#8220;Buffer overflow detected! Aborting!n&#8221;);<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; abort();<br \/>&nbsp;&nbsp; &nbsp;}<br \/>#endif<br \/>}<\/p>\n<p>int main(int argc, char **argv)<br \/>{<br \/>&nbsp;&nbsp; &nbsp;<br \/>&nbsp;&nbsp; &nbsp;char input[1024];<br \/>&nbsp;&nbsp; &nbsp;int loop;<\/p>\n<p>&nbsp;&nbsp; &nbsp;\/\/ fill up input with &#8216;A&#8217; x 256 (leaving 1024-256 bytes left)<br \/>&nbsp;&nbsp; &nbsp;memset(input, &#8216;A&#8217;, 256);<\/p>\n<p>&nbsp;&nbsp; &nbsp;printf(&#8220;size of func2&#8217;s pointer (in bytes): %ldn&#8221;, sizeof(&amp;func2));<br \/>&nbsp;&nbsp; &nbsp;printf(&#8220;func2&#8217;s address: %lxn&#8221;, (unsigned long) func2);<\/p>\n<p>&nbsp;&nbsp; &nbsp;if (argc &lt; 2) {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; loop = 2; \/\/ loop = 2 is the optimal solution for this case.<br \/>&nbsp;&nbsp; &nbsp;}<\/p>\n<p>&nbsp;&nbsp; &nbsp;else {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; loop = atoi(argv[1]);<br \/>&nbsp;&nbsp; &nbsp;}<\/p>\n<p>&nbsp;&nbsp; &nbsp;unsigned long gcc_canary = get_canary(); \/\/ get gcc canary secret value.<\/p>\n<p>&nbsp;&nbsp; &nbsp;\/\/ After the &#8216;AAAA&#8217; put a gcc_canary for us. The space gcc will provide will be 16 bytes, so we just fill <br \/>&nbsp;&nbsp; &nbsp;\/\/ it up with 2x canary secret values. (assuming loop = 2)<\/p>\n<p>&nbsp;&nbsp; &nbsp;for (int i = 0; i &lt; loop; i++) {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; unsigned long *p = (unsigned long *) (input + 256 + i * sizeof(&amp;func2));<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; *p = (unsigned long) gcc_canary;<br \/>&nbsp;&nbsp; &nbsp;}<\/p>\n<p>&nbsp;&nbsp; &nbsp;\/\/ Now put a pointer to func2(), at least twice (assuming loop = 2).<\/p>\n<p>&nbsp;&nbsp; &nbsp;for (int i = loop; i &lt; loop * 2; i++) {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; unsigned long *p = (unsigned long *) (input + 256 + i * sizeof(&amp;func2));<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; *p = (unsigned long) func2;<br \/>&nbsp;&nbsp; &nbsp;}<\/p>\n<p>&nbsp;&nbsp; &nbsp;printf(&#8220;input: %sn&#8221;, input);<\/p>\n<p>&nbsp;&nbsp; &nbsp;\/\/ verify the func2&#8217;s addresses are actually inside the input buffer.<\/p>\n<p>&nbsp;&nbsp;&nbsp; for (int i = 0; i &lt; loop * 2; i++) {<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; char *p = input + 256 + i * sizeof(&amp;func2);<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; unsigned long *q = (unsigned long *) p;<br \/>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; printf(&#8220;address or canary: %lxn&#8221;, *q);<br \/>&nbsp;&nbsp; &nbsp;}<\/p>\n<p>&nbsp;&nbsp; &nbsp;\/\/ call func with input buffer.<\/p>\n<p>&nbsp;&nbsp; &nbsp;func(input);<br \/>}<br \/><\/span><\/p>\n<p>Output:<span style=\"font-family: courier\"><\/span><\/p>\n<p><span style=\"font-family: courier\"><br \/>gcc test.c<br \/>$ .\/a.out<\/p>\n<p>size of func2&#8217;s pointer (in bytes): 8<br \/>func2&#8217;s address: 55ad7774c21d<br \/>input: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<br \/>address or canary: ac9d07067ff30500<br \/>address or canary: ac9d07067ff30500<br \/>address or canary: 55ad7774c21d<br \/>address or canary: 55ad7774c21d<br \/>buf: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<br \/>I did it!<br \/>Segmentation fault (core dumped)<\/p>\n<p><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hacking 101 &#8211; stack buffer overflows on x86_64 I won&#8217;t explain in too much detail, but the following code creates a buffer overflow that controls the return instruction pointer on the stack, changing the flow of the code into calling func2().\/* &nbsp;&nbsp; &nbsp;compile: gcc test.c -fno-stack-protector&nbsp;&nbsp; &nbsp;run: .\/a.out 4 (or .\/a.out 2&#8230; greater than .\/a.out [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-40","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/davidshoon.com\/index.php?rest_route=\/wp\/v2\/posts\/40","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/davidshoon.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/davidshoon.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/davidshoon.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/davidshoon.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=40"}],"version-history":[{"count":1,"href":"https:\/\/davidshoon.com\/index.php?rest_route=\/wp\/v2\/posts\/40\/revisions"}],"predecessor-version":[{"id":41,"href":"https:\/\/davidshoon.com\/index.php?rest_route=\/wp\/v2\/posts\/40\/revisions\/41"}],"wp:attachment":[{"href":"https:\/\/davidshoon.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=40"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/davidshoon.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=40"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/davidshoon.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=40"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}