Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On amd64-linux, read('eax', ...) wipes out the contents of eax before using it as fd #2481

Open
Russ741 opened this issue Oct 3, 2024 · 2 comments

Comments

@Russ741
Copy link

Russ741 commented Oct 3, 2024

Reproduced with the pwntools/pwntools:stable container.

Code to reproduce:

from pwn import *

context.update(arch='amd64', os='linux')

sh = shellcraft.read('eax', '0x006030c0', 0x1000)
print(sh)

eax gets overwritten before it gets read:

    /* call read('eax', '0x006030c0', 0x1000) */
    xor eax, eax /* SYS_read */
    mov edi, eax
    xor edx, edx
    mov dh, 0x1000 >> 8
    mov esi, 0x1010101 /* (0x006030c0) == 0x6030c0 */
    xor esi, 0x16131c1
    syscall

If we use rax instead, it works as expected:

/* call read('rax', '0x006030c0', 0x1000) */
    mov rdi, rax
    xor eax, eax /* SYS_read */
    xor edx, edx
    mov dh, 0x1000 >> 8
    mov esi, 0x1010101 /* (0x006030c0) == 0x6030c0 */
    xor esi, 0x16131c1
    syscall

Granted, in my use case rax was probably the correct register to use, but it was annoying to figure that out anyways.

@peace-maker
Copy link
Member

#1046 might be related

@peace-maker
Copy link
Member

Ah, no it's because of a rogue read shellcode wrapper on amd64. Removing that file fixes your issue, since the generated syscall wrapper handles arguments first before generating the syscall instruction, doing the right thing by accident. You can get your code to work by using sh = shellcraft.syscalls.read('eax', '0x006030c0', 0x1000).

The real problem is regsort not considering at the register mapping:

def regsort(in_out, all_regs, tmp = None, xchg = True, randomize = None):

i386_ordered = [
['rax', 'eax', 'ax', 'al'],
['rbx', 'ebx', 'bx', 'bl'],
['rcx', 'ecx', 'cx', 'cl'],
['rdx', 'edx', 'dx', 'dl'],
['rdi', 'edi', 'di'],
['rsi', 'esi', 'si'],
['rbp', 'ebp', 'bp'],
['rsp', 'esp', 'sp'],
['r8', 'r8d', 'r8w', 'r8b'],
['r9', 'r9d', 'r9w', 'r9b'],
['r10', 'r10d', 'r10w', 'r10b'],
['r11', 'r11d', 'r11w', 'r11b'],
['r12', 'r12d', 'r12w', 'r12b'],
['r13', 'r13d', 'r13w', 'r13b'],
['r14', 'r14d', 'r14w', 'r14b'],
['r15', 'r15d', 'r15w', 'r15b']
]
all_regs, sizes, bigger, smaller = register_sizes(i386_ordered, [64, 32, 16, 8, 8])
native64 = {k:v[0] for k,v in bigger.items()}
native32 = {k:v[1] for k,v in bigger.items() if not k.startswith('r')}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants