문제
Mommy! I think I know how to make shellcodes
ssh asm@pwnable.kr -p2222 (pw: guest)
분석
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;
}
(stub + 입력받은내용)을 실행시켜주는 간단한 구조이다.
open, read, write함수만 쓸 수 있는 듯한데, 자세한 이유는 모르겠으나 sandbox함수 때문일 것으로 추정된다.
전체 쉘코드는 항상 메모리 주소 0x41414000에 저장되고 실행된다.
즉, 메모리 주소를 알기 때문에 파일의 이름을 쉘코드와 같이 해당 메모리에 넣어주고 그 주소값을 참조해서 사용하면 된다.
stub의 내용은 다음과 같다.
참고 : Online x86 / x64 Assembler and Disassembler
즉, 모든 레지스터를 0으로 초기화시켜주는 코드인데, 별 의미가 없다.
FL4G
입력으로 넣어주는 쉘코드는 다음과 같이 구성할 수 있다.
이때, 이러한 쉘코드 뒤에는 open함수에서 mode값으로 넣어주는 "r\x00"과 파일의 이름 "this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong"이 들어가고 각각의 주소는 0x41414079와 0x4141407b이다.
참고로, x64 syscall table의 일부는 다음과 같다.
출처 : Linux System Call Table for x86 64
실행결과는 다음과 같다.
'pwnable.kr' 카테고리의 다른 글
[Toddler's Bottle] blukat writeup (0) | 2018.09.17 |
---|---|
[Toddler's Bottle] memcpy writeup (0) | 2018.09.17 |
[Toddler's Bottle] cmd2 writeup (0) | 2018.09.16 |
[Toddler's Bottle] cmd1 writeup (0) | 2018.09.16 |
[Toddler's Bottle] lotto writeup (0) | 2018.09.16 |