Attack Lab - Level 5 explained
Ning Wang has published a very good write-up (2022 update: web page is gone now) on his solutions to the Attack Lab from the CS:APP book. However, I thought his solution to Level 5 could do with a bit more elaboration for those who are struggling with this topic.
First, it is necessary to understand what ROP requires. An essential component of ROP is good luck, lots of it. Without getting lucky, you may take more than 10100 years to find a workable attack, if at all. This, the authors of CS:APP did not mention. I also could not comprehend the purpose this exercise is even given out as homework in CMU to be completed in a week (while there are tons of homework from other courses too), without an intensive course in Intel Assembler as a prerequisite.
Level 5 requires the same general logic as Level 3, which can be summarized as (pseudo code):
To achieve the above for Level 5, the next level of elaboration would be:
With ROP, you then try your luck searching for code fragments to achieve Step 2 above. It would be sensible to start "bottom up", ie work first from the last instruction (the one just before RETQ to touch3).
ROP requires finding fragments (I don't know why the lab calls it gadgets) that suit your purpose. You are at the mercy of what lucky sequences of bytes in the target program (or machine) can do. Sometimes a fragment may contain additional code that you don't want or need, but this can be ignored if those instructions do not destroy any of your data.
In the simplest form, each code fragment has to contain a RETQ instruction somewhere in it. The RETQ instruction will pop the stack and jump to the popped value. By lining up the addresses of such code fragments (gadgets) adjacent to one after another on the stack, execution will then flow from one fragment (gadget) to the next, and the last one will pass control, in a similar manner, to the function touch3.
Looking at Ning's solution, after
The solution by Ning uses the following logic (view this side-by-side with his annotated exploit string):
Note that what is not shown in Ning's comments is that every gadget ends with a RETQ instruction (opcode C3).
First, it is necessary to understand what ROP requires. An essential component of ROP is good luck, lots of it. Without getting lucky, you may take more than 10100 years to find a workable attack, if at all. This, the authors of CS:APP did not mention. I also could not comprehend the purpose this exercise is even given out as homework in CMU to be completed in a week (while there are tons of homework from other courses too), without an intensive course in Intel Assembler as a prerequisite.
Level 5 requires the same general logic as Level 3, which can be summarized as (pseudo code):
mov <cookiestring address>, %rdi //why? because touch3 is expecting it there
call touch3
To achieve the above for Level 5, the next level of elaboration would be:
- Put your cookie string somewhere on the stack, and note its (relative) position.
- Craft code to:
- Save the value of the stack pointer,
%rsp
, and determine the offset of the cookie string address from this run-time value of%rsp
. - Add the offset to the saved value of
%rsp
- Transfer this sum to the register
%rdi
. - Jump to touch3.
With ROP, you then try your luck searching for code fragments to achieve Step 2 above. It would be sensible to start "bottom up", ie work first from the last instruction (the one just before RETQ to touch3).
ROP requires finding fragments (I don't know why the lab calls it gadgets) that suit your purpose. You are at the mercy of what lucky sequences of bytes in the target program (or machine) can do. Sometimes a fragment may contain additional code that you don't want or need, but this can be ignored if those instructions do not destroy any of your data.
In the simplest form, each code fragment has to contain a RETQ instruction somewhere in it. The RETQ instruction will pop the stack and jump to the popped value. By lining up the addresses of such code fragments (gadgets) adjacent to one after another on the stack, execution will then flow from one fragment (gadget) to the next, and the last one will pass control, in a similar manner, to the function touch3.
Looking at Ning's solution, after
getbuf()
is called and the longer than expected exploit string is entered, control is passed to the sixth line in his exploit string. Sixth because the first five lines (totaling 40 bytes) are the actual string expected for the variable buf
(see page 3 of the lab handout). (For CMU students, BUFFER_SIZE is different so you have to adjust for this but adding or removing padding bytes.) The eight bytes on the sixth line (06 1a 40 00 00 00 00 00) obliterate the originally value on the stack, which previously contains the return address, ie the address of the line following the code that called getbuf()
. These six bytes now point to the address of Gadget 1. The rest of the exploit string that follows also overwrites the stack, into the parent's stack frame - a dangerous stunt indeed.The solution by Ning uses the following logic (view this side-by-side with his annotated exploit string):
Note that what is not shown in Ning's comments is that every gadget ends with a RETQ instruction (opcode C3).
I hope you now have a better idea of how the Level 5 exploit works. |
Comments