Shell Code란 Shell(/bin/sh 등)을 실행시키는 일련의 어셈블리 코드라고 할 수 있다. 보통 Shell Code는 해당 아키텍쳐 환경에서 사용되는 함수 호출 규약을 따르기 때문에 찾아보고 직접 어셈블리 코드를 작성하며 만들어 보았다. 필자는 linux x86_64 환경이고 cdecl방식으로 c언어 컴파일을 진행 했다.
myshell 바이너리 제작
우선 본격적인 Shell Code를 제작하기 전에 해당 사이트에서 execve System Call의 인자값들을 살펴보았다.
x86_64 환경에서 리눅스 4.14 기준으로 System Call의 종류와 인자 값을 확인 할 수 있었다.
우리가 사용할 execve는 rax, rdi, rsi, rdx이 4가지를 사용한다.
[사진 2] - System Call Table
확인을 위해 직접 shell.c 파일을 작성하여 아래 명령어를 통해 컴파일을 진행한다.
이때 static 옵션은 공유 라이브러리들을 모두 한파일에 묶어 컴파일 하는 옵션이다.
gcc -m64 -o shell shell.c -static
[사진 3] - Vi
warning과 함께 파일이 컴파일 되었고 실행해보니 성공적으로 쉘이 실행되어 동작함을 알 수 있다.
[사진 4] - Shell 실행 모습
PwnGDB를 통해 디버깅을 진행해보았다.
[사진 5] - PwnGDB 디버깅
execve를 call 하는 부분에서 멈춰 현재 스택상태와 레지스터 상태를 기억하고 이렇게 되도록 asm파일을 만들어 컴파일 하도록해야 한다.
[사진 6] - call execve
필자는 다음과 같이 스택에 직접 넣음으로써 인자값을 전달하고 shell을 실행하도록 어셈블리어를 작성했다.
처음 작성해보는거라 많이 부족하지만 계속 작성하다보면 실력이 늘지 않을까..?
여기서 mov al, 0xb는 mov eax, 0xb로 할시 Null Byte(공백)이 들어가게 되어 문제를 풀때 입력 시 중간에 입력이 끊기게된다 그래서 al로 하였다. 또한 /bin/sh도 /bin//sh로 하였는데 위와 동일한 이슈로 이렇게 작성했다. syscall은 Call을 뜻한다.