[NSSCTF 2021]招新赛Reverse出题人笔记
ASTJS
这段json其实是js语言的ast (抽象语法树)
简单的解答
直接看json 其实并不长 就300多行 其实认真分析一下可以猜到
"value": "EXXH_MpjxBxYnjggrM~eerv" 是数据
"operator": "^" 是计算符
"value": 11 是数据
尝试一下 可知是简单的异或 flag NSSCTF{astIsReallyFunny}
这里其实出了点问题 原来异或后有一个不可见字符 复制的时候漏掉了
所以计算结果是 NSSCTF{as+IsReallyFunny} 不过如果分析一下题目名 就知道 flag其实是 NSSCTF{astIsReallyFunny}
深入一点
我们知道 ast 其实就是方便解释器执行的一种手段
所以有能转换回JS的程序吗 有的 https://github.com/estools/escodegen/
不过没法直接使用 因为AST的规则不完全一致 需要修改一下配置
https://github.com/estools/escodegen/
源代码
(function () {
function bE(str,key){
var arr = str.split('');
return arr.map((i)=>{
return String.fromCharCode(i.charCodeAt()^key)
}).join('')
}
console.log(bE('EXXH_Mpjx•BxYnjggrM~eerv',11))
})();
easyapp
安装应用查看可知是一个输入flag判断对错的简单app
随便选择一个反编译dex的工具 反编译dex 转java可知
有3个关键的类 使用工具转java代码可知
- Encoder
public class Encoder {
private int key = 0x075bcd15;
public Encoder() {
}
public String encode(String str) {
StringBuilder sb = new StringBuilder();
for (char c : str.toCharArray()) {
sb.append((char) (c ^ this.key));
}
return sb.toString();
}
}
分析代码 可知这是一个异或函数 把字符串的每一位和 key 异或
- MainActivity
protected void onCreate(Bundle bundle) {
MainActivity.super.onCreate(bundle);
setContentView(0x7f0b001c);
encoder = new Encoder();
mainActlvity = new MainActlvity();
((Button) findViewById(0x7f080057)).setOnClickListener(new -$.Lambda.MainActivity.i-SDaQT6aGr2btgF05Lf-fvXXSo(this, (EditText) findViewById(0x7f080090)));
}
public void lambda$onCreate$0$MainActivity(EditText editText, View view) {
System.out.println(encoder.encode(editText.getText().toString()));
if (encoder.encode(editText.getText().toString()).equals("棿棢棢棲棥棷棊棐棁棚棨棨棵棢棌")) {
Toast.makeText(this, "YES", 0).show();
} else {
Toast.makeText(this, "NO", 0).show();
}
}
分析代码 可知 用户输入经过 Encode 之后 和 一个静态字符串比较
如果仔细分析一下代码 可知 在创建时 调用了MainActlvity
- MainActlvity
public class MainActlvity {
public MainActlvity() {
try {
Field declaredField = Encoder.class.getDeclaredField("key");
declaredField.setAccessible(true);
declaredField.set(MainActivity.encoder, 0x3ade68b1);
} catch (IllegalAccessException | NoSuchFieldException e) {
e.printStackTrace();
}
}
}
分析代码可知 这里把 Encode key 的值掉包成了 0x3ade68b1
综合上述本题其实就是一个最简单的异或 把 key 掉包了 如果仔细分析了代码 或者使用动态调试 都能发现
最后异或一下得出flag NSSCTF{apkYYDS}
注意 这里有个小坑
key 和 字符 异或 的结果是大于char的上限的
在强制转换中会丢失数据
写python脚本时请注意这一点
pyre
丢进Exeinfo PE 一看
[ PyInstaller v.3.6 - 2005?019 - support Python 2.7, 3.5?.7 www.pyinstaller.org ] - stub : x64 Microsoft Visual C++ v14 - 2015 - microsoft.com (exe 4883ec 28-48) ,
Overlay : - .zlib Package
pyinstaller 使用 pyinstxtractor脚本 还原pyc
https://github.com/extremecoders-re/pyinstxtractor
把 code.pyc 随便扔进一个反编译程序、网站
#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
import hashlib
import base64
def init(OOOOO00O0OO00OO00, OOO00O0000OOO0O00):
OO00O000OOO0OOOOO = 0
OOO00O0000OOO0O00 = hashlib.md5(OOO00O0000OOO0O00.encode()).hexdigest()
OOO00OO0OOO00OOO0 = []
def Encrypt(O0000O0OO00OO00O0, OO0OO00O00O0O00O0):
OOOO0O00O00OOOOO0 = OO0O000O000O0O0O0 = 0
O00O00OOOO00O0000 = ''
O00O00OOOO00O0000 = base64.b64encode(O00O00OOOO00O0000.encode())
return O00O00OOOO00O0000
input_str = input('input flag pls:')
s = []
init(s, 'bJLVFYw3WI5ncGez')
if Encrypt(s, input_str).decode() == 'w4s1PUYsJ8OYwpRXVjvDkVPCgzIEJ27Dt2I=':
print('good!')
continue
print('nonono!')
continue
可以看到代码被混淆 而且反编译的不全
其实我是没想到没法反编译的 当时python版本选错了
本来是想用py3.6这种可以完美反编译的
结果打包的时候用了py3.9
qaq.....
导致这题难度直线上升 qaq
不过如果你对RC4很熟悉 其实可以直接看出来这就是一个RC4
如果不熟悉的话。。。
就只有手搓字节码了QAQ
可以参考
https://www.cnblogs.com/yinguohai/p/11158492.html
import hashlib
import base64
def init (OOOOO00O0OO00OO00 ,OOO00O0000OOO0O00 ):
OO00O000OOO0OOOOO =0
OOO00O0000OOO0O00 =hashlib .md5 (OOO00O0000OOO0O00 .encode ()).hexdigest ()
OOO00OO0OOO00OOO0 =[]
for O0O00OO00OOO0O000 in range (256 ):
OOOOO00O0OO00OO00 .append (O0O00OO00OOO0O000 )
OOO00OO0OOO00OOO0 .append (OOO00O0000OOO0O00 [O0O00OO00OOO0O000 %len (OOO00O0000OOO0O00 )])
for O0O00OO00OOO0O000 in range (256 ):
OO00O000OOO0OOOOO =(OO00O000OOO0OOOOO +OOOOO00O0OO00OO00 [O0O00OO00OOO0O000 ]+ord (OOO00OO0OOO00OOO0 [O0O00OO00OOO0O000 ]))%256
OOOOO00O0OO00OO00 [O0O00OO00OOO0O000 ],OOOOO00O0OO00OO00 [OO00O000OOO0OOOOO ]=OOOOO00O0OO00OO00 [OO00O000OOO0OOOOO ],OOOOO00O0OO00OO00 [O0O00OO00OOO0O000 ]
def Encrypt (O0000O0OO00OO00O0 ,OO0OO00O00O0O00O0 ):
OOOO0O00O00OOOOO0 =OO0O000O000O0O0O0 =0
O00O00OOOO00O0000 =''
for O0OO0O0O0OO0O0OOO in OO0OO00O00O0O00O0 :
OOOO0O00O00OOOOO0 =(OOOO0O00O00OOOOO0 +1 )%256
OO0O000O000O0O0O0 =(OO0O000O000O0O0O0 +O0000O0OO00OO00O0 [OOOO0O00O00OOOOO0 ])%256
O0000O0OO00OO00O0 [OOOO0O00O00OOOOO0 ],O0000O0OO00OO00O0 [OO0O000O000O0O0O0 ]=O0000O0OO00OO00O0 [OO0O000O000O0O0O0 ],O0000O0OO00OO00O0 [OOOO0O00O00OOOOO0 ]
O0OO0O0OOO00O0O00 =(O0000O0OO00OO00O0 [OOOO0O00O00OOOOO0 ]+O0000O0OO00OO00O0 [OO0O000O000O0O0O0 ])%256
OOO000O0OOOOO00O0 =chr (ord (O0OO0O0O0OO0O0OOO )^O0000O0OO00OO00O0 [(O0000O0OO00OO00O0 [OOOO0O00O00OOOOO0 ]+O0000O0OO00OO00O0 [OO0O000O000O0O0O0 ])%256 ])
O00O00OOOO00O0000 +=OOO000O0OOOOO00O0
O00O00OOOO00O0000 =base64 .b64encode (O00O00OOOO00O0000 .encode ())
return O00O00OOOO00O0000
while True :#line:35
input_str =input ("input flag pls:")
s =[]
init (s ,'bJLVFYw3WI5ncGez')
if Encrypt (s ,input_str ).decode () =="w4s1PUYsJ8OYwpRXVjvDkVPCgzIEJ27Dt2I=":
print ("good!")
else :
print ("nonono!")
其实这里已经很明确了 就是RC4
init是初始化 s-box
解密后得到flag NSSCTF{more_qwq_lol}
re1
这道题出的时候出了点问题,有个地方位移12位写成了位移4位,导致解不出来只能爆破,加密后的数据是这样的(如下图)因为flag是NSSCTF{}的格式,所以要爆破十位,又因为flag由大写字母和下划线组成,所以可以减少爆破的范围,这就直接上个爆破的脚本了。
def get_flag(l):
retlist = [1 for i in range(len(l))]
for i in range(len(l)):
if isinstance(l[i],list):
tmplist = get_flag(l[i])
retlist[i] = tmplist
else:
for n in range(len(l)):
tmplist = []
h4 = ord(l[n][-1])>>4
l4 = int(s[-4*(len(l[n])+1):-4*len(l[n])],2)^h4
for m in li:
maybe = (int(m,2)<<4)+l4
if chr(maybe) in box:
tmplist.append(l[n]+chr(maybe))
retlist[n] = tmplist
return retlist
return retlist
result = 591620785604527668617886
ret = str(bin(result))[2:].zfill(80)
s = ret[8:52]
li = ['0000','0001','0010','0011','0100','0101','0110','0111']
box = 'QWERTYUIOPASDFGHJKLZXCVBNM_'
h12 = str(bin(ord('{')))[2:5].zfill(4)
r = int(s[-4:],2)^int(h12,2)
maybel = []
for n in li:
maybe = (int(n,2)<<4)+r
if chr(maybe) in box:
maybel.append(chr(maybe))
retli = maybel
for i in range(9):
retli = get_flag(retli)
print(retli)
re2
简单题直接贴脚本
result='bcfba4d0038d48bd4b00f82796d393dfec'
list = [47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25]
de = []
for i in range(len(list)):
key = (list[i]>>4)+((list[i] & 0xf)<<4)
de.append(key)
flag = ''
for i in range(len(result)//2):
n = int(result[i*2:(i+1)*2],16)
flag += chr(n^de[i])
print(flag)
re3
简单题直接贴脚本
import urllib.parse
key = "HereIsFlagggg"
enc = '%C2%A6n%C2%87Y%1Ag%3F%C2%A01.%C2%9C%C3%B7%C3%8A%02%C3%80%C2%92W%C3%8C%C3%BA'
enc = urllib.parse.unquote(enc)
s_box = list(range(256))
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]
res = []
i = j = 0
for s in enc:
i = (i + 1) % 256
j = (j + s_box[i]) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
t = (s_box[i] + s_box[j]) % 256
k = s_box[t]
res.append(chr(ord(s) ^ k))
ret = "".join(res)
print(ret)
re4
简单题直接贴脚本
s = 'wesyvbniazxchjko1973652048@$+-&*<>'
result = 'v0b9n1nkajz@j0c4jjo3oi1h1i937b395i5y5e0e$i'
flag=''
for i in range(len(result)//2):
p = result[i*2:(i+1)*2]
flag += chr((s.index(p[0])-i)*17+len(s)-s.index(p[1])-i-1)
print(flag)
re5
python反编译,使用pyinstxtractor.py将编译过的exe文件反编译,获得源码的pyc,然后再找个pyc反编译的在线网站解一下就拿到源码了。
import random
import msvcrt
(row, col) = (12, 12)
(i, j) = (0, 0)
maze = [
[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1],
[1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1],
[1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,1],
[1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1],
[1,0,0,0,1,0,0,0,1,0,1,0,1,0,1,0,1,0,0,0,1,0,0,0,1],
[1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1],
[1,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,1],
[1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1],
[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,0,0,1],
[1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1],
[1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1],
[1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1],
[1,0,0,0,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1],
[1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1],
[1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1],
[1,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1],
[1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1,0,0,0,1,0,0,0,1],
[1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1],
[1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1],
[1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1],
[1,0,1,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1],
[1,0,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,1,0,1],
[1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1]]
print("Mice walk in a maze: wasd to move,q to quit")
print(
"flag is the shortest path's md5,example:if the shortest path is wasdsdw,the flag is md5('wasdsdw')"
)
(i, j) = (0, 1)
n = 0
while i == row * 2 and j == col * 2 - 1:
print("ohhhh!!!!you did it")
break
print("your position:({},{})".format(i, j))
inp = msvcrt.getch()
n += 1
ti = i
tj = j
if b"a" == inp and i > 0:
tj -= 1
elif b"w" == inp and j > 0:
ti -= 1
elif b"s" == inp and j < row * 2:
ti += 1
elif b"d" == inp and i < col * 2:
tj += 1
elif b"q" == inp:
exit("bye!!")
else:
print("What???")
if maze[ti][tj] == 1:
print(random.choice(["no wayy!!", "it's wall", "nop"]))
continue
elif maze[ti][tj] == 0:
print(random.choice(["nice!!", "yeah!!", "Go on"]))
i = ti
j = tj
return None
获得迷宫的矩阵,然后矩阵也不大,手动走一下就能走出来了,写脚本也行,但是写脚本要动脑子我就没写,得到路径后根据提示将路径md5一下就得flag了
re6
简单题直接贴脚本
s_box = 'qwertyuiopasdfghjkzxcvb123456#$'
s = 'u#k4ggia61egegzjuqz12jhfspfkay'
s = s[::-1]
ret = 3
for i in range(len(s)):
m = s_box.index(s[i])
ret = ret*31+m
ret = str(bin(ret))[2:]
if len(ret)%8 != 0:
ret = ret.zfill(len(ret)+8-len(ret)%8)
result = ''
for i in range(0,len(ret)//8):
result += chr(int(ret[8*i:8*(i+1)],2))
print(result)
re7
简单题直接贴脚本
import random
result = [201, 8, 198, 68, 131, 152, 186, 136, 13, 130, 190, 112, 251, 93, 212, 1, 31, 214, 116, 244]
random.seed(1)
l = []
for i in range(4):
l.append(random.getrandbits(8))
flag = ''
for i in range(len(l)):
random.seed(l[i])
for n in range(5):
flag += chr(result[i*5+n]^random.getrandbits(8))
print(flag)
re8
打开之后如上图,拖进exeinfope查壳
无壳,拖进ida64
直接f5后再将ascii码转换为字符可得下图
读代码可知将{34sy_r3v3rs3}中的3换成e,4换成a,加上NSSCTF提交即可,flag为NSSCTF{easy_reverse}.
re2
打开如上图,拖进exeinfope查壳
无壳,拖进ida64
直接f5后再将ascii码转换为字符
然后读代码,可以发现就是用了一个凯撒加密,为24位,手动将ylqq]aycqyp{解码再加上NSSCTF提交即可,flag为NSSCTF{nss_caesar}.
[NSSCTF 2021]招新赛Reverse出题人笔记
https://www.wd-ljt.com/post/1016/609.html
来源于问谛居,转载记得联系作者哟~
共有 0 条评论