#### Shell 一行命令 [[目录]](#anger-table-of-contents)
##### 目录
* [terminal](#tool-terminal) - 终端
* [busybox](#tool-busybox)
* [mount](#tool-mount) - 挂载
* [fuser](#tool-fuser)
* [lsof](#tool-lsof)
* [ps](#tool-ps)
* [top](#tool-top)
* [vmstat](#tool-vmstat)
* [iostat](#tool-iostat)
* [strace](#tool-strace)
* [kill](#tool-kill)
* [find](#tool-find)
* [diff](#tool-diff)
* [vimdiff](#tool-vimdiff)
* [tail](#tool-tail)
* [cpulimit](#tool-cpulimit)
* [pwdx](#tool-pwdx)
* [tr](#tool-tr)
* [chmod](#tool-chmod)
* [who](#tool-who)
* [last](#tool-last)
* [screen](#tool-screen)
* [script](#tool-script)
* [du](#tool-du)
* [inotifywait](#tool-inotifywait)
* [openssl](#tool-openssl)
* [secure-delete](#tool-secure-delete) - 安全删除
* [dd](#tool-dd)
* [gpg](#tool-gpg)
* [system-other](#tool-system-other) - 系统其他
* [curl](#tool-curl)
* [httpie](#tool-httpie)
* [ssh](#tool-ssh)
* [linux-dev](#tool-linux-dev)
* [tcpdump](#tool-tcpdump)
* [tcpick](#tool-tcpick)
* [ngrep](#tool-ngrep)
* [hping3](#tool-hping3)
* [nmap](#tool-nmap)
* [netcat](#tool-netcat)
* [socat](#tool-socat)
* [p0f](#tool-p0f)
* [gnutls-cli](#tool-gnutls-cli)
* [netstat](#tool-netstat)
* [rsync](#tool-rsync)
* [host](#tool-host)
* [dig](#tool-dig)
* [certbot](#tool-certbot)
* [network-other](#tool-network-other) - 网络其他
* [git](#tool-git)
* [awk](#tool-awk)
* [sed](#tool-sed)
* [grep](#tool-grep)
* [perl](#tool-perl)
##### 工具: [terminal](https://en.wikipedia.org/wiki/Linux_console) - 终端
###### 不退出重新加载 Shell
```bash
exec $SHELL -l
```
###### 关闭 Shell 但保持所有子进程运行
```bash
disown -a && exit
```
###### 退出不保存 Shell 历史
```bash
kill -9 $$
unset HISTFILE && exit
```
###### 执行分支条件判断
```bash
true && echo success
false || echo failed
```
###### 将 stdout 和 stderr 管道到不同的命令
```bash
some_command > >(/bin/cmd_for_stdout) 2> >(/bin/cmd_for_stderr)
```
###### 将 stdout 和 stderr 分别重定向到不同文件,并同时打印到屏幕
```bash
(some_command 2>&1 1>&3 | tee errorlog ) 3>&1 1>&2 | tee stdoutlog
```
###### 列出最常用的命令
```bash
history | \
awk '{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a;}' | \
grep -v "./" | \
column -c3 -s " " -t | \
sort -nr | nl | head -n 20
```
###### 净化 Bash 历史
```bash
function sterile() {
history | awk '$2 != "history" { $1=""; print $0 }' | egrep -vi "\
curl\b+.*(-E|--cert)\b+.*\b*|\
curl\b+.*--pass\b+.*\b*|\
curl\b+.*(-U|--proxy-user).*:.*\b*|\
curl\b+.*(-u|--user).*:.*\b*
.*(-H|--header).*(token|auth.*)\b+.*|\
wget\b+.*--.*password\b+.*\b*|\
http.?://.+:.+@.*\
" > $HOME/histbuff; history -r $HOME/histbuff;
}
export PROMPT_COMMAND="sterile"
```
> 另见: [A naive utility to censor credentials in command history](https://github.com/lbonanomi/go/blob/master/revisionist.go)。
###### 快速备份文件
```bash
cp filename{,.orig}
```
###### 清空文件(截断为 0 大小)
```bash
>filename
```
###### 删除文件夹中不匹配特定文件扩展名的所有文件
```bash
rm !(*.foo|*.bar|*.baz)
```
###### 将多行字符串传入文件
```bash
# cat >filename ... - 覆写文件
# cat >>filename ... - 追加到文件
cat > filename << __EOF__
data data data
__EOF__
```
###### 使用 vim 编辑远程主机上的文件
```bash
vim scp://user@host//etc/fstab
```
###### 创建目录并同时进入
```bash
mkd() { mkdir -p "$@" && cd "$@"; }
```
###### 将大写文件名转换为小写
```bash
rename 'y/A-Z/a-z/' *
```
###### 在终端上打印一行字符
```bash
printf "%`tput cols`s" | tr ' ' '#'
```
###### 显示 Shell 历史但不显示行号
```bash
history | cut -c 8-
fc -l -n 1 | sed 's/^\s*//'
```
###### 退出会话后运行命令
```bash
cat > /etc/profile << __EOF__
_after_logout() {
username=$(whoami)
for _pid in $(ps afx | grep sshd | grep "$username" | awk '{print $1}') ; do
kill -9 $_pid
done
}
trap _after_logout EXIT
__EOF__
```
###### 生成数字序列
```bash
for ((i=1; i<=10; i+=2)) ; do echo $i ; done
# 替代方案: seq 1 2 10
for ((i=5; i<=10; ++i)) ; do printf '%02d\n' $i ; done
# 替代方案: seq -w 5 10
for i in {1..10} ; do echo $i ; done
```
###### 简单的 Bash 文件监视
```bash
unset MAIL; export MAILCHECK=1; export MAILPATH='$FILE_TO_WATCH?$MESSAGE'
```
---
##### 工具: [busybox](https://www.busybox.net/)
###### 静态 HTTP Web 服务器
```bash
busybox httpd -p $PORT -h $HOME [-c httpd.conf]
```
___
##### 工具: [mount](https://en.wikipedia.org/wiki/Mount_(Unix)) - 挂载
###### 挂载临时内存分区
```bash
mount -t tmpfs tmpfs /mnt -o size=64M
```
* `-t` - 文件系统类型
* `-o` - 挂载选项
###### 将文件系统重新挂载为读写
```bash
mount -o remount,rw /
```
___
##### 工具: [fuser](https://en.wikipedia.org/wiki/Fuser_(Unix))
###### 显示哪些进程使用指定文件/目录
```bash
fuser /var/log/daemon.log
fuser -v /home/supervisor
```
###### 杀死锁定文件的进程
```bash
fuser -ki filename
```
* `-i` - 交互式选项
###### 使用特定信号杀死锁定文件的进程
```bash
fuser -k -HUP filename
```
* `--list-signals` - 列出可用信号名称
###### 显示特定端口上监听的 PID
```bash
fuser -v 53/udp
```
###### 显示所有使用指定文件系统或块设备的进程
```bash
fuser -mv /var/www
```
___
##### 工具: [lsof](https://en.wikipedia.org/wiki/Lsof)
###### 显示当前使用互联网连接的进程
```bash
lsof -P -i -n
```
###### 显示使用特定端口号的进程
```bash
lsof -i tcp:443
```
###### 列出所有监听端口及关联进程的 PID
```bash
lsof -Pan -i tcp -i udp
```
###### 列出所有开放端口及其所属可执行文件
```bash
lsof -i -P | grep -i "listen"
```
###### 显示所有开放端口
```bash
lsof -Pnl -i
```
###### 显示开放端口 (LISTEN)
```bash
lsof -Pni4 | grep LISTEN | column -t
```
###### 列出特定命令打开的所有文件
```bash
lsof -c "process"
```
###### 查看每个目录的用户活动
```bash
lsof -u username -a +D /etc
```
###### 显示 10 个最大的打开文件
```bash
lsof / | \
awk '{ if($7 > 1048576) print $7/1048576 "MB" " " $9 " " $1 }' | \
sort -n -u | tail | column -t
```
###### 显示进程的当前工作目录
```bash
lsof -p | grep cwd
```
___
##### 工具: [ps](https://en.wikipedia.org/wiki/Ps_(Unix))
###### 显示可四向滚动的进程树及完整详情
```bash
ps awwfux | less -S
```
###### 每个用户的进程数统计
```bash
ps hax -o user | sort | uniq -c | sort -r
```
###### 按名称显示所有进程及主头部
```bash
ps -lfC nginx
```
___
##### 工具: [find](https://en.wikipedia.org/wiki/Find_(Unix)) - 查找
###### 查找系统中过去 60 分钟内修改过的文件
```bash
find / -mmin 60 -type f
```
###### 查找所有大于 20M 的文件
```bash
find / -type f -size +20M
```
###### 查找重复文件(基于 MD5 哈希)
```bash
find -type f -exec md5sum '{}' ';' | sort | uniq --all-repeated=separate -w 33
```
###### 仅更改文件权限
```bash
cd /var/www/site && find . -type f -exec chmod 766 {} \;
cd /var/www/site && find . -type f -exec chmod 664 {} +
```
###### 仅更改目录权限
```bash
cd /var/www/site && find . -type d -exec chmod g+x {} \;
cd /var/www/site && find . -type d -exec chmod g+rwx {} +
```
###### 查找特定用户/组的文件和目录
```bash
# 用户:
find . -user -print
find /etc -type f -user -name "*.conf"
# 组:
find /opt -group
find /etc -type f -group -iname "*.conf"
```
###### 查找不属于特定用户/组的文件和目录
```bash
# 用户:
find . \! -user -print
# 组:
find . \! -group
```
###### 查找仅具有特定权限的文件/目录
```bash
# 用户
find . -user -perm -u+rw # -rw-r--r--
find /home -user $(whoami) -perm 777 # -rwxrwxrwx
# 组:
find /home -type d -group -perm 755 # -rwxr-xr-x
```
###### 删除 60 天前的文件
```bash
find . -type f -mtime +60 -delete
```
###### 递归删除目录中所有空子目录
```bash
find . -depth -type d -empty -exec rmdir {} \;
```
###### 查找文件的所有硬链接
```bash
find -xdev -samefile filename
```
###### 递归查找最近修改的文件
```bash
find . -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head
```
###### 使用 sed 递归查找/替换字符串
```bash
find . -not -path '*/\.git*' -type f -print0 | xargs -0 sed -i 's/foo/bar/g'
```
###### 递归查找/替换目录和文件名中的字符串
```bash
find . -depth -name '*test*' -execdir bash -c 'mv -v "$1" "${1//foo/bar}"' _ {} \;
```
###### 递归查找 suid 可执行文件
```bash
find / \( -perm -4000 -o -perm -2000 \) -type f -exec ls -la {} \;
```
___
##### 工具: [top](https://en.wikipedia.org/wiki/Top_(software))
###### 使用 top 仅监控包含特定字符串的进程
```bash
top -p $(pgrep -d , )
```
* `` - 包含特定字符串的进程(如 nginx, worker)
___
##### 工具: [vmstat](https://en.wikipedia.org/wiki/Vmstat)
###### 显示当前系统利用率(字段以千字节为单位)
```bash
vmstat 2 20 -t -w
```
* `2` - 定义时间间隔的次数(延迟)
* `20` - 每次执行命令的次数(计数)
* `-t` - 显示时间戳
* `-w` - 宽输出
* `-S M` - 以兆字节为单位输出字段
###### 每 5 秒刷新显示当前系统利用率
```bash
vmstat 5 -w
```
###### 显示磁盘操作摘要报告
```bash
vmstat -D
```
###### 显示事件计数器和内存统计报告
```bash
vmstat -s
```
###### 显示关于 slab 层缓存中内核对象的报告
```bash
vmstat -m
```
##### 工具: [iostat](https://en.wikipedia.org/wiki/Iostat)
###### 显示 CPU 使用信息和所有分区的 I/O 统计
```bash
iostat 2 10 -t -m
```
* `2` - 时间间隔(延迟)
* `10` - 执行次数(计数)
* `-t` - 显示时间戳
* `-m` - 以兆字节为单位(`-k` 以千字节为单位,默认)
###### 仅显示 CPU 利用率信息
```bash
iostat 2 10 -t -m -c
```
###### 仅显示磁盘利用率信息
```bash
iostat 2 10 -t -m -d
```
###### 仅显示 LVM 利用率信息
```bash
iostat -N
```
___
##### 工具: [strace](https://en.wikipedia.org/wiki/Strace)
###### 带子进程追踪
```bash
# 1)
strace -f -p $(pidof glusterfsd)
# 2)
strace -f $(pidof php-fpm | sed 's/\([0-9]*\)/\-p \1/g')
```
###### 限制追踪进程 30 秒
```bash
timeout 30 strace $(< /var/run/zabbix/zabbix_agentd.pid)
```
###### 追踪进程并将输出重定向到文件
```bash
ps auxw | grep '[a]pache' | awk '{print " -p " $2}' | \
xargs strace -o /tmp/strace-apache-proc.out
```
###### 追踪并打印每个系统调用的耗时,限制打印字符串长度
```bash
ps auxw | grep '[i]init_policy' | awk '{print " -p " $2}' | \
xargs strace -f -e trace=network -T -s 10000
```
###### 追踪网络端口的打开请求
```bash
strace -f -e trace=bind nc -l 80
```
###### 追踪网络端口的打开请求(显示 TCP/UDP)
```bash
strace -f -e trace=network nc -lu 80
```
___
##### 工具: [kill](https://en.wikipedia.org/wiki/Kill_(command))
###### 杀死在端口上运行的进程
```bash
kill -9 $(lsof -i : | awk '{l=$2} END {print l}')
```
___
##### 工具: [diff](https://en.wikipedia.org/wiki/Diff)
###### 比较两个目录树
```bash
diff <(cd directory1 && find | sort) <(cd directory2 && find | sort)
```
###### 比较两个命令的输出
```bash
diff <(cat /etc/passwd) <(cut -f2 /etc/passwd)
```
___
##### 工具: [vimdiff](http://vimdoc.sourceforge.net/htmldoc/diff.html)
###### 基于字符和单词高亮精确差异
```bash
vimdiff file1 file2
```
###### 比较两个 JSON 文件
```bash
vimdiff <(jq -S . A.json) <(jq -S . B.json)
```
###### 比较十六进制转储
```bash
d(){ vimdiff <(f $1) <(f $2);};f(){ hexdump -C $1 | cut -d' ' -f3- | tr -s ' ';}; d ~/bin1 ~/bin2
```
###### diffchar
将 [diffchar](https://raw.githubusercontent.com/vim-scripts/diffchar.vim/master/plugin/diffchar.vim) 保存到 `~/.vim/plugins`
按 `F7` 在差异模式之间切换
有用的 `vimdiff` 命令:
* `qa` 退出所有窗口
* `:vertical resize 70` 调整窗口大小
* 设置窗口宽度 `Ctrl+W [N columns]+(Shift+)<\>`
___
##### 工具: [tail](https://en.wikipedia.org/wiki/Tail_(Unix))
###### 为 tail -f 添加时间戳注释
```bash
tail -f file | while read ; do echo "$(date +%T.%N) $REPLY" ; done
```
###### 分析 Apache 访问日志中最常见的 IP 地址
```bash
tail -10000 access_log | awk '{print $1}' | sort | uniq -c | sort -n | tail
```
###### 分析 Web 服务器日志并仅显示 5xx HTTP 状态码
```bash
tail -n 100 -f /path/to/logfile | grep "HTTP/[1-2].[0-1]\" [5]"
```
___
##### 工具: [tar](https://en.wikipedia.org/wiki/Tar_(computing))
###### 系统备份并排除特定目录
```bash
cd /
tar -czvpf /mnt/system$(date +%d%m%Y%s).tgz --directory=/ \
--exclude=proc/* --exclude=sys/* --exclude=dev/* --exclude=mnt/* .
```
###### 系统备份并排除特定目录 (使用 pigz 并行压缩)
```bash
cd /
tar cvpf /backup/snapshot-$(date +%d%m%Y%s).tgz --directory=/ \
--exclude=proc/* --exclude=sys/* --exclude=dev/* \
--exclude=mnt/* --exclude=tmp/* --use-compress-program=pigz .
```
___
##### 工具: [dump](https://en.wikipedia.org/wiki/Dump_(program))
###### 系统备份到文件
```bash
dump -y -u -f /backup/system$(date +%d%m%Y%s).lzo /
```
###### 从 lzo 文件还原系统
```bash
cd /
restore -rf /backup/system$(date +%d%m%Y%s).lzo
```
___
##### 工具: [cpulimit](http://cpulimit.sourceforge.net/)
###### 限制进程的 CPU 使用率
```bash
cpulimit -p pid -l 50
```
___
##### 工具: [pwdx](https://www.cyberciti.biz/faq/unix-linux-pwdx-command-examples-usage-syntax/)
###### 显示进程的当前工作目录
```bash
pwdx
```
___
##### 工具: [taskset](https://www.cyberciti.biz/faq/taskset-cpu-affinity-command/)
###### 仅在单个 CPU 核心上启动命令
```bash
taskset -c 0
```
___
##### 工具: [tr](https://en.wikipedia.org/wiki/Tr_(Unix))
###### 显示 PATH 中的目录,每行一个
```bash
tr : '\n' <<<$PATH
```
___
##### 工具: [chmod](https://en.wikipedia.org/wiki/Chmod)
###### 从当前目录中的所有文件移除可执行位
```bash
chmod -R -x+X *
```
###### 恢复 /bin/chmod 的权限
```bash
# 1:
cp /bin/ls chmod.01
cp /bin/chmod chmod.01
./chmod.01 700 file
# 2:
/bin/busybox chmod 0700 /bin/chmod
# 3:
setfacl --set u::rwx,g::---,o::--- /bin/chmod
```
___
##### 工具: [who](https://en.wikipedia.org/wiki/Who_(Unix))
###### 查找上次重启时间
```bash
who -b
```
###### 检测用户是否通过 sudo su 进入当前 Shell
```bash
[[ $(who -m | awk '{ print $1 }') == $(whoami) ]] || echo "You are su-ed to $(whoami)"
```
___
##### 工具: [last](https://www.howtoforge.com/linux-last-command/)
###### 上次重启是意外崩溃吗?
```bash
(last -x -f $(ls -1t /var/log/wtmp* | head -2 | tail -1); last -x -f /var/log/wtmp) | \
grep -A1 reboot | head -2 | grep -q shutdown && echo "Expected reboot" || echo "Panic reboot"
```
___
##### 工具: [screen](https://en.wikipedia.org/wiki/GNU_Screen)
###### 在分离模式下启动 screen
```bash
screen -d -m
```
###### 附加到现有的 screen 会话
```bash
screen -r -d
```
___
##### 工具: [script](https://en.wikipedia.org/wiki/Script_(Unix))
###### 录制和回放终端会话
```bash
### 录制会话
# 1)
script -t 2>~/session.time -a ~/session.log
# 2)
script --timing=session.time session.log
### 回放会话
scriptreplay --timing=session.time session.log
```
___
##### 工具: [du](https://en.wikipedia.org/wiki/GNU_Screen)
###### 显示 20 个最大的目录(以 K/M/G 标记)
```bash
du | \
sort -r -n | \
awk '{split("K M G",v); s=1; while($1>1024){$1/=1024; s++} print int($1)" "v[s]"\t"$2}' | \
head -n 20
```
___
##### 工具: [inotifywait](https://en.wikipedia.org/wiki/GNU_Screen)
###### 每当目录中的文件被修改时触发操作
```bash
while true ; do inotifywait -r -e MODIFY dir/ && ls dir/ ; done;
```
___
##### 工具: [openssl](https://www.openssl.org/)
###### 测试到远程主机的连接
```bash
echo | openssl s_client -connect google.com:443 -showcerts
```
###### 测试到远程主机的连接(调试模式)
```bash
echo | openssl s_client -connect google.com:443 -showcerts -tlsextdebug -status
```
###### 测试到远程主机的连接(支持 SNI)
```bash
echo | openssl s_client -showcerts -servername google.com -connect google.com:443
```
###### 使用特定 SSL 版本测试到远程主机的连接
```bash
openssl s_client -tls1_2 -connect google.com:443
```
###### 使用特定 SSL 密码测试到远程主机的连接
```bash
openssl s_client -cipher 'AES128-SHA' -connect google.com:443
```
###### 验证 0-RTT
```bash
_host="example.com"
cat > req.in << __EOF__
HEAD / HTTP/1.1
Host: $_host
Connection: close
__EOF__
openssl s_client -connect ${_host}:443 -tls1_3 -sess_out session.pem -ign_eof < req.in
openssl s_client -connect ${_host}:443 -tls1_3 -sess_in session.pem -early_data req.in
```
###### 生成无密码保护的私钥
```bash
# _len: 2048, 4096
( _fd="private.key" ; _len="2048" ; \
openssl genrsa -out ${_fd} ${_len} )
```
###### 生成带密码保护的私钥
```bash
# _ciph: aes128, aes256
# _len: 2048, 4096
( _ciph="aes128" ; _fd="private.key" ; _len="2048" ; \
openssl genrsa -${_ciph} -out ${_fd} ${_len} )
```
###### 移除私钥的密码保护
```bash
( _fd="private.key" ; _fd_unp="private_unp.key" ; \
openssl rsa -in ${_fd} -out ${_fd_unp} )
```
###### 为现有私钥添加密码保护
```bash
# _ciph: aes128, aes256
( _ciph="aes128" ; _fd="private.key" ; _fd_pass="private_pass.key" ; \
openssl rsa -${_ciph} -in ${_fd} -out ${_fd_pass}
```
###### 检查私钥
```bash
( _fd="private.key" ; \
openssl rsa -check -in ${_fd} )
```
###### 从私钥获取公钥
```bash
( _fd="private.key" ; _fd_pub="public.key" ; \
openssl rsa -pubout -in ${_fd} -out ${_fd_pub} )
```
###### 生成私钥和 CSR
```bash
( _fd="private.key" ; _fd_csr="request.csr" ; _len="2048" ; \
openssl req -out ${_fd_csr} -new -newkey rsa:${_len} -nodes -keyout ${_fd} )
```
###### 生成 CSR
```bash
( _fd="private.key" ; _fd_csr="request.csr" ; \
openssl req -out ${_fd_csr} -new -key ${_fd} )
```
###### 生成 CSR(从现有证书获取元数据)
> 其中 `private.key` 是现有的私钥。如你所见,不是从证书(公钥)生成此 CSR。也不是生成"相同"的 CSR,而是一个新的用于请求新证书的 CSR。
```bash
( _fd="private.key" ; _fd_csr="request.csr" ; _fd_crt="cert.crt" ; \
openssl x509 -x509toreq -in ${_fd_crt} -out ${_fd_csr} -signkey ${_fd} )
```
###### 使用 -config 参数生成 CSR
```bash
( _fd="private.key" ; _fd_csr="request.csr" ; \
openssl req -new -sha256 -key ${_fd} -out ${_fd_csr} \
-config <(
cat << __EOF__
[req]
default_bits = 2048
default_md = sha256
prompt = no
distinguished_name = dn
req_extensions = req_ext
[ dn ]
C = ""
ST = ""
L = ""
O = ""
OU = ""
CN = ""
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 =
DNS.2 =
DNS.3 =
__EOF__
))
```
`[ dn ]` 中的其他值:
```
countryName = "DE" # C=
stateOrProvinceName = "Hessen" # ST=
localityName = "Keller" # L=
postalCode = "424242" # L/postalcode=
postalAddress = "Keller" # L/postaladdress=
streetAddress = "Crater 1621" # L/street=
organizationName = "apfelboymschule" # O=
organizationalUnitName = "IT Department" # OU=
commonName = "example.com" # CN=
emailAddress = "webmaster@example.com" # CN/emailAddress=
```
`oids` 示例(你可能还需要通过在 `[new_oids]` 下添加以下内容来让 OpenSSL 知道 EV 所需的新字段):
```
[req]
...
oid_section = new_oids
[ new_oids ]
postalCode = 2.5.4.17
streetAddress = 2.5.4.9
```
完整示例:
```bash
( _fd="private.key" ; _fd_csr="request.csr" ; \
openssl req -new -sha256 -key ${_fd} -out ${_fd_csr} \
-config <(
cat << __EOF__
[req]
default_bits = 2048
default_md = sha256
prompt = no
distinguished_name = dn
req_extensions = req_ext
oid_section = new_oids
[ new_oids ]
serialNumber = 2.5.4.5
streetAddress = 2.5.4.9
postalCode = 2.5.4.17
businessCategory = 2.5.4.15
[ dn ]
serialNumber=00001111
businessCategory=Private Organization
jurisdictionC=DE
C=DE
ST=Hessen
L=Keller
postalCode=424242
streetAddress=Crater 1621
O=AV Company
OU=IT
CN=example.com
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = example.com
__EOF__
))
```
更多信息请参阅这些优秀的解释:
- [RFC 5280](https://tools.ietf.org/html/rfc5280)
- [How to create multidomain certificates using config files](https://apfelboymchen.net/gnu/notes/openssl%20multidomain%20with%20config%20files.html)
- [Generate a multi domains certificate using config files](https://gist.github.com/romainnorberg/464758a6620228b977212a3cf20c3e08)
- [Your OpenSSL CSR command is out of date](https://expeditedsecurity.com/blog/openssl-csr-command/)
- [OpenSSL example configuration file](https://www.tbs-certificats.com/openssl-dem-server-cert.cnf)
- [Object Identifiers (OIDs)](https://www.alvestrand.no/objectid/)
- [openssl objects.txt](https://github.com/openssl/openssl/blob/master/crypto/objects/objects.txt)
###### 列出可用的 EC 曲线
```bash
openssl ecparam -list_curves
```
###### 打印 ECDSA 私钥和公钥
```bash
( _fd="private.key" ; \
openssl ec -in ${_fd} -noout -text )
# 对于 x25519 仅提取公钥
( _fd="private.key" ; _fd_pub="public.key" ; \
openssl pkey -in ${_fd} -pubout -out ${_fd_pub} )
```
###### 生成 ECDSA 私钥
```bash
# _curve: prime256v1, secp521r1, secp384r1
( _fd="private.key" ; _curve="prime256v1" ; \
openssl ecparam -out ${_fd} -name ${_curve} -genkey )
# _curve: X25519
( _fd="private.key" ; _curve="x25519" ; \
openssl genpkey -algorithm ${_curve} -out ${_fd} )
```
###### 生成私钥和 CSR (ECC)
```bash
# _curve: prime256v1, secp521r1, secp384r1
( _fd="domain.com.key" ; _fd_csr="domain.com.csr" ; _curve="prime256v1" ; \
openssl ecparam -out ${_fd} -name ${_curve} -genkey ; \
openssl req -new -key ${_fd} -out ${_fd_csr} -sha256 )
```
###### 生成自签名证书
```bash
# _len: 2048, 4096
( _fd="domain.key" ; _fd_out="domain.crt" ; _len="2048" ; _days="365" ; \
openssl req -newkey rsa:${_len} -nodes \
-keyout ${_fd} -x509 -days ${_days} -out ${_fd_out} )
```
###### 从现有私钥生成自签名证书
```bash
# _len: 2048, 4096
( _fd="domain.key" ; _fd_out="domain.crt" ; _days="365" ; \
openssl req -key ${_fd} -nodes \
-x509 -days ${_days} -out ${_fd_out} )
```
###### 从现有私钥和 CSR 生成自签名证书
```bash
# _len: 2048, 4096
( _fd="domain.key" ; _fd_csr="domain.csr" ; _fd_out="domain.crt" ; _days="365" ; \
openssl x509 -signkey ${_fd} -nodes \
-in ${_fd_csr} -req -days ${_days} -out ${_fd_out} )
```
###### 生成 DH 公共参数
```bash
( _dh_size="2048" ; \
openssl dhparam -out /etc/nginx/ssl/dhparam_${_dh_size}.pem "$_dh_size" )
```
###### 显示 DH 公共参数
```bash
openssl pkeyparam -in dhparam.pem -text
```
###### 从 pfx 中提取私钥
```bash
( _fd_pfx="cert.pfx" ; _fd_key="key.pem" ; \
openssl pkcs12 -in ${_fd_pfx} -nocerts -nodes -out ${_fd_key} )
```
###### 从 pfx 中提取私钥和证书
```bash
( _fd_pfx="cert.pfx" ; _fd_pem="key_certs.pem" ; \
openssl pkcs12 -in ${_fd_pfx} -nodes -out ${_fd_pem} )
```
###### 从 p7b 中提取证书
```bash
# PKCS#7 文件不包含私钥。
( _fd_p7b="cert.p7b" ; _fd_pem="cert.pem" ; \
openssl pkcs7 -inform DER -outform PEM -in ${_fd_p7b} -print_certs > ${_fd_pem})
# 或:
openssl pkcs7 -print_certs -in -in ${_fd_p7b} -out ${_fd_pem})
```
###### 将 DER 转换为 PEM
```bash
( _fd_der="cert.crt" ; _fd_pem="cert.pem" ; \
openssl x509 -in ${_fd_der} -inform der -outform pem -out ${_fd_pem} )
```
###### 将 PEM 转换为 DER
```bash
( _fd_der="cert.crt" ; _fd_pem="cert.pem" ; \
openssl x509 -in ${_fd_pem} -outform der -out ${_fd_der} )
```
###### 验证私钥
```bash
( _fd="private.key" ; \
openssl rsa -noout -text -in ${_fd} )
```
###### 验证公钥
```bash
# 1)
( _fd="public.key" ; \
openssl pkey -noout -text -pubin -in ${_fd} )
# 2)
( _fd="private.key" ; \
openssl rsa -inform PEM -noout -in ${_fd} &> /dev/null ; \
if [ $? = 0 ] ; then echo -en "OK\n" ; fi )
```
###### 验证证书
```bash
( _fd="certificate.crt" ; # 格式: pem, cer, crt \
openssl x509 -noout -text -in ${_fd} )
```
###### 验证 CSR
```bash
( _fd_csr="request.csr" ; \
openssl req -text -noout -in ${_fd_csr} )
```
###### 检查私钥和证书是否匹配
```bash
(openssl rsa -noout -modulus -in private.key | openssl md5 ; \
openssl x509 -noout -modulus -in certificate.crt | openssl md5) | uniq
```
###### 检查私钥和 CSR 是否匹配
```bash
(openssl rsa -noout -modulus -in private.key | openssl md5 ; \
openssl req -noout -modulus -in request.csr | openssl md5) | uniq
```
___
##### 工具: [secure-delete](https://wiki.archlinux.org/index.php/Securely_wipe_disk) - 安全删除
###### 使用 shred 安全删除
```bash
shred -vfuz -n 10 file
shred --verbose --random-source=/dev/urandom -n 1 /dev/sda
```
###### 使用 scrub 安全删除
```bash
scrub -p dod /dev/sda
scrub -p dod -r file
```
###### 使用 badblocks 安全删除
```bash
badblocks -s -w -t random -v /dev/sda
badblocks -c 10240 -s -w -t random -v /dev/sda
```
###### 使用 secure-delete 安全删除
```bash
srm -vz /tmp/file
sfill -vz /local
sdmem -v
swapoff /dev/sda5 && sswap -vz /dev/sda5
```
___
##### 工具: [dd](https://en.wikipedia.org/wiki/Dd_(Unix))
###### 让 dd 显示进度状态
```bash
dd status=progress
watch --interval 5 killall -USR1 dd
```
###### 使用 dd 将输出重定向到文件
```bash
echo "string" | dd of=filename
```
___
##### 工具: [gpg](https://www.gnupg.org/)
###### 导出公钥
```bash
gpg --export --armor "" > username.pkey
```
* `--export` - 从所有密钥环导出所有密钥或特定密钥
* `-a|--armor` - 创建 ASCII armored 输出
###### 加密文件
```bash
gpg -e -r "" dump.sql
```
* `-e|--encrypt` - 加密数据
* `-r|--recipient` - 为特定 加密
###### 解密文件
```bash
gpg -o dump.sql -d dump.sql.gpg
```
* `-o|--output` - 用作输出文件
* `-d|--decrypt` - 解密数据(默认)
###### 搜索接收者
```bash
gpg --keyserver hkp://keyserver.ubuntu.com --search-keys ""
```
* `--keyserver` - 设置特定密钥服务器
* `--search-keys` - 在密钥服务器上搜索密钥
###### 列出加密文件中的所有数据包
```bash
gpg --batch --list-packets archive.gpg
gpg2 --batch --list-packets archive.gpg
```
___
##### 工具: [system-other](https://github.com/trimstray/the-book-of-secret-knowledge#tool-system-other) - 系统其他
###### 从 init 重启系统
```bash
exec /sbin/init 6
```
###### 从单用户模式初始化系统
```bash
exec /sbin/init
```
###### 显示进程的当前工作目录
```bash
readlink -f /proc//cwd
```
###### 显示已执行命令的实际路径名
```bash
readlink -f /proc//exe
```
##### 工具: [curl](https://curl.haxx.se)
```bash
curl -Iks https://www.google.com
```
* `-I` - 仅显示响应头
* `-k` - 使用 SSL 时的不安全连接
* `-s` - 静默模式(不显示主体)
```bash
curl -Iks --location -X GET -A "x-agent" https://www.google.com
```
* `--location` - 跟随重定向
* `-X` - 设置方法
* `-A` - 设置 user-agent
```bash
curl -Iks --location -X GET -A "x-agent" --proxy http://127.0.0.1:16379 https://www.google.com
```
* `--proxy [socks5://|http://]` - 设置代理服务器
```bash
curl -o file.pdf -C - https://example.com/Aiju2goo0Ja2.pdf
```
* `-o` - 将输出写入文件
* `-C` - 恢复传输
###### 查找你的外部 IP 地址(外部服务)
```bash
curl ipinfo.io
curl ipinfo.io/ip
curl icanhazip.com
curl ifconfig.me/ip ; echo
```
###### 重复 URL 请求
```bash
# 使用虚拟查询字符串进行 URL 序列替换:
curl -ks https://example.com/?[1-20]
# 使用 Shell 'for' 循环:
for i in {1..20} ; do curl -ks https://example.com/ ; done
```
###### 检查特定域名的 DNS 和 HTTP 跟踪及头部
```bash
### 设置域名和外部 DNS 服务器。
_domain_list=(google.com) ; _dns_list=("8.8.8.8" "1.1.1.1")
for _domain in "${_domain_list[@]}" ; do
printf '=%.0s' {1..48}
echo
printf "[\\e[1;32m+\\e[m] resolve: %s\\n" "$_domain"
for _dns in "${_dns_list[@]}" ; do
# 解析域名。
host "${_domain}" "${_dns}"
echo
done
for _proto in http https ; do
printf "[\\e[1;32m+\\e[m] trace + headers: %s://%s\\n" "$_proto" "$_domain"
# 获取 trace 和 http 头部。
curl -Iks -A "x-agent" --location "${_proto}://${_domain}"
echo
done
done
unset _domain_list _dns_list
```
___
##### 工具: [httpie](https://httpie.org/)
```bash
http -p Hh https://www.google.com
```
* `-p` - 打印请求和响应头
* `H` - 请求头
* `B` - 请求体
* `h` - 响应头
* `b` - 响应体
```bash
http -p Hh https://www.google.com --follow --verify no
```
* `-F, --follow` - 跟随重定向
* `--verify no` - 跳过 SSL 验证
```bash
http -p Hh https://www.google.com --follow --verify no \
--proxy http:http://127.0.0.1:16379
```
* `--proxy [http:]` - 设置代理服务器
##### 工具: [ssh](https://www.openssh.com/)
###### 转义序列
```
# 支持的转义序列:
~. - 终止连接(以及任何多路复用会话)
~B - 向远程系统发送 BREAK
~C - 打开命令行
~R - 请求重新生成密钥(仅 SSH 协议 2)
~^Z - 挂起 ssh
~# - 列出转发的连接
~& - 后台 ssh(当等待连接终止时)
~? - 此消息
~~ - 通过输入两次来发送转义字符本身
```
###### 比较远程文件与本地文件
```bash
ssh user@host cat /path/to/remotefile | diff /path/to/localfile -
```
###### 通过中间主机进行 SSH 连接
```bash
ssh -t reachable_host ssh unreachable_host
```
###### 通过 SSH 在远程主机上运行命令
```bash
cat > cmd.txt << __EOF__
cat /etc/hosts
__EOF__
ssh host -l user $(&1 | tee -a "${_sesdir}/$(date +%Y%m%d).log"
}
# 别名:
alias ssh='_ssh_sesslog'
```
###### 使用 Keychain 进行 SSH 登录
```bash
### 删除 ssh-agent 的所有密钥。
function _scl() {
/usr/bin/keychain --clear
}
### 添加密钥到 Keychain。
function _scg() {
/usr/bin/keychain /path/to/private-key
source "$HOME/.keychain/$HOSTNAME-sh"
}
```
###### SSH 登录不处理任何登录脚本
```bash
ssh -tt user@host bash
```
###### SSH 本地端口转发
示例 1:
```bash
# 将本地 2250 端口通过 localhost 转发到 nmap.org:443
host1> ssh -L 2250:nmap.org:443 localhost
# 连接到服务:
host1> curl -Iks --location -X GET https://localhost:2250
```
示例 2:
```bash
# 将本地 9051 端口通过 node.d.y 转发到 db.d.x:5432
host1> ssh -nNT -L 9051:db.d.x:5432 node.d.y
# 连接到服务:
host1> psql -U db_user -d db_dev -p 9051 -h localhost
```
* `-n` - 从 `/dev/null` 重定向 stdin
* `-N` - 不执行远程命令
* `-T` - 禁用伪终端分配
###### SSH 远程端口转发
```bash
# 将本地 9051 端口通过 node.d.y 从 host2 转发到 db.d.x:5432
host1> ssh -nNT -R 9051:db.d.x:5432 node.d.y
# 连接到服务:
host2> psql -U postgres -d postgres -p 8000 -h localhost
```
___
##### 工具: [linux-dev](https://www.tldp.org/LDP/abs/html/devref1.html)
###### 测试到端口的远程连接
```bash
timeout 1 bash -c "//" >/dev/null 2>&1 ; echo $?
```
* `` - 设置远程主机
* `` - 设置目标端口
###### 使用常用 Bash 工具读写 TCP 或 UDP 套接字
```bash
exec 5<>/dev/tcp//; cat <&5 & cat >&5; exec 5>&-
```
___
##### 工具: [tcpdump](http://www.tcpdump.org/)
###### 过滤(接口上的)传入流量(特定 )
```bash
tcpdump -ne -i eth0 -Q in host 192.168.252.1 and port 443
```
* `-n` - 不转换地址(`-nn` 将不解析主机名或端口)
* `-e` - 打印链路层头部
* `-i [iface|any]` - 设置接口
* `-Q|-D [in|out|inout]` - 选择发送/接收方向(`-D` - 旧版 tcpdump 版本)
* `host [ip|hostname]` - 设置主机,也可 `[host not]`
* `[and|or]` - 设置逻辑
* `port [1-65535]` - 设置端口号,也可 `[port not]`
###### 过滤(接口上的)传入流量(特定 )并写入文件
```bash
tcpdump -ne -i eth0 -Q in host 192.168.252.1 and port 443 -c 5 -w tcpdump.pcap
```
* `-c [num]` - 仅捕获 num 数量的数据包
* `-w [filename]` - 将数据包写入文件,`-r [filename]` - 从文件读取
###### 捕获所有 ICMP 数据包
```bash
tcpdump -nei eth0 icmp
```
###### 检查服务使用的协议(TCP 或 UDP)
```bash
tcpdump -nei eth0 tcp port 22 -vv -X | egrep "TCP|UDP"
```
###### 显示 ASCII 文本(用于使用 grep 或其他工具解析输出)
```bash
tcpdump -i eth0 -A -s0 port 443
```
###### 抓取两个关键字之间的所有内容
```bash
tcpdump -i eth0 port 80 -X | sed -n -e '/username/,/=ldap/ p'
```
###### 抓取所有明文 HTTP 的用户名和密码
```bash
tcpdump -i eth0 port http -l -A | egrep -i \
'pass=|pwd=|log=|login=|user=|username=|pw=|passw=|passwd=|password=|pass:|user:|username:|password:|login:|pass |user ' \
--color=auto --line-buffered -B20
```
###### 从 HTTP 请求头中提取 HTTP User Agent
```bash
tcpdump -ei eth0 -nn -A -s1500 -l | grep "User-Agent:"
```
###### 仅捕获 HTTP GET 和 POST 数据包
```bash
tcpdump -ei eth0 -s 0 -A -vv \
'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420' or 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354'
```
或简单地:
```bash
tcpdump -ei eth0 -s 0 -v -n -l | egrep -i "POST /|GET /|Host:"
```
###### 轮换捕获文件
```bash
tcpdump -ei eth0 -w /tmp/capture-%H.pcap -G 3600 -C 200
```
* `-G ` - 每 `` 秒创建一个新的 pcap
* `-C ` - 如果当前 pcap 大于 `` 则关闭并打开新的
###### 按数据包数排名的顶部主机
```bash
tcpdump -ei enp0s25 -nnn -t -c 200 | cut -f 1,2,3,4 -d '.' | sort | uniq -c | sort -nr | head -n 20
```
###### 排除任何 RFC 1918 私有地址
```bash
tcpdump -nei eth0 'not (src net (10 or 172.16/12 or 192.168/16) and dst net (10 or 172.16/12 or 192.168/16))'
```
___
##### 工具: [tcpick](http://tcpick.sourceforge.net/)
###### 实时分析数据包
```bash
while true ; do tcpick -a -C -r dump.pcap ; sleep 2 ; clear ; done
```
___
##### 工具: [ngrep](http://ngrep.sourceforge.net/usage.html)
```bash
ngrep -d eth0 "www.domain.com" port 443
```
* `-d [iface|any]` - 设置接口
* `[domain]` - 设置主机名
* `port [1-65535]` - 设置端口号
```bash
ngrep -d eth0 "www.domain.com" src host 10.240.20.2 and port 443
```
* `(host [ip|hostname])` - 按 IP 或主机名过滤
* `(port [1-65535])` - 按端口号过滤
```bash
ngrep -d eth0 -qt -O ngrep.pcap "www.domain.com" port 443
```
* `-q` - 安静模式(仅有效载荷)
* `-t` - 添加时间戳
* `-O [filename]` - 将输出保存到文件,`-I [filename]` - 从文件读取
```bash
ngrep -d eth0 -qt 'HTTP' 'tcp'
```
* `HTTP` - 显示 HTTP 头部
* `tcp|udp` - 设置协议
* `[src|dst] host [ip|hostname]` - 设置特定节点的方向
```bash
ngrep -l -q -d eth0 -i "User-Agent: curl*"
```
* `-l` - stdout 行缓冲
* `-i` - 不区分大小写搜索
___
##### 工具: [hping3](http://www.hping.org/)
```bash
hping3 -V -p 80 -s 5050 www.google.com
```
* `-V|--verbose` - 详细模式
* `-p|--destport` - 设置目标端口
* `-s|--baseport` - 设置源端口
* `` - 设置扫描类型
* `-F|--fin` - 设置 FIN 标志,端口开放则无回复
* `-S|--syn` - 设置 SYN 标志
* `-P|--push` - 设置 PUSH 标志
* `-A|--ack` - 设置 ACK 标志(当 ping 被阻止时使用,端口开放则返回 RST 响应)
* `-U|--urg` - 设置 URG 标志
* `-Y|--ymas` - 设置 Y 未使用标志(0x80 - nullscan),端口开放则无回复
* `-M 0 -UPF` - 设置 TCP 序列号和扫描类型(URG+PUSH+FIN),端口开放则无回复
```bash
hping3 -V -c 1 -1 -C 8 www.google.com
```
* `-c [num]` - 数据包计数
* `-1` - 设置 ICMP 模式
* `-C|--icmptype [icmp-num]` - 设置 icmp 类型(默认 icmp-echo = 8)
```bash
hping3 -V -c 1000000 -d 120 -S -w 64 -p 80 --flood --rand-source
```
* `--flood` - 尽可能快地发送数据包(不显示回复)
* `--rand-source` - 随机源地址模式
* `-d --data` - 数据大小
* `-w|--win` - winsize(默认 64)
___
##### 工具: [nmap](https://nmap.org/)
###### Ping 扫描网络
```bash
nmap -sP 192.168.0.0/24
```
###### 仅显示开放端口
```bash
nmap -F --open 192.168.0.0/24
```
###### 全 TCP 端口扫描及服务版本检测
```bash
nmap -p 1-65535 -sV -sS -T4 192.168.0.0/24
```
###### Nmap 扫描并将输出传递给 Nikto
```bash
nmap -p80,443 192.168.0.0/24 -oG - | nikto.pl -h -
```
###### 使用 Nmap NSE 脚本堆栈侦察特定 ip:service
```bash
# 设置变量:
_hosts="192.168.250.10"
_ports="80,443"
# 设置 Nmap NSE 脚本堆栈:
_nmap_nse_scripts="+dns-brute,\
+http-auth-finder,\
+http-chrono,\
+http-cookie-flags,\
+http-cors,\
+http-cross-domain-policy,\
+http-csrf,\
+http-dombased-xss,\
+http-enum,\
+http-errors,\
+http-git,\
+http-grep,\
+http-internal-ip-disclosure,\
+http-jsonp-detection,\
+http-malware-host,\
+http-methods,\
+http-passwd,\
+http-phpself-xss,\
+http-php-version,\
+http-robots.txt,\
+http-sitemap-generator,\
+http-shellshock,\
+http-stored-xss,\
+http-title,\
+http-unsafe-output-escaping,\
+http-useragent-tester,\
+http-vhosts,\
+http-waf-detect,\
+http-waf-fingerprint,\
+http-xssed,\
+traceroute-geolocation.nse,\
+ssl-enum-ciphers,\
+whois-domain,\
+whois-ip"
# 设置 Nmap NSE 脚本参数:
_nmap_nse_scripts_args="dns-brute.domain=${_hosts},http-cross-domain-policy.domain-lookup=true,"
_nmap_nse_scripts_args+="http-waf-detect.aggro,http-waf-detect.detectBodyChanges,"
_nmap_nse_scripts_args+="http-waf-fingerprint.intensive=1"
# 执行扫描:
nmap --script="$_nmap_nse_scripts" --script-args="$_nmap_nse_scripts_args" -p "$_ports" "$_hosts"
```
___
##### 工具: [netcat](http://netcat.sourceforge.net/)
```bash
nc -kl 5000
```
* `-l` - 监听传入连接
* `-k` - 客户端断开后继续监听
* `>filename.out` - 将接收到的数据保存到文件(可选)
```bash
nc 192.168.0.1 5051 < filename.in
```
* `< filename.in` - 发送数据到远程主机
```bash
nc -vz 10.240.30.3 5000
```
* `-v` - 详细输出
* `-z` - 扫描监听守护进程
```bash
nc -vzu 10.240.30.3 1-65535
```
* `-u` - 仅扫描 udp 端口
###### 传输数据文件(归档)
```bash
server> nc -l 5000 | tar xzvfp -
client> tar czvfp - /path/to/dir | nc 10.240.30.3 5000
```
###### 启动远程 Shell
```bash
# 1)
server> nc -l 5000 -e /bin/bash
client> nc 10.240.30.3 5000
# 2)
server> rm -f /tmp/f; mkfifo /tmp/f
server> cat /tmp/f | /bin/bash -i 2>&1 | nc -l 127.0.0.1 5000 > /tmp/f
client> nc 10.240.30.3 5000
```
###### 简单文件服务器
```bash
while true ; do nc -l 5000 | tar -xvf - ; done
```
###### 简单的极简 HTTP 服务器
```bash
while true ; do nc -l -p 1500 -c 'echo -e "HTTP/1.1 200 OK\n\n $(date)"' ; done
```
###### 简单 HTTP 服务器
> 每次请求后重启 Web 服务器 - 移除 `while` 条件则仅允许单次连接。
```bash
cat > index.html << __EOF__
Hello! It's a site.