这比赛没学到啥有意义的新知识。逆向有两道题是常规题,付出一定时间大家都能做出来,还有一题全场零解,还没给提示,赛后也没wp。misc很有意思,可惜我以后不走工控安全这条路。

virus

image-20200927103437050

走四次迷宫

image-20200927103538067

dddddddddsssssaaaaaaaaawww

sdsdsdsdsdsdsddwdwdwdwdwdwdw

aaaaaaaaasssssssddddddddd

wwwwwdddddddddsssss

不过flag的格式有点升级

image-20200927103732843

image-20200927104907201

意思是-和-之间的字符数,也就是走迷宫的步数。

那个判断数字是在v14=0,也就是还没扫描到-的时候,进行判断的,是数字的话就存储,直到出现了-。

后面check flag的时候,会根据先后的数字依次进行check。

image-20200927104542152

根据规定的步数,因此只能有一种走法:

flag{4312-wwwwwdddddddddsssss-aaaaaaaaasssssssddddddddd-dddddddddsssssaaaaaaaaawww-sdsdsdsdsdsdsddwdwdwdwdwdwdw}

image-20200927105521725

fu!k.pyc

uncompyle6拿到源码:

# uncompyle6 version 3.7.4
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD64)]
# Embedded file name: test233_ol.py
# Compiled at: 2020-03-20 13:22:50
(lambda __g, __print: [ [ (lambda __after: [ (lambda __after: (__print('Error len!'), (exit(), __after())[1])[1] if len(input) != 87 else __after())(lambda : [ [ [ [ (lambda __after: (__print('Error fmt!'), (exit(0), __after())[1])[1] if fmt1 != 'flag{' or fmt2 != '}' else __after())(lambda : (d.append(context[0:9]), (d.append(context[9:18]), (d.append(context[18:27]), (d.append(context[27:36]), (d.append(context[36:45]), (d.append(context[45:54]), (d.append(context[54:63]), (d.append(context[63:72]), (d.append(context[72:81]), [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[0][2] != '5' or d[0][3] != '3' else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[1][0] != '8' or d[1][7] != '2' else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[2][1] != '7' or d[2][4] != '1' or d[2][6] != '5' else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[3][0] != '4' or d[3][5] != '5' or d[3][6] != '3' else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[4][1] != '1' or d[4][4] != '7' or d[4][8] != '6' else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[5][2] != '3' or d[5][3] != '2' or d[5][7] != '8' else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[6][1] != '6' or d[6][3] != '5' or d[6][8] != '9' else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[7][2] != '4' or d[7][7] != '3' else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[8][5] != '9' or d[8][6] != '7' else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check(h1) != 45 or check(h2) != 45 or check(h3) != 45 or check(h4) != 45 or check(h5) != 45 or check(h6) != 45 or check(h7) != 45 or check(h8) != 45 or check(h9) != 45 else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check(l1) != 45 or check(l2) != 45 or check(l3) != 45 or check(l4) != 45 or check(l5) != 45 or check(l6) != 45 or check(l7) != 45 or check(l8) != 45 or check(l9) != 45 else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check(k1) != 45 or check(k2) != 45 or check(k3) != 45 or check(k4) != 45 or check(k5) != 45 or check(k6) != 45 or check(k7) != 45 or check(k8) != 45 or check(k9) != 45 else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check1(h1) != 1 or check1(h2) != 1 or check1(h3) != 1 or check1(h4) != 1 or check1(h5) != 1 or check1(h6) != 1 or check1(h7) != 1 or check1(h8) != 1 or check1(h9) != 1 else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check1(l1) != 1 or check1(l2) != 1 or check1(l3) != 1 or check1(l4) != 1 or check1(l5) != 1 or check1(l6) != 1 or check1(l7) != 1 or check1(l8) != 1 or check1(l9) != 1 else __after())(lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check1(k1) != 1 or check1(k2) != 1 or check1(k3) != 1 or check1(k4) != 1 or check1(k5) != 1 or check1(k6) != 1 or check1(k7) != 1 or check1(k8) != 1 or check1(k9) != 1 else __after())(lambda : (__print('Yes! You got it!'), __after())[1]))))))))))))))) for __g['k9'] in [context[60] + context[61] + context[62] + context[69] + context[70] + context[71] + context[78] + context[79] + context[80]] ][0] for __g['k8'] in [context[57] + context[58] + context[59] + context[66] + context[67] + context[68] + context[75] + context[76] + context[77]] ][0] for __g['k7'] in [context[54] + context[55] + context[56] + context[63] + context[64] + context[65] + context[72] + context[73] + context[74]] ][0] for __g['k6'] in [context[33] + context[34] + context[35] + context[42] + context[43] + context[44] + context[51] + context[52] + context[53]] ][0] for __g['k5'] in [context[30] + context[31] + context[32] + context[39] + context[40] + context[41] + context[48] + context[49] + context[50]] ][0] for __g['k4'] in [context[27] + context[28] + context[29] + context[36] + context[37] + context[38] + context[45] + context[46] + context[47]] ][0] for __g['k3'] in [context[6] + context[7] + context[8] + context[15] + context[16] + context[17] + context[24] + context[25] + context[26]] ][0] for __g['k2'] in [context[3] + context[4] + context[5] + context[12] + context[13] + context[14] + context[21] + context[22] + context[23]] ][0] for __g['k1'] in [context[0] + context[1] + context[2] + context[9] + context[10] + context[11] + context[18] + context[19] + context[20]] ][0] for __g['l9'] in [context[8] + context[17] + context[26] + context[35] + context[44] + context[53] + context[62] + context[71] + context[80]] ][0] for __g['l8'] in [context[7] + context[16] + context[25] + context[34] + context[43] + context[52] + context[61] + context[70] + context[79]] ][0] for __g['l7'] in [context[6] + context[15] + context[24] + context[33] + context[42] + context[51] + context[60] + context[69] + context[78]] ][0] for __g['l6'] in [context[5] + context[14] + context[23] + context[32] + context[41] + context[50] + context[59] + context[68] + context[77]] ][0] for __g['l5'] in [context[4] + context[13] + context[22] + context[31] + context[40] + context[49] + context[58] + context[67] + context[76]] ][0] for __g['l4'] in [context[3] + context[12] + context[21] + context[30] + context[39] + context[48] + context[57] + context[66] + context[75]] ][0] for __g['l3'] in [context[2] + context[11] + context[20] + context[29] + context[38] + context[47] + context[56] + context[65] + context[74]] ][0] for __g['l2'] in [context[1] + context[10] + context[19] + context[28] + context[37] + context[46] + context[55] + context[64] + context[73]] ][0] for __g['l1'] in [context[0] + context[9] + context[18] + context[27] + context[36] + context[45] + context[54] + context[63] + context[72]] ][0] for __g['h9'] in [context[72:81]] ][0] for __g['h8'] in [context[63:72]] ][0] for __g['h7'] in [context[54:63]] ][0] for __g['h6'] in [context[45:54]] ][0] for __g['h5'] in [context[36:45]] ][0] for __g['h4'] in [context[27:36]] ][0] for __g['h3'] in [context[18:27]] ][0] for __g['h2'] in [context[9:18]] ][0] for __g['h1'] in [context[0:9]] ][0])[1])[1])[1])[1])[1])[1])[1])[1])[1]) for __g['d'] in [[]] ][0] for __g['context'] in [input[5:-1]] ][0] for __g['fmt2'] in [input[(-1)]] ][0] for __g['fmt1'] in [input[0:5]] ][0])
 for __g['input'] in [raw_input('Input your flag:')] ][0] if __name__ == '__main__' else __after())(lambda : None)
 for __g['check1'], check1.__name__ in [(lambda arg: (lambda __l: [ (lambda __after: 0 if len(list(set(__l['arg']))) != 9 else 1)(lambda : None) for __l['arg'] in [arg] ][0])({}), 'check1')] ][0]
 for __g['check'], check.__name__ in [(lambda arg: (lambda __l: [ sum(map(int, __l['arg'])) for __l['arg'] in [arg] ][0])({}), 'check')] ][0])(globals(), __import__('__builtin__', level=0).__dict__['print'])
# okay decompiling fu!k.pyc

整理下:

# uncompyle6 version 3.7.4
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD64)]
# Embedded file name: test233_ol.py
# Compiled at: 2020-03-20 13:22:50


(lambda __g, __print: [ [ (lambda __after: [ 
    
    (lambda __after: (__print('Error len!'), (exit(), __after())[1])[1] if len(input) != 87 else __after())

    (lambda : 
        [ [ [ [ (lambda __after: (__print('Error fmt!'), (exit(0), __after())[1])[1] if fmt1 != 'flag{' or fmt2 != '}' else __after())
            (lambda : (d.append(context[0:9]), (d.append(context[9:18]), (d.append(context[18:27]), (d.append(context[27:36]), (d.append(context[36:45]), (d.append(context[45:54]), (d.append(context[54:63]), (d.append(context[63:72]), (d.append(context[72:81]), [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ [ 
        
        
        (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[0][2] != '5' or d[0][3] != '3' else __after())
        
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[1][0] != '8' or d[1][7] != '2' else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[2][1] != '7' or d[2][4] != '1' or d[2][6] != '5' else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[3][0] != '4' or d[3][5] != '5' or d[3][6] != '3' else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[4][1] != '1' or d[4][4] != '7' or d[4][8] != '6' else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[5][2] != '3' or d[5][3] != '2' or d[5][7] != '8' else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[6][1] != '6' or d[6][3] != '5' or d[6][8] != '9' else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[7][2] != '4' or d[7][7] != '3' else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if d[8][5] != '9' or d[8][6] != '7' else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check(h1) != 45 or check(h2) != 45 or check(h3) != 45 or check(h4) != 45 or check(h5) != 45 or check(h6) != 45 or check(h7) != 45 or check(h8) != 45 or check(h9) != 45 else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check(l1) != 45 or check(l2) != 45 or check(l3) != 45 or check(l4) != 45 or check(l5) != 45 or check(l6) != 45 or check(l7) != 45 or check(l8) != 45 or check(l9) != 45 else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check(k1) != 45 or check(k2) != 45 or check(k3) != 45 or check(k4) != 45 or check(k5) != 45 or check(k6) != 45 or check(k7) != 45 or check(k8) != 45 or check(k9) != 45 else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check1(h1) != 1 or check1(h2) != 1 or check1(h3) != 1 or check1(h4) != 1 or check1(h5) != 1 or check1(h6) != 1 or check1(h7) != 1 or check1(h8) != 1 or check1(h9) != 1 else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check1(l1) != 1 or check1(l2) != 1 or check1(l3) != 1 or check1(l4) != 1 or check1(l5) != 1 or check1(l6) != 1 or check1(l7) != 1 or check1(l8) != 1 or check1(l9) != 1 else __after())
        (lambda : (lambda __after: (__print('Error!'), (exit(), __after())[1])[1] if check1(k1) != 1 or check1(k2) != 1 or check1(k3) != 1 or check1(k4) != 1 or check1(k5) != 1 or check1(k6) != 1 or check1(k7) != 1 or check1(k8) != 1 or check1(k9) != 1 else __after())
        (lambda : (__print('Yes! You got it!'), __after())[1]
                                                        )))))))))))))))


        for __g['k9'] in [context[60] + context[61] + context[62] + context[69] + context[70] + context[71] + context[78] + context[79] + context[80]] ][0] 
        for __g['k8'] in [context[57] + context[58] + context[59] + context[66] + context[67] + context[68] + context[75] + context[76] + context[77]] ][0] 
        for __g['k7'] in [context[54] + context[55] + context[56] + context[63] + context[64] + context[65] + context[72] + context[73] + context[74]] ][0] 
        for __g['k6'] in [context[33] + context[34] + context[35] + context[42] + context[43] + context[44] + context[51] + context[52] + context[53]] ][0] 
        for __g['k5'] in [context[30] + context[31] + context[32] + context[39] + context[40] + context[41] + context[48] + context[49] + context[50]] ][0] 
        for __g['k4'] in [context[27] + context[28] + context[29] + context[36] + context[37] + context[38] + context[45] + context[46] + context[47]] ][0] 
        for __g['k3'] in [context[6] + context[7] + context[8] + context[15] + context[16] + context[17] + context[24] + context[25] + context[26]] ][0] 
        for __g['k2'] in [context[3] + context[4] + context[5] + context[12] + context[13] + context[14] + context[21] + context[22] + context[23]] ][0] 
        for __g['k1'] in [context[0] + context[1] + context[2] + context[9] + context[10] + context[11] + context[18] + context[19] + context[20]] ][0] 



        for __g['l9'] in [context[8] + context[17] + context[26] + context[35] + context[44] + context[53] + context[62] + context[71] + context[80]] ][0]      # 竖
        for __g['l8'] in [context[7] + context[16] + context[25] + context[34] + context[43] + context[52] + context[61] + context[70] + context[79]] ][0] 
        for __g['l7'] in [context[6] + context[15] + context[24] + context[33] + context[42] + context[51] + context[60] + context[69] + context[78]] ][0] 
        for __g['l6'] in [context[5] + context[14] + context[23] + context[32] + context[41] + context[50] + context[59] + context[68] + context[77]] ][0] 
        for __g['l5'] in [context[4] + context[13] + context[22] + context[31] + context[40] + context[49] + context[58] + context[67] + context[76]] ][0] 
        for __g['l4'] in [context[3] + context[12] + context[21] + context[30] + context[39] + context[48] + context[57] + context[66] + context[75]] ][0] 
        for __g['l3'] in [context[2] + context[11] + context[20] + context[29] + context[38] + context[47] + context[56] + context[65] + context[74]] ][0] 
        for __g['l2'] in [context[1] + context[10] + context[19] + context[28] + context[37] + context[46] + context[55] + context[64] + context[73]] ][0] 
        for __g['l1'] in [context[0] + context[9] + context[18] + context[27] + context[36] + context[45] + context[54] + context[63] + context[72]] ][0] 


        for __g['h9'] in [context[72:81]] ][0]      # 横
        for __g['h8'] in [context[63:72]] ][0] 
        for __g['h7'] in [context[54:63]] ][0] 
        for __g['h6'] in [context[45:54]] ][0] 
        for __g['h5'] in [context[36:45]] ][0] 
        for __g['h4'] in [context[27:36]] ][0] 
        for __g['h3'] in [context[18:27]] ][0] 
        for __g['h2'] in [context[9:18]] ][0] 
        for __g['h1'] in [context[0:9]] ][0])[1])[1])[1])[1])[1])[1])[1])[1])[1]) 
        


        for __g['d'] in [[]] ][0] 
        for __g['context'] in [input[5:-1]] ][0] 
        for __g['fmt2'] in [input[(-1)]] ][0]       # }
        for __g['fmt1'] in [input[0:5]] ][0])       # flag{

 
 
 for __g['input'] in [raw_input('Input your flag:')] ][0] if __name__ == '__main__' else __after())(lambda : None)

 for __g['check1'], check1.__name__ in [(lambda arg: (lambda __l: [ (lambda __after: 0 if len(list(set(__l['arg']))) != 9 else 1)(lambda : None) for __l['arg'] in [arg] ][0])({}), 'check1')] ][0]

 for __g['check'], check.__name__ in [(lambda arg: (lambda __l: [ sum(map(int, __l['arg'])) for __l['arg'] in [arg] ][0])({}), 'check')] ][0])(globals(), __import__('__builtin__', level=0).__dict__['print'])

注意这是python2,运行的话要注意下。

flag{}包裹着81个数字。

9个一组,check1检查9个元素不重复,check检查9个元素和为45.

9个元素的分法有三种,行为一组,列为一组,9*9矩阵内部的3*3矩阵为一组。这三种分法都要进行check和check1。

所以就是一个数独。

网上找到轮子,改改就能跑:

import re
import copy

# 默认模板,非标准数独 - 1000次平均耗时5ms/次
sudoku_template1 = [[1,0,0,0,0,0,0,0,0],
                    [0,2,0,0,0,0,0,0,0],
                    [0,0,3,0,0,0,0,0,0],
                    [0,0,0,4,0,0,0,0,0],
                    [0,0,0,0,5,0,0,0,0],
                    [0,0,0,0,0,6,0,0,0],
                    [0,0,0,0,0,0,7,0,0],
                    [0,0,0,0,0,0,0,8,0],
                    [0,0,0,0,0,0,0,0,9]]


# 芬兰数学家英卡拉(Arto Inkala)设计的号称“最难数独” - 1000次平均耗时320ms/次
sudoku_template2 = [[8,0,0,0,0,0,0,0,0],
                    [0,0,3,6,0,0,0,0,0],
                    [0,7,0,0,9,0,2,0,0],
                    [0,5,0,0,0,7,0,0,0],
                    [0,0,0,0,4,5,7,0,0],
                    [0,0,0,1,0,0,0,3,0],
                    [0,0,1,0,0,0,0,6,8],
                    [0,0,8,5,0,0,0,1,0],
                    [0,9,0,0,0,0,4,0,0]]

def crack_it(sudoku=sudoku_template1):
    '''主函数,输入数独进行运算,如未输入则调用默认数独,格式为9x9的二维列表'''
    init_sudoku = str_to_num(copy.deepcopy(sudoku))   # Python的坑!列表或字典等对象作为函数参数时,函数可能修改其元素的指针,导致外部列表也会改变
    if is_valid_sudoku(sudoku):   # 判断输入的Sudoku是否合理(是否冲突)
        candidate_list = filter_candidate_list(init_sudoku, init_candidate_list(init_sudoku), start=0)   # 针对Sudoku中的每一个空格(空格都默认填入数字0),都算出其可能的备选数,存入data_list中;每当空格被确认唯一值时,剩余data_list都需要再被刷新
        cracked_sudoku = fill_blank(init_sudoku, candidate_list, start=0)   # 破解数独
        print(cracked_sudoku)
        print_sudoku(cracked_sudoku)   # 在控制台显示已破解的数独,默认开启
        return cracked_sudoku
    else:
        return '请检查一下输入是否有误- -0'

def str_to_num(data):
    '''初步校验+统一格式,空字符转0,无效字符转0'''
    for i in range(9):
        for j in range(9):
            if re.match('[1-9]', str(data[i][j])):   # 1-9字符转int 1-9
                data[i][j] = int(data[i][j])
            elif re.match('', str(data[i][j])):   # 空位转int 0
                data[i][j] = 0
            else:   # 无效字符转int 0,或者也可以return False,拒绝服务
                data[i][j] = 0
    return data
                

def is_valid_sudoku(data):
    '''判断整个数独是否有效'''
    for y in range(9):
        for x in range(9):
            if data[y][x] > 9:
                return False

            if data[y][x] != 0 and data[y].count(data[y][x]) > 1:
                return False

            for col in range(9):
                if data[y][x] != 0 and col != y:
                    if data[col][x] == data[y][x]:
                        return False

            for i in range(3):
                for j in range(3):
                    if data[y][x] != 0 and (i+3*(y//3), j+3*(x//3)) != (y, x):
                        if data[i+3*(y//3)][j+3*(x//3)] == data[y][x]:
                            return False
    return True

def init_candidate_list(data):
    '''初始化建立一个数独的备选数列表,一个空格就对应其坐标以及填上1~9的备选数字,格式为81x9的二维列表'''
    data_list = []
    for y in range(9):
        for x in range(9):
            if data[y][x] == 0:
                data_list.append([(x, y), [1, 2, 3, 4, 5, 6, 7, 8, 9]])
    return data_list

def filter_candidate_list(data, data_list, start):
    '''对数独的备选数表进行过滤,删除无效的备选数'''
    for blank_index in range(start, len(data_list)):
        data_list[blank_index][1] = []
        for num in range(1,10):
            if is_valid_num(data, data_list[blank_index][0][0], data_list[blank_index][0][1], num):
                data_list[blank_index][1].append(num)
    return data_list

def is_valid_num(data, x, y, num):
    '''输入数独、坐标、数字,判断该位置填入该数字是否合理'''
    if data[y].count(num) > 0:   # 行判断
        return False

    for col in range(9):   # 列判断
        if data[col][x] == num:
            return False

    for a in range(3):   # 九宫格判断
        for b in range(3):
            if data[a+3*(y//3)][b+3*(x//3)] == num:
                return False
    return True

def fill_blank(data, data_list, start):
    '''
    核心函数,递归尝试代入备选数,类似深度优先遍历算法。
    一旦某位置填入为True(由is_valid_num函数判断),则开始下一位置的填入;若某位置填入为False,则return回上一级。
    参数解释:
    data: 数独矩阵,二维列表
    data_list: 备选数表,二维列表
    start: 递归进行的位置,对应data_list的下标
    '''
    all_data = []
    if start < len(data_list):
        one = data_list[start]
        for num in one[1]:
            if is_valid_num(data, one[0][0], one[0][1], num):
                data[one[0][1]][one[0][0]] = num   # 赋值,如果能给每一格成功赋值,则意味破解成功;如果出现失败,则需要将错误赋值清零
                # data_list = filter_candidate_list(data, data_list, start)   # 每一步赋值都会改变备选数表,但刷新备选数表的操作非常耗时,若加上这句,速度会慢100倍
                tem_data = fill_blank(data, data_list, start+1)   # start+1,使递归进入下一格点
                if tem_data:   # 注意!如果下一格点return,分两种情况:1.成功破解所有格点;2.发生错误,for loop结束也会return,此时返回值为None
                    return tem_data
        data[one[0][1]][one[0][0]] = 0   # 注意!可能向下递归了若干格才发现前面是错误的(即for loop结束,return None),此时需要将所有错误的赋值清零。
    else:
        return data

def print_sudoku(data):
    '''打印数独到控制台'''
    print('>>> 破解结果:')
    for i in range(9):
        for j in range(9):
            print('{:^3}'.format(data[i][j]), end='')
        print('')
    print('')

if __name__ == '__main__':
    l = [
            [0,0,5,3,0,0,0,0,0],
            [8,0,0,0,0,0,0,2,0],
            [0,7,0,0,1,0,5,0,0],
            [4,0,0,0,0,5,3,0,0],
            [0,1,0,0,7,0,0,0,6],
            [0,0,3,2,0,0,0,8,0],
            [0,6,0,5,0,0,0,0,9],
            [0,0,4,0,0,0,0,3,0],
            [0,0,0,0,0,9,7,0,0],
        ]
    crack_it(l)

    result = [[1, 4, 5, 3, 2, 7, 6, 9, 8], [8, 3, 9, 6, 5, 4, 1, 2, 7], [6, 7, 2, 9, 1, 8, 5, 4, 3], [4, 9, 6, 1, 8, 5, 3, 7, 2], [2, 1, 8, 4, 7, 3, 9, 5, 6], [7, 5, 3, 2, 9, 6, 4, 8, 1], [3, 6, 7, 5, 4, 2, 8, 1, 9], [9, 8, 4, 7, 6, 1, 2, 3, 5], [5, 2, 1, 8, 3, 9, 7, 6, 4]] 
    print('flag{',end='')
    for i in result:
        for j in i:
            print(j,end='')
    print('}')

baby取证

misc2

linux下file一波,发现是流量包

小鲨鱼打开,发现是一个用于电力控制的协议——IEC104

image-20200927105727265

主要流程就是一方发送ASDU,这个是包含数据的。

另一方发送类似于已接受序列号的东西。

IEC104协议的帧格式有三种(I帧、U帧、S帧),基本格式如下图所示:

12928033-9240deeccc11f675

I帧为信息帧,用于传输数据,长度大于6个字节,为长帧;

S帧为确认帧,用于确认接收的I帧,长度为6个字节,为短帧;

U帧为控制帧,用于控制启动/停止/测试,长度为6个字节,为短帧;

我们只许看后面跟着asdu的I帧:

主要数据如下:

image-20200927110253535

image-20200927110242400

上图:

01 类型标示,01表示01---不带时标的单点遥信,每个遥信占1个字节

遥信:

01---不带时标的单点遥信,每个遥信占1个字节

03---不带时标的双点遥信,每个遥信占1个字节

14---具有状态变位检测的成组单点遥信,每个字节包括8个遥信

SOE:记录即事件顺序记录

02---带3个字节短时标的单点遥信

04---带3个字节短时标的双点遥信

1E---带7个字节时标的单点遥信

1F---带7个字节时标的双点遥信

遥调:

0F---不带时标的电度量,每个电度量占5个字节

10---带3个字节短时标的电度量,每个电度量占8个字节

25---带7个字节长时标的电度量,每个电度量占12个字节

其他:

2D---单点遥控

2E---双点遥控

2F---双点遥调

64---召唤全数据

65---召唤全电度

67---时钟同步

常用的传送原因列表:

1---周期,循环

2---背景扫描

3---突发,自发上传

4---初始化

5---请求或被请求

6---激活

7---激活确认

8---停止激活

9---停止激活确认

0A---激活结束

14---响应总召唤

01 可变结构限定词,有1个变位遥信上送

03 00 传输原因,03 00 表示突发传输

01 00 传输地址,这个流量包的asdu的传输地址都为1

02 00 00 信息体地址IOA,这个流量包内的主要差异就在于这个IOA的变化。

后面的01是信息,不同的类型标示对应不同的信息长度,是变长的。

对于这条封包,意思就是通过遥信,向ioa处的地址写入1.

将流量包内所有的asdu的ioa都提取出来,依次按bit写1:

def hex2char(h):
    h = h[2:]
    s = ''
    for i in range(len(h)//2):
        n = h[i*2:i*2+2]
        s += chr(int(n, 16))
    return s

def get_md5(b):
    import hashlib
    return hashlib.md5(b).hexdigest()

l = [2, 3, 6, 7, 10, 11, 13, 14, 19, 20, 22, 26, 27, 30, 31, 32, 34, 36, 37, 38, 39, 40, 42, 46, 47, 50, 53, 54, 58, 64, 66, 70, 71, 72]
bl = list('~' + '0' * 8 * 9)
for i in range(1, 73):
    if i in l:
        bl[i] = '1'
bs = ''.join(bl)[1:]
hn = hex(int(bs, 2))
print(hn)
sn = hex2char(hn)
print(sn)
md5 = get_md5(sn.encode())
print('flag{%s}' % md5)

注意到最后的是72,所以猜测可能是1~8来索引的bit,而不是常用的0~7

脚本输出:

0x666c34675f464c4147
fl4g_FLAG
flag{1f363c8468013726578830465d4739fe}
Last modification:September 27th, 2020 at 01:09 pm