
**셸(Shell, 껍질)**이란 운영체제에 명령을 내리기 위해 사용되는 사용자의 인터페이스로, 운영체제의 핵심 기능을 하는 프로그램을 **커널(Kernel, 호두 속 내용물)**이라고 하는 것과 대비됩니다. 셸을 획득하면 시스템을 제어할 수 있게 되므로 통상적으로 셸 획득을 시스템 해킹의 성공으로 여깁니다.
execve 셸코드는 임의의 프로그램을 실행하는 셸코드인데, 이를 이용하면 서버의 셸을 획득할 수 있습니다. 다른 언급없이 셸코드라고 하면 이를 의미하는 경우가 많습니다.
최신의 리눅스는 대부분 sh, bash를 기본 셸 프로그램으로 탑재하고 있으며, 이 외에도 zsh, tsh 등의 셸을 유저가 설치해서 사용할 수 있습니다. 우리의 실습 환경인 Ubuntu 22.04에도 /bin/sh가 존재하므로, 이를 실행하는 execve 셸코드를 작성해보겠습니다.
execve 셸코드는 execve 시스템 콜만으로 구성됩니다.
| syscall | rax | arg0 (rdi) | arg1 (rsi) | arg2 (rdx) |
|---|---|---|---|---|
| execve | 0x3b | const char *filename | const char *const *argv | const char *const *envp |
여기서 argv는 실행파일에 넘겨줄 인자, envp는 환경변수입니다. 우리는 sh만 실행하면 되므로 다른 값들은 전부 null로 설정해줘도 됩니다. 리눅스에서는 기본 실행 프로그램들이 /bin/ 디렉토리에 저장되어 있으며, 우리가 실행할 sh도 여기에 저장되어 있습니다.
따라서 우리는 execve(“/bin/sh”, null, null)을 실행하는 것을 목표로 셸 코드를 작성하면 됩니다. 앞에서 작성한 orw셸 코드와 비교했을 때 그렇게 어렵지 않으므로, 직접 작성해보시고 오른쪽의 셸 코드와 비교해 보시기 바랍니다.
;Name: execve.S
mov rax, 0x68732f6e69622f
push rax
mov rdi, rsp ; rdi = "/bin/sh\x00"
xor rsi, rsi ; rsi = NULL
xor rdx, rdx ; rdx = NULL
mov rax, 0x3b ; rax = sys_execve
syscall ; execve("/bin/sh", null, null)