본문 바로가기
.study/pwnable

[포너블 기초] Shell Code 만들기

by hackisha 2023. 10. 23.
728x90

Shell Code 만들기

전체적이 과정은 아래와 같다.

1.C언어로 해당 코드를 구현한다.
2.gdb역어셈블링하여 필요한 부분을 찾는다.
3.필요한 부분만 뽑아 어셈블리어로 새로 구현한다.
4.컴파일한 후, objdump로 기계어를 출력한다.
5.출력된 기계어들을 하나로 연결 시킨다.
 

 

execve() 함수를 이용하여 shell code를 실행시키는 코드를 c언어로 작성해보겠다.

* execve 함수는 현재 실행 중인 프로세스를 새로운 프로세스로 덮어쓴다.

execve 함수의 인자

아래는 execve()를 이용해서/bin/sh 셸을 얻게 해주는 셸 코드를 c언어로 작성 한 것이다.

 

#include <stdio.h>

int main()

{

char*sh[]={"/bin/sh", 0};

execve(sh[0],&sh,0);

}

 

gcc로 작성한 셸코드 컴파일
컴파일 한 셸코드를 gdb로 디버깅

이제 작성한 코드를 컴파일후, gdb로 디버깅을 수행 후, 디버깅 결과를 바탕으로 셸코드를 어셈블리어로 작성해 보겠다.

앞의 내용을 기반으로 작성한 어셈블리 코드이다.

 

xor %eax, %eax

xor %edx, %edx

이부분은 나중에 스택에 push하여 인자를 전달하기 위해 0을 저장한다.

 

int 0x80은 시스템 콜을 호출하는 인터럽트이다.

objdump

셸코드 작성이 거의 다 됐다!

그런데 objdump로 작성한 코드를 디스어셈블 해보면 중간에 null(0x00)이 포함 되어 있는것을 볼 수 있다.

 

null바이트는 c언어에서 입력으로 들어오면 입력을 종료해 버리기 때문에 제거해야 한다.

 

mov $0xb, %eax
여기서 eax4바이트의 값을 저장할 수 있기 때문에 0xb는 자동으로 0b 00 00 00 으로 변환 된다.
따라서 eax의 하위 레지스터인 al을 사용해주면 null제거할 수 있다.

 

앞의 내용을 바탕으로 다시 작성한 셸코드이다.

 

objdump를 이용하여 다시 디스어셈블 해보면 아까와 다르게 null문자가 모두 제거 된 것을 확인 할 수있다!

여기서 마지막으로 기계어 코드를 추출하면 최종적으로 셸코드가 완성된다!

 

최종 완성된 셸코드(25바이트)

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80

 

728x90