2023第四届“安恒杯”CTF新生赛题解

Misc

Exif

下载图片后右键查看属性,发现图片的注释就是flag

Exif

是谁在搞渗透?

下载图片后用010 Editor打开,发现最后有一段PHP代码,是一句话木马,POST参数就是flag内容

是谁在搞渗透?

加密的压缩包1

通过阅读题面,怀疑是压缩包伪加密。使用010 Editor打开,发现"struct ZIPFILERECORD record"的"enum COMPTYPE frCompression"(全局加密标志)与"struct ZIPDIRENTRY dirEntry"的"ushort deFlags"(单个文件加密标志)不一致,将后者改为8,保存后解压,得到flag

详细请参考:https://blog.csdn.net/xiaozhaidada/article/details/124538768

加密的压缩包1

我唱片怎么坏了

听音频,发现有一段声音有问题,用Audacity或Adobe Audition打开,使用频谱图直接看到flag

我唱片怎么坏了

黑铁的鱼影

使用010 Editor打开,发现模板运行报CRC校验错误

黑铁的鱼影

结合图片观察(使用Windows自带的照片应用可以打开,其他软件可能会直接报错打不开),发现图片被截取了一部分,猜测是手动改变了高度导致看图软件无法完全显示,将高度改大,或使用CRC爆破脚本,恢复原来的高度,即可看到完整的图片。

PS: 如果做别的题目看到图片是撕裂的且CRC校验错误,也有可能是改变了宽度。

凡凡的照片

使用Wireshark打开下载的pcapng文件,发现有一段HTTP POST流量,导出后发现是一张图片,打开后发现是flag

导出文件的办法:

  1. 显示分组字节,自动渲染图片

凡凡的照片
  1. 使用binwalk或foremost提取pcapng中的文件

OSINT1

打开图片,仔细观察,发现车次和发车时间信息

OSINT1

搜索D3135时刻表,发现11:54发车的是海宁西站

QRCode.txt

下载附件得到一串疑似RGB信息的文本,行数为29*29,编写脚本将其转换为图片,得到缺失的二维码,补上三个定位点后扫码即可得到flag

QRCode.txt-1
QRCode.txt-2

OSINT2

首先阅读题面,搜索2023深圳1024程序员节CTF比赛,发现比赛地点在“深圳市龙华区北站中心公园”。

观察题目给的图片,发现对面有一座中国石化加油站。在比赛地点附近搜索,并比对图片与卫星图中的马路、天桥、周围建筑等特征,找到拍摄人所处的楼宇是“鸿荣源·天俊D栋”

OSINT2

聪明的小明

阅读密码提示,使用python脚本生成字典

使用john破解(office2john),得到密码:xiaoMing20210818()

打开PPT后发现需要寻找flag,按下Ctrl+F搜索“flag”或用Ctrl+A全选或打开选择窗格发现有一段隐藏的文本,即为flag

聪明的小明

Web

被挡住了捏

按F12打开浏览器开发者工具或Ctrl+U查看源码即可拿到flag

被挡住了捏

Dino

抓包修改数值,可使用Hackbar或BurpSuite或浏览器开发者工具-网络,大于规定值即可得到flag

Dino-1
Dino-2

sqli1

使用万能密码('or 1=1#)即可登录

sqli1-1
sqli1-2

源码如下:

username=admin' or '1'='1'#拼接后的SQL语句如下:

也可以用username=admin&password=' or '1'='1,拼接后的SQL语句如下:

执行后都可以select到admin的信息,登录成功。

easyHTTP

考点: HTTP协议方法以及结构

第一步:修改GET参数中npc的值为alice

easyHTTP-1

第二步:修改GET参数中npc的值为bob

easyHTTP-2

第三步:POST传参,使用Hackbar或其他工具POST传递指定参数和内容

easyHTTP-3

得到信息

easyHTTP-4

第四步:转到jack并修改HTTP请求头部

easyHTTP-5
easyHTTP-6

魔法猫咪

PHP反序列化漏洞

这里是我们可以利用的类

魔法猫咪-1

这里告诉我们可传入进行反序列化的参数名是lawn

魔法猫咪-2

这里理一下pop链 unserialize-> sunflower.__wakeup() -> eggplant.__debugInfo() -> cat.toString() ->flag

编写代码获得序列化结果

魔法猫咪-3

构造paylod: ?lawn=O:9:"sunflower":1:{s:3:"sun";O:8:"eggplant":3:{s:3:"egg";b:1;s:5:"plant";O:3:"cat":0:{}s:6:"zombie";N;}}

魔法猫咪-4

这里附上php的魔法函数(记得保存)

魔术方法

魔术方法是会在某种条件下发生自行调用的方法

魔术方法(magic method)
说明

__construct()

当对象创建(new)时会自动调用。但在 unserialize() 时是不会自动调用的。(构造函数)

__destruct()

当对象被销毁时会自动调用。(析构函数)

__wakeup()

使用 unserialize 反序列化时自动调用

__sleep()

使用 serialize 序列化时自动调用

__set()

在给未定义的属性赋值时自动调用

__get()

调用未定义的属性时自动调用

__isset()

使用 isset() 或 empty() 函数时自动调用

__unset()

使用 unset() 时自动调用

__call()

调用一个不存在的方法时自动调用

__callStatic()

调用一个不存在的静态方法时自动调用

__toString()

把对象转换成字符串时自动调用

__invoke()

当尝试把对象当方法调用时自动调用

__set_state()

当使用 var_export() 函数时自动调用,接受一个数组参数

__clone()

当使用 clone 复制一个对象时自动调用

__debugInfo()

使用 var_dump() 打印对象信息时自动调用

坤言坤语

考点:目录爆破

题目给了很明确的提示

坤言坤语-1

爆破之后发现了 有备份压缩包

坤言坤语-2

下载下来

坤言坤语-3

阅读源码发现是一个简单的加密函数

坤言坤语-4

简单编写解码函数 获得四个密文的明文

坤言坤语-5
坤言坤语-6

构造payload传参,进行蚁剑连接(或者手搓命令执行)

?sing=jI&dance=Ni&rap=TaI&basketball=Mei

坤言坤语-7

找到flag

坤言坤语-8

babybabyweb

考点:javaweb web.xml泄露

啥都不输都能登录 说明这个登录框肯定没用

babybabyweb-1

点开登录框下的链接

发现是java后端和一个file攻击点

尝试读取javaweb的配置文件web.xml

babybabyweb-2

读取成功

看到了源码地址 尝试继续下载

babybabyweb-3

读取成功

babybabyweb-4

class文件用ide反编译一下即可

babybabyweb-5

新人爆照

考点:文件上传漏洞,.user.ini利用

先随便传个东西 发现疑似有过滤

新人爆照-1

F12检查后发现是 前端验证

新人爆照-2
新人爆照-3

控制台直接写个同名函数给他覆盖掉

成功绕过,抓个包研究一下

新人爆照-4

发现还有后端检测

新人爆照-5

再尝试php,php3,php4,php5,phtml,pht等等一系列后缀后发现全部被过滤了

通过返回包的请求标头或使用浏览器插件Wappalyzer可以发现后端服务器是Nginx

尝试上传.user.ini文件恶意修改配置文件

修改一下文件类型和文件头绕过后端验证(仅需文件开头是图片头就可以,这里用GIF是为了方便输入)

新人爆照-6

参考连接:浅析.user.ini的利用

发现上传成功

新人爆照-7

再传一句话木马,同样加上图片头

新人爆照-8

成功

新人爆照-9

此时访问该文件夹的任意PHP文件,发现我们上传的图片马已经被附加到页面中了

新人爆照-10

直接蚁剑链接拿到flag

新人爆照-11

sqli2

考点:SQL注入布尔盲注,前端加密

首先和sqli1一样尝试万能密码登录,发现可以登录,说明存在SQL注入漏洞,闭合符号为',进入后台没发现flag,则尝试读取数据库内容

首先猜测后端PHP代码如下:

将username设为admin,如果判断条件为真(如password=' and '1'='1),则登录成功,否则登录失败,由此判断可以使用布尔盲注。

但是抓包时发现,传递的内容经过加密的

查阅前端代码,发现如下js代码:

可以看到,前端使用了AES加密,密钥为4tu39rvb6h3wbif4,加密模式为CBC,填充模式为Pkcs7,加密后的内容为base64编码

尝试使用工具解密验证加密方式和密钥,解密成功,同时可以直观地看到明文的结构

sqli2

加密的形式和密钥我们都已经知道了,那么这个加密过程就可以用脚本实现了

解题思路:使用python脚本,将需要执行的语句加密后传递给后端,后端解密后执行,根据返回的结果判断是否成功,从而实现布尔盲注。这里我们仅演示手工注入,也可以使用flask框架开启一个HTTP端口接收sqlmap的请求,这样就能用sqlmap快速获取数据库的内容了。

如果遇到无法加解密的情况,如加密函数特别复杂,也可以使用爬虫的方式模拟输入和点击。这里不再演示。

黑心商店

考点:任意文件读取,逻辑漏洞

查看url并尝试改变参数发现,图片数据是以base64的形式传输到前端的 尝试利用这个先读取一下index.php的内容

黑心商店-1

发现可以读取

黑心商店-2
黑心商店-3

研究一下源码看看还可以读什么(或者尝试爆破) 发现两个 读取一下

黑心商店-4

分析后发现loginServer.php没用 但是register.php 里有passcode的格式

黑心商店-5

按照正则表达式直接构造一个 passcode=as1as1as1aa11aa11a|/|/1111 正则表达式解析网站: https://c.runoob.com/front-end/7625/#!flags=&re=%5E(%5Ba-z%5D%2B%5B0-5%5D)%7B3%7D(%5Cw%7B2%7D%5Cd%7B2%7D)%7B2%7D%5Ba-zA-Z%5D%2B(%5C%7C%5C%2F)%7B2%7D%5Cd%7B4%7D%24 (但还是建议大家学会人工分析)

黑心商店-6

注册成功

黑心商店-7

然后进行登录 发现打工时总是会出现把我们金币重制(所以脚本暴力发包法失效)

黑心商店-8

先把服务端源码读下来

黑心商店-9

这一块发现了逻辑漏洞没有检测传入数量的合法性直接计算,那么如果我们的数量参数为负数,那这个价格就变成负数了,下面对数据库修改我们金币的时候就会减去一个负数,使我们的金币变多

黑心商店-10

传负数的时候发现还是有前端验证,可以先输入一个正数再抓包进行修改

黑心商店-11
黑心商店-12

获得金币后直接购买flag,得到答案

黑心商店-13
黑心商店-14

Crypto

胡言乱语

简单替换密码,通过比对翻译后的文本和题目给的密文,可以得到字母的对应关系,即可解密。

这题也可以用quipqiup快速解密,输入密文即可破解得到明文。

摩西摩西

考点:摩斯密码

观察文本内容,发现共有3种字词,分别是摩西?,并且?疑似作为分隔符,结合题目名,猜测是摩斯密码,将摩西分别替换为-.?替换为空格,摩斯解码后即可得到明文。

下面是使用CyberChef的示例

摩西摩西

Vigenere

维吉尼亚密码,发现没有给密钥,搜索维吉尼亚爆破,即可找到Vigenère Solver

破解后即为flag

rot13

简单的rot13解码,使用工具解码后得到flag内容

easyCaeser

考点:变异凯撒

根据题面,将"cj`dy"与"flag{"对照,发现偏移量为3213...,猜测偏移的规律为321循环,编写脚本解密

easyRSA

这个解密脚本是基于RSA加密算法的。RSA算法是一种非对称加密算法,即加密和解密使用的是两个不同的密钥。在这个脚本中,公钥是(n, e),私钥是(n, d)。

RSA基础推荐视频: 数学不好也能听懂的算法 - RSA加密和解密原理和过程

以下是解密脚本的步骤:

  1. 首先,脚本导入了long_to_bytes函数,这个函数可以将长整数转换为字节。

  2. 然后,脚本定义了p、q和c的值。这些值在加密脚本中生成并打印出来,现在我们需要它们来解密。

  3. 脚本计算n的值,n是p和q的乘积。这是RSA公钥的一部分。

  4. 脚本计算φ(n)的值,φ(n)是欧拉函数,计算小于n且与n互质的正整数个数。在这里,φ(n) = (p-1)*(q-1)。

  5. 脚本定义了e的值,这是RSA公钥的另一部分。

  6. 脚本计算d的值,d是e模φ(n)的乘法逆元。这是RSA私钥的一部分。

  7. 最后,脚本使用私钥(n, d)对密文c进行解密,得到明文m。解密的过程是计算c的d次方模n的余数,即c^d mod n。

  8. 脚本打印出解密后的明文m,但是m是一个长整数,所以我们需要使用long_to_bytes函数将其转换为字节,这样才能看到原始的明文信息。

easyXOR

这个解密脚本是基于XOR加密的。XOR加密是一种简单的对称加密算法,即加密和解密使用的是同一个密钥。在这个脚本中,密钥是前一个字符的ASCII值。

以下是解密脚本的步骤:

  1. 首先,脚本导入了加密后的十六进制列表。

  2. 然后,脚本将十六进制列表转换为整数列表。

  3. 脚本定义了初始的明文字符串,这是已知的第一个字符。

  4. 脚本使用一个循环,从第二个字符开始,将每个字符的ASCII值与前一个字符的ASCII值进行XOR运算,得到原始的字符。然后将这个字符添加到明文字符串中。

  5. 最后,脚本打印出解密后的明文字符串。

这个解密脚本的关键是理解XOR运算的性质:一个数与另一个数进行XOR运算两次,结果还是原来的数。也就是说,如果我们有a XOR b = c,那么c XOR b = a。在这个脚本中,a是原始的字符,b是前一个字符,c是加密后的字符。所以我们可以通过c XOR b得到a。

谍影重重

下载文本后,发现是一篇新闻,仔细阅读后发现有部分单词拼写错误,在网上搜索原文,与该文本比较不同之处(在线工具或自行编写脚本),将所有不相同的字符按顺序排列后得到meetyouatb113,即为flag

欧拉欧拉

分析题目给出的加密程序

只给出了e、n、c即公钥指数、模数以及密文

观察题目特征,发现没有生成素数q的代码,仅有一素数p

猜测n仅由p构成,即n = p**k,k可为任意整数

进入以下网站尝试进行n分解:http://www.factordb.com/index.php

分解n得到 n = p**5

计算私钥d需要先得出欧拉函数phi

遂查找有关欧拉函数的性质,可找到 根据欧拉函数性质则有 phi=(pk)-(pk-1)

尝试根据此式进行解密

p = 123011670148156067171935017378169146187754569417088208031467924757125444876573376178582752555425433929702259279078270486096811298079151854743684067475773465936777306722083390498141106158684676959748784222921618751967668182812790014845198142516241615533512211354021631481436898405968025433478683545771726278893

可得到b'flag{d66a8e00-8ada-46eb-bded-6840b583c98f}'

Reverse

test you ida

测试你的ida,用ida打开后即可发现flag

也可以用strings等工具查找字符串

easyBase64

方法一(优雅做法)

首先检查一下程序是什么架构的,是32位还是64位的

easyBase64-1

然后通过64位的ida打开程序,看到如下的汇编代码

easyBase64-2

通过f5键,将汇编代码转换成伪代码,如下图所示

easyBase64-3

上面的代码不方便阅读,我们进行注释和格式,如下

通过我练习时长两月半的C++编程功底,我发现这个程序的逻辑是这样的

  1. 输入一个字符串

  2. 进行base64编码

  3. 然后和target进行比较,如果相等就输出Congratulations! You got the flag!,否则输出Sorry, you are wrong!

  4. 程序结束

那么我们就需要找到target的值,然后进行base64解码,然后就可以得到flag了

于是,我们双击target,跳转到对应的位置来查看一下

esayBase64-4

发现什么东西都没有,感觉被骗了,但是仔细回想,我们这个程序用到了很多类似std::string的东西,这些东西都是C++的标准库,那么target应该就是std::string变量

C++全局变量一般是在__static_initialization_and_destruction,这个神奇的函数中进行初始化的

esayBase64-5

然后发现了target,内容是

base64_chars的内容是

对base64的编码函数进行分析,可以发现, base64_chars就是码表

所以综上,我们可以知道target的值是通过一个变码表的base64编码的, 所以最后的结果就是

然后结果是

esayBase64-6

方法二(不优雅)

用ida打开,发现疑似是一个将输入的字符串Base64编码后于另一个字符串(编码后的flag)进行比较的程序

观察函数没有得到有效的信息,按Shift+F12查看字符串,发现有一个疑似自定义Base64字符集和编码后的flag的字符串

尝试使用自定义字符集解码字符串,得到flag

easyBase64

easyRe

这道题目缺少了信息,即加密后的flag(工作疏忽,望谅解)

反汇编后的加密函数如下

这段代码是一个名为encrypt的函数,它接受两个参数:一个字符串a1和一个整数a2。这个函数的主要目的是对输入的字符串进行加密。

  1. 首先,函数定义了一些变量和数组v3,数组v3被初始化为[3, 7, 1, 4, 5]

  2. 然后,函数计算输入字符串a1的长度,并将其存储在变量v5中。

  3. 接下来,函数进入第一个for循环,该循环遍历输入字符串的每个字符。在每次迭代中,它都会取v3数组中的一个元素(索引为当前字符的索引对数组长度取余)与当前字符进行异或操作,然后将结果存储在a2 + i的位置。

  4. 在第一个for循环之后,函数进入第二个for循环。在这个循环中,函数每次迭代两个字符,然后交换这两个字符的位置。

  5. 最后,函数在字符串的末尾添加一个空字符,以确保结果字符串是以null结尾的,然后返回这个结果字符串的指针。

这个函数的加密过程包括两个步骤:首先,使用一个固定的数组对字符串进行异或操作;然后,交换字符串中的字符位置。这两个步骤共同构成了这个函数的加密算法。

那么我们编写解密脚本的步骤就是:首先,将字符串中的字符位置交换回来;最后,使用一个固定的数组对字符串进行异或操作。

py一下

根据题目提示,搜索打包工具并结合图标形状,确定打包工具为pyinstaller,使用pyinstxtractor提取后得到pyc文件

py一下

针对nihaoya.pyc进行反编译,可以使用pycdc,也可以使用在线工具

源码如下

简单的字母替换和移位加密

对于小写字母,将字符替换为字母表中后五位的字母。对于大写字母,将字符替换为字母表中后十三位的字母。对于数字,将数字替换为其加上五后对10取余的结果。再将字符串循环右移四位。

simpleMaze

运行程序,发现是一个迷宫游戏,1,2,3,4分别表示上下左右,flag为正确的移动路径

使用ida打开,关键代码是下面这一行,用于判断行走路径是否正确

查看(int)maze的值,发现是一串由01组成的字符串

再查看isValidMove函数,发现其功能是判断移动的目标是否为0

由此可以推测(int)maze字符串中的0表示可以通过的路径,1表示不可通过的路径

通过do while函数可知迷宫的大小为10*11

则将(int)maze字符串按照10*11的大小分割,得到地图形状如下

据此可得到flag为flag{md5(242444414442233233322222444411114422422)}flag{909449cac803ef4e95abbb0aefeaddd8}

Last updated