Exercise 1 (7 pts) ========== Q1. (3pts) - for function f1 (on the left), when printing sthe attacker may get access to potentially confiden tial data located in the execution stack (beyond buf), like return adresses or stack frame adresses, or even other data owned by the other calling functions of f when calling f1 with a string s larger than L elements. - for function f2 (on the right), the attacker may overwrite the buffer used to store s. If this buffer is located (itself) on the stak it could lead to arbitrary code execution (rewritting some return address), or potentially breakg data integrity (in the stack or in the heap) Q2. (4pts) The stack protector option detects consecutive write accesses to the stack beyond the canary inserted above the return address. This is not sufficient to protect against read accesses from the stack. f2 is therefore still vulnerable (while f1 is not). A solution to protect f2 could be to insert some extra checks in the code, either manualy, or using for instance tools like Address Sanitizers. Exercise 2 ========== Q1 (3 pts) When foo() terminates its return value (the local variable x, located in the stack) points to its local variable a, also located in the stack, those value is 42. This return value is then assigned to p, which therefore also points to the stack. Function bar() re-uses part of the stack frame freed by foo(), and, when it terminates, the stack location pointed by p is then assigned with 0. Hence *p equals 0 when printf() is called ... Q2. (2 pts) This code pattern may potentially lead to some information disclosure, assuming for instance that bar assigns some confidential data (like a password) to its local variable buf. This is "stack-based" use-after-free. Q3. (2 pts) At compile time a compiler could check that the return value of a function f is not the address of some of its local variable (which is not supposed to exist any more when f terminates). A similar check could be performed at runtime, or, alternatively, when a function terminates its whole stack frame could be "cleaned" (set to 0) in order to remove any sensitive data. Exercise 3 ========== Q1. (4pts) The constraints for building the content of s are the following: - the return address of foo() should be overwritten by SC address - it should not contain any 0x00 byte (apart at the end) - SC should be located withint its 40 first bytes (minimal value for L) - its lenght should be at most 308 bytes (in order to reach the return address of foo) We could also (safely) assume that the return address of foo is located in the stack at an address which is a multiple of 8 (whatever is L) Therefore: - to avoid 0x00 bytes we should not put SC at the very beginning of s - to cope with the variable value of L (from 40 to 300) we should repeat SC address inside s to make sure to overwrite the return address of foo() - to overwrite the return address of foo() whatever is L, the total length of s should be 300+8+8 A possible solution is therefore the following: s = "AAAAAA" + + "AA" + 37*0xFFDEAD06 where 0xFFDEAD06 is the address of SC (starting at index 6 of buf). Q2. (2pts) If the stack is not executable this attack will not work any more (since SC is located in the stack). A possible alternative could be to encode SC using a ROP chain ...