Skip to content

Latest commit

 

History

History
76 lines (43 loc) · 4.96 KB

File metadata and controls

76 lines (43 loc) · 4.96 KB
description
09/21/2023

📲 Syscalls

Introduction

A syscall is a system call.

Easiest explanation that I could find:

A syscall is a function executed by the kernel.

This is how the program enters the kernel in order to carry out a specific task such as creating a process, Input and Output, and other tasks that require kernel-level access.

Check out the Linux Syscall Table:

{% embed url="https://chromium.googlesource.com/chromiumos/docs/+/HEAD/constants/syscalls.md#x86_64-64_bit" %}

You will come to notice that syscalls are very similar in appearance to libc functions.

  • open()
  • fork()
  • read()

Ultimately, these functions can be summed up as wrappers around syscalls, making it easier for programmers to utilize in code.

How to Trigger Syscalls

In Linux, syscalls are triggered by using the int80 instruction.

Once called, the kernel checks the value stored in RAX and this is equivalent to the syscall number which is what depicts WHICH syscall is ran.

Execve

The execve syscall executes the program passed to it in the RDI register.

RSI and RDX hold argp and envp respectively.

  • argp are command line arguments
  • envp are environment variables

What does this mean?

If there is no system() function, we can use execve to call "/bin/sh" instead.

This will pass in a pointer "/bin/sh" to RDI, populating the RSI and RDX with 0 since both argv and envp need to have the value of NULL to grant you a shell.

Additional Context

Kernel-based malware and exploits require syscalls in order to intercept file read/writes, open sockets for network communications, creating files, read/write memory, etc.

In other words, you need syscalls in order to do something malicious.

Remote Kernel Exploits?

A remote kernel exploit is possible.

Say there is a vulnerability in the TCP/IP stack which runs in the kernel for Linux.

This vulnerability could ultimately lead to kernel-level exploitation without any syscalls ever being invoked.

Seeing Syscalls in Action

We can utilize strace to see what we are syscalls are being invoked.

This gets really interesting.

We can see execve() placing the value 0 into RAX (which the kernel checks), storing the value as a parameter (0) into RDI and calling read() or 0 which is the syscall number for read().

{% code overflow="wrap" %}

strace ./vuln                                                                                        execve("./vuln", ["./vuln"], 0x7fff13afab20 /* 22 vars */) = 0                                                                     read(0,                                                                                                                            "\n", 300)                      = 1                                                                                                --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x1} ---                                                               +++ killed by SIGSEGV +++

{% endcode %}