Skip to content

Commit 750cdfc

Browse files
committed
Expand time formats supported by chtimes
1 parent 0f128a2 commit 750cdfc

3 files changed

Lines changed: 102 additions & 12 deletions

File tree

client/command/filesystem/chtimes.go

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ package filesystem
1919

2020
import (
2121
"context"
22+
"fmt"
23+
"strconv"
2224
"time"
2325

2426
"github.com/bishopfox/sliver/client/console"
@@ -28,48 +30,113 @@ import (
2830
"google.golang.org/protobuf/proto"
2931
)
3032

33+
const chtimesDefaultLayout = "2006-01-02 15:04:05"
34+
35+
type chtimesTimeFormat struct {
36+
name string
37+
parse func(string) (int64, error)
38+
}
39+
40+
func chtimesParseUnixSeconds(value string) (int64, error) {
41+
parsed, err := strconv.ParseInt(value, 10, 64)
42+
if err != nil {
43+
return 0, err
44+
}
45+
return parsed, nil
46+
}
47+
48+
func chtimesParseUnixMillis(value string) (int64, error) {
49+
parsed, err := strconv.ParseInt(value, 10, 64)
50+
if err != nil {
51+
return 0, err
52+
}
53+
return time.UnixMilli(parsed).Unix(), nil
54+
}
55+
56+
func chtimesParseLayout(layout string) func(string) (int64, error) {
57+
return func(value string) (int64, error) {
58+
parsed, err := time.Parse(layout, value)
59+
if err != nil {
60+
return 0, err
61+
}
62+
return parsed.Unix(), nil
63+
}
64+
}
65+
66+
func chtimesFormatFromFlags(cmd *cobra.Command) (chtimesTimeFormat, error) {
67+
formatFlags := []struct {
68+
flag string
69+
format chtimesTimeFormat
70+
}{
71+
{flag: "unix", format: chtimesTimeFormat{name: "unix", parse: chtimesParseUnixSeconds}},
72+
{flag: "unix-ms", format: chtimesTimeFormat{name: "unix-ms", parse: chtimesParseUnixMillis}},
73+
{flag: "rfc3339", format: chtimesTimeFormat{name: "rfc3339", parse: chtimesParseLayout(time.RFC3339)}},
74+
{flag: "rfc1123", format: chtimesTimeFormat{name: "rfc1123", parse: chtimesParseLayout(time.RFC1123)}},
75+
}
76+
77+
var selected *chtimesTimeFormat
78+
selectedFlag := ""
79+
for _, candidate := range formatFlags {
80+
enabled, _ := cmd.Flags().GetBool(candidate.flag)
81+
if !enabled {
82+
continue
83+
}
84+
if selected != nil {
85+
return chtimesTimeFormat{}, fmt.Errorf("only one time format flag can be used (--%s and --%s are both set)", selectedFlag, candidate.flag)
86+
}
87+
selected = &candidate.format
88+
selectedFlag = candidate.flag
89+
}
90+
91+
if selected == nil {
92+
return chtimesTimeFormat{name: "datetime", parse: chtimesParseLayout(chtimesDefaultLayout)}, nil
93+
}
94+
95+
return *selected, nil
96+
}
97+
3198
// ChtimesCmd - Change the access and modified time of a file on the remote file system.
3299
func ChtimesCmd(cmd *cobra.Command, con *console.SliverClient, args []string) {
33100
session, beacon := con.ActiveTarget.GetInteractive()
34101
if session == nil && beacon == nil {
35102
return
36103
}
37-
// DateTime layout (https://pkg.go.dev/time)
38-
layout := "2006-01-02 15:04:05"
39104
filePath := args[0]
40105

41106
if filePath == "" {
42107
con.PrintErrorf("Missing parameter: file or directory name\n")
43108
return
44109
}
45110

46-
atime := args[1]
111+
format, err := chtimesFormatFromFlags(cmd)
112+
if err != nil {
113+
con.PrintErrorf("%s\n", err)
114+
return
115+
}
47116

117+
atime := args[1]
48118
if atime == "" {
49119
con.PrintErrorf("Missing parameter: Last accessed time id\n")
50120
return
51121
}
52122

53-
t_a, err := time.Parse(layout, atime)
123+
unixAtime, err := format.parse(atime)
54124
if err != nil {
55-
con.PrintErrorf("%s\n", err)
125+
con.PrintErrorf("Invalid access time (%s): %s\n", format.name, err)
56126
return
57127
}
58-
unixAtime := t_a.Unix()
59128

60129
mtime := args[2]
61-
62130
if mtime == "" {
63131
con.PrintErrorf("Missing parameter: Last modified time id\n")
64132
return
65133
}
66134

67-
t_b, err := time.Parse(layout, mtime)
135+
unixMtime, err := format.parse(mtime)
68136
if err != nil {
69-
con.PrintErrorf("%s\n", err)
137+
con.PrintErrorf("Invalid modified time (%s): %s\n", format.name, err)
70138
return
71139
}
72-
unixMtime := t_b.Unix()
73140

74141
chtimes, err := con.Rpc.Chtimes(context.Background(), &sliverpb.ChtimesReq{
75142
Request: con.ActiveTarget.Request(cmd),

client/command/help/long-help.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ var (
6464
consts.UploadStr: uploadHelp,
6565
consts.MkdirStr: mkdirHelp,
6666
consts.RmStr: rmHelp,
67+
consts.ChtimesStr: chtimesHelp,
6768
consts.ProcdumpStr: procdumpHelp,
6869
consts.ElevateStr: elevateHelp,
6970
consts.RunAsStr: runAsHelp,
@@ -299,6 +300,24 @@ On Windows, escaping is disabled. Instead, '\\' is treated as path separator.
299300
rmHelp = `[[.Bold]]Command:[[.Normal]] rm [remote path]
300301
[[.Bold]]About:[[.Normal]] Delete a remote file or directory.`
301302

303+
chtimesHelp = `[[.Bold]]Command:[[.Normal]] chtimes [--unix | --unix-ms | --rfc3339 | --rfc1123] <path> <atime> <mtime>
304+
[[.Bold]]About:[[.Normal]] Change access and modification times on a file (timestomp).
305+
306+
[[.Bold]][[.Underline]]Time Formats[[.Normal]]
307+
Default (datetime): "2006-01-02 15:04:05"
308+
--unix: 1704067200
309+
--unix-ms: 1704067200000
310+
--rfc3339: 2024-01-01T00:00:00Z
311+
--rfc1123: Mon, 02 Jan 2006 15:04:05 MST
312+
313+
[[.Bold]][[.Underline]]Examples[[.Normal]]
314+
chtimes /tmp/file "2024-01-01 12:34:56" "2024-01-01 12:35:56"
315+
chtimes --unix /tmp/file 1704112496 1704112556
316+
chtimes --unix-ms /tmp/file 1704112496000 1704112556000
317+
chtimes --rfc3339 /tmp/file 2024-01-01T12:34:56Z 2024-01-01T12:35:56Z
318+
chtimes --rfc1123 /tmp/file "Mon, 02 Jan 2006 15:04:05 MST" "Mon, 02 Jan 2006 16:04:05 MST"
319+
`
320+
302321
catHelp = `[[.Bold]]Command:[[.Normal]] cat <remote path>
303322
[[.Bold]]About:[[.Normal]] Cat a remote file to stdout.`
304323

client/command/privilege/commands.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,15 @@ func Commands(con *console.SliverClient) []*cobra.Command {
150150
}
151151
flags.Bind("", false, chtimesCmd, func(f *pflag.FlagSet) {
152152
f.Int64P("timeout", "t", flags.DefaultTimeout, "grpc timeout in seconds")
153+
f.Bool("unix", false, "interpret timestamps as Unix seconds")
154+
f.Bool("unix-ms", false, "interpret timestamps as Unix milliseconds")
155+
f.Bool("rfc3339", false, "interpret timestamps as RFC3339")
156+
f.Bool("rfc1123", false, "interpret timestamps as RFC1123")
153157
})
154158
carapace.Gen(chtimesCmd).PositionalCompletion(
155159
carapace.ActionValues().Usage("path to file to change access timestamps"),
156-
carapace.ActionValues().Usage("last accessed time in DateTime format, i.e. 2006-01-02 15:04:05"),
157-
carapace.ActionValues().Usage("last modified time in DateTime format, i.e. 2006-01-02 15:04:05"),
160+
carapace.ActionValues().Usage("last accessed time (default: 2006-01-02 15:04:05; see --help for format flags)"),
161+
carapace.ActionValues().Usage("last modified time (default: 2006-01-02 15:04:05; see --help for format flags)"),
158162
)
159163

160164
getprivsCmd := &cobra.Command{

0 commit comments

Comments
 (0)