1. 왜 system 함수를 쓰지 않을까?
shell을 따기위해서 system('/bin/sh') 를 호출해보았고
execve('/bin/sh',0,0) 도 호출해본 경험이 있다
그런데 왜 shellcode를 만들때는 execve( ) 를 사용하는 것일까?
일단 system 함수와 execve 함수가 실행되는 모습을 비교해보자
위 두 모습을 비교해보면 system 함수는 호출된 뒤에 printf 도 호출했지만
execve가 호출되고 난 뒤에는 printf 가 호출되지 않았다
system 함수의 경우 작업이 끝날때까지 호출한 프로세스가 대기하다가 계속 수행되지만
execve 는 호출 프로세스가 바뀌어버린다는 차이가 있다
system 함수는 fork() 와 execve() 의 결합물이다
fork( ) 를 통해 자식 프로세스를 만들고,
자식 프로세스는 execve( ) 에 의해 흐름이 바뀌게 된다
하지만 부모프로세스는 현 상태를 유지하기 때문에
다음 작업을 계속 수행해 나갈 수 있다.
따라서 system 함수는 결국 execve( ) 를 좀 더 편하게 사용하는 함수인 것이다
2. 왜 asm 코드로 작성할까?
shellcode 도 execve( ) 를 호출한 코드의 hex 값인데
왜 c언어로 짠 코드를 dump 시켜서 사용하지 않는 것인지에 대해서 의문이 생겼다
먼저 c로 컴파일한 파일을 objdump 명령어로 disassemble 해보자
위에 출력되는 값 이외에도 많은 함수들이 로드되어 쉘코드의 길이가 왕창 길어진다
하지만 asm 코드로 작성한 파일은 c로 작성한 코드보다 쓸데없는 함수들의 로드가 이루어지지 않아
메모리가 작을 수 밖에 없고 따라서 쉘코드의 길이도 짧아질 수 밖에 없다
3. pwntool을 사용하여 shellcode 작성해보기
* stack 영역에 실행권한 주기
-z execstack
* Canary 해제하기
-fno-stack-protector
간단하게 설명하자면
execve의 첫번째 인자인 rdi 에 /bin/sh\x00 문자열을 가르키게 한다
execve의 두번째 인자인 rsi 를 0으로 만든다
execve의 세번째 인자인 rdx 를 0으로 만든다
execve를 호출하기 위해 rax에 59를 세팅해두고 syscall을 부르면
(syscall table 참조)
execve('/bin/sh',0,0) 이 실행된다
* 2020-07-04 c언어에서 inline asm으로 작성해봄!
#include <stdio.h>
int main(){
printf("start!\n");
__asm__ __volatile__(
"mov $0x0068732f6E69622f, %rax\n\t"
"push %rax\n\t"
"mov %rsp, %rdi\n\t"
"xor %rsi, %rsi\n\t"
"xor %rdx, %rdx\n\t"
"mov $0x3b, %rax\n\t"
"syscall\n\t"
);
printf("end!\n");
return 0;
}
어셈블리어 코딩을 위한 명령어
* sudo apt-get install gcc nasm
[ 오브젝트 파일 생성]
(32비트) nasm -f elf 파일명.asm
(64비트) nasm -f elf64 파일명.asm
[ 실행파일 생성 ]
ld 파일명.o -o 결과물파일명
'System Hacking > Study Notes' 카테고리의 다른 글
pwndbg> command (0) | 2020.01.13 |
---|---|
Extra Segment & Exit (with. FSB) (0) | 2020.01.13 |
pwntool 함수 (0) | 2020.01.07 |
LD 와 libc.so.6 (0) | 2019.12.29 |
Address SANitizer 미완 (0) | 2019.11.04 |