数据处理能力是所有考虑从事安全人员应该具备的基本功之一,需要花费时间和精力来熟悉如何更好的处理数据。这意味着,你直接在文本编辑器中使用 Ctrl+F 进行查找和花费几分钟时间创建修改一行 Bash 命令是有很大区别的,从长远角度看,在刚入行时花费时间在后者的学习上,会更加有利于未来的信息安全职业生涯。
在本文中,我将带领你们通过使用不用的工具和技术来自动化的处理大量的数据,这些数据来源于各种不同的安全工具,但我们将只需要面对一个 Bash 终端就能全部搞定它们。本文内容主要包括:grep,cut,awk 和 sed 等基础命令的讲解。
首先,让我们从介绍将要使用的工具及其用法说起吧,Bash 通过使用解析工具和管道具有同时处理多个输出信息的能力。
在讲解工具之前,先让我们来了解下到底什么是管道。管道就是一种机制,可以将字符串(或文本)传递给随后的工具作为输入。语法也很简单类似于 pipe | character,例如下面的命令会先使用 cat读取 EmailAddress.txt 中的内容,然后将内容传递给 sort -u进行排序:
cat EmailAddresses.txt | sort -u
想上面这样使用管道可以快速的将大量的数据转换为我们需要的格式。
很多程序都可以直接接收管道传递来的数据作为输入,然后一些命令的输出是无法直接通过通道传递给其他程序作为输入的,此时就需要我们使用 xargs 命令来调整输出格式。xargs 命令会将数据流转换成其他命令可以接收的以空格进行分割的命令行参数。例如,我们想读取当前目录下全部的 txt 文件就可以使用如下命令:
find . -name*.txt | xargs cat
许多的 Bash 工具它们的输入输出格式相差甚大,如果想要在一行命令中完成各种操作的话,记得可以用 xargs 命令处理格式哦。
grep 可能是最著名的文本处理工具了,man的帮助页面中这么写道:“搜索以 FILE 命名的文件输入,寻找含有与给定的模式 PATTERN 相匹配的内容的行”。grep 的语法如下:
grep [options]pattern <file>
介绍 grep 的最好的方法就是列举实例。grep 最常见的用法是打印出包含给定字符串或正则表达式的行,举一个简单的例子查找指定进程的 PID 值,如果我们想要查找 evilscript 的 PID值,可以使用如下命令:
ps aux | grepevilscript
在这条命令中,grep 会搜索输出中每一包含 evilscript 的行,并把包含的行进行输出。这也是 grep 和 awk 命令的一个最大的区别,grep 会返回包含匹配项的一整行输出,想要利用 grep 输出的话还需要先使用其他工具来进行解析。
cut 命令会返回来自通道或者文件中每行指定位置的内容。同时 cut 命令与 grep 很搭配哦,因为 cut 命令是针对行进行处理的,而 grep 的输出就是行。cut 命令的基本语法如下:
cut-f<fields> [-d’<delimeter>’] [/path/to/input/file]
-f参数用来指定需要返回的字段区域,当然你可以使用逗号或者连字符来返回多个字段区域。例如:-f1-3,5会返回第一、第二、第三和第五块字段区域。默认情况下,区域的划分是基于 Tab,但我们也可以通过使用 -d进行修改,注意,在 -d参数后面不要上空格哦,同时分隔符必须包含在引号之中且只能为一个字符。
例如,我们可以使用 cut 命令来提前上一节示例中的 PID 号:
ps aux | grepevilscript | cut -d' ' -f 7
AWK是一种模式扫描和处理的编程语言,而 awk 则是一个在 Bash 中运行 AWK 脚本的工具。awk 的 man 帮助文档页面非常的长,同时还有非常多经典的书籍介绍 awk。可能很多朋友觉得 awk 非常的难学,但只要你坚持学习下去就会发现 awk 非常的强大可以更好的帮助你处理文本。使用 awk 时你可以像 grep 一样指定一种匹配模式,然后设置一系列的处理规则来匹配每一行。
多说无益,我们直接来通过一些实例来讲解吧。
还是回到上面输出 evilscript 进程 PID 的例子吧,我们可以这样来使用 awk:
ps aux | awk ‘/evilscript/’
这条命令的结果跟 grep 一样都是返回一整行,那我们为什么还要使用 awk 呢?先别急,来看看假如我们想要要直接使用一条命令同时结束 evilscript 进程呢,此时我们没法直接将整行输出传递给 kill 命令,我们需要先对行进行切割提取出我们需要的 PID 值。使用 grep 配合上 cut 可以做到这一点,但同时使用两个工具是不是稍显笨重了呢。awk 提供了更加强大的解析功能,使用 awk 我们只需如下命令:
ps aux | awk‘/evilscript/ {print $2}’ | xargs kill
现在让我们来使用这条命令试试看结果:
Match any linecontaining “evilscript” (case-sensitive) Return only the text in the NUMBER field. By default,a field is separated by a space, but it can be specified with the -F flag.
awk会将一系列相连的空格作为一个单独的分隔符,而 cut 则会将每一个空格都作为分隔符。例如,对于 awk 来说 PID 就是在第二块区域,而对 cut 来说却不确定,因为要基于用户的字段值以及 PID 的字段值,这就可能导致脚本在运行过程中出现各种 Bug。
如果你想使用 awk 来处理文件内容,只需要在最后加上文件路径即可,像下面这样:
awk‘/searchpattern/{print $1}’ /path/to/file
这里关于 awk 的介绍虽然简短,但我想也提供了不少信息可以帮助你更好的处理数据。
sed是另一个非常有用的流编辑工具。它可以基于指定的规则来重组数据。类似 awk,sed 有很非常多的选项和功能,想要全部了解它恐怕你需要查阅相关的书籍了。不过,sed 最常用的功能是替换,而下面就是使用 sed 进行替换的语法:
echo hack theworld | sed ‘s/world/planet/’
这里的斜杠是分隔符,而第一个斜杠前面的 s表面这是替换命令,第一个斜杠后面的内容为替换前的文本,第二个斜杠后面则是要替换后的文本,最后一个斜杠是结束符。在单引号中书写这些命令并不是必须的,你完全可以不加单引号,但考虑到可能存在一些头疼的逃逸字符,所以最好还是将命令包含在单引号中间比较稳妥。
再来,如果有一个名为 hacktheplanet.txt 的文档,内容为 “hack theworld”,如果我们想要替换其中的 “world” 为 “planet”,则只需要如下命令:
sed -i‘s/world/planet/’ HackThePlanet.txt
注意,如果你是在 OS X 系统上,那你需要将 -i替换为 -i''(在后面加上两个单引号)。
默认情况下,sed 只会替换每一行第一个匹配上的字符,如果想要全部匹配的话只需要在最后一个分隔符斜杠后面加上 g 参数即可,像下面这样:
sed‘s/world/planet/g’
关于 sed 配合正则表达式的使用方法,将会在后一篇进阶型的文章中在说。
“不管黑猫白猫抓到老鼠就是好猫”,不用太在意具体使用哪种工具,只要它能完成任务就行了。另外就是怎么舒服怎么来,如果能用管道配合上 grep 解决的问题,又何必去使用非常复杂的命令呢。
示例
构建IP列表
客户可能会提供一份完整的 IP 列表给你,但这个列表中的描述信息可能比较多,所以我们需要先提取出中间的 IP 地址列表,然后在使用 Nmap进行扫描。为了演示我使用如下的 IP 列表:
--First Floor-- Computers: 192.168.1.0/24 WiFi APs: 192.168.2.0/24 Printers: 192.168.2.0/24 --Second Floor-- Computers: 192.168.3.0/24 WiFi APs: 192.168.4.0/24 Printers: 192.168.4.0/24 --Server Room-- Windows Servers: 192.168.100.0/24 Switches and Wireless LAN Controllers:192.168.101.0/24
为了解决这个问题,我们需要过滤掉所有的描述信息并只返回 IP 列表。幸运的是,这些描述信息于 IP 地址之间都使用了冒号进行分割,那么我们就也可以将冒号做为分割符。
第一种方法,我们可以结合使用 grep、cut和sed来完成:
grep 192.Client-IPs.txt | cut -d: -f2 | sed ‘s/ //’
首先,grep 会返回包含有 192. 的行,随后,cut 会基于冒号进行分割后的第二部分内容,但这部分内容开头都包含空格,所以还要在使用 sed 去除空格,最后就是使用 sort 进行排序了,这里还使用了 -u 参数来进行去重。注意:sort 不能智能的排序像 IP 地址这种复杂的内容,想要智能排序 IP 地址你可能需要其他的工具来完成,比如 awk。
当然,我们同样可以使用 awk 来完成任务。假设我们面对的文件杂乱无章,描述信息和 IP 地址之间并没有像之前那样严格使用冒号、连字符或空格来进行分割,此时,我们就需要基于 IP 地址第一部分的 “192.” 来进行分割了。
awk -F'192.''/192./{print "192."$2}' client-ips.txt | sort -u
上面这个命令首先使用 “192." 作为分隔符,然后搜索每行中包含 “192." 的部分。这里需要提的就是 awk 相对于 cut 的一大优势就是可以基于多个字符进行分割。随后,就是打印输出了,因为 “192." 作为分割符在处理后会丢失,所以我们需要在输出时先手动补上 “192.",后续在跟上分割后第二部分的 IP 内容。最后,就是使用 sort 进行排序和去重了。
解析gnmap文件
在这个例子中,我们将会解析 .gnmap文件(即nmap 扫描结果输出文件)中的存活主机列表。下面是一个扫描结果的示例:
# Nmap 6.47 scaninitiated Fri Jul 22 00:58:58 2016 as: nmap -oG gnamp 192.168.55.212 Host: 192.168.55.212 () Status: Up Host: 192.168.55.212 () Ports: 135/open/tcp//msrpc///,139/open/tcp//netbios-ssn///, 445/open/tcp//microsoft-ds///,49152/open/tcp//unknown///, 49153/open/tcp//unknown///,49154/open/tcp//unknown///, 49156/open/tcp//unknown///,49157/open/tcp//unknown///, 49158/open/tcp//unknown/// Ignored State: closed (991) # Nmap done at Fri Jul 22 00:59:00 2016 -- 1 IPaddress (1 host up) scanned in 2.33 seconds
使用 grep 和 cut 提取存活主机的命令如下:
grep “Status: Up”nmap-scan.gnmap | cut -d’ ‘ -f2 | sort -u > livehosts.txt
同之前一样, grep 返回包含有 “Status: Up” 字样的行,cut 返回基于空格分割后的第二部分内容也就是 IP 地址,随后在使用 sort 进行去重,最后就是重定向输出到 livehosts.txt 文件中,这样我们就得到了目标存活主机列表了。
对于使用 awk 也只需要使用如下命令:
awk '/Status:Up/{print $2}' nmap-scan.gnmap | sort -u > live-hosts.txt
我想这已经无需在做过多的解释了,只需要注意下记得对逃逸字符进行转义即可。
总结
在我们看来,数据解析是渗透测试人员必备的基础技能之一,通常来说,在渗透测试时会面对大量需要解析的数据,如何快速并正确的解析数据将会直接影响最终的结果。在 Bash 中,一旦当你掌握了 grep、cut、awk 和 sed等本文处理工具的用法,它们可以快速的帮你完成复杂的数据解析工作。在本文中,我们讲解了这几个工具的基本用法并给出了一些基本示例,在后续的文章中我们将会介绍一些更加高级的方法,比如正则表达式,使用 Python 解析 XML,以及如何在 Windows 下面使用命令行来完成这些工作。
本文原文作者:Jeff Dimmock (@bluscreenofjeff)和 Andrew Luke (@sw4mp_f0x).
还没有评论,来说两句吧...