《bash 网络安全运维》 第五章

数据收集

数据几乎是所有安全运维防御的命脉。
防御操作相关的数据

数据 数据描述 数据位置
日志 系统历史活动和状态的详细信息,主要的日志文件包括 Web 和 DNS 服务器日志、路由器、防火墙、入侵检测系统日志和应用程序日志 在 Linux 中,大多数日志文件位于 /var/log 目录中。在 Windows 系统中,日志可以在事件日志中找到。
命令历史记录 最近执行的命令列表 在 Linux 中,可以通过执行 echo $HISTFILE 找到历史文件的位置。该文件通常位于用户的主目录 .bash_history 中。
临时文件 最近访问、保存和处理的各种用户和系统文件 在 Windows 中,可以在 c:\windows\temp 和 %USERPROFILE%\AppData\Local 中找到临时文件。在 Linux 中,临时文件通常位于 /tmp 和 /var/tmp 中,还可以使用 echo $TMPDIR 命令找到 Linux 临时目录。
用户数据 文档、图片和其他用户创建的文件 在 Linux 系统中用户文件通常位于 /home/,Windows 系统位于 c:\Users\
浏览器历史记录 Windows 注册表 用户最近访问的网页,分层式数据库,存储对 Windows 系统和应用程序的操作至关重要的设置和其他数据 根据操作系统和浏览器的不同,差异很大。windows 注册表。

命令

cut

cut 是一个用于提取文件中特定内容的命令。它逐行读取提供的输入文件,并根据指定的分隔符解析该行。
常见命令选项:

  1. -c:指定要提取的字符。
  2. -d:指定用作分隔符的字符。默认情况下,分隔符是制表符。
  3. -f:指定要提取的字段

以文件 cutfile.txt 为例。

12/05/2017 192.168.10.14 test.html
12/30/2017 192.168.10.185 login.html

运行命令:

pwnki@LAPTOP-KETPO6R7:~/project$ cut -d ' ' -f2 cutfile.txt
192.168.10.14
192.168.10.185
pwnki@LAPTOP-KETPO6R7:~/project$

注:cut 命令把每个分隔符看作分隔了一个字段。

file

file 命令用于识别给定文件的文件类型。
常见命令选项:

  1. -f:从一个给定的文件中读取需要分析的文件列表。
  2. -k:不要在第一个匹配处就停止,要列出文件类型的所有匹配。
  3. -z:检测压缩文件。

示例:

pwnki@LAPTOP-KETPO6R7:~/project$ file cutfile.txt
cutfile.txt: ASCII text
pwnki@LAPTOP-KETPO6R7:~/project$

head 命令显示文件的前几行或者前几个字节。默认情况下,head 显示前 10 行。

常见命令选项:

  1. -n:指定要输出的行数。
  2. -c:指定要输出的字节数。

reg

reg 命令用于操作 Windows XP 及更高版本中的 Windows 注册表。

常见命令参数:

  1. add:向注册表中添加条目。
  2. export:将指定的注册表条目复制到文件中。
  3. query:返回指定路径下的子健列表。

列出 HKEY_LOCAL_MACHINE 中的所有根建:

C:\Users\86189>reg query HKEY_LOCAL_MACHINE

HKEY_LOCAL_MACHINE\BCD00000000
HKEY_LOCAL_MACHINE\HARDWARE
HKEY_LOCAL_MACHINE\SAM
HKEY_LOCAL_MACHINE\SECURITY
HKEY_LOCAL_MACHINE\SOFTWARE
HKEY_LOCAL_MACHINE\SYSTEM

C:\Users\86189>

wevtutil

wevtutil 用于查看和管理 Windows 环境中的系统日志。
常见命令参数:

  1. -el:列举可用的日志文件
  2. -qe:查询日志文件中的事件

常见命令选项:

  1. /c:指定要读取的事件的最大数量。
  2. /f:将输出格式化为文本或 XML 。
  3. /rd:读取方向——如果设置为 true,它将首先读取最近的日志。

列出所有可用的日志文件:

C:\Users\86189>wevtutil el
AMSI/Debug
AirSpaceChannel
Analytic
Application
DirectShowFilterGraph
DirectShowPluginControl
Els_Hyphenation/Analytic
EndpointMapper
FirstUXPerf-Analytic
ForwardedEvents
General Logging
……

查看系统日志中的最新文件:

C:\Users\86189>wevtutil qe System /c:1 /rd:true
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'><System><Provider Name='Service Control Manager' Guid='{555908d1-a6d7-4695-8e1e-26931d2012f4}' EventSourceName='Service Control Manager'/><EventID Qualifiers='16384'>7040</EventID><Version>0</Version><Level>4</Level><Task>0</Task><Opcode>0</Opcode><Keywords>0x8080000000000000</Keywords><TimeCreated SystemTime='2021-01-13T11:15:03.4012990Z'/><EventRecordID>9285</EventRecordID><Correlation/><Execution ProcessID='980' ThreadID='6876'/><Channel>System</Channel><Computer>LAPTOP-KETPO6R7</Computer><Security UserID='S-1-5-18'/></System><EventData><Data Name='param1'>Background Intelligent Transfer Service</Data><Data Name='param2'>按需启动</Data><Data Name='param3'>自动启动</Data><Data Name='param4'>BITS</Data></EventData></Event>

C:\Users\86189>

收集系统信息

使用 SSH 远程执行指令

你想要的数据可能并不是总是在本地可用。你可能需要连接到远程系统,如 Web、FTP 或 SSH 服务器,以获得所需的数据。
在远程系统上运行命令并将输出重定向到本地系统上的文件:

ssh myserver ps > /tmp/ps.out

在远程系统上运行命令并将输出重定向到远程系统上的文件:

ssh myserver ps \> /tmp/ps.out

也可以使用驻留在本地系统中的脚本,并使用 SSH 在远程系统上运行它们:

ssh myserver bash < ./osdetect.sh

收集 Linux 日志文件

Linux 系统的日志文件通常存储在 /var/log/ 目录中。
使用 tar 命令可以将日志文件收集到单个文件中:

tar -czf ${HOSTNAME}_logs.tar.gz /var/log/
  1. -c:用于创建存档文件。
  2. -z:用于压缩文件。
  3. -f:用于指定输出文件。

Linux 日志文件:
|日志位置|描述|
|/var/log/apache2/|Apache Web 服务器的访问和错误日志|
|/var/log/auth/log|关于用户登录、授权访问和远程身份验证的信息|
|/var/log/kern.log|内核日志|
|/var/log/messages|通用非关键系统信息|
|/var/log/syslog|通用系统日志|

注:要查找给定系统的日志文件存储位置的更多信息,可以查看 /etc/syslog.conf 或 /etc/rsyslog.conf

收集 Windows 日志文件

winlogs.sh 脚本使用 wevtutil el 参数列出所有可能的日志,然后使用 epl 参数将每个日志导出到一个文件。

#!/bin/sh -
#
# Cybersecurity Ops with bash
# winlogs.sh
#
# Description:
# Gather copies of Windows log files
#
# Usage:
# winlogs.sh [-z]
#   -z Tar and zip the output

TGZ=0
if (( $# > 0 ))                                      #<1>
then
    if [[ ${1:0:2} == '-z' ]]                        #<2>
    then
        TGZ=1 # tgz flag to tar/zip the log files
        shift
    fi
fi
SYSNAM=$(hostname)
LOGDIR=${1:-/tmp/${SYSNAM}_logs}                     #<3>
mkdir -p $LOGDIR                                     #<4>
cd ${LOGDIR} || exit -2

wevtutil el | while read ALOG                        #<5>
do 
    ALOG="${ALOG%$'\r'}"                             #<6>
    echo "${ALOG}:"                                  #<7>
    SAFNAM="${ALOG// /_}"                            #<8>
    SAFNAM="${SAFNAM//\//-}"                         
    wevtutil epl "$ALOG" "${SYSNAM}_${SAFNAM}.evtx"
done

if (( TGZ == 1 ))                                    #<9>
then
    tar -czvf ${SYSNAM}_logs.tgz *.evtx              #<10>
fi
  1. 脚本从简单的初始化开始,然后是一个 if 语句,该语句检查是否向脚本提供了参数。
  2. 该检查接收字符串(偏移量为 0 字节)开头的第一个参数($1)的子字符串,长度为 2 字节。如果参数是 -z ,我们将设置一个标志。脚本还执行了一个 shift 来略过该参数。如果有第二个参数的话,现在就是第一个了。如果有第三个参数的话,就变成第二个,以此类推。
  3. 如果用户想为日志指定一个位置,可以将其指定为脚本的参数。可选的 -z 参数已经被忽略过,所以用户提供的路径现在都将是第一个参数。如果命令行上没有提供值,大括号内的表达式将返回一个默认值,如负号右侧所示。
  4. mkdir 的 -p 选项将创建目录和任何中间目录。如果目录存在,它也不会给出错误消息。在下一行,我们调用 cd 使该目录成为当前目录,日志文件将保存在其中。如果 cd 出现故障,将带着错误代码退出程序。
  5. 我们调用 wevtutil el 来列出所有可能的日志文件名。这些日志文件名通过管道输出到一个 while 虚幻,该循环每次读取一行(一个日志文件名)。
  6. wevtutil 打印的每一行都以换行 “\n” 和回车 “\r” 字符结束。我们使用 % 运算符删除字符串最右侧的字符。为了指定(不可打印的)回车字符,我们使用 “$'string'” 结构将不可打印字符替某些反斜杠转义的字符。因此 \r 的两个字符被 ASCII 13 字符(回车字符)替换。
  7. 我们回显文件名,向用户展示当前进度和正在获取哪个日志文件。
  8. 创建日志文件的文件名中,我们对该文件名进行了两次编辑。首先,由于所提供的日志文件名可能有空格,所以我们用下划线替换空格。用于替换的语法是 “${VAR/old/new}” ,即在 VAR 中对应的字符串中用 new 替换 old 。在 “${VAR//old/new}” 中使用双斜杠是为了将 VAR 字符串中所有的 old 都替换成 new,而不是仅仅是第一个。
    其次,一些 windows 日志文件名中有一个斜杠字符。然而,在 bash 中, “/” 是路径名中使用的目录之间的分隔符,它不应该在文件名中使用,所以我们使用字符 “-” 替换 “/”。
  9. 这是一个用双括号括起来的算数表达式。在这些表达式中, bash 在大多数变量名前面不需要加上 “$” 。对于位置参数,如 “$1” ,仍然需要它,以避免与整数 “1” 混淆。
  10. 在这里,我们使用 tar 将所有 .evtx 文件收集到一个归档文件中。

收集系统信息

如果能够在系统上任意执行命令,则可以使用标准 OS 命令收集关于系统的各种信息。使用的具体命令根据所连接的操作系统而有所不同。
本地数据采集命令

Linux 命令 对等的 Windows Git Bash 命令 目的
uname -a uname -a 操作系统版本信息
cat /proc/cpuinfo systeminfo 显示系统硬件及相关信息
ifconfig ipconfig 网络接口信息
route route print 显示路由表
arp -a arp -a 显示地址解析协议(ARP)表
netstat -a netstat -a 显示网络连接
mount net share 显示文件系统
ps -e tasklist 显示正在运行的进程

例子 cmds.txt

#Linux Command   |MSWin  Bash |XML tag    |Purpose
#----------------+------------+-----------+------------------------------
uname -a         |uname -a    |uname      |O.S. version etc
cat /proc/cpuinfo|systeminfo  |sysinfo    |system hardware and related info
ifconfig         |ipconfig    |nwinterface|Network interface information
ip route         |route print |nwroute    |routing table
arp -a           |arp -a      |nwarp      |ARP table
netstat -a       |netstat -a  |netstat    |network connections
mount            |net share   |diskinfo   |mounted disks
ps -e            |tasklist    |processes  |running processes

脚本 getlocal.sh ,使用 osdetect.sh 来识别操作系统类型,运行适合于不同操作系统类型的不同指令,并将结果记录到文件中。
getlocal.sh

#!/bin/bash -
#
# Cybersecurity Ops with bash
# getlocal.sh
#
# Description: 
# Gathers general system information and dumps it to a file
#
# Usage:
# bash getlocal.sh < cmds.txt
#   cmds.txt is a file with list of commands to run
#

# SepCmds - separate the commands from the line of input
function SepCmds()
{
      LCMD=${ALINE%%|*}                   # <11>
      REST=${ALINE#*|}                    # <12>
      WCMD=${REST%%|*}                    # <13>
      REST=${REST#*|}
      TAG=${REST%%|*}                     # <14>
      
      if [[ $OSTYPE == "MSWin" ]]
      then
         CMD="$WCMD"
      else
         CMD="$LCMD"
      fi
}

function DumpInfo ()
{                                                              # <5>
    printf '<systeminfo host="%s" type="%s"' "$HOSTNAME" "$OSTYPE"
    printf ' date="%s" time="%s">\n' "$(date '+%F')" "$(date '+%T')"
    readarray CMDS                           # <6>
    for ALINE in "${CMDS[@]}"                # <7>
    do
       # ignore comments
       if [[ ${ALINE:0:1} == '#' ]] ; then continue ; fi     # <8>

      SepCmds

      if [[ ${CMD:0:3} == N/A ]]             # <9>
      then
          continue
      else
          printf "<%s>\n" $TAG               # <10>
          $CMD
          printf "</%s>\n" $TAG
      fi
    done
    printf "</systeminfo>\n"
} 

OSTYPE=$(./osdetect.sh)                     # <1>
HOSTNM=$(hostname)                          # <2>
TMPFILE="${HOSTNM}.info"                    # <3>

# gather the info into the tmp file; errors, too
DumpInfo  > $TMPFILE  2>&1                  # <4>

osdetect.sh

#!/bin/sh -
#
# Cybersecurity Ops with bash
# osdetect.sh
#
# Description:
# Distinguish between MS-Windows/Linux/MacOS
#
# Usage: bash osdetect.sh
#   output will be one of: Linux MSWin macOS
#

if type -t wevtutil &> /dev/null
then
    OS=MSWin

elif type -t scutil &> /dev/null
then
    OS=macOS

else
    OS=Linux
fi

echo $OS
  1. 在定义这两个函数后,脚本从这里开始,调用 osdetect.sh 脚本。
  2. 在子 shell 中运行 hostname 程序来提取当前系统的名称。
  3. 使用主机名作为用于存放所有输出的临时文件名的一部分。
  4. 调用 Dumpinfo 函数。
  5. 函数以一个名为 的 XML 标记的输出开始,它的结束将在函数的末尾输出。
  6. bash 中的 readarray 命令将读取所有输入行(知道文件结束或键盘输出 Ctrl-D),在本例中,每一行都是名为 CMDS 的数组中的一个条目。
  7. 这个 for 循环将一次一行地遍历 CMDS 数组每一行。
  8. 这一行使用子字符串操作从变量 ALINE 获取长度为 1、位置为 0 的字符。如果这一行不是注释行,脚本将调用 SepCmds 函数。它将输入行分隔为 CMD 和 TAG,CMD 是 Linux 或 Windows 系统的相应命令。
  9. 再次使用子字符串操作来查找字符串,该操作从字符串的开始查找长度为 3 的子字符串,表示在这个特定的操作系统上没有针对所需信息的适当命令。 continue 语句告诉 bash 跳到循环的下一次迭代。
  10. 这段代码将在调用命令的两边打印上相应的 XML 标记。
  11. 通过删除竖线右侧的所有字符将 Linux 命令从输入文件的一行分离出来。“%%” 表示对变量值的右侧尽可能长地进行匹配,并在该值返回的时候再删除掉。
  12. 这里的 “#” 表示从变量值的左侧删除最短的匹配。因此,它删除了刚刚放到了 LCMD 中的 Linux 命令。
  13. 同样删除竖线右边的所有内容,但这次我们使用的是再前面的语句中进行了修改的 REST 。这将会是我们得到 MSWindows 命令。
  14. 通过替换操作提取 XML 标记。

收集 Windows 注册表

Windows 注册表是一个巨大的配置库,它定义了系统和应用程序的行为方式。特定的注册表键值通常可以用来识别恶意软件和其他入侵的存在。因此,注册表的备份对后续进行系统分析是十分有用的。
使用 Git Bash 将整个 Windows 注册表导出到一个文件:

regedit //E ${HOSTNAME}_reg.bak

如果需要,还可以使用 reg 命令导出注册表的部分或单个子健。使用 Git Bash 导出 HEY_LOCAL_MACHINE:

reg export HKEY_LOCAL_MACHINE $(HOSTNAME)_hklm.bak

索文件系统

按文件名搜索

如在 Linux/home 目录和子目录中搜索包含单词 password 的文件名,可以使用以下脚本:

find /home -name *password*

搜索隐藏文件

在 Linux 中,隐藏文件的名称以句点开头。如查找 /home 目录和子目录中的隐藏文件:

find /home -name '.*'

在 Windows 中,Git Bash 会拦截 dir 命令并执行 ls ,所以我们使用 find 命令的 -exec 选项和 Windows 的 attrib 命令来解决:

find /c -exec attrib '{}' \; | egrep '^.{4}H.*'

find 命令将对它在 c:\ 驱动器上识别出的每个文件执行 Windows attarib 命令,从而打印出每个文件的属性。然后,使用 egrep 命令和正则表达式来识别第五个字符为字符 H 的行,如果设置了文件的隐藏属性,则 egrep 命令执行的结果为真。
如果你想进一步清理输出并只显示文件路径,你可以把 egrep 的输出通过管道输入到 cut 命令中:

find . -exec attrib '{}' \; | egrep '^.{4}H.*' | cut -c22-

-c 选项告诉 cut 使用字符位置号进行截取。 22- 告诉 cut 从字符 22 开始剪取(这是文件路径的开始位置)并持续到行(-)的末尾。

按文件大小搜索

find 命令的 -size 选项可用于根据文件大小查找文件。
如在 /home 目录和子目录下收缩大于 5GB 的文件:

find /home -size +5G

要识别系统中最大的文件,可以将 find 命令与其他命令组合使用:

find / -type f -exec ls -s '{}' \; | sort -n -r | head -5

首先,使用 find / -type f 列出根目录中和根目录下的所有文件。每个文件被传递到 ls -s ,并以块的形式标识其大小。然后将列表按照文件大小从大到小排序,并使用 head 显示前五名。要查看系统中最小的文件,可以使用 tail 替代 head ,或者从 sort 中删除倒序选项 -r 。

按时间搜索

搜索修改不到 5 分钟的 /home 目录及子目录内的文件:

pwnki@LAPTOP-KETPO6R7:~/project$ find /home -mmin -5
/home/pwnki/.vscode-server/extensions/.obsolete

搜索修改不到 24 小时的文件:

pwnki@LAPTOP-KETPO6R7:~/project$ find /home -mtime -1
/home/pwnki/.cache/wslu/integration
/home/pwnki/project
/home/pwnki/project/diqi
/home/pwnki/project/diqi/countem.awk
/home/pwnki/project/diqi/access.log
……

搜索两天前已修改的文件:

find /home -mtime +2

搜索访问不到 24 小时的文件,使用 -atime 选项:

find /home -atime -1

搜索访问不到 24 小时的 /home 目录中的文件,并将每个文件复制到当前工作目录:

find /home -type f -atime -1 -exec cp '{}' ./ \;

-type f 的使用告诉 find 只匹配普通文件,忽略目录和其他特殊文件类型。

搜索内容

grep 命令可以用于搜索文件中的内容。搜索 /home 目录和子目录中包含字符串 password 的文件:

grep -i -r /home -e 'password'

-r 选项递归搜索 /home 下面的所有目录,-i 指定不区分大小写,-e 指定要搜索的正则式模式字符串。
可以将 grep 与 find 结合使用,轻松地将匹配的文件复制到当前工作目录:

find /home -type f -exec grep 'password' '{}' \; -exec cp '{}' . \;

按文件类型搜索

魔数

文件类型 魔数模式(十六进制) 魔数模式(ASCII) 文件偏移(byte)
JPEG FF D8 FF DB 希腊字母 0
DOS 可执行文件 4D 5A MZ 0
可执行和可链接文件 7F 45 4C 46 .ELF 0
Zip 文件 50 4B 03 04 PK.. 0

typesearch.sh

#!/bin/bash -
#
# Cybersecurity Ops with bash
# typesearch.sh
#
# Description: 
# Search the file system for a given file type. It prints out the
# pathname when found.
#
# Usage:
# typesearch.sh [-c dir] [-i] [-R|r] <pattern> <path>
#   -c Copy files found to dir
#   -i Ignore case
#   -R|r Recursively search subdirectories
#   <pattern> File type pattern to search for
#   <path> Path to start search
#

DEEPORNOT="-maxdepth 1"		# just the current dir; default

# PARSE option arguments:
while getopts 'c:irR' opt; do                         # <1>
  case "${opt}" in                                    # <2>
    c) # copy found files to specified directory
	       COPY=YES
	       DESTDIR="$OPTARG"                             # <3>
	       ;;
    i) # ignore u/l case differences in search
	       CASEMATCH='-i'
	       ;;
    [Rr]) # recursive                                 # <4>
        unset DEEPORNOT;;                             # <5>
    *)  # unknown/unsupported option                  # <6>
        # error mesg will come from getopts, so just exit
        exit 2 ;;
  esac
done
shift $((OPTIND - 1))                                 # <7>


PATTERN=${1:-PDF document}                            # <8>
STARTDIR=${2:-.}	# by default start here

find $STARTDIR $DEEPORNOT -type f | while read FN     # <9>
do
    file $FN | egrep -q $CASEMATCH "$PATTERN"          # <10>
    if (( $? == 0 ))   # found one                    # <11>
    then
	        echo $FN
	        if [[ $COPY ]]                               # <12>
	        then
	            cp -p $FN $DESTDIR                       # <13>
	        fi
    fi
done
  1. 此脚本支持通过选项来更改其行为,正如脚本的开头注释中提到的那样。脚本需要解析这些选项,以确定哪些选项已经设置,哪些选项没有设置。对于不仅仅有一个或两个选项的情况,可以使用 shell 内建指令 getopts 。在 while 循环中,我们继续调用 getopts ,直到它返回一个非零值,告诉我们没有更多的选项为止。我们要查找的选项在字符串 c:irR 中提供。无论找到哪个选项,都会在我们提供的变量名 opt 中返回。
  2. 使用的 case 语句是一个多路分支;它将选择与括号前提供的模式匹配的分支执行。
  3. 在支持的选项列表中,c 选项后面有一个冒号(:),这告诉 getopts,用户还将为该选项提供一个参数。对于该脚本来说,这个选项的参数就是目标目录,搜索到的文件将被复制到这个目录。当 getopts 解析一个具有这样参数的选项时,它将该参数放入名为 OPTARG 的变量中,我们将其保存在 DESTDIR 中,因为其他的对 getopts 的调用可能会更改 OPTARG。
  4. 对于这个选项,脚本支持大写 R 或者小写 r。case 语句指定要匹配的模式,而不仅仅是一个简单的字符,因此我们在本例中写了P([Rr]),使用方括号结构表示两个字符都被认为是匹配的。
  5. R、r 选项会使变量 DEEPORNOT 的值进行重新设置,从而导致递归搜索当前目录之下的文件和子目录。在本例中,我们取消了先前设置的变量。当变量稍后作为 $DEEPORNOT 引用时,他将没有值,因此它将从使用它的命令行中消失。
    • 匹配任何东西,类似于 else。
  6. 当我们完成对选项的解析后,我们就可以略过已经用 shift 命令处理的选项。单个 shift 命令可以去掉一个参数,这样第二个参数就变成了第一个,第三个就变成了第二个,以此类推。指定一个像 shift 5 这样的带数字的 shitft 命令,可以去掉前五个参数,这样 $6 就变成了 $1,$7 就变成了 $2,以此类推。调用 getopts 以追踪要处理的第几个参数的值存放在 shell 变量 OPTIND 中。它指向要处理的下一个参数的位置。通过移动这么多个值,我们就去掉了我们解析过的所有选项。在这个 shift 命令执行完后, $1 将指向第一个非选项类参数,无论用户调用脚本时是否提供了选项。
  7. 两个不是选项类型的可能的参数是我们正在搜索的模式和我们想要开始搜索的目录。当我们引用一个 bash 变量时,我们可以添加一个 :- 来表示,“如果该值为空或未设置,则返回此默认值”。我们将 PATTERN 的默认值设置为 PDF document,STARTDIR 的默认值为 .,即在当前目录。
  8. 我们调用 find 命令,告诉它在 $STARTDIR 中启动搜索。注意到 $DEEPORNOT 可能是未设置的,因此没有向 find 命令行中添加任何内容,或者它也可能是默认值 -maxdepth 1,告诉 find 不要搜索当前目录的下级目录。我们在 find 命令中添加了 -type 选项,为的是只找普通文件。找到的文件名称通过管道输入到 while 循环中, while 循环将一次读取一个文件到变量 FN 中。
  9. egrep 的 -q 选项告诉 egrep 命令以静默模式运行,不需要输出任何东西。
  10. $? 结构是一个命令返回的值,成功的结果意味着 egrep 找到了提供的模式。
  11. 这个检测主要是检查 COPY 是否有值。如果 COPY 为空,那么 if 为假。
  12. cp 命令的 -p 选项主要告诉 cp 命令执行时保存文件的模式、所有者和时间戳信息,因为这些信息对你的分析可能很重要。

按消息摘要值搜搜

密码哈希函数时一个单项函数,它将任意长度的输入消息转换为固定长度的消息摘要。常用的哈希算法包括:MD5、SHA-1 和 SHA-256。
hashsearch.sh

#!/bin/bash -
#
# Cybersecurity Ops with bash
# hashsearch.sh
#
# Description: 
# Recursively search a given directory for a file that
# matches a given SHA-1 hash
#
# Usage:
# hashsearch.sh <hash> <directory>
#   hash - SHA-1 hash value to file to find
#   directory - Top directory to start search
#

HASH=$1
DIR=${2:-.}	# default is here, cwd

# convert pathname into an absolute path
function mkabspath ()				# <6>
{
    if [[ $1 == /* ]]				# <7>
    then
    	ABS=$1
    else
    	ABS="$PWD/$1"				# <8>
    fi
}

find $DIR -type f |				# <1>
while read fn
do
    THISONE=$(sha1sum "$fn")			# <2>
    THISONE=${THISONE%% *}			# <3>
    if [[ $THISONE == $HASH ]]
    then
	mkabspath "$fn"				# <4>
	echo $ABS				# <5>
    fi
done
  1. 将依据哈希值查找任何普通文件。这行命令查找到的这些文件每行一个输出到 stdout 中,然后通过管道将其重定向到 while read 命令。
  2. 该行在子 shell 中计算文件的哈希值,捕获它的输出,并将其赋值给变量。使用引号是因为文件名中可能会有空格。
  3. 重新赋值将右侧删除以空格开头的最大子字符串。 sha1sum 的输出是计算出来的哈希值和相应的文件名。我们只需要哈希值,所以我们用这个替换删除了文件名。
  4. 我们调用 mkabspath 函数,将文件名放在引号中。引号确保整个文件名为函数单个参数,即使文件名有一个或多个空格。
  5. 除非在函数中声明为局部,否则 shell 变量都是全局的。因此,在 mkabspath 调用中设置的 ABS 值在这里也可以使用。
  6. 函数声明。声明时可以省略关键字 functiono 或括号,但不能两者都省略。
  7. 为了进行比较,我们在右边使用了 shell 模式匹配。将检查第一个参数是否以斜杠开头。如果是,这已经是一个绝对路径名,我们不需要再做什么。
  8. 当参数只是一个相对路径时,它相对于当前位置,因此我们预先将当前工作目录前置,从而使其称为绝对目录。

数据传输

如果要上传数据,请确保使用类似于安全复制(Secure Copy,简称 SCP)的安全方法。
示例:
使用 scp 命令将 some_system.tar.gz 文件上传到远程系统 10.0.0.45 上用户 bob 的主目录。

scp some_system.tar.gz bob@10.0.0.45:/home/bob/some_system.tar.gz

内容来源

《bash网络安全运维》

posted @ 2021-01-14 20:24  PwnKi  阅读(21)  评论(0编辑  收藏