CVE-2020-25989: Improper Link Resolution Before File Access ('Link Following') (CWE-59)
value: Privilege escalation via arbitrary file write in pritunl electron client 1.0.1116.6 through v1.2.2550.20. Successful exploitation of the issue may allow an attacker to execute code on the effected system with root privileges.
CWE description: The product attempts to access a file based on the filename, but it does not properly prevent that filename from identifying a link or shortcut that resolves to an unintended resource.
CVSS v3 base score: 7.8
Published: 2020-11-19T21:15Z
Repository: https://github.com/pritunl/pritunl-client-electron
Language: Go
Files changed: service/profile/profile.go, service/utils/utils.go
Commit date: 2020-08-31 05:55:29 -0400
Commit message: Remove file before io write file

Diff: diff --git a/service/profile/profile.go b/service/profile/profile.go
index b6362cc..ba0bc05 100644
--- a/service/profile/profile.go
+++ b/service/profile/profile.go
@@ -212,10 +212,11 @@ func (p *Profile) write() (pth string, err error) {
 		return
 	}
 
 	pth = filepath.Join(rootDir, p.Id)
 
+	_ = os.Remove(pth)
 	err = ioutil.WriteFile(pth, []byte(p.Data), os.FileMode(0600))
 	if err != nil {
 		err = &WriteError{
 			errors.Wrap(err, "profile: Failed to write profile"),
 		}
@@ -259,10 +260,11 @@ func (p *Profile) writeUp() (pth string, err error) {
 		break
 	default:
 		panic("profile: Not implemented")
 	}
 
+	_ = os.Remove(pth)
 	err = ioutil.WriteFile(pth, []byte(script), os.FileMode(0755))
 	if err != nil {
 		err = &WriteError{
 			errors.Wrap(err, "profile: Failed to write up script"),
 		}
@@ -306,10 +308,11 @@ func (p *Profile) writeDown() (pth string, err error) {
 		break
 	default:
 		panic("profile: Not implemented")
 	}
 
+	_ = os.Remove(pth)
 	err = ioutil.WriteFile(pth, []byte(script), os.FileMode(0755))
 	if err != nil {
 		err = &WriteError{
 			errors.Wrap(err, "profile: Failed to write down script"),
 		}
@@ -325,10 +328,11 @@ func (p *Profile) writeBlock() (pth string, err error) {
 		return
 	}
 
 	pth = filepath.Join(rootDir, p.Id+"-block.sh")
 
+	_ = os.Remove(pth)
 	err = ioutil.WriteFile(pth, []byte(blockScript), os.FileMode(0755))
 	if err != nil {
 		err = &WriteError{
 			errors.Wrap(err, "profile: Failed to write block script"),
 		}
@@ -466,10 +470,11 @@ func (p *Profile) writeAuth() (pth string, err error) {
 		password = "<%=RSA_ENCRYPTED=%>" + ciphertext64
 	}
 
 	pth = filepath.Join(rootDir, p.Id+".auth")
 
+	_ = os.Remove(pth)
 	err = ioutil.WriteFile(pth, []byte(username+"\n"+password+"\n"),
 		os.FileMode(0600))
 	if err != nil {
 		err = &WriteError{
 			errors.Wrap(err, "profile: Failed to write profile auth"),
@@ -509,10 +514,11 @@ func (p *Profile) writeConfWgLinux() (pth string, err error) {
 		return
 	}
 
 	pth = filepath.Join(rootDir, p.Id+".key")
 
+	_ = os.Remove(pth)
 	err = ioutil.WriteFile(
 		pth,
 		[]byte(p.PrivateKeyWg+"\n"),
 		os.FileMode(0600),
 	)
@@ -597,11 +603,11 @@ func (p *Profile) writeConfWgQuick(data *WgConf) (pth string, err error) {
 		}
 	}
 
 	pth = filepath.Join(rootDir, p.Iface+".conf")
 
-	os.Remove(pth)
+	_ = os.Remove(pth)
 	err = ioutil.WriteFile(
 		pth,
 		[]byte(output.String()),
 		os.FileMode(0600),
 	)
diff --git a/service/utils/utils.go b/service/utils/utils.go
index 9ac7e38..79da8ad 100644
--- a/service/utils/utils.go
+++ b/service/utils/utils.go
@@ -912,10 +912,11 @@ func PidInit() (err error) {
 		if pidStr != "" {
 			pid, _ = strconv.Atoi(pidStr)
 		}
 	}
 
+	_ = os.Remove(pth)
 	err = ioutil.WriteFile(
 		pth,
 		[]byte(strconv.Itoa(os.Getpid())),
 		0644,
 	)

Vulnerable code: 	os.Remove(pth)
Fixed code: 	_ = os.Remove(pth)
	_ = os.Remove(pth)
	_ = os.Remove(pth)
	_ = os.Remove(pth)
	_ = os.Remove(pth)
	_ = os.Remove(pth)
	_ = os.Remove(pth)
	_ = os.Remove(pth)