1.学习windows和Linux命令;
2.完成dvwa的第二个模块command execution(命令注入);
3.继续学习php(重点关注数据类型和php弱类型)
4.巩固练习:完成攻防世界web新手练习区的command_execution和simple_php;Jarvis OJ web的localhost和admin
命令注入攻击的常见模式为:仅仅需要输入数据的场合,却伴随着数据同时输入了恶意代码,而装载数据的系统对此并未设计良好的过滤过程,导致恶意代码也一并执行,最终导致信息泄露或者正常数据的破坏。
PHP命令注入攻击漏洞是PHP应用程序中常见的脚本漏洞之一,国内著名的Web应用程序Discuz!、DedeCMS等都曾经存在过该类型漏洞。
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "{$cmd}
";
}
?>
相关函数介绍:
stristr函数搜索字符串在另一字符串中的第一次出现,返回字符串的剩余部分(从匹配点),如果未找到所搜索的字符串,则返回 FALSE。参数string规定被搜索的字符串,参数search规定要搜索的字符串(如果该参数是数字,则搜索匹配该数字对应的 ASCII 值的字符),可选参数before_true为布尔型,默认为“fa lse” ,如果设置为 “true”,函数将返回 search 参数第一次出现之前的字符串部分。
这个函数会返回运行php的操作系统的相关描述,参数mode可取值
”a” (此为默认,包含序列”s n r v m”里的所有模式)
”s ”(返回操作系统名称)
”n”(返回主机名)
”r”(返回版本名称)
”v”(返回版本信息)
”m”(返回机器类型)
可以看到,服务器通过判断操作系统执行不同ping命令,但是对ip参数并未做任何的过滤,导致了严重的命令注入漏洞。
window和linux系统都可以用&&来执行多条命令
127.0.0.1&&net user
命令连接符
command1 && command2 先执行command1后执行command2
command1 | command2 只执行command2
command1 & command2 先执行command2后执行command1
以上三种连接符在windows和linux环境下都支持
如果程序没有进行过滤,那么我们就可以通过连接符执行多条系统命令。
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = $_REQUEST[ 'ip' ];
// Set blacklist
$substitutions = array(
'&&' => '',
';' => '',
);
// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "{$cmd}
";
}
?>
相比Low级别的代码,服务器端对ip参数做了一定过滤,即把”&&” ,”;”删除,本质上采用的是黑名单机制,因此依旧存在安全问题。
127.0.0.1&net user
因为被过滤的只有”&&”与” ;”,所以”&”不会受影响。
这里需要注意的是”&&”与” &”的区别:
Command 1&&Command 2
先执行Command 1,执行成功后执行Command 2,否则不执行Command 2
Command 1&Command 2
先执行Command 1,不管是否成功,都会执行Command 2
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$target = trim($_REQUEST[ 'ip' ]);
// Set blacklist
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "{$cmd}
";
}
?>
相比Medium级别的代码,High级别的代码进一步完善了黑名单,但由于黑名单机制的局限性,我们依然可以绕过。
黑名单看似过滤了所有的非法字符,但仔细观察到是把”| ”(注意这里|后有一个空格)替换为空字符,于是 ”|” 就有用了。
127.0.0.1|net user
Command 1 | Command 2
“|”是管道符,表示将Command 1的输出作为Command 2的输入,并且只打印Command 2执行的结果。
<?php
if( isset( $_POST[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$target = $_REQUEST[ 'ip' ];
$target = stripslashes( $target );
// Split the IP into 4 octects
$octet = explode( ".", $target );
// Check IF each octet is an integer
if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
// If all 4 octets are int's put the IP back together.
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
// Determine OS and execute the ping command.
if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
// Windows
$cmd = shell_exec( 'ping ' . $target );
}
else {
// *nix
$cmd = shell_exec( 'ping -c 4 ' . $target );
}
// Feedback for the end user
echo "{$cmd}
";
}
else {
// Ops. Let the user name theres a mistake
echo 'ERROR: You have entered an invalid IP.
';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
stripslashes(string)
stripslashes函数会删除字符串string中的反斜杠,返回已剥离反斜杠的字符串。
explode(separator,string,limit)
把字符串打散为数组,返回字符串的数组。参数separator规定在哪里分割字符串,参数string是要分割的字符串,可选参数limit规定所返回的数组元素的数目。
is_numeric(string)
检测string是否为数字或数字字符串,如果是返回TRUE,否则返回FALSE。
可以看到,Impossible级别的代码加入了Anti-CSRF token,同时对参数ip进行了严格的限制,只有诸如“数字.数字.数字.数字”的输入才会被接收执行,因此不存在命令注入漏洞.
附上大佬文章一篇,基本是按照他的做的,我把页面的乱码改成了正常显示的文字,方便理解意思。
PHP一共支持八种数据类型。
4种标量类型:
1.boolean(布尔型)
2. integer(整形)
3. float/double(浮点型)
4. string(字符串类型)
两种复合类型:
1.array(数组)
2.object(对象)
两种特殊类型:
1.resource(资源)
2.bull.
定义数据的语法格式:
$array = (‘value1’,‘value2’…) $array[‘key’] = ‘value’
== 资源(resource)==
资源是由专门的函数来建立和使用的,它是一种特殊的数据类型,并由程序员分配。在使用资源时,要及时释放不需要的资源。如果忘记释放资源,系统自动启动垃圾回收机制,避免内存消耗殆尽。
空值(null)
表示变量没有值。NULL不区分大小写,null和NULL都是一样。
为NULL的情况:
被赋为null;
尚未被赋值;
通过函数unset()而被销毁。
参考文章1参考文章2
啥叫弱类型????
找到以下解释:
强/弱类型是指类型检查的严格程度。语言有无类型、弱类型、强类型3种。
无类型的不检查,甚至不区分指令和数据。
弱类型的检查很弱,仅能严格地区分指令和数据。
强类型则严格在编译期进行检查。
弱类型允许将一块内存看做多种类型。比如直接将整型变量与字符变量相加。C和C++是静态语言,也是弱类型语言,Perl和PHP是动态语言,但也是弱类型语言。强类型语言在没有强制类型转化前,不允许两种不同的类型变量相互操作。Java,C#和Python都是强类型语言。
PHP为撒是弱类型语言?
找到以下解释:
php 将一块内存看成多类型的, 字符串变量和正型变量直接相加,也是动态语言
php底层所有变量都是以结构体zval来实现 ,其中refcount__gc和is_ref__gc表示变量是否是一个引用。type字段标识变量的类型,type的值可以是:IS_NULL,IS_BOOL,IS_LONG,IS_FLOAT,IS_STRING,IS_ARRAY,IS_OBJECT,IS_RESOURCE。PHP根据type的类型,来选择如何存储到zvalue_value。
例如:$val = ‘helloworld’; v a l 的 变 量 名 存 储 在 变 量 符 号 表 中 , 代 表 val的变量名存储在变量符号表中,代表 val的变量名存储在变量符号表中,代表val的类型和值的zval结构存储在哈希表中,内核通过变量的符号表与zval地址的哈希映射,来实现PHP变量的存取。
=== 在进行比较的时候,会先判断两种字符串的类型是否相等,再比较
==在进行比较的时候,会先将字符串类型转化成相同,再比较
php不会严格检验传入的变量类型,也可以将变量自由的转换类型。
另外,如果一个数值和字符串进行比较的时候,会将字符串转换成数值.
1 、观察上述代码,“admin”==0 比较的时候,会将admin转化成数值,强制转化,由于admin是字符串,转化的结果是0自然和0相等。
2 、“1admin”==1 比较的时候会将1admin转化成数值,结果为1,而“admin1“==1 却等于错误,也就是"admin1"被转化成了0。
3 、“0e123456”=="0e456789"相互比较的时候,会将0e这类字符串识别为科学技术法的数字,0的无论多少次方都是零,所以相等。
应当注意的是: 当一个字符串被当作一个数值来取值,其结果和类型如下:如果该字符串没有包含 ‘.’ ,‘e’ , ‘E’,并且其数值值在整形的范围之内 该字符串被当作int来取值,其他所有情况下都被作为float来取值,该字符串的开始部分决定了它的值,如果该字符串以合法的数值开始,则使用该数值,否则其值为0。
参考文章
先读代码:
get a和b的值
如果a和0比较返回为true而且a为真
而且b不是纯数字
而且b要大于1234
满足这些条件则返回flag
分析代码
a可以=abcd(以0开头会认为是八进制数字)
因为b不能是纯数字而且要大于1234(很明显提醒你了,可以在数字后面加字母表示非纯数字)
则b可以=9958c
然后把a=abcd,b=9958c写进去即可
先ping一本地网址,可以跑通
尝试拼接命令:127.0.0.1 | find / -name “flag.txt”,发现flag.txt路径;
使用拼接命令127.0.0.1 | cat /home/flag.txt,得到flag。