# 
EHAX CTF 2026

RE
Pathfinder 

```python

5555555556d0    int32_t main(int32_t argc, char** argv, char** envp)

5555555556db        void* fsbase
5555555556db        int64_t rax = *(fsbase + 0x28)
5555555556ea        sub_5555555555a1()
5555555556fe        printf(format: "Are you a pathfinder?\n[y/n]: ")
55555555570d        fflush(fp: stdout)
555555555738        char buf[0x40]
555555555738        int32_t result
555555555738        
555555555738        if (read(fd: 0, &buf, nbytes: 1) != 0)
55555555576b            int32_t i
55555555576b            
55555555576b            do
555555555763                i = getchar()
55555555576b            while (i != 0xa)
55555555576b            
555555555776            if (buf[0] == 'n')
555555555782                puts(str: "Understandable. See you again, maybe..")
555555555791                fflush(fp: stdout)
555555555796                result = 1
555555555776            else if (buf[0] == 'y')
5555555557e2                printf(format: "Ok, tell me the best path: ")
5555555557f1                fflush(fp: stdout)
🛑55555555580a                memset(&buf, 0, 0x40)
🛑55555555580a                
555555555835                if (read(fd: 0, &buf, nbytes: 0x40) != 0)
555555555878                    buf[strcspn(&buf, "\n")] = 0
555555555878                    
🛑555555555891                    if (sub_555555555444(&buf) == 0)
5555555558ea                        puts(str: "Better luck next time.")
5555555558f9                        fflush(fp: stdout)
5555555558fe                        result = 1
🛑555555555891                    else
5555555558a7                        char flag[0x108]
5555555558a7                        sub_555555555602(&buf, &flag)
5555555558c5                        printf(format: "You have what it takes. Flag: %s\nBye.\n", 
5555555558c5                            &flag, "You have what it takes. Flag: %s\nBye.\n")
5555555558d4                        fflush(fp: stdout)
5555555558d9                        result = 0
555555555835                else
555555555841                    puts(str: "Where dat path tho?")
555555555850                    fflush(fp: stdout)
555555555855                    result = 1
5555555557a9            else
5555555557b5                puts(str: "Invalid option")
5555555557c4                fflush(fp: stdout)
5555555557c9                result = 1
555555555738        else
555555555744            puts(str: "No input?")
555555555753            fflush(fp: stdout)
555555555758            result = 1
555555555758        
555555555907        *(fsbase + 0x28)
555555555907        
555555555910        if (rax == *(fsbase + 0x28))
555555555918            return result
555555555918        
555555555912        __stack_chk_fail()
555555555912        noreturn
```

Nothing too interesting in main, its a maze and you have to find the path through it

The function, that could be an initialization is not setting anything interesting

```python
5555555555a1    int64_t sub_5555555555a1()

5555555555be        setvbuf(fp: stdin, buf: nullptr, mode: 2, size: 0)
5555555555dc        setvbuf(fp: stdout, buf: nullptr, mode: 2, size: 0)
555555555601        return setvbuf(fp: stderr, buf: nullptr, mode: 2, size: 0)
```

The check path function

```python
555555555444    uint64_t sub_555555555444(char* arg1)

555555555450        int32_t var_30 = 0
555555555457        int32_t var_2c = 0
555555555462        char* var_20 = arg1
555555555462        
55555555556f        while (*var_20 != 0)
55555555546f            char rax_2 = *var_20
555555555485            int64_t rax_7 = sx.q(zx.d(rax_2)) * 0xc
555555555493            int64_t rcx_1 = *(rax_7 + &data_555555558120)
55555555549b            int24_t rax_8 = (*(rax_7 + 0x555555558128)).3
55555555549b            
🛑5555555554d8            if (rax_8:2.b == 0)
5555555554da                return 0
5555555554da            
5555555554ea            int32_t rax_20 = var_30 + rcx_1.d
5555555554f5            int32_t rax_22 = var_2c + rcx_1:4.d
5555555554f5            
555555555508            if (rax_20 u> 9 || rax_22 u> 9)
55555555550a                return 0
55555555550a            
55555555551e            char rax_26 = sub_55555555523f(var_30, var_2c)
55555555551e            
55555555554c            if (((sub_55555555523f(rax_20, rax_22)
55555555554c                    & ((rax_2 * 0x6b) ^ rax_8:1.b ^ 0x3c))
55555555554c                    | (rax_26 & ((rax_2 * 0x6b) ^ rax_8.b ^ 0x3c))) == 0)
55555555554e                return 0
55555555554e            
555555555558            var_30 = rax_20
55555555555e            var_2c = rax_22
555555555561            var_20 = &var_20[1]
555555555561        
55555555557f        if (var_30 != 9 || var_2c != 9)
555555555581            return 0
555555555581        
555555555599        int32_t rax_37
555555555599        rax_37.b = sub_55555555526b(arg1) == 0x86ba520c
55555555559c        return zx.q(rax_37.b)
```

is referring to `0x555555558128` but in the binary its only zeroes. There is no obvious place to look for the initialization of the maze

The answer is inside of `.init_array` section

```python
.init_array section started  {0x555555557dc0-0x555555557dd8}
555555557dc0  void (* init_array[0x3])() = 
555555557dc0  {
555555557dc0      [0x0] = _INIT_0
555555557dc8      [0x1] = _INIT_1
555555557dd0      [0x2] = _INIT_2
```

function `_INIT_1` sets up the maze

```python
555555555235        for (int32_t i = 0; i s<= 0x63; i += 1)
55555555522a            *(sx.q(i) + &data_5555555580a0) =
55555555522a                *(sx.q(i) + &data_555555556020) ^ sub_5555555551c9(i)
```

Claude wrote the BFS script to find the way around the maze

\``` EESSSWWSSSSSSEEEEEEEENNESS` ``

EHAX{2E3S2W6S8E2NE2S}

## WEB

### Borderline Personality

![](https://cdn.hashnode.com/uploads/covers/64e077c7857a8e8e2aca61b0/3b002ac3-182d-47aa-87ff-76e661eb0fc3.png align="center")

Inside of the handout directory there are two subdirectories `backend` and `haproxy`

The admin route is very straightforward

```python
@app.route('/admin/flag', methods=['GET', 'POST'])
def flag():
    return "EHAX{TEST_FLAG}\n", 200
```

But there is a haproxy in front of it

```python
frontend http-in
    bind *:8080
    
    acl restricted_path path -m reg ^/+admin
    http-request deny if restricted_path
    
    default_backend application_backend

backend application_backend
    server backend1 backend:5000
```

URL encoding of `a` in admin is enough to fool that rule

`http://chall.ehax.in:9098/%61dmin/flag`

EH4X{BYP4SSING\_R3QU3S7S\_7HR0UGH\_SMUGGLING\_\_IS\_H4RD}
