00.jpg

最后一舞离一等奖最近的一次,因为数据安全第二题浪费太多时间,导致web2来不及了,开始因为fenjing没换模板,后面手注爆的差一点😭
还是把希望寄托给学弟了哈哈哈

Web

咋输不进去捏

题目内容:咋输不进去捏,咋这么奇怪捏?

01.jpg

根据前端源码就行了

02.png

Crypto

简单数学题

题目内容:简单数学题
from Crypto.Util.number import *

sum_pq = 15870713655456272818998868095126610389501417235762009793315127525027164306871912572802442396878309282140184445917718237547340279497682840149930939938364752
diff_pq = 836877201325346306269647062252443025692393860257609240213263622058769344319275021861627524327674665653956022396760961371531780934904914806513684926008590
e = 65537
c = 24161337439375469726924397660125738582989340535865292626109110404205047138648291988394300469831314677804449487707306159537988907383165388647811395995713768215918986950780552907040433887058197369446944754008620731946047814491450890197003594397567524722975778515304899628035385825818809556412246258855782770070

p = (sum_pq + diff_pq) // 2
q = (sum_pq - diff_pq) // 2

phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
n = p * q
m = pow(c, d, n)

flag = long_to_bytes(m)
print(f"Flag: {flag.decode('utf-8')}")

AES

题目内容:AES
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import hashlib

iv_str = "0123456789abcdef"

ciphertext_b64 = "H4vkfGfsU+qBEwaa7ea9gBkRcraMqbe4BGaxDb/9JG4zGleqT1VxyzGbDj/yuQn8"

password = "Cryptography"

def decrypt_aes_cbc(ciphertext_b64, password, iv_str):
    try:
        key = hashlib.md5(password.encode()).digest()[:16]
        
        ciphertext = base64.b64decode(ciphertext_b64)

        iv = iv_str.encode()

        cipher = AES.new(key, AES.MODE_CBC, iv)

        decrypted_padded = cipher.decrypt(ciphertext)

        plaintext = unpad(decrypted_padded, AES.block_size)

        return plaintext.decode('utf-8')

    except Exception as e:
        print(f"解密出错: {e}")
        return None

plaintext_decrypted = decrypt_aes_cbc(ciphertext_b64, password, iv_str)

if plaintext_decrypted is not None:
    print(f"解密后的明文: {plaintext_decrypted}")
else:
    print("解密失败")

base64

题目内容:REFTQ1RGezQwYjkwNTA4ZjYzYmM3OTYyOGIyZWRjNzc1ZTE0OGI5fQ==

请尝试使用base64解码

DASCTF{40b90508f63bc79628b2edc775e148b9}

Misc

easySteg0

题目内容:easy stego

图片备注中有表

03.png

table: FI0EHKRkclAYN/xvgim2XCUdSf8O6osJVPb+LZu5nyQjqGt49BDwhrz3pWTaeM17

文件尾处找到压缩包文件

09.png

526172211a0701003392b5e50a01050600050101808000959525532e02030b970004970020197f88b9800000126561737953746567302f666c61672e7478740a030275a1a3332d4adc014441534354467b6e6f666c6167686572655f6e7466737d35856c841e032308c1800004b68000003fc2ed198003000353544d07073a632e747874c1a53e2656423f933c83ab6b96c84084e4fc49041c0944381453877fa55c87d4fbed9e7e1b2569fd7c51d15370ed146215046bfbfa21bfb135379c9b780a85ec80969d8de92302030b0005001000000000800000096561737953746567300a030244a0b7fb2c4adc011d77565103050400

解压后看见两个文件其中一个为密文

04.png

iHK2griRswoPfuKPNEluNwXpN+KuSUC+NwoPf2lPf2LBNEL9Nul+Jg

05.png

DASCTF{7afaa02f35821faec37ae2ae910902bc}

Simple_Domain

题目内容:dict and system!!!

磁盘读取工具中,kali自带的secretsdump.py可以直接读取

python3 /usr/share/doc/python3-impacket/examples/secretsdump.py -ntds ntds.dit -system system LOCA

10.png

└─# python3 /usr/share/doc/python3-impacket/examples/secretsdump.py -ntds ntds.dit -system system LOCAL
Impacket v0.13.0.dev0 - Copyright Fortra, LLC and its affiliated companies 

[*] Target system bootKey: 0xae5564d04e225ccba0d2643161c48b10
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: ddb6a826834aad5816b4c80b5220276b
[*] Reading and decrypting hashes from ntds.dit 
KINGSLANDING$:1001:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Administrator:500:aad3b435b51404eeaad3b435b51404ee:dbd13e1c4e338284ac4e9874f7de6ef4:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
vagrant:1000:aad3b435b51404eeaad3b435b51404ee:e02bc503339d51f71d913c245d35b50b:::
WINTERFELL$:1001:aad3b435b51404eeaad3b435b51404ee:aa685d65871bfdf122009745b03f8e01:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:8bf38852ab8d3a887ae867500c9a48c5:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
vagrant:1000:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
ESSOS$:1104:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
NORTH$:1105:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
CASTELBLACK$:1104:aad3b435b51404eeaad3b435b51404ee:723026eda8195b4bd9e82caef809c40f:::
arya.stark:1109:aad3b435b51404eeaad3b435b51404ee:4f622f4cd4284a887228940e2ff4e709:::
tywin.lannister:1113:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
eddard.stark:1110:aad3b435b51404eeaad3b435b51404ee:d977b98c6c9282c5c478be1d97b237b8:::
jaime.lannister:1114:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
catelyn.stark:1111:aad3b435b51404eeaad3b435b51404ee:cba36eccfd9d949c73bc73715364aff5:::
robb.stark:1112:aad3b435b51404eeaad3b435b51404ee:831486ac7f26860c9e2f51ac91e1a07a:::
cersei.lannister:1115:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
tyron.lannister:1116:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
sansa.stark:1113:aad3b435b51404eeaad3b435b51404ee:2c643546d00054420505a2bf86d77c47:::
brandon.stark:1114:aad3b435b51404eeaad3b435b51404ee:84bbaa1c58b7f69d2192560a3f932129:::
robert.baratheon:1117:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
joffrey.baratheon:1118:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
rickon.stark:1115:aad3b435b51404eeaad3b435b51404ee:7978dc8a66d8e480d9a86041f8409560:::
hodor:1116:aad3b435b51404eeaad3b435b51404ee:337d2667505c203904bd899c6c95525e:::
renly.baratheon:1119:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
stannis.baratheon:1120:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
jon.snow:1117:aad3b435b51404eeaad3b435b51404ee:b8d76e56e9dac90539aff05e3ccb1755:::
samwell.tarly:1118:aad3b435b51404eeaad3b435b51404ee:f5db9e027ef824d029262068ac826843:::
petyer.baelish:1121:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
lord.varys:1122:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
jeor.mormont:1119:aad3b435b51404eeaad3b435b51404ee:6dccf1c567c56a40e56691a723a49664:::
sql_svc:1120:aad3b435b51404eeaad3b435b51404ee:84a5092f53390ea48d660be52b93b804:::
maester.pycelle:1123:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SEVENKINGDOMS$:1121:aad3b435b51404eeaad3b435b51404ee:1b89cf55c349b296a8fc34f95d7580e0:::
[*] Kerberos keys from ntds.dit 
Administrator:aes256-cts-hmac-sha1-96:e7aa0f8a649aa96fab5ed9e65438392bfc549cb2695ac4237e97996823619972
Administrator:aes128-cts-hmac-sha1-96:bb7b6aed58a7a395e0e674ac76c28aa0
Administrator:des-cbc-md5:fe58cdcd13a43243
vagrant:aes256-cts-hmac-sha1-96:aa97635c942315178db04791ffa240411c36963b5a5e775e785c6bd21dd11c24
vagrant:aes128-cts-hmac-sha1-96:0d7c6160ffb016857b9af96c44110ab1
vagrant:des-cbc-md5:16dc9e8ad3dfc47f
WINTERFELL$:aes256-cts-hmac-sha1-96:c0880c4af7d14d09402a8138bb48d1b526e1fa5f5fc4ce4f9fe89ef2422eb304
WINTERFELL$:aes128-cts-hmac-sha1-96:23b19c152d6b8c3aa275b16b082675ed
WINTERFELL$:des-cbc-md5:7ff72c75d5d683b5
krbtgt:aes256-cts-hmac-sha1-96:82b8cbbbe398df35611657a4fab06f32fedc6a9c0036ae6e0988193de5c30a8c
krbtgt:aes128-cts-hmac-sha1-96:d4a753716a2747b19c1eb09a9e0d4a97
krbtgt:des-cbc-md5:708ad92523fdf7b6
CASTELBLACK$:aes256-cts-hmac-sha1-96:ac20a1c7051889152b6811094c6e52bd854d347a0e9b52ad63b6ea98794b1423
CASTELBLACK$:aes128-cts-hmac-sha1-96:c1fe9a27470b9bd8e0e9537e4f63b3ae
CASTELBLACK$:des-cbc-md5:fec498bf3eea5ef8
arya.stark:aes256-cts-hmac-sha1-96:2001e8fb3da02f3be6945b4cce16e6abdd304974615d6feca7d135d4009d4f7d
arya.stark:aes128-cts-hmac-sha1-96:8477cba28e7d7cfe5338d172a23d74df
arya.stark:des-cbc-md5:13525243d6643285
eddard.stark:aes256-cts-hmac-sha1-96:f6b4d01107eb34c0ecb5f07d804fa9959dce6643f8e4688df17623b847ec7fc4
eddard.stark:aes128-cts-hmac-sha1-96:5f9b06a24b90862367ec221a11f92203
eddard.stark:des-cbc-md5:8067f7abecc7d346
catelyn.stark:aes256-cts-hmac-sha1-96:c8302e270b04252251de40b2bd5fba37395b55d5ed9ac95e03213dc739827283
catelyn.stark:aes128-cts-hmac-sha1-96:50ce7e2ad069fa40fb2bc7f5f9643d93
catelyn.stark:des-cbc-md5:6b314670a2f84cfb
robb.stark:aes256-cts-hmac-sha1-96:d7df5069178bbc93fdc34bbbcb8e374fd75c44d6ce51000f24688925cc4d9c2a
robb.stark:aes128-cts-hmac-sha1-96:b2965905e68356d63fedd9904357cc42
robb.stark:des-cbc-md5:c4b62c797f5dd01f
sansa.stark:aes256-cts-hmac-sha1-96:cd2460a78e8993442498d3f242a88ae110ec6556e40c8add6aab12cfb44b3fa1
sansa.stark:aes128-cts-hmac-sha1-96:18b9d10bd18d1956ba73c14426ec519f
sansa.stark:des-cbc-md5:e66445757c31c176
brandon.stark:aes256-cts-hmac-sha1-96:6dd181186b68898376d3236662f8aeb8fa68e4b5880744034d293d18b6753b10
brandon.stark:aes128-cts-hmac-sha1-96:9de3581a163bd056073b71ab23142d73
brandon.stark:des-cbc-md5:76e61fda8a4f5245
rickon.stark:aes256-cts-hmac-sha1-96:79ffda34e5b23584b3bd67c887629815bb9ab8a1952ae9fda15511996587dcda
rickon.stark:aes128-cts-hmac-sha1-96:d4a0669b1eff6caa42f2632ebca8cd8d
rickon.stark:des-cbc-md5:b9ec3b8f2fd9d98a
hodor:aes256-cts-hmac-sha1-96:a33579ec769f3d6477a98e72102a7f8964f09a745c1191a705d8e1c3ab6e4287
hodor:aes128-cts-hmac-sha1-96:929126dcca8c698230b5787e8f5a5b60
hodor:des-cbc-md5:d5764373f2545dfd
jon.snow:aes256-cts-hmac-sha1-96:5a1bc13364e758131f87a1f37d2f1b1fa8aa7a4be10e3fe5a69e80a5c4c408fb
jon.snow:aes128-cts-hmac-sha1-96:d8bc99ccfebe2d6e97d15f147aa50e8b
jon.snow:des-cbc-md5:084358ceb3290d7c
samwell.tarly:aes256-cts-hmac-sha1-96:b66738c4d2391b0602871d0a5cd1f9add8ff6b91dcbb7bc325dc76986496c605
samwell.tarly:aes128-cts-hmac-sha1-96:3943b4ac630b0294d5a4e8b940101fae
samwell.tarly:des-cbc-md5:5efed0e0a45dd951
jeor.mormont:aes256-cts-hmac-sha1-96:be10f893afa35457fcf61ecc40dc032399b7aee77c87bb71dd2fe91411d2bd50
jeor.mormont:aes128-cts-hmac-sha1-96:1b0a98958e19d6092c8e8dc1d25c788b
jeor.mormont:des-cbc-md5:1a68641a3e9bb6ea
sql_svc:aes256-cts-hmac-sha1-96:24d57467625d5510d6acfddf776264db60a40c934fcf518eacd7916936b1d6af
sql_svc:aes128-cts-hmac-sha1-96:01290f5b76c04e39fb2cb58330a22029
sql_svc:des-cbc-md5:8645d5cd402f16c7
SEVENKINGDOMS$:aes256-cts-hmac-sha1-96:c2ac7ab055d49ba523564eab3bfe041e026ce6745413cb8ea19514771de06080
SEVENKINGDOMS$:aes128-cts-hmac-sha1-96:5796cbf539ac141f8fed3a05892eff12
SEVENKINGDOMS$:des-cbc-md5:92d5bf79fe57158a
[*] Cleaning up... 

根据压缩包注释提示密码长32且与Administrator有关经过搜索尝试最后解压码为dbd13e1c4e338284ac4e9874f7de6ef4

11.png

DASCTF{dbd13e1c4e338284ac4e9874f7de6ef9}

AI

寻找可爱的小狗

直接翻6只猫出来

06.png

import hashlib

# 需要加密的字符串
text = "26c39cf8-55fb-4899-82bc-442cf4627d95.jpg+6e17fffa-b696-4769-9b43-e0f453f8098d.jpg+7a19da17-9f4a-411b-bac7-83d2454d868a.jpg+897a3a87-dfcf-4233-8097-6bba2e6507ba.jpg+c6b1099a-d626-4cbd-94fc-32aa46ffb02b.jpg+d5117480-7943-48f8-9e79-67fdd51092d2.jpg"
# 计算 MD5 哈希值
md5_hash = hashlib.md5(text.encode('utf-8')).hexdigest()

# 输出结果
print(f'[+] str  :{text}')
print(f'[+] MD5 hash :{md5_hash}')

# [+] MD5 hash :4c5e686c28a5409e6f19598b97d39964

DS

check1

题目内容:某互联网公司在数据迁移过程中发现用户注册信息存在不一致,不规范的问题,需要对用户数据进行规范性和一致性验证,确保数据质量符合业务要求,将提取出的正确的数据保存为csv文件,提交到验证靶机,若准确率通过则给出flag。
import re
from datetime import datetime


def validate_id_card(id_card):
    """验证身份证号格式和校验码"""
    # 长度验证
    if len(id_card) != 18:
        return False

    # 字符验证:前17位为数字,第18位为数字或X
    if not re.match(r'^\d{17}[\dXx]$', id_card):
        return False

    # 校验码验证
    # 加权因子
    weights = [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']

    # 计算前17位数字的加权和
    sum_value = sum(int(id_card[i]) * weights[i] for i in range(17))
    # 计算校验码
    check_code = check_codes[sum_value % 11]

    return id_card[17].upper() == check_code


def get_gender_from_id_card(id_card):
    """从身份证号获取性别"""
    # 第17位(倒数第2位)奇数为男性,偶数为女性
    gender_digit = int(id_card[16])
    return '男' if gender_digit % 2 == 1 else '女'


def validate_phone(phone):
    """验证手机号格式"""
    # 长度为11位数字,开头为1
    return re.match(r'^1\d{10}$', phone) is not None


def validate_name(name):
    """验证姓名格式(2-4个汉字)"""
    # 汉字的Unicode范围
    return re.match(r'^[\u4e00-\u9fa5]{2,4}$', name) is not None


def validate_date_format(date_str):
    """验证日期格式是否正确"""
    try:
        datetime.strptime(date_str, '%Y-%m-%d')
        return True
    except ValueError:
        return False


def validate_datetime_format(datetime_str):
    """验证时间格式是否正确"""
    try:
        datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S')
        return True
    except ValueError:
        return False


def validate_time_logic(birth_date, register_time, login_time):
    """验证时间逻辑"""
    try:
        birth_dt = datetime.strptime(birth_date, '%Y-%m-%d')
        register_dt = datetime.strptime(register_time, '%Y-%m-%d %H:%M:%S')
        login_dt = datetime.strptime(login_time, '%Y-%m-%d %H:%M:%S')

        # 出生日期必须早于注册时间
        if birth_dt >= register_dt:
            return False, "出生日期必须早于注册时间"

        # 注册时间必须早于或等于最后登录时间
        if register_dt > login_dt:
            return False, "注册时间必须早于或等于最后登录时间"

        return True, ""
    except ValueError as e:
        return False, f"时间格式错误: {str(e)}"


def validate_row(data_list, original_line):
    """验证一行数据"""
    if len(data_list) != 8:
        return False, f"数据字段数量不正确,期望8个字段,实际{len(data_list)}个字段"

    customer_id, name, id_card, gender, phone, birth_date, register_time, login_time = data_list

    # 1. 身份证号验证
    if not validate_id_card(id_card):
        return False, "身份证号格式或校验码错误"

    # 2. 性别一致性验证
    id_gender = get_gender_from_id_card(id_card)
    if gender != id_gender:
        return False, f"性别不一致,身份证号对应性别为{id_gender},但字段值为{gender}"

    # 3. 出生日期一致性验证
    id_birth_date = id_card[6:14]  # 身份证号第7-14位
    formatted_birth_date = f"{id_birth_date[:4]}-{id_birth_date[4:6]}-{id_birth_date[6:8]}"
    if birth_date != formatted_birth_date:
        return False, f"出生日期不一致,身份证号对应出生日期为{formatted_birth_date},但字段值为{birth_date}"

    # 4. 手机号验证
    if not validate_phone(phone):
        return False, "手机号格式错误"

    # 5. 姓名验证
    if not validate_name(name):
        return False, "姓名格式错误,必须为2-4个汉字"

    # 6. 时间格式验证
    if not validate_date_format(birth_date):
        return False, "出生日期格式错误"

    if not validate_datetime_format(register_time):
        return False, "注册时间格式错误"

    if not validate_datetime_format(login_time):
        return False, "最后登录时间格式错误"

    # 7. 时间逻辑验证
    time_valid, time_error = validate_time_logic(birth_date, register_time, login_time)
    if not time_valid:
        return False, time_error

    return True, ""


def main():
    input_file = 'data.txt'  # 输入文件名
    output_file = '2.txt'  # 输出文件名

    try:
        with open(input_file, 'r', encoding='utf-8') as f:
            lines = f.readlines()

        valid_lines = []
        invalid_lines = []

        print("开始验证数据...")

        for i, line in enumerate(lines, 1):
            line = line.strip()
            if not line:  # 跳过空行
                continue

            try:
                # 按逗号分割数据
                data_list = [item.strip() for item in line.split(',')]

                # 验证数据
                is_valid, error_msg = validate_row(data_list, line)

                if is_valid:
                    valid_lines.append(line)
                else:
                    invalid_lines.append(f"{line}")

            except Exception as e:
                invalid_lines.append(f"第{i}行解析错误: {line} (错误: {str(e)})")

        # 写入验证结果
        with open(output_file, 'w', encoding='utf-8') as f:
            if invalid_lines:
                f.write("不符合要求的数据:\n")
                for line in invalid_lines:
                    f.write(line + '\n')
            else:
                f.write("所有数据都符合要求\n")

        # 输出统计信息
        print(f"总行数: {len(lines)}")
        print(f"有效行数: {len(valid_lines)}")
        print(f"无效行数: {len(invalid_lines)}")

        if invalid_lines:
            print("\n无效数据已写入2.txt文件")
        else:
            print("\n所有数据都符合要求")

    except FileNotFoundError:
        print(f"错误: 找不到文件 {input_file}")
    except Exception as e:
        print(f"处理文件时发生错误: {str(e)}")


if __name__ == "__main__":
    main()

07.png

Shop

题目内容:本题目要求分析电商平台的交易数据,识别存在金额异常、银行卡异常或频率异常行为的可疑用户,并将结果保存到CSV文件中并提交到验证靶机,若正确率达标则会给出flag。

当时整了好久,浪费太多时间了,最后还是一个一个分析的然后,最后整合在一块

# 金额异常
import re
from collections import defaultdict
from datetime import datetime

# 定义商品类型与对应的金额范围
price_ranges = {
    '电子产品': (100, 5000),
    '服装鞋包': (50, 1000),
    '家居用品': (30, 2000),
    '美妆护肤': (20, 800),
    '食品饮料': (5, 300),
    '图书文具': (5, 200),
    '运动户外': (50, 3000)
}

# 存储用户的订单信息
user_orders = defaultdict(list)

# 存储异常用户
abnormal_users = set()

# 读取并处理文件
with open('data.txt', 'r', encoding='utf-8') as file:
    for line_num, line in enumerate(file, 1):
        line = line.strip()
        if not line:
            continue  # 忽略空行
        try:
            order_info = line.split(',')
            order_id, user_id, amount, timestamp, product_type, payment_method, bank_card, register_days, history_orders = order_info

            # 校验字段数量是否正确
            if len(order_info) != 9:
                print(f"第{line_num}行字段数量不正确: {line}")
                with open('1.txt', 'a', encoding='utf-8') as abnormal_file:
                    abnormal_file.write(f"{user_id},字段数异常\n")
                continue

            # 验证金额格式是否为数字
            try:
                amount = float(amount)
            except ValueError:
                print(f"第{line_num}行金额格式错误: {amount}")
                with open('1.txt', 'a', encoding='utf-8') as abnormal_file:
                    abnormal_file.write(f"{user_id},金额格式错误\n")
                continue

            # 检查商品类型是否存在于规则中
            if product_type not in price_ranges:
                print(f"第{line_num}行商品类型未定义: {product_type}")
                with open('1.txt', 'a', encoding='utf-8') as abnormal_file:
                    abnormal_file.write(f"{user_id},商品类型异常\n")
                continue

            min_price, max_price = price_ranges[product_type]

            # 校验金额是否在合理范围内
            if amount < min_price or amount > max_price:
                print(f"第{line_num}行用户{user_id}的订单金额{amount}超出商品类型{product_type}的价格范围({min_price}到{max_price})")
                abnormal_users.add(user_id)

            # 将数据存入用户的订单列表
            user_orders[user_id].append({
                'amount': amount,
                'product_type': product_type,
                'min_price': min_price,
                'max_price': max_price
            })

        except Exception as e:
            print(f"处理第{line_num}行时出错: {line}")
            with open('1.txt', 'a', encoding='utf-8') as abnormal_file:
                abnormal_file.write(f"未知,解析错误\n")

# 检查每个用户的订单是否存在金额异常
with open('1.txt', 'a', encoding='utf-8') as abnormal_file:
    for user_id, orders in user_orders.items():
        for order in orders:
            amount = order['amount']
            min_price = order['min_price']
            max_price = order['max_price']
            if amount < min_price or amount > max_price:
                # 如果是该用户第一次被标记为异常,则写入文件
                if user_id in abnormal_users:
                    abnormal_file.write(f"{user_id},金额异常\n")
                    abnormal_users.remove(user_id) # 避免重复标记
                break # 只要有一个异常就标记该用户,无需继续检查其他订单
# 银行卡异常
import re
from collections import defaultdict
from datetime import datetime

# 商品类型和价格范围映射
PRODUCT_PRICE_RANGES = {
    '电子产品': (100, 5000),
    '服装鞋包': (50, 1000),
    '家居用品': (30, 2000),
    '美妆护肤': (20, 800),
    '食品饮料': (5, 300),
    '图书文具': (5, 200),
    '运动户外': (50, 3000)
}


# Luhn算法验证银行卡号
def luhn_check(card_number):
    # 从右向左,偶数位数字乘以2
    digits = [int(d) for d in card_number]
    for i in range(len(digits) - 2, -1, -2):
        doubled = digits[i] * 2
        if doubled > 9:
            doubled -= 9
        digits[i] = doubled

    # 计算总和
    total = sum(digits)

    # 总和能被10整除则有效
    return total % 10 == 0


# 检查银行卡号是否符合格式和校验规则
def is_valid_card(card_number):
    # 1. 长度要求: 16-19位数字
    if not (16 <= len(card_number) <= 19):
        return False

    # 2. 字符要求: 仅包含数字字符
    if not card_number.isdigit():
        return False

    # 3. Luhn算法验证
    return luhn_check(card_number)


# 检查订单金额是否在商品类型的价格范围内
def is_valid_amount(product_type, amount):
    if product_type not in PRODUCT_PRICE_RANGES:
        return False

    min_price, max_price = PRODUCT_PRICE_RANGES[product_type]
    return min_price <= amount <= max_price


# 验证订单信息
def validate_order(order_line):
    try:
        # 解析每行信息
        parts = order_line.strip().split(',')
        if len(parts) != 9:
            return False, f"字段数量不匹配,应为9个但实际有{len(parts)}个"

        order_id, user_id, amount_str, order_time, product_type, payment_method, card_number, register_days, history_orders_str = parts

        # 转换为对应的类型
        amount = float(amount_str)
        register_days = int(register_days)
        history_orders = int(history_orders_str)



        # 验证银行卡号
        if not is_valid_card(card_number):
            return False, "银行卡异常"

        # 只有当所有验证都通过时才返回True
        return True, "验证通过"

    except Exception as e:
        return False, f"解析失败: {str(e)}"


# 主函数
def main():
    # 存储银行卡号使用情况(用于用户级检测)
    card_usage_by_hour = defaultdict(list)
    card_users = defaultdict(list)  # 用于检测同一卡号在同一小时内被多个用户使用

    valid_orders = []  # 有效的订单
    invalid_orders = []  # 无效的订单

    # 检查文件是否存在
    try:
        with open('data.txt', 'r', encoding='utf-8') as file:
            lines = file.readlines()

            # 先处理所有订单,收集银行卡使用信息
            for line in lines:
                if line.strip() == "":
                    continue

                parts = line.strip().split(',')
                if len(parts) != 9:
                    invalid_orders.append((parts[1], "字段数量不匹配"))
                    continue

                order_id, user_id, amount_str, order_time, product_type, payment_method, card_number, register_days, history_orders_str = parts

                try:
                    # 转换时间格式
                    order_time_dt = datetime.strptime(order_time, "%Y-%m-%d %H:%M:%S")
                    hour = order_time_dt.hour

                    # 收集银行卡使用情况
                    card_usage_by_hour[(card_number, hour)].append(user_id)
                    card_users[card_number].append(user_id)
                except Exception as e:
                    pass  # 如果时间解析出错,先忽略

            # 然后进行实际验证
            for line in lines:
                if line.strip() == "":
                    continue

                is_valid, reason = validate_order(line)
                if not is_valid:
                    parts = line.strip().split(',')
                    user_id = parts[1]
                    invalid_orders.append((user_id, reason))
                else:
                    # 如果有效,则添加到有效订单列表
                    valid_orders.append(line)

    except FileNotFoundError:
        print("订单文件 orders.txt 未找到")
        return

    # 检查银行卡号是否在同一小时内被多个用户使用(用户级异常检测)
    for (card_number, hour), users in card_usage_by_hour.items():
        if len(set(users)) > 1:
            # 同一个卡号在同一小时内被多个不同的用户使用
            # 这里简单地记录所有使用这个卡号的用户
            for user in set(users):
                # 如果这个用户的记录已经被标记为异常,则只保留一次
                exists = any(user_id == user and reason == "银行卡异常" for user_id, reason in invalid_orders)
                if not exists:
                    invalid_orders.append((user, "银行卡异常"))

    # 将无效订单输出到文件
    with open('1.txt', 'w', encoding='utf-8') as output_file:
        for user_id, reason in invalid_orders:
            output_file.write(f"{user_id},{reason}\n")

    print(f"总订单数: {len(lines)}")
    print(f"有效订单数: {len(valid_orders)}")
    print(f"无效订单数: {len(invalid_orders)}")


# 运行主程序
if __name__ == "__main__":
    main()
# 频率异常
import re
from collections import defaultdict
from datetime import datetime
import csv

# 商品类型与价格范围的映射
price_ranges = {
    '电子产品': (100, 5000),
    '服装鞋包': (50, 1000),
    '家居用品': (30, 2000),
    '美妆护肤': (20, 800),
    '食品饮料': (5, 300),
    '图书文具': (5, 200),
    '运动户外': (50, 3000)
}

# 存储用户的订单列表
user_orders = defaultdict(list)

# 存储异常用户ID
abnormal_users = set()

# 存储用户异常类型记录
user_abnormal_records = defaultdict(set)

# 读取并处理文件
with open('data.txt', 'r', encoding='utf-8') as file:
    for line_num, line in enumerate(file, 1):
        line = line.strip()
        if not line:
            continue
        try:
            order_info = line.split(',')
            # 检查字段数量是否正确
            if len(order_info) != 9:
                print(f"第{line_num}行字段数量不正确: {line}")
                with open('1.txt', 'a', encoding='utf-8') as abnormal_file:
                    abnormal_file.write(f"未知,字段数异常\n")
                continue

            order_id, user_id, amount, timestamp, product_type, payment_method, bank_card, register_days, history_orders = order_info

            # 验证金额格式是否为数字
            try:
                amount = float(amount)
            except ValueError:
                print(f"第{line_num}行金额格式错误: {amount}")
                with open('1.txt', 'a', encoding='utf-8') as abnormal_file:
                    abnormal_file.write(f"{user_id},金额格式错误\n")
                continue

            # 检查商品类型是否存在
            if product_type not in price_ranges:
                print(f"第{line_num}行商品类型未定义: {product_type}")
                with open('1.txt', 'a', encoding='utf-8') as abnormal_file:
                    abnormal_file.write(f"{user_id},商品类型异常\n")
                continue

            # 获取价格区间
            min_price, max_price = price_ranges[product_type]

            # 验证金额是否在正常范围内
            if amount < min_price or amount > max_price:
                print(f"第{line_num}行用户{user_id}的订单金额{amount}超出商品类型{product_type}的价格范围({min_price}到{max_price})")
                abnormal_users.add(user_id)
                user_abnormal_records[user_id].add('金额异常')

            # 解析时间戳
            try:
                order_time = datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S')
            except ValueError:
                print(f"第{line_num}行时间戳格式错误: {timestamp}")
                with open('1.txt', 'a', encoding='utf-8') as abnormal_file:
                    abnormal_file.write(f"{user_id},时间戳格式错误\n")
                continue

            # 将订单信息存入对应用户的列表中
            user_orders[user_id].append({
                'order_id': order_id,
                'amount': amount,
                'timestamp': order_time,
                'product_type': product_type
            })

        except Exception as e:
            print(f"处理第{line_num}行时出错: {line}")
            with open('1.txt', 'a', encoding='utf-8') as abnormal_file:
                abnormal_file.write(f"未知,解析错误\n")

# 排序各用户的所有订单(按时间)
for user_id in user_orders:
    user_orders[user_id].sort(key=lambda x: x['timestamp'])

# 进行频率异常检测
user_window_orders = defaultdict(list)

for user_id, orders in user_orders.items():
    # 按照时间窗口来分组统计每个窗口内的订单数
    last_order_time = None
    window_start = None
    window_orders = []

    for order in orders:
        order_time = order['timestamp']
        if last_order_time is None:
            # 开始新窗口
            window_start = order_time
            window_orders = [order]
            last_order_time = order_time
        else:
            # 如果当前订单与上一个订单时间差小于等于一小时,则加入窗口
            time_diff = (order_time - last_order_time).total_seconds()
            total_seconds = time_diff
            if total_seconds <= 3600:  # 一小时=3600秒
                window_orders.append(order)
                last_order_time = order_time
            else:
                # 如果当前订单与上一个订单时间差大于一小时,结束当前窗口
                window_order_count = len(window_orders)
                # 若窗口内订单数超过阈值10,则标记用户
                if window_order_count > 10:
                    user_abnormal_records[user_id].add('频率异常')
                # 开启新的窗口
                window_start = order_time
                window_orders = [order]
                last_order_time = order_time

    # 检查最后一个窗口
    if window_orders:
        window_order_count = len(window_orders)
        if window_order_count > 10:
            user_abnormal_records[user_id].add('频率异常')

# 将异常结果写入文件
with open('1.txt', 'w', encoding='utf-8') as abnormal_file:  # 用 'w' 覆盖已有内容
    for user_id, abnormal_types in user_abnormal_records.items():
        for abnormal_type in abnormal_types:
            abnormal_file.write(f"{user_id},{abnormal_type}\n")

print("异常检测完成,结果已写入 1.txt 文件")

08.png