[2024 领航杯]veee

发布于 2024-10-15  118 次阅读


这比赛挺无语的,给一堆身份证,也是第一次了解到身份证的编码规则

身份证号码编码规则

国标GB 11643规定,全国所有公民的身份号码都是18位的特征码。所谓特征码,就是号码本身反映了公民的一些基本特征,比如籍贯、年龄、性别等。

  1. 第1、2位数字表示:所在省(直辖市、自治区)的代码;
华北东北华东华中/华南西南西北台湾港澳
北京 11辽宁 21上海 31河南 41重庆 50陕西 61台湾 71香港 81
天津 12吉林 22江苏 32湖北 42四川 51甘肃 62澳门 82
河北 13黑龙江 23浙江 33湖南 43贵州 52青海 63
山西 14安徽 34广东 44云南 53宁夏 64
内蒙古 15福建 35广西 45西藏 54新疆 65
江西 36海南 46
山东 37
  1. 第3、4位数字表示:所在地级市(自治州)的代码;
  1. 第5、6位数字表示:所在区(县、自治县、县级市)的代码;
  1. 第7—14位数字表示:出生年、月、日;
  2. 第15、16位数字表示:所在地的派出所的代码;
  3. 第17位数字表示性别:奇数表示男性,偶数表示女性;
  4. 第18位数字是校检码:是根据《中华人民共和国国家标准GB 11643-1999》中有关公民身份号码的规定,根据精密的计算公式计算出来的。

顺序码

顺序码表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。

国标GB/T 10114规定,县级以下行政区划指镇、乡、民族乡及街道;县级以下行政区划代码由三位数字构成,具体划分为:001~099表示街道;100~199表示镇、民族镇;200~399表示乡、民族乡、苏木(内蒙的基层行政单位)。

校验码

校验码采用ISO 7064:1983,MOD 11-2校验算法对前面的地址码、出生日期码和顺序码进行校验。

将上面公式稍作变换,具体是将a1×w1从求和表达式中提取出来

公式中a1就是我们要求的校验码字符值,其取值范围是0~10。当a1=10时,用罗马字符X表示

根据上面公式(2),只要求出第2~18位的∑ai×wi ,就能换算出校验码的值

第一步,列出该身份号码的本体码,结果如下

第二步,依据公式wi=(2^(i-1))(mod 11)计算加权因子

第三步,计算各位置上的乘积

第四步,乘积求和:∑ai×wi=7+9+0+5+0+32+4+0+6+21+7+18+20+5+40+36+2=212。

第五步,对11取模:∑ai×wi(mod 11)=212%11=3。

第六步,求出校验码字符值,根据(3+a1)≡1(mod 11),算出a1=9。

因此,该男性公民身份号码的本体码为110108201712215919

为了方便查找最终总结出了一个关系表,方便查阅

因为身份证有着校验码这个机制,所以我们是可以验证他给的身份证是否是合规的

我们把错误的校验码拼接起来

import re

# 判断身份证号码是否合法的函数
def is_id_card(id_card):
    # 正则表达式,用于验证身份证号格式(18位身份证)
    reg_id_card = re.compile(r'^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])(\d{3}(\d|X|x))$')

    # 使用正则表达式进行初步验证
    if reg_id_card.match(id_card):
        # 如果是18位身份证,进行校验码计算
        if len(id_card) == 18:
            # 加权因子,用于计算校验码
            id_card_wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
            # 校验码对应的值
            id_card_y = [1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2]
            # 用于存储加权和
            id_card_wi_sum = 0

            # 计算加权和
            for i in range(17):
                id_card_wi_sum += int(id_card[i]) * id_card_wi[i]

            # 计算出校验码的模数
            id_card_mod = id_card_wi_sum % 11
            # 获取身份证的最后一位(校验位)
            id_card_last = id_card[17]

            # 如果模数是2,校验位可以是"X"或"x"
            if id_card_mod == 2:
                if id_card_last.upper() == "X":
                    return True  # 校验成功
                else:
                    return False  # 校验位错误
            else:
                # 否则,校验位应与id_card_y数组中对应的值相等
                if id_card_last == str(id_card_y[id_card_mod]):
                    return True  # 校验成功
                else:
                    return False  # 校验位错误
    else:
        # 正则表达式验证不通过
        return False

# 读取文件中的身份证号码列表
try:
    with open('./sfz.txt', 'r', encoding='utf-8') as file:
        id_card_numbers = file.readlines()

    # 去除每一行的多余空格,并验证身份证号是否合法
    invalid_ids = []  # 存储不合法身份证号的最后一位
    for id_card_number in id_card_numbers:
        id_card_number = id_card_number.strip()  # 去掉首尾空白字符
        if id_card_number:
            # 调用 is_id_card 函数进行验证
            if not is_id_card(id_card_number):  # 如果身份证号不合法
                invalid_ids.append(id_card_number[-1])  # 保存不合法身份证号的最后一位

    # 输出不合法身份证号的最后一位,不带空格
    print("".join(invalid_ids))  # 输出为一行,不带空格

except FileNotFoundError:
    print("文件未找到,请检查文件路径是否正确。")
except Exception as e:
    print("出现错误:", e)
//(脚本搞了半天没搞出来了,这里借用了Peterpan师傅的脚本)

得到 746869735f69735f7077645f6a37316e617332

然后再进行 hex 解码,得到key: this_is_pwd_j71nas2

文件名是vera,所以很明显使用veracrypt挂载

成功挂载

文本中没有隐写内容,但是这个文件足足有1kb大小,所以可以尝试考虑NTFS

使用NtfsStreamsEditor2扫描,果然里面藏有文件


Defend with determination