命令注入简介

成因

简单来说就是服务器上的应用程序有的时候需要去使用shell提供的命令(比如利用mv移动一个文件之类的),当这个应用程序把用户提供的数据交给shell的时候,就有可能发生命令注入。

常见语言执行系统命令

这里简单总结了java、PHP和Python这几种语言执行系统命令的代码。

java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import java.io.IOException;

public class RunSystemCommand {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder("touch", "/root/javaRuncommand");
Process p;
{
try {
p = pb.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

这里需要注意的是,如果希望能够显示结果,需要把输出重定向一下。

python

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import os
import subprocess

# os.system("ping www.baidu.com")

# os.popen("touch /root/python")

subprocess.Popen("date")

这里只推荐subprocess包下的程序了,其他的并不推荐使用。

php

1
2
3
4
5
6
<?php
# echo exec("ipconfig");
# echo system("ipconfig");
# echo shell_exec("ipconfig");
passthru("ipconfig");
?>

常见注入方法

在理解注入方法之前,首先需要理解shell中的一些操作,比如&&表示前面的一条命令成功执行就执行后面一条命令等,这些基础操作在这里不再赘述。基于这些bash的操作,就有了一些常见的方法:

  • 利用分号来执行多个命令
  • 利用&&||来进行分割
  • 利用管道符|

常见绕过方法

一般来说上面的注入方法是无法得逞的,因为类似分号和&这种符号肯定会被过滤掉的,这个时候就需要用一些小技巧来绕过,以下的绕过方法均以执行ls为例。

  • 利用环境变量巧妙执行:env1=l;env2=s;$env1$env2,相当于拼接出了ls
  • 利用bash通配符(注意通配符可能会出现多种符合的情况)/?in/?s会提示你到底是/bin/ls还是/bin/ss
  • 利用一些编码绕过,比如lsbase64编码是bHM=,那么就可以用$(echo "bHM=" | base64 -d)来执行ls

防御手段

  • 根本解决之道:不要使用系统命令。这是因为绝大部分的功能都可以通过那些第三方的库完成而不需要使用这些shell函数。
  • 如果实在无法避免使用shell函数,那么就避免将外界输入的字符传入进去
  • 如果连外界字符传入都无法避免,那么就使用函数对输入进行检查,尤其需要转义掉shell的元字符#&;\,|*?~<>^()[]{}$