-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feat] support capture zsh command (#683)
- Loading branch information
Showing
10 changed files
with
546 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
//go:build !androidgki | ||
// +build !androidgki | ||
|
||
// Copyright 2022 CFC4N <cfc4n.cs@gmail.com>. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package cmd | ||
|
||
import ( | ||
"github.com/gojue/ecapture/user/config" | ||
"github.com/gojue/ecapture/user/module" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var zc = config.NewZshConfig() | ||
|
||
// zshCmd represents the zsh command | ||
var zshCmd = &cobra.Command{ | ||
Use: "zsh", | ||
Short: "capture zsh command", | ||
Long: `eCapture capture zsh commands for zsh security audit, | ||
Auto find the zsh of the current env as the capture target.`, | ||
Run: zshCommandFunc, | ||
} | ||
|
||
func init() { | ||
zshCmd.PersistentFlags().StringVar(&zc.Zshpath, "zsh", "", "$SHELL file path, eg: /bin/zsh , will automatically find it from $ENV default.") | ||
zshCmd.Flags().IntVarP(&zc.ErrNo, "errnumber", "e", module.ZshErrnoDefault, "only show the command which exec reulst equals err number.") | ||
rootCmd.AddCommand(zshCmd) | ||
|
||
// Here you will define your flags and configuration settings. | ||
|
||
// Cobra supports Persistent Flags which will work for this command | ||
// and all suzcommands, e.g.: | ||
// zshCmd.PersistentFlags().String("foo", "", "A help for foo") | ||
|
||
// Cobra supports local flags which will only run when this command | ||
// is called directly, e.g.: | ||
// zshCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") | ||
} | ||
|
||
// zshCommandFunc executes the "zsh" command. | ||
func zshCommandFunc(command *cobra.Command, args []string) { | ||
runModule(module.ModuleNameZsh, zc) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#include "ecapture.h" | ||
|
||
struct event { | ||
u32 type; | ||
u32 pid; | ||
u32 uid; | ||
char comm[TASK_COMM_LEN]; | ||
u8 line[MAX_DATA_SIZE_ZSH]; | ||
}; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY); | ||
__uint(key_size, sizeof(u32)); | ||
__uint(value_size, sizeof(u32)); | ||
__uint(max_entries, 1024); | ||
} events SEC(".maps"); | ||
|
||
// Force emitting struct event into the ELF. | ||
const struct event *unused __attribute__((unused)); | ||
|
||
SEC("uretprobe/zsh_zleentry") | ||
int uretprobe_zsh_zleentry(struct pt_regs *ctx) { | ||
u64 pid_tgid = bpf_get_current_pid_tgid(); | ||
u32 pid = pid_tgid >> 32; | ||
u64 current_uid_gid = bpf_get_current_uid_gid(); | ||
u32 uid = current_uid_gid; | ||
#ifndef KERNEL_LESS_5_2 | ||
// if target_ppid is 0 then we target all pids | ||
if (target_pid != 0 && target_pid != pid) { | ||
return 0; | ||
} | ||
if (target_uid != 0 && target_uid != uid) { | ||
return 0; | ||
} | ||
#endif | ||
struct event event = {}; | ||
event.pid = pid; | ||
event.uid = uid; | ||
event.type = ZSH_EVENT_TYPE_READLINE; | ||
bpf_get_current_comm(&event.comm, sizeof(event.comm)); | ||
bpf_probe_read_user(&event.line, sizeof(event.line),(void *)PT_REGS_RC(ctx)); | ||
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(struct event)); | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
//go:build !androidgki | ||
// +build !androidgki | ||
|
||
// Copyright 2022 CFC4N <cfc4n.cs@gmail.com>. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package config | ||
|
||
import ( | ||
"debug/elf" | ||
"encoding/json" | ||
"fmt" | ||
"os" | ||
"strings" | ||
) | ||
|
||
// ZshConfig | ||
type ZshConfig struct { | ||
BaseConfig | ||
Zshpath string `json:"zshpath"` //zsh的文件路径 | ||
ErrNo int | ||
ElfType uint8 // | ||
ReadlineFuncName string | ||
} | ||
|
||
func NewZshConfig() *ZshConfig { | ||
config := &ZshConfig{} | ||
config.PerCpuMapSize = DefaultMapSizePerCpu | ||
return config | ||
} | ||
|
||
func (zc *ZshConfig) Check() error { | ||
var binaryPath string | ||
switch zc.ElfType { | ||
case ElfTypeBin: | ||
binaryPath = zc.Zshpath | ||
default: | ||
binaryPath = "/bin/zsh" | ||
} | ||
|
||
file, err := elf.Open(binaryPath) | ||
if err != nil { | ||
return err | ||
} | ||
defer file.Close() | ||
|
||
symbols, err := file.DynamicSymbols() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
zc.ReadlineFuncName = "zleentry" | ||
|
||
targetSymbol := "zleentry" | ||
for _, sym := range symbols { | ||
if sym.Name == targetSymbol { | ||
return nil | ||
} | ||
} | ||
|
||
return fmt.Errorf("symbol [%s] not found in [%s]", targetSymbol, binaryPath) | ||
} | ||
|
||
func (zc *ZshConfig) checkElf() error { | ||
//如果配置 zsh的地址,且存在,则直接返回 | ||
if zc.Zshpath != "" || len(strings.TrimSpace(zc.Zshpath)) > 0 { | ||
_, e := os.Stat(zc.Zshpath) | ||
if e != nil { | ||
return e | ||
} | ||
zc.ElfType = ElfTypeBin | ||
return nil | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (zc *ZshConfig) Bytes() []byte { | ||
b, e := json.Marshal(zc) | ||
if e != nil { | ||
return []byte{} | ||
} | ||
return b | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
//go:build !androidgki | ||
// +build !androidgki | ||
|
||
// Copyright 2022 CFC4N <cfc4n.cs@gmail.com>. All Rights Reserved. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package event | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"fmt" | ||
"strings" | ||
|
||
"golang.org/x/sys/unix" | ||
) | ||
|
||
/* | ||
u8 type; | ||
u32 pid; | ||
u32 uid; | ||
u8 line[MAX_DATA_SIZE_BASH]; | ||
u32 retval; | ||
char comm[TASK_COMM_LEN]; | ||
*/ | ||
|
||
const MaxDataSizeZsh = 256 | ||
|
||
type ZshEvent struct { | ||
eventType EventType | ||
ZshType uint32 `json:"zsh_type"` | ||
Pid uint32 `json:"pid"` | ||
Uid uint32 `json:"uid"` | ||
Comm [16]byte `json:"Comm"` | ||
Line [MaxDataSizeZsh]uint8 `json:"line"` | ||
} | ||
|
||
func (be *ZshEvent) Decode(payload []byte) (err error) { | ||
buf := bytes.NewBuffer(payload) | ||
if err = binary.Read(buf, binary.LittleEndian, &be.ZshType); err != nil { | ||
return | ||
} | ||
if err = binary.Read(buf, binary.LittleEndian, &be.Pid); err != nil { | ||
return | ||
} | ||
if err = binary.Read(buf, binary.LittleEndian, &be.Uid); err != nil { | ||
return | ||
} | ||
if err = binary.Read(buf, binary.LittleEndian, &be.Comm); err != nil { | ||
return | ||
} | ||
if err = binary.Read(buf, binary.LittleEndian, &be.Line); err != nil { | ||
return | ||
} | ||
return nil | ||
} | ||
|
||
func (be *ZshEvent) String() string { | ||
s := fmt.Sprintf("PID:%d, UID:%d, \tComm:%s, \tLine:\n%s", be.Pid, be.Uid, be.Comm, strings.TrimSuffix(unix.ByteSliceToString(be.Line[:]), "\n")) | ||
return s | ||
} | ||
|
||
func (be *ZshEvent) StringHex() string { | ||
s := fmt.Sprintf("PID:%d, UID:%d, \tComm:%s, \tLine:\n%s,", be.Pid, be.Uid, be.Comm, be.Line) | ||
return s | ||
} | ||
|
||
func (be *ZshEvent) Clone() IEventStruct { | ||
event := new(ZshEvent) | ||
event.eventType = EventTypeModuleData | ||
return event | ||
} | ||
|
||
func (be *ZshEvent) EventType() EventType { | ||
return be.eventType | ||
} | ||
|
||
func (be *ZshEvent) GetUUID() string { | ||
return fmt.Sprintf("%d_%d_%s", be.Pid, be.Uid, be.Comm) | ||
} | ||
|
||
func (be *ZshEvent) Payload() []byte { | ||
return be.Line[:] | ||
} | ||
|
||
func (be *ZshEvent) PayloadLen() int { | ||
return len(be.Line) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.