밑에 다른 게시글도 보고 어셈에서 OpCode로 변환하는 방법 찾아서 테스트 삼아 Hello world!!!\n를 출력하는 셀코드를 전송하였는데 아무 반응이 없습니다.
아래는 쉘 코드에 적용된 어셈블리로 작성된 코드 입니다.
- 주석은 이해를 돕기 위해 md 파일에만 작성되어 있으며 실제 코드에서는 주석이 없습니다.
.globl main
.type main, @function
.intel_syntax noprefix
main:
push rbp
mov rbp, rsp
mov rax, 0xa212121646c726f ; 스택에 hello world!!!\n 저장중
push rax ; 스택에 hello world!!!\n 저장중
mov rax, 0x77202c6f6c6c6548 ; 스택에 hello world!!!\n 저장중
push rax ; 스택에 hello world!!!\n 저장중
xor rax, rax ; rax = 0
xor rdx, rdx ; rdx = 0
mov al, 0x1 ; al(rax) = 1 ; write
mov rdi, rax ; rdi = rax(1) ; stdout
lea rsi, [rsp] ; rsi = 스택에 저장된 hello world!!!\n 주소
mov dl, 0x10 ; rsi = 16 ; 출력할 글자 수
syscall ; write(stdout, 스택에 저장된 hello world!!!\n 주소, 16)
xor rax, rax ; rax = 0 ; return 0
leave
ret
해당 코드 작성 이후 gcc a.s -o a.out
커맨드를 통하여 어셈블리어를 컴파일하였고 ./a.out
커맨드 실행 결과로 Hello, world!!!\n
이 나왔습니다.
이후 objdump -d a.out
커맨드로 OpCode를 확인하였고 이를 쉘 코드로 변경하였습니다.
아래는 objdump -d a.out
커맨드 출력 결과입니다.
...다른 코드들
00000000000005fa <main>:
5fa: 55 push %rbp
5fb: 48 89 e5 mov %rsp,%rbp
5fe: 48 b8 6f 72 6c 64 21 movabs $0xa212121646c726f,%rax
605: 21 21 0a
608: 50 push %rax
609: 48 b8 48 65 6c 6c 6f movabs $0x77202c6f6c6c6548,%rax
610: 2c 20 77
613: 50 push %rax
614: 48 31 c0 xor %rax,%rax
617: 48 31 d2 xor %rdx,%rdx
61a: b0 01 mov $0x1,%al
61c: 48 89 c7 mov %rax,%rdi
61f: 48 8d 34 24 lea (%rsp),%rsi
623: b2 10 mov $0x10,%dl
625: 0f 05 syscall
627: 48 31 c0 xor %rax,%rax
62a: c9 leaveq
62b: c3 retq
62c: 0f 1f 40 00 nopl 0x0(%rax)
...다른 코드들
아래는 위 결과를 셀 코드(OpCode)로 변환한 결과입니다.
\x55\x48\x89\xe5\x48\xb8\x6f\x72\x6c\x64\x21\x21\x21\x0a\x50\x48\xb8\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x50\x48\x31\xc0\x48\x31\xd2\xb0\x01\x48\x89\xc7\x48\x8d\x34\x24\xb2\x10\x0f\x05\x48\x31\xc0\xc9\xc3\x0f\x1f\x40\x00
이후 해당 셀 코드가 정상 작동하는지 C 코드를 통해 확인 후 nc host1.dreamhack.games <custom port>
커맨드를 통해 제출하였는데 하다못해 에러 메세지조차도 없으며 아무런 반응이 없습니다.
아래는 C 코드를 통한 확인 및 제가 진행한 제출 과정입니다.
- 아래 코드에서는 shellcode: 이후 엔터가 들어간 것처럼 보이나 실제로는 한줄로 구성되어 있으며 길이가 길어 엔터가 들어간 것처럼 보이는 것입니다.
root@dev:~/dh# cat a.c
char s[] = "\x55\x48\x89\xe5\x48\xb8\x6f\x72\x6c\x64\x21\x21\x21\x0a\x50\x48\xb8\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x50\x48\x31\xc0\x48\x31\xd2\xb0\x01\x48\x89\xc7\x48\x8d\x34\x24\xb2\x10\x0f\x05\x48\x31\xc0\xc9\xc3\x0f\x1f\x40\x00";
int main(void) {
(*(void (*)()) s)();
}
root@dev:~/dh# gcc -fno-stack-protector -z execstack -o shell.out a.c
root@dev:~/dh# ./shell.out
Hello, world!!!
root@dev:~/dh# nc host1.dreamhack.games <some port>
shellcode: \x55\x48\x89\xe5\x48\xb8\x6f\x72\x6c\x64\x21\x21\x21\x0a\x50\x48\xb8\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x50\x48\x31\xc0\x48\x31\xd2\xb0\x01\x48\x89\xc7\x48\x8d\x34\x24\xb2\x10\x0f\x05\x48\x31\xc0\xc9\xc3\x0f\x1f\x40\x00
root@dev:~/dh#
어떻게 제출해야지 인식이 될까요...
\x55\x48\x89\xe5\x48\xb8\x6f\x72\x6c\x64\x21\x21\x21\x0a\x50\x48\xb8\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x50\x48\x31\xc0\x48\x31\xd2\xb0\x01\x48\x89\xc7\x48\x8d\x34\x24\xb2\x10\x0f\x05\x48\x31\xc0\xc9\xc3\x0f\x1f\x40\x00를 그대로 제출하시면 문자열로 제출됩니다.
그러니까 \x55가 opcode 55가 아닌 그냥 문자열 '\x55'로 인식되게 되요...
파이썬 pwntools를 이용해서
from pwn import *
p = remote('host1.dreamhack.games',<port>)
shellcode = b'\x55\x48\x89\xe5\x48\xb8\x6f\x72\x6c\x64\x21\x21\x21\x0a\x50\x48\xb8\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x50\x48\x31\xc0\x48\x31\xd2\xb0\x01\x48\x89\xc7\x48\x8d\x34\x24\xb2\x10\x0f\x05\x48\x31\xc0\xc9\xc3\x0f\x1f\x40\x00'
p.send(shellcode)
p.interactive()
이런식으로 제출하실 수 있습니다.