莲城杯
[TOC]
A1igNed战队 莲城杯wp
排名:14
pwn
free_free_free
libc为2.23_11.3
1 | root@ubuntu:/.../free_free_free的附件# checksec free_free_free |
保护全开
只有add和free
1 | unsigned __int64 add() |
add中不限制堆块个数,限制了大小
1 | unsigned __int64 free_() |
free后指针没有置零,可以进行fastbin attack,double free
具体思路在脚本注释中
1 | #!/usr/bin/env python3 |
pwn10
1 | __int64 __fastcall shell(__int64 a1, int a2, int a3, int a4, int a5, int a6) |
gets可以无限输入,不过name不在栈上
往下看func(v11)
1 | __int64 __fastcall func(char *a1) |
qmemcpy(v1,…,….)
v1又和a1有关,a1即为外面的v11
v11是一个字符数组,存在溢出,带几个地址进去,发现qmemcpy上面的一堆没啥影响
而程序又是静态链接,直接用ropchain生成rop链
ROPgadget –binary pwn10 –ropchain
1 | #!/usr/bin/env python3 |
web
Easy_go
gob序列化储存结构体
1 | package main |
上传生成文件,获得flag
Minesweepe
js游戏题,更改地雷数量,点三局就成。
re
readme
在start函数找到主函数。发现不能正常用ida,f5。发现存在两处花指令,直接patch 两处的E8就可以正常f5了
读取一个固定的前16字节,然后用输入的前4个字节替换,然后去哈希作为key去解密。爆破前四个字节,然后判断解密出来前四个字节是否存在。然后里面再下一步,将哈希调用的转为字符,然后与刚才得到的16个字节异或,然后前16个字符作为key调用了一个魔改的TEA。最后得到另一部分flag
1 | import hashlib |
rust
运行,发现代码很麻,调试也运行不起来,然后下面,发现是rc4,key也有
尝试拿去解密。
1 | from Crypto.Cipher import ARC4 |
LongTime
算法优化,时间浪费在sleep和大量的v1循环中,易观察v4的值24组循环依次,复制源码在循环处加个%24即可。
1 | table='0123456789abcdef' |
misc
Bit map
bmp文件,添加.bmp还是无法查看图片
010打开
根据计算方式可知,数据一共是1080054-54字节,然后因为32位深,需要除以4.高度为-300,得出宽度900
得到图片上面写了R G B,那么还有一个颜色就是A透明通道,用gimp打开切换为RGBA即可看到base64,解码为flag,高度-300记得换成300
midi player
下载里面的mid,然后010打开,往下拉的时候发现f l a g,手撸下来正好也是flag没毛病
flag{Th3_M1D1_SteGh1d3_is_T0_1asy}
解密看看
题目叫解密看看,猜测有密码,估计在内存里,先用passware kit一把梭,梭出来一个开机密码为passwd123
然后用DG打开
打开虚拟磁盘文件,然后恢复文件
在他的document文件夹下发现hint,说是rabbit的密码。
那么rabbit是对称加密,对称加密开头都是U2F,直接010搜
Rabbit解密即可
秘钥passwd123
crypto
\1. randomCrypto:
没啥好说的,单字节异或,直接爆破a就行了,找到可读flag字符串
s=’11011000 11110000 11000100 11011100 10101100 11001000 110011000 11001100 110001100 110011100 110001000 11010100 110011100 110100100 11000100 110100100 11001000 110010100 110011100 110011000 110001000 110001000 110001100 11001100 110000100 11010100 110010000 110000100 11010000 110010100 11000100 110100100 110010000 110010000 110000000 11001000 110000000 10110100’
s=s.split(‘ ‘)
for a in range(65,255):
f=’’
for i in s:
jj=i[:-2]
f+=chr(int(jj,2)^a)
if ‘flag’ in f:
print(f)
#flag{b6c372e79a9b576223c1e41d5a9440b0}
\2. Mt19937
这个题刚开始一看还以为和以前做的32位的mt19937一样,结果拿来一梭,根本不对。
于是去网上翻C++64位mt19937的源码,网上也能找到一些源码https://github.com/lineplay/mt19937_64_cs/blob/master/mt19937_64.cs
实际上实现和32位的异曲同工,当然如果要逆也是一样,直接尝试搜索有没有现成的轮子https://github.com/oToToT/PRNGP/blob/main/mt19937_64/predict.py
不说和题目完全相同,只能说是一模一样,利用这里的脚本可以实现预测,原理和32类似,而且也只需要312个64比特的。
来看具体的,首先flag随机产生的,与之前的无关。而pop函数才是细节,flag小于999,可以爆破(bushi,一个数组pop出对应下标元素,然后数组也会移除,所以可以通过前后的来查找丢失了哪个元素,最后就得到flag了。
from typing import List
class mt19937_64:
def init(self):
self._n = 312
self._i = 0
self._state = [0] * self._n
def _untemper(self, value: int) -> int:
value ^= value >> 43
value ^= (value << 37) & 0xfff7eee000000000
_value = value
for i in range(64):
value = _value ^ ((value << 17) & 0x71d67fffeda60000)
value ^= (value >> 29) & 0x5555555555555555
return value
def from_output(self, output: List[int]) -> None:
assert len(output) >= self._n
output = output[:self._n]
self._state = list(map(self._untemper, output))
def random(self) -> int:
j = (self._i + 1) % self._n
mask = (1 << 31) - 1
inv_mask = (1 << 64) - 1 - mask
yp = (self._state[self._i] & inv_mask) | (self._state[j] & mask)
k = (self._i + 156) % self._n
self._state[self._i] = self._state[k] ^ (yp >> 1) ^ (
0xb5026f5aa96619e9 * (yp & 1))
z = self._state[self._i] ^ (
(self._state[self._i] >> 29) & 0x5555555555555555)
self._i = j
z ^= (z << 17) & 0x71d67fffeda60000
z ^= (z << 37) & 0xfff7eee000000000
return z ^ (z >> 43)
from hashlib import *
f=eval(open(r’D:\桌面\outputs_374.txt’,’r’).read())
pre=mt19937_64()
pre.from_output(f[:312])
for rand in f[312:]:
temp=pre.random()
if rand!=temp:
print(rand)
flag= b’DASCTF{‘+md5(str(temp).encode()).hexdigest().encode()+b’}’
print(flag)
break
else:
print(‘True’)
-------------本文结束感谢您的阅读-------------