Home (CTF) just CTF 2023 rustberry, manGO writeup
Post
Cancel

(CTF) just CTF 2023 rustberry, manGO writeup

rustberry

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
36
  if (puVar1 != (undefined4 *)0x0) {
    puVar1[0x25] = 0x7;
    puVar1[0x29] = 0x1c;
    puVar1[0x2a] = 0xff;
    puVar1[0x18] = 0x3;
    puVar1[0x26] = 0x21;
    puVar1[0x19] = 0x1a;
    puVar1[0x1a] = 0x11;
    puVar1[0x1b] = 0x14;
    ...
          memcpy(__dest,
             "abcdefghijklmnopqrstuvwxyz_{}0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZGive me the flag? \nYou\'ve entered \nError: \nIndex out  of bounds()/rustc/84c898d65adf2f39a5a98507f1fe0ce10a2b8dbc/library/core/src/str/pattern.rs"
             ,0x41);
    }
    ...
        do {
      uVar3 = (uint)*(byte *)(unaff_r11 + uVar7);
      if (uVar3 == *unaff_r6) {
        uVar3 = count_leading_zeroes(0x0);
        iVar5 = 0x0;
LAB_0001624c:
        iVar5 = iVar5 + (uVar3 >> 0x5 ^ 0x1);
      }
      else {
        if (uVar3 == unaff_r6[0x1]) {
          uVar3 = count_leading_zeroes(0x0);
          iVar5 = 0x1;
          goto LAB_0001624c;
        }
        if (uVar3 == unaff_r6[0x2]) {
          uVar3 = count_leading_zeroes(0x0);
          iVar5 = 0x2;
          goto LAB_0001624c;
        }
        if (uVar3 == unaff_r6[0x3]) {
          uVar3 = count_leading_zeroes(0x0);

arm & rust 바이너리, 기드라로 열면 디컴이 잘 보인다. puVar1 배열의 값을 인덱스로 문자열 가져와서 단순비교. arm & rust binary, if you open it with Ghidra, you can see pseudo code well. Simple comparison by getting the value of puVar1 array as a index of string at __dest

1
2
3
4
5
6
7
8
9
puVar1 = [0]*100
puVar1[0x25] = 0x7;
...
puVar1[0x1] = 0x2;
puVar1[0x2] = 0x13;

s = """abcdefghijklmnopqrstuvwxyz_{}0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"""
for i in range(len(puVar1)):
    print(s[puVar1[i]], end="")

jctf{n0_vM_just_plain_0ld_ru5tb3rry_ch4ll}

manGO

Analysis while watching assembly and decompilation with ida Encryption proceeds in the following order in main.main

  1. main.conv xor with 0x37, concatenates each string after converting to octal
  2. main.gen_table Creating a table using math/rand
  3. main.shuffle shuffle
  4. main.mangoify Converts each shuffled string to binary number, converts 1 -> O, and connects each character with o

table 만 알아내면 쉽게 복호화할 수 있지만 테이블값을 모른다. 모든 table 을 생성해보기에는 경우의수가 너무 많다. 디버깅해보면, seed 값으로 0x100000 이하의 랜덤한 소수를 사용하는 것을 볼 수 있다. 이정도면 빠른 시간안에 찾을 수 있으므로, 복호화했을 때 flag format 인 just 으로 시작하는 문자열을 출력했다

It can be easily decrypted if only the table is known, but the table value is unknown. There are too many cases to create all tables. When debugging, you can see that a random prime number less than 0x100000 is used as the seed value. This can be found quickly, so when decrypted, a string starting with just, which is a flag format, was output.

1
2
3
4
5
6
7
8
9
10
11
12
13
f = open("./output.txt").read()

def unbin(data):
    data = data.replace("O","1")
    data = data.split("o")
    data = list(map(lambda x:str(int(x[2:],2)),data))
    return ''.join(data)

data = unbin(f)
out = "list := []int{"
out += ','.join(data)
out += "}"
print(out)

list := []int{3,0,0,6,0,3,2,1,4,0,0,3,0,1,0,3,0,2,0,5,0,6,1,5,0,0,2,4,1,4,1,6,2,1,1,7,2,0,1,1,5,0,1,1,1,2,1,1,1,0,0,1,7,0,3,1,1,1,1,0,0,7,1,5,4,1,0,2,3,1,0,5,1,1,6,0,6,2,1,0,3,2,0,0,4,6,1,5,2,7,0,3,1,7,0,7,3,1,1,7,1,3,4,1,1} ( used python because I don’t know golang )

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main

import (
	"fmt"
	"math/rand"
	"strconv"
	"strings"
)

func main() {
	var i int64 = 0
	list := []int{3, 0, 0, 6, 0, 3, 2, 1, 4, 0, 0, 3, 0, 1, 0, 3, 0, 2, 0, 5, 0, 6, 1, 5, 0, 0, 2, 4, 1, 4, 1, 6, 2, 1, 1, 7, 2, 0, 1, 1, 5, 0, 1, 1, 1, 2, 1, 1, 1, 0, 0, 1, 7, 0, 3, 1, 1, 1, 1, 0, 0, 7, 1, 5, 4, 1, 0, 2, 3, 1, 0, 5, 1, 1, 6, 0, 6, 2, 1, 0, 3, 2, 0, 0, 4, 6, 1, 5, 2, 7, 0, 3, 1, 7, 0, 7, 3, 1, 1, 7, 1, 3, 4, 1, 1}
	for i = 0; i < 0x100000; i++ {
		rand.Seed(i)
		m := make(map[int]int)
		dup := make([]int, 0)
		j := 0
		for j < len(list) {
			rnd := rand.Intn(len(list))
			flag := 0
			for _, v := range dup {
				if v == rnd {
					flag = 1
				}
			}
			if flag == 1 {
				continue
			} else {
				dup = append(dup, rnd)
				m[j] = rnd
				j++
			}
		}
		unshuffled := make([]int, len(list))
		for k, _ := range m {
			unshuffled[m[k]] = list[k]
		}
		strs := make([]string, len(unshuffled))
		for i, number := range unshuffled {
			strs[i] = strconv.Itoa(number)
		}
		result := strs[0]
		for _, string := range strs[1:] {
			result += string
		}
		chunks := make([]string, 0)
		for j := 0; j < len(result); j += 3 {
			chunk, _ := strconv.ParseInt(result[j:j+3], 8, 8)
			chunk ^= 0x37
			if chunk < 32 || chunk > 126 {
				break
			}
			chunks = append(chunks, string(chunk))
		}
		if len(chunks) == len(list)/3 {
			if chunks[0] == "j" && chunks[1] == "u" && chunks[2] == "s" {
				fmt.Println(strings.Join(chunks, ""))
			}
		}
	}
}

( that code is generated by chatGPT.. I don’t know about golang )

justCTF{1_h0pe_y0u_l1ke_mang0s_t00}

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