关注 泷羽Sec和泷羽Sec-静安公众号,这里会定期更新与 OSCP、渗透测试等相关的最新文章,帮助你理解网络安全领域的最新动态。后台回复“OSCP配套工具”获取本文的工具
Bash脚本基础
新建一个hello-world.sh
文件,写入以下内容:
#!/bin/bash
#Hello world Bash Script
echo "hello world!"
然后给脚本添加执行权限后运行
chmod +x hello-world.sh
./hello-world.sh
变量
s1=hello
s2=world
s3="I am Hacker"
echo $s2 $s2 $s3
参数里面套命令,推荐用$()
的用法,` 是过时的用法。
user1=$(whoami) && user2=`whoami`
echo $user1 $user2
参数
$0 脚本文件名自己
$1-$9 bash脚本的前九个参数
$# 传递给bash脚本的参数数量
$@ 传递给bash 脚本的所有参数
$? 最近运行的程序的退出状态
$USER 运行脚本的用户的用户名
$HOSTNAME 计算机的主机名
$RANDOM 生成一个随机数
$LINENO 脚本中的当前行号
新建一个脚本写入如下内容。
#!/bin/bash
echo "The first two arguments are $1 and $2"
#!/bin/bash
# 文件名: demo_script.sh
# 功能: 演示常用 Bash 参数的用法
# 1. 打印脚本名称
echo "脚本名称: $0"
# 2. 打印前三个参数(若未传递参数则显示空)
echo "第一个参数: ${1:-未提供}"
echo "第二个参数: ${2:-未提供}"
echo "第三个参数: ${3:-未提供}"
# 3. 打印总参数个数
echo "参数总数: $#"
# 4. 打印所有参数(带循环)
echo "所有参数:"
count=1
for arg in "$@"; do
echo " 参数$count: $arg"
((count++))
done
# 5. 测试上一个命令的退出状态
echo "生成随机数(测试退出状态):"
echo "随机数: $RANDOM"
echo "生成随机数的退出状态: $? (0表示成功)"
# 6. 故意执行一个失败的命令
echo "执行一个失败的命令:"
ls /non_existent_file
echo "失败命令的退出状态: $? (非0表示失败)"
# 7. 用户和主机信息
echo "当前用户: $USER"
echo "主机名: $HOSTNAME"
# 8. 显示脚本当前行号(动态变化)
echo "当前行号(执行前): $LINENO"
echo "当前行号(执行后): $LINENO"
# 9. 结束提示
echo "脚本结束于行号: $LINENO"
Bash 特殊变量
变量名 | 作用 | 示例代码 | 输出示例(假设场景) |
---|---|---|---|
$0 | 当前脚本文件名 | echo "脚本名: $0" | 脚本名: ./test.sh |
$1 -$9 | 脚本的第1到第9个参数 | echo "参数1: $1" | 若执行 ./test.sh hi → 参数1: hi |
$# | 传递给脚本的参数个数 | echo "参数总数: $#" | 若执行 ./test.sh a b → 参数总数: 2 |
$@ | 所有参数,每个参数独立(推荐使用) | for arg in "$@"; do echo "$arg"; done | 循环打印每个参数 |
$* | 所有参数,合并为一个字符串 | echo "所有参数: $*" | 所有参数: a b c |
$? | 上一个命令的退出状态(0为成功) | ls /tmp; echo "状态: $?" | 状态: 0 (若目录存在) |
$$ | 当前 Shell 进程的 PID | echo "PID: $$" | PID: 12345 |
$! | 最后一个后台进程的 PID | sleep 10 &; echo "后台PID: $!" | 后台PID: 6789 |
$_ | 上一个命令的最后一个参数 | ls /var; echo "$_" | /var (假设 ls 命令的参数是 /var ) |
$RANDOM | 生成一个 0-32767 的随机数 | echo "随机数: $RANDOM" | 随机数: 18492 |
$LINENO | 当前脚本中的行号 | echo "当前行: $LINENO" | 当前行: 15 |
$FUNCNAME | 当前函数名(数组,${FUNCNAME[0]} 为当前函数) | function test_fn { echo "函数名: ${FUNCNAME[0]}"; }; test_fn | 函数名: test_fn |
$SECONDS | 脚本已运行的秒数 | echo "运行时间: $SECONDS秒" | 运行时间: 5秒 |
$PWD | 当前工作目录路径 | echo "当前目录: $PWD" | 当前目录: /home/user |
$OLDPWD | 上一个工作目录路径(cd - 切换时会更新) | echo "上一个目录: $OLDPWD" | 上一个目录: /tmp |
$IFS | 输入字段分隔符(默认是空格、制表符、换行) | IFS=:; echo "拆分: $*" | 若参数为 a:b:c → 拆分: a b c |
$BASH_VERSION | Bash 版本信息 | echo "Bash版本: $BASH_VERSION" | Bash版本: 5.1.16(1)-release |
$PPID | 父进程的 PID | echo "父进程PID: $PPID" | 父进程PID: 1234 |
$BASH_SOURCE | 当前脚本的路径(数组,${BASH_SOURCE[0]} 为当前脚本) | echo "脚本路径: ${BASH_SOURCE[0]}" | 脚本路径: ./test.sh |
常用环境变量
变量名 | 作用 | 示例代码 | 输出示例 |
---|---|---|---|
$USER | 当前用户名 | echo "用户: $USER" | 用户: ubuntu |
$HOME | 当前用户的主目录路径 | echo "主目录: $HOME" | 主目录: /home/user |
$PATH | 可执行文件的搜索路径 | echo "PATH: $PATH" | PATH: /usr/bin:/bin |
$SHELL | 当前 Shell 的路径 | echo "Shell: $SHELL" | Shell: /bin/bash |
$LANG | 系统语言设置 | echo "语言: $LANG" | 语言: en_US.UTF-8 |
$TERM | 终端类型 | echo "终端类型: $TERM" | 终端类型: xterm-256color |
$EDITOR | 默认文本编辑器 | echo "编辑器: $EDITOR" | 编辑器: vim |
$UID | 当前用户的 UID | echo "UID: $UID" | UID: 1000 |
$GROUPS | 当前用户所属的组(数组) | echo "组: ${GROUPS[@]}" | 组: 1000 4 24 |
$HOSTNAME | 系统主机名 | echo "主机名: $HOSTNAME" | 主机名: myserver |
$OSTYPE | 操作系统类型 | echo "系统类型: $OSTYPE" | 系统类型: linux-gnu |
用户输入
#!/bin/bash
echo "Hello there, would you like to learn how to hack: Y/N?"
read answer # 把用户输入存到answer变量中
echo "Your answer was $answer"
#!/bin/bash
# Prompt the user for credentials
# Penetration Testing with Kali Linux 2.0
# PWK 2.0 Copyright © Offensive Security Ltd. All rights reserved. 110
read -p 'Username: ' username # 输出提示的同时将用户输入存入username变量
read -sp 'Password: ' password # 输出提示的同时将用户输入存入password变量,且不显示,用于密码
echo " "
echo "Thanks, your creds are as follows: " $username " and " $password
判断
Bash 条件测试操作符详解
逻辑操作符
操作符 | 描述 | 示例 |
---|---|---|
! EXPRESSION | 对表达式取反(非) | if ! [ -e file ] → 文件不存在时条件为真 |
字符串比较
操作符 | 描述 | 示例 |
---|---|---|
-n STRING | 字符串长度大于零(非空) | if [ -n "$name" ] → 检查变量 name 是否非空 |
-z STRING | 字符串长度为零(空) | if [ -z "$error" ] → 检查变量 error 是否为空 |
STRING1 = STRING2 | 字符串相等 | if [ "$os" = "Linux" ] → 判断系统是否为 Linux |
STRING1 != STRING2 | 字符串不相等 | if [ "$input" != "exit" ] → 输入不是 “exit” 时条件为真 |
整数比较
操作符 | 描述 | 示例 |
---|---|---|
INT1 -eq INT2 | 等于(Equal) | if [ "$a" -eq 5 ] → 判断 a 是否等于 5 |
INT1 -ne INT2 | 不等于(Not Equal) | if [ "$retry" -ne 0 ] → 重试次数不为 0 |
INT1 -gt INT2 | 大于(Greater Than) | if [ "$score" -gt 60 ] → 分数超过 60 |
INT1 -lt INT2 | 小于(Less Than) | if [ "$age" -lt 18 ] → 年龄小于 18 |
INT1 -ge INT2 | 大于等于(Greater or Equal) | if [ "$count" -ge 10 ] → 计数达到或超过 10 |
INT1 -le INT2 | 小于等于(Less or Equal) | if [ "$time" -le 30 ] → 时间小于等于 30 秒 |
文件测试
操作符 | 描述 | 示例 |
---|---|---|
-d FILE | 文件存在且是目录 | if [ -d "/tmp" ] → 检查 /tmp 是否是目录 |
-e FILE | 文件存在 | if [ -e "log.txt" ] → 检查 log.txt 是否存在 |
-r FILE | 文件存在且有读权限 | if [ -r "config.cfg" ] → 检查配置文件是否可读 |
-s FILE | 文件存在且非空 | if [ -s "data.csv" ] → 检查数据文件是否有内容 |
-w FILE | 文件存在且有写权限 | if [ -w "output.log" ] → 检查日志文件是否可写 |
-x FILE | 文件存在且有执行权限 | if [ -x "install.sh" ] → 检查安装脚本是否有执行权限 |
新建一个文件**number_game.sh
**
#!/bin/bash
# 生成随机数,用户猜测数字比大小
# 生成1-100的随机数
target=$((RANDOM % 100 + 1))
attempts=0
max_attempts=10
echo "欢迎来到猜数字游戏!"
echo "我已生成一个1到100之间的整数,你有${max_attempts}次机会猜中它。"
while [ $attempts -lt $max_attempts ]; do
((attempts++))
remaining=$((max_attempts - attempts + 1))
echo -n "第${attempts}次猜测(剩余${remaining}次):"
read guess
# 检查输入是否为空或非数字
if [ -z "$guess" ]; then
echo "错误:输入不能为空!"
((attempts--))
continue
elif ! [[ "$guess" =~ ^[0-9]+$ ]]; then
echo "错误:请输入数字!"
((attempts--))
continue
fi
# 比较数字
if [ "$guess" -eq "$target" ]; then
echo "恭喜!你在第${attempts}次猜中了正确答案:${target}!"
exit 0
elif [ "$guess" -lt "$target" ]; then
echo "提示:你猜的数字太小了!"
else
echo "提示:你猜的数字太大了!"
fi
done
echo "很遗憾,你已经用完所有次数。正确答案是:${target}。"
exit 1
循环
1. for
循环
基本语法
for 变量 in 列表; do
循环体
done
应用场景
- 遍历已知序列(数字、文件、字符串等)。
- 执行固定次数的重复操作。
示例 1:遍历数字序列
终端输入cat > for1.sh
,复制粘贴如下内容,回车后按ctrl D
结束输入。就能不用打开vim直接输入脚本了。
#!/bin/bash
# 遍历 1-5 并打印平方数
for i in 1 2 3 4 5; do
echo "$i 的平方是 $((i*i))"
done
# 使用序列生成器 {起..止..步长}
for i in {1..5}; do
echo "数字: $i"
done
# 指定步长(仅 Bash 4+ 支持)
for i in {0..10..2}; do
echo "偶数: $i"
done
输出示例
示例 2:遍历文件
#!/bin/bash
# 遍历当前目录所有 .txt 文件并输出文件名
for file in *.txt; do
echo "find_${file}"
done
# 遍历带空格的文件名(需设置 IFS)
IFS=$'\n' # 将字段分隔符设为换行符
for file in $(find . -name "*.log"); do
echo "处理文件: $file"
done
示例 3:遍历数组
#!/bin/bash
fruits=("苹果" "香蕉" "橘子")
for fruit in "${fruits[@]}"; do
echo "水果: $fruit"
done
输出示例
2. while
循环
基本语法
while 条件; do
循环体
done
应用场景
- 条件持续满足时循环(如读取文件、等待任务完成)。
- 无限循环(需搭配
break
或外部终止条件)。
示例 1:条件控制循环
#!/bin/bash
# 计数器从1累加到5
count=1
while [ $count -le 5 ]; do
echo "计数: $count"
((count++))
done
输出示例
示例 2:读取文件内容**
#!/bin/bash
# 逐行读取文件
while IFS= read -r line; do
echo "行内容: $line"
done < "w2.txt"
示例 3:无限循环 + 用户输入退出
#!/bin/bash
# 持续询问用户输入,直到输入 "exit"
while true; do
read -p "请输入命令(输入 exit 退出): " cmd
if [ "$cmd" = "exit" ]; then
break
else
echo "执行命令: $cmd" && echo $($cmd)
fi
done
3. until
循环(补充)
与 while
逻辑相反,当条件为 假 时执行循环。
#!/bin/bash
# 直到计数器大于5时停止
count=1
until [ $count -gt 5 ]; do
echo "计数: $count"
((count++))
done
循环控制语句
命令 | 作用 | 示例 |
---|---|---|
break | 立即终止循环 | if [ $i -eq 3 ]; then break; fi |
continue | 跳过当前循环,进入下一次 | if [ $i -eq 2 ]; then continue; fi |
选择循环的建议
- 已知迭代次数/列表 →
for
循环
(如处理文件、数组、数字序列) - 依赖动态条件 →
while
循环
(如读取输入、监控进程状态)
综合应用脚本
#!/bin/bash
# 功能: 查找并压缩所有 .log 文件,直到总压缩文件超过 3 个
log_count=0
while [ $log_count -lt 3 ]; do
# 查找未压缩的 .log 文件
for file in *.log; do
if [ -f "$file" ]; then
gzip "$file"
echo "已压缩: $file"
((log_count++))
# 达到3个后退出循环
if [ $log_count -ge 3 ]; then
break 2 # 跳出外层 while 循环
fi
fi
done
sleep 1 # 等待新日志生成
done
echo "已压缩满3个文件!"
通过灵活组合 for
和 while
,可以高效处理文件操作、系统监控等任务。
函数
在 Bash 脚本中,函数(Function)用于封装可重复使用的代码块,提升代码的可读性和复用性。以下是 Bash 函数的详细用法及示例:
1. 定义函数
语法
# 方式1:使用 function 关键字
function 函数名 {
函数体
}
# 方式2:直接定义(兼容性更好)
函数名() {
函数体
}
示例 1:简单函数
# 定义一个打印欢迎信息的函数
welcome() {
echo "欢迎使用本脚本!当前用户:$USER"
}
# 调用函数
welcome
输出:
欢迎使用本脚本!当前用户:ubuntu
2. 函数参数
函数通过位置参数($1
、$2
…)接收参数,与脚本参数类似。
示例 2:带参数的函数
# 定义一个加法计算器
add() {
local sum=$(( $1 + $2 )) # 使用 local 定义局部变量
echo "$1 + $2 = $sum"
}
# 调用函数并传递参数
add 5 3
输出:
5 + 3 = 8
3. 返回值
Bash 函数通过 return
返回 退出状态码(0 表示成功,非 0 表示错误),或通过 echo
输出结果。
示例 3:返回状态码
# 检查文件是否存在
file_exists() {
if [ -f "$1" ]; then
return 0 # 文件存在,返回成功
else
return 1 # 文件不存在,返回失败
fi
}
# 调用函数并检查返回值
if file_exists "/etc/passwd"; then
echo "文件存在!"
else
echo "文件不存在!"
fi
示例 4:返回字符串
# 生成问候语(通过 echo 返回结果)
get_greeting() {
local name=$1
echo "你好,$name!今天是 $(date +%F)"
}
# 捕获函数输出
message=$(get_greeting "大黑阔")
echo "$message"
输出:
你好,小明!今天是 2023-10-05
4. 局部变量
使用 local
关键字定义局部变量,避免污染全局作用域。
# 生成问候语(通过 echo 返回结果)
get_greeting() {
local name=$1
globalname=$2
echo "你好,$name!今天是 $(date +%F)"
}
# 捕获函数输出
get_greeting "大黑阔" "Hacker"
echo $name # 局部变量不可见
echo $globalname
5. 高级用法
递归函数
# 计算阶乘(递归实现)
factorial() {
if [ $1 -le 1 ]; then
echo 1
else
local prev=$(factorial $(( $1 - 1 )) )
echo $(( $1 * $prev ))
fi
}
# 计算 5!
result=$(factorial 5)
echo "5! = $result" # 输出 "5! = 120"
函数库
将常用函数保存为独立文件(如 utils.sh
),通过 source
导入:to_upper函数实现小写转大写。
# utils.sh
to_upper() {
echo "$1" | tr '[:lower:]' '[:upper:]'
}
# main.sh
#!/bin/bash
source utils.sh
echo $(to_upper "hello")
6. 注意事项
- 定义顺序:函数必须在调用之前定义。
- 命名冲突:避免函数名与系统命令或别名重复。
- 参数传递:参数通过空格分隔,若参数含空格需用引号包裹(如
func "参数 1"
)。 - 返回值限制:
return
只能返回 0-255 的整数,返回字符串或复杂数据需用echo
。
布尔逻辑运算
在 Bash 中,&&
、||
、&
和 |
是常用的操作符,用于控制命令的执行逻辑和流程。以下是它们的详细解释及示例:
1. &&
(逻辑与)
- 作用:只有 前一个命令成功执行(退出状态码为
0
),才会执行后面的命令。
mkdir mydir && cd mydir # 先创建目录,若成功则进入该目录
- 如果
mkdir mydir
成功(目录创建成功),则执行cd mydir
。 - 如果
mkdir
失败(如目录已存在),则不会执行cd
。
2. ||
(逻辑或)
- 作用:只有 前一个命令执行失败(退出状态码非
0
),才会执行后面的命令。
ping -c1 google.com || echo "网络不可达" # 若 ping 失败,则提示错误
- 如果
ping
失败(网络断开),则执行echo
输出提示。 - 如果
ping
成功,不执行echo
。
3. &
(后台执行)
- 作用:将命令放入 后台执行,终端可继续输入其他命令。
sleep 10 & # 后台休眠10秒,终端可继续操作
- 命令后加
&
会返回一个后台进程的PID
(如[1] 12345
)。 - 可通过
jobs
查看后台任务,fg %1
将任务调回前台。
4. |
(管道)
- 作用:将 前一个命令的输出 作为 后一个命令的输入。
cat log.txt | grep "error" | wc -l # 统计 log.txt 中 "error" 的行数
cat log.txt
输出文件内容。grep "error"
过滤含 “error” 的行。wc -l
统计行数。
组合使用示例
场景:下载文件,若失败则重试,成功后解压并删除原文件。
wget http://example.com/file.tar.gz && \
tar -xzf file.tar.gz || \
echo "下载失败,请检查网络!"
wget
下载文件,若成功则执行tar
解压。- 若
wget
失败,直接执行echo
提示错误。
符号优先级
- 默认优先级:
&&
和||
的优先级低于|
和&
。 - 强制优先级:用
()
或{}
- 分组:
(cmd1 && cmd2) || cmd3 # 若 cmd1 和 cmd2 都成功则不执行 cmd3,否则执行
实操练习1-网页地址查找
wget www.megacorpone.com
ls -al index.html
grep "href=" index.html
grep "href=" index.html | grep "\.megacorpone" | grep -v "www\.megacorpone\.com" | head
grep "href=" index.html | grep "\.megacorpone" | grep -v "www\.megacorpone\.com" | awk -F "http://" '{print $2}'
grep "href=" index.html # 1. 提取所有包含 href= 的 HTML 行
| grep "\.megacorpone" # 2. 筛选含 .megacorpone 的行(子域名或路径)
| grep -v "www\.megacorpone\.com" # 3. 排除含 www.megacorpone.com 的行
| head # 4. 仅显示前 10 条结果
grep "href=" index.html | grep "\.megacorpone" | grep -v "www\.megacorpone\.com" | awk -F "http://" '{print $2}' | cut -d "/" -f 1
grep -o '[^/]*\.megacorpone\.com' index.html | sort -u > list.txt
命令 1:提取特定子域名并处理链接结构
分步解析
grep "href=" index.html
- 从
index.html
中提取所有包含href=
的行(HTML 超链接标签)。
- 从
grep "\.megacorpone"
- 筛选包含
.megacorpone
的行(匹配子域名或路径中的该字段)。
- 筛选包含
grep -v "www\.megacorpone\.com"
- 排除包含
www.megacorpone.com
的行(主站域名)。
- 排除包含
awk -F "http://" '{print $2}'
- 以
http://
为分隔符,提取其后的内容(如cdn.megacorpone.com/style.css
)。
- 以
cut -d "/" -f 1
- 以
/
为分隔符,提取第一个字段(即域名部分,如cdn.megacorpone.com
)。
- 以
命令 2:直接匹配并收集所有子域名
分步解析
-
grep -o '[^/]\*\.megacorpone\.com'
-
-o
:仅输出匹配的部分。 -
正则
[^/]*\.megacorpone\.com
[^/]*
:匹配不包含/
的任意字符(避免包含路径或端口)。\.megacorpone\.com
:匹配以.megacorpone.com
结尾的域名。
-
-
sort -u
- 对结果排序并去重(
-u
表示唯一性)。
- 对结果排序并去重(
-
> list.txt
- 将结果保存到
list.txt
文件。
- 将结果保存到
主机ip筛查
for url in $(cat list.txt); do host $url; done
for url in $(cat list.txt); do host $url; done | grep "has address" | cut -d " " -f 4 | sort -u
查找发现教材上的示例网页页面中的子域名,ip主要集中在加拿大(这里和教材示例不同,推测是因为使用了VPN的缘故,以及网页距离写教材时已经过去多年,更换过服务器)。
实操练习2-筛选漏洞脚本并下载
searchsploit afd windows -w -t
searchsploit afd windows -w -t | grep http | cut -f 2 -d "|"
mkdir afd && cd afd
for e in $(searchsploit afd windows -w -t | grep http | cut -f 2 -d "|"); do exp_name=$(echo $e | cut -d "/" -f 5) && url=$(echo $e | sed 's/exploits/raw/') && wget -q --no-check-certificate $url -O $exp_name; done
file 17133
cat 17133
实操练习3-Nmap扫描
sudo nmap --script=vuln -p- -T4 -iL nmaphost.txt --min-rate 1000 --open
sudo nmap -A -p80 --open 10.11.1.0/24 -oG nmap-scan_10.11.1.1-254
cat nmap-scan_10.11.1.1-254 | grep 80 | grep -v "Nmap"
cat nmap-scan_10.11.1.1-254 | grep 80 | grep -v "Nmap" | awk '{print $2}'
for ip in $(cat nmap-scan_10.11.1.1-254 | grep 80 | grep -v "Nmap" | awk '{print $2}'); do cutycapt --url=$ip --out=$ip.png;done
课后练习
-
Research Bash loops and write a short script to perform a ping sweep of your target IP range of 10.11.1.0/24.
-
Try to do the above exercise with a higher-level scripting language such as Python, Perl, or Ruby.
-
Use the practical examples in this module to help you create a Bash script that extracts JavaScript files from the access_log.txt file (http://www.offensive-security.com/pwkfiles/access_log.txt.gz). Make sure the file names DO NOT include the path, are unique, and are sorted.
-
Re-write the previous exercise in another language such as Python, Perl, or Ruby.
-
研究 Bash 循环,编写一个简短的脚本,对目标 IP 范围
10.11.1.0/24
执行 Ping 扫描。 -
尝试用 Python 等高级语言实现上述功能。
-
使用本模块的实例,编写一个 Bash 脚本从
access_log.txt
中提取 JavaScript 文件名,要求文件名不包含路径、唯一且排序。 -
用 Python 等语言重写上述提取 JavaScript 文件名的功能。
1. Bash 脚本:Ping 扫描 10.11.1.0/24
网段
这里为了能有输出,改为172.168.169.0/24
网段,时我本地虚拟机的内网
#!/bin/bash
# 遍历 1-254,发送 Ping 请求并输出存活主机
for ip in {1..254}; do
target="172.168.169.$ip"
# -c 1: 发送 1 个包,-W 1: 超时 1 秒
ping -c 1 -W 1 $target > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "$target is up"
fi
done
2. Python 脚本:Ping 扫描 10.11.1.0/24
网段
import os
import subprocess
from concurrent.futures import ThreadPoolExecutor
def ping_host(ip):
target = f"172.168.169.{ip}"
# 调用系统 Ping 命令(Windows 需将 '-c 1' 改为 '-n 1')
result = subprocess.run(['ping', '-c', '1', '-W', '1', target],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if result.returncode == 0:
print(f"{target} is up")
# 使用多线程加速扫描(1-254)
with ThreadPoolExecutor(max_workers=50) as executor:
executor.map(ping_host, range(1, 255))
3. Bash 脚本:从 access_log.txt
提取唯一 JS 文件名
wget --secure-protocol=TLSv1_2 https://www.offensive-security.com/pwk-files/access_log.txt.gz
gunzip access_log.txt.gz
#!/bin/bash
# 提取所有 JS 文件,去重并排序
grep -oP 'GET \K[^ ]+?\.js' access_log.txt | awk -F/ '{print $NF}' | sort -u
说明:
grep -oP 'GET \K[^ ]+?\.js'
:
匹配GET
请求中的.js
文件路径,\K
丢弃GET
前缀。awk -F/ '{print $NF}'
:
以/
分割路径,输出最后一个字段(文件名)。sort -u
:
排序并去重。
4. Python 脚本:提取唯一 JS 文件名
import re
from collections import defaultdict
js_files = set()
# 匹配 GET 请求中的 JS 文件
pattern = re.compile(r'GET\s+([^ ]+?\.js)')
with open('access_log.txt', 'r') as f:
for line in f:
match = pattern.search(line)
if match:
path = match.group(1)
# 提取文件名(忽略路径)
filename = path.split('/')[-1]
js_files.add(filename)
# 排序并输出
for filename in sorted(js_files):
print(filename)
🔔 想要获取更多网络安全与编程技术干货?
关注 泷羽Sec-静安 公众号,与你一起探索前沿技术,分享实用的学习资源与工具。我们专注于深入分析,拒绝浮躁,只做最实用的技术分享!💻
扫描下方二维码,马上加入我们,共同成长!🌟
👉 长按或扫描二维码关注公众号
或者直接回复文章中的关键词,获取更多技术资料与书单推荐!📚