Tags: golang cryptography math 

Rating:

The Most Worthy Distinction of Pain

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strings"
)

func readFlag() (string, error) {
    flag_file, err := os.Open("flag.txt")
    if err != nil {
        return "", err
    }
    defer flag_file.Close()
    scanner := bufio.NewScanner(flag_file)
    scanner.Scan()
    flag := scanner.Text()
    return flag, nil
}

func combine(flag []uint8) []uint16 {
    combined := []uint16{}
    for i := 0; i < len(flag); i += 2 {
        c := uint16(flag[i]) << 8
        if i+1 < len(flag) {
            c += uint16(flag[i+1])
        }
        combined = append(combined, c)
    }
    return combined
}

func encrypt(flag string) string {
    codex_file, err := os.Open("CROSSWD.TXT")
    if err != nil {
        return "!"
    }
    defer codex_file.Close()
    all_words := []string{}
    combined := combine([]uint8(flag))
    for _, c := range combined {
        all_words = append(all_words, encode_one(c, codex_file))
    }
    return strings.Join(all_words, " ")
}

func encode_one(c uint16, codex_file *os.File) string {
    codex_file.Seek(0, io.SeekStart)
    scanner := bufio.NewScanner(codex_file)
    for i := uint16(0); i < c; i++ {
        scanner.Scan()
    }
    return scanner.Text()
}

func main() {
    flag, err := readFlag()
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(encrypt(flag))
}

it's all around the abyse of bit operations.

There, every second character was encrypted as follows: ascii character code << 8 and add to it the ascii code of the next character (For example, 98 << 8 = 25088 + 121 = 25209), then, from the line number, which is equal to the received number, we take a word from the dictionary and substitute it into the ciphertext.

To decipher, it turns out we need to do the reverse operation: find a word in the dictionary, take its number, subtract the number X from it, and here stop, we don't know the number, that's where the abuz begins.

We can simply perform the reverse shift operation >>, without adding, and we will get the number to which we added (25088). For example, if we shift 25209 >> 8 = 98, and now if we shift 98 << 8, then we get 25088!!!! From here we get the following: 25209 - 25088 = 121, so we get all the numbers that are in even positions.

As part of the byuctf{testflag} test flag, it will be y c f t s f a } And it's even easier to get odd ones, we just take the line numbers and move them (25209 >> 8 = 98)

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strings"
)

func readFlag() (string, error) {
    flagFile, err := os.Open("encrypted.txt")
    if err != nil {
        return "", err
    }
    defer flagFile.Close()
    scanner := bufio.NewScanner(flagFile)
    scanner.Scan()
    flag := scanner.Text()
    return flag, nil
}

func combine(flag []uint8) []uint16 {
    combined := []uint16{}
    for i := 0; i < len(flag); i += 2 {
        c := uint16(flag[i]) << 8
        if i+1 < len(flag) {
            c += uint16(flag[i+1])
        }
        combined = append(combined, c)
    }
    return combined
}

func revertCombine(flag []uint16) []uint16 {
    combined := []uint16{}
    for i := 0; i < len(flag); i += 1 {
        c := flag[i] >> 8
        combined = append(combined, c)
    }
    return combined
}

func encrypt(flag string) string {
    codex_file, err := os.Open("CROSSWD.TXT")
    if err != nil {
        return "!"
    }
    defer codex_file.Close()
    all_words := []string{}
    combined := combine([]uint8(flag))
    for _, c := range combined {
        all_words = append(all_words, encodeOne(c, codex_file))
    }
    return strings.Join(all_words, " ")
}

func encodeOne(c uint16, codex_file *os.File) string {
    codex_file.Seek(0, io.SeekStart)
    scanner := bufio.NewScanner(codex_file)
    for i := uint16(0); i < c; i++ {
        scanner.Scan()
    }
    return scanner.Text()
}

func getLineNumber(myString string) (int, error) {
    f, err := os.Open("CROSSWD.txt")

    if err != nil {
        return 0, err
    }
    defer f.Close()

    scanner := bufio.NewScanner(f)

    line := 1

    for scanner.Scan() {
        if scanner.Text() == myString {
            return line, nil
        }

        line++
    }

    if err := scanner.Err(); err != nil {
    }
    return 0, nil
}

func makeThatShit(flag_data []uint16) ([]uint16, []string) {
    result_flag := revertCombine(flag_data)
    second_flag_part := []string{}

    for i, c := range result_flag {
        c = c << 8
        second_flag_part = append(second_flag_part, string(flag_data[i]-uint16(c)))
    }

    return result_flag, second_flag_part
}

func main() {
    flag, err := readFlag()

    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(encrypt(flag))

    words := strings.Fields(flag)
    fmt.Println(words)
    flag_data := []uint16{}

    for _, c := range words {
        lineNumber, _ := getLineNumber(c)
        flag_data = append(flag_data, uint16(lineNumber))
    }

    fmt.Println(flag_data)
    first, second := makeThatShit(flag_data)

    for i := 0; i < len(first); i++ {
        print(string(first[i]), second[i])
    }
}
Original writeup (https://ctftime.org/team/144064).