CTF中bash逆向题型
概述
CTF竞赛中的bash相关题目涉及脚本逆向、编码解码、环境变量利用等多个方面。本文详细介绍常见的bash逆向题型及解题技巧。
核心理念
- 理解执行流程:分析bash脚本的执行逻辑
- 编码识别:快速识别各种编码方式
- 变量追踪:跟踪环境变量和局部变量的变化
- 工具辅助:善用bash调试工具辅助分析
1. bash 脚本逆向
1.1 静态分析技巧
# 查看脚本内容(排除空行和注释)
cat script.sh | grep -v '^#' | grep -v '^$'
# 查找所有变量赋值
grep -oP '[A-Za-z_]+=' script.sh
# 查找所有命令调用
grep -oP '^[a-z]+' script.sh
# 查找所有函数定义
grep -oP '^[a-zA-Z_]+\(\)' script.sh
# 查找所有 eval/base64/decode 调用
grep -n 'eval\|base64\|decode\|exec\|system\|passthru' script.sh1.2 动态调试
# 使用 bash -x 跟踪执行
bash -x script.sh
# 使用 PS4 显示更多信息
PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' bash -x script.sh
# 使用 trap 拦截信号
trap 'echo "Signal received at line $LINENO"' DEBUG1.3 常见混淆手法
# base64 混淆
echo "aGVsbG8gd29ybGQ=" | base64 -d
# 解码: hello world
# hex 编码
echo "68656c6c6f" | xxd -r -p
# chr 拼接
echo $'\x48\x65\x6c\x6c\x6f'
# 变量拼接
a=he; b=ll; c=o
echo ${a}${b}${c}
# 字符串反转
echo "dlrow olleh" | rev2. eval/base64 解码
2.1 多层 base64 解码
multi_decode_base64() {
local encoded="$1"
local decoded="$encoded"
local layer=0
while true; do
local temp
temp=$(echo "$decoded" | base64 -d 2>/dev/null) || break
if [[ "$temp" == "$decoded" ]]; then
break
fi
decoded="$temp"
((layer++))
echo "[Layer $layer] $decoded"
done
echo "最终解码结果: $decoded"
echo "共 $layer 层"
}2.2 eval 混淆分析
# 安全分析:不执行,只查看
safe_analyze_eval() {
local script="$1"
sed 's/eval/echo/g' "$script" | bash 2>/dev/null
}2.3 混合编码解码
decode_mixed() {
local input="$1"
# 尝试 base64
if echo "$input" | base64 -d 2>/dev/null | grep -qP '[a-zA-Z]'; then
echo "Base64: $(echo "$input" | base64 -d)"
fi
# 尝试 hex
if echo "$input" | xxd -r -p 2>/dev/null | grep -qP '[a-zA-Z]'; then
echo "Hex: $(echo "$input" | xxd -r -p)"
fi
# 尝试 URL decode
if echo "$input" | python3 -c "import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))" 2>/dev/null | grep -qP '[a-zA-Z]'; then
echo "URL: $(echo "$input" | python3 -c "import sys,urllib.parse; print(urllib.parse.unquote(sys.stdin.read()))")"
fi
# ROT13
echo "ROT13: $(echo "$input" | tr 'A-Za-z' 'N-ZA-Mn-za-m')"
}3. 环境变量利用
3.1 环境变量注入
# 利用 IFS 分割
IFS=','
set a,b,c,d
echo "$1" # 输出: a
# 利用 PATH 劫持
create_fake_command() {
local cmd="$1" payload="$2"
local tmp_dir="/tmp/fake_$$"
mkdir -p "$tmp_dir"
echo "#!/bin/bash" > "$tmp_dir/$cmd"
echo "$payload" >> "$tmp_dir/$cmd"
chmod +x "$tmp_dir/$cmd"
export PATH="$tmp_dir:$PATH"
}
# 利用 BASH_ENV
export BASH_ENV="/tmp/malicious.sh"3.2 隐藏变量
# 在变量名中使用特殊字符
declare -x $'\x41\x42\x43'="hidden_value"
echo ${!'\x41\x42\x43'}
# 利用 /proc/self/environ
cat /proc/self/environ | tr '\0' '\n'
# 利用 declare 查看所有变量
declare -p4. 文件描述符题目
4.1 文件描述符操作
# 打开文件描述符
exec 3< /etc/passwd
cat <&3
exec 3<&-
# 写入文件描述符
exec 4> /tmp/output.txt
echo "data" >&4
exec 4>&-
# 管道文件描述符
exec 3< <(echo "data from fd 3")
read line <&3
echo "$line"4.2 常见文件描述符技巧
read_from_fd() {
local fd="$1"
local line
while read -u "$fd" line; do
echo "$line"
done
}
# 创建匿名管道
mkfifo /tmp/pipe_$$
exec 3<>/tmp/pipe_$$
echo "data through pipe" >&3
read <&3
exec 3>&-
rm -f /tmp/pipe_$$5. 管道题目
5.1 管道基础
# 管道连接
echo "data" | grep "pattern" | sed 's/old/new/g'
# 命名管道 (FIFO)
mkfifo /tmp/mypipe
# 终端1: echo "secret" > /tmp/mypipe
# 终端2: cat /tmp/mypipe
# 进程替换
diff <(ls /dir1) <(ls /dir2)5.2 管道中的信号处理
set -o pipefail
command1 | command2 | command3
echo "Exit status: ${PIPESTATUS[@]}"6. CTF 解题模板
#!/usr/bin/env bash
# CTF Bash 逆向解题模板
set -euo pipefail
# 颜色输出
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
info() { echo -e "${YELLOW}[*]${NC} $*"; }
ok() { echo -e "${GREEN}[+]${NC} $*"; }
fail() { echo -e "${RED}[-]${NC} $*"; }
# base64 自动解码
auto_base64() {
local input="$1"
local decoded
decoded=$(echo "$input" | base64 -d 2>/dev/null) || { fail "base64 解码失败"; return 1; }
ok "Base64: $decoded"
}
# hex 自动解码
auto_hex() {
local input="$1"
local decoded
decoded=$(echo "$input" | xxd -r -p 2>/dev/null) || { fail "hex 解码失败"; return 1; }
ok "Hex: $decoded"
}
# 逐字符分析
analyze_chars() {
local input="$1"
for ((i=0; i<${#input}; i++)); do
local c="${input:$i:1}"
local ord=$(printf '%d' "'$c")
echo " [$i] '$c' -> $ord (0x$(printf '%02x' $ord))"
done
}
# XOR 分析
xor_analyze() {
local input="$1" key="$2"
local result=""
for ((i=0; i<${#input}; i++)); do
local c1=$(printf '%d' "'${input:$i:1}")
local c2=$(printf '%d' "'${key:$((i % ${#key})):1}")
local xored=$((c1 ^ c2))
result+=$(printf '\x%02x' "$xored")
done
echo "$result" | xxd -r -p
}
# 主函数
main() {
info "CTF Bash 逆向解题工具"
echo "用法:"
echo " auto_base64 "encoded_string""
echo " auto_hex "hex_string""
echo " analyze_chars "string""
echo " xor_analyze "input" "key""
}
[[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@"