execve() argv в ассемблере GAS AT

#assembly #x86-64 #system-calls #shellcode #execve

#сборка #x86-64 #системные вызовы #шелл-код #execve

Вопрос:

Мой код:

 .section .data
name: .string "/bin/sh"
args:
        .string "-c"
        .string "ls"

.section .text
.globl _start
_start:
        pushq $0
        pushq name

        movq $59, %rax
        movq %rsp, %rdi

        pushq $0
        pushq args

        movq %rsp, %rsi
        movq $0, %rdx

        syscall
  

Я знаю, что вторым аргументом execve является массив символов.

Как это сделать в сборке, чтобы избежать этого:

 execve("./payload", ["./payload"], 0x7ffc291fd160 /* 40 vars */) = 0
execve("/bin/sh", [0x736c00632d], NULL) = -1 EFAULT (Bad address)
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xfffffffffffffff2} ---
    killed by SIGSEGV    
Segmentation fault
  

Комментарии:

1. Второй аргумент to execve — это указатель на массив указателей на символы, то есть массив строк, а не массив символов. Вот почему ваш код не работает.

2. Если я изменю .asciz на .string тот же результат

3. Это в конечном итоге для использования буфера?

4. Это для моего первого шелл-кода, я студент CTF.

5. @EntyAV Это ничего не меняет; .asciz является псевдонимом .string . Вам нужен массив строк, а не массив символов. То есть массив указателей на массивы символов. Последний указатель должен быть NULL , а последний символ в каждом массиве символов должен быть нулевым символом ( .asciz гарантирует это для вас).

Ответ №1:

execve Системный вызов имеет подпись

 execve(const char *path, char *const argv[], char *const envp[]);
  

Вектор аргументов представляет собой массив строк, то есть указатель на массив указателей на массивы символов. Однако вы указали указатель на массив символов, который неверен и не будет работать. Чтобы исправить это, добавьте массив указателей, ссылающихся на ваши аргументы:

         .section .data
name:   .string "/bin/sh"
arg1:   .string "-c"
arg2:   .string "ls"

args:   .quad name
        .quad arg1
        .quad arg2
        .quad 0

        .section .text
        .globl _start
_start: movq $59, %rax
        leaq name(%rip), %rdi
        leaq args(%rip), %rsi
        movq $0, %rdx

        syscall
  

Посмотрите, как теперь args массив указателей на аргументы завершается нулем. Также обратите внимание, что первым аргументом (с индексом 0) обычно является само имя программы. Передача фактического параметра там не будет работать должным образом.

Я также упростил код, загрузив адреса строк непосредственно с помощью lea инструкции, а не обходным путем, который вы использовали.

Комментарии:

1. В конечном итоге это будет шелл-код, поэтому была причина, по которой они пытались собрать аргументы в стеке. Я считаю, что более предпочтительным здесь был бы ответ, который строит аргументы в стеке и передает адреса данных стека в syscall .

2. @MichaelPetch Мой ответ направлен на объяснение требуемой структуры данных. Заставить это работать как код оболочки по-прежнему является проблемой.

3. @fuz как заставить его работать как шелл-код, я новичок и не могу понять, почему сгенерированный шелл-код вызывает ошибку неправильной инструкции. Возможно, мне следует писать полезные нагрузки в NASM, а не в GAS.

4. @EntyAV Выбор ассемблера на самом деле не имеет значения. Существует несколько способов заставить это работать в коде оболочки. Для новичка это немного сложно, и я не рекомендую выполнять эту задачу. Общая идея состоит в том, чтобы создавать массивы в стеке вместо того, чтобы иметь их в разделе данных.