6 - Whitehorse
The basic idea is the same of Cusco, we still have the same buffer overflow, but this time the function unlock_door is not present, so we have to create it: what that function did was simply to call INT passing on the stack the value 0x7f. We forge our input as follows:call INT (4 bytes) + 12 rand bytes + address of the beginning of the input + 0x7f00
How does this work? When the last ret is executed, the address of the beginning of the input will be poped from the stack so SP will point to 0x7f00 (007f in little endian), the PC will be set to the value that was just poped, meaning that we jump to our call instruction. Now everything is set: we have our 0x7f on the stack and we are about to call INT
7 - Montevideo
Identical to the previous one, the only difference is that instead of directly writing the input on the stack, it is first read into a variable, then copied into the stack and finally the the variable is set to all 0s. As no check on the length of the input is performed, the previous solution still holds8 - Johannesburg
Finally a "check" for too long inputs. What happens is that after checking if the password is correct, it compares the 18th byte of the input with 0x76, if it is different it prints the error message, otherwise it goes on adding 18 to SP and performing a return. Our simple solution is to provide 17 random bytes, then 0x76 and finally our return address, that is the address of unlock_door9 - Santa Cruz
In this version we are asked both a username and password. Reversing a bit the login function we can see that the program puts on the stack the values 8 and 16 and then it checks if the length of the password is between them, after that it calls the interrupt to check the password and if it is wrong it checks if the byte 17 of the password is 0x00, if it is it performs a regular return; this is of course the point that we want to reach because is where we can somehow overwrite the return address. As no check on the username is performed, we try a very long one and we can see that it overwrites the values against which the length of the password is is compared, in particular they are the bytes 17 and 18 respectively, so setting them to 0x01 and 0x99 allows us to bypass any check on the password length. Still we cannot use the password to overwrite the return address, because we are forced to put byte 17 == 0, so all following bytes are not copied in the stack by the previous strcpy. Putting an even longer username we see that it actually overwrites the return address we want, so we can put there the unlock_door address:
username = 17 rand bytes + 0x01 + 0x99 + 22 rand bytes + return addr
password = 17 rand bytes + 0x00
10 - Jakarta
This time the concatenation of username and password should be less than 32 bytes. Lets see how the program controls this:- 45AE check that the username is less than 33 bytes long, if it is copy it in the stack
- 45C8 max length of the password to be read = (31 - username_length) & 0x1ff
- 4600 compute the length of the password, if pass_length+username_length < 33 copy the password in the stack after the username
Note that a space of 34 bytes in the stack is given for
username+password, so to perform our usual return address overwrite we
need to find a way to feed longer inputs.
To do this we use two bugs:
- if we write a username of more than 31 bytes we bypass the control over the maximum password length, so username_length = 32 => max pass length = 0x1ff if we do the math
- pass_length+username_length is stored in a register of 16 bits, but the check is performed only on the LSB, so if we use a password that is, for example, 256 bytes long, pass_length+username_length = 256 + 32 = 284 = 0x0120, LSB = 0x20 = 32 < 33
No comments:
Post a Comment