2020数字中国创新大赛虎符网络安全赛道官方writeup
Crypto
GM
1.拿到encrypt.py 发现其输出了N,phi,和密文
2.根据N和phi可以分解出p,q
3.查阅资料,可知这是Goldwasser–Micali cryptosystem(https://en.wikipedia.org/wiki/Goldwasser–Micali_cryptosystem),有了p,q,可以通过二次剩余判定进行解密
解题脚本 见 GM_solve.sage
Mceliece
1.题目给了一个mceliece 加密系统的实现,给了公钥和密文,需要还原明文
2.经过查找资料,可以找到破解mceliece的相关论文 Stern, Jacques. A method for finding codewords of small weight. Coding theory and applications, Volume 388 of Lecture Notes in Computer Science, 1989.提出了一种Stern Attack 可以攻破该系统。
3.编写SternsAlgorithm.sage 用Sage 实现这篇论文的攻击方法。
4.编写solve.sage,用SternsAlgorithm还原明文,得到flag,脚本如下:
SternsAlgorithm.sage
1 | def _GetRandomPermutationMatrix(n): |
1 | #A copy of H_Prime with only the l selected rows (in Z) remaining |
solve.sage
1 | load("./SternsAlgorithm.sage") |
Pell
1.查看服务器源代码,发现服务器会生成两个随机数a,b ,要求输入150对不同的正整数(x,y),使得满足等式x^2+a*y^2 =b
2.这种形式的方程被称为佩尔方程(https://en.wikipedia.org/wiki/Pell's_equation)。求解佩尔方程的一般方法见 http://www.irishmathsoc.org/bull54/M5403.pdf
3.当b=1时,解佩尔方法的一种较快的方法是用连分数法(https://en.wikipedia.org/wiki/Continued_fraction),但是当a比较大时,连分数复杂度比较高
4.此外佩尔方程的解还满足递推关系
x_{n + 1} = a * x_{n} + b * D * y_{n}
y_{n + 1} = b * x_{n} + a * y_{n}
5.所以对连分数法做了个优化,用连分数发得到前两组较小的解,然后可以求出这些解的递推公式的参数,然后根据递推公式去求后续的解。
6.用sagemath实现了上述求解佩尔方程的算法,并与服务器交互即可得到flag。
1 | import sys,string |
Misc
签到题
打开题目页面,任意敲击,即会出现flag:
Misc
签到题
打开题目页面,任意敲击,即会出现flag:
但不能复制或者鼠标右键菜单,可通过浏览器菜单栏调出开发者工具,复制flag。
Minesweeper
通过三关游戏,得到三个字符串并拼接(FLOAT_STRING)
再将浮点数转换为字符串可得flag,脚本如下:
1 | import sys |
奇怪的组织
1.首先找到用户应用数据目录下存在的Firefox和Thunderbird配置文件
2.自己下载一个Firefox和Thunderbird,将这些配置文件覆盖自己的配置文件,可以使用-p指定或者修改profile.ini,将proflies里的文件保存到自己电脑里的相应位置(根据windows或者mac系统路劲有差异,但文件是通用的)这里有两个profiles的文件夹,都尝试一下,修改profile.ini,使默认的配置文件用我们刚才拷过来的那个。Firefox使用hn0lxrho.default-release之后,打开即可以看到之前用户的浏览行为了
3.打开Firefox,可以看到之前用户的浏览记录了,找到emojiwiki的网页,此时用户正在浏览🐉这个emoji
4.用同样的办法,打开Thunderbird,配置文件是7ev2i8k4.default-release,可以看到有一堆邮件,我们按照时间顺序从早到晚来还原
5.将重点的聊天内容还原
按照对话提示,我们需要去找到一个真实姓名,在奇怪的组织/Users/bob/Pictures/CameraRoll/sdcard/Android/data/com.android.backup
目录下可以发现一个通讯录的导出文件,找到邮箱号为rjddd321@protonmail.com
的通讯人,真实姓名是matachuan
,使用这个key在emoji-aes继续解密,发现后面对话内容如下
6.从邮件我们得知了两个信息,一个是存在一个后台网站,另一个是暗号已经换成了GxD1r
7.于是去dedecms的目录奇怪的组织/phpstudy_pro/WWW/dede/a/Blog/2019/1130中寻找,发现有一个博文写着一段aes加密的结果
8.U2FsdGVkX1+z9Q5Yznug4MiYfkWZNHWTOt1nIUllLgNXSKQxIiF8zmW z2cdmmPxmQkeQ/uF3INEXBZlhruUFJg==
9.使用新keyGxD1r来解密,得到flag:flag{3e5923d2-c31c-49cd-bfa3-e366a1a59c4d}
密码机器
1.使用hex2bin,将hex转化成bin,在文件结尾的地方可以看到明显的字符串,有python notepad,且存在一段python代码,可以得知是badusb的固件。
2.固件模拟鼠标键盘进行了一些操作,切换窗口,输入代码
3.根据逆向和字符串规律的观察,发现在python串口输入的代码为
1 | import base64 |
flag{ce19feba-e620-4477-8e93-a0abcdecb80d}
Reverse
Game
1.逆向python bytecode,可知flag需经过check0,check1,check2, check3四个函数的检查
2.逆向check0函数,发现flag字符均在32, 128范围内
3.逆向check1函数,爆破条件l < 100 and ((l*l) % 777) ^ 233 == 513获得 flag长度为39
4.逆向check2函数,通过128进制得到flag的开头为“flag{5”以及结尾为“}”
5.逆向check3函数,其中对三段flag进行了计算,第一部分可以爆破运算 式得到,第二部分需要通过第一部分的结果异或得到,第三部分类似16 进制编码,可以直接恢复:
1 | flag = [' ']*39 |
Enc
1.使用IDA逆向程序,找到主要逻辑sub_401490函数
2.识别md5算法(sub_401050函数),还原加密算法(sub_4012A0函 数)的密钥生成和加密逻辑。其中有类似RC6的加密算法和一段简单的异 或和换位操作。
3.逆向发现加密密钥是由当前时间决定的srand(time % 177),一共只有 177种可能,因此可以爆破。还原解密算法后,得到flag开头的结果即为 最终flag
1 |
|
VM
1.逆向vm解析器,可以发现这是一个基于栈的vm,其中也有一个内存段 和5个寄存器
2.还原每个opcode,编写disassembler翻译vm指令
3.逆向vm指令可以发现程序首先做了一个异或+移位,然后根据当前位置 的奇偶再做一个数字运算,将这两步还原即可:
1 | dest=[102, 78, 169, 253, 60, 85, 144, 36, 87, 246, 93, 177, 1, 32, 129, 253, 54, 169, 31, 161, 14, 13, 128, 143, 206, 119, 232, 35, 158, 39, 96, 47, 165, 207, 27, 189, 50, 219, 255, 40, 164, 93] |
Pwn
MarksMan
1.本题libc版本为2.27,保护全开。
2.题目逻辑比较直白,送个libc地址,写3个连续byte拿shell。
3.难点在于所有one gadget都被禁用了。
4.一个可行的思路是打ld,在ld上找到两个比较有意思的函数指针rtld_lock_default_unlock_recursive和rtld_lock_default_lock_recursive。在dlopen里调用rtld_lock_default_unlock_recursive时,rdi指向__rtld_global+2312,假设能把rtld_lock_default_unlock_recursive改为gets就有非常大的发挥空间了。后面选择进一步把rtld_lock_default_lock_recursive改为system,用稳定的方式拿shell,当然这时候也可以尝试one gadget因为这里的gets没有原题的check了。
5.当然我觉得这个题还有别的解法,各凭本事吧。
1 | from pwn import * |
SecureBox
1.本题libc版本为2.30, 保护全开。
2.漏洞点在于Allocate函数,首先uint64_t强制转换为uint32_t可以bypass到size的check。其次malloc的size过大时,返回值为0。
3.利用malloc未清空的特点泄露libc基地址。
4.然后malloc(0x7fffffff00000500),这样就等于libc范围内任意写了。
5.提供的exp选择将free_hook改成system来稳定拿shell。
1 | from pwn import * |
Count
程序随机生成200道算术题,全部答对之后进入漏洞处,看到栈溢出溢出覆盖拿到flag
1 | from pwn import * |
Encnote
1.检查题目保护,题目保护全开
2.使用 IDA逆向,发现只有增删两个功能,改查两个功能都是空的,新增功能允许分配0x30-0x200大小的堆块,但是只能写前8个字节。
3.此外还有加密和解密两个功能,密钥是初始时随机的,经过逆向可发现加密用的是blowfish算法
4.题目的漏洞在于解密函数中有一个后门,解密出的明文的左半侧如果是某个值,可以通过右半侧的明文在栈上修改一个字节
5.可以把指向存储明文的指针的低字节改掉,使明文可以覆盖bss段上的其他字段。
6.这个题目的难点在于没有泄露,加密和解密的对象是用户的输入,而不是libc地址之类的值。
7.key是存储在堆上的,可以选择用5中的覆盖,覆盖key指针的低字节,使其指向堆上unsorted bin的开头,此时key的第一位是unsorted bin的fd的高字节,其他都是0,然后用这个key加密一段内容,再在本地,爆破这个key,只需256次就能得到fd的最高位。然后再用5,使key指向unsorted bin的次高字节,继续爆破,这样本地只需要6*256次爆破就可以得到完整的unsorted bin的fd,也就获得了libc地址
8.有了libc地址,可以继续用5中的覆盖,改写指向加密的密文的指针,使其指向libc中的free_hook,然后加密system地址的解密的结果,就可以使free_hook被改写成system。
9.此时free 一个/bin/sh的堆块,得到shell
1 | #!/usr/bin/env python |
Web
easy_login
题目说明:
最近正在开始学习nodejs开发,不如先写个登陆界面练练手。什么,大 佬说我的程序有bug?我写的代码逻辑完美顺利运行怎么可能出错?!错 的一定是我的依赖库!!
可推测是题目依赖库存在问题。
测试题目功能,注册账号,不能注册admin – 登陆 – 在home页可以看到 输入框和get flag的按钮,点击按钮提示权限不足。
翻看题目前端代码/burp记录的流量,在 /static/js/app.js 发现:
/**
或许该用 koa-static 来处理静态文件
路径该怎么配置?不管了先填个根目录XD
*/
利用 koa-static 错误配置的源码泄露获得源码,进行审计
发现关键代码:
const token = ctx.header.authorization || ctx.request.body.authorization || ctx.request.query.authorization;
const sid = JSON.parse(Buffer.from(token.split(‘.’)[1], ‘base64’).toString()).secretid;
if(sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) {
throw new APIError(‘login error’, ‘no such secret id’);
}
const secret = global.secrets[sid];
const user = jwt.verify(token, secret, {algorithm: ‘HS256’});
发现可以用小数绕过 secretid 的限制,将 secret 置空。发现本题考点为利用 node 的 jsonwebtoken 库的已知缺陷:当 jwt secret 为空时,jsonwebtoken 会采用 algorithm none 进行解密伪造 secretid 为小数的 token,让 secret 成为 undefined,导致 algorithm 为 none 进而使用户变成 admin
脚本:
1 | import jwt |
just_escape
打开浏览器,检查 header,发现是后端是 express,说明 run.php 只是出题人的恶趣味
运行代码
run.php?code=Error().stack
根据报错信息发现是 vm2 的沙盒逃逸问题https://github.com/patriksimek/vm2/issues/225 搜索可得 vm2 最新沙盒逃逸 poc
但在直接使用时发现存在 waf:
探测 waf 发现程序过滤了以下关键字:
[‘for’, ‘while’, ‘process’, ‘exec’, ‘eval’, ‘constructor’, ‘prototype’, ‘Function’, ‘+’, ‘“‘,’'‘]绕过 waf,并根据 poc 改写 exp.py ,获取 flag
1 | import requests |
babyupload
解题思路:
利用download读取自己的session
发现session内容格式,得知session引起为php_binary
构造admin的session内容,利用attr和sha256拼接后缀的规则,进行bypass,往session目录上传sess文件
伪造session成为admin
利用attr的截断,去掉拼接的sha256后缀,达成任意文件名控制
成功创建success.txt文件,获取flag
解题脚本:
1 | import requests |