Передача массива (argv) в системный вызов в сборке x64 - PullRequest
0 голосов
/ 05 мая 2020

Я учусь создавать шелл-код и отлично провожу время. Я в основном понимаю, что мне делать. Я могу создать asm-код, который фактически сгенерирует оболочку. Однако я собирался проверить свои способности, попробовав другой системный вызов, а именно cat.

Я использую метод построения стека из регистров. Однако я столкнулся с проблемой, когда мне нужно передать массив параметру argv. Это достаточно просто при выполнении оболочки, я могу просто передать адрес адреса строки /bin/sh в стеке. Но с cat мне нужно передать как имя функции /bin/cat, так и аргумент для cat ie /etc/issue.

Я знаю, что макет для системного вызова:

rax : syscall ID
rdi : arg0
rsi : arg1
rdx : arg2
r10 : arg3
r8 : arg4
r9 : arg5

Я не могу расшифровать, как передать {"cat","/etc/issue"} в один регистр, а именно в rsi.

Моя сборка:

global _start
section .text
_start:
;third argument
xor rdx,rdx

;second array member
xor rbx,rbx
push rbx ;null terminator for upcoming string
;push string in 2 parts
mov rbx,6374652f ;python '/etc/issue'[::-1].encode().hex()
push rbx
xor rbx,rbx
mov rbx, 0x65757373692f
push rbx

;first array member
xor rcx,rcx ;null terminator for upcoming string
add rcx,0x746163 ;python 'cat'[::-1].encode().hex()
push rcx

;first argument
xor rdi,rdi
push rdi ;null terminator for upcoming string
add rdi,7461632f6e69622f ;python '/bin/cat'[::-1].encode().hex()
push rdi
mov rdi,rsp

;execve syscall
xor rax,rax
add rax,59

;exit call
xor rdi,rdi
xor rax,rax
add rax,60

Она работает, но (как и ожидалось) прерывается, когда в качестве argv передается NULL.

Я даже попытался просто написать приложение C который создает массив, завершает работу и отлаживает его, но я все еще не совсем понимал, что он делал для создания массива.

1 Ответ

2 голосов
/ 05 мая 2020

Вы делаете этот путь более сложным, чем вам нужно. Вот все, что вам нужно сделать:

    jmp .afterdata
.pathname:
    db '/bin/' ; note lack of null terminator
.argv0:
    db 'cat'
.endargv0:
    db 1 ; we'll have to change the last byte to a null manually
.argv1:
    db '/etc/issue'
.endargv1:
    db 1 ; we'll have to change the last byte to a null manually
.afterdata:
    xor eax, eax ; the null terminator for argv and envp
    push rax
    mov rdx, rsp ; rdx = envp
    dec byte [rel .endargv1] ; change our 1 byte to a null byte
    lea rax, [rel .argv1]
    push rax
    dec byte [rel .endargv0] ; change our 1 byte to a null byte
    lea rax, [rel .argv0]
    push rax
    mov rsi, rsp ; rsi = argv
    lea rdi, [rel .pathname]
    xor eax, eax
    mov al, 59 ; SYS_execve
    syscall
    ; if you wanted to do an exit in case the execve fails, you could here, but for shellcode I don't see the point

Вам не нужно вручную выполнять шестнадцатеричное кодирование или реверсирование строк. Вы можете просто вставить нужные строки прямо в конец вашего шелл-кода и поместить sh их адреса в стек с относительной адресацией. Единственные препятствия, через которые мы переходим, - это убедиться, что данные находятся перед инструкциями, которые их используют, поэтому там нет нулевых байтов, и необходимо добавлять нулевые терминаторы в строку во время выполнения.

* 1005 хочу, чтобы шеллкод был коротким. Обратите внимание на то, как я указываю на cat, который является частью /bin/cat, вместо того, чтобы указывать ему дополнительное время, и повторно использую ноль в конце argv для envp.

Кстати, если вы хотите попробовать это как отдельную программу, вам нужно передать -Wl,-N и -static в G CC, так как байты, которые он изменяет, будут в разделе .text (который обычно доступен только для чтения) . Это не будет проблемой, если вы на самом деле используете его как шелл-код, поскольку он все равно будет доступен для записи, независимо от того, каким способом вы изначально поместили его в память.

...